RtmpPusher.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. using Android.App;
  2. using Android.Content.Res;
  3. using System;
  4. using System.Linq;
  5. using Vinno.vCloud.FIS.CrossPlatform.Common;
  6. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  7. using Vinno.vCloud.FIS.CrossPlatform.Common.Hardware;
  8. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  9. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
  10. namespace Vinno.vCloud.FIS.CrossPlatform.Android.LiveVideo.RTMP
  11. {
  12. public class RtmpPusher : ILiveVideoPusher
  13. {
  14. private SmartPublisher _pusher;
  15. private CPCombineSmartPushConfiguration _pushConfiguration;
  16. private int _screenWidth;
  17. private int _screenHeight;
  18. private Action<EnumLiveStates> _updateState;
  19. /// <summary>
  20. /// Preview local camera capured changed, Rtmp unused
  21. /// </summary>
  22. public event EventHandler<CPVideoFrameData> PreviewCameraCapured;
  23. /// <summary>
  24. /// The event to notificate the US to show or hide the live video out put window
  25. /// </summary>
  26. public event EventHandler<LiveNotificationArgs> LiveNotification;
  27. /// <summary>
  28. /// The event to notificate the Live Status Changed.
  29. /// Only used for RTMP pusher.
  30. /// </summary>
  31. public event EventHandler<EnumLiveStatus> StatusChanged;
  32. public int TerminalWidth { get; private set; }
  33. public int TerminalHeight { get; private set; }
  34. public int CameraWidth { get; private set; }
  35. public int CameraHeight { get; private set; }
  36. public RtmpPusher(Action<EnumLiveStates> updateState)
  37. {
  38. _updateState = updateState;
  39. var orientation = Application.Context.Resources.Configuration.Orientation;
  40. switch (orientation)
  41. {
  42. case Orientation.Landscape:
  43. _screenWidth = Application.Context.Resources.DisplayMetrics.WidthPixels;
  44. _screenHeight = Application.Context.Resources.DisplayMetrics.HeightPixels;
  45. break;
  46. case Orientation.Portrait:
  47. _screenWidth = Application.Context.Resources.DisplayMetrics.HeightPixels;
  48. _screenHeight = Application.Context.Resources.DisplayMetrics.WidthPixels;
  49. break;
  50. default:
  51. var screenWidth = Application.Context.Resources.DisplayMetrics.WidthPixels;
  52. var screenHeight = Application.Context.Resources.DisplayMetrics.HeightPixels;
  53. if (screenHeight > screenWidth)
  54. {
  55. _screenWidth = screenHeight;
  56. _screenHeight = screenWidth;
  57. }
  58. else
  59. {
  60. _screenHeight = screenHeight;
  61. _screenWidth = screenWidth;
  62. }
  63. break;
  64. }
  65. }
  66. public bool Start(CPCombineSmartPushConfiguration configuration)
  67. {
  68. try
  69. {
  70. _pushConfiguration = configuration;
  71. UpdateResolution(_pushConfiguration);
  72. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"Started rtmp pusher: {configuration}");
  73. if (_pushConfiguration.ShouldPushData || _pushConfiguration.ShowPreviewImage)
  74. {
  75. DoPush();
  76. }
  77. if (_pushConfiguration.ShouldPushData)
  78. {
  79. _updateState?.Invoke(EnumLiveStates.TerminalIsPushing);
  80. }
  81. return true;
  82. }
  83. catch (Exception ex)
  84. {
  85. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: start failed ex:{ex}");
  86. }
  87. return true;
  88. }
  89. public bool Stop()
  90. {
  91. try
  92. {
  93. if (_pushConfiguration != null)
  94. {
  95. if (!_pushConfiguration.ShouldPushData && _pushConfiguration.ShowPreviewImage)//本地预览
  96. {
  97. CloseSmartPusher();
  98. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"Restart smart pusher");
  99. DoPush();
  100. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"RtmpPusher: stop and only show preview to restart push");
  101. return true;
  102. }
  103. else
  104. {
  105. try
  106. {
  107. CloseSmartPusher();
  108. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"RtmpPusher: Dispose");
  109. return true;
  110. }
  111. catch (Exception ex)
  112. {
  113. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: stop failed to kill ex:{ex}");
  114. }
  115. }
  116. }
  117. }
  118. catch (Exception e)
  119. {
  120. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: stop failed ex:{e}");
  121. }
  122. finally
  123. {
  124. LiveNotification?.Invoke(this, new LiveNotificationArgs(false, TerminalWidth, TerminalHeight));
  125. }
  126. return false;
  127. }
  128. /// <summary>
  129. /// set push mute or ummute
  130. /// </summary>
  131. /// <param name="isMute"></param>
  132. public void SetMute(bool isMute)
  133. {
  134. if (_pusher != null)
  135. {
  136. _pusher.IsMute = isMute;
  137. }
  138. }
  139. public void SetPreviewCamera(bool isShowPreview)
  140. {
  141. if (isShowPreview)
  142. {
  143. _pusher.PreviewImageReceived += OnPreviewImageReceived;
  144. }
  145. else
  146. {
  147. if (_pushConfiguration.ShouldPushData)//如果正在推流
  148. {
  149. _pusher.PreviewImageReceived -= OnPreviewImageReceived;
  150. }
  151. else
  152. {
  153. Stop();
  154. }
  155. }
  156. }
  157. public void ChangeCamera(string cameraId)
  158. {
  159. if (_pusher != null && !_pushConfiguration.ShouldPushData)
  160. {
  161. Stop();
  162. }
  163. }
  164. public void ChangeMic(string micId)
  165. {
  166. if (_pusher != null && !_pushConfiguration.ShouldPushData)
  167. {
  168. Stop();
  169. }
  170. }
  171. public bool StartSpeedTest(uint appId, string userid, string userSign)
  172. {
  173. // throw new NotImplementedException();
  174. return true;
  175. }
  176. public void StopSpeedTest()
  177. {
  178. // throw new NotImplementedException();
  179. }
  180. private void DoPush()
  181. {
  182. switch (_pushConfiguration.Mode)
  183. {
  184. case EnumPushMode.Screen:
  185. StartPushScreen();
  186. break;
  187. case EnumPushMode.Camera when !string.IsNullOrEmpty(_pushConfiguration.VideoDevicePath):
  188. StartPushCamera();
  189. break;
  190. case EnumPushMode.CombineTerminal:
  191. case EnumPushMode.CombineTerminalGetResolution:
  192. StartPush();
  193. break;
  194. }
  195. }
  196. private bool StartPushScreen()
  197. {
  198. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushScreen begin");
  199. var noError = true;
  200. try
  201. {
  202. CloseSmartPusher();
  203. _pusher = new SuperScreenPublisher(_pushConfiguration.PushUrl, _updateState);
  204. _pusher.IsMute = _pushConfiguration.IsMute;
  205. _pusher.StatusChanged += OnStatusChanged;
  206. if (_pushConfiguration.ShouldPushData)
  207. {
  208. _pusher.Start();
  209. }
  210. LiveNotification?.Invoke(this, new LiveNotificationArgs(true, TerminalWidth, TerminalHeight));
  211. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushScreen successfully");
  212. }
  213. catch (Exception e)
  214. {
  215. noError = false;
  216. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushScreen ex:{e}");
  217. }
  218. if (!noError)
  219. {
  220. return false;
  221. }
  222. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo("Start Push Screen Success");
  223. return true;
  224. }
  225. private bool StartPushCamera()
  226. {
  227. var noError = true;
  228. try
  229. {
  230. CloseSmartPusher();
  231. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCamera begin");
  232. _pusher = new SuperDevicePublisher(_pushConfiguration.VideoDevicePath, _pushConfiguration.PushUrl, _updateState);
  233. _pusher.IsMute = _pushConfiguration.IsMute;
  234. _pusher.StatusChanged += OnStatusChanged;
  235. if (_pushConfiguration.EnablePreviewImage)
  236. {
  237. _pusher.EnablePreview = true;
  238. _pusher.PreviewImageReceived += OnPreviewImageReceived;
  239. }
  240. if (_pushConfiguration.ShouldPushData)
  241. {
  242. _pusher.Start();
  243. }
  244. else if (_pushConfiguration.ShowPreviewImage)
  245. {
  246. _pusher.StartOnlyPreview();
  247. }
  248. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCamera successfully");
  249. }
  250. catch (Exception e)
  251. {
  252. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushCamera ex:{e}");
  253. noError = false;
  254. }
  255. if (!noError)
  256. {
  257. return false;
  258. }
  259. return true;
  260. }
  261. /// <summary>
  262. /// update TerminalWidth TerminalHeight CameraWidth CameraHeight
  263. /// </summary>
  264. /// <param name="configuration"></param>
  265. public void UpdateResolution(CPCombineSmartPushConfiguration configuration)
  266. {
  267. var pusher = new CombineSmartPublisher(configuration.PushDataSourceType, configuration.VideoDevicePath, configuration.PushUrl, null);
  268. var resolutions = pusher.GetDeviceResolutions();
  269. if (resolutions != null)
  270. {
  271. if (resolutions != null)
  272. {
  273. TerminalWidth = resolutions.TerminalWidth;
  274. TerminalHeight = resolutions.TerminalHeight;
  275. CameraWidth = resolutions.CameraWidth;
  276. CameraHeight = resolutions.CameraHeight;
  277. }
  278. }
  279. pusher.Dispose();
  280. }
  281. private void StartPush()
  282. {
  283. EnumPushDataSourceType pushDataSourceType = _pushConfiguration.PushDataSourceType;
  284. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCombine begin");
  285. try
  286. {
  287. CloseSmartPusher();
  288. _pusher = new CombineSmartPublisher(pushDataSourceType, _pushConfiguration.VideoDevicePath, _pushConfiguration.PushUrl, _updateState);
  289. _pusher.IsMute = _pushConfiguration.IsMute;
  290. _pusher.StatusChanged += OnStatusChanged;
  291. if (_pushConfiguration.EnablePreviewImage)
  292. {
  293. _pusher.EnablePreview = true;
  294. _pusher.PreviewImageReceived += OnPreviewImageReceived;
  295. }
  296. if (_pushConfiguration.ShouldPushData)
  297. {
  298. _pusher.Start();
  299. }
  300. else if (_pushConfiguration.ShowPreviewImage)
  301. {
  302. _pusher.StartOnlyPreview();
  303. }
  304. LiveNotification?.Invoke(this, new LiveNotificationArgs(true, TerminalWidth, TerminalHeight));
  305. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo("Start Push Screen and Camera Success");
  306. }
  307. catch (Exception e)
  308. {
  309. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushScreen ex:{e}");
  310. }
  311. }
  312. private void OnStatusChanged(object sender, CPLiveStatusData publisherStatusData)
  313. {
  314. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"SamrtPusher status changed:{publisherStatusData.Status}");
  315. StatusChanged?.Invoke(this, publisherStatusData.Status);
  316. }
  317. private void OnPreviewImageReceived(object sender, CPVideoFrameData e)
  318. {
  319. PreviewCameraCapured?.Invoke(this, e);
  320. }
  321. private void CloseSmartPusher()
  322. {
  323. if (_pusher != null)
  324. {
  325. _pusher.PreviewImageReceived -= OnPreviewImageReceived;
  326. _pusher.StatusChanged -= OnStatusChanged;
  327. _pusher.Dispose();
  328. _pusher = null;
  329. }
  330. }
  331. }
  332. }