双人互动白板


通过阅读本章节,您将快速了解双人互动白板的相关功能,并且能通过本章节中介绍的流程和接口快速搭建一个双人互动白板会话。双人互动白板也称点对点互动白板,参与互动白板的共有两方,按照发起会话与接收会话区分为主叫与被叫角色。SDK提供点对点互动白板从发起会话建立会话会话互动解散会话整个过程的能力,包括呼叫/接收、发送白板数据、结束白板等基础能力接口与异常流程控制与回调。 考虑到白板使用场景与音频使用场景强关联,双人互动白板中包含语音通道(可选)更方便快捷满足简单白板的场景,需要注意的是语音通道全局只能有一个,并且与音视频通话和互动直播功能互斥。

双人互动白板主要流程如下:

sequenceDiagram participant 主叫 participant 被叫 主叫-->被叫:Step1:建立互动白板 主叫->>被叫:主叫发起互动白板请求(requestRTS) 被叫->>被叫:被叫收到互动白板请求回调(onRTSRequest) 被叫->>主叫:被叫响应互动白板请求(responseRTS) 主叫 ->>主叫:主叫收到被叫互动白板响应回调(onRTSResponse) 主叫-->被叫:Step2:互动白板过程 loop 互动白板 主叫 ->>主叫:互动白板状态反馈回调(onRTS) 被叫 ->>被叫:互动白板状态反馈回调(onRTS) 主叫->>被叫: 发送互动白板数据(sendRTSData) 被叫->>被叫:互动白板数据回调(onRTSReceive) 主叫->>被叫: [可选]发送互动白板控制指令(sendRTSControl) 被叫->>被叫: [可选]互动白板控制指令回调(onRTSControl) end 主叫-->被叫:Step3:结束互动白板 主叫->>被叫:结束互动白板(terminateRTS) 被叫->>主叫:对方结束互动白板回调(onRTSTerminate)

流程中涉及到的API介绍如下:

主叫发起互动白板请求

主叫通过该接口给被叫发起一通互动白板呼叫。


@protocol NIMRTSManager <NSObject>

/**
 *  主叫发起互动白板请求
 *
 *  @param callees 被叫帐号列表, 当前版本只支持一个被叫
 *  @param types  互动白板服务类型, NIMRTSService的组合, 如果要同时发起可靠传输通道和音频通话, 使用 NIMRTSServiceReliableTransfer | NIMRTSServiceAudio
 *  @param option 发起会话附带的选项, 可以是nil
 *  @param completion  发起互动白板结果回调
 *
 *  @return 发起的互动白板ID
 */
- (NSString *)requestRTS:(NSArray<NSString *> *)callees
                services:(NSUInteger)types
                  option:(nullable NIMRTSOption *)option
              completion:(nullable NIMRTSRequestHandler)completion;

@end

每一通发起请求都会返回会话 ID sessionID,用于后续操作和回调中唯一标识这通请求。

发起结果由 completion 返回,仅表示发起流程的结果,不表示被叫已经接受改请求。其原型为:

/**
 *  发起互动白板请求Block
 *
 *  @param error 发起结果, 如果成功 error 为 nil
 *  @param sessionID 发起的互动白板的 ID
 *  @param channelID 互动白板内部使用的通道号, 对应服务器白板时长消息抄送里的 channelId. 仅在 error 为 nil 时有效
 */
typedef void(^NIMRTSRequestHandler)(NSError * __nullable error,NSString * __nullable sessionID,UInt64 channelID);

API 接口参数:

参数 类型 说明
callees NSArray 被叫帐号列表, 现在只支持传入一个被叫
types NSUInteger 互动白板服务类型, NIMRTSService的组合, 如果要同时发起可靠传输通道和音频通话, 使用 `NIMRTSServiceReliableTransfer NIMRTSServiceAudio`
option NIMRTSOption 发起会话附带的选项, 可以是 nil
completion NIMRTSRequestHandler 发起互动白板结果回调

option 参数:

