using Android.App; using Android.Content.Res; using System; using System.Linq; using Vinno.vCloud.FIS.CrossPlatform.Common; using Vinno.vCloud.FIS.CrossPlatform.Common.Enum; using Vinno.vCloud.FIS.CrossPlatform.Common.Hardware; using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo; using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface; namespace Vinno.vCloud.FIS.CrossPlatform.Android.LiveVideo.RTMP { public class RtmpPusher : ILiveVideoPusher { private SmartPublisher _pusher; private CPCombineSmartPushConfiguration _pushConfiguration; private int _screenWidth; private int _screenHeight; private Action _updateState; /// /// Preview local camera capured changed, Rtmp unused /// public event EventHandler PreviewCameraCapured; /// /// The event to notificate the US to show or hide the live video out put window /// public event EventHandler LiveNotification; /// /// The event to notificate the Live Status Changed. /// Only used for RTMP pusher. /// public event EventHandler StatusChanged; public int TerminalWidth { get; private set; } public int TerminalHeight { get; private set; } public int CameraWidth { get; private set; } public int CameraHeight { get; private set; } public RtmpPusher(Action updateState) { _updateState = updateState; var orientation = Application.Context.Resources.Configuration.Orientation; switch (orientation) { case Orientation.Landscape: _screenWidth = Application.Context.Resources.DisplayMetrics.WidthPixels; _screenHeight = Application.Context.Resources.DisplayMetrics.HeightPixels; break; case Orientation.Portrait: _screenWidth = Application.Context.Resources.DisplayMetrics.HeightPixels; _screenHeight = Application.Context.Resources.DisplayMetrics.WidthPixels; break; default: var screenWidth = Application.Context.Resources.DisplayMetrics.WidthPixels; var screenHeight = Application.Context.Resources.DisplayMetrics.HeightPixels; if (screenHeight > screenWidth) { _screenWidth = screenHeight; _screenHeight = screenWidth; } else { _screenHeight = screenHeight; _screenWidth = screenWidth; } break; } } public bool Start(CPCombineSmartPushConfiguration configuration) { try { _pushConfiguration = configuration; UpdateResolution(_pushConfiguration); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"Started rtmp pusher: {configuration}"); if (_pushConfiguration.ShouldPushData || _pushConfiguration.ShowPreviewImage) { DoPush(); } if (_pushConfiguration.ShouldPushData) { _updateState?.Invoke(EnumLiveStates.TerminalIsPushing); } return true; } catch (Exception ex) { CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: start failed ex:{ex}"); } return true; } public bool Stop() { try { if (_pushConfiguration != null) { if (!_pushConfiguration.ShouldPushData && _pushConfiguration.ShowPreviewImage)//本地预览 { CloseSmartPusher(); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"Restart smart pusher"); DoPush(); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"RtmpPusher: stop and only show preview to restart push"); return true; } else { try { CloseSmartPusher(); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"RtmpPusher: Dispose"); return true; } catch (Exception ex) { CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: stop failed to kill ex:{ex}"); } } } } catch (Exception e) { CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"RtmpPusher: stop failed ex:{e}"); } finally { LiveNotification?.Invoke(this, new LiveNotificationArgs(false, TerminalWidth, TerminalHeight)); } return false; } /// /// set push mute or ummute /// /// public void SetMute(bool isMute) { if (_pusher != null) { _pusher.IsMute = isMute; } } public void SetPreviewCamera(bool isShowPreview) { if (isShowPreview) { _pusher.PreviewImageReceived += OnPreviewImageReceived; } else { if (_pushConfiguration.ShouldPushData)//如果正在推流 { _pusher.PreviewImageReceived -= OnPreviewImageReceived; } else { Stop(); } } } public void ChangeCamera(string cameraId) { if (_pusher != null && !_pushConfiguration.ShouldPushData) { Stop(); } } public void ChangeMic(string micId) { if (_pusher != null && !_pushConfiguration.ShouldPushData) { Stop(); } } public bool StartSpeedTest(uint appId, string userid, string userSign) { // throw new NotImplementedException(); return true; } public void StopSpeedTest() { // throw new NotImplementedException(); } private void DoPush() { switch (_pushConfiguration.Mode) { case EnumPushMode.Screen: StartPushScreen(); break; case EnumPushMode.Camera when !string.IsNullOrEmpty(_pushConfiguration.VideoDevicePath): StartPushCamera(); break; case EnumPushMode.CombineTerminal: case EnumPushMode.CombineTerminalGetResolution: StartPush(); break; } } private bool StartPushScreen() { CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushScreen begin"); var noError = true; try { CloseSmartPusher(); _pusher = new SuperScreenPublisher(_pushConfiguration.PushUrl, _updateState); _pusher.IsMute = _pushConfiguration.IsMute; _pusher.StatusChanged += OnStatusChanged; if (_pushConfiguration.ShouldPushData) { _pusher.Start(); } LiveNotification?.Invoke(this, new LiveNotificationArgs(true, TerminalWidth, TerminalHeight)); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushScreen successfully"); } catch (Exception e) { noError = false; CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushScreen ex:{e}"); } if (!noError) { return false; } CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo("Start Push Screen Success"); return true; } private bool StartPushCamera() { var noError = true; try { CloseSmartPusher(); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCamera begin"); _pusher = new SuperDevicePublisher(_pushConfiguration.VideoDevicePath, _pushConfiguration.PushUrl, _updateState); _pusher.IsMute = _pushConfiguration.IsMute; _pusher.StatusChanged += OnStatusChanged; if (_pushConfiguration.EnablePreviewImage) { _pusher.EnablePreview = true; _pusher.PreviewImageReceived += OnPreviewImageReceived; } if (_pushConfiguration.ShouldPushData) { _pusher.Start(); } else if (_pushConfiguration.ShowPreviewImage) { _pusher.StartOnlyPreview(); } CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCamera successfully"); } catch (Exception e) { CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushCamera ex:{e}"); noError = false; } if (!noError) { return false; } return true; } /// /// update TerminalWidth TerminalHeight CameraWidth CameraHeight /// /// public void UpdateResolution(CPCombineSmartPushConfiguration configuration) { var pusher = new CombineSmartPublisher(configuration.PushDataSourceType, configuration.VideoDevicePath, configuration.PushUrl, null); var resolutions = pusher.GetDeviceResolutions(); if (resolutions != null) { if (resolutions != null) { TerminalWidth = resolutions.TerminalWidth; TerminalHeight = resolutions.TerminalHeight; CameraWidth = resolutions.CameraWidth; CameraHeight = resolutions.CameraHeight; } } pusher.Dispose(); } private void StartPush() { EnumPushDataSourceType pushDataSourceType = _pushConfiguration.PushDataSourceType; CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"StartPushCombine begin"); try { CloseSmartPusher(); _pusher = new CombineSmartPublisher(pushDataSourceType, _pushConfiguration.VideoDevicePath, _pushConfiguration.PushUrl, _updateState); _pusher.IsMute = _pushConfiguration.IsMute; _pusher.StatusChanged += OnStatusChanged; if (_pushConfiguration.EnablePreviewImage) { _pusher.EnablePreview = true; _pusher.PreviewImageReceived += OnPreviewImageReceived; } if (_pushConfiguration.ShouldPushData) { _pusher.Start(); } else if (_pushConfiguration.ShowPreviewImage) { _pusher.StartOnlyPreview(); } LiveNotification?.Invoke(this, new LiveNotificationArgs(true, TerminalWidth, TerminalHeight)); CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo("Start Push Screen and Camera Success"); } catch (Exception e) { CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"StartPushScreen ex:{e}"); } } private void OnStatusChanged(object sender, CPLiveStatusData publisherStatusData) { CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"SamrtPusher status changed:{publisherStatusData.Status}"); StatusChanged?.Invoke(this, publisherStatusData.Status); } private void OnPreviewImageReceived(object sender, CPVideoFrameData e) { PreviewCameraCapured?.Invoke(this, e); } private void CloseSmartPusher() { if (_pusher != null) { _pusher.PreviewImageReceived -= OnPreviewImageReceived; _pusher.StatusChanged -= OnStatusChanged; _pusher.Dispose(); _pusher = null; } } } }