You need to enable JavaScript to run this app.
导航
Android
最近更新时间:2024.05.23 19:32:10首次发布时间:2022.07.18 21:22:43

本章节介绍 Android 端互动直播场景核心功能的实现方式。

前提条件

版本说明

互动直播功能需要使用互动版 SDK,请您在安装 SDK 时选择正确的版本。

最新互动版 SDK 适配 RTC Native SDK 3.52,请参考 RTC Native SDK API 查看对应版本 SDK API 说明。

说明

您也可以关注视频直播客户端 SDK 发布历史,从中获取 RTC SDK 适配信息。

主播端核心功能实现

以下是主播端核心功能实现的时序图和参考接入代码。

主播开播

主播通过 RTC 引擎和推流引擎开始直播推流。

时序图

示例代码

  • 创建 RTC 视频引擎,设置本地预览视图,设置视频编码参数。

    // 初始化 RTCVideo 对象
    mRTCVideo = RTCVideo.createRTCVideo(Env.getApplicationContext(), mAppId, mRTCVideoEventHandler, null, null);
    
    // 设置本地视图
    VideoCanvas videoCanvas = new VideoCanvas();
    // renderView 为本地用户预览视图,需自行创建、布局并赋值给 videoCanvas
    videoCanvas.renderView = renderView;
    videoCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
    mRTCVideo.setLocalVideoCanvas(StreamIndex.STREAM_INDEX_MAIN, videoCanvas);
    
    // 设置视频编码参数
    VideoEncoderConfig config = new VideoEncoderConfig(
            mConfig.mVideoEncoderWidth, mConfig.mVideoEncoderHeight, mConfig.mVideoEncoderFps, mConfig.mVideoEncoderKBitrate * 1000);
    mRTCVideo.setVideoEncoderConfig(config);  
    
  • 订阅 RTC 本地音视频数据。

    // 订阅本地视频数据
    mRTCVideo.setLocalVideoSink(StreamIndex.STREAM_INDEX_MAIN, mVideoFrameListener, IVideoSink.PixelFormat.I420);
    
    // 订阅本地音频数据
    mRTCVideo.enableAudioFrameCallback(AudioFrameCallbackMethod.AUDIO_FRAME_CALLBACK_RECORD,
            new AudioFormat(changeSampleRate(mConfig.mAudioCaptureSampleRate),
                    changeChannel(mConfig.mAudioCaptureChannel)));
    mRTCVideo.registerAudioFrameObserver(mAudioFrameListener);
    
  • 创建推流引擎,设置推流视频编码参数。

    //  创建推流引擎
    //  推流配置  
    VeLivePusherConfiguration config = new VeLivePusherConfiguration();
    //  配置上下文  
    config.setContext(Env.getApplicationContext());
    //  失败重连次数  
    config.setReconnectCount(10);
    //  创建推流器  
    mLivePusher = config.build();
    
    //  配置推流参数
    //  视频编码配置  
    VeLivePusherDef.VeLiveVideoEncoderConfiguration videoEncoderCfg = new VeLivePusherDef.VeLiveVideoEncoderConfiguration();
    //  设置视频分辨率,内部会根据分辨率设置最佳码率参数  
    videoEncoderCfg.setResolution(VeLiveVideoResolution720P);
    //  视频编码初始化码率(仅供参考)  
    videoEncoderCfg.setBitrate(mConfig.mVideoEncoderKBitrate);
    //  视频编码最大码率(仅供参考)  
    videoEncoderCfg.setMaxBitrate(mConfig.mVideoEncoderKBitrate);
    //  视频编码最小码率(仅供参考)  
    videoEncoderCfg.setMinBitrate(mConfig.mVideoEncoderKBitrate);
    //  硬编码  
    videoEncoderCfg.setEnableAccelerate(mConfig.mIsVideoHardwareEncoder);
    //  编码帧率  
    videoEncoderCfg.setFps(mConfig.mVideoEncoderFps);
    
    VeLivePusherDef.VeLiveAudioEncoderConfiguration audioEncoderCfg = new VeLivePusherDef.VeLiveAudioEncoderConfiguration();
    //  音频编码采样率  
    if (mConfig.mAudioEncoderSampleRate == 32000) {
        audioEncoderCfg.setSampleRate(VeLiveAudioSampleRate32000);
    } else if (mConfig.mAudioEncoderSampleRate == 48000) {
        audioEncoderCfg.setSampleRate(VeLiveAudioSampleRate48000);
    } else {
        audioEncoderCfg.setSampleRate(VeLiveAudioSampleRate44100);
    }
    
    //  音频编码通道数  
    if (mConfig.mAudioEncoderChannel == 1) {
        audioEncoderCfg.setChannel(VeLiveAudioChannelMono);
    } else {
        audioEncoderCfg.setChannel(VeLiveAudioChannelStereo);
    }
    
    //  音频编码码率  
    audioEncoderCfg.setBitrate(mConfig.mAudioEncoderKBitrate);
    //  配置视频编码  
    mLivePusher.setVideoEncoderConfiguration(videoEncoderCfg);
    //  配置音频编码  
    mLivePusher.setAudioEncoderConfiguration(audioEncoderCfg);
    
    //  开始视频采集  
    mLivePusher.startVideoCapture(VeLiveVideoCaptureExternal);
    //  开始音频采集  
    mLivePusher.startAudioCapture(VeLiveAudioCaptureExternal);
    
  • 开启 RTC 音视频采集。

    // 开始视频采集
    mRTCVideo.startVideoCapture();
    
    // 开始音频采集
    mRTCVideo.startAudioCapture();
    
  • 开启推流引擎推流。

    // 开始推流,url 为 RTMP 推流地址
    mLivePusher.startPush(url);
    
  • RTC 本地音视频回调数据发送给推流引擎。

    // 视频采集回调, 发送视频数据给推流引擎
    IVideoSink mVideoFrameListener = new IVideoSink() {
        @Override
        public void onFrame(com.ss.bytertc.engine.video.VideoFrame frame) {
            final int width = videoFrame.getWidth();
            final int height = videoFrame.getHeight();
            final int chromaHeight = (height + 1) / 2;
            final int chromaWidth = (width + 1) / 2;
            int bufferSize = width * height + chromaWidth * chromaHeight * 2;
            final ByteBuffer dstBuffer = ByteBuffer.allocateDirect(bufferSize);
    
            YuvHelper.I420Rotate(videoFrame.getPlaneData(0), videoFrame.getPlaneStride(0),
                    videoFrame.getPlaneData(1), videoFrame.getPlaneStride(1),
                    videoFrame.getPlaneData(2), videoFrame.getPlaneStride(2),
                    dstBuffer,width, height,videoFrame.getRotation().value());
    
            dstBuffer.position(0);
            VeLiveVideoFrame videoFrame1 = new VeLiveVideoFrame(width, height, System.currentTimeMillis() * 1000, dstBuffer);
            mLivePusher.pushExternalVideoFrame(videoFrame1);
            videoFrame1.release();
            frame.release();
        }
    };
    
    // 音频采集回调, 发送音频数据给推流引擎
    mAudioFrameListener = new IAudioFrameObserver() {
        @Override
        public void onRecordAudioFrame(IAudioFrame audioFrame) {
            VeLiveAudioFrame audioFrame = new VeLiveAudioFrame(VeLivePusherDef.VeLiveAudioSampleRate.fromValue(sampleRate, VeLiveAudioSampleRate44100),
            VeLivePusherDef.VeLiveAudioChannel.fromValue(channels, VeLiveAudioChannelStereo),
            timestamp,
            byteBuffer);
            mLivePusher.pushExternalAudioFrame(audioFrame);
        }
    
    };
    

