LiveVideoForSonopost.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using Vinno.FIS.TRTCClient.Common.Enum;
  6. using Vinno.IUS.Common.Log;
  7. using Vinno.IUS.Common.Network.Leaf;
  8. using Vinno.IUS.Common.Network.Transfer;
  9. using Vinno.vCloud.FIS.CrossPlatform.Common;
  10. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  11. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  12. using Vinno.vCloud.Protocol.Infrastructures;
  13. using Vinno.vCloud.Protocol.Messages.Client.Live;
  14. using Vinno.vCloud.Protocol.Messages.Live;
  15. namespace Vinno.vCloud.Common.FIS.LiveVideos
  16. {
  17. internal class LiveVideoForSonopost : ILiveVideo
  18. {
  19. private readonly object _operateLocker = new object();
  20. private readonly object _locker = new object();
  21. private readonly string _terminalId;
  22. private readonly string _terminalName;
  23. private readonly ClientLeaf _leaf;
  24. private readonly ILiveVideoPusherManager _liveVideoPusherManager;
  25. private readonly IPreviewManager _previewManager;
  26. private readonly List<CPVideoDeviceInfo> _currentVideoDeviceInfoList;
  27. private bool _firstCommit;
  28. private bool _disposed;
  29. private string _connectionUrl;
  30. private byte[] _previewBuffer;
  31. private int _cameraPreviewWidth;
  32. private int _cameraPreviewHeight;
  33. private string _micDeviceId;
  34. private string _oldPreviewCameraId;
  35. private bool _isMute;
  36. private bool _isPaused;
  37. private RainbowImageDetectConfig _rainbowImageDetectConfig;
  38. public event EventHandler<LiveProtocol> LiveProtocolChanged;
  39. public event EventHandler<LiveNotificationArgs> LiveNotification;
  40. /// <summary>
  41. /// Raised when camera Preview Excute
  42. /// </summary>
  43. public event EventHandler<byte[]> PreviewCameraCaptured;
  44. /// <summary>
  45. /// Raised when Camera Preview Image Size Changed
  46. /// </summary>
  47. public event EventHandler<ImageSize> CameraPreviewImageSizeChanged;
  48. public LiveVideoForSonopost(string terminalId, string terminalName, ClientLeaf leaf)
  49. {
  50. _terminalId = terminalId;
  51. _terminalName = terminalName;
  52. _firstCommit = true;
  53. _leaf = leaf;
  54. _leaf.MessageArrived += OnMessageArrived;
  55. _currentVideoDeviceInfoList = new List<CPVideoDeviceInfo>();
  56. _liveVideoPusherManager = new LiveVideoPusherManager(terminalId, terminalName, leaf);
  57. _previewManager = new PreviewManager(_liveVideoPusherManager);
  58. _previewManager.PreviewImageReceived += OnPreviewImageReceived;
  59. RainbowImageDetector.Instance.IsPaused += OnIsPaused;
  60. }
  61. private void OnPreviewImageReceived(object sender, ImageFrameData e)
  62. {
  63. if (e == null)
  64. {
  65. return;
  66. }
  67. if (_cameraPreviewHeight != e.Height || _cameraPreviewWidth != e.Width)
  68. {
  69. _cameraPreviewHeight = e.Height;
  70. _cameraPreviewWidth = e.Width;
  71. CameraPreviewImageSizeChanged?.Invoke(this, new ImageSize(_cameraPreviewWidth, _cameraPreviewHeight));
  72. }
  73. if (_previewBuffer == null)
  74. {
  75. _previewBuffer = new byte[e.Size];
  76. }
  77. else if (_previewBuffer.Length != e.Size)
  78. {
  79. Array.Resize(ref _previewBuffer, e.Size);
  80. }
  81. Marshal.Copy(e.Data, _previewBuffer, 0, e.Size);
  82. PreviewCameraCaptured?.Invoke(this, _previewBuffer);
  83. }
  84. private void OnMessageArrived(object sender, Message e)
  85. {
  86. var startLiveNotification = NewStartLiveNotification.Convert(e);
  87. if (startLiveNotification != null)
  88. {
  89. HandleNewStartLiveNotification(startLiveNotification);
  90. }
  91. var closeLiveNotification = CloseLiveNotification.Convert(e);
  92. if (closeLiveNotification != null)
  93. {
  94. HandleCloseLiveNotification(closeLiveNotification);
  95. }
  96. var configNotification = TerminalPushLiveConfigNotification.Convert(e);
  97. if (configNotification != null)
  98. {
  99. HandleTerminalPushLiveConfigNotification(configNotification);
  100. }
  101. }
  102. private void HandleTerminalPushLiveConfigNotification(TerminalPushLiveConfigNotification configNotification)
  103. {
  104. if (_terminalId == configNotification.TerminalId)
  105. {
  106. lock (_operateLocker)
  107. {
  108. Logger.WriteLineInfo("Receive TerminalPushLiveConfigNotification");
  109. _liveVideoPusherManager.PushModeChanged(configNotification.PushLiveMode, configNotification.LiveProtocol);
  110. }
  111. }
  112. }
  113. private void HandleCloseLiveNotification(CloseLiveNotification closeLiveNotification)
  114. {
  115. lock (_operateLocker)
  116. {
  117. if (_isPaused)
  118. {
  119. Logger.WriteLineInfo($"Receive CloseLiveNotification,but it is paused,so skipped it.");
  120. return;
  121. }
  122. Logger.WriteLineInfo("Receive CloseLiveNotification");
  123. _connectionUrl = string.Empty;
  124. var liveEventArgs = new LiveEventArgs(false);
  125. if (!liveEventArgs.IsLive && !_liveVideoPusherManager.IsPushing)
  126. {
  127. return;
  128. }
  129. _liveVideoPusherManager.LiveStateChanged(liveEventArgs);
  130. }
  131. }
  132. private void HandleNewStartLiveNotification(NewStartLiveNotification startLiveNotification)
  133. {
  134. lock (_operateLocker)
  135. {
  136. if (_isPaused)
  137. {
  138. Logger.WriteLineInfo($"Receive NewStartLiveNotification,but it is paused,so skipped it.");
  139. return;
  140. }
  141. Logger.WriteLineInfo("Receive NewStartLiveNotification");
  142. _connectionUrl = startLiveNotification.LiveServiceUrl;
  143. var protocol = startLiveNotification.LiveProtocol;
  144. var pushMode = startLiveNotification.PushLiveMode;
  145. var extendedData = CreateExtentedData(protocol, startLiveNotification, _micDeviceId, _isMute);
  146. Logger.WriteLineInfo($"ExtendedData:{extendedData}");
  147. var liveEventArgs = new LiveEventArgs(true, (EnumLiveProtocol)protocol, (EnumLiveDataMode)pushMode, extendedData);
  148. _liveVideoPusherManager.LiveStateChanged(liveEventArgs);
  149. }
  150. }
  151. private IExtendedData CreateExtentedData(LiveProtocol protocol, NewStartLiveNotification notification, string micId, bool isMute)
  152. {
  153. var channels = notification.PushChannels;
  154. if (protocol == LiveProtocol.Rtmp)
  155. {
  156. var rtmpExtentedData = new RtmpExtendedData(notification.LiveServiceUrl, micId, isMute);
  157. if (notification.PushLiveMode == LiveDataMode.MergeLive)
  158. {
  159. rtmpExtentedData.IsMergeChannel = true;
  160. rtmpExtentedData.MergeType = EnumMergeType.Merge1920X1080;
  161. }
  162. else if (notification.PushLiveMode == LiveDataMode.OnlyLive)
  163. {
  164. rtmpExtentedData.IsMergeChannel = false;
  165. rtmpExtentedData.MergeType = EnumMergeType.None;
  166. }
  167. foreach (var channel in channels)
  168. {
  169. if (Enum.TryParse<EnumLiveChannelCategory>(channel.Name, out var category))
  170. {
  171. rtmpExtentedData.UserInfos.Add(new RtmpUserInfo(category, channel.Url, channel.Width, channel.Height));
  172. }
  173. }
  174. return rtmpExtentedData;
  175. }
  176. else if (protocol == LiveProtocol.RTC)
  177. {
  178. var rtcExtentedData = new RtcExtendedData(notification.LiveServiceUrl, micId, isMute);
  179. rtcExtentedData.AppId = notification.AppId;
  180. rtcExtentedData.RoomId = notification.IntegerRoomId;
  181. if (notification.PushLiveMode == LiveDataMode.MergeLive)
  182. {
  183. rtcExtentedData.IsMergeChannel = true;
  184. rtcExtentedData.MergeType = EnumMergeType.Merge1920X1080;
  185. }
  186. else if (notification.PushLiveMode == LiveDataMode.OnlyLive)
  187. {
  188. rtcExtentedData.IsMergeChannel = false;
  189. rtcExtentedData.MergeType = EnumMergeType.None;
  190. }
  191. foreach (var channel in channels)
  192. {
  193. if (Enum.TryParse<EnumLiveChannelCategory>(channel.Name, out var category))
  194. {
  195. rtcExtentedData.UserInfos.Add(new RtcUserInfo(category, channel.UserId, channel.UserSign, channel.Width, channel.Height));
  196. }
  197. }
  198. return rtcExtentedData;
  199. }
  200. return null;
  201. }
  202. public void ChangeCameraSettings(bool enableCameraLive, string cameraId, string micId, bool showPreviewImage, bool enableLiveVideo, bool isMute)
  203. {
  204. throw new NotImplementedException();
  205. }
  206. public void ChangeCameraSettingsForSonopost(bool showPreviewImage, EnumLiveChannelCategory previewLiveChannel, IEnumerable<CPVideoDeviceInfo> infos, RainbowImageDetectConfig rainbowImageDetectConfig, string micId, bool isMute)
  207. {
  208. lock (_locker)
  209. {
  210. bool needNotifyServer = false;
  211. if (_firstCommit)
  212. {
  213. _firstCommit = false;
  214. needNotifyServer = true;
  215. }
  216. if (_micDeviceId != micId)
  217. {
  218. _micDeviceId = micId;
  219. needNotifyServer = true;
  220. }
  221. if (infos == null)
  222. {
  223. if (_currentVideoDeviceInfoList.Count != 0 || needNotifyServer)
  224. {
  225. _currentVideoDeviceInfoList.Clear();
  226. _previewManager.UpdateCurrentVideoDeviceInfoList(new List<CPVideoDeviceInfo>());
  227. }
  228. }
  229. else
  230. {
  231. if (infos.Count() != _currentVideoDeviceInfoList.Count() || needNotifyServer)
  232. {
  233. _currentVideoDeviceInfoList.Clear();
  234. foreach (var info in infos)
  235. {
  236. var item = info.Clone() as CPVideoDeviceInfo;
  237. _currentVideoDeviceInfoList.Add(item);
  238. }
  239. _previewManager.UpdateCurrentVideoDeviceInfoList(infos.ToList());
  240. }
  241. else
  242. {
  243. if (IsDifferent(infos.ToList()) || needNotifyServer)
  244. {
  245. _currentVideoDeviceInfoList.Clear();
  246. foreach (var info in infos)
  247. {
  248. var item = info.Clone() as CPVideoDeviceInfo;
  249. _currentVideoDeviceInfoList.Add(item);
  250. }
  251. _previewManager.UpdateCurrentVideoDeviceInfoList(infos.ToList());
  252. }
  253. }
  254. }
  255. if (_isMute != isMute)
  256. {
  257. _isMute = isMute;
  258. _liveVideoPusherManager.SetMute(isMute);
  259. }
  260. var device = infos.FirstOrDefault(x => x.Category == previewLiveChannel);
  261. if (showPreviewImage && device != null)
  262. {
  263. if (device.Id != _oldPreviewCameraId && _previewManager.IsPreviewing)
  264. {
  265. _previewManager.StopPreview(true);
  266. }
  267. _oldPreviewCameraId = device.Id;
  268. _previewManager.StartPreview(device.Id, device.Width, device.Height, device.FrameRate, device.Category);
  269. }
  270. else
  271. {
  272. _previewManager.StopPreview(true);
  273. }
  274. var init = false;
  275. var updateEnable = false;
  276. var updateIntervalTime = false;
  277. if (_rainbowImageDetectConfig == null)
  278. {
  279. updateEnable = true;
  280. updateIntervalTime = true;
  281. init = true;
  282. _rainbowImageDetectConfig = rainbowImageDetectConfig;
  283. }
  284. else
  285. {
  286. if (_rainbowImageDetectConfig.IsDetectRainbowImage != rainbowImageDetectConfig.IsDetectRainbowImage)
  287. {
  288. _rainbowImageDetectConfig.IsDetectRainbowImage = rainbowImageDetectConfig.IsDetectRainbowImage;
  289. updateEnable = true;
  290. }
  291. if (_rainbowImageDetectConfig.BeforeDisableIntervalTime != rainbowImageDetectConfig.BeforeDisableIntervalTime)
  292. {
  293. _rainbowImageDetectConfig.BeforeDisableIntervalTime = rainbowImageDetectConfig.BeforeDisableIntervalTime;
  294. updateIntervalTime = true;
  295. }
  296. if (_rainbowImageDetectConfig.BeforeEnableIntervalTime != rainbowImageDetectConfig.BeforeEnableIntervalTime)
  297. {
  298. _rainbowImageDetectConfig.BeforeEnableIntervalTime = rainbowImageDetectConfig.BeforeEnableIntervalTime;
  299. updateIntervalTime = true;
  300. }
  301. if (_rainbowImageDetectConfig.AfterEnableIntervalTime != rainbowImageDetectConfig.AfterEnableIntervalTime)
  302. {
  303. _rainbowImageDetectConfig.AfterEnableIntervalTime = rainbowImageDetectConfig.AfterEnableIntervalTime;
  304. updateIntervalTime = true;
  305. }
  306. if (_rainbowImageDetectConfig.ScanIntervalTime != rainbowImageDetectConfig.ScanIntervalTime)
  307. {
  308. _rainbowImageDetectConfig.ScanIntervalTime = rainbowImageDetectConfig.ScanIntervalTime;
  309. updateIntervalTime = true;
  310. }
  311. }
  312. UpdateRainbowImageDetectConfig(updateEnable, init, updateIntervalTime);
  313. }
  314. }
  315. private void UpdateRainbowImageDetectConfig(bool updateEnable, bool init, bool updateIntervalTime)
  316. {
  317. if (init)
  318. {
  319. CrossPlatformHelper.Instance.DriverHelper.InitializeCaptureCard(_rainbowImageDetectConfig.CaptureCardList);
  320. }
  321. if (updateIntervalTime)
  322. {
  323. RainbowImageDetector.Instance.SetIntervalTime(_rainbowImageDetectConfig.BeforeDisableIntervalTime, _rainbowImageDetectConfig.BeforeEnableIntervalTime, _rainbowImageDetectConfig.AfterEnableIntervalTime, _rainbowImageDetectConfig.ScanIntervalTime);
  324. }
  325. if (updateEnable)
  326. {
  327. if (_rainbowImageDetectConfig.IsDetectRainbowImage)
  328. {
  329. RainbowImageDetector.Instance.StartDetect();
  330. }
  331. else
  332. {
  333. RainbowImageDetector.Instance.StopDetect();
  334. }
  335. }
  336. }
  337. private bool IsDifferent(List<CPVideoDeviceInfo> infos)
  338. {
  339. for (int i = 0; i < infos.Count(); i++)
  340. {
  341. if (infos[i].ToString() != _currentVideoDeviceInfoList[i].ToString())
  342. {
  343. return true;
  344. }
  345. }
  346. return false;
  347. }
  348. /// <summary>
  349. /// 获取品牌列表
  350. /// </summary>
  351. /// <returns></returns>
  352. public List<string> GetBrandList()
  353. {
  354. return _liveVideoPusherManager?.GetBrandList();
  355. }
  356. /// <summary>
  357. /// 获取型号列表
  358. /// </summary>
  359. /// <param name="brand"></param>
  360. /// <param name="model"></param>
  361. /// <returns></returns>
  362. public List<string> GetModelList(string brand)
  363. {
  364. return _liveVideoPusherManager?.GetModelList(brand);
  365. }
  366. /// <summary>
  367. /// 获取推荐分辨率
  368. /// </summary>
  369. /// <param name="brand"></param>
  370. /// <param name="model"></param>
  371. /// <returns></returns>
  372. public DeviceRecommandResolution GetRecommandResolution(string brand, string model)
  373. {
  374. return _liveVideoPusherManager?.GetRecommandResolution(brand, model);
  375. }
  376. private void DoDispose()
  377. {
  378. if (!_disposed)
  379. {
  380. RainbowImageDetector.Instance.IsPaused -= OnIsPaused;
  381. RainbowImageDetector.Instance.StopDetect();
  382. _liveVideoPusherManager.Dispose();
  383. _previewManager.PreviewImageReceived -= OnPreviewImageReceived;
  384. _previewManager.Dispose();
  385. _leaf.MessageArrived -= OnMessageArrived;
  386. _disposed = true;
  387. }
  388. }
  389. private void OnIsPaused(object sender, bool e)
  390. {
  391. lock (_operateLocker)
  392. {
  393. Logger.WriteLineInfo($"LiveVideoForSonopost Set IsPaused:{e}");
  394. if (e)
  395. {
  396. _isPaused = true;
  397. _liveVideoPusherManager.SetIsPaused(e);
  398. _previewManager.SetIsPaused(e);
  399. }
  400. else
  401. {
  402. _liveVideoPusherManager.SetIsPaused(e);
  403. _previewManager.SetIsPaused(e);
  404. _isPaused = false;
  405. }
  406. }
  407. }
  408. public void Dispose()
  409. {
  410. DoDispose();
  411. GC.SuppressFinalize(this);
  412. }
  413. public bool StartSpeedTest()
  414. {
  415. throw new NotImplementedException();
  416. }
  417. }
  418. }