NERtcCallKit-iOS
为了方便开发者接入音视频2.0呼叫功能,以组件的形式提供给客户,提高接入效率。Demo 链接
功能开通
1. 登录
网易云控制台,点击【应用】>【创建】创建自己的 App,在【功能管理】中申请开通以下功能
-
如果仅使用呼叫功能,则需要开通
- 【信令】
- 【音视频通话2.0】
- 【非安全模式】-组件默认使用非安全模式,开启安全模式请联系 SO 咨询
-
如果还需要使用话单功能,则还需要开通
- 【IM】
- 【G2话单功能】-目前仅支持联系销售/SO 开通
- 发送邮件至 [email protected]
- 抄送[email protected]、[email protected]、[email protected]、[email protected]、[email protected]
- 邮件内容:appkey、功能名称:G2 话单消息通知
-
在控制台中【appkey 管理】获取 appkey。
注:如果曾经已有相应的应用,可在原应用上申请开通【音视频通话2.0】及【信令】功能
整体架构图
- 下载Demo解压,进入NIMDemo,点击NIM.xcworkspace进入工程
- 查找组件为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) {
// 根据挂断完成操作的回调处理
}];
话单
注:多人通话未封装话单,如有需要,请自行实现。
话单功能需单独开通,如有需要,请联系相应商务。
- 正常挂断,NIMRtcCallStatus状态为NIMRtcCallStatusComplete
调用组件封装的挂断后,服务器将下发正常结束的话单。
客户端通过客户端接收消息的回调函数 `onRecvMessages` 收到一条类型为 NIMMessageTypeRtcCallRecord 的消息,然后对消息进行解析并将其抛给上层进行展示,可以参考
-
- NIMRtcCallRecordObject.h 文件,它保存当前的通话类型、频道ID、通话状态以及时长
-
- NIMRtcCallRecordContentConfig.h 文件,用于对消息进行封装
-
- NIMSessionRtcCallRecordContentView.h 文件,负责展示消息
- 非正常挂断
异常挂断时,需要业务层主动调用以下方法:组件话单提供给对方,包含 超时、忙线、拒绝 的话单都是组件内部发送的
// 取消通话
[[NERtcCallKit sharedInstance] cancel:^(NSError * _Nullable error) {
// Do something
}];
底层实现主要调用 SDK 的 `sendMessage` 方法发送点对点消息,通过封装信息后发送到对方,对方收到消息后进行解析。可以参考 NERtcCallKit 中的 send1to1CallRecord 方法
UI相关
Demo中的UI可以参考以下模块:
路径为:NIMDemo -> Classes -> Sections -> Session -> ViewController -> RTCVideoChat