You need to enable JavaScript to run this app.
导航
同一用户加入多个房间
最近更新时间:2025.11.10 15:11:17首次发布时间:2023.03.21 14:36:57
复制全文
我的收藏
有用
有用
无用
无用

同一个用户可以加入多个房间,分别订阅和接收这些房间中的音视频流,并在其中一个房间中发布音视频。也可以发送和接收实时消息

适用场景

  • 大班小组课:主讲老师在大班房间内讲课,学生在该房间内听讲,同时可以在小组房间交流提问,并由助教老师答疑。

  • 游戏场景:玩家可以在已加入的小队房间内和其他小队成员进行语音互动,同时能收听到世界房间内的广播音频。

  • 会议场景:云端会议过程中,主持人可以发起分组讨论。参会者无需离开原先的会议,即可在各自小组中进行音视频互动,不同讨论组互不干扰。

前提条件

你已经集成 RTC SDK v3.43 或更新的版本,实现了基本的音视频通话。
支持多房间功能的 SDK 详见API 及回调

功能实现

在集成 RTC SDK,并完成业务逻辑代码时,你已发现,音视频引擎类和房间类两个常用的主调类有明显的功能区分:

  • 通过使用音视频引擎类的方法,你可以启动音视频采集,并进行相关设置(如切换摄像头等);

  • 通过房间类的方法,你可以在房间内发布/订阅流,并进行相关设置(如用户自身在房间内的可见性等)。

要让一个用户加入多个房间,可以通过一个音视频引擎实例,创建多个房间实例,并为这些实例设置不同的房间 ID。同一个用户在多个房间中,可以订阅在这些房间中发布的音视频流。
本文以加入两个房间为例,你可以按照相同流程,让用户加入更多房间。

以下时序图以 Android SDK 中的 API 名称为例。不同端的 SDK 中 API 或回调名称可能略有不同,以 API 及回调为准。

1. 创建引擎类

创建和初始化一个音视频引擎类。

参考 构建 RTC 应用 获取详细步骤。