主播美颜(可选)

主播美颜功能都是通过 RTC 引擎进行对接,使用方式请参考 美颜特效(CV)

主播上麦

主播停止推流引擎推流,通过 RTC 引擎加入房间连麦,并开启 RTC 服务端合流转推。

时序图

示例代码

  • 停止推流引擎推流。

    // 停止推流引擎推流
    mLivePusher.stopPush();
    
  • 创建 RTC 房间,设置用户信息,加入 RTC 房间。参考使用 Token 完成鉴权了解如何通过业务服务器获取鉴权 token。

    // 创建 RTC 房间
    mRTCRoom = mRTCVideo.createRTCRoom(roomId);
    mRTCRoom.setRTCRoomEventHandler(mIRtcRoomEventHandler);
    
    // 设置用户信息
    mUserId = userId;
    mRoomId = roomId;
    UserInfo userInfo = new UserInfo(userId, null);
    RTCRoomConfig roomConfig = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_COMMUNICATION,
            true, true, true);
            
    // 加入房间,token 信息通过业务服务器申请
    mRTCRoom.joinRoom(token, userInfo, roomConfig);
    
  • 收到加入 RTC 房间成功回调,开启 RTC 服务端合流转推。

    // 加入房间成功通知
    private RtcRoomEventHandlerAdapter mIRtcRoomEventHandler = new RtcRoomEventHandlerAdapter() {
        @Override
        public void onRoomStateChanged(String roomId, String uid, int state, String extraInfo) {
            // 创建 RTC 服务端合流配置
            mMixedStreamConfig = MixedStreamConfig.defaultMixedStreamConfig();
            mMixedStreamConfig.setRoomID(mRoomId);
            mMixedStreamConfig.setUserID(mUserId);
            
            // 服务端合流
            mMixedStreamConfig.setExpectedMixingType(STREAM_MIXING_BY_SERVER);
            
            // 设置推流地址, 这里为主播的 RTMP 推流地址
            mMixedStreamConfig.setPushURL(mPushUrl);
            
            // 设置视频编码参数。该参数需要和推流视频编码参数保持一致
            MixedStreamConfig.MixedStreamVideoConfig videoConfig = mMixedStreamConfig.getVideoConfig();
            // 分辨率宽
            videoConfig.setWidth(mConfig.mVideoEncoderWidth);
            // 分辨率高
            videoConfig.setHeight(mConfig.mVideoEncoderHeight);
            // fps
            videoConfig.setFps(mConfig.mVideoEncoderFps);
            // 比特率
            videoConfig.setBitrate(mConfig.mVideoEncoderKBitrate);
            mMixedStreamConfig.setVideo(videoConfig);
            
            // 设置音频编码参数。该参数需要和推流音频编码参数保持一致
            MixedStreamConfig.MixedStreamAudioConfig audioConfig = mMixedStreamConfig.getAudioConfig();
            // 音频采样率
            audioConfig.setSampleRate(mConfig.mAudioEncoderSampleRate);
            // 通道数
            audioConfig.setChannels(mConfig.mAudioEncoderChannel);
            // 比特率 k
            audioConfig.setBitrate(mConfig.mAudioEncoderKBitrate);
            // 配置音频参数
            mMixedStreamConfig.setAudioConfig(audioConfig);
            
            MixedStreamConfig.MixedStreamLayoutConfig layout = new MixedStreamConfig.MixedStreamLayoutConfig();
            // 主播合流布局
            MixedStreamConfig.MixedStreamLayoutRegionConfig[] regions = new MixedStreamConfig.MixedStreamLayoutRegionConfig[1];
            MixedStreamConfig.MixedStreamLayoutRegionConfig region = new MixedStreamConfig.MixedStreamLayoutRegionConfig();
            region.setUserID(mUserId); // 主播uid
            region.setRoomID(mRoomId);
            region.setIsLocalUser(true);
            region.setLocationX(0.0); // 仅供参考
            region.setLocationY(0.0); // 仅供参考
            region.setWidthProportion(1); // 仅供参考
            region.setHeightProportion(1); // 仅供参考
            region.setZOrder(0); // 仅供参考
            region.setAlpha(1); // 仅供参考
            region.setRenderMode(MixedStreamConfig.MixedStreamRenderMode.MIXED_STREAM_RENDER_MODE_HIDDEN);
            
            regions[0] = region;
            layout.setRegions(regions);
                    
            // 设置合流模版
            mMixedStreamConfig.setLayout(layout);
            
            // 设置合流任务 ID
            String taskId = "";
        
            // 开始合流转推
            mRTCVideo.startPushMixedStreamToCDN(taskId, mMixedStreamConfig, mIMixedStreamObserver);
        }
    }
    
  • 收到房间内连麦用户的音视频流发布通知后,调整用户视图以及合流布局。

    private RtcRoomEventHandlerAdapter mIRtcRoomEventHandler = new RtcRoomEventHandlerAdapter() {
        @Override
        public void onUserPublishStream(String uid, MediaStreamType type) {
            if (type == RTC_MEDIA_STREAM_TYPE_VIDEO || type == RTC_MEDIA_STREAM_TYPE_BOTH) {
                // 添加连麦用户视图
                TextureView renderView = new TextureView(Env.getApplicationContext());
                VideoCanvas canvas = new VideoCanvas();
                canvas.renderView = renderView;
                canvas.renderMode = RENDER_MODE_HIDDEN;
                RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
                mRTCVideo.setRemoteVideoCanvas(key, canvas);
            }
    
            MixedStreamConfig.MixedStreamLayoutRegionConfig[] regions = new MixedStreamConfig.MixedStreamLayoutRegionConfig[2];
            
            // 主播合流布局
            MixedStreamConfig.MixedStreamLayoutRegionConfig region = new MixedStreamConfig.MixedStreamLayoutRegionConfig();
            region.setUserID(mUserId); // 主播uid
            region.setRoomID(mRoomId);
            region.setIsLocalUser(true);
            region.setLocationX(0.0); //仅供参考
            region.setLocationY(0.0); //仅供参考
            region.setWidthProportion(0.5); //仅供参考
            region.setHeightProportion(0.5); //仅供参考
            region.setAlpha(1.0); //仅供参考
            region.setZOrder(0); //仅供参考
            region.setRenderMode(MixedStreamConfig.MixedStreamRenderMode.MIXED_STREAM_RENDER_MODE_HIDDEN);
            regions[0] = region;
            
            // 连麦用户合流布局
            MixedStreamConfig.MixedStreamLayoutRegionConfig regionRemote = new MixedStreamConfig.MixedStreamLayoutRegionConfig();
            regionRemote.setUserID(uid); // 连麦uid
            regionRemote.setRoomID(mRoomId);
            regionRemote.setIsLocalUser(false);
            regionRemote.setLocationX(0.0); //仅供参考
            regionRemote.setLocationY(0.0); //仅供参考
            regionRemote.setWidthProportion(0.5); //仅供参考
            regionRemote.setHeightProportion(0.5); //仅供参考
            regionRemote.setAlpha(1.0); //仅供参考
            regionRemote.setZOrder(0); //仅供参考
            regionRemote.setRenderMode(MixedStreamConfig.MixedStreamRenderMode.MIXED_STREAM_RENDER_MODE_HIDDEN);
            regions[1] = regionRemote;
              
            // 设置合流模版
            MixedStreamConfig.MixedStreamLayoutConfig layout = new MixedStreamConfig.MixedStreamLayoutConfig();
            layout.setRegions(regions);
            
             // 设置合流任务ID,ID 为上一步设置的合流任务 ID
            String taskId = "";
            
            mMixedStreamConfig.setLayout(layout);
            // 更新合流
            mRTCVideo.updatePushMixedStreamToCDN(taskId, mMixedStreamConfig);
        }
    
        @Override
        public void onUserUnpublishStream(String uid, MediaStreamType type, StreamRemoveReason reason) {
            if (type == RTC_MEDIA_STREAM_TYPE_VIDEO || type == RTC_MEDIA_STREAM_TYPE_BOTH) {
                // 移除连麦用户视图
                VideoCanvas canvas = new VideoCanvas();
                canvas.renderView = null;
                canvas.renderMode = RENDER_MODE_HIDDEN;
                RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
                mRTCVideo.setRemoteVideoCanvas(key, canvas);
            }
            MixedStreamConfig.MixedStreamLayoutConfig layout = new MixedStreamConfig.MixedStreamLayoutConfig();
            // 主播合流布局
            MixedStreamConfig.MixedStreamLayoutRegionConfig[] regions = new MixedStreamConfig.MixedStreamLayoutRegionConfig[1];
            MixedStreamConfig.MixedStreamLayoutRegionConfig region = new MixedStreamConfig.MixedStreamLayoutRegionConfig();
            region.setUserID(mUserId); // 主播uid
            region.setRoomID(mRoomId);
            region.setIsLocalUser(true);
            region.setLocationX(0.0); // 仅供参考
            region.setLocationY(0.0); // 仅供参考
            region.setWidthProportion(1); // 仅供参考
            region.setHeightProportion(1); // 仅供参考
            region.setZOrder(0); // 仅供参考
            region.setAlpha(1); // 仅供参考
            region.setRenderMode(MixedStreamConfig.MixedStreamRenderMode.MIXED_STREAM_RENDER_MODE_HIDDEN);
            
            regions[0] = region;
            layout.setRegions(regions);
                    
            // 设置合流模版
            mMixedStreamConfig.setLayout(layout);
            
            // 设置合流任务ID,ID 为上一步设置的合流任务 ID
            String taskId = "";
            
            // 更新合流
            mRTCVideo.updatePushMixedStreamToCDN(taskId, mLiveTranscoding);
        }
    };
    