参数 类型 说明
extendMessage NSString 扩展消息。用于开发者在主被叫之间沟通额外信息
autoDeactivateAudioSession BOOL 结束语音服务时自动停止AudioSession, 默认为 YES。可以禁用自动停止,以用于某些情况下结束通话后希望应用继续播放之前被 SDK 打断的声音的场景
audioDenoise BOOL 语音降噪, 默认为 YES。可以改善嘈杂环境下的通话体验。如果不需要该功能可以关闭
voiceDetect BOOL 人声检测, 默认为 YES。可以降低安静环境下的语音数据流量。如果不需要该功能可以关闭
audioHowlingSuppress BOOL 啸叫抑制, 默认为 NO
preferHDAudio BOOL 期望发送高清语音, 只有在通话的所有的参与者都设置为高清语音时才生效。高清语音提高了语音采样率,提供更高的听觉体验。开启该选项后蓝牙耳机将不能使用
scene NIMAVChatScene 可以在高清语音 preferHDAudio 开启时设置高清音乐场景,针对含音乐的使用环境做优化,并自动关闭语音降噪和人声检测
serverRecordAudio BOOL 服务器录制语音。可以在开启了服务器录制功能的 APP 中用禁用这通互动白板的录制功能
serverRecordData BOOL 服务器录制互动白板数据
alwaysKeepCalling BOOL 始终持续呼叫, 用于设置被叫离线时是否仍然需要持续呼叫, 默认为 YES
webrtcCompatible BOOL 语音通道兼容 webrtc
apnsInuse BOOL 互动白板请求是否附带推送,默认为YES。将这个字段设为NO,互动白板请求将不再有苹果推送通知
apnsBadge BOOL 推送是否需要角标计数,默认为YES。将这个字段设为NO,互动白板请求将不再对角标计数
apnsWithPrefix BOOL 推送是否需要带前缀xx: (xx 一般为昵称),默认为YES。将这个字段设为NO,推送消息将不带有前缀
apnsContent NSString apns推送文案。将这个字段设为 nil,互动白板请求将不再有苹果推送通知
apnsSound NSString apns推送声音文件,默认为nil。用户可以设置当前通知的推送声音。该设置会覆盖apnsPayload中的sound设置
apnsPayload NSDictionary apns推送Payload。可以通过这个字段定义自定义通知的推送Payload,支持字段参考苹果技术文档,最多支持2K

NIMRTSRequestHandler 的参数:

参数 类型 说明
error NSError 发起结果。如果成功 error 为 nil
sessionID NSString 发起的互动白板的 ID
channelID UInt64 互动白板内部使用的通道号, 对应服务器白板时长消息抄送里的 channelId. 仅在 error 为 nil 时有效
    NIMRTSOption *option = [[NIMRTSOption alloc] init];
    option.extendMessage = @"ext msg example";

    NSString *theSessionID = [[NIMAVChatSDK sharedSDK].rtsManager requestRTS:@[@"callee_accid"]
                                                                    services:NIMRTSServiceAudio | NIMRTSServiceReliableTransfer
                                                                      option:[[NIMRTSOption alloc] init]
                                                                  completion::^(NSError *error, NSString *sessionID, UInt64 channelID)
    {
        if (error && (sessionID == theSessionID)) {
            //error handling
        }
    }];
}

SDK 没有呼叫超时时间,开发者可根据自己的业务场景通过定时器设置呼叫超时时间,在被叫超时未接听时调用 结束互动白板 接口挂断该呼叫。

被叫收到互动白板请求回调

主叫发起呼叫后,被叫会收到该回调通知。

需要先注册 delegate 以接收互动白板回调。请确保注册了 delegete 的对象不被释放,以便随时接收互动白板请求并唤起接听界面。示例代码:

[[NIMAVChatSDK sharedSDK].rtsManager addDelegate:self];
@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  被叫收到互动白板请求
 *
 *  @param sessionID 互动白板ID
 *  @param caller 主叫帐号
 *  @param types 服务类型, NIMRTSService的组合
 *  @param extendMessage 附加信息
 */
