通信集成指南—— Android

简介

本文档主要介绍使用 JusTalk Cloud SDK for Android(以下简称 SDK)实现基本的音频或视频通信功能的调用逻辑。请根据需要集成其他扩展功能。
本文涉及的接口类和对象有:

房间对象

房间对象包括房间信息、状态和参与成员信息。

房间

房间是通信的基础,当第一个成员进入房间时,自动创建。最后一个成员离开时,自动销毁。

成员

成员分为参与者和观察者。

  • 参与者:即可以参与交互的成员。一个房间中参与者人数可以多达16人。
  • 观察者:即仅能观看的普通成员。一个房间的观察者人数可以多达500名。参与者和观察者可以互相转化,但参与者最多不超过 16 人。

交互说明

SDK 封装了来自服务器的通知和异步执行的用户操作结果通知,开发者在初始化 SDK 时设置 JCEngineEventHandler,SDK 会通过触发 JCEngineEventHandler 回调来通知事件。

eventHandler = new MyEventHandler();

mJCEngine = JCEngine.create(context.getApplicationContext(), MY_APP_KEY, eventHandler);
// state == JCEngine.STATE_INIT 表示初始化成功
int state = mJCEngine.getState();

private static class MyEventHandler implements JCEngineEventHandler {
...
// 回调实现
...
}

初始化时设置 JCEngineEventHandler。具体回调信息请参考 SDK API Reference。

通信

加入房间

加入房间前,需要定义一个 roomId 作为该实例的唯一标识。在多个设备上使用同一个 AppKey 初始化 SDK,并使用同一个 roomId,即可加入同一个房间。
1.调用加入房间接口。加入房间接口为异步调用,调用后等待 eventHandler 回调:

    int ret = mJCEngine.joinRoom(roomId, displayName);

