NERtcCallKit 2.5.0

NERtcCallKit 2.5.0

丁文超cytoolyunxin_staffyunxin_staff张世文ginger维护。



  • 网易云技术部门

NERtcCallKit-iOS

为了方便开发者接入音视频2.0呼叫功能,以组件的形式提供给客户,提高接入效率。Demo 链接

功能开通

1. 登录

网易云控制台,点击【应用】>【创建】创建自己的 App,在【功能管理】中申请开通以下功能

  1. 如果仅使用呼叫功能,则需要开通

    1. 【信令】
    2. 【音视频通话2.0】
    3. 【非安全模式】-组件默认使用非安全模式,开启安全模式请联系 SO 咨询
  2. 如果还需要使用话单功能,则还需要开通

    1. 【IM】
    2. 【G2话单功能】-目前仅支持联系销售/SO 开通
  3. 在控制台中【appkey 管理】获取 appkey。

注:如果曾经已有相应的应用,可在原应用上申请开通【音视频通话2.0】及【信令】功能

整体架构图

img

  1. 下载Demo解压,进入NIMDemo,点击NIM.xcworkspace进入工程
  2. 查找组件为NERtcCallKit

集成方式

  • cocoapods集成(推荐)
pod 'NERtcCallKit'
  • 手动集成

Demo中使用Pod形式导入音视频2.0 SDK,依赖于

NERtcSDK 3.7.1 版本,

NIMSDK 8.1.0 版本,

NIMKIT 3.1.1 版本,

如有需要可自行升级

复制NERtcCallKit文件夹以及文件夹下的.h和.m文件,根据自己的工程需求,将它们复制到工程对应的路径下

组件结构

  • NERtcCallKit文件夹:音视频管理类,包含初始化、登录、呼叫、邀请等逻辑的相关操作管理
    • NERtcCallKit.h:封装层实现protocal NERtcCallKitDelegate封装实例方法
    • NERtcCallKitDelegateProxy.h:代理proxy的头文件(Demo业务层,可不关注)
    • NERtcCallOptions.h:组件推送配置
    • NERtcCallKitContext.h:存储用户信息相关(Demo业务层,可不关注)
    • NERtcCallKit+Private.h:组件封装私有的实例方法
    • NERtcCallKitConsts.h:定义类型的枚举
    • Consts文件夹:定义NERtcCallKitErrors的头文件
    • Utils文件夹:生成信令唯一标识requestID(Demo业务层,可不关注)
    • Status文件夹
      • INERtcCallStatus.h:组件的接口
      • NERtcCallStatusIdleImpl.h:底层NERtc封装的实例方法
      • NERtcCallStatusCallingImpl.h:底层NERtc封装的实例方法
      • NERtcCallStatusCalledImpl.h:底层NERtc封装的实例方法
      • NERtcCallStatusInCallImpl.h:底层NERtc封装的实例方法

代码说明

初始化

// 在AppDelegate中初始化
- (void)setupRTCKit {
    // 读取配置的appkey信息
   NSString *appKey = <#您的AppKey#>

   // 配置 NERtcCallOptions
    NERtcCallOptions *option = [NERtcCallOptions new];
    option.APNSCerName = yourCerName;

   // 初始化 组件
    [[NERtcCallKit sharedInstance] setupAppKey:appKey options:option];
}

登录

组件与IM的login方法可共用,如果IM登录成功,组件无需再次调用login方法

// userID为云信的accid,token为云信的token
[[NERtcCallKit sharedInstance] login:userID token:token completion:^(NSError * _Nullable error) {

    //  根据登录回调处理业务

}];

Token注入

// 安全模式音视频房间token获取,nil表示非安全模式. Block中一定要调用complete

@property (nonatomic, copy, nullable) NERtcCallKitTokenHandler tokenHandler;

可参考在NTESAppDelegate.m的setupRTCKit方法中实现

// 注册获取token的服务
// 安全模式需要计算token,如果tokenHandler为nil表示非安全模式,需要联系经销商开通
 NERtcCallKit.sharedInstance.tokenHandler = ^(uint64_t uid, void (^complete)(NSString *token, NSError *error)) {

    // 下面获取token的逻辑建议替换成自己的,不建议从Demo服务器获取token
    [NTESRtcTokenUtils requestTokenWithUid:uid appKey:appKey completion:^(NSError * _Nullable error, NSString * _Nullable token) {

        complete(token, error);

    }];

 };

在线上环境中,token的获取需要放到您的应用服务端完成,然后由服务器通过安全通道把token传递给客户端。Demo中使用的URL仅仅是demoserver,请勿在您的应用中使用。详细请参考: 获取安全模式token

呼叫

Demo中在onTapMediaItemVideoChat初始化NECallViewController,并使用initWithOtherMember传入userID和当前通话类型,开发者可以根据业务需求实现该controller。

这是为了获取userID和通话类型。

