实现1对1呼叫(不含UI集成-V1)
更新时间: 2024/08/23 10:16:57
本文介绍通过 NERTCCallkit 呼叫组件(V1 版本)实现 1 对 1 通话(点对点通话)的方法。
注意事项
- 呼叫组件默认使用调试模式。应用正式上线前,请在控制台中将指定应用的鉴权方式改回安全模式。安全模式下需要使用 Token 加入房间,详细说明请参见Token 鉴权。
- 针对组件中的回调信息,开发者要做好相应回调数据的上报及存储,以便于后期上线之后排查问题。
开发环境
在开始运行工程之前,请您准备以下开发环境:
- Xcode 10 及以上版本。
- iOS 9.0 及以上版本的 iOS 设备。
- 已安装 CocoaPods。
准备工作
-
已在控制台创建应用,并获取了对应的 App Key。详细操作请参见创建应用。
-
已开通 IM 即时通讯、音视频通话 2.0 及信令产品。开通服务的操作流程请参见开通服务。
-
已在网易云信控制台开通音视频通话 2.0 产品的话单功能。详细操作请参见开通话单功能。
集成呼叫组件
步骤 1 引入呼叫组件
建议使用 CocoaPods 进行管理。V1.8.0 版本开始,呼叫组件内部没有引入 NERTC,请在 Podfile
中添加以下内容,单独引入 NERTC SDK 。
pod 'NERtcCallKit', '1.8.2'
pod 'NERtcSDK', '4.6.29', :subspecs => ['RtcBasic'] // subspecs => ['RtcBasic']用于指定使用RTC基础版本,不包含美颜功能。若要使用美颜功能,此行请修改为 pod 'NERtcSDK', '4.6.22'
SDK 版本限制:
-
呼叫组件与 NIM SDK、NERTC SDK 之间存在映射关系,使用呼叫组件时,必须使用指定版本的 NIM SDK 和 NERTC SDK。如果您在集成呼叫组件之前,已经集成了 NIM SDK 和 NERTC SDK,请确认 SDK 版本为指定版本。
-
不同版本的呼叫组件适配不同版本的 NIM SDK 和 NERTC SDK,具体版本的适配关系请参见更新日志。
步骤 2 初始化组件
组件实现为单实例,通过接口 NERtcCallKit.sharedInstance
获取此实例,调用实例方法 setupAppKey
完成初始化。
setupAppKey
方法为使用组件前必须调用的方法,若未初始化直接调用其他组件方法,会发生不可预知的问题或故障。
objc#import <NERtcCallKit/NERtcCallKit.h>
@interface SomeViewController()<NERtcCallKitDelegate>
@end
@implementation SomeViewController
- (void)viewDidLoad {
[self setupSDK];
}
- (void)setupSDK {
NERtcCallOptions *option = [NERtcCallOptions new];
option.APNSCerName = @"anps cer name"; //输入 APNs 推送证书名
option.VoIPCerName = "your push kit cer"; //输入 pushkit 的证书名
NERtcCallKit *callkit = [NERtcCallKit sharedInstance];
[callkit setupAppKey:@"app key" options:option];
// 请求 rtc token 服务,若非安全模式则不需设置。V1.8.0及之后版本不需要执行如下配置。V1.8.0之前版本需要执行如下配置。
callkit.tokenHandler = ^(uint64_t uid, void (^complete)(NSString *token, NSError *error)) {
// 获取token以及回传给SDK(通常从业务服务器获取)
NSString *token = @"get your token";
complete(token,nil);
};
}
@end
步骤 3 登录和登出
若已经在 App 内实现了 NIMSDK 登录和登出逻辑,则不必调用相应的登录、登出接口,直接跳过此步骤即可。
使用组件的 -[NERtcCallKit login:]
进行登录,使用 -[NERtcCallKit logout:]
进行登出,登出或未进行登录则不能进行呼叫。
objective-c[[NERtcCallKit sharedInstance] login:@"im accid" token:@"im token" completion:^(NSError * _Nullable error) {
}];
[[NERtcCallKit sharedInstance] logout:^(NSError * _Nullable error) {
}];
(可选)设置预览的分辨率
在初始化呼叫组件之后,调用 RTC 的 setLocalVideoConfig
接口,通过 width
和 height
参数设置采集分辨率。默认预览分辨率为 640*480。
objcNERtcEngine *coreEngine = [NERtcEngine sharedEngine];
NERtcVideoEncodeConfiguration *config = [[NERtcVideoEncodeConfiguration alloc] init];
config.width = 640;
config.height = 360;
[coreEngine setLocalVideoConfig:config];
实现 1 对 1 呼叫
呼叫组件的典型应用场景为 1 对 1 呼叫场景,即用户 A 发起视频呼叫用户 B ,用户 B 同意呼叫,通话接通、两人进行实时音视频通信。
-
用户 A 以及用户 B 均完成云信 IM SDK 的登录,并成功初始化呼叫组件。
-
用户 A 获取到自己以及用户 B 登录云信 IM SDK 的账号(AccId)。
-
(可选)配置自定义推送。
[NERtcCallKit sharedInstance].pushConfigHandler = ^(NERtcCallKitPushConfig *config, NERtcCallKitContext *context) { // [config.pushPayload setValue:@"message.wav" forKey:@"sound"]; NSDictionary *apsField = @{@"sound":@"message.wav"}; [config.pushPayload setValue:apsField forKey:@"apsField"]; };
推送参数需要在 config.pushPayload
的内层推送参数 apsField
中设置。详细的配置方法请参见[KB0198] 关于IM提供的推送配置apsField字段。
config.pushPayload
的外层推送参数中只支持 iOS 部分属性的设置,例如 sound、自定义参数等。
-
用户 A 通过如下代码触发呼叫用户 B 的操作。
objc
[[NERtcCallKit sharedInstance] call:@"被叫 im Accid" type: NERtcCallTypeVideo completion:^(NSError * _Nullable error) { }];
如果需要实现音视频录制,请在调用
call
方法之前,调用setParameters 方法,设置kNERtcKeyRecordAudioEnabled
和kNERtcKeyRecordVideoEnabled
的值为YES
。 -
用户 B 实现呼叫组件监听并且在有呼叫回调发生时候调用
accept
方法即可实现通话。-
被叫通话页面的前置页面监听。
objc
- (void)onInvited:(NSString *)invitor userIDs:(NSArray<NSString *> *)userIDs isFromGroup:(BOOL)isFromGroup groupID:(nullable NSString *)groupID type:(NERtcCallType)type attachment:(nullable NSString *)attachment { [NIMSDK.sharedSDK.userManager fetchUserInfos:@[invitor] completion:^(NSArray<NIMUser *> * _Nullable users, NSError * _Nullable error) { if (error) { NSLog(@"fetchUserInfo failed : %@", error); }else { //调起通话页面(根据业务自己实现或者参见示例工程中的通话页面 NECallViewController ) } }]; }
-
被叫通话页面中接受通话邀请。
objc
- (void)acceptCall { __weak typeof(self) weakSelf = self; [[NERtcCallKit sharedInstance] accept:^(NSError * _Nullable error) { if (error) { NSLog(@"接听失败 : %@", error); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 销毁当前通话页面 }); }else { //设置通话页面相关显示或者参见示例工程中的通话页面 NECallViewController } }]; }
-
-
通话完成后点击挂断即可。
objc
- (void)hangup{ [[NERtcCallKit sharedInstance] hangup:^(NSError * _Nullable error) { }]; }
示例代码
由于完成一次视频通话还需要预览视图设置等复杂调用,如果要接入工程并完成视频呼叫流程还需参见如下代码,如果需要实现一些复杂操作请参见呼叫组件示例项目源码。
1 对 1 通话在呼叫或收到呼叫邀请时需要设置相应的回调监听,用于接收对应通话的控制消息。首先在需要收到监听的地方实现 NERtcCallKitDelegate
。
objc#import <NERtcCallKit/NERtcCallKit.h>
@interface SomeViewController: UIViewController <NERtcCallKitDelegate>
- (void)dealloc {
[NERtcCallKit.sharedInstance removeDelegate:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[NERtcCallKit.sharedInstance addDelegate:self];
}
#pragma mark - NERtcVideoCallDelegate
// 被叫实现监听回调
- (void)onInvited:(NSString *)invitor
userIDs:(NSArray<NSString *> *)userIDs
isFromGroup:(BOOL)isFromGroup
groupID:(nullable NSString *)groupID
type:(NERtcCallType)type
attachment:(nullable NSString *)attachment {
[NIMSDK.sharedSDK.userManager fetchUserInfos:@[invitor] completion:^(NSArray<NIMUser *> * _Nullable users, NSError * _Nullable error) {
if (error) {
NSLog(@"fetchUserInfo failed : %@", error);
}else {
NIMUser *imUser = users.firstObject;
NECallViewController *callVC = [[NECallViewController alloc] init];
//callVC.isCaller = NO;
//callVC.remoteImAccid = imUser.userId;
[self.navigationController presentViewController:callVC animated:YES completion:nil];
}
}];
}
@end
SomeViewController
为通话页面的前置页面,可能是通讯录 IM 消息等页面,通话页面的使用参见下面代码或者示例工程。
objc@interface NECallViewController : UIViewController<NERtcCallKitDelegate>
@property(strong,nonatomic) UIView *smallVideoView;
@property(strong,nonatomic) UIView *bigVideoView;
@end
@implementation NECallViewController {
- (void)dealloc {
[NERtcCallKit.sharedInstance removeDelegate:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self setupSDK];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NERtcCallKit sharedInstance] setupLocalView:nil];
}
- (void)setupUI {
[self.view addSubview:self.bigVideoView];
self.bigVideoView.frame = self.view.bounds;
[self.view addSubview:self.smallVideoView];
self.smallVideoView.frame = CGRectMake(0, 0, 100, 100);
}
- (void)setupSDK {
[[NERtcCallKit sharedInstance] addDelegate:self];
[NERtcCallKit sharedInstance].timeOutSeconds = 30;
NSError *error;
[[NERtcCallKit sharedInstance] setLoudSpeakerMode:YES error:&error];
[[NERtcCallKit sharedInstance] enableLocalVideo:YES];
[[NERtcEngine sharedEngine] adjustRecordingSignalVolume:200];
[[NERtcEngine sharedEngine] adjustPlaybackSignalVolume:200];
}
// 主叫发起呼叫
- (void)didCall {
[[NERtcCallKit sharedInstance] call:@"im Accid" type: NERtcCallTypeVideo completion:^(NSError * _Nullable error) {
NSLog(@"call error code : %@", error);
[[NERtcCallKit sharedInstance] setupLocalView:self.bigVideoView.videoView];
if (error) {
/// 对方离线时 通过APNS推送 UI不弹框提示
if (error.code == 10202 || error.code == 10201) {
return;
}
if (error.code == 21000 || error.code == 21001) {
//呼叫失败销毁当前通话页面
}
}else {
}
}];
}
// 当被叫 onInvited 回调发生,调用 accept 接听呼叫
- (void)acceptCall {
__weak typeof(self) weakSelf = self;
[[NERtcCallKit sharedInstance] accept:^(NSError * _Nullable error) {
if (error) {
NSLog(@"接听失败 : %@", error);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 销毁当前通话页面
});
}else {
[[NERtcCallKit sharedInstance] setupLocalView:weakSelf.smallVideoView];
[[NERtcCallKit sharedInstance] setupRemoteView:weakSelf.bigVideoView forUser:@"对端 im accid"];
}
}];
}
// 主叫被叫结束通话
- (void)hangup{
[[NERtcCallKit sharedInstance] hangup:^(NSError * _Nullable error) {
}];
}
- (UIView *)bigVideoView {
if (!_bigVideoView) {
_bigVideoView = [[UIView alloc] init];
_bigVideoView.backgroundColor = [UIColor darkGrayColor];
}
return _bigVideoView;
}
- (UIView *)smallVideoView {
if (!_smallVideoView) {
_smallVideoView = [[UIView alloc] init];
_smallVideoView.backgroundColor = [UIColor darkGrayColor];
}
return _smallVideoView;
}
#pragma mark - NERtcVideoCallDelegate
- (void)onUserEnter:(NSString *)userID {
// 被叫加入可以进行视频通话,设置本地音视频相关api
[[NERtcCallKit sharedInstance] setupLocalView:self.smallVideoView];
[[NERtcCallKit sharedInstance] setupRemoteView:self.bigVideoView forUser:userID];
}