双人互动白板

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

sequenceDiagram participant 主叫 participant 被叫 主叫-->被叫:Step1:建立实时会话 主叫->>被叫:主叫发起实时会话请求(start) 被叫->>被叫:被叫收到实时会话请求回调(observeIncomingSession) 被叫->>主叫:被叫响应实时会话请求(接受accept/拒绝close) 主叫 ->>主叫:主叫收到被叫实时会话响应回调(observeCalleeAckNotification) 主叫-->被叫:Step2:实时会话过程 loop 实时会话 主叫->>被叫: 发送实时会话数据(sendData) 被叫->>主叫:实时会话数据回调(observeReceiveData) 主叫-->>被叫: [可选]发送实时会话控制指令(sendControlCommand) 被叫-->>主叫: [可选]发送实时会话控制指令(sendControlCommand) 被叫->>主叫:实时会话状态反馈回调(observeCalleeAckNotification) end 主叫-->被叫:Step3:结束实时会话 主叫->>被叫:结束实时会话(close) 被叫->>主叫:对方结束实时会话回调(observeHangUpNotification)

下面介绍流程中涉及到的功能点,包含API介绍、API原型、参数说明、示例,若有特殊说明会在最后添加。

主叫发起互动白板请求

目前我们提供两种数据通道:DATA 通道和 Audio 通道。通道类型见 RTSTunnelType,可选参数见 RTSOptions(包含推送内容、发起方附带给其他参与者的内容、是否录制通道数据等) 一个会话可以同时创建多个通道,但全局只能有一个语音通道。发起会话时,RTSNotifyOption 中可进行iOS端推送通知自定义配置,同时也包含一个可自定的扩展字段。

    /**
     * (发送方)发起会话, 调用此接口对方会收到相应的会话请求通知
     *
     * @param account      对方帐号
     * @param tunTypes     通道类型集合:AUDIO、DATA
     * @param options      可选参数: 是否录制通道数据
     * @param notifyOption 可选参数: 推送相关参数控制
     * @param callback     回调函数,返回RTSData
     * @return Session ID,若返回null,表示发起失败,注意:音频通道同时只能有一个会话开启。
     * 回调onFailed错误码:
     * 200:成功
     * 414:参数错误
     * 509:通道失效
     * 11001:无可送达的被叫方,主叫方可直接挂断
     * 501:数据库失败
     * 514:服务不可用
     */
    public abstract String start(String account, List<RTSTunnelType> tunTypes, RTSOptions options, RTSNotifyOption notifyOption, RTSCallback<RTSData> callback);
参数 说明
account 对方帐号。
tunTypes 通道类型集合:AUDIO、DATA,参考RTSTunnelType
options 是否录制通道数据,参考RTSOptions
notifyOption 推送相关参数控制,参考RTSNotifyOption
callback 回调函数,返回RTSData,参考RTSCallback
List<RTSTunnelType> types = new ArrayList<>(1);
types.add(RTSTunnelType.AUDIO);
types.add(RTSTunnelType.DATA);

String pushContent = account + "发起一个会话";
String extra = "extra_data";
RTSOptions options = new RTSOptions().setRecordAudioTun(true).setRecordTCPTun(true);
RTSNotifyOption notifyOption = new RTSNotifyOption();

sessionId = RTSManager.getInstance().start(account, types, options, notifyOption, new RTSCallback<RTSData>() { ... });
if (sessionId == null) {
    // 发起会话失败,音频通道同时只能有一个会话开启
    onFinish();
}

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

一般是在 APP 启动时监听会话(新通道)请求,例如在 Application 的 onCreate 里添加。当监听到新通道请求时,会返回基本信息 RTSData,其中包括通道类型列表、发起方帐号。

    /**
     * 注册/注销监听收到的会话请求
     * 建议在APP启动时就添加此监听
     *
     * @param observer 观察者,参数为会话的信息
     * @param register true为注册,false为注销
     */
    public abstract void observeIncomingSession(Observer<RTSData> observer, boolean register);
