You need to enable JavaScript to run this app.
导航

场景搭建(Android)

最近更新时间2023.08.28 12:05:42

首次发布时间2023.07.19 10:32:42

SDK集成

如下是一个总体接入流程,详细细节请参见 RTC服务开通指南

alt

整体实现流程

整体业务流程图

alt

核心功能实现

准备通话

时序图

alt

示例代码

public void startCall(String appId, String bid) {
    // 创建 RTC 引擎
     mRTCVideo = RTCVideo.createRTCVideo(AppUtil.getApplicationContext(), appId, 
             mVideoEventHandler, null, null);
             
    // 采集视频:分辨率 540*960,帧率 15fps,最大码率1520kbps,最小码率300kbps
    VideoEncoderConfig config = new VideoEncoderConfig(540, 960, 15, 1520, 300);
    mRTCVideo.setVideoEncoderConfig(config);
    
    //  设置视频帧方向
    mRTCVideo.setVideoOrientation(VideoOrientation.Portrait);
    
    //  设置默认音频路由
    mRTCVideo.setDefaultAudioRoute(AudioRoute.AUDIO_ROUTE_SPEAKERPHONE); 
    
    //  设置本地视频画布
    VideoCanvas canvas = new VideoCanvas(mLocalVideoRenderView, VideoCanvas.RENDER_MODE_HIDDEN);
    mRTCVideo.setLocalVideoCanvas(StreamIndex.STREAM_INDEX_MAIN, canvas);
    
    //  设置本地视频采集,移动端默认会开启前置摄像头。
    if (userSetting.openCamera) {
        mRTCVideo.startVideoCapture();
    } else {
        mRTCVideo.stopVideoCapture();
    }
    
    // 设置本地音频采集 
    if (userSetting.openMic) {
        mRTCVideo.startAudioCapture();
    } else {
        mRTCVideo.stopAudioCapture();
    }
 }

响铃

时序图

alt

示例代码

private static final int MIX_ID = 19;

public void startRinging() {
    mMixingManager = mRTCVideo == null ? null : mRTCVideo.getAudioMixingManager();
    if (mMixingManager == null || mRinging.get()) {
        return;
    }
    // 音频场景设置为媒体
    mRTCVideo.setAudioScenario(AudioScenarioType.AUDIO_SCENARIO_MEDIA);
    // 音频文件路径
    String filePathInAssets = "call_receive.mp3";
    String parentPath = AppUtil.getApplicationContext().getExternalFilesDir("assets").getAbsolutePath() + "/resource/";
    File ringMusicFile = new File(parentPath, filePathInAssets);
    if (ringMusicFile.exists()) {
        // 开始响铃
        startAudioMixing(ringMusicFile);
    } else {
        AppExecutors.networkIO().execute(() -> {
            boolean success = copyAssetFile(AppUtil.getApplicationContext(), filePathInAssets, ringMusicFile.getAbsolutePath());
            if (success) {
                startAudioMixing(ringMusicFile);
            }
        });
    }
}

public void stopRinging() {
    if (mMixingManager != null && mRinging.get()) {
        mMixingManager.stopAudioMixing(MIX_ID);
        mRinging.set(false);
    }
}

private void startAudioMixing(File ringMusicFile) {
    mMixingManager.startAudioMixing(MIX_ID, ringMusicFile.getAbsolutePath(),
            new AudioMixingConfig(AudioMixingType.AUDIO_MIXING_TYPE_PLAYOUT, -1));
    mRinging.set(true);
}

进行通话

时序图

alt

示例代码

public int creteAndJoinRTCRoom(String token, String userId, String roomID, boolean autoPublish) {
    mRTCRoom = mRTCVideo.createRTCRoom(roomID);
    if (mRoomEventHandler != null) {
        mRTCRoom.setRTCRoomEventHandler(mRoomEventHandler);
    }
    RTCRoomConfig roomConfig = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_COMMUNICATION, autoPublish, true, true);
    return mRTCRoom.joinRoom(token, new UserInfo(userId, null), roomConfig);
}

// 远端用户加入房间后设置渲染画布。
public void onUserJoined(UserInfo userInfo, int elapsed) {
      Runnable runnable = () -> {
           setRemoteVideoCanvas(userInfo.getUid(), mLocalVideoView);
      };
      AppExecutors.execRunnableInMainThread(runnable);
}

// 切换前后置摄像头
public void switchCamera() {
    if (mRTCVideo == null) {
        return;
    }
    CameraId targetId = mCameraId == CameraId.CAMERA_ID_FRONT
            ? CameraId.CAMERA_ID_BACK
            : CameraId.CAMERA_ID_FRONT;

    mRTCVideo.setLocalVideoMirrorType(
                cameraId == CameraId.CAMERA_ID_FRONT
                        ? MirrorType.MIRROR_TYPE_RENDER_AND_ENCODER
                        : MirrorType.MIRROR_TYPE_NONE);
                                   
    mRTCVideo.switchCamera(targetId);
    
    mCameraId = targetId;
}

