实现1对1呼叫(不含UI集成-V1)

更新时间: 2023/07/28 02:09:46

本文介绍通过 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 接口,通过 widthheight 参数设置采集分辨率。默认预览分辨率为 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 同意呼叫,通话接通、两人进行实时音视频通信。

  1. 用户 A 以及用户 B 均完成云信 IM SDK 的登录,并成功初始化呼叫组件。

  2. 用户 A 获取到自己以及用户 B 登录云信 IM SDK 的账号(AccId)。

  3. (可选)配置自定义推送。

    [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、自定义参数等。

  1. 用户 A 通过如下代码触发呼叫用户 B 的操作。

    objc    [[NERtcCallKit sharedInstance] call:@"被叫 im Accid" type: NERtcCallTypeVideo       completion:^(NSError * _Nullable error) {
    
        }];
    

    如果需要实现音视频录制,请在调用 call 方法之前,调用setParameters 方法,设置 kNERtcKeyRecordAudioEnabledkNERtcKeyRecordVideoEnabled 的值为 YES

  2. 用户 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
              }
          }];
      }
      
  3. 通话完成后点击挂断即可。

    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];
}

此文档是否对你有帮助?
有帮助
去反馈
  • 注意事项
  • 开发环境
  • 准备工作
  • 集成呼叫组件
  • 步骤 1 引入呼叫组件
  • 步骤 2 初始化组件
  • 步骤 3 登录和登出
  • (可选)设置预览的分辨率
  • 实现 1 对 1 呼叫
  • 示例代码