参数 说明
observer 观察者,参数为会话的信息。RTSData参考RTSData
register true为注册,false为注销。
private void registerRTSIncomingCallObserver(boolean register) {
    RTSManager.getInstance().observeIncomingSession(new Observer<RTSData>() {
        @Override
        public void onEvent(RTSData rtsData) {
            // 启动会话界面
        }
    },register);
}

被叫响应互动白板请求

被叫接听互动白板请求

当监听到会话请求后,被叫方可以选择接受或者拒绝,可以传入可选参数:是否录制通道数据。当选择接受时,SDK 会自动开启相关的通道,建立与对方的连接。

    /**
     * (接收方)接受会话
     *
     * @param sessionId 会话ID
     * @param options   可选参数:是否录制通道数据
     * @param callback  回调函数,返回本地通道初始化是否成功
     * @return 是否成功调用,若返回false,表示接受失败,注意:音频通道同时只能有一个会话开启。
     * 回调onFailed错误码:
     * -1:接受失败,本地正在使用语音通道。
     */
    public abstract boolean accept(String sessionId, RTSOptions options, RTSCallback<Boolean> callback);
参数 说明
sessionId 会话ID。
options 可选参数:是否录制通道数据,参考RTSOptions
callback 回调函数,返回本地通道初始化是否成功,参考RTSCallback
RTSOptions options = new RTSOptions().setRecordAudioTun(true).setRecordTCPTun(true);
RTSManager.getInstance().accept(sessionId, options, new RTSCallback<Boolean>() { ... });

被叫拒绝互动白板请求

接受方拒绝会话或者结束会话。

    /**
     * (接受方)拒绝会话或者结束会话
     *
     * @param sessionId 会话ID
     * @param callback  回调函数
     * @return 是否成功调用
     */
    public abstract boolean close(String sessionId, RTSCallback<Void> callback);
参数 说明
sessionId 会话ID。
callback 回调函数,参考RTSCallback
RTSManager.getInstance().close(sessionId, new RTSCallback<Void>() { ... });

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

主叫方在发起会话成功后需要监听被叫方的回应,监听接口 observeCalleeAckNotification,回调返回 RTSCalleeAckEvent,其中包含被叫方的回应结果:

对方同意,此时 SDK 会自动开启相应的通道,建立通道连接。 对方拒绝,结束会话。

    /**
     * 注册/注销发起会话后,被叫方的响应(接听、拒绝、忙)
     *
     * @param sessionId 会话ID
     * @param observer  观察者, 参数为被叫方的响应
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeCalleeAckNotification(String sessionId, Observer<RTSCalleeAckEvent> observer, boolean register);
参数 说明
sessionId 会话ID。
observer 观察者, 参数为被叫方的响应,参考RTSCalleeAckEvent
register true为注册,false为注销。
RTSManager.getInstance().observeCalleeAckNotification(sessionId, calleeAckEventObserver, register);
private Observer<RTSCalleeAckEvent> calleeAckEventObserver = new Observer<RTSCalleeAckEvent>() {
    @Override
    public void onEvent(RTSCalleeAckEvent rtsCalleeAckEvent) {
        if (rtsCalleeAckEvent.getEvent() == RTSEventType.CALLEE_ACK_AGREE) {
            // 判断SDK自动开启通道是否成功
            if (!rtsCalleeAckEvent.isTunReady()) {
                return;
            }
            // 进入会话界面
        } else if (rtsCalleeAckEvent.getEvent() == RTSEventType.CALLEE_ACK_REJECT) {
            // 被拒绝,结束会话
        }
    }
};

监听互动白板数据通道状态

发起会话(对方接受后),或者接受了会话请求后,需要立即注册对数据通道状态的监听。

    /**
     * 注册/注销通道状态变化的通知
     *
     * @param sessionId 会话ID
     * @param observer  观察者,参数为通话会话(通道)状态回调(例如是否连接上服务器,通道是否有成员加入等)
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeChannelState(String sessionId, RTSChannelStateObserver observer, boolean register);
参数 说明
sessionId 会话ID。
observer 观察者,参数为通话会话(通道)状态回调(例如是否连接上服务器,通道是否有成员加入等)。
register true为注册,false为注销。
RTSManager.getInstance().observeChannelState(sessionId, channelStateObserver, register);

RTSChannelStateObserver channelStateObserver = new RTSChannelStateObserver() {

    @Override
    public void onConnectResult(String localSessionId, RTSTunnelType tunType, long channelId, int code, String recordFile) {
        // 与服务器连接结果通知,成功返回 200, 同时返回服务器录制文件的地址
    }

    @Override
    public void onChannelEstablished(String localSessionId, RTSTunnelType tunType) {
        // 双方通道连接建立(对方用户已加入)
    }

    @Override
    public void onUserJoin(String localSessionId, RTSTunnelType tunType, String account) {
        // 用户加入
    }

    @Override
    public void onUserLeave(String localSessionId, RTSTunnelType tunType, String account, int event) {
        // 用户离开
    }

    @Override
    public void onDisconnectServer(String localSessionId, RTSTunnelType tunType) {
        // 与服务器断开连接
    }

    @Override
    public void onError(String localSessionId, RTSTunnelType tunType, int error) {
        // 通道发生错误
    }

    @Override
    public void onNetworkStatusChange(String localSessionId, RTSTunnelType channelType, int value) {
        // 网络信号强弱
    }
};

发送互动白板数据

数据通道建立之后就可以进行数据的收发。发送数据,需要构造 RTSTunData, 需要指定会话 ID,通道类型,对方帐号,数据(字节数组)及数据的长度。如果需要发送数据到所有用户,对方帐号填 null。

    /**
     * 向指定会话的某个通道中的某个用户发送数据,也可以广播给所有用户(在RTSTunData中,对方帐号填null)
     *
     * @param data 要发送的数据信息,其中toAccount表示目标用户(填null,表示广播给所有用户)
     * @return 参数是否有效
     */
    public abstract boolean sendData(RTSTunData data);