主播下麦

主播停止 RTC 服务端合流转推,离开 RTC 房间,开启推流引擎推流。

时序图

示例代码

  • 停止 RTC 服务端合流,离开房间,移除连麦用户视图。

    // 停止 RTC 服务端合流转推
    mRTCVideo.stopPushStreamToCDN(taskId);
    
    // 离开 RTC 房间
    mRTCRoom.leaveRoom();
    
    // 移除连麦用户视图
    VideoCanvas canvas = new VideoCanvas();
    canvas.renderView = null;
    canvas.renderMode = RENDER_MODE_HIDDEN;
    RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
    mRTCVideo.setRemoteVideoCanvas(key, canvas);
    
  • 开启推流引擎推流。

    // 开始推流引擎推流
    mLivePusher.startPush(url);
    

主播停播

主播停止直播,销毁 RTC 引擎和推流引擎。

时序图

示例代码

  • 停止推流引擎推流,销毁 RTC 引擎和推流引擎。

    // 停止推流引擎推流
    mLivePusher.stopPush();
    
    // 销毁推流引擎
    mLivePusher.release();
    mLivePusher = null;
    
  • 停止 RTC 音视频采集,移除本地预览视图。

    // 停止 RTC 视频采集
    mRTCVideo.stopVideoCapture();
    
    // 停止 RTC 音频采集
    mRTCVideo.stopAudioCapture();
    
    // 移除 RTC 本地预览视图
    VideoCanvas videoCanvas = new VideoCanvas();
    videoCanvas.renderView = null;
    videoCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
    mRTCVideo.setLocalVideoCanvas(StreamIndex.STREAM_INDEX_MAIN, videoCanvas);
    
  • 销毁 RTC 房间,销毁 RTC 视频引擎。

    // 销毁 RTC 房间
    mRTCRoom.destroy();
    mRTCRoom = null;
    
    // 销毁 RTC 视频引擎
    RTCVideo.destroyRTCVideo();
    mRTCVideo = null;
    

