| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- //
- // TUIChatCallingDataProvider.m
- // TUIChat
- //
- // Created by harvy on 2022/12/21.
- // Copyright © 2023 Tencent. All rights reserved.
- //
- #import "TUIChatCallingDataProvider.h"
- #import <TIMCommon/TIMDefine.h>
- #import <TUICore/TUICore.h>
- #import <TUICore/TUILogin.h>
- #import "TUIMessageBaseDataProvider.h"
- typedef NSString *TUIChatMessageID;
- typedef NSDictionary *TUIChatCallingJsonData;
- // ********************************************************************
- // TUIChatCallingInfo
- // ********************************************************************
- @interface TUIChatCallingInfo : NSObject <TUIChatCallingInfoProtocol>
- @property(nonatomic, strong) TUIChatMessageID msgID;
- @property(nonatomic, strong, nullable) TUIChatCallingJsonData jsonData;
- @property(nonatomic, strong, nullable) V2TIMSignalingInfo *signalingInfo;
- @property(nonatomic, strong, nullable) V2TIMMessage *innerMessage;
- @property(nonatomic, assign) TUIChatCallingMessageAppearance style;
- @end
- @implementation TUIChatCallingInfo
- #pragma mark - TUIChatCallingInfoProtocol
- - (TUICallProtocolType)protocolType {
- if (self.jsonData == nil || self.signalingInfo == nil || self.innerMessage == nil) {
- return TUICallProtocolTypeUnknown;
- }
- TUICallProtocolType type = TUICallProtocolTypeUnknown;
- switch (self.signalingInfo.actionType) {
- case SignalingActionType_Invite: {
- NSDictionary *data = [self.jsonData objectForKey:@"data"];
- if (data && [data isKindOfClass:NSDictionary.class]) {
- // New version for calling
- NSString *cmd = [data objectForKey:@"cmd"];
- if ([cmd isKindOfClass:NSString.class]) {
- if ([cmd isEqualToString:@"switchToAudio"]) {
- type = TUICallProtocolTypeSwitchToAudio;
- } else if ([cmd isEqualToString:@"hangup"]) {
- type = TUICallProtocolTypeHangup;
- } else if ([cmd isEqualToString:@"videoCall"]) {
- type = TUICallProtocolTypeSend;
- } else if ([cmd isEqualToString:@"audioCall"]) {
- type = TUICallProtocolTypeSend;
- } else {
- type = TUICallProtocolTypeUnknown;
- }
- } else {
- NSLog(@"calling protocol error, %@", self.jsonData);
- type = TUICallProtocolTypeUnknown;
- }
- } else {
- // Compatiable
- NSNumber *callEnd = [self.jsonData objectForKey:@"call_end"];
- if (callEnd && [callEnd isKindOfClass:NSNumber.class]) {
- type = TUICallProtocolTypeHangup;
- } else {
- type = TUICallProtocolTypeSend;
- }
- }
- } break;
- case SignalingActionType_Cancel_Invite: {
- type = TUICallProtocolTypeCancel;
- } break;
- case SignalingActionType_Accept_Invite: {
- NSDictionary *data = [self.jsonData objectForKey:@"data"];
- if (data && [data isKindOfClass:NSDictionary.class]) {
- // New version for calling
- NSString *cmd = [data objectForKey:@"cmd"];
- if ([cmd isKindOfClass:NSString.class]) {
- if ([cmd isEqualToString:@"switchToAudio"]) {
- type = TUICallProtocolTypeSwitchToAudioConfirm;
- } else {
- type = TUICallProtocolTypeAccept;
- }
- } else {
- NSLog(@"calling protocol error, %@", self.jsonData);
- type = TUICallProtocolTypeAccept;
- }
- } else {
- // Compatiable
- type = TUICallProtocolTypeAccept;
- }
- } break;
- case SignalingActionType_Reject_Invite: {
- if ([self.jsonData objectForKey:@"line_busy"]) {
- type = TUICallProtocolTypeLineBusy;
- } else {
- type = TUICallProtocolTypeReject;
- }
- } break;
- case SignalingActionType_Invite_Timeout: {
- type = TUICallProtocolTypeTimeout;
- } break;
- default:
- type = TUICallProtocolTypeUnknown;
- break;
- }
- return type;
- }
- - (TUICallStreamMediaType)streamMediaType {
- TUICallProtocolType protocolType = self.protocolType;
- if (protocolType == TUICallProtocolTypeUnknown) {
- return TUICallStreamMediaTypeUnknown;
- }
- // Default type
- TUICallStreamMediaType type = TUICallStreamMediaTypeUnknown;
- NSNumber *callType = [self.jsonData objectForKey:@"call_type"];
- if (callType && [callType isKindOfClass:NSNumber.class]) {
- if ([callType integerValue] == 1) {
- type = TUICallStreamMediaTypeVoice;
- } else if ([callType integerValue] == 2) {
- type = TUICallStreamMediaTypeVideo;
- }
- }
- // Read from special protocol
- if (protocolType == TUICallProtocolTypeSend) {
- NSDictionary *data = [self.jsonData objectForKey:@"data"];
- if (data && [data isKindOfClass:NSDictionary.class]) {
- NSString *cmd = [data objectForKey:@"cmd"];
- if ([cmd isEqual:@"audioCall"]) {
- type = TUICallStreamMediaTypeVoice;
- } else if ([cmd isEqual:@"videoCall"]) {
- type = TUICallStreamMediaTypeVideo;
- }
- }
- } else if (protocolType == TUICallProtocolTypeSwitchToAudio || protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
- type = TUICallStreamMediaTypeVideo;
- }
- return type;
- }
- - (TUICallParticipantType)participantType {
- if (self.protocolType == TUICallProtocolTypeUnknown) {
- return TUICallParticipantTypeUnknown;
- }
- if (self.signalingInfo.groupID.length > 0) {
- return TUICallParticipantTypeGroup;
- } else {
- return TUICallParticipantTypeC2C;
- }
- }
- - (NSString *)caller {
- NSString *callerID = nil;
- NSDictionary *data = [self.jsonData objectForKey:@"data"];
- if (data && [data isKindOfClass:NSDictionary.class]) {
- NSString *inviter = [data objectForKey:@"inviter"];
- if (inviter && [inviter isKindOfClass:NSString.class]) {
- callerID = inviter;
- }
- }
- if (callerID == nil) {
- callerID = TUILogin.getUserID;
- }
- return callerID;
- }
- - (TUICallParticipantRole)participantRole {
- if ([self.caller isEqualToString:TUILogin.getUserID]) {
- return TUICallParticipantRoleCaller;
- } else {
- return TUICallParticipantRoleCallee;
- }
- }
- - (BOOL)excludeFromHistory {
- if (self.style == TUIChatCallingMessageAppearanceSimplify) {
- return self.protocolType != TUICallProtocolTypeUnknown && self.innerMessage.isExcludedFromLastMessage && self.innerMessage.isExcludedFromUnreadCount;
- } else {
- return NO;
- }
- }
- - (NSString *)content {
- if (self.style == TUIChatCallingMessageAppearanceSimplify) {
- return [self contentForSimplifyAppearance];
- } else {
- return [self contentForDetailsAppearance];
- }
- }
- - (TUICallMessageDirection)direction {
- if (self.style == TUIChatCallingMessageAppearanceSimplify) {
- return [self directionForSimplifyAppearance];
- } else {
- return [self directionForDetailsAppearance];
- }
- }
- - (BOOL)showUnreadPoint {
- if (self.excludeFromHistory) {
- return NO;
- }
- return (self.innerMessage.localCustomInt == 0) && (self.participantRole == TUICallParticipantRoleCallee) &&
- (self.participantType == TUICallParticipantTypeC2C) &&
- (self.protocolType == TUICallProtocolTypeCancel || self.protocolType == TUICallProtocolTypeTimeout ||
- self.protocolType == TUICallProtocolTypeLineBusy);
- }
- - (BOOL)isUseReceiverAvatar {
- if (self.style == TUIChatCallingMessageAppearanceSimplify) {
- return [self isUseReceiverAvatarForSimplifyAppearance];
- } else {
- return [self isUseReceiverAvatarForDetailsAppearance];
- }
- }
- - (NSArray<NSString *> *)participantIDList {
- NSMutableArray *arrayM = [NSMutableArray array];
- if (self.signalingInfo.inviter) {
- [arrayM addObject:self.signalingInfo.inviter];
- }
- if (self.signalingInfo.inviteeList.count > 0) {
- [arrayM addObjectsFromArray:self.signalingInfo.inviteeList];
- }
- return [NSArray arrayWithArray:arrayM];
- }
- #pragma mark - Details style
- - (NSString *)contentForDetailsAppearance {
- TUICallProtocolType protocolType = self.protocolType;
- BOOL isGroup = (self.participantType == TUICallParticipantTypeGroup);
- if (protocolType == TUICallProtocolTypeUnknown) {
- return TIMCommonLocalizableString(TUIkitSignalingUnrecognlize);
- }
- NSString *display = TIMCommonLocalizableString(TUIkitSignalingUnrecognlize);
- NSString *showName = [TUIMessageBaseDataProvider getShowName:self.innerMessage];
- if (protocolType == TUICallProtocolTypeSend) {
- // Launch call
- display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingNewGroupCallFormat), showName]
- : TIMCommonLocalizableString(TUIKitSignalingNewCall);
- } else if (protocolType == TUICallProtocolTypeAccept) {
- // Accept call
- display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingHangonCallFormat), showName]
- : TIMCommonLocalizableString(TUIkitSignalingHangonCall);
- } else if (protocolType == TUICallProtocolTypeReject) {
- // Reject call
- display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingDeclineFormat), showName]
- : TIMCommonLocalizableString(TUIkitSignalingDecline);
- } else if (protocolType == TUICallProtocolTypeCancel) {
- // Cancel pending call
- display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIkitSignalingCancelGroupCallFormat), showName]
- : TIMCommonLocalizableString(TUIkitSignalingCancelCall);
- } else if (protocolType == TUICallProtocolTypeHangup) {
- // Hang up
- NSUInteger duration = [[self.jsonData objectForKey:@"call_end"] unsignedIntegerValue];
- display = isGroup
- ? TIMCommonLocalizableString(TUIKitSignalingFinishGroupChat)
- : [NSString stringWithFormat:@"%@:%.2d:%.2d",TIMCommonLocalizableString(TUIKitSignalingFinishConversationAndTimeFormat),duration / 60, duration % 60];
- } else if (protocolType == TUICallProtocolTypeTimeout) {
- // Call timeout
- NSMutableString *mutableContent = [NSMutableString string];
- if (isGroup) {
- for (NSString *invitee in self.signalingInfo.inviteeList) {
- [mutableContent appendString:@"\"{"];
- [mutableContent appendString:invitee];
- [mutableContent appendString:@"}\"、"];
- }
- if (mutableContent.length > 0) {
- [mutableContent replaceCharactersInRange:NSMakeRange(mutableContent.length - 1, 1) withString:@" "];
- }
- }
- [mutableContent appendString:TIMCommonLocalizableString(TUIKitSignalingNoResponse)];
- display = [NSString stringWithString:mutableContent];
- } else if (protocolType == TUICallProtocolTypeLineBusy) {
- // Hang up with line busy
- display = isGroup ? [NSString stringWithFormat:TIMCommonLocalizableString(TUIKitSignalingBusyFormat), showName]
- : TIMCommonLocalizableString(TUIKitSignalingCallBusy);
- } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
- // Change video-call to voice-call
- display = TIMCommonLocalizableString(TUIKitSignalingSwitchToAudio);
- } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
- // Confirm the change of video-voice-call
- display = TIMCommonLocalizableString(TUIKitSignalingComfirmSwitchToAudio);
- }
- return rtlString(display);
- }
- - (TUICallMessageDirection)directionForDetailsAppearance {
- if (self.innerMessage.isSelf) {
- return TUICallMessageDirectionOutgoing;
- } else {
- return TUICallMessageDirectionIncoming;
- }
- }
- - (BOOL)isUseReceiverAvatarForDetailsAppearance {
- return NO;
- }
- #pragma mark - Simplify style
- - (NSString *)contentForSimplifyAppearance {
- if (self.excludeFromHistory) {
- return nil;
- }
- TUICallParticipantType participantType = self.participantType;
- TUICallProtocolType protocolType = self.protocolType;
- BOOL isCaller = (self.participantRole == TUICallParticipantRoleCaller);
- NSString *display = nil;
- NSString *showName = [TUIMessageBaseDataProvider getShowName:self.innerMessage];
- if (participantType == TUICallParticipantTypeC2C) {
- // C2C shown: reject、cancel、hangup、timeout、line_busy
- if (protocolType == TUICallProtocolTypeReject) {
- display = isCaller ? TUIChatLocalizableString(TUIChatCallRejectInCaller) : TUIChatLocalizableString(TUIChatCallRejectInCallee);
- } else if (protocolType == TUICallProtocolTypeCancel) {
- display = isCaller ? TUIChatLocalizableString(TUIChatCallCancelInCaller) : TUIChatLocalizableString(TUIChatCallCancelInCallee);
- } else if (protocolType == TUICallProtocolTypeHangup) {
- NSInteger duration = [[self.jsonData objectForKey:@"call_end"] integerValue];
- display = [NSString stringWithFormat:@"%@:%.2d:%.2d",TUIChatLocalizableString(TUIChatCallDurationFormat),duration / 60, duration % 60];
- } else if (protocolType == TUICallProtocolTypeTimeout) {
- display = isCaller ? TUIChatLocalizableString(TUIChatCallTimeoutInCaller) : TUIChatLocalizableString(TUIChatCallTimeoutInCallee);
- } else if (protocolType == TUICallProtocolTypeLineBusy) {
- display = isCaller ? TUIChatLocalizableString(TUIChatCallLinebusyInCaller) : TUIChatLocalizableString(TUIChatCallLinebusyInCallee);
- }
- // C2C compatiable
- else if (protocolType == TUICallProtocolTypeSend) {
- display = TUIChatLocalizableString(TUIChatCallSend);
- } else if (protocolType == TUICallProtocolTypeAccept) {
- display = TUIChatLocalizableString(TUIChatCallAccept);
- } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
- display = TUIChatLocalizableString(TUIChatCallSwitchToAudio);
- } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
- display = TUIChatLocalizableString(TUIChatCallConfirmSwitchToAudio);
- } else {
- display = TUIChatLocalizableString(TUIChatCallUnrecognized);
- }
- } else if (participantType == TUICallParticipantTypeGroup) {
- // Group shown: invite、cancel、hangup、timeout、line_busy
- if (protocolType == TUICallProtocolTypeSend) {
- display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallSendFormat), showName];
- } else if (protocolType == TUICallProtocolTypeCancel) {
- display = TUIChatLocalizableString(TUIChatGroupCallEnd);
- } else if (protocolType == TUICallProtocolTypeHangup) {
- display = TUIChatLocalizableString(TUIChatGroupCallEnd);
- } else if (protocolType == TUICallProtocolTypeTimeout || protocolType == TUICallProtocolTypeLineBusy) {
- NSMutableString *mutableContent = [NSMutableString string];
- if (participantType == TUICallParticipantTypeGroup) {
- for (NSString *invitee in self.signalingInfo.inviteeList) {
- [mutableContent appendString:@"\"{"];
- [mutableContent appendString:invitee];
- [mutableContent appendString:@"}\"、"];
- }
- [mutableContent replaceCharactersInRange:NSMakeRange(mutableContent.length - 1, 1) withString:@" "];
- }
-
- if (protocolType == TUICallProtocolTypeLineBusy) {
- [mutableContent appendString:TUIChatLocalizableString(TUIChatCallLinebusyInCallee)];
- } else {
- [mutableContent appendString:TUIChatLocalizableString(TUIChatGroupCallNoAnswer)];
- }
- display = [NSString stringWithString:mutableContent];
-
- }
- // Group compatiable
- else if (protocolType == TUICallProtocolTypeReject) {
- display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallRejectFormat), showName];
- } else if (protocolType == TUICallProtocolTypeAccept) {
- display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallAcceptFormat), showName];
- } else if (protocolType == TUICallProtocolTypeSwitchToAudio) {
- display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallSwitchToAudioFormat), showName];
- } else if (protocolType == TUICallProtocolTypeSwitchToAudioConfirm) {
- display = [NSString stringWithFormat:TUIChatLocalizableString(TUIChatGroupCallConfirmSwitchToAudioFormat), showName];
- } else {
- display = TUIChatLocalizableString(TUIChatCallUnrecognized);
- }
- } else {
- display = TUIChatLocalizableString(TUIChatCallUnrecognized);
- }
- return rtlString(display);
- }
- - (TUICallMessageDirection)directionForSimplifyAppearance {
- if (self.participantRole == TUICallParticipantRoleCaller) {
- return TUICallMessageDirectionOutgoing;
- } else {
- return TUICallMessageDirectionIncoming;
- }
- }
- - (BOOL)isUseReceiverAvatarForSimplifyAppearance {
- if (self.direction == TUICallMessageDirectionOutgoing) {
- return !self.innerMessage.isSelf;
- } else {
- return self.innerMessage.isSelf;
- }
- }
- #pragma mark - Utils
- - (NSString *)convertProtocolTypeToString:(TUICallProtocolType)type {
- static NSDictionary *dict = nil;
- if (dict == nil) {
- dict = @{
- @(TUICallProtocolTypeSend) : @"TUICallProtocolTypeSend",
- @(TUICallProtocolTypeAccept) : @"TUICallProtocolTypeAccept",
- @(TUICallProtocolTypeReject) : @"TUICallProtocolTypeReject",
- @(TUICallProtocolTypeCancel) : @"TUICallProtocolTypeCancel",
- @(TUICallProtocolTypeHangup) : @"TUICallProtocolTypeHangup",
- @(TUICallProtocolTypeTimeout) : @"TUICallProtocolTypeTimeout",
- @(TUICallProtocolTypeLineBusy) : @"TUICallProtocolTypeLineBusy",
- @(TUICallProtocolTypeSwitchToAudio) : @"TUICallProtocolTypeSwitchToAudio",
- @(TUICallProtocolTypeSwitchToAudioConfirm) : @"TUICallProtocolTypeSwitchToAudioConfirm",
- };
- }
- return [dict objectForKey:@(type)] ?: @"unknown";
- }
- @end
- // ********************************************************************
- // ********************************************************************
- // TUIChatCallingDataProvider
- // ********************************************************************
- @interface TUIChatCallingDataProvider ()
- @property(nonatomic, assign) TUIChatCallingMessageAppearance style;
- @property(nonatomic, strong) NSCache<TUIChatMessageID, TUIChatCallingInfo *> *callingCache;
- @end
- @implementation TUIChatCallingDataProvider
- - (instancetype)init {
- if (self = [super init]) {
- self.style = TUIChatCallingMessageAppearanceSimplify;
- }
- return self;
- }
- - (void)setCallingMessageStyle:(TUIChatCallingMessageAppearance)style {
- self.style = style;
- }
- - (void)redialFromMessage:(V2TIMMessage *)innerMessage {
- NSDictionary *param = nil;
- id<TUIChatCallingInfoProtocol> callingInfo = nil;
- if ([self isCallingMessage:innerMessage callingInfo:&callingInfo]) {
- if (callingInfo.streamMediaType == TUICallStreamMediaTypeVoice) {
- param = @{
- TUICore_TUICallingService_ShowCallingViewMethod_UserIDsKey : @[ innerMessage.userID ],
- TUICore_TUICallingService_ShowCallingViewMethod_CallTypeKey : @"0"
- };
- } else if (callingInfo.streamMediaType == TUICallStreamMediaTypeVideo) {
- param = @{
- TUICore_TUICallingService_ShowCallingViewMethod_UserIDsKey : @[ innerMessage.userID ],
- TUICore_TUICallingService_ShowCallingViewMethod_CallTypeKey : @"1"
- };
- }
- if (param) {
- [TUICore callService:TUICore_TUICallingService method:TUICore_TUICallingService_ShowCallingViewMethod param:param];
- }
- }
- }
- - (BOOL)isCallingMessage:(V2TIMMessage *)innerMessage callingInfo:(id<TUIChatCallingInfoProtocol> __nullable *__nullable)callingInfo {
- TUIChatCallingInfo *item = [self callingInfoForMesssage:innerMessage];
- if (item == nil) {
- if (callingInfo) {
- *callingInfo = nil;
- }
- return NO;
- } else {
- if (callingInfo) {
- *callingInfo = item;
- }
- return YES;
- }
- }
- - (TUIChatCallingInfo *__nullable)callingInfoForMesssage:(V2TIMMessage *)innerMessage {
- // 1. Fetch from cache
- TUIChatMessageID msgID = innerMessage.msgID ?: @"";
- TUIChatCallingInfo *item = [self.callingCache objectForKey:msgID];
- if (item) {
- item.innerMessage = innerMessage;
- return item;
- }
- // 2. Parse
- V2TIMSignalingInfo *info = [V2TIMManager.sharedInstance getSignallingInfo:innerMessage];
- if (info == nil || info.data.length == 0) {
- return nil;
- }
- NSData *data = [info.data dataUsingEncoding:NSUTF8StringEncoding];
- if (data == nil) {
- return nil;
- }
- NSError *err = nil;
- NSDictionary *param = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
- if (param == nil || ![param isKindOfClass:NSDictionary.class]) {
- return nil;
- }
- NSString *businessID = [param objectForKey:@"businessID"];
- if (businessID == nil || ![businessID isKindOfClass:NSString.class]) {
- return nil;
- }
- if (![businessID isEqualToString:@"av_call"] && ![businessID isEqualToString:@"rtc_call"] ) {
- return nil;
- }
- // 3 Cached and return
- item = [[TUIChatCallingInfo alloc] init];
- item.style = self.style;
- item.signalingInfo = info;
- item.jsonData = param;
- item.innerMessage = innerMessage;
- [self.callingCache setObject:item forKey:msgID];
- return item;
- }
- #pragma mark - Lazy
- - (NSCache<TUIChatMessageID, TUIChatCallingInfo *> *)callingCache {
- if (_callingCache == nil) {
- _callingCache = [[NSCache alloc] init];
- }
- return _callingCache;
- }
- @end
- // ********************************************************************
|