- (void)onRTSRequest:(NSString *)sessionID
                from:(NSString *)caller
            services:(NSUInteger)types
             message:(nullable NSString *)extendMessage;

@end

API 接口参数:

参数 类型 说明
sessionID NSString 互动白板ID。用户每收到一个互动白板请求都由唯一的 sessionID 标识,用于后续操作和回调中指定这通请求
caller NSString 主叫的帐号 ID
types NSUInteger 互动白板服务类型。主叫呼叫被叫时请求的服务类型组合通过该参数告知被叫
extendMessage NSString 附加信息。主叫呼叫被叫时在 option 中填入的 extendMessage 通过该参数告知被叫
- (void)onRTSRequest:(NSString *)sessionID
                from:(NSString *)caller
            services:(NSUInteger)types
             message:(nullable NSString *)extendMessage
{
    NTESWhiteboardViewController *vc = [[NTESWhiteboardViewController alloc] initWithSessionID:sessionID
                                                                                        peerID:caller
                                                                                         types:types
                                                                                          info:extendMessage];
    [self presentModelViewController:vc];

}

被叫响应互动白板请求

被叫收到互动白板请求回调后,通过该接口响应该请求,主叫会收到该响应对应的通知。

@protocol NIMRTSManager <NSObject>

/**
 *  被叫响应互动白板请求
 *
 *  @param sessionID 互动白板ID
 *  @param accept  是否接听
 *  @param option  接收会话附带的选项, 可以是nil
 *  @param completion  响应呼叫结果回调
 *
 */
- (void)responseRTS:(NSString *)sessionID
             accept:(BOOL)accept
             option:(nullable NIMRTSOption *)option
         completion:(nullable NIMRTSResponseHandler)completion;

@end

响应结果由 completion 返回,仅表示响应流程的结果,不表示互动白板呼叫已经建立连接。其原型为

/**
 *  响应互动白板请求Block
 *
 *  @param error  响应互动白板请求, 如果成功 error 为 nil
 *  @param sessionID 响应的互动白板的 ID
 *  @param channelID 互动白板内部使用的通道号, 对应服务器白板时长消息抄送里的 channelId. 仅在 error 为 nil 时有效
 */
typedef void(^NIMRTSResponseHandler)(NSError * __nullable error,NSString * __nullable sessionID,UInt64 channelID);

API 接口参数:

参数 类型 说明
sessionID NSString 互动白板ID。传入 被叫收到互动白板请求回调 中的 sessionID 以响应该请求
accept BOOL 是否接听。如果有正在进行的网络通话或者互动白板,可以传入 NO 以拒绝该请求。
option NIMRTSOption 接受会话附带的选项。只有 accept 为 YES时有效,只有部分参数对被叫有效
completion NIMRTSResponseHandler 响应呼叫结果回调

option 中对被叫有效的参数:

参数 类型 说明
autoDeactivateAudioSession BOOL 结束语音服务时自动停止AudioSession, 默认为 YES。可以禁用自动停止,以用于某些情况下结束通话后希望应用继续播放之前被 SDK 打断的声音的场景
audioDenoise BOOL 语音降噪, 默认为 YES。可以改善嘈杂环境下的通话体验。如果不需要该功能可以关闭
voiceDetect BOOL 人声检测, 默认为 YES。可以降低安静环境下的语音数据流量。如果不需要该功能可以关闭
audioHowlingSuppress BOOL 啸叫抑制, 默认为 NO
preferHDAudio BOOL 期望发送高清语音, 只有在通话的所有的参与者都设置为高清语音时才生效。高清语音提高了语音采样率,提供更高的听觉体验。开启该选项后蓝牙耳机将不能使用
scene NIMAVChatScene 可以在高清语音 preferHDAudio 开启时设置高清音乐场景,针对含音乐的使用环境做优化,并自动关闭语音降噪和人声检测
serverRecordAudio BOOL 服务器录制语音。可以在开启了服务器录制功能的 APP 中用禁用这通互动白板的录制功能
serverRecordData BOOL 服务器录制互动白板数据
webrtcCompatible BOOL 语音通道兼容 webrtc

