using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; 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; 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 LiveVideoPusherManager : ILiveVideoPusherManager { private readonly string _terminalId; private readonly string _terminalName; private readonly ManualResetEvent _timingRefreshManualResetEvent = new ManualResetEvent(false); private readonly ClientLeaf _leaf; private bool _disposed; private EnumPusherType _currentPushType; private SonopostLiveVideoPusher _liveVideoPusher; private readonly List _currentVideoDeviceInfoList; public bool IsPushing => _liveVideoPusher?.IsPushing ?? false; public EnumPusherType CurrentPushType => _currentPushType; public event EventHandler PreviewImageReceived; public event EventHandler PusherStateChanged; public LiveVideoPusherManager(string terminalId, string terminalName, ClientLeaf leaf) { _terminalId = terminalId; _terminalName = terminalName; _leaf = leaf; _currentPushType = EnumPusherType.RtcMerge; _currentVideoDeviceInfoList = new List(); _liveVideoPusher = new SonopostLiveVideoPusher(leaf, terminalId, terminalName); _liveVideoPusher.PusherStateChanged += OnPusherStateChanegd; Init(); } private void Init() { RegisterPusherCreations(); InitCurrentPusherType(); } private void RegisterPusherCreations() { if (_liveVideoPusher != null) { _liveVideoPusher.RegisterPusher(EnumPusherType.RtmpMerge, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTMPMergePusher()); _liveVideoPusher.RegisterPusher(EnumPusherType.RtmpMulti, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTMPMultiPusher()); _liveVideoPusher.RegisterPusher(EnumPusherType.RtmpSingle, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTMPSinglePusher()); _liveVideoPusher.RegisterPusher(EnumPusherType.RtcMerge, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTCMergePusher()); _liveVideoPusher.RegisterPusher(EnumPusherType.RtcMulti, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTCMultiPusher()); _liveVideoPusher.RegisterPusher(EnumPusherType.RtcSingle, () => CrossPlatformHelper.Instance.LiveVideoPusherCreatorForSonopost.CreateRTCSinglePusher()); } } public void LiveStateChanged(LiveEventArgs liveEventArgs) { _liveVideoPusher?.LiveStateChanged(liveEventArgs); } public void PushModeChanged(LiveDataMode pushLiveMode, LiveProtocol liveProtocol) { SetCurrentPusherType(pushLiveMode, liveProtocol); UpdateDeviceResoution(_currentVideoDeviceInfoList); //RestartPusher(); } private void SetCurrentPusherType(LiveDataMode pushLiveMode, LiveProtocol liveProtocol) { if (liveProtocol == LiveProtocol.RTC) { if (pushLiveMode == LiveDataMode.MergeLive) { if (_currentVideoDeviceInfoList.Count <= 1) { _currentPushType = EnumPusherType.RtcSingle; } else { _currentPushType = EnumPusherType.RtcMerge; } } else if (pushLiveMode == LiveDataMode.OnlyLive) { _currentPushType = EnumPusherType.RtcMulti; } else { throw new Exception($"Live Video Pusher Manager SetCurrentPusherType Error:Unknown Pusher Type:{pushLiveMode}|{liveProtocol}"); } } else if (liveProtocol == LiveProtocol.Rtmp) { if (pushLiveMode == LiveDataMode.MergeLive) { if (_currentVideoDeviceInfoList.Count <= 1) { _currentPushType = EnumPusherType.RtmpSingle; } else { _currentPushType = EnumPusherType.RtmpMerge; } } else if (pushLiveMode == LiveDataMode.OnlyLive) { _currentPushType = EnumPusherType.RtmpMulti; } else { throw new Exception($"Live Video Pusher Manager SetCurrentPusherType Error:Unknown Pusher Type:{pushLiveMode}|{liveProtocol}"); } } else { throw new Exception($"Live Video Pusher Manager SetCurrentPusherType Error:Unknown Pusher Type:{pushLiveMode}|{liveProtocol}"); } Logger.WriteLineInfo($"Live VideoManager Current Push Type:{_currentPushType}"); } public void RestartPusher() { _liveVideoPusher?.ReStartPusher(); } private void OnPusherStateChanegd(object sender, PusherState e) { PusherStateChanged?.Invoke(this, e); } public void SetIsPaused(bool isPaused) { _liveVideoPusher?.SetIsPaused(isPaused); } private void UpdateDeviceResoution(List videoDeviceInfos) { try { Logger.WriteLineInfo("LiveVideo PusherManager UpdateDeviceResoution"); var list = new List(); if (videoDeviceInfos != null) { foreach (var device in videoDeviceInfos) { var item = device.Clone() as CPVideoDeviceInfo; var cability = CrossPlatformHelper.Instance.HardwareDetector.GetMaxResolutionUnderTheSpecial(item.Id, item.Width, item.Height, _currentPushType, device.Category); if (cability != null) { item.Width = cability.Width; item.Height = cability.Height; } list.Add(item); } } UpdateLiveChannelInfos(list); _liveVideoPusher?.StopPusher(); } catch (Exception ex) { Logger.WriteLineError($"UpdateDeviceResoution Error:{ex}"); } } public void SetMute(bool isMute) { _liveVideoPusher?.SetMute(isMute); } public List GetBrandList() { var brandList = new List(); using (var request = MessagePool.GetMessage()) { request.TerminalId = _terminalId; var resultMessage = _leaf.Send(request); var result = GetPushLiveConfigResult.Convert(resultMessage); if (result != null) { foreach (var brand in result.PushLiveConfigs) { brandList.Add(brand.Brand); } } } return brandList; } public List GetModelList(string brand) { if (string.IsNullOrWhiteSpace(brand)) { Logger.WriteLineError($"LiveVideoPusherManager GetModelList Error:brand is null"); return new List(); } var modelList = new List(); using (var request = MessagePool.GetMessage()) { request.TerminalId = _terminalId; var resultMessage = _leaf.Send(request); var result = GetPushLiveConfigResult.Convert(resultMessage); if (result != null) { var selectedBrand = result.PushLiveConfigs.FirstOrDefault(x => x.Brand == brand); if (selectedBrand != null && selectedBrand.PushLiveModelConfigs != null) { foreach (var model in selectedBrand.PushLiveModelConfigs) { modelList.Add(model.Model); } } } } return modelList; } public DeviceRecommandResolution GetRecommandResolution(string brand, string model) { try { if (string.IsNullOrWhiteSpace(brand)) { Logger.WriteLineError($"LiveVideoPusherManager GetRecommandResolution Error:brand is null"); return null; } if (string.IsNullOrWhiteSpace(model)) { Logger.WriteLineError($"LiveVideoPusherManager GetRecommandResolution Error:model is null"); return null; } using (var request = MessagePool.GetMessage()) { request.TerminalId = _terminalId; var resultMessage = _leaf.Send(request); var result = GetPushLiveConfigResult.Convert(resultMessage); if (result != null) { var selectedBrand = result.PushLiveConfigs.FirstOrDefault(x => x.Brand == brand); if (selectedBrand != null && selectedBrand.PushLiveModelConfigs != null) { var selectedModel = selectedBrand.PushLiveModelConfigs.FirstOrDefault(x => x.Model == model); if (selectedModel != null) { return new DeviceRecommandResolution(brand, null, model, selectedModel.RecommendWidth, selectedModel.RecommendHeight); } else { Logger.WriteLineError($"LiveVideoPusherManager GetRecommandResolution Error:Model Didn't find RecommandResolution"); return null; } } else { Logger.WriteLineError($"LiveVideoPusherManager GetRecommandResolution Error:Brand Didn't find"); return null; } } } return null; } catch (Exception ex) { Logger.WriteLineError($"LiveVideoPusherManager GetRecommandResolution Error:{ex}"); return null; } } private void InitCurrentPusherType() { var brandList = new List(); using (var request = MessagePool.GetMessage()) { request.TerminalId = _terminalId; var resultMessage = _leaf.Send(request); var result = GetPushLiveConfigResult.Convert(resultMessage); if (result != null) { SetCurrentPusherType(result.PushLiveMode, result.LiveProtocol); } } } private void UpdateLiveChannelInfos(IEnumerable infos) { var version = Assembly.GetExecutingAssembly().GetName().Version; using (var request = MessagePool.GetMessage()) { request.TerminalName = _terminalName; request.Version = version.ToString(); var terminalChannels = new List(); foreach (var info in infos) { Logger.WriteLineInfo($"Update Channel Info:{info}"); var channelMessage = new TerminalChannelInfoMessage(); channelMessage.Width = info.Width; channelMessage.Height = info.Height; channelMessage.Name = info.Category.ToString(); channelMessage.Enable = info.IsEnable && info.IsAvailable; channelMessage.Fps = info.FrameRate; channelMessage.Bitrate = info.Bitrate; channelMessage.Brand = info.Brand; channelMessage.ModelId = info.ModelId; channelMessage.Category = (LiveChannelCategory)info.Category; terminalChannels.Add(channelMessage); } request.TerminalChannels = terminalChannels; var result = _leaf.Send(request); var resultMsg = ResultMessage.Convert(result); string channelInfos = string.Empty; if (infos != null) { foreach (var info in infos) { channelInfos += info.ToString(); } } if (resultMsg == CCR.OK) { Logger.WriteLineInfo($"UpdateLiveChannelInfos Success! {channelInfos}"); } else { Logger.WriteLineError($"UpdateLiveChannelInfos Fail! {channelInfos}"); } } } public void StartPreview(EnumLiveChannelCategory category) { if (_liveVideoPusher?.LivePusher is PusherBase pusher) { pusher.PreviewImageReceived += OnPreviewImageReceived; pusher.StartPreview(category); } } public void StopPreview() { if (_liveVideoPusher?.LivePusher is PusherBase pusher) { pusher.PreviewImageReceived -= OnPreviewImageReceived; pusher.StopPreview(); } } private void OnPreviewImageReceived(object sender, ImageFrameData e) { PreviewImageReceived?.Invoke(sender, e); } public void Dispose() { if (!_disposed) { DoDispose(); GC.SuppressFinalize(this); _disposed = true; } } public void DoDispose() { _timingRefreshManualResetEvent.Set(); StopPreview(); if (_liveVideoPusher != null) { _liveVideoPusher.PusherStateChanged -= OnPusherStateChanegd; _liveVideoPusher.Dispose(); _liveVideoPusher = null; } } public void UpdateCurrentVideoDeviceInfoList(List infos) { _currentVideoDeviceInfoList.Clear(); if (infos != null) { foreach (var info in infos) { var item = info.Clone() as CPVideoDeviceInfo; _currentVideoDeviceInfoList.Add(item); } } _liveVideoPusher.UpdateCurrentVideoDeviceInfoList(infos); if (_currentPushType == EnumPusherType.RtcSingle || _currentPushType == EnumPusherType.RtcMerge) { PushModeChanged(LiveDataMode.MergeLive, LiveProtocol.RTC); } else if (_currentPushType == EnumPusherType.RtcMulti) { PushModeChanged(LiveDataMode.OnlyLive, LiveProtocol.RTC); } else if (_currentPushType == EnumPusherType.RtmpSingle || _currentPushType == EnumPusherType.RtmpMerge) { PushModeChanged(LiveDataMode.MergeLive, LiveProtocol.Rtmp); } else if (_currentPushType == EnumPusherType.RtmpMulti) { PushModeChanged(LiveDataMode.OnlyLive, LiveProtocol.Rtmp); } } ~LiveVideoPusherManager() { Dispose(); } } }