// 组件封装的点对点呼叫方式
// self.otherUserID 为对方accid,type为NERtcCallType的枚举类型
[[NERtcCallKit sharedInstance] call:self.otherUserID type:self.type completion:^(NSError * _Nullable error) {
     //  根据登录回调处理业务

}];

多人呼叫

/// 多人呼叫
/// @param userIDs  呼叫的用户ID数组
/// @param type 通话类型
/// @param completion 回调

 [[NERtcCallKit sharedInstance] groupCall:self.otherMembers type:NERtcCallTypeVideo completion:^(NSError * _Nullable error) {
     //  根据登录回调处理业务

}];

监听

详情请参考组件中的NERtcCallKit.h

/// 收到邀请的回调
/// @param invitor 邀请方
/// @param userIDs 房间中的被邀请的所有人(不包含邀请者)
/// @param isFromGroup 是否是群组
/// @param groupID 群组ID
/// @param type 通话类型
- (void)onInvited:(NSString *)invitor
          userIDs:(NSArray<NSString *> *)userIDs
      isFromGroup:(BOOL)isFromGroup
          groupID:(nullable NSString *)groupID
             type:(NERtcCallType)type;


/// 接受邀请的回调
/// @param userID 接受者
- (void)onUserEnter:(NSString *)userID;


/// 拒绝邀请的回调
/// @param userID 拒绝者
- (void)onUserReject:(NSString *)userID;


/// 取消邀请的回调
/// @param userID 邀请方
- (void)onUserCancel:(NSString *)userID;


/// 用户离开的回调
/// @param userID 用户userID
- (void)onUserLeave:(NSString *)userID;


/// 用户异常离开的回调
/// @param userID 用户userID
- (void)onUserDisconnect:(NSString *)userID;


/// 用户接受邀请的回调
/// @param userID 用户userID
- (void)onUserAccept:(NSString *)userID;


/// 忙线
/// @param userID 忙线的用户ID
- (void)onUserBusy:(NSString *)userID;


/// 通话结束
- (void)onCallEnd;


/// 呼叫超时
- (void)onCallingTimeOut;


/// 连接断开
/// @param reason 断开原因
- (void)onDisconnect:(NSError *)reason;


/// 发生错误
- (void)onError:(NSError *)error;


/// 启用/禁用相机
/// @param available 是否可用
/// @param userID 用户ID
- (void)onCameraAvailable:(BOOL)available userID:(NSString *)userID;


/// 启用/紧用麦克风
/// @param available 是否可用
/// @param userID 用户userID
- (void)onAudioAvailable:(BOOL)available userID:(NSString *)userID;


/// 网络状态监测回调
/// @param stats key为用户ID, value为对应网络状态
- (void)onUserNetworkQuality:(NSDictionary<NSString *, NERtcNetworkQualityStats *> *)stats;


/// 呼叫请求已被其他端接收的回调
- (void)onOtherClientAccept;


/// 呼叫请求已被其他端拒绝的回调
- (void)onOtherClientReject;

接听

// 组件封装的接听方式
[[NERtcCallKit sharedInstance] accept:^(NSError * _Nullable error, NSArray<NSString *> * _Nullable joinedMembers) {
    //  根据登录回调处理业务
}];

挂断

// 组件封装的挂断方式
[[NERtcCallKit sharedInstance] hangup:^(NSError * _Nullable error) {
    // 根据挂断完成操作的回调处理
}];

话单

注:多人通话未封装话单,如有需要,请自行实现。

话单功能需单独开通,如有需要,请联系相应商务。

  1. 正常挂断,NIMRtcCallStatus状态为NIMRtcCallStatusComplete

调用组件封装的挂断后,服务器将下发正常结束的话单。

客户端通过客户端接收消息的回调函数 `onRecvMessages` 收到一条类型为 NIMMessageTypeRtcCallRecord 的消息,然后对消息进行解析并将其抛给上层进行展示,可以参考

    • NIMRtcCallRecordObject.h 文件,它保存当前的通话类型、频道ID、通话状态以及时长
    • NIMRtcCallRecordContentConfig.h 文件,用于对消息进行封装
    • NIMSessionRtcCallRecordContentView.h 文件,负责展示消息
  1. 非正常挂断

异常挂断时,需要业务层主动调用以下方法:组件话单提供给对方,包含 超时忙线拒绝 的话单都是组件内部发送的

// 取消通话
[[NERtcCallKit sharedInstance] cancel:^(NSError * _Nullable error) {
   // Do something
}];

底层实现主要调用 SDK 的 `sendMessage` 方法发送点对点消息,通过封装信息后发送到对方,对方收到消息后进行解析。可以参考 NERtcCallKit 中的 send1to1CallRecord 方法

UI相关

Demo中的UI可以参考以下模块:

路径为:NIMDemo -> Classes -> Sections -> Session -> ViewController -> RTCVideoChat