// 设置远端渲染画布
public void setRemoteVideoCanvas(String remoteUserId, TextureView view) {
    if (mRTCVideo == null || TextUtils.isEmpty(remoteUserId)) {
        return;
    }
    VideoCanvas canvas = new VideoCanvas(view, VideoCanvas.RENDER_MODE_HIDDEN);
    mRTCVideo.setRemoteVideoCanvas(new RemoteStreamKey(mRoomId, remoteUserId, StreamIndex.STREAM_INDEX_MAIN), canvas);
}

网络状态提示

用户加入 RTC 房间后,onNetworkQuality 每 2 s 回调一次,返回本地用户和已订阅远端用户的上下行网络质量评分。 RTC 根据 NetworkQuality 的数值,对网络状况进行判定,在网络质量不好时进行提示。

  • 在本地断网(如开启飞行模式)时,onNetworkTypeChanged(kNetworkTypeDisconnected) 会立即触发。
  • 连接断开时长达 12s 时,RTC 会触发 onConnectionStateChanged(kConnectionStateDisconnected) 回调通知连接断开。
  • 连接断开后,RTC 内部会不断重连,超过一段时间未重连成功,会进入断联超时状态,建议业务 App 挂断通话。

示例代码

public void onNetworkQuality(NetworkQualityStats localQuality, NetworkQualityStats[] remoteQualities) {
    if (remoteQualities.length == 0) {
        return;
    }
    
    int localQuality = max(localQuality.txQuality, localQuality.rxQuality);
    int remoteQuality = max(remoteQuality.txQuality, remoteQuality.rxQuality);
    
    if (localQuality <= NetworkQuality.NETWORK_QUALITY_POOR &&
        remoteQuality <= NetworkQuality.NETWORK_QUALITY_POOR) {
        Runnable runnable = () -> {
            // 网络恢复,清除弱网提示。
        };
        AppExecutors.execRunnableInMainThread(runnable);
        return;
    }
    
    // 优先提示本地弱网状态
    if (localQuality > NetworkQuality.NETWORK_QUALITY_POOR) {
        Runnable runnable = () -> {
            // 提示本地弱网
            // 若 localQuality == NetworkQuality.NETWORK_QUALITY_VERY_BAD,提示建议用户关闭摄像头。
        };
        AppExecutors.execRunnableInMainThread(runnable);    
        return;
    }
    
    // 本地网络正常,对端网络异常,提示对端弱网
    if (remoteQuality > NetworkQuality.NETWORK_QUALITY_POOR) {
        Runnable runnable = () -> {
            // 提示对端弱网
            // 若 localQuality == NetworkQuality.NETWORK_QUALITY_VERY_BAD,提示建议用户关闭摄像头。
        };
        AppExecutors.execRunnableInMainThread(runnable);
        return;
    }    
}

结束通话

时序图

alt

示例代码

public void onLeaveCall() {
    if (mRTCRoom != null) {
        mRTCRoom.leaveRoom();
        mRTCRoom.destroy();
        mRTCRoom = null;
    }
    if (mRTCVideo != null) {
        mRTCVideo.stopAudioCapture();
        mRTCVideo.stopVideoCapture();       
        RTCVideo.destroyRTCVideo();
        RTCVideo = null;
    }
}

核心功能 API 与回调参考

API

功能点API
创建 ByteRTCVideo 实例createRTCVideo
设置视频发布参数SetVideoEncoderConfig
设置默认音频播放路由setDefaultAudioRoute
设置视频朝向setVideoOrientation
开启本地音频采集startAudioCapture
开启本地视频采集startVideoCapture
设置本地视频渲染setLocalVideoCanvas
获取混音管理接口getAudioMixingManager
开启 PCM 音频数据混音startAudioMixing
关闭PCM 混音disableAudioMixingFrame
创建 RTCRoom 实例createRTCRoom
设置房间事件处理器setRTCRoomEventHandler
加入 RTC 房间joinRoom
切换前后置摄像头switchCamera
开启镜像setLocalVideoMirrorType
关闭内部音频采集stopAudioCapture
关闭内部视频采集stopVideoCapture
设置视频渲染视图setRemoteVideoCanvas
离开房间leaveRoom
销毁引擎实例对象destroyRTCVideo

回调

功能点回调
用户开启音频采集onUserStartAudioCapture
用户停止音频采集onUserStopAudioCapture
用户开启视频采集onUserStartVideoCapture
用户停止视频采集onUserStopVideoCapture
用户停止视频采集onUserStopVideoCapture
音频混音文件播放状态改变onAudioMixingStateChanged
远端首帧解码onFirstRemoteVideoFrameDecoded
房间 token 即将失效回调onTokenWillExpire
本地进房成功回调onRoomStateChanged
远端可见用户加入房间onUserJoined