FISTRTCClient.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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 TRTCPusher _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.ImageTransferFolderForTRTCLiveVideo, _fisFolderPath);
  71. _fileReaderFromCommonToTRTC.LogMsgThrow += OnLogMsgThrow;
  72. _fileReaderFromCommonToTRTC.DataReceived += OnDataReceived;
  73. _fileReaderFromCommonToTRTC.StartContinuousRead();
  74. _fileWriterFromTRTCToCommon = new FileTransferWriter(FISTRTCConsts.TRTCLiveVideoToCommonMessageTransferFolder, FISTRTCConsts.ImageTransferFolderForTRTCLiveVideo, _fisFolderPath);
  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.ImageTransferFolderForTRTCConsultation, _fisFolderPath);
  82. _fileReaderFromCommonToTRTC.LogMsgThrow += OnLogMsgThrow;
  83. _fileReaderFromCommonToTRTC.DataReceived += OnDataReceived;
  84. _fileReaderFromCommonToTRTC.StartContinuousRead();
  85. _fileWriterFromTRTCToCommon = new FileTransferWriter(FISTRTCConsts.TRTCConsultationToCommonMessageTransferFolder, FISTRTCConsts.ImageTransferFolderForTRTCConsultation, _fisFolderPath);
  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. }
  148. }
  149. catch (Exception ex)
  150. {
  151. Logger.WriteLineError($"FISTRTCClient OnDataReceived Error:{ex}");
  152. }
  153. }
  154. public static void Enter(TRTCRoomInfo roomInfo, Context context)
  155. {
  156. try
  157. {
  158. Logger.WriteLineInfo("TRTCClient Start Up......");
  159. Logger.WriteLineInfo($"RoomInfo:{roomInfo}");
  160. _localId = roomInfo.UserId;
  161. StartLocalVideoFileReader();
  162. if (_isLiveMode)
  163. {
  164. _trtcPusher = new TRTCPusher(_logPath, context);
  165. _trtcPusher.FirstFrameSend += OnFirstFrameSend;
  166. var videoResolution = GetResolution(roomInfo.OutputWidth, roomInfo.OutputHeight);
  167. _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);
  168. }
  169. else
  170. {
  171. _trtcChatRoom = new TRTCChatRoom(_logPath, context);
  172. _trtcChatRoom.RemoteVideoFrameArrived += OnRemoteVideoFrameReceived;
  173. _trtcChatRoom.OnTRTCEnterRoomError += OnEnterRoomError;
  174. _trtcChatRoom.RemoteUserLeaveRoomArrived += OnRemoteUserLeaveRoomArrived;
  175. _trtcChatRoom.TryToReconnect += OnTryToReconnect;
  176. var videoResolution = GetResolution(roomInfo.OutputWidth, roomInfo.OutputHeight);
  177. _trtcChatRoom.Enter(roomInfo, videoResolution);
  178. if (roomInfo.TerminalIsPushing && roomInfo.TerminalRoomId > 0)
  179. {
  180. _trtcChatRoom.ConnectRoom(roomInfo.TerminalRoomId, roomInfo.TerminalId);
  181. }
  182. }
  183. }
  184. catch (Exception ex)
  185. {
  186. Logger.WriteLineError($"FISTRTCClient Start Error:{ex}");
  187. }
  188. }
  189. private static void OnFirstFrameSend(object sender, EventArgs e)
  190. {
  191. Logger.WriteLineInfo($"OnFirstFrameSend Invoke");
  192. var firstFrame = new TRTCMessage(EnumMessageType.FirstFrameReceived, new byte[0]);
  193. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(firstFrame.ToBytes());
  194. }
  195. private static int GetResolution(int width, int height)
  196. {
  197. if (width <= 640 && height <= 480)
  198. {
  199. return TRTCCloudDef.TrtcVideoResolution640480;
  200. }
  201. else if (width <= 960 && height <= 544)
  202. {
  203. return TRTCCloudDef.TrtcVideoResolution960540;
  204. }
  205. else if (width <= 960 && height <= 720)
  206. {
  207. return TRTCCloudDef.TrtcVideoResolution960720;
  208. }
  209. else if (width <= 1280 && height <= 720)
  210. {
  211. return TRTCCloudDef.TrtcVideoResolution1280720;
  212. }
  213. else
  214. {
  215. return TRTCCloudDef.TrtcVideoResolution19201080;
  216. }
  217. }
  218. private static void StartLocalVideoFileReader()
  219. {
  220. if (_isLiveMode)
  221. {
  222. if (_localVideoReader == null)
  223. {
  224. _localVideoReader = new FileTransferReader($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationLocalVideo}_{_localId}", FISTRTCConsts.ImageTransferFolderForTRTCLiveVideo, _fisFolderPath);
  225. _localVideoReader.LogMsgThrow += OnLogMsgThrow;
  226. _localVideoReader.DataReceived += OnLocalVideoFrameReceived;
  227. _localVideoReader.StartContinuousRead();
  228. Logger.WriteLineInfo($"Start Local Video File Reader:{_localVideoReader.Name}");
  229. }
  230. }
  231. else
  232. {
  233. if (_localVideoReader == null)
  234. {
  235. _localVideoReader = new FileTransferReader($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationLocalVideo}_{_localId}", FISTRTCConsts.ImageTransferFolderForTRTCConsultation, _fisFolderPath);
  236. _localVideoReader.LogMsgThrow += OnLogMsgThrow;
  237. _localVideoReader.DataReceived += OnLocalVideoFrameReceived;
  238. _localVideoReader.StartContinuousRead();
  239. Logger.WriteLineInfo($"Start Local Video File Reader:{_localVideoReader.Name}");
  240. }
  241. }
  242. }
  243. private static void OnLocalVideoFrameReceived(object sender, byte[] e)
  244. {
  245. if (e == null)
  246. {
  247. return;
  248. }
  249. if (e.Length != _localImageHeight * _localImageWidth * 3 / 2)
  250. {
  251. return;
  252. }
  253. if (_isLiveMode)
  254. {
  255. _trtcPusher?.SendData(_localImageWidth, _localImageHeight, e);
  256. }
  257. else
  258. {
  259. _trtcChatRoom?.SendData(_localImageWidth, _localImageHeight, e);
  260. }
  261. }
  262. private static void StopLocalVideoFileReader()
  263. {
  264. if (_localVideoReader != null)
  265. {
  266. _localVideoReader.DataReceived -= OnLocalVideoFrameReceived;
  267. _localVideoReader.Dispose();
  268. _localVideoReader.LogMsgThrow -= OnLogMsgThrow;
  269. _localVideoReader = null;
  270. }
  271. }
  272. public static void Exit()
  273. {
  274. try
  275. {
  276. ExitRoom();
  277. StopFileTransfer();
  278. }
  279. catch (Exception ex)
  280. {
  281. Logger.WriteLineError($"FISTRTCClient Stop error:{ex}");
  282. }
  283. }
  284. private static void ExitRoom()
  285. {
  286. try
  287. {
  288. if (_trtcChatRoom != null)
  289. {
  290. _trtcChatRoom.RemoteVideoFrameArrived -= OnRemoteVideoFrameReceived;
  291. _trtcChatRoom.OnTRTCEnterRoomError -= OnEnterRoomError;
  292. _trtcChatRoom.RemoteUserLeaveRoomArrived -= OnRemoteUserLeaveRoomArrived;
  293. _trtcChatRoom.TryToReconnect -= OnTryToReconnect;
  294. _trtcChatRoom.Exit();
  295. _trtcChatRoom = null;
  296. Logger.WriteLineInfo("Exit Room success");
  297. }
  298. if (_trtcPusher != null)
  299. {
  300. _trtcPusher.FirstFrameSend -= OnFirstFrameSend;
  301. _trtcPusher.ExitRoom();
  302. _trtcPusher.Dispose();
  303. _trtcPusher = null;
  304. }
  305. }
  306. catch (Exception ex)
  307. {
  308. Logger.WriteLineError($"FISTRTCClient Exit Room error:{ex}");
  309. }
  310. }
  311. private static void StopFileTransfer()
  312. {
  313. try
  314. {
  315. Logger.WriteLineInfo("Stop File Writers");
  316. StopLocalVideoFileReader();
  317. foreach (var userId in _remoteVideoFileWriter.Keys)
  318. {
  319. Logger.WriteLineInfo($"Stop File Writer Remote Video{_remoteVideoFileWriter[userId].Name}");
  320. _remoteVideoFileWriter[userId].Dispose();
  321. _remoteVideoFileWriter[userId].LogMsgThrow -= OnLogMsgThrow;
  322. }
  323. _remoteVideoFileWriter.Clear();
  324. }
  325. catch (Exception ex)
  326. {
  327. Logger.WriteLineError($"FISTRTCClient Stop error:{ex}");
  328. }
  329. }
  330. public static void Destroy()
  331. {
  332. if (_fileReaderFromCommonToTRTC != null)
  333. {
  334. _fileReaderFromCommonToTRTC.DataReceived -= OnDataReceived;
  335. _fileReaderFromCommonToTRTC.Dispose();
  336. _fileReaderFromCommonToTRTC.LogMsgThrow -= OnLogMsgThrow;
  337. _fileReaderFromCommonToTRTC = null;
  338. }
  339. if (_fileWriterFromTRTCToCommon != null)
  340. {
  341. _fileWriterFromTRTCToCommon.Dispose();
  342. _fileWriterFromTRTCToCommon.LogMsgThrow -= OnLogMsgThrow;
  343. _fileWriterFromTRTCToCommon = null;
  344. }
  345. }
  346. public static void SetMute(bool isMute)
  347. {
  348. if (_isLiveMode)
  349. {
  350. if (_trtcPusher != null)
  351. {
  352. _trtcPusher.SetMute(isMute);
  353. }
  354. }
  355. else
  356. {
  357. if (_trtcChatRoom != null)
  358. {
  359. _trtcChatRoom.Mute(isMute);
  360. }
  361. }
  362. }
  363. private static void OnRemoteVideoFrameReceived(object sender, TRTCVideoFrameData e)
  364. {
  365. try
  366. {
  367. if (string.IsNullOrEmpty(e.UserId))
  368. {
  369. return;
  370. }
  371. if (!_remoteVideoFileWriter.ContainsKey(e.UserId))
  372. {
  373. StartNewRemoteVideoFileWriter(e.UserId, e.Width, e.Height);
  374. }
  375. if (!_remoteImageList.ContainsKey(e.UserId))
  376. {
  377. if (_remoteImageList.TryAdd(e.UserId, new TRTCRemoteImageSizeData(e.UserId, e.Width, e.Height)))
  378. {
  379. Logger.WriteLineInfo($"RemoteImageSize Invoke,UserId:{e.UserId},Width:{e.Width},Height:{e.Height}");
  380. var remoteImageSizeData = new TRTCRemoteImageSizeData(e.UserId, e.Width, e.Height);
  381. var trtcMessage = new TRTCMessage(EnumMessageType.RemoteImageSizeChanged, remoteImageSizeData.ToBytes());
  382. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(trtcMessage.ToBytes());
  383. }
  384. }
  385. _remoteVideoFileWriter[e.UserId].WriteToFileContinuous(e.Data);
  386. }
  387. catch (Exception ex)
  388. {
  389. Logger.WriteLineError($"OnRemoteVideoFrameReceived error:userId:{e.UserId},{ex}");
  390. }
  391. }
  392. private static void StartNewRemoteVideoFileWriter(string userId, int width, int height)
  393. {
  394. var remoteVideoFileWriter = new FileTransferWriter($"{FISTRTCConsts.ImageTransferFolderForTRTCConsultationRemoteVideo}_{userId}", FISTRTCConsts.ImageTransferFolderForTRTCConsultation, _fisFolderPath);
  395. if (!_remoteVideoFileWriter.TryAdd(userId, remoteVideoFileWriter))
  396. {
  397. OnLogMsgThrow(null, new LogEventArgs(DeviceLogCategory.Error, $"Remote Video File Writer List Try Add Failed, Id: {userId}"));
  398. }
  399. else
  400. {
  401. Logger.WriteLineInfo($"Start Remote Video File Writer Client :{remoteVideoFileWriter.Name},Width:{width},Height:{height}");
  402. var remoteMessage = new TRTCRemoteImageSizeData(userId, width, height);
  403. var fileTransferMessageData = new TRTCMessage(EnumMessageType.AddRemoteFileTransfer, remoteMessage.ToBytes());
  404. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  405. remoteVideoFileWriter.LogMsgThrow += OnLogMsgThrow;
  406. }
  407. }
  408. private static void OnEnterRoomError(object sender, EventArgs e)
  409. {
  410. var fileTransferMessageData = new TRTCMessage(EnumMessageType.EnterRoomError, null);
  411. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  412. Logger.WriteLineInfo($"OnEnterRoomError Invoked");
  413. }
  414. private static void OnRemoteUserLeaveRoomArrived(object sender, TRTCRemoteUserLeaveRoomMessage e)
  415. {
  416. var fileTransferMessageData = new TRTCMessage(EnumMessageType.RemoteUserLeaveRoom, e.ToBytes());
  417. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  418. Logger.WriteLineInfo($"OnRemoteUserLeaveRoomArrived Invoked,userId:{e.UserId},reason:{e.Reason}.");
  419. }
  420. private static void OnTryToReconnect(object sender, EventArgs e)
  421. {
  422. var fileTransferMessageData = new TRTCMessage(EnumMessageType.TryToReconnect, null);
  423. _fileWriterFromTRTCToCommon.WriteMessageToFileContinuous(fileTransferMessageData.ToBytes());
  424. Logger.WriteLineInfo("OnTryToReconnect Invoked.");
  425. }
  426. }
  427. }