VideoProviderV2.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading.Tasks;
  4. using Vinno.FIS.TRTCClient.Common.Enum;
  5. using Vinno.IUS.Common.Log;
  6. using Vinno.vCloud.Common.FIS.LiveVideos;
  7. using Vinno.vCloud.FIS.CrossPlatform.Common;
  8. using Vinno.vCloud.FIS.CrossPlatform.Common.Consultation.Interface;
  9. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  10. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  11. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
  12. using WingInterfaceLibrary.LiveConsultation;
  13. namespace Vinno.vCloud.Common.FIS.Consultation
  14. {
  15. public abstract class VideoProviderV2 : IDisposable
  16. {
  17. private readonly ConsultationVideoFrameData _consultationVideoFrameData;
  18. private readonly object _connectionKeeperLock = new object();
  19. private PushHeartRateKeeperV2 _connectionKeeper;
  20. protected ConsultationMemberInfo _consultationMemberInfo;
  21. protected bool _disposed;
  22. public event EventHandler Offlined;
  23. public ConsultationMemberInfo ConsultationMemberInfo
  24. {
  25. get => _consultationMemberInfo;
  26. set
  27. {
  28. _consultationMemberInfo = value;
  29. }
  30. }
  31. /// <summary>
  32. /// Video frame arrived
  33. /// </summary>
  34. public event EventHandler<ConsultationVideoFrameData> VideoFrameArrived;
  35. public VideoProviderV2(ConsultationMemberInfo consultationMemberInfo)
  36. {
  37. _consultationMemberInfo = consultationMemberInfo;
  38. _consultationVideoFrameData = new ConsultationVideoFrameData(null, _consultationMemberInfo);
  39. }
  40. public abstract void Dispose();
  41. protected void UpdateFrame(CPVideoFrameData data)
  42. {
  43. _consultationVideoFrameData.VideoFrameData = data;
  44. VideoFrameArrived?.Invoke(this, _consultationVideoFrameData);
  45. }
  46. public void StartConsultationConnectionKeeper(string token, string consultationCode, int heartRateInterval, ILiveConsultationService liveConsultationService)
  47. {
  48. lock (_connectionKeeperLock)
  49. {
  50. _connectionKeeper = new PushHeartRateKeeperV2(token, consultationCode, heartRateInterval, liveConsultationService);
  51. _connectionKeeper.Offlined += OnOfflined;
  52. _connectionKeeper.Start();
  53. }
  54. }
  55. public void ChangeConsultationCode(string consultationCode)
  56. {
  57. lock (_connectionKeeperLock)
  58. {
  59. if (_connectionKeeper != null)
  60. {
  61. _connectionKeeper.SetHeartRateCode(consultationCode);
  62. Logger.WriteLineInfo($"Consultation Connection Keeper Change Consultation Code {consultationCode}");
  63. }
  64. }
  65. }
  66. private void OnOfflined(object sender, EventArgs e)
  67. {
  68. Offlined?.Invoke(this, e);
  69. Logger.WriteLineInfo($"Connection keeper offline ");
  70. }
  71. internal void DisposeConnectionKeeper()
  72. {
  73. if (_connectionKeeper != null)
  74. {
  75. _connectionKeeper.Offlined -= OnOfflined;
  76. _connectionKeeper.Stop();
  77. _connectionKeeper = null;
  78. }
  79. }
  80. }
  81. public class RtcVideoProviderV2 : VideoProviderV2
  82. {
  83. public RtcVideoProviderV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
  84. {
  85. }
  86. public override void Dispose()
  87. {
  88. if (_disposed)
  89. return;
  90. DisposeConnectionKeeper();
  91. _disposed = true;
  92. }
  93. }
  94. public class RtmpVideoProviderV2 : VideoProviderV2
  95. {
  96. public RtmpVideoProviderV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
  97. {
  98. }
  99. public override void Dispose()
  100. {
  101. if (_disposed)
  102. return;
  103. DisposeConnectionKeeper();
  104. _disposed = true;
  105. }
  106. }
  107. public class RtmpVideoPlayerV2 : VideoProviderV2
  108. {
  109. private IRtmpPlayer _smartPlayer;
  110. private int _videoBufferSize = 300;
  111. private bool _isClosed;
  112. private readonly object _locker = new object();
  113. public RtmpVideoPlayerV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
  114. {
  115. CreateSmartPlayer(consultationMemberInfo.PullRtmpUrl);
  116. }
  117. private void CreateSmartPlayer(string url)
  118. {
  119. if (!string.IsNullOrEmpty(url))
  120. {
  121. _smartPlayer = CrossPlatformHelper.Instance.RtmpPlayerCreator.CreateLivePlayer(url);
  122. _smartPlayer.Buffer = _videoBufferSize;
  123. _smartPlayer.VideoFrameReceived += OnVideoFrameReceived;
  124. Task.Run(async () =>
  125. {
  126. await Task.Delay(3000);
  127. lock (_locker)
  128. {
  129. if (!_isClosed)
  130. {
  131. _smartPlayer.Play();
  132. }
  133. }
  134. });
  135. }
  136. }
  137. private void CloseSmartPlayer()
  138. {
  139. if (_smartPlayer != null)
  140. {
  141. lock (_locker)
  142. {
  143. _isClosed = true;
  144. }
  145. _smartPlayer.VideoFrameReceived -= OnVideoFrameReceived;
  146. _smartPlayer.Stop();
  147. _smartPlayer = null;
  148. }
  149. }
  150. private void OnVideoFrameReceived(object sender, CPVideoFrameData e)
  151. {
  152. UpdateFrame(e);
  153. }
  154. public override void Dispose()
  155. {
  156. if (_disposed)
  157. return;
  158. DisposeConnectionKeeper();
  159. CloseSmartPlayer();
  160. _disposed = true;
  161. }
  162. ~RtmpVideoPlayerV2()
  163. {
  164. }
  165. }
  166. public class RtmpVideoPusherV2 : VideoProviderV2
  167. {
  168. private IRtmpPusherV2 _smartPublisher;
  169. private CPVideoFrameData _videoFrameData;
  170. public RtmpVideoPusherV2(ConsultationMemberInfo consultationMemberInfo, string videoDeviceId, string micDeviceId, bool onlyForRtmpPushing) : base(consultationMemberInfo)
  171. {
  172. var deviceInfo = new CPVideoDeviceOutputInfo
  173. {
  174. VideoDeviceId = videoDeviceId,
  175. IdForServer = "",
  176. VideoDeviceSourceType = EnumVideoDeviceSourceType.Camera,
  177. OutputWidth = 640,
  178. OutputHeight = 480,
  179. Category = EnumLiveChannelCategory.Main,
  180. };
  181. _smartPublisher = CrossPlatformHelper.Instance.RtmpPusherCreator.CreateLivePusherV2(deviceInfo, consultationMemberInfo.PushUrl, micDeviceId, 640, 480);
  182. if (!onlyForRtmpPushing)
  183. {
  184. _smartPublisher.ImageFrameReceived += OnImageFrameReceived;
  185. }
  186. _smartPublisher.Start();
  187. }
  188. ~RtmpVideoPusherV2()
  189. {
  190. }
  191. private void OnImageFrameReceived(object sender, ImageFrameData e)
  192. {
  193. if (_videoFrameData == null)
  194. {
  195. _videoFrameData = new CPVideoFrameData(e.Width, e.Height, new byte[e.Size]);
  196. }
  197. else if (_videoFrameData.Height != e.Height || _videoFrameData.Width != e.Width)
  198. {
  199. _videoFrameData.Height = e.Height;
  200. _videoFrameData.Width = e.Width;
  201. _videoFrameData.Data = new byte[e.Size];
  202. }
  203. Marshal.Copy(e.Data, _videoFrameData.Data, 0, e.Size);
  204. UpdateFrame(_videoFrameData);
  205. }
  206. public override void Dispose()
  207. {
  208. if (_disposed)
  209. return;
  210. LiveVideoStatusChecker.Instance.IsConsultationLivingInCurrentMachine = false;
  211. if (_smartPublisher != null)
  212. {
  213. _smartPublisher.ImageFrameReceived -= OnImageFrameReceived;
  214. _smartPublisher.Stop();
  215. _smartPublisher.Dispose();
  216. _smartPublisher = null;
  217. }
  218. DisposeConnectionKeeper();
  219. _disposed = true;
  220. }
  221. public void SetMute(bool isMute)
  222. {
  223. if (_smartPublisher != null)
  224. {
  225. _smartPublisher.SetMute(isMute);
  226. }
  227. }
  228. public void SwitchCamera()
  229. {
  230. if (_smartPublisher != null)
  231. {
  232. //TODOFelix
  233. }
  234. }
  235. }
  236. }