DeviceService.Live.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Newtonsoft.Json;
  6. using WingInterfaceLibrary.DB.Request;
  7. using WingInterfaceLibrary.DTO.Device;
  8. using WingInterfaceLibrary.DTO.LiveRoom;
  9. using WingInterfaceLibrary.DTO.Share;
  10. using WingInterfaceLibrary.Enum;
  11. using WingInterfaceLibrary.Interface;
  12. using WingInterfaceLibrary.Internal.Request;
  13. using WingInterfaceLibrary.Notifications;
  14. using WingInterfaceLibrary.Notifications.Live;
  15. using WingInterfaceLibrary.Notifications.Remote;
  16. using WingInterfaceLibrary.Request;
  17. using WingInterfaceLibrary.Request.Authentication;
  18. using WingInterfaceLibrary.Request.Device;
  19. using WingInterfaceLibrary.Request.Remote;
  20. using WingServerCommon.Config;
  21. using WingServerCommon.Interfaces.Cache;
  22. using WingServerCommon.Service;
  23. namespace WingDeviceService.Service
  24. {
  25. /// <summary>
  26. /// 设备直播
  27. /// </summary>
  28. public partial class DeviceService : JsonRpcService, IDeviceService
  29. {
  30. /// <summary>
  31. /// 用户进入设备直播房间
  32. /// </summary>
  33. /// <param name="request">用户进入设备直播房间请求实体</param>
  34. /// <returns></returns>
  35. public async Task<JoinDeviceLiveRoomResult> JoinDeviceLiveRoomAsync(JoinDeviceLiveRoomRequest request)
  36. {
  37. var userInfo = await _authenticationService.GetTokenAsync(request);
  38. var deviceCode = request.DeviceCode;
  39. var deviceTokenInfo = CacheMaintenance.Instance.Get<ITokensManager>().Where(x => x.ClientId == deviceCode).FirstOrDefault();
  40. if (deviceTokenInfo == null || !deviceTokenInfo.IsOnline)
  41. {
  42. ThrowCustomerException(CustomerRpcCode.DeviceNotOnline, "DeviceNotOnline");
  43. }
  44. if (deviceTokenInfo.IsOldPlatform)
  45. {
  46. await _deviceForwardService.GetDeviceVideoInfosAsync(new GetDeviceVideoInfosRequest { DeviceCode = deviceCode });
  47. }
  48. var deviceInfo = CacheMaintenance.Instance.Get<IDeviceInfosManager>().Get(deviceCode);
  49. if (deviceInfo == null)
  50. {
  51. ThrowCustomerException(CustomerRpcCode.DeviceNotExist, "Not find device");
  52. }
  53. if (!deviceInfo.LiveOpened)
  54. {
  55. ThrowCustomerException(CustomerRpcCode.DeviceLiveClosed, "DeviceLiveClosed");
  56. }
  57. return await JoinDeviceLiveRoomAsync(deviceCode, userInfo);
  58. }
  59. /// <summary>
  60. /// 用户离开设备直播房间
  61. /// </summary>
  62. /// <param name="request">用户离开设备直播房间请求实体</param>
  63. /// <returns></returns>
  64. public async Task<bool> LeaveDeviceLiveRoomAsync(LeaveDeviceLiveRoomRequest request)
  65. {
  66. var userInfo = await _authenticationService.GetTokenAsync(request);
  67. var userCode = userInfo.ClientId;
  68. var deviceCode = request.DeviceCode;
  69. var liveRoom = await _rtcService.GetInitiatingRoomByDeviceCodeAsync(new GetInitiatingRoomByDeviceCodeRequest
  70. {
  71. DeviceCode = deviceCode
  72. });
  73. if (liveRoom != null)
  74. {
  75. //移除观众
  76. var removeViewerResult = await _rtcService.RemoveViewerAsync(new RemoveViewerRequest
  77. {
  78. LiveRoomCode = liveRoom.LiveRoomCode,
  79. UserCode = userInfo.ClientId,
  80. });
  81. var timeoutTime = DateTime.UtcNow.AddSeconds(-1 * _reportStateTimeout);
  82. if (liveRoom.BusinessModule == BusinessModuleEnum.DeviceLiving && !liveRoom.ViewerInfos.Any(x => x.UserCode != userCode && x.LastReportTime >= timeoutTime))
  83. {
  84. await _rtcService.CloseAsync(new CloseRequest
  85. {
  86. LiveRoomCode = liveRoom.LiveRoomCode
  87. });
  88. }
  89. }
  90. return true;
  91. }
  92. /// <summary>
  93. /// 上报观看直播状态
  94. /// </summary>
  95. /// <param name="request">上报观看直播状态请求实体</param>
  96. /// <returns></returns>
  97. public async Task<bool> ReportLiveViewStateAsync(ReportLiveViewStateRequest request)
  98. {
  99. var userInfo = await _authenticationService.GetTokenAsync(request);
  100. var deviceCode = request.DeviceCode;
  101. var liveRoom = await _rtcService.GetInitiatingRoomByDeviceCodeAsync(new GetInitiatingRoomByDeviceCodeRequest
  102. {
  103. DeviceCode = deviceCode
  104. });
  105. if (liveRoom != null)
  106. {
  107. //添加观众
  108. var addOrUpdateViewerResult = await _rtcService.SaveViewerAsync(new SaveViewerRequest
  109. {
  110. LiveRoomCode = liveRoom.LiveRoomCode,
  111. UserCode = userInfo.ClientId,
  112. UserName = userInfo.AccountName,
  113. });
  114. }
  115. return true;
  116. }
  117. /// <summary>
  118. /// 生成设备直播分享地址
  119. /// </summary>
  120. /// <param name="request">生成设备直播分享地址请求实体</param>
  121. /// <errorCodes></errorCodes>
  122. /// <returns></returns>
  123. public async Task<CreateLiveShareInfoResult> CreateLiveShareInfoAsync(CreateLiveShareInfoRequest request)
  124. {
  125. var deviceCode = request.DeviceCode;
  126. var deviceInfo = CacheMaintenance.Instance.Get<IDeviceInfosManager>().Get(deviceCode);
  127. if (deviceInfo == null)
  128. {
  129. ThrowCustomerException(CustomerRpcCode.DeviceNotExist, "Not find device");
  130. }
  131. if (!deviceInfo.LiveOpened)
  132. {
  133. ThrowCustomerException(CustomerRpcCode.DeviceLiveClosed, "DeviceLiveClosed");
  134. }
  135. var userInfo = await _authenticationService.GetTokenAsync(request);
  136. var shareInfo = new DeviceLiveShareInfoDTO
  137. {
  138. DeviceCode = request.DeviceCode,
  139. ShareUserCode = userInfo.Code,
  140. ShareUserName = userInfo.AccountName,
  141. ShareTime = DateTime.UtcNow,
  142. };
  143. var shareContent = Newtonsoft.Json.JsonConvert.SerializeObject(shareInfo);
  144. var shortCode = await _shareDBService.AddShareInfoAsync(new AddShareInfoDBRequest { Data = new ShareDTO { ShareContent = shareContent } });
  145. return new CreateLiveShareInfoResult
  146. {
  147. ShareUrl = string.Format(_deviceShareUrl, shortCode),
  148. };
  149. }
  150. /// <summary>
  151. /// 用户进入设备直播房间(无token)
  152. /// </summary>
  153. /// <param name="request">用户进入设备直播房间请求实体</param>
  154. /// <errorCodes></errorCodes>
  155. /// <returns></returns>
  156. public async Task<JoinDeviceLiveRoomByShareResult> JoinDeviceLiveRoomByShareAsync(JoinDeviceLiveRoomByShareRequest request)
  157. {
  158. if (string.IsNullOrWhiteSpace(request.ShareCode))
  159. {
  160. ThrowCustomerException(CustomerRpcCode.ShareCodeIsEmpty, "ShareCodeIsEmpty");
  161. }
  162. var shareResult = await _shareDBService.GetShareInfoAsync(new GetShareInfoDBRequest
  163. {
  164. ShortCode = request.ShareCode,
  165. });
  166. if (string.IsNullOrWhiteSpace(shareResult.ShareContent))
  167. {
  168. ThrowCustomerException(CustomerRpcCode.DeviceShareDataError, "DeviceShareDataError");
  169. }
  170. DeviceLiveShareInfoDTO shareInfo = null;
  171. try
  172. {
  173. shareInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<DeviceLiveShareInfoDTO>(shareResult.ShareContent);
  174. }
  175. catch (Exception ex)
  176. {
  177. ThrowCustomerException(CustomerRpcCode.DeviceShareDataError, "DeviceShareDataError");
  178. }
  179. if (shareInfo == null || shareInfo.ShareTime.AddSeconds(_shareEffectiveSeconds) < DateTime.UtcNow)
  180. {
  181. ThrowCustomerException(CustomerRpcCode.DeviceShareExpired, "DeviceShareExpired");
  182. }
  183. var deviceCode = shareInfo.DeviceCode;
  184. var deviceInfo = CacheMaintenance.Instance.Get<IDeviceInfosManager>().Get(deviceCode);
  185. if (deviceInfo == null)
  186. {
  187. ThrowCustomerException(CustomerRpcCode.DeviceNotExist, "Not find device");
  188. }
  189. if (!deviceInfo.LiveOpened)
  190. {
  191. ThrowCustomerException(CustomerRpcCode.DeviceLiveClosed, "DeviceLiveClosed");
  192. }
  193. var deviceTokenInfo = CacheMaintenance.Instance.Get<ITokensManager>().Where(x => x.ClientId == deviceCode).FirstOrDefault();
  194. if (deviceTokenInfo == null || !deviceTokenInfo.IsOnline)
  195. {
  196. ThrowCustomerException(CustomerRpcCode.DeviceNotOnline, "DeviceNotOnline");
  197. }
  198. if (deviceTokenInfo.IsOldPlatform)
  199. {
  200. await _deviceForwardService.GetDeviceVideoInfosAsync(new GetDeviceVideoInfosRequest { DeviceCode = deviceCode });
  201. }
  202. var joinResult = await JoinDeviceLiveRoomAsync(deviceCode);
  203. return new JoinDeviceLiveRoomByShareResult
  204. {
  205. RoomNo = joinResult.RoomNo,
  206. LiveProtocol = EnvironmentConfigs.General.LiveProtocolDetail<TransactionStatusEnum>(),
  207. ReportStateIntervalSeconds = joinResult.ReportStateIntervalSeconds,
  208. DeviceCode = joinResult.DeviceCode,
  209. MergedChannel = joinResult.MergedChannel,
  210. MergedVideoOutputWidth = joinResult.MergedVideoOutputWidth,
  211. MergedVideoOutputHeight = joinResult.MergedVideoOutputHeight,
  212. VideoDeviceInfos = joinResult.VideoDeviceInfos,
  213. IsOldPlatform = joinResult.IsOldPlatform,
  214. SupportRtc = joinResult.SupportRtc,
  215. };
  216. }
  217. /// <summary>
  218. /// 用户离开设备直播房间(无token)
  219. /// </summary>
  220. /// <param name="request">用户离开设备直播房间请求实体</param>
  221. /// <errorCodes></errorCodes>
  222. /// <returns></returns>
  223. public async Task<bool> LeaveDeviceLiveRoomByShareAsync(LeaveDeviceLiveRoomByShareRequest request)
  224. {
  225. if (string.IsNullOrWhiteSpace(request.DeviceCode))
  226. {
  227. ThrowCustomerException(CustomerRpcCode.DeviceCodeIsEmpty, "DeviceCodeIsEmpty");
  228. }
  229. if (string.IsNullOrWhiteSpace(request.ViewerUniqueId))
  230. {
  231. ThrowCustomerException(CustomerRpcCode.UniqueIdIsEmpty, "UniqueIdIsEmpty");
  232. }
  233. var userCode = request.ViewerUniqueId;
  234. var deviceCode = request.DeviceCode;
  235. var liveRoom = await _rtcService.GetInitiatingRoomByDeviceCodeAsync(new GetInitiatingRoomByDeviceCodeRequest
  236. {
  237. DeviceCode = deviceCode
  238. });
  239. if (liveRoom != null)
  240. {
  241. //移除观众
  242. var removeViewerResult = await _rtcService.RemoveViewerAsync(new RemoveViewerRequest
  243. {
  244. LiveRoomCode = liveRoom.LiveRoomCode,
  245. UserCode = userCode,
  246. });
  247. var timeoutTime = DateTime.UtcNow.AddSeconds(-1 * _reportStateTimeout);
  248. if (liveRoom.BusinessModule == BusinessModuleEnum.DeviceLiving && !liveRoom.ViewerInfos.Any(x => x.UserCode != userCode && x.LastReportTime >= timeoutTime))
  249. {
  250. await _rtcService.CloseAsync(new CloseRequest
  251. {
  252. LiveRoomCode = liveRoom.LiveRoomCode
  253. });
  254. }
  255. }
  256. return true;
  257. }
  258. /// <summary>
  259. /// 上报观看直播状态(无token)
  260. /// </summary>
  261. /// <param name="request">上报观看直播状态请求实体</param>
  262. /// <errorCodes></errorCodes>
  263. /// <returns></returns>
  264. public async Task<bool> ReportLiveViewStateByShareAsync(ReportLiveViewStateByShareRequest request)
  265. {
  266. if (string.IsNullOrWhiteSpace(request.DeviceCode))
  267. {
  268. ThrowCustomerException(CustomerRpcCode.DeviceCodeIsEmpty, "DeviceCodeIsEmpty");
  269. }
  270. if (string.IsNullOrWhiteSpace(request.ViewerUniqueId))
  271. {
  272. ThrowCustomerException(CustomerRpcCode.UniqueIdIsEmpty, "UniqueIdIsEmpty");
  273. }
  274. var deviceCode = request.DeviceCode;
  275. var liveRoom = await _rtcService.GetInitiatingRoomByDeviceCodeAsync(new GetInitiatingRoomByDeviceCodeRequest
  276. {
  277. DeviceCode = deviceCode
  278. });
  279. if (liveRoom != null)
  280. {
  281. //添加观众
  282. var uniqueId = request.ViewerUniqueId;
  283. var addOrUpdateViewerResult = await _rtcService.SaveViewerAsync(new SaveViewerRequest
  284. {
  285. LiveRoomCode = liveRoom.LiveRoomCode,
  286. UserCode = uniqueId,
  287. UserName = uniqueId,
  288. });
  289. }
  290. return true;
  291. }
  292. /// <summary>
  293. /// 开始直播
  294. /// </summary>
  295. /// <param name="deviceCode"></param>
  296. /// <param name="userInfo"></param>
  297. /// <returns></returns>
  298. private async Task<JoinDeviceLiveRoomResult> JoinDeviceLiveRoomAsync(string deviceCode, TokenDTO userInfo = null)
  299. {
  300. var deviceInfo = CacheMaintenance.Instance.Get<IDeviceInfosManager>().Get(deviceCode);
  301. if (deviceInfo == null)
  302. {
  303. ThrowCustomerException(CustomerRpcCode.DeviceNotExist, "Not find device");
  304. }
  305. var liveRoom = await _rtcService.GetInitiatingRoomByDeviceCodeAsync(new GetInitiatingRoomByDeviceCodeRequest
  306. {
  307. DeviceCode = deviceCode
  308. });
  309. var deviceTokenInfo = CacheMaintenance.Instance.Get<ITokensManager>().Where(x => x.ClientId == deviceCode)?.FirstOrDefault();
  310. LiveMemberDTO deviceMemberInfo;
  311. if (liveRoom != null)
  312. {
  313. if (liveRoom.LiveRoomCode == deviceCode)
  314. {
  315. //设备正在推流
  316. deviceMemberInfo = liveRoom.DeviceInfos.FirstOrDefault(x => x.Code == deviceCode);
  317. if (deviceMemberInfo?.Status == LiveMemberStatus.Joined)
  318. {
  319. if (userInfo != null)
  320. {
  321. //添加观众
  322. await _rtcService.SaveViewerAsync(new SaveViewerRequest
  323. {
  324. LiveRoomCode = liveRoom.LiveRoomCode,
  325. UserCode = userInfo.ClientId,
  326. UserName = userInfo.AccountName,
  327. });
  328. }
  329. return new JoinDeviceLiveRoomResult
  330. {
  331. RoomNo = liveRoom.RtcRoomId,
  332. LiveProtocol = EnvironmentConfigs.General.LiveProtocolDetail<TransactionStatusEnum>(),
  333. ReportStateIntervalSeconds = _reportStateIntervalSeconds,
  334. DeviceCode = deviceCode,
  335. MergedChannel = deviceInfo.MergedChannel,
  336. MergedVideoOutputWidth = deviceInfo.MergedVideoOutputWidth,
  337. MergedVideoOutputHeight = deviceInfo.MergedVideoOutputHeight,
  338. VideoDeviceInfos = deviceMemberInfo.VideoDeviceInfos?.Select(x => new VideoDeviceInfoDTO
  339. {
  340. VideoDeviceId = x.VideoDeviceId,
  341. VideoDeviceSourceType = x.VideoDeviceSourceType,
  342. LiveData = x.LiveData
  343. })?.ToList() ?? new List<VideoDeviceInfoDTO>(),
  344. IsOldPlatform = deviceTokenInfo != null && deviceTokenInfo.IsOnline && deviceTokenInfo.IsOldPlatform,
  345. SupportRtc = deviceInfo.SupportRtc,
  346. };
  347. }
  348. }
  349. }
  350. //新增或更新设备直播间
  351. var deviceName = deviceInfo.DisplayName;
  352. var deviceLiveInfo = new LiveMemberDTO
  353. {
  354. Code = deviceCode,
  355. Name = deviceName,
  356. MemberType = LiveMemberEnum.Device,
  357. HeadImageToken = deviceInfo.HeadPicUrl,
  358. Status = LiveMemberStatus.Accepted,
  359. };
  360. var room = new LiveRoomDTO
  361. {
  362. LiveRoomCode = deviceCode,
  363. Name = deviceName,
  364. RelatedCode = deviceCode,
  365. BusinessModule = BusinessModuleEnum.DeviceLiving,
  366. Status = LiveRoomStatus.Default,
  367. UserInfos = new List<LiveMemberDTO>(),
  368. DeviceInfos = new List<LiveMemberDTO> { deviceLiveInfo }
  369. };
  370. await _rtcService.AddOrUpdateLiveRoomAsync(new AddOrUpdateLiveRoomRequest
  371. {
  372. LiveRoom = room,
  373. });
  374. var initiateResult = await _rtcService.InitiateAsync(new InitiateRequest
  375. {
  376. LiveRoomCode = deviceCode,
  377. InitiatorCode = deviceCode,
  378. });
  379. deviceMemberInfo = initiateResult.DeviceInfos.FirstOrDefault(x => x.Code == deviceCode);
  380. if (userInfo != null)
  381. {
  382. //添加观众
  383. await _rtcService.SaveViewerAsync(new SaveViewerRequest
  384. {
  385. LiveRoomCode = initiateResult.LiveRoomCode,
  386. UserCode = userInfo.ClientId,
  387. UserName = userInfo.AccountName,
  388. });
  389. }
  390. return new JoinDeviceLiveRoomResult
  391. {
  392. RoomNo = initiateResult.RtcRoomId,
  393. LiveProtocol = EnvironmentConfigs.General.LiveProtocolDetail<TransactionStatusEnum>(),
  394. ReportStateIntervalSeconds = _reportStateIntervalSeconds,
  395. DeviceCode = deviceCode,
  396. MergedChannel = deviceInfo.MergedChannel,
  397. MergedVideoOutputWidth = deviceInfo.MergedVideoOutputWidth,
  398. MergedVideoOutputHeight = deviceInfo.MergedVideoOutputHeight,
  399. VideoDeviceInfos = deviceMemberInfo.VideoDeviceInfos?.Select(x => new VideoDeviceInfoDTO
  400. {
  401. VideoDeviceId = x.VideoDeviceId,
  402. VideoDeviceSourceType = x.VideoDeviceSourceType,
  403. LiveData = x.LiveData
  404. })?.ToList() ?? new List<VideoDeviceInfoDTO>(),
  405. IsOldPlatform = deviceTokenInfo != null && deviceTokenInfo.IsOnline && deviceTokenInfo.IsOldPlatform,
  406. SupportRtc = deviceInfo.SupportRtc,
  407. };
  408. }
  409. }
  410. }