LiveVideoPusher.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  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.Enum;
  10. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  11. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
  12. using Vinno.vCloud.Protocol.Infrastructures;
  13. using Vinno.vCloud.Protocol.Messages.Client;
  14. using Vinno.vCloud.Protocol.Messages.Live;
  15. namespace Vinno.vCloud.Common.FIS.LiveVideos
  16. {
  17. public abstract class LiveVideoPusher : IDisposable
  18. {
  19. private readonly object _locker = new object();
  20. private readonly object _currentDeviceInfolocker = new object();
  21. private readonly ConcurrentDictionary<EnumPusherType, Func<ILiveVideoPusherForSonopost>> _pusherCreations;
  22. private readonly ClientLeaf _leaf;
  23. private readonly string _terminalId;
  24. private readonly string _terminalName;
  25. private readonly List<CPVideoDeviceInfo> _currentVideoDeviceInfoList;
  26. private IExtendedData _currentExtendData;
  27. private EnumPusherType _currentPushType;
  28. private PushHeartRateKeeper _pushHeartRateKeeper;
  29. private bool _isPaused;
  30. protected ILiveVideoPusherForSonopost _pusher;
  31. /// <summary>
  32. /// 是否正在推流
  33. /// </summary>
  34. public bool IsPushing { get; private set; }
  35. public LiveVideoPusher(ClientLeaf leaf, string terminalId, string terminalName)
  36. {
  37. _leaf = leaf;
  38. _terminalId = terminalId;
  39. _terminalName = terminalName;
  40. _pusherCreations = new ConcurrentDictionary<EnumPusherType, Func<ILiveVideoPusherForSonopost>>();
  41. _currentVideoDeviceInfoList = new List<CPVideoDeviceInfo>();
  42. }
  43. public void UpdateCurrentVideoDeviceInfoList(List<CPVideoDeviceInfo> infos)
  44. {
  45. lock (_currentDeviceInfolocker)
  46. {
  47. _currentVideoDeviceInfoList.Clear();
  48. if (infos != null)
  49. {
  50. foreach (var info in infos)
  51. {
  52. var item = info.Clone() as CPVideoDeviceInfo;
  53. _currentVideoDeviceInfoList.Add(item);
  54. }
  55. }
  56. }
  57. }
  58. /// <summary>
  59. /// 注册具体推流类
  60. /// </summary>
  61. /// <param name="type">推流类型</param>
  62. /// <param name="pusher">推流类的创建方法</param>
  63. public void RegisterPusher(EnumPusherType type, Func<ILiveVideoPusherForSonopost> pusher)
  64. {
  65. _pusherCreations.TryAdd(type, pusher);
  66. }
  67. public void LiveStateChanged(LiveEventArgs e)
  68. {
  69. try
  70. {
  71. if (e.IsLive && IsPushing)
  72. {
  73. Logger.WriteLineError($"LiveVideoPusherV2 LiveStateChanged Error,it is already pushing.");
  74. return;
  75. }
  76. if (e.IsLive)
  77. {
  78. _currentPushType = ConvertToPusherType(e);
  79. Logger.WriteLineInfo($"Current Push Type:{_currentPushType}");
  80. InitPusher(_currentPushType);
  81. StartPusher(e.ExtendedData);
  82. }
  83. else
  84. {
  85. StopPusher(false);
  86. }
  87. }
  88. catch (Exception ex)
  89. {
  90. Logger.WriteLineError($"Receive Live State Error:{ex}");
  91. }
  92. }
  93. public void SetIsPaused(bool isPaused)
  94. {
  95. Logger.WriteLineInfo($"LiveVideoPusher Set IsPaused:{isPaused}");
  96. _isPaused = isPaused;
  97. if (isPaused)
  98. {
  99. StopPusher(isPaused);
  100. }
  101. }
  102. /// <summary>
  103. /// 开始推流
  104. /// </summary>
  105. /// <param name="pushParams"></param>
  106. protected virtual void StartPusher(IExtendedData pushParams)
  107. {
  108. try
  109. {
  110. lock (_locker)
  111. {
  112. if (_isPaused)
  113. {
  114. Logger.WriteLineError("StartPusherError,it is paused");
  115. return;
  116. }
  117. _pusher.ChannelStateChanged += OnChannelStateChanged;
  118. var success = _pusher.StartPusher(pushParams, _currentVideoDeviceInfoList);
  119. if (success)
  120. {
  121. Logger.WriteLineInfo("Start Pusher Success!");
  122. _currentExtendData = pushParams;
  123. IsPushing = true;
  124. LiveVideoStatusChecker.Instance.IsPushing = true;
  125. StartHeartRateKeeper(pushParams);
  126. }
  127. else
  128. {
  129. Logger.WriteLineError("Start Pusher Fail!");
  130. }
  131. }
  132. }
  133. catch (Exception e)
  134. {
  135. Logger.WriteLineError($"Start Pusher Error:{e}");
  136. }
  137. }
  138. /// <summary>
  139. /// 结束推流
  140. /// </summary>
  141. protected virtual void StopPusher(bool isPaused = false)
  142. {
  143. try
  144. {
  145. lock (_locker)
  146. {
  147. if (_pusher == null)
  148. return;
  149. _pusher.ChannelStateChanged -= OnChannelStateChanged;
  150. var success = _pusher.StopPusher();
  151. if (success)
  152. {
  153. Logger.WriteLineInfo("Stop Pusher Success!");
  154. _pusher.Dispose();
  155. _pusher = null;
  156. IsPushing = false;
  157. LiveVideoStatusChecker.Instance.IsPushing = false;
  158. StopHeartRateKeeper();
  159. }
  160. else
  161. {
  162. Logger.WriteLineError("Stop Pusher Fail!");
  163. }
  164. }
  165. }
  166. catch (Exception e)
  167. {
  168. Logger.WriteLineError($"Stop Pusher Error:{e}");
  169. }
  170. }
  171. /// <summary>
  172. /// 停止推流
  173. /// </summary>
  174. public void StopPusher()
  175. {
  176. StopPusher(false);
  177. }
  178. public void SetMute(bool isMute)
  179. {
  180. lock (_locker)
  181. {
  182. _pusher?.SetMute(isMute);
  183. }
  184. }
  185. /// <summary>
  186. /// 重新推流
  187. /// </summary>
  188. public void ReStartPusher()
  189. {
  190. if (IsPushing == false)
  191. return;
  192. Logger.WriteLineInfo("Restart Pusher");
  193. StopPusher(false);
  194. InitPusher(_currentPushType);
  195. StartPusher(_currentExtendData);
  196. }
  197. private void OnChannelStateChanged(object sender, ChannelStateEventArgs e)
  198. {
  199. try
  200. {
  201. UpdateChannelState(e.Category, e.State);
  202. }
  203. catch (Exception ex)
  204. {
  205. Logger.WriteLineError($"Update Channel State Error:{ex}");
  206. }
  207. }
  208. public void UpdateChannelState(EnumLiveChannelCategory category, EnumLiveStates state)
  209. {
  210. Logger.WriteLineInfo($"UpdateChannelState:{category},{state}");
  211. using (var request = MessagePool.GetMessage<UpdateTerminalMultiLiveStateRequest>())
  212. {
  213. request.TerminalId = _terminalId;
  214. request.LiveChannelName = ((LiveChannelCategory)category).ToString();
  215. request.State = (LiveStates)state;
  216. var result = _leaf.Send(request);
  217. var resultMsg = ResultMessage.Convert(result);
  218. if (resultMsg == CCR.OK)
  219. {
  220. Logger.WriteLineInfo("UpdateChannelState Success!");
  221. }
  222. else
  223. {
  224. Logger.WriteLineError("UpdateChannelState Fail!");
  225. }
  226. }
  227. }
  228. public void StartHeartRateKeeper(IExtendedData extendedData)
  229. {
  230. if (_pushHeartRateKeeper == null && !string.IsNullOrEmpty(extendedData?.HeartRateCode))
  231. {
  232. _pushHeartRateKeeper = new PushHeartRateKeeper(_terminalId, extendedData?.HeartRateCode, _leaf);
  233. _pushHeartRateKeeper.Offlined += OnOfflined;
  234. _pushHeartRateKeeper.Start();
  235. Logger.WriteLineInfo("Start Pusher HeartRate Keeper ");
  236. }
  237. else
  238. {
  239. Logger.WriteLineInfo($"Start Pusher HeartRate Keeper Fail,The ConnectionUrl is{extendedData?.HeartRateCode}");
  240. }
  241. }
  242. public void StopHeartRateKeeper()
  243. {
  244. if (_pushHeartRateKeeper != null)
  245. {
  246. _pushHeartRateKeeper.Offlined -= OnOfflined;
  247. _pushHeartRateKeeper.Stop();
  248. _pushHeartRateKeeper = null;
  249. Logger.WriteLineInfo("Stop Pusher HeartRate Keeper");
  250. }
  251. }
  252. private void OnOfflined(object sender, EventArgs e)
  253. {
  254. Logger.WriteLineInfo($"Pusher is offline,terminal id is :{_terminalId}");
  255. }
  256. private void InitPusher(EnumPusherType type)
  257. {
  258. lock (_locker)
  259. {
  260. if (_pusherCreations.TryGetValue(type, out var creation))
  261. {
  262. if (_pusher != null)
  263. {
  264. StopPusher();
  265. }
  266. _pusher = creation.Invoke();
  267. }
  268. else
  269. {
  270. throw new ArgumentException($"Not support Mode {type}");
  271. }
  272. }
  273. }
  274. private EnumPusherType ConvertToPusherType(LiveEventArgs liveEventArgs)
  275. {
  276. if (liveEventArgs.Protocol == EnumLiveProtocol.RTC)
  277. {
  278. if (liveEventArgs.PushMode == EnumLiveDataMode.MergeLive)
  279. {
  280. var rtcExtendedData = liveEventArgs.ExtendedData as RtcExtendedData;
  281. if (rtcExtendedData.UserInfos.Count() == 1)
  282. {
  283. return EnumPusherType.RtcSingle;
  284. }
  285. else
  286. {
  287. return EnumPusherType.RtcMerge;
  288. }
  289. }
  290. else if (liveEventArgs.PushMode == EnumLiveDataMode.OnlyLive)
  291. {
  292. return EnumPusherType.RtcMulti;
  293. }
  294. }
  295. else if (liveEventArgs.Protocol == EnumLiveProtocol.Rtmp)
  296. {
  297. if (liveEventArgs.PushMode == EnumLiveDataMode.MergeLive)
  298. {
  299. var rtmpExtendedData = liveEventArgs.ExtendedData as RtmpExtendedData;
  300. if (rtmpExtendedData.UserInfos.Count() == 1)
  301. {
  302. return EnumPusherType.RtmpSingle;
  303. }
  304. else
  305. {
  306. return EnumPusherType.RtmpMerge;
  307. }
  308. }
  309. else if (liveEventArgs.PushMode == EnumLiveDataMode.OnlyLive)
  310. {
  311. return EnumPusherType.RtmpMulti;
  312. }
  313. }
  314. throw new ArgumentException("Unknown Pusher type");
  315. }
  316. public void Dispose()
  317. {
  318. StopPusher(false);
  319. _pusherCreations.Clear();
  320. }
  321. }
  322. }