NIMRTSResponseHandler 的参数:

参数 类型 说明
error NSError 响应结果。如果成功 error 为 nil
sessionID NSString 响应结果对应的互动白板的 ID
channelID UInt64 响应结果对应的互动白板内部使用的通道号, 对应服务器白板时长消息抄送里的 channelId。仅在 error 为 nil 时有效

收到互动白板请求后马上接受该请求的简单示例代码:

- (void)onRTSRequest:(NSString *)sessionID
                from:(NSString *)caller
            services:(NSUInteger)types
             message:(nullable NSString *)extendMessage
{
    NIMRTSOption *option = [[NIMRTSOption alloc] init];
    [[NIMAVChatSDK sharedSDK].rtsManager responseRTS:sessionID accept:YES
                                              option:option
                                          completion:^(NSError * _Nullable error, NSString * _Nullable sessionID, UInt64 channelID)
    {
        if (error) {
            //error handling
        }
    }];
}

主叫收到被叫互动白板响应回调

被叫响应一个互动白板请求后,主叫会收到该回调通知。

需要先注册 delegate 以接收互动白板回调。示例代码:

[[NIMAVChatSDK sharedSDK].rtsManager addDelegate:self];
@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  主叫收到被叫互动白板响应
 *
 *  @param sessionID 互动白板ID
 *  @param callee 被叫帐号
 *  @param accepted 是否接听
 *
 *  @discussion 被叫拒绝接听时, 主叫不需要再调用termimateRTS:接口
 */
- (void)onRTSResponse:(NSString *)sessionID
                 from:(NSString *)callee
             accepted:(BOOL)accepted;             
@end

API 接口参数:

参数 类型 说明
sessionID NSString 互动白板 ID
callee NSString 被叫的帐号 ID
accepted BOOL 是否受该互动白板。接受后 SDK 讲开始互动白板的连接建立
- (void)onRTSResponse:(NSString *)sessionID
                 from:(NSString *)callee
             accepted:(BOOL)accepted
{
    if (!accepted) {
        [self makeToast:@"对方拒绝了本次请求"];
        [self dismiss];
    }
    else {
        [self switchToWaitingConnectView];
        [_callerWaitingTimer stopTimer];
    }
}

互动白板状态反馈回调

被叫接受互动白板呼叫后,会话双方的 SDK 会主动建立互动白板通道,建立的结果通过该回调通知两端。

@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  互动白板状态反馈
 *
 *  @param sessionID 互动白板ID
 *  @param type 互动白板服务类型
 *  @param status 通话状态, 收到NIMRTSStatusDisconnect时无需调用terminate:结束该会话
 *  @param error 出错信息, 正常连接和断开时为nil
 */
- (void)onRTS:(NSString *)sessionID
      service:(NIMRTSService)type
       status:(NIMRTSStatus)status
        error:(nullable NSError *)error;

@end

API 接口参数:

参数 类型 说明
sessionID NSString 互动白板 ID
type NIMRTSService 互动白板服务类型。数据传输和实时语音通道的建立结果会分别反馈,应用层可以通过该字段判断是哪个通道的状态反馈
status NIMRTSStatus 状态。有 已连接已断开 两种状态
error NSError 出错信息, 正常连接和断开时为 nil。如果断开时携带错误码,说明是非正常断开,可以通过code字段获取错误信息

- (void)onRTS:(NSString *)sessionID
      service:(NIMRTSService)type
       status:(NIMRTSStatus)status
        error:(NSError *)error
{
    if (type == NIMRTSServiceReliableTransfer) {
        if (status == NIMRTSStatusConnect) {
            [self switchToConnectedView];
        }
        else {
             NSLog(@"已断开数据传输: %zd", error.code);
            [self termimateRTS];
        }
    }
    else if (type == NIMRTSServiceAudio) {
        _audioConnected = (status == NIMRTSStatusConnect) ? YES : NO;
        if (!_audioConnected) {
            NSLog(@"已断开音频服务: %zd", error.code);
        }
    }
}

