龙空技术网

IOS技术分享|ARCallPlus 开源项目(一)

anyRTC云平台 351

前言:

此刻小伙伴们对“vad算法源代码”可能比较重视,朋友们都想要学习一些“vad算法源代码”的相关资讯。那么小编同时在网上收集了一些关于“vad算法源代码””的相关知识,希望我们能喜欢,你们一起来学习一下吧!

ARCallPlus 简介

ARCallPlus 是开源的音视频通话项目,同时支持iOS、Android、Web等平台。本文主要介绍音视频通话 ARUICalling 模块 iOS 本地库的封装。

源码下载

三行代码、二十分钟应用内构建,实现音视频通话。本项目已上架App Store,欢迎下载体验。

[GitHub 开源地址]()[App Store 下载地址]()

开发环境开发工具:Xcode13 真机运行开发语言:Objective-C、Swift

项目结构

核心 API:

ARUILogin(登录 API)ARUICalling(通话 API)ARUICallingListerner(通话回调)

内部核心 API:

ARTCCalling(音视频)ARTCCallingDelegate(音视频回调)ARTCCalling+Signal(实时消息)

核心 API 和回调

@interface ARUICalling : NSObject+ (instancetype)shareInstance;/// 通话接口/// @param users 用户信息/// @param type 呼叫类型:视频/语音- (void)call:(NSArray<ARCallUser *> *)users type:(ARUICallingType)type;/// 通话回调/// @param listener 回调- (void)setCallingListener:(id<ARUICallingListerner>)listener;/// 设置铃声,建议在30s以内,只支持本地音频文件/// @param filePath 音频文件路径- (void)setCallingBell:(NSString *)filePath;/// 开启静音模式(默认关)- (void)enableMuteMode:(BOOL)enable;/// 开启自定义路由(默认关)/// @param enable 打开后,在onStart回调中,会收到对应的ViewController对象,可以自行决定视图展示方式- (void)enableCustomViewRoute:(BOOL)enable;@end@protocol ARUICallingListerner <NSObject>// 收到呼叫时,先通过此方法询问是否可以唤起被叫UI.// 返回为true,直接唤起UI。返回为false,内部返回忙线// 不实现默认直接可以唤起UI- (BOOL)shouldShowOnCallView NS_SWIFT_NAME(shouldShowOnCallView());/// 呼叫开始回调。主叫、被叫均会触发;/// 被叫触发时,会将控制器通过监听回调出来,由接入方决定显示方案。/// @param userIDs 本次通话用户id(自己除外)/// @param type 通话类型:视频\音频/// @param role 通话角色:主叫\被叫/// @param viewController 提供Calling功能页面给调用方,可以让用户在此基础上自定义- (void)callStart:(NSArray<NSString *> *)userIDs type:(ARUICallingType)type role:(ARUICallingRole)role viewController:(UIViewController * _Nullable)viewController NS_SWIFT_NAME(callStart(userIDs:type:role:viewController:));/// 通话结束回调/// @param userIDs 本次通话用户id(自己除外)/// @param type 通话类型:视频\音频/// @param role 通话角色:主叫\被叫/// @param totalTime 通话时长- (void)callEnd:(NSArray<NSString *> *)userIDs type:(ARUICallingType)type role:(ARUICallingRole)role totalTime:(float)totalTime NS_SWIFT_NAME(callEnd(userIDs:type:role:totalTime:));/// 通话事件回调/// @param event 回调事件类型/// @param type 通话类型:视频\音频/// @param role 通话角色:主叫\被叫/// @param message 事件- (void)onCallEvent:(ARUICallingEvent)event type:(ARUICallingType)type role:(ARUICallingRole)role message:(NSString *)message NS_SWIFT_NAME(onCallEvent(event:type:role:message:));/// 推送事件回调/// @param userIDs 不在线的用户id/// @param type 通话类型:视频\音频- (void)onPushToOfflineUser:(NSArray<NSString *> *)userIDs type:(ARUICallingType)type;@end

示例代码

效果展示(点对点音频通话)

代码实现