观众端核心功能实现

以下是观众端核心功能实现的时序图和参考接入代码。

观众拉流

观众端通过播放器拉流观看直播。

时序图

示例代码

  • 创建和设置播放器。

    // 创建播放器
    VeLivePlayer mLivePlayer = new VideoLiveManager(Env.getApplicationContext());
    
    // 设置播放器回调
    mLivePlayer.setObserver(mLivePlayerObserver);
    
    // 播放器参数设置
    VeLivePlayerConfiguration config = new VeLivePlayerConfiguration();
    config.enableStatisticsCallback = true;
    config.enableLiveDNS = true;
    mLivePlayer.setConfig(config);
    
  • 设置播放器视图,设置直播地址,开启拉流播放。

    // 设置播放器视图
    mLivePlayer.setSurfaceHolder(holder);
    
    // 设置播放地址
    mLivePlayer.setPlayUrl(mPullUrl);
    
    // 开始播放
    mLivePlayer.play();
    

观众上麦

连麦观众停止播放器拉流播放,通过 RTC 引擎进行连麦。

时序图

示例代码

  • 停止播放,移除播放器视图。

    // 停止播放
    mLivePlayer.stop();
    // 移除播放器视图
    mLocalVideoContainer.removeView(mPlayerView);
    
  • 创建 RTC 视频引擎,设置本地预览视图,设置视频编码参数。

    // 初始化 ByteRTCVideo 对象
    mRTCVideo = RTCVideo.createRTCVideo(Env.getApplicationContext(), mAppId, mRTCVideoEventHandler, null, null);
    
    // 设置本地视图
    VideoCanvas videoCanvas = new VideoCanvas();
    // renderView 为本地用户预览视图,需自行创建、布局并赋值给 VideoCanvas
    videoCanvas.renderView = renderView;
    videoCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
    mRTCVideo.setLocalVideoCanvas(StreamIndex.STREAM_INDEX_MAIN, videoCanvas);
    
    // 设置视频编码参数
    VideoEncoderConfig config = new VideoEncoderConfig(
            mConfig.mVideoEncoderWidth, mConfig.mVideoEncoderHeight, mConfig.mVideoEncoderFps, mConfig.mVideoEncoderKBitrate * 1000);
    mRTCVideo.setVideoEncoderConfig(config);
    
  • 开启 RTC 音视频采集。

    // 开始视频采集
    mRTCVideo.startVideoCapture();
    
    // 开始音频采集
    mRTCVideo.startAudioCapture();
    
  • 创建 RTC 房间,设置用户信息,加入 RTC 房间。

    // 创建 RTC 房间
    mRTCRoom = mRTCVideo.createRTCRoom(roomId);
    mRTCRoom.setRTCRoomEventHandler(mIRtcRoomEventHandler);
    
     // 设置用户信息
    UserInfo userInfo = new UserInfo(userId, null);
    RTCRoomConfig roomConfig = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_COMMUNICATION,
            true, true, true);
        
    // 加入房间,token 信息通过业务服务器申请
    mRTCRoom.joinRoom(token, userInfo, roomConfig);
    
  • 收到房间内连麦用户的音视频流发布通知后,调整用户视图。

    private RtcRoomEventHandlerAdapter mIRtcRoomEventHandler = new RtcRoomEventHandlerAdapter() {
        @Override
        public void onUserPublishStream(String uid, MediaStreamType type) {
            if (type == RTC_MEDIA_STREAM_TYPE_VIDEO || type == RTC_MEDIA_STREAM_TYPE_BOTH) {
                // 添加连麦用户视图
                TextureView renderView = new TextureView(Env.getApplicationContext());
                VideoCanvas canvas = new VideoCanvas();
                canvas.renderView = renderView;
                canvas.renderMode = RENDER_MODE_HIDDEN;
                RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
                mRTCVideo.setRemoteVideoCanvas(key, canvas);
            }          
        }
    
        @Override
        public void onUserUnpublishStream(String uid, MediaStreamType type, StreamRemoveReason reason) {
            if (type == RTC_MEDIA_STREAM_TYPE_VIDEO || type == RTC_MEDIA_STREAM_TYPE_BOTH) {
                // 移除连麦用户视图
                VideoCanvas canvas = new VideoCanvas();
                canvas.renderView = null;
                canvas.renderMode = RENDER_MODE_HIDDEN;
                RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
                mRTCVideo.setRemoteVideoCanvas(key, canvas);
            }
        }
    };
    

