using Android.Content; using Android.OS; using Com.Tencent.Trtc; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Threading; using System.Threading.Tasks; using Vinno.FIS.TRTCClient.Common.Log; using Vinno.FIS.TRTCClient.Common.Models; using static Com.Tencent.Trtc.TRTCCloudDef; namespace Vinno.FIS.TRTCClient.Android { internal class TRTCChatRoom : TRTCCloudListener { private const int JoinAndLeaveRoomTimeout = 8000; private readonly AutoResetEvent _joinRoomWiator = new AutoResetEvent(false); private readonly AutoResetEvent _leafRoomWiator = new AutoResetEvent(false); private TRTCCloud _trtcCloud; private uint _roomId; private bool _enterRoomSuccess = false; private bool _isOldServerMode; private RemoteVideoRenderListener _remoteRenderListener; private TRTCVideoFrame _videoFrame; private uint _connectRoomId; private string _connectUserId; private int _reconnectTryCount; private int _videoResolution; private string _terminalId; private string _cameraId; public event EventHandler RemoteUserLeaveRoomArrived; public event EventHandler TryToReconnect; /// /// Remote device video frame arrived /// public event EventHandler RemoteVideoFrameArrived; public event EventHandler OnTRTCEnterRoomError; public TRTCChatRoom(string logPath, Context context) { TRTCCloud.SetLogCompressEnabled(false); TRTCCloud.SetLogDirPath(logPath); TRTCCloud.SetLogLevel(TrtcLogLevelError); _trtcCloud = TRTCCloud.SharedInstance(context); _remoteRenderListener = new RemoteVideoRenderListener(OnRemoteVideoFrameArrived); } /// /// enter room /// /// /// /// /// /// public void Enter(TRTCRoomInfo roomInfo, int videoResolution) { Logger.WriteLineInfo($"RtcChatRoom {roomInfo.RoomId} Enter begin"); _videoResolution = videoResolution; _terminalId = roomInfo.TerminalId; _cameraId = roomInfo.CameraId; _isOldServerMode = roomInfo.IsOldServerMode; _roomId = roomInfo.RoomId; _trtcCloud.StartLocalAudio(TrtcAudioQualityMusic); _trtcCloud.EnableCustomVideoCapture(TrtcVideoStreamTypeBig, true); _trtcCloud.EnableCustomAudioCapture(false); InitVideoParam(15, 1000, 600); var renderParams = new TRTCRenderParams { FillMode = TrtcVideoRenderModeFit, MirrorType = TrtcVideoMirrorTypeDisable }; _trtcCloud.SetLocalRenderParams(renderParams); TRTCParams trtcParams = new TRTCParams { SdkAppId = (int)roomInfo.AppId, RoomId = (int)roomInfo.RoomId, UserId = roomInfo.UserId, UserSig = roomInfo.UserSig, PrivateMapKey = "", BusinessInfo = "" }; _trtcCloud.SetListener(this); _trtcCloud.EnterRoom(trtcParams, TrtcAppSceneVideocall); Logger.WriteLineInfo($"RtcChatRoom JoinRoom exectuted"); if (!_joinRoomWiator.WaitOne(JoinAndLeaveRoomTimeout)) { Logger.WriteLineWarn("RtcChatRoom Joint Room timeout"); } } internal void UpdateCameraId(string cameraId) { _cameraId = cameraId; } /// /// 发送要推流的数据 /// /// /// /// 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); } /// /// Exit Room /// public void Exit() { if (_trtcCloud == null) { return; } Logger.WriteLineInfo($"RtcChatRoom {_roomId} Exit begin"); _trtcCloud.StopAllRemoteView(); _trtcCloud.StopLocalPreview(); _trtcCloud.StopLocalAudio(); _trtcCloud.MuteLocalAudio(true); _trtcCloud.MuteLocalVideo(0, true); _roomId = 0; _connectRoomId = 0; _connectUserId = string.Empty; _trtcCloud.ExitRoom(); if (_enterRoomSuccess && !_leafRoomWiator.WaitOne(JoinAndLeaveRoomTimeout)) { Logger.WriteLineWarn("RtcChatRoom exit Room timeout"); } _enterRoomSuccess = false; _trtcCloud.SetListener(null); _trtcCloud = null; TRTCCloud.DestroySharedInstance(); Logger.WriteLineInfo($"RtcChatRoom {_roomId} Exit end "); } private void OnRemoteVideoFrameArrived(TRTCVideoFrameData data) { if (_isOldServerMode || (_terminalId != data.UserId && _cameraId != data.UserId))//超声机画面过滤,只拉取远端用户画面 { RemoteVideoFrameArrived?.Invoke(this, data); } } public override void OnError(int errCode, string errMsg, Bundle extInfo) { Logger.WriteLineError($"{errCode},{errMsg},{extInfo}"); } public override void OnWarning(int warningCode, string warningMsg, Bundle extInfo) { Logger.WriteLineWarn($"{warningCode},{warningMsg},{extInfo}"); } public override void OnEnterRoom(long result) { Logger.WriteLineInfo($"onEnterRoom result: {result}"); _joinRoomWiator.Set(); if (result >= 0) { _enterRoomSuccess = true; } else { OnTRTCEnterRoomError?.Invoke(this, EventArgs.Empty); } } public override void OnExitRoom(int reason) { Logger.WriteLineInfo($"onExitRoom reason: {reason}"); _leafRoomWiator.Set(); } public override void OnConnectOtherRoom(string userId, int errCode, string errMsg) { Logger.WriteLineInfo($"onConnectOtherRoom userId :{userId}, errCode: {errCode}, errMsg: {errMsg}"); if (errCode != 0 && _reconnectTryCount <= 3) { ReconnectOtherRoom("onConnectOtherRoom failed"); } } public override void OnRemoteUserLeaveRoom(string userId, int reason) { Logger.WriteLineInfo($"Remote User Leave Room,userId:{userId},reason:{reason}"); RemoteUserLeaveRoomArrived?.Invoke(this, new TRTCRemoteUserLeaveRoomMessage(userId, reason)); } public override void OnUserVideoAvailable(string userId, bool available) { if (available) { //远程用户可用 _trtcCloud.SetRemoteVideoRenderListener(userId, TrtcVideoPixelFormatRgba, TrtcVideoBufferTypeByteBuffer, _remoteRenderListener); _trtcCloud.StartRemoteView(userId, 0, null); _trtcCloud.SetRemoteRenderParams(userId, 0, new TRTCRenderParams { FillMode = TrtcVideoRenderModeFit, MirrorType = TrtcVideoMirrorTypeDisable, Rotation = TrtcVideoRotation0, }); } else { //远程用户离开 _trtcCloud.StopRemoteView(userId, 0); if (!string.IsNullOrEmpty(_connectUserId) && _connectUserId == userId && _reconnectTryCount <= 3) { Task.Run(() => { ReconnectOtherRoom("onUserVideoAvailable false"); }); } } Logger.WriteLineInfo($"onUserVideoAvailable userId: {userId}, available: {available}"); } private async void ReconnectOtherRoom(string reason) { await Task.Delay(1000); if (_enterRoomSuccess) { Logger.WriteLineInfo($"Reason:{reason},OnReconnect Other Room userId: {_connectUserId}, roomId {_connectRoomId}"); ConnectRoom(_connectRoomId, _connectUserId); _reconnectTryCount++; } } public void ConnectRoom(uint roomId, string terminalId) { var jsonObj = new JObject(); jsonObj["roomId"] = roomId; jsonObj["userId"] = terminalId; _connectRoomId = roomId; _connectUserId = terminalId; _reconnectTryCount = 0; var jsonData = JsonConvert.SerializeObject(jsonObj); Logger.WriteLineInfo($"TRTC ConnectRoom Room id {roomId} - terminal id: {terminalId}"); _trtcCloud.ConnectOtherRoom(jsonData); } public void SwitchCamera() { } public void Mute(bool isMute) { _trtcCloud.MuteLocalAudio(isMute); } /// /// 开始渲染本地或远程用户的首帧画面 /// /// /// d /// /// public override void OnFirstVideoFrame(string userId, int streamType, int width, int height) { Logger.WriteLineInfo($"OnFirstVideoFrame userId: {userId},{streamType},{width},{height}"); } public override void OnConnectionLost() { Logger.WriteLineInfo($"onConnectionLost"); } public override void OnTryToReconnect() { Logger.WriteLineInfo($"onTryToReconnect"); TryToReconnect?.Invoke(this, EventArgs.Empty); } public override void OnConnectionRecovery() { Logger.WriteLineInfo($"onConnectionRecovery"); } public override void OnStartPublishing(int errCode, string errMsg) { Logger.WriteLineInfo($"onStartPublishing errCode: {errCode}, errMsg: {errMsg}"); } public override void OnStopPublishing(int errCode, string errMsg) { Logger.WriteLineInfo($"onStopPublishing errCode: {errCode}, errMsg: {errMsg}"); } public override void OnSwitchRoom(int errCode, string errMsg) { Logger.WriteLineInfo($"onSwitchRoom: {errCode}, errMsg: {errMsg}"); } } }