using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Vinno.FIS.TRTCClient.Common.Enum;
using Vinno.IUS.Common.Log;
using Vinno.vCloud.Common.FIS.LiveVideos;
using Vinno.vCloud.FIS.CrossPlatform.Common;
using Vinno.vCloud.FIS.CrossPlatform.Common.Consultation.Interface;
using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
using WingInterfaceLibrary.LiveConsultation;
namespace Vinno.vCloud.Common.FIS.Consultation
{
public abstract class VideoProviderV2 : IDisposable
{
private readonly ConsultationVideoFrameData _consultationVideoFrameData;
private readonly object _connectionKeeperLock = new object();
private PushHeartRateKeeperV2 _connectionKeeper;
protected ConsultationMemberInfo _consultationMemberInfo;
protected bool _disposed;
public event EventHandler Offlined;
public ConsultationMemberInfo ConsultationMemberInfo
{
get => _consultationMemberInfo;
set
{
_consultationMemberInfo = value;
}
}
///
/// Video frame arrived
///
public event EventHandler VideoFrameArrived;
public VideoProviderV2(ConsultationMemberInfo consultationMemberInfo)
{
_consultationMemberInfo = consultationMemberInfo;
_consultationVideoFrameData = new ConsultationVideoFrameData(null, _consultationMemberInfo);
}
public abstract void Dispose();
protected void UpdateFrame(CPVideoFrameData data)
{
_consultationVideoFrameData.VideoFrameData = data;
VideoFrameArrived?.Invoke(this, _consultationVideoFrameData);
}
public void StartConsultationConnectionKeeper(string token, string consultationCode, int heartRateInterval, ILiveConsultationService liveConsultationService)
{
lock (_connectionKeeperLock)
{
_connectionKeeper = new PushHeartRateKeeperV2(token, consultationCode, heartRateInterval, liveConsultationService);
_connectionKeeper.Offlined += OnOfflined;
_connectionKeeper.Start();
}
}
public void ChangeConsultationCode(string consultationCode)
{
lock (_connectionKeeperLock)
{
if (_connectionKeeper != null)
{
_connectionKeeper.SetHeartRateCode(consultationCode);
Logger.WriteLineInfo($"Consultation Connection Keeper Change Consultation Code {consultationCode}");
}
}
}
private void OnOfflined(object sender, EventArgs e)
{
Offlined?.Invoke(this, e);
Logger.WriteLineInfo($"Connection keeper offline ");
}
internal void DisposeConnectionKeeper()
{
if (_connectionKeeper != null)
{
_connectionKeeper.Offlined -= OnOfflined;
_connectionKeeper.Stop();
_connectionKeeper = null;
}
}
}
public class RtcVideoProviderV2 : VideoProviderV2
{
public RtcVideoProviderV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
{
}
public override void Dispose()
{
if (_disposed)
return;
DisposeConnectionKeeper();
_disposed = true;
}
}
public class RtmpVideoProviderV2 : VideoProviderV2
{
public RtmpVideoProviderV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
{
}
public override void Dispose()
{
if (_disposed)
return;
DisposeConnectionKeeper();
_disposed = true;
}
}
public class RtmpVideoPlayerV2 : VideoProviderV2
{
private IRtmpPlayer _smartPlayer;
private int _videoBufferSize = 300;
private bool _isClosed;
private readonly object _locker = new object();
public RtmpVideoPlayerV2(ConsultationMemberInfo consultationMemberInfo) : base(consultationMemberInfo)
{
CreateSmartPlayer(consultationMemberInfo.PullRtmpUrl);
}
private void CreateSmartPlayer(string url)
{
if (!string.IsNullOrEmpty(url))
{
_smartPlayer = CrossPlatformHelper.Instance.RtmpPlayerCreator.CreateLivePlayer(url);
_smartPlayer.Buffer = _videoBufferSize;
_smartPlayer.VideoFrameReceived += OnVideoFrameReceived;
Task.Run(async () =>
{
await Task.Delay(3000);
lock (_locker)
{
if (!_isClosed)
{
_smartPlayer.Play();
}
}
});
}
}
private void CloseSmartPlayer()
{
if (_smartPlayer != null)
{
lock (_locker)
{
_isClosed = true;
}
_smartPlayer.VideoFrameReceived -= OnVideoFrameReceived;
_smartPlayer.Stop();
_smartPlayer = null;
}
}
private void OnVideoFrameReceived(object sender, CPVideoFrameData e)
{
UpdateFrame(e);
}
public override void Dispose()
{
if (_disposed)
return;
DisposeConnectionKeeper();
CloseSmartPlayer();
_disposed = true;
}
~RtmpVideoPlayerV2()
{
}
}
public class RtmpVideoPusherV2 : VideoProviderV2
{
private IRtmpPusherV2 _smartPublisher;
private CPVideoFrameData _videoFrameData;
public RtmpVideoPusherV2(ConsultationMemberInfo consultationMemberInfo, string videoDeviceId, string micDeviceId, bool onlyForRtmpPushing) : base(consultationMemberInfo)
{
var deviceInfo = new CPVideoDeviceOutputInfo
{
VideoDeviceId = videoDeviceId,
IdForServer = "",
VideoDeviceSourceType = EnumVideoDeviceSourceType.Camera,
OutputWidth = 640,
OutputHeight = 480,
Category = EnumLiveChannelCategory.Main,
};
_smartPublisher = CrossPlatformHelper.Instance.RtmpPusherCreator.CreateLivePusherV2(deviceInfo, consultationMemberInfo.PushUrl, micDeviceId, 640, 480);
if (!onlyForRtmpPushing)
{
_smartPublisher.ImageFrameReceived += OnImageFrameReceived;
}
_smartPublisher.Start();
}
~RtmpVideoPusherV2()
{
}
private void OnImageFrameReceived(object sender, ImageFrameData e)
{
if (_videoFrameData == null)
{
_videoFrameData = new CPVideoFrameData(e.Width, e.Height, new byte[e.Size]);
}
else if (_videoFrameData.Height != e.Height || _videoFrameData.Width != e.Width)
{
_videoFrameData.Height = e.Height;
_videoFrameData.Width = e.Width;
_videoFrameData.Data = new byte[e.Size];
}
Marshal.Copy(e.Data, _videoFrameData.Data, 0, e.Size);
UpdateFrame(_videoFrameData);
}
public override void Dispose()
{
if (_disposed)
return;
LiveVideoStatusChecker.Instance.IsConsultationLivingInCurrentMachine = false;
if (_smartPublisher != null)
{
_smartPublisher.ImageFrameReceived -= OnImageFrameReceived;
_smartPublisher.Stop();
_smartPublisher.Dispose();
_smartPublisher = null;
}
DisposeConnectionKeeper();
_disposed = true;
}
public void SetMute(bool isMute)
{
if (_smartPublisher != null)
{
_smartPublisher.SetMute(isMute);
}
}
public void SwitchCamera()
{
if (_smartPublisher != null)
{
//TODOFelix
}
}
}
}