using Android.Content;
using Android.OS;
using Com.Tencent.Trtc;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Vinno.FIS.TRTCClient.Common.Log;
using static Com.Tencent.Trtc.TRTCCloudDef;
namespace Vinno.vCloud.FIS.CrossPlatform.Android.LiveVideo.RTC
{
public class TRTCLivePusher : TRTCCloudListener, IDisposable
{
private readonly ManualResetEvent _exitResetEvent = new ManualResetEvent(false);
private TRTCCloud _tRtcCloud;
private TRTCVideoFrame _videoFrame;
private byte[] _tempData;
private int _videoResolution;
public event EventHandler FirstFrameSend;
public TRTCLivePusher(string logPath, Context context)
{
TRTCCloud.SetLogCompressEnabled(false);
TRTCCloud.SetLogDirPath(logPath);
TRTCCloud.SetLogLevel(TrtcLogLevelError);
_tRtcCloud = TRTCCloud.SharedInstance(context);
}
///
/// 进入房间
///
///
///
///
///
///
///
///
public void EnterRoom(string userId, int roomId, string userSign, int appid, int videoResolution, int videoFps, int videoBitrate, int minVideoBitrate, bool isMute, string micId)
{
Logger.WriteLineInfo($"Enter Room,UserId:{userId},RoomId:{roomId}");
_videoResolution = videoResolution;
_tRtcCloud.MuteAllRemoteVideoStreams(true);
_tRtcCloud.SetDefaultStreamRecvMode(false, false);
_tRtcCloud.MuteAllRemoteAudio(true);
_tRtcCloud.StartLocalAudio(TrtcAudioQualityMusic);//开启本地音频的采集和上行
_tRtcCloud.EnableCustomVideoCapture(TrtcVideoStreamTypeBig, true);
_tRtcCloud.EnableCustomAudioCapture(false);
_tRtcCloud.SetVideoEncoderMirror(false);
InitVideoParam(videoFps, videoBitrate, minVideoBitrate);
var renderParams = new TRTCRenderParams
{
FillMode = TrtcVideoRenderModeFit,
MirrorType = TrtcVideoMirrorTypeDisable
};
_tRtcCloud.SetLocalRenderParams(renderParams);
TRTCParams trtcParams = new TRTCParams
{
SdkAppId = appid,
RoomId = roomId,
UserId = userId,
UserSig = userSign,
Role = TRTCRoleAnchor
};
_tRtcCloud.SetListener(this);
_tRtcCloud.MuteLocalAudio(isMute);
_tRtcCloud.EnterRoom(trtcParams, TrtcAppSceneLive);
}
public void SetMute(bool isMute)
{
if (_tRtcCloud != null)
{
_tRtcCloud.MuteLocalAudio(isMute);
}
}
public void SwitchMic(string micId)
{
}
///
/// 离开房间
///
public void ExitRoom()
{
if (_tRtcCloud != null)
{
Logger.WriteLineInfo($"Exit room");
_tRtcCloud.StopAllRemoteView();
_tRtcCloud.StopLocalPreview();
_tRtcCloud.StopLocalAudio();
_tRtcCloud.MuteLocalAudio(true);
_tRtcCloud.MuteLocalVideo(0, true);
_exitResetEvent.Reset();
_tRtcCloud.ExitRoom();
_exitResetEvent.WaitOne(5000);
_tRtcCloud.SetListener(null);
_tRtcCloud = null;
}
}
///
/// 发送要推流的数据
///
///
///
///
public void SendData(int width, int height, IntPtr frameBuffer)
{
var len = width * height * 3 / 2;
if (_videoFrame == null)
{
_videoFrame = new TRTCVideoFrame
{
PixelFormat = TrtcVideoPixelFormatI420,
BufferType = TrtcVideoBufferTypeByteArray,
Width = width,
Height = height,
Timestamp = 0
};
}
if (_tempData == null)
{
_tempData = new byte[len];
}
else if (_tempData.Length != len)
{
Array.Resize(ref _tempData, len);
}
Marshal.Copy(frameBuffer, _tempData, 0, len);
_videoFrame.Data = _tempData;
_tRtcCloud?.SendCustomVideoData(TrtcVideoStreamTypeBig, _videoFrame);
}
///
/// 发送要推流的数据
///
///
///
///
public void SendData(int width, int height, byte[] frameBuffer)
{
var len = width * height * 3 / 2;
if (_videoFrame == null)
{
_videoFrame = new TRTCVideoFrame
{
PixelFormat = TrtcVideoPixelFormatI420,
BufferType = TrtcVideoBufferTypeByteArray,
Width = width,
Height = height,
Timestamp = 0,
};
}
_videoFrame.Data = frameBuffer;
_tRtcCloud?.SendCustomVideoData(TrtcVideoStreamTypeBig, _videoFrame);
}
private void InitVideoParam(int videoFps, int videoBitrate, int minVideoBitrate)
{
TRTCVideoEncParam videoEncParams = new TRTCVideoEncParam
{
VideoBitrate = videoBitrate,
MinVideoBitrate = minVideoBitrate,
VideoFps = videoFps,
VideoResolution = _videoResolution,
VideoResolutionMode = TrtcVideoResolutionModeLandscape,
EnableAdjustRes = false
};
_tRtcCloud.SetVideoEncoderParam(videoEncParams);
var qosParams = new TRTCNetworkQosParam
{
Preference = TrtcVideoQosPreferenceClear,
ControlMode = VideoQosControlServer,
};
_tRtcCloud.SetNetworkQosParam(qosParams);
}
#region 回调
public override void OnError(int errCode, string errMsg, Bundle extInfo)
{
Logger.WriteLineError(string.Format("RtcPusher: Tecent errCode : {0}, errMsg : {1}, ExtInfo = {2}", errCode, errMsg, extInfo));
}
public override void OnWarning(int warningCode, string warningMsg, Bundle extInfo)
{
if (warningCode == 1208)
{
return;
}
Logger.WriteLineWarn(string.Format("RtcPusher: Tecent warningCode : {0}, warningMsg : {1}, ExtInfo = {2}", warningCode, warningMsg, extInfo));
}
public override void OnSendFirstLocalVideoFrame(int p0)
{
Logger.WriteLineInfo($"onSendFirstLocalVideoFrame successed{p0}");
Task.Run(() =>//Felix:如果不用Task,容易Crash,会SIGSEGV Error
{
FirstFrameSend?.Invoke(null, EventArgs.Empty);
});
}
public override void OnEnterRoom(long result)
{
if (result > 0)
{
Logger.WriteLineInfo($"Enter Room Success!:{result}");
}
else
{
Logger.WriteLineInfo($"Enter Room Fail!:{result}");
}
}
public override void OnExitRoom(int reason)
{
Logger.WriteLineInfo($"Exit Room Success,{reason}");
_exitResetEvent.Set();
}
public override void OnConnectionLost()
{
Logger.WriteLineWarn("RtcPusher Tx connection lost");
}
public override void OnTryToReconnect()
{
Logger.WriteLineWarn("RtcPusher Tx try to reconnect");
}
public override void OnConnectionRecovery()
{
Logger.WriteLineWarn("RtcPusher Tx connection recovery");
}
public override void OnConnectOtherRoom(string userId, int errCode, string errMsg)
{
Logger.WriteLineInfo($"onConnectOtherRoom userId :{userId}, errCode: {errCode}, errMsg: {errMsg}");
}
public override void OnFirstVideoFrame(string p0, int p1, int p2, int p3)
{
}
public override void OnSpeedTestResult(TRTCSpeedTestResult currentResult)
{
}
#endregion 回调
}
}