TUIChatCallingDataProvider.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. //
  2. // TUIChatCallingDataProvider.m
  3. // TUIChat
  4. //
  5. // Created by harvy on 2022/12/21.
  6. // Copyright © 2023 Tencent. All rights reserved.
  7. //
  8. #import "TUIChatCallingDataProvider.h"
  9. #import <TIMCommon/TIMDefine.h>
  10. #import <TUICore/TUICore.h>
  11. #import <TUICore/TUILogin.h>
  12. #import "TUIMessageBaseDataProvider.h"
  13. typedef NSString *TUIChatMessageID;
  14. typedef NSDictionary *TUIChatCallingJsonData;
  15. // ********************************************************************
  16. // TUIChatCallingInfo
  17. // ********************************************************************
  18. @interface TUIChatCallingInfo : NSObject <TUIChatCallingInfoProtocol>
  19. @property(nonatomic, strong) TUIChatMessageID msgID;
  20. @property(nonatomic, strong, nullable) TUIChatCallingJsonData jsonData;
  21. @property(nonatomic, strong, nullable) V2TIMSignalingInfo *signalingInfo;
  22. @property(nonatomic, strong, nullable) V2TIMMessage *innerMessage;
  23. @property(nonatomic, assign) TUIChatCallingMessageAppearance style;
  24. @end
  25. @implementation TUIChatCallingInfo
  26. #pragma mark - TUIChatCallingInfoProtocol
  27. - (TUICallProtocolType)protocolType {
  28. if (self.jsonData == nil || self.signalingInfo == nil || self.innerMessage == nil) {
  29. return TUICallProtocolTypeUnknown;
  30. }
  31. TUICallProtocolType type = TUICallProtocolTypeUnknown;
  32. switch (self.signalingInfo.actionType) {
  33. case SignalingActionType_Invite: {
  34. NSDictionary *data = [self.jsonData objectForKey:@"data"];
  35. if (data && [data isKindOfClass:NSDictionary.class]) {
  36. // New version for calling
  37. NSString *cmd = [data objectForKey:@"cmd"];
  38. if ([cmd isKindOfClass:NSString.class]) {
  39. if ([cmd isEqualToString:@"switchToAudio"]) {
  40. type = TUICallProtocolTypeSwitchToAudio;
  41. } else if ([cmd isEqualToString:@"hangup"]) {
  42. type = TUICallProtocolTypeHangup;
  43. } else if ([cmd isEqualToString:@"videoCall"]) {
  44. type = TUICallProtocolTypeSend;
  45. } else if ([cmd isEqualToString:@"audioCall"]) {
  46. type = TUICallProtocolTypeSend;
  47. } else {
  48. type = TUICallProtocolTypeUnknown;
  49. }
  50. } else {
  51. NSLog(@"calling protocol error, %@", self.jsonData);
  52. type = TUICallProtocolTypeUnknown;
  53. }
  54. } else {
  55. // Compatiable
  56. NSNumber *callEnd = [self.jsonData objectForKey:@"call_end"];
  57. if (callEnd && [callEnd isKindOfClass:NSNumber.class]) {
  58. type = TUICallProtocolTypeHangup;
  59. } else {
  60. type = TUICallProtocolTypeSend;
  61. }
  62. }
  63. } break;
  64. case SignalingActionType_Cancel_Invite: {
  65. type = TUICallProtocolTypeCancel;
  66. } break;
  67. case SignalingActionType_Accept_Invite: {
  68. NSDictionary *data = [self.jsonData objectForKey:@"data"];
  69. if (data && [data isKindOfClass:NSDictionary.class]) {
  70. // New version for calling
  71. NSString *cmd = [data objectForKey:@"cmd"];
  72. if ([cmd isKindOfClass:NSString.class]) {
  73. if ([cmd isEqualToString:@"switchToAudio"]) {
  74. type = TUICallProtocolTypeSwitchToAudioConfirm;
  75. } else {
  76. type = TUICallProtocolTypeAccept;
  77. }
  78. } else {
  79. NSLog(@"calling protocol error, %@", self.jsonData);
  80. type = TUICallProtocolTypeAccept;
  81. }
  82. } else {
  83. // Compatiable
  84. type = TUICallProtocolTypeAccept;
  85. }
  86. } break;
  87. case SignalingActionType_Reject_Invite: {
  88. if ([self.jsonData objectForKey:@"line_busy"]) {
  89. type = TUICallProtocolTypeLineBusy;
  90. } else {
  91. type = TUICallProtocolTypeReject;
  92. }
  93. } break;
  94. case SignalingActionType_Invite_Timeout: {
  95. type = TUICallProtocolTypeTimeout;
  96. } break;
  97. default:
  98. type = TUICallProtocolTypeUnknown;
  99. break;
  100. }
  101. return type;
  102. }
  103. - (TUICallStreamMediaType)streamMediaType {
  104. TUICallProtocolType protocolType = self.protocolType;
  105. if (protocolType == TUICallProtocolTypeUnknown) {
  106. return TUICallStreamMediaTypeUnknown;
  107. }
  108. // Default type
  109. TUICallStreamMediaType type = TUICallStreamMediaTypeUnknown;
  110. NSNumber *callType = [self.jsonData objectForKey:@"call_type"];
  111. if (callType && [callType isKindOfClass:NSNumber.class]) {
  112. if ([callType integerValue] == 1) {
  113. type = TUICallStreamMediaTypeVoice;
  114. } else if ([callType integerValue] == 2) {
  115. type = TUICallStreamMediaTypeVideo;
  116. }
  117. }
  118. // Read from special protocol
  119. if (protocolType == TUICallProtocolTypeSend) {
  120. NSDictionary *data = [self.jsonData objectForKey:@"data"];
  121. if (data && [data isKindOfClass:NSDictionary.class]) {
  122. NSString *cmd = [data objectForKey:@"cmd"];
  123. if ([cmd isEqual:@"audioCall"]) {
  124. type = TUICallStreamMediaTypeVoice;
  125. } else if ([cmd isEqual:@"videoCall"]) {
  126. type = TUICallStreamMediaTypeVideo;
  127. }
  128. }
  129. } else if (protocolType == TUICallProtocolTypeSwitchToAudio || protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
  130. type = TUICallStreamMediaTypeVideo;
  131. }
  132. return type;
  133. }
  134. - (TUICallParticipantType)participantType {
  135. if (self.protocolType == TUICallProtocolTypeUnknown) {
  136. return TUICallParticipantTypeUnknown;
  137. }
  138. if (self.signalingInfo.groupID.length > 0) {
  139. return TUICallParticipantTypeGroup;
  140. } else {
  141. return TUICallParticipantTypeC2C;
  142. }
  143. }
  144. - (NSString *)caller {
  145. NSString *callerID = nil;
  146. NSDictionary *data = [self.jsonData objectForKey:@"data"];
  147. if (data && [data isKindOfClass:NSDictionary.class]) {
  148. NSString *inviter = [data objectForKey:@"inviter"];
  149. if (inviter && [inviter isKindOfClass:NSString.class]) {
  150. callerID = inviter;
  151. }
  152. }
  153. if (callerID == nil) {
  154. callerID = TUILogin.getUserID;
  155. }
  156. return callerID;
  157. }
  158. - (TUICallParticipantRole)participantRole {
  159. if ([self.caller isEqualToString:TUILogin.getUserID]) {
  160. return TUICallParticipantRoleCaller;
  161. } else {
  162. return TUICallParticipantRoleCallee;
  163. }
  164. }
  165. - (BOOL)excludeFromHistory {
  166. if (self.style == TUIChatCallingMessageAppearanceSimplify) {
  167. return self.protocolType != TUICallProtocolTypeUnknown && self.innerMessage.isExcludedFromLastMessage && self.innerMessage.isExcludedFromUnreadCount;
  168. } else {
  169. return NO;
  170. }
  171. }
  172. - (NSString *)content {
  173. if (self.style == TUIChatCallingMessageAppearanceSimplify) {
  174. return [self contentForSimplifyAppearance];
  175. } else {
  176. return [self contentForDetailsAppearance];
  177. }
  178. }
  179. - (TUICallMessageDirection)direction {
  180. if (self.style == TUIChatCallingMessageAppearanceSimplify) {
  181. return [self directionForSimplifyAppearance];
  182. } else {
  183. return [self directionForDetailsAppearance];
  184. }
  185. }
  186. - (BOOL)showUnreadPoint {
  187. if (self.excludeFromHistory) {
  188. return NO;
  189. }
  190. return (self.innerMessage.localCustomInt == 0) && (self.participantRole == TUICallParticipantRoleCallee) &&
  191. (self.participantType == TUICallParticipantTypeC2C) &&
  192. (self.protocolType == TUICallProtocolTypeCancel || self.protocolType == TUICallProtocolTypeTimeout ||
  193. self.protocolType == TUICallProtocolTypeLineBusy);
  194. }
  195. - (BOOL)isUseReceiverAvatar {
  196. if (self.style == TUIChatCallingMessageAppearanceSimplify) {
  197. return [self isUseReceiverAvatarForSimplifyAppearance];
  198. } else {
  199. return [self isUseReceiverAvatarForDetailsAppearance];
  200. }
  201. }
  202. - (NSArray<NSString *> *)participantIDList {
  203. NSMutableArray *arrayM = [NSMutableArray array];
  204. if (self.signalingInfo.inviter) {
  205. [arrayM addObject:self.signalingInfo.inviter];
  206. }
  207. if (self.signalingInfo.inviteeList.count > 0) {
  208. [arrayM addObjectsFromArray:self.signalingInfo.inviteeList];
  209. }
  210. return [NSArray arrayWithArray:arrayM];
  211. }
  212. #pragma mark - Details style
  213. - (NSString *)contentForDetailsAppearance {
  214. TUICallProtocolType protocolType = self.protocolType;
  215. BOOL isGroup = (self.participantType == TUICallParticipantTypeGroup);
  216. if (protocolType == TUICallProtocolTypeUnknown) {
  217. return TIMCommonLocalizableString(TUIkitSignalingUnrecognlize);
  218. }
  219. NSString *display = TIMCommonLocalizableString(TUIkitSignalingUnrecognlize);
  220. NSString *showName = [TUIMessageBaseDataProvider getShowName:self.innerMessage];
  221. if (protocolType == TUICallProtocolTypeSend) {
  222. // Launch call
  223. display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingNewGroupCallFormat), showName]
  224. : TIMCommonLocalizableString(TUIKitSignalingNewCall);
  225. } else if (protocolType == TUICallProtocolTypeAccept) {
  226. // Accept call
  227. display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingHangonCallFormat), showName]
  228. : TIMCommonLocalizableString(TUIkitSignalingHangonCall);
  229. } else if (protocolType == TUICallProtocolTypeReject) {
  230. // Reject call
  231. display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingDeclineFormat), showName]
  232. : TIMCommonLocalizableString(TUIkitSignalingDecline);
  233. } else if (protocolType == TUICallProtocolTypeCancel) {
  234. // Cancel pending call
  235. display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIkitSignalingCancelGroupCallFormat), showName]
  236. : TIMCommonLocalizableString(TUIkitSignalingCancelCall);
  237. } else if (protocolType == TUICallProtocolTypeHangup) {
  238. // Hang up
  239. NSUInteger duration = [[self.jsonData objectForKey:@"call_end"] unsignedIntegerValue];
  240. display = isGroup
  241. ? TIMCommonLocalizableString(TUIKitSignalingFinishGroupChat)
  242. : [NSString stringWithFormat:@"%@:%.2d:%.2d",TIMCommonLocalizableString(TUIKitSignalingFinishConversationAndTimeFormat),duration / 60, duration % 60];
  243. } else if (protocolType == TUICallProtocolTypeTimeout) {
  244. // Call timeout
  245. NSMutableString *mutableContent = [NSMutableString string];
  246. if (isGroup) {
  247. for (NSString *invitee in self.signalingInfo.inviteeList) {
  248. [mutableContent appendString:@"\"{"];
  249. [mutableContent appendString:invitee];
  250. [mutableContent appendString:@"}\"、"];
  251. }
  252. if (mutableContent.length > 0) {
  253. [mutableContent replaceCharactersInRange:NSMakeRange(mutableContent.length - 1, 1) withString:@" "];
  254. }
  255. }
  256. [mutableContent appendString:TIMCommonLocalizableString(TUIKitSignalingNoResponse)];
  257. display = [NSString stringWithString:mutableContent];
  258. } else if (protocolType == TUICallProtocolTypeLineBusy) {
  259. // Hang up with line busy
  260. display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingBusyFormat), showName]
  261. : TIMCommonLocalizableString(TUIKitSignalingCallBusy);
  262. } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
  263. // Change video-call to voice-call
  264. display = TIMCommonLocalizableString(TUIKitSignalingSwitchToAudio);
  265. } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
  266. // Confirm the change of video-voice-call
  267. display = TIMCommonLocalizableString(TUIKitSignalingComfirmSwitchToAudio);
  268. }
  269. return rtlString(display);
  270. }
  271. - (TUICallMessageDirection)directionForDetailsAppearance {
  272. if (self.innerMessage.isSelf) {
  273. return TUICallMessageDirectionOutgoing;
  274. } else {
  275. return TUICallMessageDirectionIncoming;
  276. }
  277. }
  278. - (BOOL)isUseReceiverAvatarForDetailsAppearance {
  279. return NO;
  280. }
  281. #pragma mark - Simplify style
  282. - (NSString *)contentForSimplifyAppearance {
  283. if (self.excludeFromHistory) {
  284. return nil;
  285. }
  286. TUICallParticipantType participantType = self.participantType;
  287. TUICallProtocolType protocolType = self.protocolType;
  288. BOOL isCaller = (self.participantRole == TUICallParticipantRoleCaller);
  289. NSString *display = nil;
  290. NSString *showName = [TUIMessageBaseDataProvider getShowName:self.innerMessage];
  291. if (participantType == TUICallParticipantTypeC2C) {
  292. // C2C shown: reject、cancel、hangup、timeout、line_busy
  293. if (protocolType == TUICallProtocolTypeReject) {
  294. display = isCaller ? TUIChatLocalizableString(TUIChatCallRejectInCaller) : TUIChatLocalizableString(TUIChatCallRejectInCallee);
  295. } else if (protocolType == TUICallProtocolTypeCancel) {
  296. display = isCaller ? TUIChatLocalizableString(TUIChatCallCancelInCaller) : TUIChatLocalizableString(TUIChatCallCancelInCallee);
  297. } else if (protocolType == TUICallProtocolTypeHangup) {
  298. NSInteger duration = [[self.jsonData objectForKey:@"call_end"] integerValue];
  299. display = [NSString stringWithFormat:@"%@:%.2d:%.2d",TUIChatLocalizableString(TUIChatCallDurationFormat),duration / 60, duration % 60];
  300. } else if (protocolType == TUICallProtocolTypeTimeout) {
  301. display = isCaller ? TUIChatLocalizableString(TUIChatCallTimeoutInCaller) : TUIChatLocalizableString(TUIChatCallTimeoutInCallee);
  302. } else if (protocolType == TUICallProtocolTypeLineBusy) {
  303. display = isCaller ? TUIChatLocalizableString(TUIChatCallLinebusyInCaller) : TUIChatLocalizableString(TUIChatCallLinebusyInCallee);
  304. }
  305. // C2C compatiable
  306. else if (protocolType == TUICallProtocolTypeSend) {
  307. display = TUIChatLocalizableString(TUIChatCallSend);
  308. } else if (protocolType == TUICallProtocolTypeAccept) {
  309. display = TUIChatLocalizableString(TUIChatCallAccept);
  310. } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
  311. display = TUIChatLocalizableString(TUIChatCallSwitchToAudio);
  312. } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
  313. display = TUIChatLocalizableString(TUIChatCallConfirmSwitchToAudio);
  314. } else {
  315. display = TUIChatLocalizableString(TUIChatCallUnrecognized);
  316. }
  317. } else if (participantType == TUICallParticipantTypeGroup) {
  318. // Group shown: invite、cancel、hangup、timeout、line_busy
  319. if (protocolType == TUICallProtocolTypeSend) {
  320. display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallSendFormat), showName];
  321. } else if (protocolType == TUICallProtocolTypeCancel) {
  322. display = TUIChatLocalizableString(TUIChatGroupCallEnd);
  323. } else if (protocolType == TUICallProtocolTypeHangup) {
  324. display = TUIChatLocalizableString(TUIChatGroupCallEnd);
  325. } else if (protocolType == TUICallProtocolTypeTimeout || protocolType == TUICallProtocolTypeLineBusy) {
  326. NSMutableString *mutableContent = [NSMutableString string];
  327. if (participantType == TUICallParticipantTypeGroup) {
  328. for (NSString *invitee in self.signalingInfo.inviteeList) {
  329. [mutableContent appendString:@"\"{"];
  330. [mutableContent appendString:invitee];
  331. [mutableContent appendString:@"}\"、"];
  332. }
  333. [mutableContent replaceCharactersInRange:NSMakeRange(mutableContent.length - 1, 1) withString:@" "];
  334. }
  335. if (protocolType == TUICallProtocolTypeLineBusy) {
  336. [mutableContent appendString:TUIChatLocalizableString(TUIChatCallLinebusyInCallee)];
  337. } else {
  338. [mutableContent appendString:TUIChatLocalizableString(TUIChatGroupCallNoAnswer)];
  339. }
  340. display = [NSString stringWithString:mutableContent];
  341. }
  342. // Group compatiable
  343. else if (protocolType == TUICallProtocolTypeReject) {
  344. display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallRejectFormat), showName];
  345. } else if (protocolType == TUICallProtocolTypeAccept) {
  346. display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallAcceptFormat), showName];
  347. } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
  348. display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallSwitchToAudioFormat), showName];
  349. } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
  350. display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallConfirmSwitchToAudioFormat), showName];
  351. } else {
  352. display = TUIChatLocalizableString(TUIChatCallUnrecognized);
  353. }
  354. } else {
  355. display = TUIChatLocalizableString(TUIChatCallUnrecognized);
  356. }
  357. return rtlString(display);
  358. }
  359. - (TUICallMessageDirection)directionForSimplifyAppearance {
  360. if (self.participantRole == TUICallParticipantRoleCaller) {
  361. return TUICallMessageDirectionOutgoing;
  362. } else {
  363. return TUICallMessageDirectionIncoming;
  364. }
  365. }
  366. - (BOOL)isUseReceiverAvatarForSimplifyAppearance {
  367. if (self.direction == TUICallMessageDirectionOutgoing) {
  368. return !self.innerMessage.isSelf;
  369. } else {
  370. return self.innerMessage.isSelf;
  371. }
  372. }
  373. #pragma mark - Utils
  374. - (NSString *)convertProtocolTypeToString:(TUICallProtocolType)type {
  375. static NSDictionary *dict = nil;
  376. if (dict == nil) {
  377. dict = @{
  378. @(TUICallProtocolTypeSend) : @"TUICallProtocolTypeSend",
  379. @(TUICallProtocolTypeAccept) : @"TUICallProtocolTypeAccept",
  380. @(TUICallProtocolTypeReject) : @"TUICallProtocolTypeReject",
  381. @(TUICallProtocolTypeCancel) : @"TUICallProtocolTypeCancel",
  382. @(TUICallProtocolTypeHangup) : @"TUICallProtocolTypeHangup",
  383. @(TUICallProtocolTypeTimeout) : @"TUICallProtocolTypeTimeout",
  384. @(TUICallProtocolTypeLineBusy) : @"TUICallProtocolTypeLineBusy",
  385. @(TUICallProtocolTypeSwitchToAudio) : @"TUICallProtocolTypeSwitchToAudio",
  386. @(TUICallProtocolTypeSwitchToAudioConfirm) : @"TUICallProtocolTypeSwitchToAudioConfirm",
  387. };
  388. }
  389. return [dict objectForKey:@(type)] ?: @"unknown";
  390. }
  391. @end
  392. // ********************************************************************
  393. // ********************************************************************
  394. // TUIChatCallingDataProvider
  395. // ********************************************************************
  396. @interface TUIChatCallingDataProvider ()
  397. @property(nonatomic, assign) TUIChatCallingMessageAppearance style;
  398. @property(nonatomic, strong) NSCache<TUIChatMessageID, TUIChatCallingInfo *> *callingCache;
  399. @end
  400. @implementation TUIChatCallingDataProvider
  401. - (instancetype)init {
  402. if (self = [super init]) {
  403. self.style = TUIChatCallingMessageAppearanceSimplify;
  404. }
  405. return self;
  406. }
  407. - (void)setCallingMessageStyle:(TUIChatCallingMessageAppearance)style {
  408. self.style = style;
  409. }
  410. - (void)redialFromMessage:(V2TIMMessage *)innerMessage {
  411. NSDictionary *param = nil;
  412. id<TUIChatCallingInfoProtocol> callingInfo = nil;
  413. if ([self isCallingMessage:innerMessage callingInfo:&callingInfo]) {
  414. if (callingInfo.streamMediaType == TUICallStreamMediaTypeVoice) {
  415. param = @{
  416. TUICore_TUICallingService_ShowCallingViewMethod_UserIDsKey : @[ innerMessage.userID ],
  417. TUICore_TUICallingService_ShowCallingViewMethod_CallTypeKey : @"0"
  418. };
  419. } else if (callingInfo.streamMediaType == TUICallStreamMediaTypeVideo) {
  420. param = @{
  421. TUICore_TUICallingService_ShowCallingViewMethod_UserIDsKey : @[ innerMessage.userID ],
  422. TUICore_TUICallingService_ShowCallingViewMethod_CallTypeKey : @"1"
  423. };
  424. }
  425. if (param) {
  426. [TUICore callService:TUICore_TUICallingService method:TUICore_TUICallingService_ShowCallingViewMethod param:param];
  427. }
  428. }
  429. }
  430. - (BOOL)isCallingMessage:(V2TIMMessage *)innerMessage callingInfo:(id<TUIChatCallingInfoProtocol> __nullable *__nullable)callingInfo {
  431. TUIChatCallingInfo *item = [self callingInfoForMesssage:innerMessage];
  432. if (item == nil) {
  433. if (callingInfo) {
  434. *callingInfo = nil;
  435. }
  436. return NO;
  437. } else {
  438. if (callingInfo) {
  439. *callingInfo = item;
  440. }
  441. return YES;
  442. }
  443. }
  444. - (TUIChatCallingInfo *__nullable)callingInfoForMesssage:(V2TIMMessage *)innerMessage {
  445. // 1. Fetch from cache
  446. TUIChatMessageID msgID = innerMessage.msgID ?: @"";
  447. TUIChatCallingInfo *item = [self.callingCache objectForKey:msgID];
  448. if (item) {
  449. item.innerMessage = innerMessage;
  450. return item;
  451. }
  452. // 2. Parse
  453. V2TIMSignalingInfo *info = [V2TIMManager.sharedInstance getSignallingInfo:innerMessage];
  454. if (info == nil || info.data.length == 0) {
  455. return nil;
  456. }
  457. NSData *data = [info.data dataUsingEncoding:NSUTF8StringEncoding];
  458. if (data == nil) {
  459. return nil;
  460. }
  461. NSError *err = nil;
  462. NSDictionary *param = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
  463. if (param == nil || ![param isKindOfClass:NSDictionary.class]) {
  464. return nil;
  465. }
  466. NSString *businessID = [param objectForKey:@"businessID"];
  467. if (businessID == nil || ![businessID isKindOfClass:NSString.class]) {
  468. return nil;
  469. }
  470. if (![businessID isEqualToString:@"av_call"] && ![businessID isEqualToString:@"rtc_call"] ) {
  471. return nil;
  472. }
  473. // 3 Cached and return
  474. item = [[TUIChatCallingInfo alloc] init];
  475. item.style = self.style;
  476. item.signalingInfo = info;
  477. item.jsonData = param;
  478. item.innerMessage = innerMessage;
  479. [self.callingCache setObject:item forKey:msgID];
  480. return item;
  481. }
  482. #pragma mark - Lazy
  483. - (NSCache<TUIChatMessageID, TUIChatCallingInfo *> *)callingCache {
  484. if (_callingCache == nil) {
  485. _callingCache = [[NSCache alloc] init];
  486. }
  487. return _callingCache;
  488. }
  489. @end
  490. // ********************************************************************