- (ARtcEngineKit *)rtcEngine {if (!_rtcEngine) {/// 实例化音视频引擎对象_rtcEngine = [ARtcEngineKit sharedEngineWithAppId:[ARUILogin getSdkAppID] delegate:self];/// 直播模式[_rtcEngine setChannelProfile: ARChannelProfileLiveBroadcasting];[_rtcEngine setClientRole: ARClientRoleBroadcaster];/// 编码配置ARVideoEncoderConfiguration *configuration = [[ARVideoEncoderConfiguration alloc] init];configuration.dimensions = CGSizeMake(960, 540);configuration.frameRate = 15;configuration.bitrate = 500;[_rtcEngine setVideoEncoderConfiguration:configuration];/// 启用说话者音量提示[_rtcEngine enableAudioVolumeIndication:2000 smooth:3 report_vad: YES];/// 开启美颜[_rtcEngine setBeautyEffectOptions:YES options:[[ARBeautyOptions alloc]init]];}return _rtcEngine;}//MARK: - Publish Method- (void)call:(NSArray *)userIDs type:(CallType)type {/// 发起通话if (!self.isOnCalling) {self.curLastModel.inviter = [ARUILogin getUserID];self.curLastModel.action = CallAction_Call;self.curLastModel.calltype = type;self.curRoomID = [NSString stringWithFormat:@"%d", [ARTCCallingUtils generateRoomID]];self.isMembers = userIDs.count >= 2 ? YES : NO;self.calleeUserIDs = [@[] mutableCopy];self.curType = type;self.isOnCalling = YES;self.isBeingCalled = NO;[self joinRoom];[self createMemberChannel];}// 如果不在当前邀请列表,则新增NSMutableArray *newInviteList = [NSMutableArray array];for (NSString *userID in userIDs) {if (![self.curInvitingList containsObject:userID]) {[newInviteList addObject:userID];}}[self.curInvitingList addObjectsFromArray:newInviteList];[self.calleeUserIDs addObjectsFromArray:newInviteList];if (!(self.curInvitingList && self.curInvitingList.count > 0)) return;self.currentCallingUserID = newInviteList.firstObject;for (NSString *userID in self.curInvitingList) {[self invite:userID action:CallAction_Call];}}- (void)accept:(BOOL)isVideo {/// 接受当前通话ARLog(@"Calling - accept Call");if (!isVideo) {[self.rtcEngine disableVideo];self.curType = CallType_Audio;if ([self canDelegateRespondMethod:@selector(onSwitchToAudio:message:)]) {[self.delegate onSwitchToAudio:YES message:@""];}}[self joinRoom];self.currentCallingUserID = self.curSponsorForMe;[self invite:self.curSponsorForMe action:CallAction_Accept];self.isCallSucess = YES;[self dealWithException:10];}- (void)reject {/// 拒绝当前通话ARLog(@"Calling - reject Call");[self invite:self.curSponsorForMe action:CallAction_Reject];self.isOnCalling = NO;[self.rtcEngine disableVideo];}- (void)hangup {/// 主动挂断通话__block BOOL hasCallUser = NO;[self.curRoomList enumerateObjectsUsingBlock:^(NSString *user, NSUInteger idx, BOOL * _Nonnull stop) {if ((user && user.length > 0) && ![self.curInvitingList containsObject:user]) {// 还有正在通话的用户hasCallUser = YES;[self invite:user action:CallAction_End];*stop = YES;}}];/// 主叫需要取消未接通的通话if (hasCallUser == NO) {ARLog(@"Calling - GroupHangup Send CallAction_Cancel");[self.curInvitingList enumerateObjectsUsingBlock:^(NSString *invitedId, NSUInteger idx, BOOL * _Nonnull stop) {[self invite:invitedId action:CallAction_Cancel];}];}[self leaveRoom];self.isOnCalling = NO;}- (void)switchToAudio {/// 切换到语音通话(通话中)self.curType = CallType_Audio;[self.rtcEngine disableVideo];[self invite:self.currentCallingUserID action:CallAction_SwitchToAudio];if ([self canDelegateRespondMethod:@selector(onSwitchToAudio:message:)]) {[self.delegate onSwitchToAudio:YES message:@""];}}- (void)startRemoteView:(NSString *)userID view:(UIView *)view {/// 开启远程用户视频渲染ARLog(@"Calling - startRemoteView userID = %@", userID);if (userID.length != 0) {ARtcVideoCanvas *canvas = [[ARtcVideoCanvas alloc] init];canvas.uid = userID;canvas.view = view;[self.rtcEngine setupRemoteVideo:canvas];}}- (void)stopRemoteView:(NSString *)userID {/// 关闭远程用户视频渲染ARLog(@"Calling - stopRemoteView userID = %@", userID);ARtcVideoCanvas *canvas = [[ARtcVideoCanvas alloc] init];canvas.uid = userID;canvas.view = nil;[self.rtcEngine setupRemoteVideo:canvas];}- (void)openCamera:(BOOL)frontCamera view:(UIView *)view {/// 打开摄像头ARLog(@"Calling - openCamera");if (self.curType == CallType_Video) {[self.rtcEngine enableVideo];}ARtcVideoCanvas *canvas = [[ARtcVideoCanvas alloc] init];canvas.uid = [ARUILogin getUserID];canvas.view = view;[self.rtcEngine setupLocalVideo:canvas];[self.rtcEngine startPreview];self.isFrontCamera = frontCamera;}

效果展示(点对点视频通话)

代码实现

//MARK: - ARtcEngineDelegate- (void)rtcEngine:(ARtcEngineKit *)engine didOccurError:(ARErrorCode)errorCode {/// 发生错误回调ARLog(@"Calling - didOccurError = %ld", (long)errorCode);}- (void)rtcEngine:(ARtcEngineKit *)engine firstRemoteVideoDecodedOfUid:(NSString *)uid size:(CGSize)size elapsed:(NSInteger)elapsed {ARLog(@"Calling - firstRemoteVideoDecodedOfUid = %@", uid);}- (void)rtcEngine:(ARtcEngineKit *)engine didJoinedOfUid:(NSString *)uid elapsed:(NSInteger)elapsed {/// 远端用户/主播加入回调ARLog(@"Calling - didJoinedOfUid = %@", uid);// C2C curInvitingList 不要移除 userID,如果是自己邀请的对方,这里移除后,最后发结束信令的时候找不到人[self dealWithException:0];[self removeTimer:uid];if ([self.curInvitingList containsObject:uid]) {[self.curInvitingList removeObject:uid];}if (![self.curRoomList containsObject:uid]) {[self.curRoomList addObject:uid];}// C2C 通话要计算通话时长if ([self canDelegateRespondMethod:@selector(onUserEnter:)]) {[self.delegate onUserEnter:uid];}}- (void)rtcEngine:(ARtcEngineKit *)engine didOfflineOfUid:(NSString *)uid reason:(ARUserOfflineReason)reason {/// 远端用户(通信场景)/主播(直播场景)离开当前频道回调ARLog(@"Calling - didOfflineOfUid = %@", uid);// C2C curInvitingList 不要移除 userID,如果是自己邀请的对方,这里移除后,最后发结束信令的时候找不到人if (self.isMembers || (!self.isMembers && reason == ARUserOfflineReasonQuit)) {if ([self.curInvitingList containsObject:uid]) {[self.curInvitingList removeObject:uid];}if ([self.curRoomList containsObject:uid]) {[self.curRoomList removeObject:uid];}if ([self canDelegateRespondMethod:@selector(onUserLeave:)]) {[self.delegate onUserLeave:uid];}[self preExitRoom];} else if (reason == ARUserOfflineReasonDropped) {[self dealWithException:10];}}- (void)rtcEngine:(ARtcEngineKit *)engine remoteVideoStateChangedOfUid:(NSString *)uid state:(ARVideoRemoteState)state reason:(ARVideoRemoteStateReason)reason elapsed:(NSInteger)elapsed {/// 远端视频状态发生改变回调if (reason == ARVideoRemoteStateReasonRemoteMuted || reason == ARVideoRemoteStateReasonRemoteUnmuted) {if ([self canDelegateRespondMethod:@selector(onUserVideoAvailable:available:)]) {[self.delegate onUserVideoAvailable:uid available:(reason == ARVideoRemoteStateReasonRemoteMuted) ? NO : YES];}}}- (void)rtcEngine:(ARtcEngineKit *)engine remoteAudioStateChangedOfUid:(NSString *)uid state:(ARAudioRemoteState)state reason:(ARAudioRemoteStateReason)reason elapsed:(NSInteger)elapsed {/// 远端音频状态发生改变回调if (reason == ARAudioRemoteReasonRemoteMuted || reason == ARAudioRemoteReasonRemoteUnmuted) {if ([self canDelegateRespondMethod:@selector(onUserAudioAvailable:available:)]) {[self.delegate onUserAudioAvailable:uid available:(reason == ARAudioRemoteReasonRemoteMuted) ? NO : YES];}}}- (void)rtcEngine:(ARtcEngineKit *)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<ARtcAudioVolumeInfo *> *)speakers totalVolume:(NSInteger)totalVolume {/// 提示频道内谁正在说话、说话者音量及本地用户是否在说话的回调if ([self canDelegateRespondMethod:@selector(onUserVoiceVolume:volume:)]) {for (ARtcAudioVolumeInfo *info in speakers) {if ([info.uid isEqualToString:@"0"]) {[self.delegate onUserVoiceVolume:[ARUILogin getUserID] volume:(UInt32)info.volume];} else {[self.delegate onUserVoiceVolume:info.uid volume:(UInt32)info.volume];}}}}- (void)rtcEngine:(ARtcEngineKit *)engine connectionChangedToState:(ARConnectionStateType)state reason:(ARConnectionChangedReason)reason {//ARLog(@"Calling - rtc connectionStateChanged state = %ld reason = %ld", (long)state, (long)reason);}- (void)rtcEngine:(ARtcEngineKit *)engine didVideoSubscribeStateChange:(NSString *)channel withUid:(NSString *)uid oldState:(ARStreamSubscribeState)oldState newState:(ARStreamSubscribeState)newState elapseSinceLastState:(NSInteger)elapseSinceLastState {ARLog(@"Calling - didVideoSubscribeStateChange = %@ %@ %lu %lu", channel, uid, (unsigned long)oldState, (unsigned long)newState);}

效果展示(多人视频通话)

代码实现

- (void)addSignalListener {ARUILogin.kit.aRtmDelegate = self;self.callEngine.callDelegate = self;/// 用户进入后台推送问题[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(enterBackground:) name:UIApplicationWillResignActiveNotification object:nil];[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(becomeActive:) name:UIApplicationWillEnterForegroundNotification object:nil];}- (void)removeSignalListener {self.callEngine.callDelegate = nil;self.callEngine = nil;[NSNotificationCenter.defaultCenter removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];[NSNotificationCenter.defaultCenter removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];}- (void)invite:(NSString *)receiver action:(CallAction)action {if (action == CallAction_Call) {/// 发起呼叫邀请NSMutableArray *arr = [[NSMutableArray alloc] initWithObjects:[ARUILogin getUserID], nil];[arr addObjectsFromArray:self.calleeUserIDs];NSMutableArray *infoArr = [NSMutableArray array];for (NSInteger i = 0; i < arr.count; i++) {ARCallUser *user = [ARUILogin getCallUserInfo:arr[i]];[infoArr addObject:[NSObject ar_dictionaryWithObject: user]];}NSDictionary *dic = @{@"Mode": @(self.curType == CallType_Video ? 0 : 1),@"Conference": [NSNumber numberWithBool:self.isMembers],@"ChanId": self.curRoomID,@"UserData": arr,@"UserInfo": infoArr};ARtmLocalInvitation *localInvitation = [[ARtmLocalInvitation alloc] initWithCalleeId:receiver];localInvitation.content = [ARTCCallingUtils dictionary2JsonStr:dic];[self.callEngine sendLocalInvitation:localInvitation completion:^(ARtmInvitationApiCallErrorCode errorCode) {ARLog(@"sendLocalInvitation code = %ld", (long)errorCode);}];[self.callingDic setObject:localInvitation forKey:receiver];} else if (action == CallAction_Cancel) {/// 取消呼叫邀请id invitation = [self.callingDic objectForKey:receiver];if (invitation) {ARtmLocalInvitation *localInvitation = (ARtmLocalInvitation *)invitation;[self.callEngine cancelLocalInvitation:localInvitation completion:^(ARtmInvitationApiCallErrorCode errorCode) {ARLog(@"cancelLocalInvitation code = %ld", (long)errorCode);}];}} else if (action == CallAction_Accept) {/// 接受呼叫邀请id invitation = [self.calledDic objectForKey:receiver];if (invitation) {ARtmRemoteInvitation *remoteInvitation = (ARtmRemoteInvitation *)invitation;NSDictionary *dic = @{@"Mode": @(self.curType == CallType_Video ? 0: 1), @"Conference": [NSNumber numberWithBool:self.isMembers]};remoteInvitation.response = [ARTCCallingUtils dictionary2JsonStr:dic];[self.callEngine acceptRemoteInvitation:remoteInvitation completion:^(ARtmInvitationApiCallErrorCode errorCode) {ARLog(@"acceptRemoteInvitation code = %ld", (long)errorCode);}];}} else if (action == CallAction_Reject) {/// 拒绝呼叫邀请id invitation = [self.calledDic objectForKey:receiver];if (invitation) {ARtmRemoteInvitation *remoteInvitation = (ARtmRemoteInvitation *)invitation;[self.callEngine refuseRemoteInvitation:remoteInvitation completion:^(ARtmInvitationApiCallErrorCode errorCode) {ARLog(@"refuseRemoteInvitation code = %ld", (long)errorCode);}];}} else if (action == CallAction_SwitchToAudio) {/// 切换成语音通话NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"SwitchAudio", @"Cmd",nil];ARtmMessage *message = [[ARtmMessage alloc] initWithText:[ARTCCallingUtils dictionary2JsonStr:dic]];[self sendPeerMessage:message user:receiver];} else if (action == CallAction_End) {/// 通话中断if (!self.isMembers) {NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"EndCall", @"Cmd",nil];ARtmMessage *message = [[ARtmMessage alloc] initWithText:[ARTCCallingUtils dictionary2JsonStr:dic]];[self sendPeerMessage:message user:receiver];}}}- (void)preExitRoom {/// 当前房间中存在成员,不能自动退房if (self.curRoomList.count > 0) return;/// 存在正在呼叫的通话if (self.curInvitingList.count >= 1) {return;}[self exitRoom];}- (void)exitRoom {ARLog(@"Calling - exitRoom");if ([self canDelegateRespondMethod:@selector(onCallEnd)]) {[self.delegate onCallEnd];}for (NSString *uid in self.timerDic.allKeys) {[self removeTimer:uid];}[self dealWithException:0];[self leaveRoom];self.isOnCalling = NO;if(UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {[self logout];}}// MARK: - privite- (ARtmCallKit *)callEngine {return [ARUILogin.kit getRtmCallKit];}- (void)sendPeerMessage:(ARtmMessage *)message user:(NSString *)uid {ARLog(@"Calling - sendPeerMessage = %@", message.text);ARtmSendMessageOptions *options = [[ARtmSendMessageOptions alloc] init];[[ARUILogin kit] sendMessage:message toPeer:uid sendMessageOptions:options completion:^(ARtmSendPeerMessageErrorCode errorCode) {ARLog(@"Calling - SendPeerMessage code = %ld", (long)errorCode);}];}- (void)logout {if (!self.isOnCalling && ARUILogin.kit != nil) {[ARUILogin.kit logoutWithCompletion:nil];self.interrupt = YES;}}- (void)enterBackground:(NSNotification *)notification {[self logout];}- (void)becomeActive:(NSNotification *)notification {if (!self.isOnCalling && self.interrupt) {[ARUILogin.kit loginByToken:nil user:ARUILogin.getUserID completion:nil];self.interrupt = NO;}}//MARK: - ARtmDelegate- (void)rtmKit:(ARtmKit *)kit connectionStateChanged:(ARtmConnectionState)state reason:(ARtmConnectionChangeReason)reason {ARLog(@"Calling - rtm connectionStateChanged state = %ld reason = %ld", (long)state, (long)reason);if (reason == ARtmConnectionChangeReasonRemoteLogin) {[self.delegate onError:401 msg:@"RemoteLogin"];[self exitRoom];return;}if (!self.isMembers) {if (state == ARtmConnectionStateDisconnected || state == ARtmConnectionStateReconnecting) {self.isReconnection = YES;[self dealWithException: 30];} else if (state == ARtmConnectionStateConnected) {[self dealWithException:0];if (self.isReconnection && self.isOnCalling && self.currentCallingUserID) {/// 兼容异常[self dealWithException:10];self.isReconnection = NO;NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"CallState", @"Cmd",nil];ARtmMessage *message = [[ARtmMessage alloc] initWithText:[ARTCCallingUtils dictionary2JsonStr:dic]];[self sendPeerMessage:message user:self.currentCallingUserID];}}}}- (void)rtmKit:(ARtmKit *)kit messageReceived:(ARtmMessage *)message fromPeer:(NSString *)peerId {/// 收到点对点消息回调ARLog(@"Calling - messageReceived text = %@ ", message.text);if (message.text.length != 0) {NSDictionary *dic = [ARTCCallingUtils jsonSring2Dictionary:message.text];NSString *value = [dic objectForKey:@"Cmd"];if ([value isEqualToString:@"SwitchAudio"]) {/// 切换成语音通话if ([self canDelegateRespondMethod:@selector(onSwitchToAudio:message:)]) {[self.delegate onSwitchToAudio:YES message:@""];}self.curType = CallType_Audio;} else if ([value isEqualToString:@"EndCall"]) {/// 结束通话if (!self.isMembers) {if ([self canDelegateRespondMethod:@selector(onUserLeave:)]) {[self.delegate onUserLeave:peerId];}[self exitRoom];}} else if ([value isEqualToString:@"CallState"]) {/// 确认通话状态NSDictionary *dic;if (self.isCallSucess) {dic = @{@"Cmd": @"CallStateResult", @"state": @(2), @"Mode": (self.curType == CallType_Video ? @(0) : @(1))};} else {dic= @{@"Cmd": @"CallStateResult", @"state": @(1)};}ARtmMessage *message = [[ARtmMessage alloc] initWithText:[ARTCCallingUtils dictionary2JsonStr:dic]];[self sendPeerMessage:message user:peerId];} else if ([value isEqualToString:@"CallStateResult"]) {/// 对方通话状态回复结果[self dealWithException:0];int state = [[dic objectForKey:@"state"] intValue];if (state == 0) {/// 已挂断[self exitRoom];} else if (state == 1) {/// 呼叫等待} else {/// 已同意int mode = [[dic objectForKey:@"Mode"] intValue];if (self.curType == CallType_Video && mode == 1) {self.curType = CallType_Audio;[self switchToAudio];}}}}}// MARK: - ARtmCallDelegate- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit localInvitationReceivedByPeer:(ARtmLocalInvitation * _Nonnull)localInvitation {/// 被叫已收到呼叫邀请ARLog(@"Calling - localInvitationReceivedByPeer");}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit localInvitationAccepted:(ARtmLocalInvitation * _Nonnull)localInvitation withResponse:(NSString * _Nullable) response {/// 被叫已接受呼叫邀请ARLog(@"Calling - localInvitationAccepted response = %@", response);[self.callingDic removeObjectForKey:localInvitation.calleeId];if (response != nil) {NSDictionary * dic = [ARTCCallingUtils jsonSring2Dictionary:response];if (self.curType == CallType_Video && [[dic objectForKey:@"Mode"] intValue] == 1) {if ([self canDelegateRespondMethod:@selector(onSwitchToAudio:message:)]) {[self.delegate onSwitchToAudio:YES message:@""];}self.curType = CallType_Audio;}}self.isCallSucess = YES;}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit localInvitationRefused:(ARtmLocalInvitation * _Nonnull)localInvitation withResponse:(NSString * _Nullable) response {/// 被叫已拒绝呼叫邀请ARLog(@"Calling - localInvitationRefused");[self.callingDic removeObjectForKey:localInvitation.calleeId];BOOL isBusy = NO;if (localInvitation.response.length != 0) {NSDictionary * dic = [ARTCCallingUtils jsonSring2Dictionary:localInvitation.response];if ([dic.allValues containsObject:@"Calling"]) {isBusy = YES;}}if (self.delegate) {NSString *uid = localInvitation.calleeId;if ([self.curInvitingList containsObject:uid]) {[self.curInvitingList removeObject:uid];}if (isBusy) {if ([self canDelegateRespondMethod:@selector(onLineBusy:)]) {[self.delegate onLineBusy:localInvitation.calleeId];}} else {if ([self canDelegateRespondMethod:@selector(onReject:)]) {[self.delegate onReject:uid];}}[self preExitRoom];}}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit localInvitationCanceled:(ARtmLocalInvitation * _Nonnull)localInvitation {/// 呼叫邀请已被取消ARLog(@"Calling - localInvitationCanceled");[self.callingDic removeObjectForKey:localInvitation.calleeId];}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit localInvitationFailure:(ARtmLocalInvitation * _Nonnull)localInvitation errorCode:(ARtmLocalInvitationErrorCode)errorCode {/// 呼叫邀请发送失败ARLog(@"Calling - localInvitationFailure");NSString *calleeId = localInvitation.calleeId;[self.callingDic removeObjectForKey:calleeId];if ([self canDelegateRespondMethod:@selector(onNoResp:)]) {[self.delegate onNoResp:calleeId];}if ([self.curInvitingList containsObject:calleeId]) {[self.curInvitingList removeObject:calleeId];}[self preExitRoom];}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit remoteInvitationReceived:(ARtmRemoteInvitation * _Nonnull)remoteInvitation {/// 收到一个呼叫邀请ARLog(@"Calling - remoteInvitationReceived");[self.calledDic setObject:remoteInvitation forKey:remoteInvitation.callerId];if (!self.isOnCalling) {self.isOnCalling = YES;self.curSponsorForMe = remoteInvitation.callerId;self.currentCallingUserID = remoteInvitation.callerId;NSDictionary *dic = [ARTCCallingUtils jsonSring2Dictionary:remoteInvitation.content];self.isMembers = [[dic objectForKey:@"Conference"] boolValue];self.curRoomID = [dic objectForKey:@"ChanId"];CallType type = ([[dic objectForKey:@"Mode"] intValue] == 0) ? CallType_Video : CallType_Audio;self.curType = type;if ([dic.allKeys containsObject:@"UserInfo"]) {NSArray *infoArr = [dic objectForKey:@"UserInfo"];for (NSInteger i = 0; i < infoArr.count; i++) {ARCallUser *user = [ARCallUser ar_objectWithDictionary: infoArr[i]];[ARUILogin setCallUserInfo:user];}}if (self.isMembers) {/// 多人通话NSArray *arr = [dic objectForKey:@"UserData"];[self.delegate onInvited:remoteInvitation.callerId userIds:arr isFromGroup:NO callType:type];[self createMemberChannel];/// 30sfor (NSInteger i = 0; i < arr.count; i++) {NSString *uid = arr[i];/// 被叫对其他受邀者倒计时 -- 异常处理if (![uid isEqualToString:[ARUILogin getUserID]] && ![uid isEqualToString:self.curSponsorForMe]) {__block NSInteger totalTime = 0;NSTimeInterval interval = 1.0;__weak typeof(self) weakSelf = self;NSString *timerName = [ARTCGCDTimer timerTask:^{totalTime += (NSInteger)interval;if (totalTime == 30) {if ([weakSelf canDelegateRespondMethod:@selector(onNoResp:)]) {[weakSelf.delegate onNoResp:uid];[weakSelf removeTimer: uid];}}ARLog(@"%@ ==> %ld \n", uid, (long)totalTime);} start:0 interval:interval repeats:YES async:NO];[self.timerDic setObject:timerName forKey:uid];}}} else {/// 单人通话[self.delegate onInvited:remoteInvitation.callerId userIds:@[[ARUILogin getUserID]] isFromGroup:NO callType:type];}} else {NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"Calling", @"Cmd",nil];remoteInvitation.response = [ARTCCallingUtils dictionary2JsonStr:dic];[self invite:remoteInvitation.callerId action:CallAction_Reject];}}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit remoteInvitationRefused:(ARtmRemoteInvitation * _Nonnull)remoteInvitation {/// 拒绝呼叫邀请成功ARLog(@"Calling - remoteInvitationRefused");[self.calledDic removeObjectForKey:remoteInvitation.callerId];}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit remoteInvitationAccepted:(ARtmRemoteInvitation * _Nonnull)remoteInvitation {/// 接受呼叫邀请成功ARLog(@"Calling - remoteInvitationAccepted");[self.calledDic removeObjectForKey:remoteInvitation.callerId];}- (void)rtmCallKit:(ARtmCallKit * _Nonnull)callKit remoteInvitationCanceled:(ARtmRemoteInvitation * _Nonnull)remoteInvitation {/// 主叫已取消呼叫邀请ARLog(@"Calling - remoteInvitationCanceled");[self.calledDic removeObjectForKey:remoteInvitation.callerId];if ([self.curSponsorForMe isEqualToString:remoteInvitation.callerId]) {[self exitRoom];if ([self canDelegateRespondMethod:@selector(onCallingCancel:)]) {[self.delegate onCallingCancel:remoteInvitation.callerId];}}}

结束语

最后,ARCallPlus开源项目中还存在一些bug和待完善的功能点。有不足之处欢迎大家指出issues。最后再贴一下 Github开源下载地址。

[Github开源下载地址]()。

标签: #vad算法源代码