SDK 没有呼叫超时时间,开发者可根据自己的业务场景通过定时器设置呼叫超时时间,在被叫超时未接听时调用 结束互动白板 接口挂断该呼叫。

发送互动白板数据

互动白板通道建立后,应用可以通过该接口发送自定义的数据给对方。


@protocol NIMRTSManager <NSObject>

/**
 *  从指定通道发送数据
 *
 *  @param data 需要发送的互动白板数据, 数据长度不允许超过50KB, 推荐不超过4KB; 发送数据的周期建议控制在50ms以上
 *  @param sessionID 互动白板ID
 *  @param userID 发送数据目标用户名, nil表示广播给所有用户
 *  @param service 互动白板服务类型
 *
 *  @return 是否允许发送
 *
 *  @discussion 被叫在响应请求之前不要调用挂断接口
 */
- (BOOL)sendRTSData:(NSData *)data
               from:(NSString *)sessionID
                 to:(NSString *)userID
               with:(NIMRTSService)service;

@end
参数 类型 说明
data NSData 需要发送的互动白板数据, 数据长度不允许超过50 KB, 推荐不超过4 KB; 发送数据的周期建议控制在50ms以上, 否则可能引起延迟增大等问题
sessionID NSString 互动白板 ID
userID NSString 发送数据目标用户名, 也可以不指定
service NIMRTSService 互动白板服务类型,现在只允许通过数据传输通道 NIMRTSServiceReliableTransfer 发送数据

- (void)sendRTSData:(NSString *)data
{
    BOOL success = [[NIMAVChatSDK sharedSDK].rtsManager sendRTSData:[data dataUsingEncoding:NSUTF8StringEncoding]
                                                        from:_sessionID
                                                           to:_peerUserID
                                                        with:NIMRTSServiceReliableTransfer];
    if (!success) {
        [self.view.window makeToast:@"数据发送失败" duration:1 position:CSToastPositionBottom];
    }
}

收到互动白板数据回调

一方调用发送互动白板数据后,对方通过该回调接收数据。

@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  收到互动白板数据
 *
 *  @param sessionID 互动白板ID
 *  @param data 收到的互动白板数据
 *  @param user 发送互动白板数据的用户
 *  @param channel 收发实时数据的服务通道
 */
- (void)onRTSReceive:(NSString *)sessionID
                data:(NSData *)data
                from:(NSString *)user
              withIn:(NIMRTSService)channel;

@end
参数 类型 说明
sessionID NSString 互动白板 ID
data NSData 收到的互动白板数据
user NSString 发送互动白板数据的用户
channel NIMRTSService 收发实时数据的服务通道
- (void)onRTSReceive:(NSString *)sessionID
                data:(NSData *)data
                from:(NSString *)user
              withIn:(NIMRTSService)channel
{
    NSString *cmdString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    //handle the cmd string
}

发送互动白板控制指令

互动白板控制指令用于方便双方沟通信息,可以选择性使用。该指令通道使用云信 IM 消息通道,而不是互动白板数据通道。

@protocol NIMRTSManager <NSObject>

/**
 *  发送互动白板控制指令
 *
 *  @param controlInfo 控制信息, 自定义实现
 *  @param sessionID   互动白板ID
 */
- (void)sendRTSControl:(NSString *)controlInfo
            forSession:(NSString *)sessionID;

@end
参数 类型 说明
controlInfo NSString 控制信息, 自定义实现
sessionID NSString 互动白板 ID
- (IBAction)onMuteButtonPressed:(id)sender {
    _mute = !_mute;
    [[NIMAVChatSDK sharedSDK].rtsManager setMute:_mute];
    [[NIMAVChatSDK sharedSDK].rtsManager sendRTSControl:_mute ? @"关闭了声音" : @"打开了声音" forSession:_sessionID];
}

收到互动白板控制指令回调

互动白板一方发送控制指令后,另一方通过该回调接受指令。

@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  收到互动白板控制信息
 *
 *  @param controlInfo 控制信息
 *  @param user 发送指令的用户
 *  @param sessionID   互动白板ID
 */
