LiveVideoV2.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. using JsonRpcLite.Rpc;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using Vinno.FIS.TRTCClient.Common.Enum;
  7. using Vinno.IUS.Common.Log;
  8. using Vinno.vCloud.Common.FIS.Helper;
  9. using Vinno.vCloud.Common.FIS.Notification;
  10. using Vinno.vCloud.FIS.CrossPlatform.Common;
  11. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  12. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  13. using WingInterfaceLibrary.Enum;
  14. using WingInterfaceLibrary.Enum.NotificationEnum;
  15. using WingInterfaceLibrary.Interface;
  16. using WingInterfaceLibrary.LiveConsultation;
  17. using WingInterfaceLibrary.Notifications;
  18. using WingInterfaceLibrary.Notifications.Consultation;
  19. using WingInterfaceLibrary.Notifications.Education;
  20. using WingInterfaceLibrary.Notifications.Live;
  21. namespace Vinno.vCloud.Common.FIS.LiveVideos
  22. {
  23. internal class LiveVideoV2 : ILiveVideoV2
  24. {
  25. private readonly string _token;
  26. private readonly JsonRpcClient _client;
  27. private readonly IDeviceService _deviceService;
  28. private readonly ILiveConsultationService _liveConsultationService;
  29. private readonly IEducationService _educationService;
  30. private readonly object _operateLocker = new object();
  31. private readonly object _locker = new object();
  32. private readonly string _uniqueId;
  33. private readonly ILiveVideoPusherManagerV2 _pusherManager;
  34. private readonly IPreviewManagerV2 _previewManager;
  35. private readonly RealTimeCaptureManager _realtimeCaptureManager;
  36. private readonly FISWebSocket _websocket;
  37. private readonly List<CPVideoDeviceOutputInfo> _currentVideoDeviceInfoList;
  38. private readonly List<VideoDeviceOutputInfoDTO> _currentOutputVideoInfoList;
  39. private readonly int _usScreenWidth;
  40. private readonly int _usScreenHeight;
  41. private bool _isMainLiveVideoDisabled;
  42. private string _currentHeartRateCode;
  43. private bool _disposed;
  44. private bool _liveVideoEnabled;
  45. private bool _firstCommit;
  46. private string _oldPreviewCameraId;
  47. private RainbowImageDetectConfig _rainbowImageDetectConfig;
  48. private bool _isPaused;
  49. private bool _cameraLiveEnabled;
  50. private int _cameraPreviewWidth;
  51. private int _cameraPreviewHeight;
  52. private byte[] _previewBuffer;
  53. private string _cameraId;
  54. private string _micDeviceId;
  55. private bool _isMute;
  56. /// <summary>
  57. /// Raised when camera Preview Excute
  58. /// </summary>
  59. public event EventHandler<byte[]> PreviewCameraCaptured;
  60. /// <summary>
  61. /// Raised when Camera Preview Image Size Changed
  62. /// </summary>
  63. public event EventHandler<ImageSize> CameraPreviewImageSizeChanged;
  64. /// <summary>
  65. /// The event to notificate the US to show or hide the live video out put window
  66. /// </summary>
  67. public event EventHandler<LiveNotificationArgs> LiveNotification;
  68. /// <summary>
  69. /// Raised when capture image generated.(only for new server)
  70. /// </summary>
  71. public event EventHandler<string> CaptureImageGenerated;
  72. /// <summary>
  73. /// Raised when record video generated.(only for new server)
  74. /// </summary>
  75. public event EventHandler<string> RecordVideoGenerated;
  76. public LiveVideoV2(string token, string uniqueId, int usScreenWidth, int usScreenHeight, FISWebSocket websocket, JsonRpcClient client, string deviceModel, string deviceType, string softwareVersion)
  77. {
  78. _token = token;
  79. _uniqueId = uniqueId;
  80. if (websocket != null)
  81. {
  82. _websocket = websocket;
  83. _websocket.NotificationReceived += OnNotificationReceived;
  84. }
  85. _client = client;
  86. _deviceService = _client?.CreateProxy<IDeviceService>();
  87. _liveConsultationService = _client?.CreateProxy<ILiveConsultationService>();
  88. _educationService = _client?.CreateProxy<IEducationService>();
  89. _usScreenWidth = usScreenWidth;
  90. _usScreenHeight = usScreenHeight;
  91. _previewBuffer = new byte[0];
  92. _firstCommit = true;
  93. _currentOutputVideoInfoList = new List<VideoDeviceOutputInfoDTO>();
  94. _currentVideoDeviceInfoList = new List<CPVideoDeviceOutputInfo>();
  95. _pusherManager = new LiveVideoPusherManagerV2(_token, _liveConsultationService, _deviceService, _educationService, _uniqueId, deviceModel, deviceType, softwareVersion);
  96. _pusherManager.LiveVideoNotification += OnLiveVideoNotification;
  97. _previewManager = new PreviewManagerV2(_pusherManager, _uniqueId);
  98. _previewManager.PreviewImageReceived += OnPreviewImageReceived;
  99. RainbowImageDetector.Instance.IsPaused += OnIsPaused;
  100. if (CommonParameter.Instance.IsSonopost)
  101. {
  102. _realtimeCaptureManager = new RealTimeCaptureManager();
  103. _realtimeCaptureManager.CaptureImageGenerated += OnCaptureImageGenerated;
  104. _realtimeCaptureManager.RecordVideoGenerated += OnRecordVideoGenerated;
  105. }
  106. }
  107. public void ReUploadRestVid()
  108. {
  109. _realtimeCaptureManager?.ReUploadRestVid();
  110. }
  111. private void OnRecordVideoGenerated(object sender, string e)
  112. {
  113. RecordVideoGenerated?.Invoke(this, e);
  114. }
  115. private void OnCaptureImageGenerated(object sender, string e)
  116. {
  117. CaptureImageGenerated?.Invoke(this, e);
  118. }
  119. private void OnPreviewImageReceived(object sender, ImageFrameData data)
  120. {
  121. if (data == null)
  122. {
  123. return;
  124. }
  125. if (_cameraPreviewHeight != data.Height || _cameraPreviewWidth != data.Width)
  126. {
  127. _cameraPreviewHeight = data.Height;
  128. _cameraPreviewWidth = data.Width;
  129. Array.Resize(ref _previewBuffer, data.Size);
  130. CameraPreviewImageSizeChanged?.Invoke(this, new ImageSize(_cameraPreviewWidth, _cameraPreviewHeight));
  131. }
  132. Marshal.Copy(data.Data, _previewBuffer, 0, data.Size);
  133. PreviewCameraCaptured?.Invoke(this, _previewBuffer);
  134. }
  135. /// <summary>
  136. /// Speed live test network and auto select good network to server
  137. /// </summary>
  138. /// <returns></returns>
  139. public bool StartSpeedTest()
  140. {
  141. bool speedTest = false;
  142. if (_pusherManager != null)
  143. {
  144. speedTest = _pusherManager.StartSpeedTest();
  145. }
  146. return speedTest;
  147. }
  148. private void OnNotificationReceived(object sender, NotificationArgs e)
  149. {
  150. switch (e.NotificationType)
  151. {
  152. case NotificationTypeEnum.StartLiveToDeviceNotification:
  153. try
  154. {
  155. Logger.WriteLineInfo($"LiveVideoV2 StartLiveToDeviceNotification Receive");
  156. if (e.Params is StartLiveToDeviceNotification startLiveToDeviceNotification)
  157. {
  158. HandleStartLiveToDeviceNotification(startLiveToDeviceNotification);
  159. }
  160. }
  161. catch (Exception ex)
  162. {
  163. Logger.WriteLineError($"LiveVideoV2 Handle StartLiveToDeviceNotification Error:{ex}");
  164. }
  165. break;
  166. case NotificationTypeEnum.CloseLiveToDeviceNotification:
  167. try
  168. {
  169. Logger.WriteLineInfo($"LiveVideoV2 CloseLiveToDeviceNotification Receive");
  170. HandleCloseLiveToDeviceNotification();
  171. }
  172. catch (Exception ex)
  173. {
  174. Logger.WriteLineError($"LiveVideoV2 Handle CloseLiveToDeviceNotification Error:{ex}");
  175. }
  176. break;
  177. case NotificationTypeEnum.ModifyDeviceMergedVideoSizeNotification:
  178. try
  179. {
  180. Logger.WriteLineInfo($"LiveVideoV2 ModifyDeviceMergedVideoSizeNotification Receive");
  181. if (e.Params is ModifyDeviceMergedVideoSizeNotification modifyDeviceMergedVideoSizeNotification)
  182. {
  183. HandleModifyDeviceMergedVideoSizeNotification(modifyDeviceMergedVideoSizeNotification);
  184. }
  185. }
  186. catch (Exception ex)
  187. {
  188. Logger.WriteLineError($"LiveVideoV2 Handle ModifyDeviceMergedVideoSizeNotification Error:{ex}");
  189. }
  190. break;
  191. case NotificationTypeEnum.StartConsolutionHeartRateToDeviceNotification:
  192. try
  193. {
  194. Logger.WriteLineInfo($"LiveVideoV2 StartConsolutionHeartRateToDeviceNotification Receive");
  195. if (e.Params is StartConsolutionHeartRateToDeviceNotification startConsolutionHeartRateToDeviceNotification)
  196. {
  197. HandleStartConsolutionHeartRateToDeviceNotification(startConsolutionHeartRateToDeviceNotification);
  198. }
  199. }
  200. catch (Exception ex)
  201. {
  202. Logger.WriteLineError($"LiveVideoV2 Handle StartConsolutionHeartRateToDeviceNotification Error:{ex}");
  203. }
  204. break;
  205. case NotificationTypeEnum.CloseConsolutionHeartRateToDeviceNotification:
  206. try
  207. {
  208. Logger.WriteLineInfo($"LiveVideoV2 CloseConsolutionHeartRateToDeviceNotification Receive");
  209. if (e.Params is CloseConsolutionHeartRateToDeviceNotification closeConsolutionHeartRateToDeviceNotification)
  210. {
  211. HandleCloseConsolutionHeartRateToDeviceNotification(closeConsolutionHeartRateToDeviceNotification);
  212. }
  213. }
  214. catch (Exception ex)
  215. {
  216. Logger.WriteLineError($"LiveVideoV2 Handle CloseConsolutionHeartRateToDeviceNotification Error:{ex}");
  217. }
  218. break;
  219. case NotificationTypeEnum.StartEducationHeartRateToDeviceNotification:
  220. try
  221. {
  222. Logger.WriteLineInfo($"LiveVideoV2 StartEducationHeartRateToDeviceNotification Receive");
  223. if (e.Params is StartEducationHeartRateToDeviceNotification startEducationHeartRateToDeviceNotification)
  224. {
  225. HandleStartEducationHeartRateToDeviceNotification(startEducationHeartRateToDeviceNotification);
  226. }
  227. }
  228. catch (Exception ex)
  229. {
  230. Logger.WriteLineError($"LiveVideoV2 Handle StartEducationHeartRateToDeviceNotification Error:{ex}");
  231. }
  232. break;
  233. case NotificationTypeEnum.CloseCourseHeartRateToDeviceNotification:
  234. try
  235. {
  236. Logger.WriteLineInfo($"LiveVideoV2 CloseCourseHeartRateToDeviceNotification Receive");
  237. if (e.Params is CloseCourseHeartRateToDeviceNotification closeCourseHeartRateToDeviceNotification)
  238. {
  239. HandleCloseCourseHeartRateToDeviceNotification(closeCourseHeartRateToDeviceNotification);
  240. }
  241. }
  242. catch (Exception ex)
  243. {
  244. Logger.WriteLineError($"LiveVideoV2 Handle CloseCourseHeartRateToDeviceNotification Error:{ex}");
  245. }
  246. break;
  247. case NotificationTypeEnum.ChangeConsultationToDeviceNotification:
  248. try
  249. {
  250. Logger.WriteLineInfo($"LiveVideoV2 ChangeConsultationToDeviceNotification Receive");
  251. if (e.Params is ChangeConsultationToDeviceNotification changeConsultationToDeviceNotification)
  252. {
  253. HandleChangeConsultationToDeviceNotification(changeConsultationToDeviceNotification);
  254. }
  255. }
  256. catch (Exception ex)
  257. {
  258. Logger.WriteLineError($"LiveVideoV2 Handle ChangeConsultationToDeviceNotification Error:{ex}");
  259. }
  260. break;
  261. }
  262. }
  263. private void HandleCloseLiveToDeviceNotification()
  264. {
  265. lock (_operateLocker)
  266. {
  267. if (_isPaused)
  268. {
  269. Logger.WriteLineInfo($"Receive CloseLiveToDeviceNotification,but it is paused,so skipped it.");
  270. return;
  271. }
  272. _currentHeartRateCode = string.Empty;
  273. _pusherManager.LiveStateChanged(new LiveEventArgs(false));
  274. }
  275. }
  276. private void HandleModifyDeviceMergedVideoSizeNotification(ModifyDeviceMergedVideoSizeNotification modifyDeviceMergedVideoSizeNotification)
  277. {
  278. lock (_operateLocker)
  279. {
  280. if (vCloudServerConfig.Instance.MergedChannel != modifyDeviceMergedVideoSizeNotification.MergedChannel)
  281. {
  282. vCloudServerConfig.Instance.MergedChannel = modifyDeviceMergedVideoSizeNotification.MergedChannel;
  283. _currentHeartRateCode = string.Empty;
  284. _pusherManager.LiveStateChanged(new LiveEventArgs(false));
  285. }
  286. else
  287. {
  288. if (modifyDeviceMergedVideoSizeNotification.VideoDeviceInfos == null)
  289. {
  290. if (_currentOutputVideoInfoList.Count > 0)
  291. {
  292. _currentHeartRateCode = string.Empty;
  293. _pusherManager.LiveStateChanged(new LiveEventArgs(false));
  294. }
  295. }
  296. else
  297. {
  298. if (modifyDeviceMergedVideoSizeNotification.VideoDeviceInfos.Count != _currentOutputVideoInfoList.Count)
  299. {
  300. _currentHeartRateCode = string.Empty;
  301. _pusherManager.LiveStateChanged(new LiveEventArgs(false));
  302. }
  303. else
  304. {
  305. var deviceInfos = new List<VideoDeviceOutputInfoDTO>();
  306. foreach (var device in modifyDeviceMergedVideoSizeNotification.VideoDeviceInfos)
  307. {
  308. deviceInfos.Add(DTOConverter.ConvertVideoDeviceDTOToVideoDeviceOutputInfoDTO(device));
  309. }
  310. if (IsDifferent(deviceInfos))
  311. {
  312. _currentHeartRateCode = string.Empty;
  313. _pusherManager.LiveStateChanged(new LiveEventArgs(false));
  314. }
  315. }
  316. }
  317. }
  318. }
  319. }
  320. private void HandleStartConsolutionHeartRateToDeviceNotification(StartConsolutionHeartRateToDeviceNotification startConsolutionHeartRateToDeviceNotification)
  321. {
  322. _currentHeartRateCode = startConsolutionHeartRateToDeviceNotification.LiveRoomCode;
  323. _pusherManager.StartHeartRateKeeper(startConsolutionHeartRateToDeviceNotification.LiveRoomCode, startConsolutionHeartRateToDeviceNotification.IntervalSeconds, EnumHeartRateType.LiveConsultation);
  324. }
  325. private void HandleStartEducationHeartRateToDeviceNotification(StartEducationHeartRateToDeviceNotification startEducationHeartRateToDeviceNotification)
  326. {
  327. _currentHeartRateCode = startEducationHeartRateToDeviceNotification.LiveRoomCode;
  328. _pusherManager.StartHeartRateKeeper(startEducationHeartRateToDeviceNotification.LiveRoomCode, startEducationHeartRateToDeviceNotification.IntervalSeconds, EnumHeartRateType.Education);
  329. }
  330. private void HandleCloseConsolutionHeartRateToDeviceNotification(CloseConsolutionHeartRateToDeviceNotification closeConsolutionHeartRateToDeviceNotification)
  331. {
  332. if (_currentHeartRateCode != closeConsolutionHeartRateToDeviceNotification.LiveRoomCode)
  333. {
  334. Logger.WriteLineInfo($"Current HeartRate Code:{_currentHeartRateCode},not {closeConsolutionHeartRateToDeviceNotification.LiveRoomCode}");
  335. return;
  336. }
  337. _currentHeartRateCode = string.Empty;
  338. _pusherManager.StopHeartRateKeeper();
  339. }
  340. private void HandleCloseCourseHeartRateToDeviceNotification(CloseCourseHeartRateToDeviceNotification closeCourseHeartRateToDeviceNotification)
  341. {
  342. if (_currentHeartRateCode != closeCourseHeartRateToDeviceNotification.LiveRoomCode)
  343. {
  344. Logger.WriteLineInfo($"Current HeartRate Code:{_currentHeartRateCode},not {closeCourseHeartRateToDeviceNotification.LiveRoomCode}");
  345. return;
  346. }
  347. _currentHeartRateCode = string.Empty;
  348. _pusherManager.StopHeartRateKeeper();
  349. }
  350. private void HandleChangeConsultationToDeviceNotification(ChangeConsultationToDeviceNotification changeConsultationToDeviceNotification)
  351. {
  352. if (_currentHeartRateCode != changeConsultationToDeviceNotification.ConsultationCode)
  353. {
  354. Logger.WriteLineInfo($"Current HeartRate Code Change From {_currentHeartRateCode} to {changeConsultationToDeviceNotification.ConsultationCode}");
  355. _currentHeartRateCode = changeConsultationToDeviceNotification.ConsultationCode;
  356. _pusherManager.ChangeHeartRateCode(changeConsultationToDeviceNotification.ConsultationCode);
  357. }
  358. }
  359. private void HandleStartLiveToDeviceNotification(StartLiveToDeviceNotification startLiveToDeviceNotification)
  360. {
  361. lock (_operateLocker)
  362. {
  363. if (_isPaused)
  364. {
  365. Logger.WriteLineInfo($"Receive StartLiveToDeviceNotification,but it is paused,so skipped it.");
  366. return;
  367. }
  368. if (startLiveToDeviceNotification.VideoDeviceOutputList?.Count == 0)
  369. {
  370. Logger.WriteLineError("LiveVideoV2 Receive StartLiveToDeviceNotification,But the VideoDeviceOutputInfo Count is 0");
  371. return;
  372. }
  373. _currentOutputVideoInfoList.Clear();
  374. foreach (var device in startLiveToDeviceNotification.VideoDeviceOutputList)
  375. {
  376. _currentOutputVideoInfoList.Add(DTOConverter.ConvertVideoDeviceOutputInfoToVideoDeviceOutputInfoDTO(device));
  377. }
  378. IExtendedData extendedData;
  379. switch (vCloudServerConfig.Instance.LiveProtocolType)
  380. {
  381. case TransactionStatusEnum.TRTC:
  382. extendedData = CreateExtentedData(EnumLiveProtocol.RTC, startLiveToDeviceNotification, _micDeviceId, _isMute);
  383. break;
  384. case TransactionStatusEnum.VRTC:
  385. Logger.WriteLineError("LiveVideoV2 Current doesn't support VRTC Mode");
  386. return;
  387. default:
  388. extendedData = CreateExtentedData(EnumLiveProtocol.Rtmp, startLiveToDeviceNotification, _micDeviceId, _isMute);
  389. break;
  390. }
  391. Logger.WriteLineInfo($"ExtendedData:{extendedData}");
  392. if (extendedData != null)
  393. {
  394. var pushMode = startLiveToDeviceNotification.MergedChannel ? EnumLiveDataMode.MergeLive : EnumLiveDataMode.OnlyLive;
  395. var liveProtocol = extendedData is RtcExtendedData ? EnumLiveProtocol.RTC : EnumLiveProtocol.Rtmp;
  396. var liveEventArgs = new LiveEventArgs(true, liveProtocol, pushMode, extendedData);
  397. _pusherManager.LiveStateChanged(liveEventArgs);
  398. }
  399. }
  400. }
  401. private void DoDispose()
  402. {
  403. if (!_disposed)
  404. {
  405. RainbowImageDetector.Instance.IsPaused -= OnIsPaused;
  406. RainbowImageDetector.Instance.StopDetect();
  407. if (_websocket != null)
  408. {
  409. _websocket.NotificationReceived -= OnNotificationReceived;
  410. }
  411. _currentHeartRateCode = string.Empty;
  412. _pusherManager.Dispose();
  413. _pusherManager.LiveVideoNotification -= OnLiveVideoNotification;//需放在Dispose之后,否则收不到Close的通知
  414. _previewManager.PreviewImageReceived -= OnPreviewImageReceived;
  415. _previewManager.Dispose();
  416. if (_realtimeCaptureManager != null)
  417. {
  418. _realtimeCaptureManager.CaptureImageGenerated -= OnCaptureImageGenerated;
  419. _realtimeCaptureManager.RecordVideoGenerated -= OnRecordVideoGenerated;
  420. _realtimeCaptureManager.StopRecordVideo(false);
  421. _realtimeCaptureManager.ClearImageCache();
  422. }
  423. _disposed = true;
  424. }
  425. }
  426. private void OnIsPaused(object sender, bool e)
  427. {
  428. lock (_operateLocker)
  429. {
  430. Logger.WriteLineInfo($"LiveVideoV2 Set IsPaused:{e}");
  431. if (e)
  432. {
  433. _isPaused = true;
  434. _pusherManager.SetIsPaused(e);
  435. _previewManager.SetIsPaused(e);
  436. }
  437. else
  438. {
  439. _pusherManager.SetIsPaused(e);
  440. _previewManager.SetIsPaused(e);
  441. _isPaused = false;
  442. }
  443. }
  444. }
  445. private void OnLiveVideoNotification(object sender, LiveNotificationArgs e)
  446. {
  447. LiveNotification?.Invoke(this, e);
  448. }
  449. /// <param name="enableCameraLive"></param>
  450. /// <param name="cameraId"></param>
  451. /// <param name="micId"></param>
  452. /// <param name="showPreviewImage"></param>
  453. /// <param name="enableLiveVideo"></param>
  454. /// <param name="isMute"></param>
  455. public void ChangeCameraSettings(bool enableCameraLive, string cameraId, string micId, bool showPreviewImage, bool enableLiveVideo, bool isMute)
  456. {
  457. lock (_locker)
  458. {
  459. var needNotifyServer = false;
  460. if (!enableCameraLive)
  461. {
  462. cameraId = null;
  463. showPreviewImage = false;
  464. }
  465. if (_firstCommit)
  466. {
  467. _firstCommit = false;
  468. needNotifyServer = true;
  469. }
  470. if (_cameraId != cameraId)
  471. {
  472. _cameraId = cameraId;
  473. needNotifyServer = true;
  474. }
  475. _isMainLiveVideoDisabled = !enableLiveVideo;
  476. if (_liveVideoEnabled != enableLiveVideo)
  477. {
  478. _liveVideoEnabled = enableLiveVideo;
  479. needNotifyServer = true;
  480. }
  481. if (_cameraLiveEnabled != enableCameraLive)
  482. {
  483. _cameraLiveEnabled = enableCameraLive;
  484. needNotifyServer = true;
  485. }
  486. if (needNotifyServer)
  487. {
  488. var infos = GetVideoDeviceInfos(enableLiveVideo, enableCameraLive, cameraId);
  489. _currentVideoDeviceInfoList.Clear();
  490. foreach (var info in infos)
  491. {
  492. var item = info.Clone() as CPVideoDeviceOutputInfo;
  493. _currentVideoDeviceInfoList.Add(item);
  494. }
  495. _previewManager.UpdateCurrentVideoDeviceInfoList(infos);
  496. }
  497. if (_micDeviceId != micId)
  498. {
  499. _micDeviceId = micId;
  500. _pusherManager.SwitchMic(micId);
  501. }
  502. if (_isMute != isMute)
  503. {
  504. _isMute = isMute;
  505. _pusherManager.SetMute(isMute);
  506. }
  507. if (showPreviewImage && cameraId != null)
  508. {
  509. if (cameraId != _oldPreviewCameraId && _previewManager.IsPreviewing)
  510. {
  511. _previewManager.StopPreview(true);
  512. }
  513. _oldPreviewCameraId = cameraId;
  514. _previewManager.StartPreview(cameraId, 640, 480, 20, EnumLiveChannelCategory.Auxiliary1);
  515. }
  516. else
  517. {
  518. _previewManager.StopPreview(false);
  519. }
  520. }
  521. }
  522. public void ChangeCameraSettingsForSonopost(bool showPreviewImage, EnumLiveChannelCategory previewLiveChannel, IEnumerable<CPVideoDeviceInfo> infos, string micId, bool isMute, RainbowImageDetectConfig rainbowImageDetectConfig)
  523. {
  524. lock (_locker)
  525. {
  526. bool needNotifyServer = false;
  527. if (_firstCommit)
  528. {
  529. _firstCommit = false;
  530. needNotifyServer = true;
  531. }
  532. if (infos == null)
  533. {
  534. if (_currentVideoDeviceInfoList.Count != 0 || needNotifyServer)
  535. {
  536. _currentVideoDeviceInfoList.Clear();
  537. _previewManager.UpdateCurrentVideoDeviceInfoList(new List<CPVideoDeviceOutputInfo>());
  538. }
  539. }
  540. else
  541. {
  542. var mainInfo = infos.FirstOrDefault(x => x.Category == EnumLiveChannelCategory.Main);
  543. if (mainInfo == null)//关闭主通道直播
  544. {
  545. _realtimeCaptureManager?.ClearImageCache();
  546. _isMainLiveVideoDisabled = true;
  547. }
  548. else
  549. {
  550. _isMainLiveVideoDisabled = false;
  551. }
  552. var newInfos = new List<CPVideoDeviceOutputInfo>();
  553. foreach (var info in infos)
  554. {
  555. string idForServer = null;
  556. switch (info.Category)
  557. {
  558. case EnumLiveChannelCategory.Main:
  559. idForServer = _uniqueId;
  560. break;
  561. case EnumLiveChannelCategory.Auxiliary1:
  562. idForServer = "Camera1";
  563. break;
  564. case EnumLiveChannelCategory.Auxiliary2:
  565. idForServer = "Camera2";
  566. break;
  567. case EnumLiveChannelCategory.Auxiliary3:
  568. idForServer = "Camera3";
  569. break;
  570. }
  571. var item = new CPVideoDeviceOutputInfo
  572. {
  573. VideoDeviceId = info.Id,
  574. IdForServer = idForServer,
  575. VideoDeviceSourceType = info.Category == EnumLiveChannelCategory.Main ? EnumVideoDeviceSourceType.Desktop : EnumVideoDeviceSourceType.Camera,
  576. Category = info.Category,
  577. OutputWidth = info.Width,
  578. OutputHeight = info.Height,
  579. };
  580. newInfos.Add(item);
  581. }
  582. if (newInfos.Count() != _currentVideoDeviceInfoList.Count() || needNotifyServer)
  583. {
  584. _currentVideoDeviceInfoList.Clear();
  585. foreach (var info in newInfos)
  586. {
  587. var item = info.Clone() as CPVideoDeviceOutputInfo;
  588. _currentVideoDeviceInfoList.Add(item);
  589. }
  590. _previewManager.UpdateCurrentVideoDeviceInfoList(newInfos.ToList());
  591. }
  592. else
  593. {
  594. if (IsDifferent(newInfos.ToList()) || needNotifyServer)
  595. {
  596. _currentVideoDeviceInfoList.Clear();
  597. foreach (var info in newInfos)
  598. {
  599. var item = info.Clone() as CPVideoDeviceOutputInfo;
  600. _currentVideoDeviceInfoList.Add(item);
  601. }
  602. _previewManager.UpdateCurrentVideoDeviceInfoList(newInfos.ToList());
  603. }
  604. }
  605. }
  606. if (_micDeviceId != micId)
  607. {
  608. _micDeviceId = micId;
  609. _pusherManager.SwitchMic(micId);
  610. }
  611. if (_isMute != isMute)
  612. {
  613. _isMute = isMute;
  614. _pusherManager.SetMute(isMute);
  615. }
  616. var device = infos.FirstOrDefault(x => x.Category == previewLiveChannel);
  617. if (showPreviewImage && device != null)
  618. {
  619. if (device.Id != _oldPreviewCameraId && _previewManager.IsPreviewing)
  620. {
  621. _previewManager.StopPreview(true);
  622. }
  623. _oldPreviewCameraId = device.Id;
  624. _previewManager.StartPreview(device.Id, device.Width, device.Height, device.FrameRate, device.Category);
  625. }
  626. else
  627. {
  628. _previewManager.StopPreview(false);
  629. }
  630. }
  631. var init = false;
  632. var updateEnable = false;
  633. var updateIntervalTime = false;
  634. if (_rainbowImageDetectConfig == null)
  635. {
  636. updateEnable = true;
  637. updateIntervalTime = true;
  638. init = true;
  639. _rainbowImageDetectConfig = rainbowImageDetectConfig;
  640. }
  641. else
  642. {
  643. if (_rainbowImageDetectConfig.IsDetectRainbowImage != rainbowImageDetectConfig.IsDetectRainbowImage)
  644. {
  645. _rainbowImageDetectConfig.IsDetectRainbowImage = rainbowImageDetectConfig.IsDetectRainbowImage;
  646. updateEnable = true;
  647. }
  648. if (_rainbowImageDetectConfig.BeforeDisableIntervalTime != rainbowImageDetectConfig.BeforeDisableIntervalTime)
  649. {
  650. _rainbowImageDetectConfig.BeforeDisableIntervalTime = rainbowImageDetectConfig.BeforeDisableIntervalTime;
  651. updateIntervalTime = true;
  652. }
  653. if (_rainbowImageDetectConfig.BeforeEnableIntervalTime != rainbowImageDetectConfig.BeforeEnableIntervalTime)
  654. {
  655. _rainbowImageDetectConfig.BeforeEnableIntervalTime = rainbowImageDetectConfig.BeforeEnableIntervalTime;
  656. updateIntervalTime = true;
  657. }
  658. if (_rainbowImageDetectConfig.AfterEnableIntervalTime != rainbowImageDetectConfig.AfterEnableIntervalTime)
  659. {
  660. _rainbowImageDetectConfig.AfterEnableIntervalTime = rainbowImageDetectConfig.AfterEnableIntervalTime;
  661. updateIntervalTime = true;
  662. }
  663. if (_rainbowImageDetectConfig.ScanIntervalTime != rainbowImageDetectConfig.ScanIntervalTime)
  664. {
  665. _rainbowImageDetectConfig.ScanIntervalTime = rainbowImageDetectConfig.ScanIntervalTime;
  666. updateIntervalTime = true;
  667. }
  668. }
  669. UpdateRainbowImageDetectConfig(updateEnable, init, updateIntervalTime);
  670. }
  671. private void UpdateRainbowImageDetectConfig(bool updateEnable, bool init, bool updateIntervalTime)
  672. {
  673. if (init)
  674. {
  675. CrossPlatformHelper.Instance.DriverHelper.InitializeCaptureCard(_rainbowImageDetectConfig.CaptureCardList);
  676. }
  677. if (updateIntervalTime)
  678. {
  679. RainbowImageDetector.Instance.SetIntervalTime(_rainbowImageDetectConfig.BeforeDisableIntervalTime, _rainbowImageDetectConfig.BeforeEnableIntervalTime, _rainbowImageDetectConfig.AfterEnableIntervalTime, _rainbowImageDetectConfig.ScanIntervalTime);
  680. }
  681. if (updateEnable)
  682. {
  683. if (_rainbowImageDetectConfig.IsDetectRainbowImage)
  684. {
  685. RainbowImageDetector.Instance.StartDetect();
  686. }
  687. else
  688. {
  689. RainbowImageDetector.Instance.StopDetect();
  690. }
  691. }
  692. }
  693. public void Dispose()
  694. {
  695. DoDispose();
  696. GC.SuppressFinalize(this);
  697. }
  698. private List<CPVideoDeviceOutputInfo> GetVideoDeviceInfos(bool liveVideoEnabled, bool cameraEnabled, string cameraId)
  699. {
  700. var videoInfoList = new List<CPVideoDeviceOutputInfo>();
  701. if (liveVideoEnabled)
  702. {
  703. videoInfoList.Add(new CPVideoDeviceOutputInfo
  704. {
  705. Category = EnumLiveChannelCategory.Main,
  706. VideoDeviceId = _uniqueId,
  707. IdForServer = _uniqueId,
  708. VideoDeviceSourceType = EnumVideoDeviceSourceType.Desktop,
  709. OutputHeight = _usScreenHeight,
  710. OutputWidth = _usScreenWidth,
  711. });
  712. if (cameraEnabled)
  713. {
  714. videoInfoList.Add(new CPVideoDeviceOutputInfo
  715. {
  716. Category = EnumLiveChannelCategory.Auxiliary1,
  717. IdForServer = "Camera1",
  718. VideoDeviceId = cameraId,
  719. VideoDeviceSourceType = EnumVideoDeviceSourceType.Camera,
  720. OutputHeight = 480,
  721. OutputWidth = 640,
  722. });
  723. }
  724. }
  725. return videoInfoList;
  726. }
  727. private IExtendedData CreateExtentedData(EnumLiveProtocol protocol, StartLiveToDeviceNotification notification, string micId, bool isMute)
  728. {
  729. if (protocol == EnumLiveProtocol.RTC)
  730. {
  731. var rtcExtentedData = new RtcExtendedData(null, micId, isMute);
  732. rtcExtentedData.AppId = notification.AppId;
  733. rtcExtentedData.RoomId = notification.RoomNo;
  734. if (notification.MergedChannel)
  735. {
  736. if (notification.MergedVideoOutputHeight == 720 && notification.MergedVideoOutputWidth == 1280)
  737. {
  738. rtcExtentedData.IsMergeChannel = notification.MergedChannel;
  739. rtcExtentedData.MergeType = EnumMergeType.Merge1280X720;
  740. }
  741. else
  742. {
  743. rtcExtentedData.IsMergeChannel = notification.MergedChannel;
  744. rtcExtentedData.MergeType = EnumMergeType.Merge1920X1080;
  745. }
  746. }
  747. else
  748. {
  749. rtcExtentedData.IsMergeChannel = notification.MergedChannel;
  750. rtcExtentedData.MergeType = EnumMergeType.None;
  751. }
  752. int cameraNo = 0;
  753. if (notification.VideoDeviceOutputList != null && notification.VideoDeviceOutputList.Count > 0)
  754. {
  755. for (int i = 0; i < notification.VideoDeviceOutputList.Count(); i++)
  756. {
  757. EnumLiveChannelCategory enumLiveChannelCategory;
  758. var userId = notification.VideoDeviceOutputList[i].VideoDeviceId;
  759. var userSign = notification.VideoDeviceOutputList[i].VideoDeviceSign;
  760. if (notification.VideoDeviceOutputList[i].VideoDeviceSourceType == VideoDeviceSourceTypeEnum.Desktop)
  761. {
  762. enumLiveChannelCategory = EnumLiveChannelCategory.Main;
  763. }
  764. else
  765. {
  766. switch (cameraNo)
  767. {
  768. case 0:
  769. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary1;
  770. cameraNo++;
  771. break;
  772. case 1:
  773. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary2;
  774. cameraNo++;
  775. break;
  776. case 2:
  777. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary3;
  778. cameraNo++;
  779. break;
  780. default:
  781. continue;
  782. }
  783. }
  784. var width = notification.VideoDeviceOutputList[i].OutputWidth;
  785. var height = notification.VideoDeviceOutputList[i].OutputHeight;
  786. var fps = notification.VideoDeviceOutputList[i].VideoFps;
  787. var bitrate = notification.VideoDeviceOutputList[i].VideoBitrate;
  788. var minBitrate = notification.VideoDeviceOutputList[i].MinVideoBitrate;
  789. rtcExtentedData.UserInfos.Add(new RtcUserInfo(enumLiveChannelCategory, userId, userSign, width, height, fps, bitrate, minBitrate));
  790. }
  791. }
  792. return rtcExtentedData;
  793. }
  794. else if (protocol == EnumLiveProtocol.Rtmp)
  795. {
  796. var rtmpExtendedData = new RtmpExtendedData(null, micId, isMute);
  797. if (notification.MergedChannel)
  798. {
  799. if (notification.MergedVideoOutputHeight == 720 && notification.MergedVideoOutputWidth == 1280)
  800. {
  801. rtmpExtendedData.IsMergeChannel = notification.MergedChannel;
  802. rtmpExtendedData.MergeType = EnumMergeType.Merge1280X720;
  803. }
  804. else
  805. {
  806. rtmpExtendedData.IsMergeChannel = notification.MergedChannel;
  807. rtmpExtendedData.MergeType = EnumMergeType.Merge1920X1080;
  808. }
  809. }
  810. else
  811. {
  812. rtmpExtendedData.IsMergeChannel = notification.MergedChannel;
  813. rtmpExtendedData.MergeType = EnumMergeType.None;
  814. }
  815. int cameraNo = 0;
  816. if (notification.VideoDeviceOutputList != null && notification.VideoDeviceOutputList.Count > 0)
  817. {
  818. for (int i = 0; i < notification.VideoDeviceOutputList.Count(); i++)
  819. {
  820. EnumLiveChannelCategory enumLiveChannelCategory;
  821. if (notification.VideoDeviceOutputList[i].LiveData == null)
  822. {
  823. Logger.WriteLineError($"{notification.VideoDeviceOutputList[i].VideoDeviceId}'s RtmpPushUrl is null");
  824. }
  825. var pushUrl = notification.VideoDeviceOutputList[i].LiveData?.RtmpPushUrl;
  826. if (notification.VideoDeviceOutputList[i].VideoDeviceSourceType == VideoDeviceSourceTypeEnum.Desktop)
  827. {
  828. enumLiveChannelCategory = EnumLiveChannelCategory.Main;
  829. }
  830. else
  831. {
  832. switch (cameraNo)
  833. {
  834. case 0:
  835. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary1;
  836. cameraNo++;
  837. break;
  838. case 1:
  839. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary2;
  840. cameraNo++;
  841. break;
  842. case 2:
  843. enumLiveChannelCategory = EnumLiveChannelCategory.Auxiliary3;
  844. cameraNo++;
  845. break;
  846. default:
  847. continue;
  848. }
  849. }
  850. var width = notification.VideoDeviceOutputList[i].OutputWidth;
  851. var height = notification.VideoDeviceOutputList[i].OutputHeight; ;
  852. rtmpExtendedData.UserInfos.Add(new RtmpUserInfo(enumLiveChannelCategory, pushUrl, width, height));
  853. }
  854. }
  855. return rtmpExtendedData;
  856. }
  857. return null;
  858. }
  859. /// <summary>
  860. /// 获取品牌列表
  861. /// </summary>
  862. /// <returns></returns>
  863. public List<string> GetBrandList()
  864. {
  865. return _pusherManager?.GetBrandList();
  866. }
  867. /// <summary>
  868. /// 获取型号列表
  869. /// </summary>
  870. /// <param name="brand"></param>
  871. /// <param name="model"></param>
  872. /// <returns></returns>
  873. public List<string> GetModelList(string brand)
  874. {
  875. return _pusherManager?.GetModelList(brand);
  876. }
  877. /// <summary>
  878. /// 获取推荐分辨率
  879. /// </summary>
  880. /// <param name="brand"></param>
  881. /// <param name="model"></param>
  882. /// <returns></returns>
  883. public DeviceRecommandResolution GetRecommandResolution(string brand, string model)
  884. {
  885. return _pusherManager?.GetRecommandResolution(brand, model);
  886. }
  887. private bool IsDifferent(List<CPVideoDeviceOutputInfo> newVideoDeviceInfos)
  888. {
  889. for (int i = 0; i < newVideoDeviceInfos.Count(); i++)
  890. {
  891. if (newVideoDeviceInfos[i].ToString() != _currentVideoDeviceInfoList[i].ToString())
  892. {
  893. return true;
  894. }
  895. }
  896. return false;
  897. }
  898. private bool IsDifferent(List<VideoDeviceOutputInfoDTO> newVideoDeviceInfos)
  899. {
  900. for (int i = 0; i < newVideoDeviceInfos.Count(); i++)
  901. {
  902. if (newVideoDeviceInfos[i].ToString() != _currentOutputVideoInfoList[i].ToString())
  903. {
  904. return true;
  905. }
  906. }
  907. return false;
  908. }
  909. public void ChangeRealTimeCaptureSetting(bool isStart)
  910. {
  911. LiveVideoStatusChecker.Instance.IsRealTimeCapturing = isStart;
  912. _previewManager.ChangeRealTimeCaptureSetting(isStart);
  913. }
  914. public void CaptureCurrentImage()
  915. {
  916. _realtimeCaptureManager?.CaptureCurrentImage();
  917. }
  918. public void StartRecordVideo()
  919. {
  920. _realtimeCaptureManager?.StartRecordVideo();
  921. }
  922. public void StopRecordVideo(bool isTimeOut)
  923. {
  924. _realtimeCaptureManager?.StopRecordVideo(isTimeOut);
  925. }
  926. public CPBase64ImageData GetCurrentCaptureFrame()
  927. {
  928. if (_isMainLiveVideoDisabled)
  929. {
  930. return new CPBase64ImageData(0, 0, "", EnumFailReasonForNullBase64Data.LiveVideoIsDisabled);
  931. }
  932. return _realtimeCaptureManager?.GetCurrentCaptureFrame();
  933. }
  934. }
  935. }