FISTRTCClient.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using Android.App;
  2. using Android.Content;
  3. using Android.OS;
  4. using Com.Tencent.Trtc;
  5. using System;
  6. using System.Collections.Concurrent;
  7. using System.IO;
  8. using Vinno.FIS.TRTCClient.Common;
  9. using Vinno.FIS.TRTCClient.Common.Enum;
  10. using Vinno.FIS.TRTCClient.Common.FileTransfer;
  11. using Vinno.FIS.TRTCClient.Common.Log;
  12. using Vinno.FIS.TRTCClient.Common.Models;
  13. using Vinno.vCloud.FIS.CrossPlatform.Android.LiveVideo.RTC;
  14. namespace Vinno.FIS.TRTCClient.Android
  15. {
  16. public class FISTRTCClient
  17. {
  18. private static readonly ConcurrentDictionary<string, FileTransferWriter> _remoteVideoFileWriter = new ConcurrentDictionary<string, FileTransferWriter>();
  19. private static readonly ConcurrentDictionary<string, TRTCRemoteImageSizeData> _remoteImageList = new ConcurrentDictionary<string, TRTCRemoteImageSizeData>();
  20. private static TRTCChatRoom _trtcChatRoom;
  21. private static TRTCLivePusher _trtcPusher;
  22. private static bool _isLiveMode;
  23. private static string _localId;
  24. private static int _processId;
  25. private static string _fisFolderPath;
  26. private static DefaultLogEngine _logEngine;
  27. private static FileTransferReader _localVideoReader;
  28. private static Context _context;
  29. private static FileTransferReader _fileReaderFromCommonToTRTC;
  30. private static FileTransferWriter _fileWriterFromTRTCToCommon;
  31. private static string _logPath;
  32. private static int _localImageWidth;
  33. private static int _localImageHeight;
  34. internal static string TempFolderPath { get; private set; }
  35. public static void Init(Context context, string fisLogFolderPath, string fisFolderPath, bool isLiveMode)
  36. {
  37. try
  38. {
  39. _context = context;
  40. _isLiveMode = isLiveMode;
  41. _processId = Process.MyPid();
  42. if (string.IsNullOrEmpty(fisFolderPath))
  43. {
  44. _fisFolderPath = Path.Combine(Application.Context.GetExternalFilesDir(null).Path, "FIS");
  45. }
  46. else
  47. {
  48. _fisFolderPath = fisFolderPath;
  49. }
  50. if (string.IsNullOrEmpty(fisLogFolderPath))
  51. {
  52. _logPath = Path.Combine(_fisFolderPath, "FISLogs", "TRTCClientLogs");
  53. }
  54. else
  55. {
  56. _logPath = Path.Combine(fisLogFolderPath, "TRTCClientLogs");
  57. }
  58. if (!Directory.Exists(_fisFolderPath))
  59. {
  60. Directory.CreateDirectory(_fisFolderPath);
  61. }
  62. if (!Directory.Exists(_logPath))
  63. {
  64. Directory.CreateDirectory(_logPath);
  65. }
  66. if (_isLiveMode)
  67. {
  68. _logEngine = new DefaultLogEngine(_logPath, EnumLiveChannelCategory.Auxiliary1);
  69. Logger.RegisterEngine(_logEngine);
  70. _fileReaderFromCommonToTRTC = new FileTransferReader(FISTRTCConsts.CommonToTRTCLiveVideoMessageTransferFolder, FISTRTCConsts.DataTransferFolderForTRTCLiveVideo, _fisFolderPath, FISTRTCConsts.CommonToTRTCLiveVideoReserveMessageTransferFolder);
  71. _fileReaderFromCommonToTRTC.LogMsgThrow += OnLogMsgThrow;
  72. _fileReaderFromCommonToTRTC.DataReceived += OnDataReceived;
  73. _fileReaderFromCommonToTRTC.StartContinuousRead();
  74. _fileWriterFromTRTCToCommon = new FileTransferWriter(FISTRTCConsts.TRTCLiveVideoToCommonMessageTransferFolder, FISTRTCConsts.DataTransferFolderForTRTCLiveVideo, _fisFolderPath, null);
  75. _fileWriterFromTRTCToCommon.LogMsgThrow += OnLogMsgThrow;
  76. }
  77. else
  78. {
  79. _logEngine = new DefaultLogEngine(_logPath, EnumLiveChannelCategory.Main);
  80. Logger.RegisterEngine(_logEngine);
  81. _fileReaderFromCommonToTRTC = new FileTransferReader(FISTRTCConsts.CommonToTRTCConsultationMessageTransferFolder, FISTRTCConsts.DataTransferFolderForTRTCConsultation, _fisFolderPath, FISTRTCConsts.CommonToTRTCConsultationReserveMessageTransferFolder);
  82. _fileReaderFromCommonToTRTC.LogMsgThrow += OnLogMsgThrow;
  83. _fileReaderFromCommonToTRTC.DataReceived += OnDataReceived;
  84. _fileReaderFromCommonToTRTC.StartContinuousRead();
  85. _fileWriterFromTRTCToCommon = new FileTransferWriter(FISTRTCConsts.TRTCConsultationToCommonMessageTransferFolder, FISTRTCConsts.DataTransferFolderForTRTCConsultation, _fisFolderPath, null);
  86. _fileWriterFromTRTCToCommon.LogMsgThrow += OnLogMsgThrow;
  87. }
  88. Logger.WriteLineInfo($"TRTCClient Init,Current Process Id:{_processId},IsLiveMode:{_isLiveMode}");
  89. }
  90. catch (Exception ex)
  91. {
  92. Logger.WriteLineError($"FISTRTCClient Init Error:{ex}");
  93. }
  94. }
  95. private static void OnLogMsgThrow(object sender, LogEventArgs e)
  96. {
  97. switch (e.LogType)
  98. {
  99. case DeviceLogCategory.Error:
  100. Logger.WriteLineError(e.Msg);
  101. break;
  102. case DeviceLogCategory.Info:
  103. Logger.WriteLineInfo(e.Msg);
  104. break;
  105. case DeviceLogCategory.Warn:
  106. Logger.WriteLineWarn(e.Msg);
  107. break;
  108. case DeviceLogCategory.Verb:
  109. Logger.WriteLineDebug(e.Msg);
  110. break;
  111. }
  112. }
  113. private static void OnDataReceived(object sender, byte[] e)
  114. {
  115. try
  116. {
  117. if (e == null)
  118. {
  119. return;
  120. }
  121. var trtcMessage = TRTCMessage.FromBytes(e);
  122. Logger.WriteLineInfo($"FISTRTCClient OnDataReceived:{trtcMessage.MessageType}");
  123. switch (trtcMessage.MessageType)
  124. {
  125. case EnumMessageType.EnterRoom:
  126. var roomInfo = TRTCRoomInfo.FromBytes(trtcMessage?.MessageData);
  127. if (roomInfo != null)
  128. {
  129. Enter(roomInfo, _context);
  130. }
  131. break;
  132. case EnumMessageType.ImageSizeChanged:
  133. var imageSizeData = TRTCImageSizeData.FromBytes(trtcMessage?.MessageData);
  134. if (imageSizeData != null)
  135. {
  136. _localImageHeight = imageSizeData.Height;
  137. _localImageWidth = imageSizeData.Width;
  138. }
  139. break;
  140. case EnumMessageType.ExitRoom:
  141. Exit();
  142. break;
  143. case EnumMessageType.Mute:
  144. var mute = BitConverter.ToBoolean(trtcMessage?.MessageData, 0);
  145. SetMute(mute);
  146. break;
  147. case EnumMessageType.UpdateCameraId:
  148. var cameraIdMessage = TRTCStringMessage.FromBytes(trtcMessage.MessageData);
  149. if (cameraIdMessage != null)
  150. {
  151. if (!_isLiveMode)
  152. {
  153. _trtcChatRoom?.UpdateCameraId(cameraIdMessage.Value);
  154. Logger.WriteLineInfo($"TrtcChatRoom UpdateCameraId {cameraIdMessage.Value}");
  155. }
  156. }
  157. break;
  158. }
  159. }
  160. catch (Exception ex)
  161. {
  162. Logger.WriteLineError($"FISTRTCClient OnDataReceived Error:{ex}");
  163. }
  164. }
  165. public static void Enter(TRTCRoomInfo roomInfo, Context context)
  166. {
  167. try
  168. {
  169. Logger.WriteLineInfo("TRTCClient Start Up......");
  170. Logger.WriteLineInfo($"RoomInfo:{roomInfo}");
  171. _localId = roomInfo.UserId;
  172. StartLocalVideoFileReader();
  173. if (_isLiveMode)
  174. {
  175. _trtcPusher = new TRTCLivePusher(_logPath, context);
  176. _trtcPusher.FirstFrameSend += OnFirstFrameSend;
  177. var videoResolution = GetResolution(roomInfo.OutputWidth, roomInfo.OutputHeight);
  178. _trtcPusher.EnterRoom(roomInfo.UserId, (int)roomInfo.RoomId, roomInfo.UserSig, (int)roomInfo.AppId, videoResolution, (int)roomInfo.VideoFps, (int)roomInfo.VideoBitrate, (int)roomInfo.MinVideoBitrate, roomInfo.IsMute, null);
  179. }
  180. else
  181. {
  182. _trtcChatRoom = new TRTCChatRoom(_logPath, context);
  183. _trtcChatRoom.RemoteVideoFrameArrived += OnRemoteVideoFrameReceived;
  184. _trtcChatRoom.OnTRTCEnterRoomError += OnEnterRoomError;
  185. _trtcChatRoom.RemoteUserLeaveRoomArrived += OnRemoteUserLeaveRoomArrived;
  186. _trtcChatRoom.TryToReconnect += OnTryToReconnect;
  187. var videoResolution = GetResolution(roomInfo.OutputWidth, roomInfo.OutputHeight);
  188. _trtcChatRoom.Enter(roomInfo, videoResolution);
  189. if (roomInfo.TerminalIsPushing && roomInfo.TerminalRoomId > 0)
  190. {
  191. _trtcChatRoom.ConnectRoom(roomInfo.TerminalRoomId, roomInfo.TerminalId);
  192. }
  193. }
  194. }
  195. catch (Exception ex)
  196. {
  197. Logger.WriteLineError($"FISTRTCClient Start Error:{ex}");
  198. }
  199. }
  200. private static void OnFirstFrameSend(object sender, EventArgs e)
  201. {
  202. Logger.WriteLineInfo($"OnFirstFrameSend Invoke");
  203. var firstFrame = new TRTCMessage(EnumMessageType.FirstFrameReceived, new byte[0]);
  204. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(firstFrame.ToBytes());
  205. }
  206. private static int GetResolution(int width, int height)
  207. {
  208. if (width <= 640 && height <= 480)
  209. {
  210. return TRTCCloudDef.TrtcVideoResolution640480;
  211. }
  212. else if (width <= 960 && height <= 544)
  213. {
  214. return TRTCCloudDef.TrtcVideoResolution960540;
  215. }
  216. else if (width <= 960 && height <= 720)
  217. {
  218. return TRTCCloudDef.TrtcVideoResolution960720;
  219. }
  220. else if (width <= 1280 && height <= 720)
  221. {
  222. return TRTCCloudDef.TrtcVideoResolution1280720;
  223. }
  224. else
  225. {
  226. return TRTCCloudDef.TrtcVideoResolution19201080;
  227. }
  228. }
  229. private static void StartLocalVideoFileReader()
  230. {
  231. if (_isLiveMode)
  232. {
  233. if (_localVideoReader == null)
  234. {
  235. _localVideoReader = new FileTransferReader($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationLocalVideo}_{_localId}", FISTRTCConsts.DataTransferFolderForTRTCLiveVideo, _fisFolderPath, null);
  236. _localVideoReader.LogMsgThrow += OnLogMsgThrow;
  237. _localVideoReader.DataReceived += OnLocalVideoFrameReceived;
  238. _localVideoReader.StartContinuousRead();
  239. Logger.WriteLineInfo($"Start Local Video File Reader:{_localVideoReader.Name}");
  240. }
  241. }
  242. else
  243. {
  244. if (_localVideoReader == null)
  245. {
  246. _localVideoReader = new FileTransferReader($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationLocalVideo}_{_localId}", FISTRTCConsts.DataTransferFolderForTRTCConsultation, _fisFolderPath, null);
  247. _localVideoReader.LogMsgThrow += OnLogMsgThrow;
  248. _localVideoReader.DataReceived += OnLocalVideoFrameReceived;
  249. _localVideoReader.StartContinuousRead();
  250. Logger.WriteLineInfo($"Start Local Video File Reader:{_localVideoReader.Name}");
  251. }
  252. }
  253. }
  254. private static void OnLocalVideoFrameReceived(object sender, byte[] e)
  255. {
  256. if (e == null)
  257. {
  258. return;
  259. }
  260. if (e.Length != _localImageHeight * _localImageWidth * 3 / 2)
  261. {
  262. return;
  263. }
  264. if (_isLiveMode)
  265. {
  266. _trtcPusher?.SendData(_localImageWidth, _localImageHeight, e);
  267. }
  268. else
  269. {
  270. _trtcChatRoom?.SendData(_localImageWidth, _localImageHeight, e);
  271. }
  272. }
  273. private static void StopLocalVideoFileReader()
  274. {
  275. if (_localVideoReader != null)
  276. {
  277. _localVideoReader.DataReceived -= OnLocalVideoFrameReceived;
  278. _localVideoReader.Dispose();
  279. _localVideoReader.LogMsgThrow -= OnLogMsgThrow;
  280. _localVideoReader = null;
  281. }
  282. }
  283. public static void Exit()
  284. {
  285. try
  286. {
  287. ExitRoom();
  288. StopFileTransfer();
  289. }
  290. catch (Exception ex)
  291. {
  292. Logger.WriteLineError($"FISTRTCClient Stop error:{ex}");
  293. }
  294. }
  295. private static void ExitRoom()
  296. {
  297. try
  298. {
  299. if (_trtcChatRoom != null)
  300. {
  301. _trtcChatRoom.RemoteVideoFrameArrived -= OnRemoteVideoFrameReceived;
  302. _trtcChatRoom.OnTRTCEnterRoomError -= OnEnterRoomError;
  303. _trtcChatRoom.RemoteUserLeaveRoomArrived -= OnRemoteUserLeaveRoomArrived;
  304. _trtcChatRoom.TryToReconnect -= OnTryToReconnect;
  305. _trtcChatRoom.Exit();
  306. _trtcChatRoom = null;
  307. Logger.WriteLineInfo("Exit Room success");
  308. }
  309. if (_trtcPusher != null)
  310. {
  311. _trtcPusher.FirstFrameSend -= OnFirstFrameSend;
  312. _trtcPusher.ExitRoom();
  313. _trtcPusher.Dispose();
  314. _trtcPusher = null;
  315. }
  316. }
  317. catch (Exception ex)
  318. {
  319. Logger.WriteLineError($"FISTRTCClient Exit Room error:{ex}");
  320. }
  321. }
  322. private static void StopFileTransfer()
  323. {
  324. try
  325. {
  326. Logger.WriteLineInfo("Stop File Writers");
  327. StopLocalVideoFileReader();
  328. foreach (var userId in _remoteVideoFileWriter.Keys)
  329. {
  330. Logger.WriteLineInfo($"Stop File Writer Remote Video{_remoteVideoFileWriter[userId].Name}");
  331. _remoteVideoFileWriter[userId].Dispose();
  332. _remoteVideoFileWriter[userId].LogMsgThrow -= OnLogMsgThrow;
  333. }
  334. _remoteVideoFileWriter.Clear();
  335. }
  336. catch (Exception ex)
  337. {
  338. Logger.WriteLineError($"FISTRTCClient Stop error:{ex}");
  339. }
  340. }
  341. public static void Destroy()
  342. {
  343. if (_fileReaderFromCommonToTRTC != null)
  344. {
  345. _fileReaderFromCommonToTRTC.DataReceived -= OnDataReceived;
  346. _fileReaderFromCommonToTRTC.Dispose();
  347. _fileReaderFromCommonToTRTC.LogMsgThrow -= OnLogMsgThrow;
  348. _fileReaderFromCommonToTRTC = null;
  349. }
  350. if (_fileWriterFromTRTCToCommon != null)
  351. {
  352. _fileWriterFromTRTCToCommon.Dispose();
  353. _fileWriterFromTRTCToCommon.LogMsgThrow -= OnLogMsgThrow;
  354. _fileWriterFromTRTCToCommon = null;
  355. }
  356. }
  357. public static void SetMute(bool isMute)
  358. {
  359. if (_isLiveMode)
  360. {
  361. if (_trtcPusher != null)
  362. {
  363. _trtcPusher.SetMute(isMute);
  364. }
  365. }
  366. else
  367. {
  368. if (_trtcChatRoom != null)
  369. {
  370. _trtcChatRoom.Mute(isMute);
  371. }
  372. }
  373. }
  374. private static void OnRemoteVideoFrameReceived(object sender, TRTCVideoFrameData e)
  375. {
  376. try
  377. {
  378. if (string.IsNullOrEmpty(e.UserId))
  379. {
  380. return;
  381. }
  382. if (!_remoteVideoFileWriter.ContainsKey(e.UserId))
  383. {
  384. StartNewRemoteVideoFileWriter(e.UserId, e.Width, e.Height);
  385. }
  386. if (!_remoteImageList.ContainsKey(e.UserId))
  387. {
  388. if (_remoteImageList.TryAdd(e.UserId, new TRTCRemoteImageSizeData(e.UserId, e.Width, e.Height)))
  389. {
  390. Logger.WriteLineInfo($"RemoteImageSize Invoke,UserId:{e.UserId},Width:{e.Width},Height:{e.Height}");
  391. var remoteImageSizeData = new TRTCRemoteImageSizeData(e.UserId, e.Width, e.Height);
  392. var trtcMessage = new TRTCMessage(EnumMessageType.RemoteImageSizeChanged, remoteImageSizeData.ToBytes());
  393. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(trtcMessage.ToBytes());
  394. }
  395. }
  396. _remoteVideoFileWriter[e.UserId].WriteToFileContinuous(e.Data);
  397. }
  398. catch (Exception ex)
  399. {
  400. Logger.WriteLineError($"OnRemoteVideoFrameReceived error:userId:{e.UserId},{ex}");
  401. }
  402. }
  403. private static void StartNewRemoteVideoFileWriter(string userId, int width, int height)
  404. {
  405. var remoteVideoFileWriter = new FileTransferWriter($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationRemoteVideo}_{userId}", FISTRTCConsts.DataTransferFolderForTRTCConsultation, _fisFolderPath, null);
  406. if (!_remoteVideoFileWriter.TryAdd(userId, remoteVideoFileWriter))
  407. {
  408. OnLogMsgThrow(null, new LogEventArgs(DeviceLogCategory.Error, $"Remote Video File Writer List Try Add Failed, Id: {userId}"));
  409. }
  410. else
  411. {
  412. Logger.WriteLineInfo($"Start Remote Video File Writer Client :{remoteVideoFileWriter.Name},Width:{width},Height:{height}");
  413. var remoteMessage = new TRTCRemoteImageSizeData(userId, width, height);
  414. var fileTransferMessageData = new TRTCMessage(EnumMessageType.AddRemoteFileTransfer, remoteMessage.ToBytes());
  415. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  416. remoteVideoFileWriter.LogMsgThrow += OnLogMsgThrow;
  417. }
  418. }
  419. private static void OnEnterRoomError(object sender, EventArgs e)
  420. {
  421. var fileTransferMessageData = new TRTCMessage(EnumMessageType.EnterRoomError, null);
  422. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  423. Logger.WriteLineInfo($"OnEnterRoomError Invoked");
  424. }
  425. private static void OnRemoteUserLeaveRoomArrived(object sender, TRTCRemoteUserLeaveRoomMessage e)
  426. {
  427. var fileTransferMessageData = new TRTCMessage(EnumMessageType.RemoteUserLeaveRoom, e.ToBytes());
  428. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  429. Logger.WriteLineInfo($"OnRemoteUserLeaveRoomArrived Invoked,userId:{e.UserId},reason:{e.Reason}.");
  430. }
  431. private static void OnTryToReconnect(object sender, EventArgs e)
  432. {
  433. var fileTransferMessageData = new TRTCMessage(EnumMessageType.TryToReconnect, null);
  434. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  435. Logger.WriteLineInfo("OnTryToReconnect Invoked.");
  436. }
  437. }
  438. }