const list = [
  {
    "lang": "java",
    "text": `// APP_ID: 已经在控制台申请的app_id
    // engineEventHandler: 用于接收 RTCEngine 回调的接口实例
    EngineConfig config = new EngineConfig();
    config.appID = appId;
    config.context = applicationContext;
    rtcEngine = RTCEngine.createRTCEngine(config, engineEventHandler);`, 
    "selected": true,
  },
  {
    "lang": "swift",
    "text": `// kAppID: 已经在控制台申请的app_id
    let engineCfg = ByteRTCEngineConfig.init()
    engineCfg.appID = appId
    //私有参数,可以填空
    engineCfg.parameters = [:]
    //delegate: 用于接收 ByteRTCEngine 回调的接口实例
    self.rtcEngine = ByteRTCEngine.createRTCEngine(engineCfg, delegate: self)`,  
  },
  {
    "lang": "cpp",
    "text": `// app_id: 已经在控制台申请的app_id
// handler: 用于接收 RTCEngine 回调的接口实例
// parameters: 私有参数,可以填 nullptr
    bytertc::EngineConfig conf;
    conf.app_id = g_appid.c_str();
    engine = bytertc::IRTCEngine::createRTCEngine(conf, handler.get());
  },
]
return (<PreCodeTabs list={list} />);

2. 启动音视频采集

创建音视频引擎类后,你可以启动音视频采集,并设置渲染视图。

// 开启音视频采集
    rtcEngine.startAudioCapture();
    rtcEngine.startVideoCapture();

    // 设置本地渲染视图,支持 TextureView 和 SurfaceView
    private void setLocalRenderView() {
        VideoCanvas videoCanvas = new VideoCanvas();
        videoCanvas.renderView = localView;
        videoCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
        rtcEngine.setLocalVideoCanvas(videoCanvas);
    }

3. 创建房间实例

创建房间实例后,你可以加入房间发布和订阅音视频流。建议设置房间回调接口,以便监听房间和音视频流的状态回调。
继续调用 createRTCRoom 并传入不同房间 ID,以创建多个房间实例,并分别加入这些房间。

// 创建房间1
    rtcRoom1 = rtcEngine.createRTCRoom(roomID);
    rtcRoom1.setRTCRoomEventHandler(firstRoomEventHandler);
    
    // 创建房间2
    rtcRoom2 = rtcEngine.createRTCRoom(roomID);
    rtcRoom2.setRTCRoomEventHandler(secondRoomEventHandler);

4. 加入 RTC 房间

alt

  1. 加入每个房间时,默认自动订阅房间中的音视频流。
// 用户信息
    UserInfo userInfo = new UserInfo(localUid, "");
    // 房间1配置
    RTCRoomConfig room1Config = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_LIVE, true, true, true, true);
    // 加入房间
    rtcRoom1.joinRoom(room1token, userInfo, true, room1Config);

    // 房间2配置
    // 一个用户只能在一个房间中发布视频流。
    RTCRoomConfig room2Config = new RTCRoomConfig(ChannelProfile.CHANNEL_PROFILE_LIVE, false, false, true, true);
    // 加入房间
    rtcRoom2.joinRoom(room2token, userInfo, true, room2Config);
  1. 监听进房状态,处理进房失败。
public void onRoomStateChanged(String roomId, String uid, int state, String extraInfo) {
    if (state == 0) { //进房成功
    } else if (state == -1000) { //token错误
    } else {// .... 其他错误
    }
}
  1. 订阅端在接收到其他用户发布/取消发布音视频流回调时,设置渲染视图。

在收到远端用户的 onUserPublishVideoStream 或 onFirstRemoteVideoFrameDecoded 回调后,你需要调用 setRemoteVideoCanvas 设置远端视图以在通话中查看远端视频。建议您在 onFirstRemoteVideoFrameDecoded 回调中设置视频渲染,确保视频渲染在视频解码完成后进行,以避免卡顿。

const list = [
  {
    "lang": "java",
    "text": `
    @Override
    public void onFirstRemoteVideoFrameDecoded(String streamId, StreamInfo streamInfo, VideoFrameInfo frameInfo) {
        runOnUiThread(() -> {
            // 设置远端视频渲染视图
            VideoCanvas videoCanvas = new VideoCanvas();
            videoCanvas.renderView = firstRoomRemoteView;
            videoCanvas.renderMode = VideoCanvas.RENDER_MODE_HIDDEN;
            rtcEngine.setRemoteVideoCanvas(streamId, videoCanvas);
        });
    }

    @Override
    public void onUserPublishStreamVideo(String streamId, StreamInfo streamInfo, boolean isPublish) {
        if (!isPublish) {
            runOnUiThread(() -> {
                // 解除远端视频渲染视图绑定
                rtcEngine.setRemoteVideoCanvas(streamId, null);
            });
        }
    }`,
    "selected": true,
  },
  {
    "lang": "swift",
    "text": `// 远端用户发布流
    func rtcEngine(_ rtcEngine: ByteRTCEngine, onFirstRemoteVideoFrameDecoded streamId: String, info: ByteRTCStreamInfo, withFrameInfo: ByteRTCVideoFrameInfo) { 
        // 渲染远端用户
        DispatchQueue.main.async {
            // 设置远端用户视频渲染视图
            let canvas = ByteRTCVideoCanvas.init()
            canvas.view = view.videoView
            canvas.renderMode = .hidden
            self.rtcEngine?.setRemoteVideoCanvas(streamId, withCanvas: canvas);
        }
    }

    func rtcRoom(_ rtcRoom: ByteRTCRoom, onUserPublishStreamVideo streamId: String, info: ByteRTCStreamInfo, isPublish: Bool) {
        if !isPublish  {
        //移除 UI 显示
            DispatchQueue.main.async {
                let canvas = ByteRTCVideoCanvas.init()
                canvas.view = nil // 置为空
                canvas.renderMode = .hidden
                self.rtcEngine?.setRemoteVideoCanvas(streamId, withCanvas: canvas)
            }
        }
    }`, 
  },
  {
    "lang": "cpp",
    "text": `//远端用户发布流
void EngineHandler::onFirstRemoteVideoFrameDecoded(std::string streamId, bytertc::StreamInfo info, bytertc::VideoFrameInfo frameInfo) {
    bytertc::VideoCanvas canvas;
    canvas.view = (void*)ui->widget->winId();
    engine->setRemoteVideoCanvas(streamId.c_str(), canvas);
}

void RoomHandler::onUserPublishStreamVideo(std::string streamId, bytertc::StreamInfo info, bool publish)
    if (!publish) { //远端用户取消发布流
      bytertc::VideoCanvas cas;
      cas.view = nullptr;
      engine->setRemoteVideoCanvas(streamId.c_str(), cas);
    }
}
`, 
]
return (<PreCodeTabs list={list} />);

5. 离开 RTC 房间

用户结束通话时,退出各个房间,并销毁本地房间实例。

rtcRoom.leaveRoom();
    rtcRoom.destroy();
    rtcRoom = null;

6. 销毁引擎类

在销毁所有房间实例后可销毁音视频引擎。

RTCEngine.destroyRTCEngine();

示例项目

参考以下项目获取完整代码。在示例项目中,本端用户加入了两个不同的 RTC 房间。你可以按照相同流程,让用户加入更多房间。

API 及回调

你可以根据上文的描述和示例,使用以下客户端 SDK,在不同的端上实现同一用户加入多房间功能。

说明:表格中的 macOS API 接口为 Objective-C,而示例项目中的 macOS 项目使用的是 Windows SDK 中的 API 接口。

平台AndroidiOSmacOSWindowsLinuxElectronFlutterUnity
音视频引擎类RTCEngineByteRTCEngineByteRTCEngineIRTCEngineIRTCEngineRTCVideoRTCVideoIRTCVideo
开启视频采集startVideoCapturestartVideoCapturestartVideoCapturestartVideoCapturestartVideoCapturestartVideoCapturestartVideoCaptureStartVideoCapture
开始音频采集startAudioCapturestartAudioCapturestartAudioCapturestartAudioCapturestartAudioCapturestartAudioCapturestartAudioCaptureStartAudioCapture
设置本地视图setLocalVideoCanvassetLocalVideoCanvas:setLocalVideoCanvas:setLocalVideoCanvassetLocalVideoCanvassetupLocalVideoRTCViewContextSetLocalVideoSink
创建房间createRTCRoomcreateRTCRoom:createRTCRoom:createRTCRoomcreateRTCRoomcreateRTCRoomcreateRTCRoomCreateRTCRoom
音视频房间类RTCRoomByteRTCRoomByteRTCRoomIRTCRoomIRTCRoomRTCRoomRTCRoomIRTCVideoRoom
设置房间回调setRTCRoomEventHandlersetRTCRoomDelegate:setRTCRoomDelegate:setRTCRoomEventHandlersetRTCRoomEventHandlersetRTCRoomEventHandler
加入房间joinRoomjoinRoom:userInfo:userVisibility:roomConfig:joinRoom:userInfo:userVisibility:roomConfig:joinRoomjoinRoomjoinRoomjoinRoomJoinRoom
房间状态回调onRoomStateChangedrtcRoom:onRoomStateChanged:withUid:state:extraInfo:rtcRoom:onRoomStateChanged:withUid:state:extraInfo:onRoomStateChangedonRoomStateChangedonRoomStateChangedonRoomStateChangedOnRoomStateChangedEventHandler
发布或取消回调视频流onUserPublishStreamVideortcRoom:onUserPublishStreamVideo:info:isPublish:rtcRoom:onUserPublishStreamVideo:info:isPublish:onUserPublishStreamVideoonUserPublishStreamVideoonUserPublishStreamonUserPublishStreamOnUserPublishStreamEventHandler
离开房间leaveRoomleaveRoomleaveRoomleaveRoomleaveRoomleaveRoomleaveRoomLeaveRoom
离开房间leaveRoomleaveRoomleaveRoomleaveRoomleaveRoomleaveRoomleaveRoomLeaveRoom
销毁房间destroydestroydestroydestroydestroydestroydestroyDestroy
销毁音视频引擎destroyRTCEnginedestroyRTCEnginedestroyRTCEnginedestroyRTCEnginedestroyRTCEnginedestroyRTCVideodestroyRelease

常见问题

Q1: 同一用户如何在多个房间内同时发送音视频流?

A:对于一个音视频引擎实例,即使加入了多个房间,也仅能同时在其中的一个房间中发布音视频流。如果需要在多个房间中同时发布音视频流,参看 跨房间转发媒体流

Q2: 如何处理 Token 相关错误?

A:确保每个房间的 token 使用了对应的 roomId 生成。更多 Token 相关问题,参见 Token 使用常见问题