观众美颜(可选)

观众连麦美时颜功能都是通过 RTC 引擎进行对接,使用方式请参考 美颜特效(CV)

观众下麦

观众停止 RTC 引擎连麦,恢复拉流观看直播。

时序图

示例代码

  • 离开 RTC 房间,停止 RTC 音视频采集,移除 RTC 本地和远端视图。

    // 离开 RTC 房间
    mRTCRoom.leaveRoom();
    
    // 停止视频采集
    mRTCVideo.stopVideoCapture();
    
    // 停止音频采集
    mRTCVideo.stopAudioCapture();
    
    // 移除本地用户视图
    VideoCanvas canvas = new VideoCanvas(null, RENDER_MODE_HIDDEN, mRoomId, mUserId, false);
    mRTCVideo.setLocalVideoCanvas(mUserId, StreamIndex.STREAM_INDEX_MAIN, canvas);
    
    // 移除连麦用户视图
    VideoCanvas canvas = new VideoCanvas();
    canvas.renderView = null;
    canvas.renderMode = RENDER_MODE_HIDDEN;
    RemoteStreamKey key = new RemoteStreamKey(mRoomId, uid, StreamIndex.STREAM_INDEX_MAIN);
    mRTCVideo.setRemoteVideoCanvas(key, canvas);
    
  • 设置播放器视图,启动拉流播放。

    // 设置播放器视图
    mLivePlayer.setSurfaceHolder(holder);
    // 开始播放
    mLivePlayer.play();
    

观众离开

观众停止观看直播,销毁播放器。

时序图

示例代码

  • 停止播放,移除播放器视图,销毁播放器。

    // 停止播放
    mLivePlayer.stop();
    
    // 移除播放器视图
    mLocalVideoContainer.removeView(mPlayerView);
    
    // 销毁播放器
    mLivePlayer.destroy();
    mLivePlayer = null;
    
  • 销毁 RTC 房间,销毁 RTC 引擎。

    // 销毁 RTC 房间
    mRTCRoom.destroy();
    mRTCRoom = null;
    
    // 销毁 RTC 引擎
    RTCVideo.destroyRTCVideo();
    mRTCVideo = null;