参数 说明
data 要发送的数据信息,参考RTSTunData
RTSTunData channelData = new RTSTunData(sessionId, RTSTunnelType.DATA, toAccount, data.getBytes("UTF-8"), data.getBytes().length);
RTSManager.getInstance().sendData(channelData);

收到互动白板数据回调

数据通道建立完之后,就可以监听对方发送来的数据。

    /**
     * 注册/注销对方从某个通道发来的数据
     *
     * @param sessionId 会话ID
     * @param observer  观察者,参数为收到的数据信息
     * @param register  true为注册,false为注销
     */
    public abstract boolean observeReceiveData(String sessionId, Observer<RTSTunData> observer, boolean register);
参数 说明
sessionId 会话ID。
observer 观察者,参数为收到的数据信息,参考RTSTunData
register true为注册,false为注销。
RTSManager.getInstance().observeReceiveData(sessionId, receiveDataObserver, register);
Observer<RTSTunData> receiveDataObserver = new Observer<RTSTunData>() {
    @Override
    public void onEvent(RTSTunData rtsTunData) {
        String data = "[parse bytes error]";
        try {
            data = new String(rtsTunData.getData(), 0, rtsTunData.getLength(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        TransactionCenter.getInstance().onReceive(sessionId, data);
    }
};

发送互动白板控制指令

双方会话建立之后,就可以相互发送控制信息了。

    /**
     * 发送控制指令
     *
     * @param sessionId 会话ID
     * @param data      控制指令内容
     * @param callback  回调函数
     * @return 是否调用成功
     */
    public abstract boolean sendControlCommand(String sessionId, String data, RTSCallback<Void> callback);
参数 说明
sessionId 会话ID。
data 控制指令内容。
callback 回调函数,参考RTSCallback
RTSManager.getInstance().sendControlCommand(sessionId, content, new RTSCallback<Void>() { ... });

监听互动白板控制回调

双方会话建立之后,需要监听会话控制通知。

    /**
     * 注册/注销会话控制消息
     *
     * @param sessionId 会话ID
     * @param observer  观察者, 参数为接收到的会话控制消息
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeControlNotification(String sessionId, Observer<RTSControlEvent> observer, boolean register);
参数 说明
sessionId 会话ID。
observer 观察者, 参数为接收到的会话控制消息,参考RTSControlEvent
register true为注册,false为注销。
RTSManager.getInstance().observeControlNotification(sessionId, controlObserver, register);

Observer<RTSControlEvent> controlObserver = new Observer<RTSControlEvent>() {
    @Override
    public void onEvent(RTSControlEvent rtsControlEvent) {
        // your code
    }
};

结束互动白板

发起结束通话的一方,调用 close 接口。另外一方,需要注册 observeHangUpNotification 监听挂断通知,收到通知后,做相应处理,代码示例见对方结束实时会话回调(主叫方、被叫方)

    /**
     * (接受方)拒绝会话或者结束会话
     *
     * @param sessionId 会话ID
     * @param callback  回调函数
     * @return 是否成功调用
     */
    public abstract boolean close(String sessionId, RTSCallback<Void> callback);
参数 说明
sessionId 会话ID。
callback 回调函数,参考RTSCallback
RTSManager.getInstance().close(sessionId, new RTSCallback<Void>() { ... });

对方结束互动白板回调

当被叫方收到会话请求时需要监听主叫方结束会话的通知;当双方会话建立之后,需要监听对方结束会话的通知。

    /**
     * 注册/注销会话对方挂断的通知
     *
     * @param sessionId 会话ID
     * @param observer  观察者, 参数为对方挂断信息
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeHangUpNotification(String sessionId, Observer<RTSCommonEvent> observer, boolean register);
参数 说明
sessionId 会话ID。
observer 观察者, 参数为对方挂断信息,参考RTSCommonEvent
register true为注册,false为注销。
RTSManager.getInstance().observeHangUpNotification(sessionId, endSessionObserver, register);
private Observer<RTSCommonEvent> endSessionObserver = new Observer<RTSCommonEvent>() {
    @Override
    public void onEvent(RTSCommonEvent rtsCommonEvent) {
        // 结束会话
    }
};

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

如果自己的帐号有其他端在线(例如 PC 端),其他端做了回应(接受或者拒绝),那么移动端会收到一条通知。因此,移动端在收到会话请求后需要监听 PC 端对发起方的响应。

    /**
     * 注册/注销同时在线的其他端对主叫方的响应
     *
     * @param sessionId 会话ID
     * @param observer  观察者,参数为同时在线的其他端响应主叫方的同步通知
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeOnlineAckNotification(String sessionId, Observer<RTSOnlineAckEvent> observer, boolean register);
参数 说明
sessionId 会话ID。
observer true为注册,false为注销。参考RTSOnlineAckEvent
register 是否成功调用。
RTSManager.getInstance().observeOnlineAckNotification(sessionId, onlineAckObserver, register);
Observer<RTSOnlineAckEvent> onlineAckObserver = new Observer<RTSOnlineAckEvent>() {
    @Override
    public void onEvent(RTSOnlineAckEvent rtsOnlineAckEvent) {
        if (rtsOnlineAckEvent.getClientType() != ClientType.Android) {
            String client = null;
            switch (rtsOnlineAckEvent.getClientType()) {
                case ClientType.Web:
                    client = "Web";
                    break;
                case ClientType.Windows:
                    client = "Windows";
                    break;
                default:
                    break;
            }
            // your code
            onFinish();
        }
    };

发起或者接听对方新通道超时回调

主叫方在(发起会话)创建通道时,超过 40 秒被叫方还未接受,则自动挂断。被叫方超过 40 秒接受会话,也会自动挂断。

    /**
     * 注册/注销到来的会话或者自己发起的会话(自己或者对方无响应)超时的通知,默认超时时间为40秒
     *
     * @param sessionId 会话ID
     * @param observer  观察者,参数为超时事件详细信息
     * @param register  true为注册,false为注销
     * @return 是否成功调用
     */
    public abstract boolean observeTimeoutNotification(String sessionId, Observer<RTSTimeOutEvent> observer, boolean  register);
参数 说明
sessionId 会话ID。
observer 观察者,参数为超时事件详细信息。参考RTSTimeOutEvent
register true为注册,false为注销。
Observer<RTSTimeOutEvent> timeoutObserver = new Observer<RTSTimeOutEvent>() {
    @Override
    public void onEvent(RTSTimeOutEvent rtsTimeOutEvent) {
        // 超时,结束会话
    }
};