2.处理回调:

    private static class MyEventHandler implements JCEngineEventHandler {
    ...

        void onJoinRoomSuccess() {
            // 加入成功
        }

        void onError(int errorCode) {
            switch (errorCode) {
                case JCEngine.ERROR_JOIN_FAIL_BUSY:
                case JCEngine.ERROR_JOIN_FAIL_INVALID_ROOM_ID:
                case JCEngine.ERROR_JOIN_FAIL_NET_UNAVAILABLE:
                case JCEngine.ERROR_JOIN_FAIL_TIMEOUT:
                case JCEngine.ERROR_JOIN_FAIL_FULL:
                case JCEngine.ERROR_JOIN_FAIL_CONNECT:
                case JCEngine.ERROR_JOIN_FAIL_OTHER:
                // 加入失败 
        }

    ...
    }

3.音频
SDK 默认不发送音频,但会接受并播放其他成员的音频,您可以关闭声音外放:

    mJCEngine.enableAudioOutput(false);

您也可以根据后续章节介绍,开启发送音频。

离开房间

离开房间只需调用离开接口,如下。您必须先离开房间才能加入下一个房间。
1.调用离开接口。离开接口为异步调用,调用后等待回调。

    mJCEngine.leave();

2.处理回调: 主动调用离开接口或者被动离开房间都会收到此回调。

    private static class MyEventHandler implements JCEngineEventHandler {
        ...
        void onLeftRoom(int reason) {
            // 离开房间。
            // reason:离开原因。
        }

        ...
    }

成员变化

加入房间后,您可以调用以下接口获取房间中的成员列表:

    ArrayList<JCParticipant> list = mJCEngine.getParticipants();

成员发生变化时都会触发成员变化相关回调。

    private static class MyEventHandler implements JCEngineEventHandler {
    ...
        void onParticipantJoin(String userId) {
            // 成员加入
        }

        void onParticipantLeft(String userId, int reason) {
            // 成员离开
        }

        void onParticipantUpdated(String userId) {
            // 成员变化
        }

        ...
    }

打开/关闭摄像头

调用打开摄像头接口以打开摄像头:

    mJCEngine.startCamera();

默认情况下,SDK 会打开前置摄像头,您可以在调用打开摄像头接口之前设置默认摄像头。

    // 参数为是否前置摄像头,摄像头采集分辨率
    mJCEngine.setupCapture(isFront, JCEngine.RESOLUTION_360);

调用关闭摄像头接口,即可关闭摄像头:

    mJCEngine.stopCamera();

渲染本地预览

完成打开摄像头后,您可以开始渲染本地预览。 1.准备界面布局: 您可以预先在界面布局中留出视频渲染位置,也可以在界面上动态添加。以预先留出位置为例:

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/video_container"
            android:layout_width="100dp"
            android:layout_height="100dp" />
</RelativeLayout >

2.开始渲染
在界面代码中找到 View,并参考以下示例添加渲染控件,并开始渲染:

    FrameLayout layout = findViewById(R.id.video_container);
    SurfaceView surfaceView = ZmfVideo.renderNew(getApplicationContext());
    layout.addView(surfaceView);
    mJCEngine.startRender(surfaceView, userId, ZmfVideo.RENDER_FULL_CONTENT);

3.停止渲染
需要停止渲染视频时,参考以下示例停止渲染并释放控件:

    mJCEngine.stopRender(surfaceView);
    layout.removeView(surfaceView);

订阅成员视频

默认情况下,SDK 不会接收其他成员的视频,您需要根据实际需求和成员状态决定是否订阅视频及视频大小。 1.订阅成员视频:

    JCParticipant partp = mJCEngine.getParticipant(userId);
    if (partp.hasVideo()) {
        mJCEngine.requestVideo(userId, JCEngine.PICTURE_SIZE_LARGE);
    }

2.取消订阅

    mJCEngine.cancelVideoRequest(userId, JCEngine.PICTURE_SIZE_LARGE);

渲染成员视频

在渲染成员视频前,您需要订阅成员视频,以获取该成员的视频流。不要忘记停止渲染后需要取消成员视频的订阅。

1.准备界面布局: 您可以预先在界面布局中留出视频渲染位置,也可以在界面上动态添加。以预先留出位置为例:

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/video_container"
            android:layout_width="100dp"
            android:layout_height="100dp" />
</RelativeLayout >

2.开始渲染
在界面代码中找到 View,并参考以下示例添加渲染控件,并开始渲染:

    FrameLayout layout = findViewById(R.id.video_container);
    SurfaceView surfaceView = ZmfVideo.renderNew(getApplicationContext());
    layout.addView(surfaceView);
    mJCEngine.startRender(surfaceView, userId, ZmfVideo.RENDER_FULL_CONTENT);

3.停止渲染
需要停止渲染视频时,参考以下示例停止渲染并释放控件:

    mJCEngine.stopRender(surfaceView);
    layout.removeView(surfaceView);

发送音频

加入房间后,默认是关闭语音发送的,此时房间中的其它成员是听不到该成员的声音。需要如下操作来开始发送音频数据。
1.调用打开/关闭音频发送接口

    mJCEngine.enableLocalAudioStream(enable);

2.监听成员变化通知,关注自己的 onParticipantUpdated 成员状态变化。

    private static class MyEventHandler implements JCEngineEventHandler {
        ...

        void onParticipantUpdated(String userId) {
            // 成员变化
            if(JCUtils.isSelf(userId)) {
                JCParticipant self = mJCEngine.getParticipant(userId);
                if (self.hasAudio()) {
                    // 音频发送打开
                } else {
                    // 音频发送关闭(失败)
                }
            }
        }

        ...
    }

发送视频

加入房间后,默认是关闭视频发送的,此时房间中的其它成员是订阅不到该成员的视频。需要如下操作来开始发送视频数据。
1.调用打开/关闭视频发送接口

    mJCEngine.enableLocalVideoStream(enable);

2.监听成员变化通知,关注自己的 onParticipantUpdated 成员状态变化。

    private static class MyEventHandler implements JCEngineEventHandler {
        ...

        void onParticipantUpdated(String userId) {
            // 成员变化
            if(JCUtils.isSelf(userId)) {
                JCParticipant self = mJCEngine.getParticipant(userId);
                if (self.hasVideo()) {
                    // 视频发送打开
                } else {
                    // 视频发送关闭(失败)
                }
            }
        }

        ...
    }