using System; using System.Collections.Generic; using Vinno.FIS.TRTCClient.Common.Enum; using Vinno.IUS.Common.Log; using Vinno.IUS.Common.Network.Leaf; using Vinno.IUS.Common.Network.Transfer; using Vinno.vCloud.FIS.CrossPlatform.Common.Enum; using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo; using Vinno.vCloud.Protocol.Infrastructures; using Vinno.vCloud.Protocol.Messages.Client; using Vinno.vCloud.Protocol.Messages.Client.Live; using Vinno.vCloud.Protocol.Messages.Live; namespace Vinno.vCloud.Common.FIS.LiveVideos { internal class LiveVideo : ILiveVideo, IDisposable { private readonly string _terminalId; private readonly string _terminalName; private readonly ClientLeaf _leaf; private bool _disposed; private bool _isCameraLiveEnabled; private bool _isLiveVideoEnabled; private LiveClient _liveClient; private bool _cameraMute; private bool _previewCameraEnabled; private LiveProtocol _liveProtocol; private string _cameraId; private string _micId; private int _cameraPreviewWidth; private int _cameraPreviewHeight; private LiveClient LiveClient { get { return _liveClient; } set { if (_liveClient != value) { if (_liveClient != null) { _liveClient.PreviewCameraCapured -= OnPreviewCameraCaptured; _liveClient.LiveProtocolChanged -= OnLiveProtocolChanged; _liveClient.LiveNotification -= OnLiveNotification; _liveClient.Dispose(); } _liveClient = value; if (_liveClient != null) { _liveClient.PreviewCameraCapured += OnPreviewCameraCaptured; _liveClient.LiveProtocolChanged += OnLiveProtocolChanged; _liveClient.LiveNotification += OnLiveNotification; _cameraPreviewWidth = 0; _cameraPreviewHeight = 0; } } } } /// /// Raised when live changed to protocol /// public event EventHandler LiveProtocolChanged; /// /// The event to notificate the US to show or hide the live video out put window /// public event EventHandler LiveNotification; /// /// Raised when camera Preview Excute /// public event EventHandler PreviewCameraCaptured; /// /// Raised when Camera Preview Image Size Changed /// public event EventHandler CameraPreviewImageSizeChanged; /// /// Create the liveVideo module. /// /// /// /// /// public LiveVideo(string terminalId, string terminalName, ClientLeaf leaf, int usScreenWidth, int usScreenHeight) { _terminalId = terminalId; _terminalName = terminalName; _leaf = leaf; _liveProtocol = LiveProtocol.RTC; LiveClient = new LiveClient(_leaf, usScreenWidth, usScreenHeight); _leaf.MessageArrived += OnMessageArrived; } ~LiveVideo() { DoDispose(); } /// /// Handle the message from network. /// /// /// private void OnMessageArrived(object sender, Message e) { var startLiveNotification = StartLiveNotification.Convert(e); if (startLiveNotification != null) { HandleStatLiveNotification(startLiveNotification); } var closeLiveNotification = CloseLiveNotification.Convert(e); if (closeLiveNotification != null) { HandleCloseLiveNotification(closeLiveNotification); } } private void HandleCloseLiveNotification(CloseLiveNotification closeLiveNotification) { lock (CPCombineSmartPushConfiguration.Instance) { try { Logger.WriteLineInfo($"Handle CloseLiveNotification begin"); CPCombineSmartPushConfiguration.Instance.PushUrl = string.Empty; if (LiveClient != null) { LiveClient.SetPushStatus(EnumLivePushStatus.Ide); LiveClient.Stop(); } Logger.WriteLineInfo($"Handle CloseLiveNotification end"); } catch (Exception ex) { Logger.WriteLineError($"Handle CloseLiveNotification ex:{ex}"); } finally { CPCombineSmartPushConfiguration.Instance.LiveServiceUrl = string.Empty; } } } private void HandleStatLiveNotification(StartLiveNotification startLiveNotification) { lock (CPCombineSmartPushConfiguration.Instance) { try { var pushConfiguration = CPCombineSmartPushConfiguration.Instance; var notificationDetails = $"LiveProtocol:{startLiveNotification.LiveProtocol},TerminalId:{startLiveNotification.TerminalId},IntegerRoomId:{startLiveNotification.IntegerRoomId},UserSign:{startLiveNotification.UserSign},TerminalPushUrl:{startLiveNotification.TerminalPushUrl},LiveServiceUrl:{startLiveNotification.LiveServiceUrl},AppId:{startLiveNotification.AppId}"; Logger.WriteLineInfo($"Handle StartLiveNotification begin,{notificationDetails}"); var terminalUrl = startLiveNotification.TerminalPushUrl; if (_isLiveVideoEnabled || _isCameraLiveEnabled) { if (_isLiveVideoEnabled && !_isCameraLiveEnabled) { pushConfiguration.PushDataSourceType = EnumPushDataSourceType.Screen; pushConfiguration.Mode = EnumPushMode.Screen; } else if (!_isLiveVideoEnabled && _isCameraLiveEnabled) { pushConfiguration.PushDataSourceType = EnumPushDataSourceType.Camera; pushConfiguration.Mode = EnumPushMode.Camera; } else if (_isLiveVideoEnabled && _isCameraLiveEnabled) { pushConfiguration.PushDataSourceType = EnumPushDataSourceType.ScreenAndCamera; pushConfiguration.Mode = EnumPushMode.CombineTerminal; } var protocol = startLiveNotification.LiveProtocol; if (protocol == LiveProtocol.Rtmp) { pushConfiguration.PushUrl = terminalUrl; } pushConfiguration.ShouldPushData = true; pushConfiguration.LiveServiceUrl = startLiveNotification.LiveServiceUrl; pushConfiguration.AppId = startLiveNotification.AppId; var roomId = startLiveNotification.IntegerRoomId; var terminalId = startLiveNotification.TerminalId; var userSign = startLiveNotification.UserSign; pushConfiguration.RoomId = (uint)roomId; pushConfiguration.TerminalId = terminalId; pushConfiguration.UserSign = userSign; LiveClient.Start(startLiveNotification.LiveProtocol); if (_liveProtocol != protocol) { _liveProtocol = protocol; InvokeLiveProtocolChanged(_liveProtocol); } } Logger.WriteLineInfo($"Handle StartLiveNotification end"); } catch (Exception ex) { Logger.WriteLineError($"Handle StartLiveNotification ex:{ex}"); } } } private void OnPreviewCameraCaptured(object sender, CPVideoFrameData data) { if (data == null || data.Data == null) { return; } if (_cameraPreviewHeight != data.Height || _cameraPreviewWidth != data.Width) { _cameraPreviewHeight = data.Height; _cameraPreviewWidth = data.Width; CameraPreviewImageSizeChanged?.Invoke(this, new ImageSize(_cameraPreviewWidth, _cameraPreviewHeight)); } PreviewCameraCaptured?.Invoke(this, data.Data); } private void DoDispose() { if (!_disposed) { lock (CPCombineSmartPushConfiguration.Instance) { try { Logger.WriteLineInfo($"DoDispose:Handle CloseLiveNotification begin"); CPCombineSmartPushConfiguration.Instance.PushUrl = string.Empty; if (LiveClient != null) { LiveClient.SetPushStatus(EnumLivePushStatus.Ide); LiveClient.Stop(); LiveClient.Dispose(); LiveClient = null; } Logger.WriteLineInfo($"DoDispose:Handle CloseLiveNotification end"); } catch (Exception ex) { Logger.WriteLineError($"Handle CloseLiveNotification ex:{ex}"); } finally { CPCombineSmartPushConfiguration.Instance.LiveServiceUrl = string.Empty; } } _leaf.MessageArrived -= OnMessageArrived; _disposed = true; } } public void Dispose() { DoDispose(); GC.SuppressFinalize(this); } private void NotifyLiveEnabledChanged() { try { using (var changeTerminalSupportLiveRequest = new ChangeTerminalLiveEnabledRequest { TerminalLiveEnabled = _isLiveVideoEnabled, TerminalName = _terminalName, CameraLiveEnabled = _isCameraLiveEnabled }) { var changeTerminalSupportLiveServerResult = _leaf.Send(changeTerminalSupportLiveRequest); var changeTerminalSupportLiveResult = ResultMessage.Convert(changeTerminalSupportLiveServerResult); if (changeTerminalSupportLiveResult != CCR.OK) { Logger.WriteLineError($"On_isCameraLiveEnabledChanged notification failed, _isCameraLiveEnabled:{_isCameraLiveEnabled}"); } } } catch (Exception e) { Logger.WriteLineError($"On_isCameraLiveEnabledChanged notification, _isCameraLiveEnabled:{_isCameraLiveEnabled}, ex: {e}"); } } /// /// Change CameraSettings to upload server hardware info /// /// /// /// /// /// /// public void ChangeCameraSettings(bool enableCameraLive, string cameraId, string micId, bool showPreviewImage, bool enableLiveVideo, bool isMute) { lock (CPCombineSmartPushConfiguration.Instance) { var pushConfiguration = CPCombineSmartPushConfiguration.Instance; var needNotifyToServer = false; var needNotifyLiveStatus = false; if (enableCameraLive && enableLiveVideo) { pushConfiguration.Mode = EnumPushMode.CombineTerminal; pushConfiguration.PushDataSourceType = EnumPushDataSourceType.ScreenAndCamera; } else if (enableLiveVideo) { pushConfiguration.Mode = EnumPushMode.Screen; pushConfiguration.PushDataSourceType = EnumPushDataSourceType.Screen; } else { pushConfiguration.Mode = EnumPushMode.Camera; pushConfiguration.PushDataSourceType = EnumPushDataSourceType.Camera; } pushConfiguration.VideoDevicePath = cameraId; if (!enableCameraLive) { cameraId = null; showPreviewImage = false; } pushConfiguration.AudioDevicePath = micId; //是否停止推送 bool stopliveClient = false; if (_isLiveVideoEnabled != enableLiveVideo && !enableLiveVideo) { stopliveClient = true; } else if (_isCameraLiveEnabled != enableCameraLive && enableCameraLive && enableLiveVideo) //单路切换双路 { stopliveClient = true; Logger.WriteLineInfo($"LiveVideo Screen to ScreenAndCamera"); } else if (_isLiveVideoEnabled != enableLiveVideo && enableCameraLive && enableLiveVideo) //单路切换双路 { stopliveClient = true; Logger.WriteLineInfo($"LiveVideo Camera to ScreenAndCamera"); } else if (_isCameraLiveEnabled != enableCameraLive && !enableCameraLive && enableLiveVideo) //双路切换单路 { stopliveClient = true; Logger.WriteLineInfo($"LiveVideo ScreenAndCamera to Screen"); } if (_cameraId != pushConfiguration.VideoDevicePath && pushConfiguration.ShouldPushData)//切换摄像头 { stopliveClient = true; Logger.WriteLineInfo($"LiveVideo Change Camera"); } if (_micId != pushConfiguration.AudioDevicePath && pushConfiguration.ShouldPushData)//切换麦克风 { stopliveClient = true; Logger.WriteLineInfo($"LiveVideo Change Mic"); } if (stopliveClient) { pushConfiguration.ShowPreviewImage = false; pushConfiguration.IsMute = true; LiveClient?.Stop(); // stop and set default LiveClient?.SetPushStatus(EnumLivePushStatus.Ide); } if (!enableCameraLive)//未开摄像头默认静音 true { isMute = true; } var cameraMute = isMute; //isMute true 静音 pushConfiguration.IsMute = cameraMute; if (!cameraMute) { pushConfiguration.AudioMode = EnumAudioMode.Mic; } if (enableCameraLive && enableLiveVideo && showPreviewImage) { pushConfiguration.ShowPreviewImage = true; LiveVideoStatusChecker.Instance.IsPreviewing = true; } else { pushConfiguration.ShowPreviewImage = false; LiveVideoStatusChecker.Instance.IsPreviewing = false; } if (_previewCameraEnabled != pushConfiguration.ShowPreviewImage)//是否预览 { _previewCameraEnabled = pushConfiguration.ShowPreviewImage; if (!pushConfiguration.ShouldPushData)//不在推流 { if (_previewCameraEnabled)//只是本地预览 { LiveClient?.StartOnlyPreviewImage(); } else { if (!stopliveClient) { LiveClient?.SetPreviewCamera(_previewCameraEnabled); } } } else { if (!stopliveClient) { LiveClient?.SetPreviewCamera(_previewCameraEnabled); } } } if (_cameraId != pushConfiguration.VideoDevicePath)//切换摄像头 { _cameraId = pushConfiguration.VideoDevicePath; needNotifyToServer = true; if (!stopliveClient) { LiveClient?.ChangeCamera(_cameraId); } Logger.WriteLineInfo($"Change Camera Setting: Camera Id Changed:{_cameraId}"); } if (_micId != pushConfiguration.AudioDevicePath) { _micId = pushConfiguration.AudioDevicePath; if (!stopliveClient) { LiveClient?.ChangeMic(_micId); } Logger.WriteLineInfo($"Change Camera Setting: Audio Id Changed:{_micId}"); } if (_cameraMute != cameraMute) { _cameraMute = cameraMute; _liveClient?.SetMute(_cameraMute); Logger.WriteLineInfo($"Change Camera Setting: Camera Mute Changed:{_cameraMute}"); } if (_isLiveVideoEnabled != enableLiveVideo) { needNotifyToServer = true; needNotifyLiveStatus = true; _isLiveVideoEnabled = enableLiveVideo; Logger.WriteLineInfo($"Change Camera Setting: Live Video Enabled Changed:{_isLiveVideoEnabled}"); } if (_isCameraLiveEnabled != enableCameraLive) { needNotifyLiveStatus = true; needNotifyToServer = true; _isCameraLiveEnabled = enableCameraLive; Logger.WriteLineInfo($"Change Camera Setting: Camera Live Enabled Changed:{_isCameraLiveEnabled}"); } if (needNotifyLiveStatus) { NotifyLiveEnabledChanged(); } if (needNotifyToServer && _isLiveVideoEnabled) { _liveClient?.NotifyStatusAndResolutions(_terminalId); } } } /// /// Speed live test network and auto select good network to server /// /// public bool StartSpeedTest() { bool speedTest = false; if (_liveClient != null) { speedTest = _liveClient.StartSpeedTest(); } return speedTest; } private void InvokeLiveProtocolChanged(LiveProtocol liveProtocol) { LiveProtocolChanged?.Invoke(this, liveProtocol); } private void OnLiveProtocolChanged(object sender, LiveProtocol liveProtocol) { _liveProtocol = liveProtocol; InvokeLiveProtocolChanged(_liveProtocol); } private void OnLiveNotification(object sender, LiveNotificationArgs e) { LiveNotification?.Invoke(this, e); } public void ChangeCameraSettingsForSonopost(bool showPreviewImage, EnumLiveChannelCategory previewLiveChannel, IEnumerable infos, RainbowImageDetectConfig rainbowImageCheckConfig, string micId, bool isMute) { throw new NotImplementedException(); } /// /// 获取品牌列表 /// /// public List GetBrandList() { return new List(); } /// /// 获取型号列表 /// /// /// /// public List GetModelList(string brand) { return new List(); } /// /// 获取推荐分辨率 /// /// /// /// public DeviceRecommandResolution GetRecommandResolution(string brand, string model) { return null; } } }