- (void)onRTSControl:(NSString *)controlInfo
                from:(NSString *)user
          forSession:(NSString *)sessionID;

@end
参数 类型 说明
controlInfo NSString 控制信息
user NSString 发送指令的用户
sessionID NSString 互动白板 ID
- (void)onRTSControl:(NSString *)controlInfo
                from:(NSString *)user
          forSession:(NSString *)sessionID
{
    if (sessionID == _sessionID) {
        [self.view.window makeToast:[NSString stringWithFormat:@"%@: %@", user, controlInfo]
                           duration:2
                           position:CSToastPositionBottom];
    }
}

设置静音

如果该互动白板开启了音频通话服务,通过该接口控制音频的静音开关。

@protocol NIMRTSManager <NSObject>

/**
 *  设置当前互动白板静音模式
 *
 *  @param mute 是否开启静音
 *
 */
- (void)setMute:(BOOL)mute;

@end
参数 类型 说明
mute BOOL 是否开启静音
- (IBAction)onMuteButtonPressed:(id)sender {
    _mute = !_mute;
    [[NIMAVChatSDK sharedSDK].rtsManager setMute:_mute];
}

设置扬声器

如果该互动白板开启了音频通话服务,通过该接口控制控制音频的扬声器开关。

@protocol NIMRTSManager <NSObject>

/**
 *  设置当前互动白板扬声器模式
 *
 *  @param useSpeaker 是否开启扬声器
 *
 */
- (void)setSpeaker:(BOOL)useSpeaker;

@end
参数 类型 说明
useSpeaker BOOL 是否开启扬声器
- (IBAction)onSpeakerButtonPressed:(id)sender {
    _useSpeaker = ! _useSpeaker;
    [[NIMAVChatSDK sharedSDK].rtsManager setSpeaker: _useSpeaker];
}

结束互动白板

通话建立以后,可以通过该接口结束这通互动白板。

@protocol NIMRTSManager <NSObject>

/**
 *  挂断互动白板
 *
 *  @param sessionID 需要挂断的互动白板ID
 *
 *  @discussion 被叫在响应请求之前不要调用挂断接口
 */
- (void)terminateRTS:(NSString *)sessionID;

@end
参数 类型 说明
sessionID NSString 需要结束的互动白板 ID
[[NIMAVChatSDK sharedSDK].rtsManager terminateRTS:_sessionID];

对方结束互动白板回调

一方调用结束互动白板接口以后,互动白板的对端会收到该回调。

@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  对方结束互动白板
 *
 *  @param sessionID 互动白板ID
 *  @param user   对方帐号
 */
- (void)onRTSTerminate:(NSString *)sessionID
                    by:(NSString *)user;

@end
参数 类型 说明
sessionID NSString 对方结束的互动白板 ID
user NSString 对方帐号
- (void)onRTSTerminate:(NSString *)sessionID
                    by:(NSString *)user
{
    if (sessionID == _sessionID) {
        [self makeToast:@"对方已离开"];
        [self termimateRTS];
        [self dismiss];
    }
}

呼入的互动白板请求已经被该帐号其他端处理回调

在多端登录的场景中,主叫呼叫被叫,如果被叫多个端同时在线,这些端都会收到呼叫请求。其中一个端响应了呼叫以后,其他会收到该回调,表示这通呼叫已经在其他端被处理了。

@protocol NIMRTSManagerDelegate <NSObject>

/**
 *  这通呼入的互动白板请求已经被该帐号其他端处理
 *
 *  @param sessionID 互动白板ID
 *  @param accepted 是否被接听
 */
- (void)onRTSResponsedByOther:(NSString *)sessionID
                     accepted:(BOOL)accepted;

@end
参数 类型 说明
sessionID NSString 被其他端处理了的互动白板 ID
accepted BOOL 在其他端是否被接听
- (void)onRTSResponsedByOther:(NSString *)sessionID
                     accepted:(BOOL)accepted
{
    if (sessionID == _sessionID) {
        [self makeToast:@"呼叫已被其他端处理"];
        [self dismiss];
    }
}