ConsultationLiveVideoProvider.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Vinno.FIS.TRTCClient.Common.Enum;
  6. using Vinno.FIS.TRTCClient.Common.Models;
  7. using Vinno.IUS.Common.Log;
  8. using Vinno.IUS.Common.Network.Leaf;
  9. using Vinno.vCloud.Common.FIS.Helper;
  10. using Vinno.vCloud.FIS.CrossPlatform.Common;
  11. using Vinno.vCloud.FIS.CrossPlatform.Common.Consultation;
  12. using Vinno.vCloud.FIS.CrossPlatform.Common.Consultation.Interface;
  13. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  14. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  15. using Vinno.vCloud.Protocol.Infrastructures;
  16. using Vinno.vCloud.Protocol.Messages.Live;
  17. namespace Vinno.vCloud.Common.FIS.Consultation
  18. {
  19. internal class ConsultationLiveVideoProvider : IDisposable
  20. {
  21. private readonly object _lock = new object();
  22. private readonly object _startConsultationLocker = new object();//Felix之所以加这个lock,会有Start没跑完就Stop的情况。
  23. private readonly IImageHelper _imageHelper;
  24. private readonly List<VideoProvider> _videoProviders;
  25. private IRtcRoom _rtcRoom;
  26. private IRtmpPlayer _terminalMergePlayer; //拉超声机图像与摄像机流
  27. private IRtmpPlayer _terminalVideoPlayer; //拉超声机图像流
  28. private IRtmpPlayer _terminalCameraPlayer; //拉超声机摄像机流
  29. private bool _isConsulting;
  30. private LiveProtocol _liveProtocol;
  31. private string _accountId;
  32. private ConsultationInfo _consultationInfo;
  33. private CPVideoFrameData _terminalVideoFrameData;
  34. private CPVideoFrameData _cameraVideoFrameData;
  35. private CPVideoFrameData _rtcTerminaVideoFrameData;
  36. private CPVideoFrameData _completeVideoFrameData;
  37. private int _videoBufferSize = 300;
  38. private int _imagePreviewErrorLogCount;
  39. //单路超声机数据缓存区
  40. private byte[] _rtcTerminalLiveDataBuffer;
  41. private LiveDataBytes _liveDataBytes = new LiveDataBytes();
  42. private TerminalLiveDataBytes _termialLiveDataBytes = new TerminalLiveDataBytes();
  43. public event EventHandler<EnumTRTCRoomError> OnTRTCRoomEnterError;
  44. /// <summary>
  45. /// 本地的摄像头数据
  46. /// </summary>
  47. public event EventHandler<ConsultationVideoFrameData> ConsultationLocalVideoFrameArrived;
  48. /// <summary>
  49. /// 其余所有用户的摄像头数据
  50. /// </summary>
  51. public event EventHandler<ConsultationVideoFrameData> ConsultationRemoteVideoFrameArrived;
  52. /// <summary>
  53. /// 超声机画面
  54. /// </summary>
  55. public event EventHandler<CPVideoFrameData> TerminalImageFrameArrived;
  56. /// <summary>
  57. /// 超声机摄像头画面
  58. /// </summary>
  59. public event EventHandler<CPVideoFrameData> TerminalCameraFrameArrived;
  60. public event EventHandler<RefreshStatus> TerminalRefreshCaseHappened;
  61. public event EventHandler<CPLiveStatusData> CameraLiveStatusChanged;
  62. public event EventHandler<CPLiveStatusData> TerminalLiveStatusChanged;
  63. public event EventHandler<RemoteUserLeaveRoomArgs> RemoteUserLeaveRoomArrived;
  64. public event EventHandler CloseConsultation;
  65. public event EventHandler TryToReconnect;
  66. public ConsultationLiveVideoProvider()
  67. {
  68. _videoProviders = new List<VideoProvider>();
  69. _imageHelper = CrossPlatformHelper.Instance.ImageHelperCreator.CreateImageHelper();
  70. }
  71. /// <summary>
  72. /// 开始会诊
  73. /// </summary>
  74. /// <param name="consultationInfo"></param>
  75. public void StartConsultationVideo(ConsultationInfo consultationInfo, string accountId, string accountName, string videoDeviceId, string micDeviceId, string speakerDeviceId, ClientLeaf leaf)
  76. {
  77. if (_isConsulting)
  78. {
  79. return;
  80. }
  81. lock (_startConsultationLocker)
  82. {
  83. _isConsulting = true;
  84. _liveProtocol = consultationInfo.LiveProtocol;
  85. _accountId = accountId;
  86. _consultationInfo = consultationInfo;
  87. var terminalInfo = consultationInfo.TerminalInfo;
  88. var consultationMembers = consultationInfo.ConsultationMemberInfos;
  89. if (consultationInfo.LiveTalkingMode == Protocol.Messages.Client.LiveTalking.LiveTalkingMode.Speech)
  90. {
  91. videoDeviceId = string.Empty;
  92. }
  93. if (_liveProtocol == LiveProtocol.RTC)
  94. {
  95. if (consultationInfo.State == LiveStates.OK)
  96. {
  97. foreach (var member in consultationMembers)
  98. {
  99. if (member.Id == _accountId)
  100. {
  101. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  102. if (videoProvider == null)
  103. {
  104. Logger.WriteLineInfo($"Start To Create RTC Video Provider, Name:{member.Name},Id:{member.Id}");
  105. _videoProviders.Add(new RtcVideoProvider(member));
  106. }
  107. else
  108. {
  109. Logger.WriteLineInfo($"RTC Video Provider Already exist, Name:{member.Name},Id:{member.Id}");
  110. videoProvider.ConsultationMemberInfo = member;
  111. }
  112. var userSign = member.UserSign;
  113. var integerRoomId = consultationInfo.IntegerRoomId;
  114. var appId = consultationInfo.AppId;
  115. var mode = consultationInfo.LiveTalkingMode;
  116. _rtcRoom = CrossPlatformHelper.Instance.RtcRoomCreator.CreateRtcRoom();
  117. _rtcRoom.LocalVideoFrameArrived += OnRtcLocalVideoFrameArrived;
  118. _rtcRoom.RemoteVideoFrameArrived += OnRtcRemoteVideoFrameArrived;
  119. _rtcRoom.OnTRTCRoomEnterError += OnTRTCRoomEnterErrorHappened;
  120. _rtcRoom.RemoteUserLeaveRoomArrived += OnRemoteUserLeaveRoomArrived;
  121. _rtcRoom.TryToReconnect += OnTryToReconnect;
  122. var roomInfo = new TRTCRoomInfo
  123. {
  124. AppId = (uint)appId,
  125. UserSig = userSign,
  126. UserId = accountId,
  127. RoomId = (uint)integerRoomId,
  128. VideoDeviceId = videoDeviceId,
  129. MicDeviceId = micDeviceId,
  130. SpeakerDeviceId = speakerDeviceId,
  131. TerminalIsPushing = _consultationInfo.TerminalInfo?.State == LiveStates.OK,
  132. TerminalId = _consultationInfo.TerminalInfo?.Id,
  133. CameraId = _consultationInfo.TerminalInfo?.CameraId,
  134. IsMultiChannel = _consultationInfo.TerminalInfo == null ? false : _consultationInfo.TerminalInfo.IsMultiChannels,
  135. TerminalRoomId = (uint)_consultationInfo.TerminalInfo?.TerminalIntegerRoomId,
  136. IsLiveMode = false,
  137. IsOldServerMode = true,
  138. Category = EnumLiveChannelCategory.Main,
  139. };
  140. _rtcRoom.Enter(roomInfo);
  141. Logger.WriteLineInfo($"{accountName} enterred room {integerRoomId}");
  142. }
  143. else
  144. {
  145. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  146. if (videoProvider == null)
  147. {
  148. Logger.WriteLineInfo($"Start To Create RTC Video Provider, Name:{member.Name},Id:{member.Id}");
  149. _videoProviders.Add(new RtcVideoProvider(member));
  150. }
  151. else
  152. {
  153. Logger.WriteLineInfo($"RTC Video Provider Already exist, Name:{member.Name},Id:{member.Id}");
  154. videoProvider.ConsultationMemberInfo = member;
  155. }
  156. }
  157. }
  158. }
  159. }
  160. else if (_liveProtocol == LiveProtocol.Rtmp)
  161. {
  162. foreach (var member in consultationMembers)
  163. {
  164. if (member.Id == _accountId)
  165. {
  166. RtmpVideoPusher rtmpVideoPusher = null;
  167. try
  168. {
  169. var pusherUrl = member.PushUrl;
  170. if (!string.IsNullOrEmpty(pusherUrl))
  171. {
  172. Logger.WriteLineInfo($"Start push with rtmp address {pusherUrl}");
  173. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  174. if (videoProvider == null)
  175. {
  176. Logger.WriteLineInfo($"Start To Create Rtmp Video Pusher, Name:{member.Name},Id:{member.Id}");
  177. rtmpVideoPusher = new RtmpVideoPusher(member, videoDeviceId, micDeviceId);
  178. rtmpVideoPusher.VideoFrameArrived += OnLocalVideoFrameArrived;
  179. _videoProviders.Add(rtmpVideoPusher);
  180. if (member.State == LiveStates.OK)
  181. {
  182. rtmpVideoPusher.StartConnectionKeeper(consultationInfo.RoomId, accountId, leaf);
  183. rtmpVideoPusher.Offlined += OnOfflined;
  184. }
  185. }
  186. else
  187. {
  188. Logger.WriteLineInfo($"Rtmp video Pusher already exists,Name:{member.Name},Id:{member.Id}");
  189. videoProvider.ConsultationMemberInfo = member;
  190. }
  191. }
  192. }
  193. catch (Exception ex)
  194. {
  195. Logger.WriteLineError($"Exception happened while play rtmp{ex}");
  196. }
  197. }
  198. else
  199. {
  200. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  201. if (videoProvider == null)
  202. {
  203. Logger.WriteLineInfo($"Start To Create Rtmp Player,Name:{member.Name},Id:{member.Id}");
  204. CreateRtmpPlayer(member);
  205. }
  206. else
  207. {
  208. Logger.WriteLineInfo($"Rtmp Player already exists,Name:{member.Name},Id:{member.Id}");
  209. videoProvider.ConsultationMemberInfo = member;
  210. }
  211. }
  212. }
  213. }
  214. if (terminalInfo.TerminalLiveProtocol == LiveProtocol.RTC)
  215. {
  216. Logger.WriteLineInfo($"Wait for terminal state arriving, then start cross-room communication");
  217. terminalInfo.IsSupportRtc = true;
  218. //if (terminalInfo.State == LiveStates.OK)
  219. //{
  220. // Logger.WriteLineInfo($"Connect terminal room when already pushing- {terminalInfo.IntegerRoomId}-{terminalInfo.Id}");
  221. // _rtcRoom.ConnectRoom((uint)terminalInfo.IntegerRoomId, terminalInfo.Id);
  222. //}
  223. //var isAvailableTerminal = terminalInfo?.State != LiveStates.TerminalOffLine;
  224. //if (isAvailableTerminal)
  225. //{
  226. // var isRecipient = consultationInfo?.ChatRole == ChatRole.Recipient;
  227. // //ResetTheTerminalLiveStatusWatcher(isRecipient, true);
  228. //}
  229. }
  230. else if (terminalInfo.TerminalLiveProtocol == LiveProtocol.Rtmp && terminalInfo.State == LiveStates.OK)
  231. {
  232. var terminalUrl = terminalInfo.TerminalUrl;
  233. Logger.WriteLineInfo($"Start to create ultrasouind player,Name{terminalInfo?.Name},TerminalUrl:{terminalUrl}");
  234. if (terminalInfo.IsMergeChannel)
  235. {
  236. if (!string.IsNullOrEmpty(terminalUrl))
  237. {
  238. _terminalMergePlayer = CrossPlatformHelper.Instance.RtmpPlayerCreator.CreateLivePlayer(terminalUrl);
  239. _terminalMergePlayer.Buffer = _videoBufferSize;
  240. _terminalMergePlayer.VideoFrameReceived += OnRtmpUltrasoundMergeImageFrameReceived;
  241. _terminalMergePlayer.StatusChanged += OnRtmpUltrasoundMergeVideoStatusChanged;
  242. _terminalMergePlayer.Play();
  243. Logger.WriteLineInfo($"{terminalInfo?.Name}: play single merge channel success,terminalUrl:{terminalUrl}");
  244. }
  245. }
  246. else
  247. {
  248. var cameraUrl = terminalInfo.CameraUrl;
  249. if (!string.IsNullOrEmpty(terminalUrl))
  250. {
  251. _terminalVideoPlayer = CrossPlatformHelper.Instance.RtmpPlayerCreator.CreateLivePlayer(terminalUrl);
  252. _terminalVideoPlayer.Buffer = _videoBufferSize;
  253. _terminalVideoPlayer.VideoFrameReceived += OnTerminalVideoFrameArrived;
  254. _terminalVideoPlayer.StatusChanged += OnTerminalVideoStatusChanged;
  255. _terminalVideoPlayer.Play();
  256. }
  257. if (!string.IsNullOrEmpty(cameraUrl))
  258. {
  259. _terminalCameraPlayer = CrossPlatformHelper.Instance.RtmpPlayerCreator.CreateLivePlayer(cameraUrl);
  260. _terminalCameraPlayer.Buffer = _videoBufferSize;
  261. _terminalCameraPlayer.VideoFrameReceived += OnTerminalCameraFrameArrived;
  262. _terminalCameraPlayer.StatusChanged += OnTerminalCameraVideoStatusChanged;
  263. _terminalCameraPlayer.Play();
  264. }
  265. Logger.WriteLineInfo($"{terminalInfo?.Name}: play dual channel success,terminal url {terminalUrl}" +
  266. $",camara url {cameraUrl}");
  267. }
  268. }
  269. }
  270. }
  271. private void OnTerminalVideoFrameArrived(object sender, CPVideoFrameData e)
  272. {
  273. TerminalImageFrameArrived?.Invoke(this, e);
  274. }
  275. private void OnTerminalCameraFrameArrived(object sender, CPVideoFrameData e)
  276. {
  277. TerminalCameraFrameArrived?.Invoke(this, e);
  278. }
  279. private void OnRtcLocalVideoFrameArrived(object sender, CPVideoFrameData e)
  280. {
  281. var consultationMembers = _consultationInfo.ConsultationMemberInfos;
  282. var consultationMember = consultationMembers.FirstOrDefault(x => x.Id == _accountId);
  283. if (consultationMember != null)
  284. {
  285. OnLocalVideoFrameArrived(this, new ConsultationVideoFrameData(e, consultationMember));
  286. }
  287. }
  288. private void OnLocalVideoFrameArrived(object sender, ConsultationVideoFrameData e)
  289. {
  290. ConsultationLocalVideoFrameArrived?.Invoke(this, e);
  291. }
  292. private void OnRtcRemoteVideoFrameArrived(object sender, CPRemoteVideoFrameData e)
  293. {
  294. try
  295. {
  296. if (_consultationInfo != null)
  297. {
  298. var terminalInfo = _consultationInfo.TerminalInfo;
  299. if (terminalInfo == null)
  300. {
  301. return;
  302. }
  303. var terminaId = terminalInfo.Id;
  304. var cameraId = terminalInfo.CameraId;
  305. if (terminalInfo.IsMultiChannels && terminalInfo.PullDataMode == LiveDataMode.OnlyLive)
  306. {
  307. if (e.UserId == terminaId)
  308. {
  309. OnTerminalVideoFrameArrived(sender, e.Data);
  310. }
  311. else if (!string.IsNullOrEmpty(cameraId) && e.UserId == cameraId)
  312. {
  313. OnTerminalCameraFrameArrived(sender, e.Data);
  314. }
  315. else
  316. {
  317. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == e.UserId);
  318. if (videoProvider != null)
  319. {
  320. OnVideoFrameArrived(videoProvider, e.Data);
  321. }
  322. }
  323. }
  324. else
  325. {
  326. if (terminaId == e.UserId)
  327. {
  328. var remoteTerminalRawData = e.Data;
  329. int terminalCompleteWidth = terminalInfo.TerminalWidth;
  330. int terminalCompleteHeight = terminalInfo.TerminalHeight;
  331. int cameraCompleteWidth = terminalInfo.CameraWidth;
  332. int cameraCompleteHeight = terminalInfo.CameraHeight;
  333. byte[] terminalData;
  334. byte[] cameraData;
  335. var terminalBytes = terminalCompleteWidth * terminalCompleteHeight * 4;
  336. var cameraBytes = cameraCompleteWidth * cameraCompleteHeight * 4;
  337. var isMergeImage = terminalInfo.CameraLiveEnabled && terminalInfo.TerminalLiveEnabled;
  338. if (isMergeImage)
  339. {
  340. _termialLiveDataBytes.Update(remoteTerminalRawData.Data, terminalBytes, cameraBytes,
  341. terminalCompleteWidth, terminalCompleteHeight, remoteTerminalRawData.Width, _imageHelper.OSType);
  342. }
  343. else
  344. {
  345. if (terminalInfo.CameraLiveEnabled)
  346. {
  347. OnTerminalCameraFrameArrived(sender, e.Data);
  348. return;
  349. }
  350. if (terminalInfo.TerminalLiveEnabled)
  351. {
  352. var usWidth = terminalInfo.TerminalWidth;
  353. var usHeight = terminalInfo.TerminalHeight;
  354. var terminallength = usWidth * usHeight * 4;
  355. if (_rtcTerminalLiveDataBuffer == null)
  356. {
  357. _rtcTerminalLiveDataBuffer = new byte[terminallength];
  358. }
  359. else if (terminallength != _rtcTerminalLiveDataBuffer.Length)
  360. {
  361. Array.Resize(ref _rtcTerminalLiveDataBuffer, terminallength);
  362. }
  363. if (_rtcTerminalLiveDataBuffer.Length <= e.Data.Data.Length)
  364. {
  365. switch (_imageHelper?.OSType)
  366. {
  367. case EnumClientOSType.PC:
  368. ParallelOptions parallelOptions = new ParallelOptions
  369. {
  370. MaxDegreeOfParallelism = 10
  371. };
  372. Parallel.For(0, usHeight, parallelOptions, row =>
  373. {
  374. Array.Copy(e.Data.Data, row * e.Data.Width * 4, _rtcTerminalLiveDataBuffer, row * usWidth * 4, usWidth * 4);
  375. });
  376. break;
  377. case EnumClientOSType.Android:
  378. for (int row = 0; row < usHeight; row++)
  379. {
  380. Array.Copy(e.Data.Data, row * e.Data.Width * 4, _rtcTerminalLiveDataBuffer, row * usWidth * 4, usWidth * 4);
  381. }
  382. break;
  383. }
  384. }
  385. else
  386. {
  387. if (_imagePreviewErrorLogCount++ < 1)
  388. {
  389. Logger.WriteLineError($"rtcTerminalLiveDataBuffer is small than terminal data size, " +
  390. $"terminal width:{terminalInfo.TerminalWidth}, terminal height:{terminalInfo.TerminalHeight}" +
  391. $",terminal array length:{terminallength} " +
  392. $"destination array length: {_rtcTerminalLiveDataBuffer.Length}, data size: {e.Data.Width}*{e.Data.Height}");
  393. }
  394. }
  395. ResizeVideoFrameData(ref _terminalVideoFrameData, usWidth, usHeight, _rtcTerminalLiveDataBuffer);
  396. OnTerminalVideoFrameArrived(sender, _terminalVideoFrameData);
  397. return;
  398. }
  399. }
  400. terminalData = _termialLiveDataBytes.TerminalData;
  401. cameraData = _termialLiveDataBytes.CameraData;
  402. var needCameraData = terminalInfo.CameraLiveEnabled;
  403. if (terminalData != null)
  404. {
  405. ResizeVideoFrameData(ref _terminalVideoFrameData, terminalCompleteWidth, terminalCompleteHeight, terminalData, remoteTerminalRawData.ImageData);
  406. OnTerminalVideoFrameArrived(sender, _terminalVideoFrameData);
  407. }
  408. if (needCameraData)
  409. {
  410. OnTerminalCameraFrameArrived(sender, new CPVideoFrameData(cameraCompleteWidth, cameraCompleteHeight, cameraData));
  411. }
  412. }
  413. else
  414. {
  415. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == e.UserId);
  416. if (videoProvider != null)
  417. {
  418. OnVideoFrameArrived(videoProvider, e.Data);
  419. }
  420. }
  421. }
  422. }
  423. _imagePreviewErrorLogCount = 0;
  424. }
  425. catch (Exception ex)
  426. {
  427. if (_imagePreviewErrorLogCount++ < 1)
  428. {
  429. Logger.WriteLineError($"destination array length: {_rtcTerminalLiveDataBuffer?.Length}, data size: {e?.Data?.Width}*{e?.Data?.Height}");
  430. Logger.WriteLineError($"OnRtcRemoteVideoFrameArrived ex:{ex}");
  431. }
  432. }
  433. }
  434. private void OnVideoFrameArrived(VideoProvider videoProvider, CPVideoFrameData e)
  435. {
  436. OnRemoteVideoFrameArrived(this, new ConsultationVideoFrameData(e, videoProvider.ConsultationMemberInfo));
  437. }
  438. private void OnTRTCRoomEnterErrorHappened(object sender, EnumTRTCRoomError e)
  439. {
  440. OnTRTCRoomEnterError?.Invoke(sender, e);
  441. }
  442. private void ResizeVideoFrameData(ref CPVideoFrameData videoFrameData, int width, int height, byte[] data, object imageData = null)
  443. {
  444. if (videoFrameData == null)
  445. {
  446. videoFrameData = new CPVideoFrameData(width, height, data) { ImageData = imageData };
  447. }
  448. else
  449. {
  450. videoFrameData.Width = width;
  451. videoFrameData.Height = height;
  452. videoFrameData.Data = data;
  453. videoFrameData.ImageData = imageData;
  454. }
  455. }
  456. private void OnTryToReconnect(object sender, EventArgs e)
  457. {
  458. TryToReconnect?.Invoke(this, EventArgs.Empty);
  459. }
  460. private void OnOfflined(object sender, EventArgs e)
  461. {
  462. CloseConsultation?.Invoke(sender, e);
  463. }
  464. private void CreateRtmpPlayer(ConsultationMemberInfo consultationMember)
  465. {
  466. var rtmpVideoProvider = new RtmpVideoProvider(consultationMember);
  467. rtmpVideoProvider.VideoFrameArrived += OnRemoteVideoFrameArrived;
  468. _videoProviders.Add(rtmpVideoProvider);
  469. }
  470. private void OnRemoteVideoFrameArrived(object sender, ConsultationVideoFrameData e)
  471. {
  472. ConsultationRemoteVideoFrameArrived?.Invoke(this, e);
  473. }
  474. private void OnRemoteUserLeaveRoomArrived(object sender, RemoteUserLeaveRoomArgs e)
  475. {
  476. RemoteUserLeaveRoomArrived?.Invoke(this, e);
  477. }
  478. private void OnRtmpUltrasoundMergeImageFrameReceived(object sender, CPVideoFrameData e)
  479. {
  480. try
  481. {
  482. var terminal = _consultationInfo.TerminalInfo;
  483. var needCameraData = terminal.CameraLiveEnabled;
  484. var liveProtocol = terminal.TerminalLiveProtocol;
  485. if (terminal != null)
  486. {
  487. if (terminal.TerminalLiveEnabled && terminal.CameraLiveEnabled)
  488. {
  489. int terminalCompleteWidth = terminal.TerminalWidth;
  490. int terminalCompleteHeight = terminal.TerminalHeight;
  491. int cameraCompleteWidth = terminal.CameraWidth;
  492. int cameraCompleteHeight = terminal.CameraHeight;
  493. byte[] terminalData;
  494. byte[] cameraData;
  495. if (liveProtocol == LiveProtocol.RTC)
  496. {
  497. var terminalBytes = terminalCompleteWidth * terminalCompleteHeight * 4;
  498. var cameraBytes = cameraCompleteWidth * cameraCompleteHeight * 4;
  499. _termialLiveDataBytes.Update(e.Data, terminalBytes, cameraBytes,
  500. terminalCompleteWidth, terminalCompleteHeight, e.Width, _imageHelper.OSType);
  501. terminalData = _termialLiveDataBytes.TerminalData;
  502. cameraData = _termialLiveDataBytes.CameraData;
  503. }
  504. else
  505. {
  506. _imageHelper.SplitImageData(ref _liveDataBytes, e, terminalCompleteWidth, terminalCompleteHeight, cameraCompleteWidth, cameraCompleteHeight, needCameraData);
  507. terminalData = _liveDataBytes.TerminalData;
  508. cameraData = _liveDataBytes.CameraData;
  509. }
  510. if (terminalData != null)
  511. {
  512. ResizeVideoFrameData(ref _completeVideoFrameData, terminalCompleteWidth, terminalCompleteHeight, terminalData, e.ImageData);
  513. OnTerminalVideoFrameArrived(sender, _completeVideoFrameData);
  514. }
  515. if (needCameraData)
  516. {
  517. if (cameraData != null)
  518. {
  519. ResizeVideoFrameData(ref _cameraVideoFrameData, cameraCompleteWidth, cameraCompleteHeight, cameraData);
  520. OnTerminalCameraFrameArrived(sender, _cameraVideoFrameData);
  521. }
  522. }
  523. }
  524. else if (terminal.TerminalLiveEnabled && !terminal.CameraLiveEnabled)
  525. {
  526. var width = terminal.TerminalWidth;
  527. var height = terminal.TerminalHeight;
  528. if (liveProtocol == LiveProtocol.RTC && width > 0 && height > 0)
  529. {
  530. var terminallength = width * height * 4;
  531. if (_rtcTerminalLiveDataBuffer == null)
  532. {
  533. _rtcTerminalLiveDataBuffer = new byte[terminallength];
  534. }
  535. else if (terminallength != _rtcTerminalLiveDataBuffer.Length)
  536. {
  537. Array.Resize(ref _rtcTerminalLiveDataBuffer, terminallength);
  538. }
  539. if (_rtcTerminalLiveDataBuffer.Length >= terminallength)
  540. {
  541. for (int row = 0; row < height; row++)
  542. {
  543. Array.Copy(e.Data, row * e.Width * 4, _rtcTerminalLiveDataBuffer, row * width * 4, width * 4);
  544. }
  545. }
  546. else
  547. {
  548. if (_imagePreviewErrorLogCount++ < 1)
  549. {
  550. Logger.WriteLineError($"rtcTerminalLiveDataBuffer is small than terminal data size, " +
  551. $"terminal width:{terminal.TerminalWidth}, " +
  552. $"terminal height:{terminal.TerminalHeight},terminal array length:{terminallength} " +
  553. $"destination array length: {_rtcTerminalLiveDataBuffer.Length}, data size {e.Width}*{e.Height}");
  554. }
  555. }
  556. ResizeVideoFrameData(ref _rtcTerminaVideoFrameData, width, height, _rtcTerminalLiveDataBuffer);
  557. OnTerminalVideoFrameArrived(sender, _rtcTerminaVideoFrameData);
  558. }
  559. else
  560. {
  561. OnTerminalVideoFrameArrived(sender, e);
  562. }
  563. }
  564. else if (terminal.CameraLiveEnabled && !terminal.TerminalLiveEnabled)
  565. {
  566. OnTerminalCameraFrameArrived(sender, e);
  567. }
  568. _imagePreviewErrorLogCount = 0;
  569. }
  570. }
  571. catch (Exception ex)
  572. {
  573. if (_imagePreviewErrorLogCount++ < 1)
  574. {
  575. Logger.WriteLineError($"destination array length: {_rtcTerminalLiveDataBuffer?.Length}, data size: {e?.Width}*{e?.Height}");
  576. Logger.WriteLineError($"OnPreviewImageReceived ex:{ex}");
  577. }
  578. }
  579. }
  580. /// <summary>
  581. /// 会诊人员发生变化
  582. /// </summary>
  583. public void ConsultationMemberChange(MeetingMemberNotification meetingChangeMember)
  584. {
  585. var members = meetingChangeMember.Members;
  586. if (_liveProtocol == LiveProtocol.RTC)
  587. {
  588. foreach (var member in members)
  589. {
  590. var memberInfo = DTOConverter.ConvertMeetingMemberInfoMessageToMeetingMemberInfo(member);
  591. if (member.OperationType == ClientMessageOperationType.Add)
  592. {
  593. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  594. if (videoProvider == null)
  595. {
  596. _videoProviders.Add(new RtcVideoProvider(memberInfo));
  597. }
  598. else
  599. {
  600. videoProvider.ConsultationMemberInfo = memberInfo;
  601. }
  602. }
  603. else if (member.OperationType == ClientMessageOperationType.Delete)
  604. {
  605. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  606. if (videoProvider != null)
  607. {
  608. videoProvider.Dispose();
  609. _videoProviders.Remove(videoProvider);
  610. }
  611. }
  612. }
  613. }
  614. else if (_liveProtocol == LiveProtocol.Rtmp)
  615. {
  616. foreach (var member in members)
  617. {
  618. var memberInfo = DTOConverter.ConvertMeetingMemberInfoMessageToMeetingMemberInfo(member);
  619. if (member.OperationType == ClientMessageOperationType.Add)
  620. {
  621. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  622. if (videoProvider == null)
  623. {
  624. CreateRtmpPlayer(memberInfo);
  625. }
  626. else
  627. {
  628. videoProvider.ConsultationMemberInfo = memberInfo;
  629. }
  630. }
  631. else if (member.OperationType == ClientMessageOperationType.Delete)
  632. {
  633. var videoProvider = _videoProviders.FirstOrDefault(f => f.ConsultationMemberInfo.Id == member.Id);
  634. if (videoProvider != null)
  635. {
  636. videoProvider.Dispose();
  637. _videoProviders.Remove(videoProvider);
  638. }
  639. }
  640. }
  641. }
  642. }
  643. public void RemoveVideoProvider(string userId)
  644. {
  645. lock (_startConsultationLocker)
  646. {
  647. if (_videoProviders.Count > 0)
  648. {
  649. var video = _videoProviders.FirstOrDefault(v => v.ConsultationMemberInfo.Id == userId);
  650. if (video != null)
  651. {
  652. video.Dispose();
  653. _videoProviders.Remove(video);
  654. }
  655. if (_liveProtocol == LiveProtocol.RTC)
  656. {
  657. if (_videoProviders.Count <= 1)
  658. {
  659. _rtcRoom.LocalVideoFrameArrived -= OnRtcLocalVideoFrameArrived;
  660. _rtcRoom.RemoteVideoFrameArrived -= OnRtcRemoteVideoFrameArrived;
  661. _rtcRoom.TryToReconnect -= OnTryToReconnect;
  662. _rtcRoom.RemoteUserLeaveRoomArrived -= OnRemoteUserLeaveRoomArrived;
  663. _rtcRoom.Exit();
  664. for (int i = _videoProviders.Count - 1; i >= 0; i--)
  665. {
  666. _videoProviders[i].Dispose();
  667. }
  668. _videoProviders.Clear();
  669. }
  670. }
  671. else if (_liveProtocol == LiveProtocol.Rtmp)
  672. {
  673. if (_videoProviders.Count <= 1)
  674. {
  675. for (int i = _videoProviders.Count - 1; i >= 0; i--)
  676. {
  677. UnregisterReference(_videoProviders[i]);
  678. _videoProviders[i].Dispose();
  679. }
  680. _videoProviders.Clear();
  681. }
  682. }
  683. if (_videoProviders.Count == 0)
  684. {
  685. if (_terminalMergePlayer != null)
  686. {
  687. _terminalMergePlayer.VideoFrameReceived -= OnRtmpUltrasoundMergeImageFrameReceived;
  688. _terminalMergePlayer.StatusChanged -= OnRtmpUltrasoundMergeVideoStatusChanged;
  689. _terminalMergePlayer.Stop();
  690. _terminalMergePlayer = null;
  691. }
  692. if (_terminalVideoPlayer != null)
  693. {
  694. _terminalVideoPlayer.VideoFrameReceived -= OnTerminalVideoFrameArrived;
  695. _terminalVideoPlayer.StatusChanged -= OnTerminalVideoStatusChanged;
  696. _terminalVideoPlayer.Stop();
  697. _terminalVideoPlayer = null;
  698. }
  699. if (_terminalCameraPlayer != null)
  700. {
  701. _terminalCameraPlayer.VideoFrameReceived -= OnTerminalCameraFrameArrived;
  702. _terminalCameraPlayer.StatusChanged -= OnTerminalCameraVideoStatusChanged;
  703. _terminalCameraPlayer.Stop();
  704. _terminalCameraPlayer = null;
  705. }
  706. }
  707. }
  708. }
  709. }
  710. private void OnRtmpUltrasoundMergeVideoStatusChanged(object sender, CPLiveStatusData e)
  711. {
  712. var terminalInfo = _consultationInfo?.TerminalInfo;
  713. if (terminalInfo.TerminalLiveEnabled)
  714. {
  715. OnTerminalVideoStatusChanged(this, e);
  716. }
  717. if (terminalInfo.CameraLiveEnabled)
  718. {
  719. OnTerminalCameraVideoStatusChanged(this, e);
  720. }
  721. }
  722. private void OnTerminalCameraVideoStatusChanged(object sender, CPLiveStatusData e)
  723. {
  724. CameraLiveStatusChanged?.Invoke(this, e);
  725. }
  726. private void OnTerminalVideoStatusChanged(object sender, CPLiveStatusData e)
  727. {
  728. TerminalLiveStatusChanged?.Invoke(this, e);
  729. }
  730. /// <summary>
  731. /// 挂断
  732. /// </summary>
  733. public void Hangup()
  734. {
  735. if (!_isConsulting)
  736. {
  737. return;
  738. }
  739. lock (_startConsultationLocker)
  740. {
  741. try
  742. {
  743. if (_isConsulting)
  744. {
  745. if (_videoProviders.Count > 0)
  746. {
  747. if (_liveProtocol == LiveProtocol.RTC)
  748. {
  749. _rtcRoom.LocalVideoFrameArrived -= OnRtcLocalVideoFrameArrived;
  750. _rtcRoom.RemoteVideoFrameArrived -= OnRtcRemoteVideoFrameArrived;
  751. _rtcRoom.TryToReconnect -= OnTryToReconnect;
  752. _rtcRoom.RemoteUserLeaveRoomArrived -= OnRemoteUserLeaveRoomArrived;
  753. _rtcRoom.Exit();
  754. for (int i = _videoProviders.Count - 1; i >= 0; i--)
  755. {
  756. _videoProviders[i].Dispose();
  757. }
  758. _videoProviders.Clear();
  759. }
  760. else if (_liveProtocol == LiveProtocol.Rtmp)
  761. {
  762. for (int i = _videoProviders.Count - 1; i >= 0; i--)
  763. {
  764. var videoProvider = _videoProviders[i];
  765. UnregisterReference(videoProvider);
  766. videoProvider.Dispose();
  767. }
  768. _videoProviders.Clear();
  769. }
  770. }
  771. if (_terminalMergePlayer != null)
  772. {
  773. _terminalMergePlayer.VideoFrameReceived -= OnRtmpUltrasoundMergeImageFrameReceived;
  774. _terminalMergePlayer.Stop();
  775. _terminalMergePlayer = null;
  776. }
  777. if (_terminalVideoPlayer != null)
  778. {
  779. _terminalVideoPlayer.VideoFrameReceived -= OnTerminalVideoFrameArrived;
  780. _terminalVideoPlayer.Stop();
  781. _terminalVideoPlayer = null;
  782. }
  783. if (_terminalCameraPlayer != null)
  784. {
  785. _terminalCameraPlayer.VideoFrameReceived -= OnTerminalCameraFrameArrived;
  786. _terminalCameraPlayer.Stop();
  787. _terminalCameraPlayer = null;
  788. }
  789. }
  790. }
  791. catch (Exception ex)
  792. {
  793. Logger.WriteLineInfo($"Hangup failed ex: {ex}");
  794. }
  795. finally
  796. {
  797. _isConsulting = false;
  798. }
  799. }
  800. }
  801. private void UnregisterReference(VideoProvider videoProvider)
  802. {
  803. if (videoProvider.ConsultationMemberInfo.Id == _accountId)
  804. {
  805. videoProvider.VideoFrameArrived -= OnLocalVideoFrameArrived;
  806. videoProvider.Offlined -= OnOfflined;
  807. }
  808. else
  809. {
  810. videoProvider.VideoFrameArrived -= OnRemoteVideoFrameArrived;
  811. videoProvider.Offlined -= OnOfflined;
  812. }
  813. }
  814. public void SwitchCamera()
  815. {
  816. lock (_lock)
  817. {
  818. if (_isConsulting && _consultationInfo != null)
  819. {
  820. if (_liveProtocol == LiveProtocol.RTC)
  821. {
  822. _rtcRoom?.SwitchCamera();
  823. }
  824. else
  825. {
  826. var rtmpPusher = (RtmpVideoPusher)_videoProviders.FirstOrDefault(x => x is RtmpVideoPusher);
  827. if (rtmpPusher != null)
  828. {
  829. rtmpPusher.SwitchCamera();
  830. }
  831. }
  832. }
  833. }
  834. }
  835. public void Mute(bool isMute)
  836. {
  837. lock (_lock)
  838. {
  839. if (_isConsulting && _consultationInfo != null)
  840. {
  841. if (_liveProtocol == LiveProtocol.RTC)
  842. {
  843. _rtcRoom?.Mute(isMute);
  844. }
  845. else
  846. {
  847. var rtmpPusher = (RtmpVideoPusher)_videoProviders.FirstOrDefault(x => x is RtmpVideoPusher);
  848. if (rtmpPusher != null)
  849. {
  850. rtmpPusher.SetMute(isMute);
  851. }
  852. }
  853. }
  854. }
  855. }
  856. public void Dispose()
  857. {
  858. Hangup();
  859. }
  860. }
  861. }