跨房间连麦
跨房间连麦需要区分“主房间”和“副房间”的概念,主副房间是相对概念,定义如下:
- 主房间:本端最先加入的房间,即 RCRTCRoom。
- 副房间:在连麦邀请被接受后,双方加入对方房间,对方房间即:RCRTCOtherRoom。
开始跨房间连麦前,双方都需要先加入各自的主房间;未加入主房间前,无法发起或接收跨房间连麦邀 请。
两种房间类型对应不同的事件回调:主房间使用 IRCRTCRoomEventsListener,副房间使用 IRCRTCOtherRoomEventsListener。
主流程

发起邀请
向指定用户发送跨房间连麦请求:在加入房间成功的回调中,通过 RCRTCRoom 获取 RCRTCLocalUser 对象,调用 requestJoinOtherRoom 方法。
示例代码:
/**
* 向指定用户发送跨房间连麦请求
* 1. 当 inviterAutoMix 为 true 时:
*
* 1.1 如果被邀请方在加入邀请方房间之前发布了资源,当被邀请方加入邀请方房间成功后,服务器会将被邀请方的流资源合并到邀请方视图(默认仅悬浮布局合流)上。
*
* 1.2 如果被邀请方在加入邀请方房间之前未发布资源,将在被邀请方发布资源成功后,服务器再把被邀请方的流资源合并到邀请方视图(默认仅悬浮布局合流)上。
*
* 2. 无论 inviterAutoMix 为 true 还是 false,双方都可以使用 {@link RCRTCLiveInfo#setMixConfig(RCRTCMixConfig, IRCRTCResultCallback)} 主动设置合流布局。
* 一旦主动设置过合流布局,后续音视频直播过程中设置的自动合流参数将失效。
*/
RCRTCRoom.getLocalUser().requestJoinOtherRoom(inviteeRoomId, inviteeUserId, inviterAutoMix, "extra", new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(RTCErrorCode errorCode) {
}
});
取消邀请
收到其他房间主播的跨房间连麦邀请后,如果不打算加入,调用 RCRTCLocalUser 的 cancelRequestJoinOtherRoom 取消进行中的邀请。
示例代码
RCRTCRoom.getLocalUser().cancelRequestJoinOtherRoom(inviteeRoomId, inviteeUserId, "extra", new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(RTCErrorCode errorCode) {
}
});
应答邀请
收到跨房间连麦邀请后,如果同意加入,需要先调用 RCRTCLocalUser 的 responseJoinOtherRoom 应答,再调用 joinOtherRoom 加入副房间。
示例代码
/**
* <p>
* 1. 当 inviteeAutoMix 为 true 时:
*
* 1.1 如果邀请方在发送连麦请求之前发布了资源,当被邀请方加入邀请方房间成功后,服务器会把邀请方的流资源合并到被邀请方视图(默认仅悬浮布局合流)上。
*
* 1.2 如果邀请方在发送连麦请求之前未发布资源,将在邀请方发布资源成功后,服务器才会把邀请方的资源合并到被邀请方视图(默认仅悬浮布局合流)上。
*
* 2. 无论 inviteeAutoMix 为 true 还是 false,双方都可以使用 {@link RCRTCLiveInfo#setMixConfig(RCRTCMixConfig, IRCRTCResultCallback)} 主动设置合流布局。
* 一旦主动设置过合流布局,后续音视频直播过程中设置的自动合流参数将失效。
* </p>
*/
RCRTCRoom.getLocalUser().responseJoinOtherRoom(inviterRoomId, inviterUserId, agree, inviteeAutoMix, "extra", new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(RTCErrorCode errorCode) {
}
});
加入副房间
可调用 joinOtherRoom 方法,加入副房间。
示例代码
RCRTCEngine.getInstance().joinOtherRoom(roomId, new IRCRTCResultDataCallback<RCRTCOtherRoom>() {
@Override
public void onSuccess(RCRTCOtherRoom rcrtcOtherRoom) {
}
@Override
public void onFailed(RTCErrorCode rtcErrorCode) {
}
});
注册其他房间事件监听
- 在加入副房间成功后的回调中,获取
RCRTCOtherRoom对象,调用registerOtherRoomEventsListener注册副房间事件监听。当副房间主播加入、离开、发布资源时会触发回调;在回调中按需订阅音视频资源。可进行音视频通话。 - 在不使用或退出房间前,调用
RCRTCOtherRoom.unregisterOtherRoomEventsListener取消注册。
RCRTCOtherRoom.registerOtherRoomEventsListener(new IRCRTCOtherRoomEventsListener() {
/**
* 其他房间内用户发布资源
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
* @param list 发布的资源
*/
@Override
public void onRemoteUserPublishResource(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {}
/**
* 其他房间用户发布的音频资源静音或取消静音
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
* @param rcrtcInputStream 音频流
* @param mute 为 true 表示静音,为 false 表示取消静音
*/
@Override
public void onRemoteUserMuteAudio(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean mute) {}
/**
* 远端用户打开或关闭发布的视频流(例如开启/关闭摄像头)
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
* @param rcrtcInputStream 视频流
* @param mute 为 true 表示关闭,为 false 表示打开
*/
@Override
public void onRemoteUserMuteVideo(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser, RCRTCInputStream rcrtcInputStream, boolean mute) {}
/**
* 房间内用户取消发布资源
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
* @param list 远端用户取消发布的资源
*/
@Override
public void onRemoteUserUnpublishResource(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {}
/**
* 用户加入房间
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
*/
@Override
public void onUserJoined(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser) {}
/**
* 用户离开房间
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
*/
@Override
public void onUserLeft(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser) {}
/**
* 用户离线
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
*/
@Override
public void onUserOffline(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser) {}
/**
* 自己退出其他房间(如断网导致)
*
* @param rcrtcOtherRoom 加入的其他房间对象
* @param reasonCode 状态码
*/
@Override
public void onLeaveRoom(RCRTCOtherRoom rcrtcOtherRoom, int reasonCode) {}
});
离开副房间
需要结束跨房间连麦时,调用 RCRTCEngine 的 leaveOtherRoom 离开副房间。
示例代码:
RCRTCEngine.getInstance().leaveOtherRoom(roomId, notifyFinished, new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(RTCErrorCode rtcErrorCode) {
}
});
邀请连麦流程
-
场景一:邀请方发起邀请后又取消邀请。
提示此场景 中,被邀请方未做任何操作,仅被动收到两次代理回调。
邀请方 被邀请方 步骤 1:调用 RCRTCLocalUser 的 requestJoinOtherRoom发起跨房间连麦邀请步骤 2:在 IRCRTCRoomEventsListener 中收到 onRequestJoinOtherRoom邀请回调步骤 3:调用 RCRTCLocalUser的cancelRequestJoinOtherRoom方法结束之前发起的邀请步骤 4:在 IRCRTCRoomEventsListener 中收到 onCancelRequestOtherRoom取消受邀请的回调 -
场景二:邀请方发起邀请后,被邀请方应答同意。
提示此场景中,被邀请方应答同意。只有被邀请方不会收到应答回调,包含邀请人在内的两个房间中所有非观众用户都会收到代理回调。
邀请方 被邀请方 步骤 1:调用 RCRTCLocalUser 的 requestJoinOtherRoom发起跨房间连麦邀请步骤 2:在 IRCRTCRoomEventsListener 中收到 onRequestJoinOtherRoom邀请回调步骤 4:包含邀请人在内的两个房间中所有非观众用户(不含被邀请方)会在 IRCRTCRoomEventsListener 中收到 onResponseJoinOtherRoom应答回调步骤 3:调用 RCRTCLocalUser 的 responseJoinOtherRoom应答邀请,其中agree参数设为true -
场景三:邀请方发起邀请后,被邀请方应答拒绝。
提示此场景中,被邀请方应答拒绝。只有邀请方会收到应答拒绝回调,其他所有用户都不会收到代理回调。
邀请方 被邀请方 步骤 1:调用 RCRTCLocalUser 的 requestJoinOtherRoom发起跨房间连麦邀请步骤 2:在 IRCRTCRoomEventsListener 中收到 onRequestJoinOtherRoom邀请回调步骤 4:只有邀请方会收到应答拒绝回调;其他用户不会在 IRCRTCRoomEventsListener 中收到 onResponseJoinOtherRoom应答回调步骤 3:调用 RCRTCLocalUser 的 responseJoinOtherRoom应答邀请,其中agree参数设为false
加入副房间流程
-
场景四:基于“场景二”,邀请方在收到应答同意回调后加入被邀请方的房间(副房间);被邀请方在应答同意后加入邀请方的房间(副房间)。
邀请方 被邀请方 步骤 2:在收到被邀请方同意回调后,调用 RCRTCEngine 的 joinOtherRoom加入副房间步骤 1:在应答同意后,调用 RCRTCEngine 的 joinOtherRoom加入副房间 -
场景五:在加入主房间前,主房间的某用户已经与其他房间另一用户成功建立跨房间连麦。
加入主房间成功后,可通过 RCRTCRoom 的
getOtherRoomIds()检查是否存在房间中的用户已经加入的副房 间。如果存在,可选择是否加入其他副房间。Java/**
* 主房间中主播已经加入的副房间 ID 列表
*/
List<String> getOtherRoomIds();跨房间连麦成功后加入主房间的用户 步骤 1:调用 RCRTCEngine 的 joinRoom加入主房间步骤 2:检查发现 getOtherRoomIds()中存在其他副房间步骤 3:调用 RCRTCEngine 的 joinOtherRoom加入副房间
订阅流程
在“场景四”或“场景五”的前提下:
-
场景六:方式一,订阅副房间用户已发布的音视频资源。加入副房间后,通过遍历取得副房间中所有远端用户中的 RCRTCInputStream 列表,再调用 RCRTCLocalUser 的
subscribeStreams订阅副房间中远端用户已经发布的音视频资源。JavaRCRTCEngine.getInstance().joinOtherRoom(roomId, new IRCRTCResultDataCallback<RCRTCOtherRoom>() {
@Override
public void onSuccess(RCRTCOtherRoom rcrtcOtherRoom) {
List<RCRTCInputStream> inputStreamList = new ArrayList<>();
// 遍历远端用户列表
for (int i = 0; i < rcrtcOtherRoom.getRemoteUsers().size(); i++) {
// 遍历远端用户发布的资源列表
for (RCRTCInputStream stream : rcrtcOtherRoom.getRemoteUsers().get(i).getStreams()) {
if (stream.getMediaType() == RCRTCMediaType.VIDEO) {
// 若为视频流,创建显示视图 RCRTCVideoView,并添加到布局中显示
//SurfaceView 类型
RCRTCVideoView videoView = new RCRTCVideoView(this.getApplicationContext());
//5.34.0 版本开始支持 TextureView 类型
//RCRTCTextureView videoView = new RCRTCTextureView(this.getApplicationContext());
((RCRTCVideoInputStream) stream).setVideoView(videoView);
// TODO 示例仅演示添加 1 个远端用户的视图
frameyout_remote.removeAllViews();
frameyout_remote.addView(videoView);
}
// 若要订阅所有远端用户的流,请将其保存,以便统一订阅
inputStreamList.add(stream);
}
}
// 开始订阅资源
RCRTCRoom.getLocalUser().subscribeStreams(inputStreamList, new IRCRTCResultDataCallback<List<RCRTCInputStream>>() {
@Override
public void onSuccess() {
}
@Override
public void onSuccess(List<RCRTCInputStream> data) {
}
@Override
// 如果 SDK ≥ 5.3.4,您可以使用 IRCRTCResultDataCallback,onFailed 方法会返回订阅失败的流列表和错误码。
// 如果 SDK < 5.3.4,仅支持使用 IRCRTCResultCallback,onFailed 方法仅返回错误码。
public void onFailed(List<RCRTCInputStream> failedStreams, RTCErrorCode errorCode) {
}
});
}
@Override
public void onFailed(RTCErrorCode rtcErrorCode) {
}
}); -
场景七:方式二,订阅副房间中“刚发布”的音视频资源。加入副房间后, 当有副房间中远端用户发布资源时,会回调 IRCRTCOtherRoomEventsListener 的
onRemoteUserPublishResource方法,调用 RCRTCLocalUser 的subscribeStreams订阅刚发布的资源。Java@Override
public void onRemoteUserPublishResource(RCRTCOtherRoom rcrtcOtherRoom, RCRTCRemoteUser rcrtcRemoteUser, List<RCRTCInputStream> list) {
// 遍历远端用户发布的资源列表
for (RCRTCInputStream stream : list) {
if (stream.getMediaType() == RCRTCMediaType.VIDEO) {
// 若为视频流,创建显示视图RCRTCVideoView,并添加到布局中显示
RCRTCVideoView remoteView = new RCRTCVideoView(MainActivity.this);
((RCRTCVideoInputStream)stream).setVideoView(remoteView);
frameyout_remote.removeAllViews();
frameyout_remote.addView(remoteView);
}
}
// 开始订阅资源
RCRTCRoom.getLocalUser().subscribeStreams(list, new IRCRTCResultDataCallback<List<RCRTCInputStream>>() {
@Override
public void onSuccess() {
}
@Override
public void onSuccess(List<RCRTCInputStream> data) {
}
@Override
// 如果 SDK ≥ 5.3.4,您可以使用 IRCRTCResultDataCallback,onFailed 方法会返回订阅失败的流列表和错误码。
// 如果 SDK < 5.3.4,仅支持使用 IRCRTCResultCallback,onFailed 方法仅返回错误码。
public void onFailed(List<RCRTCInputStream> failedStreams, RTCErrorCode errorCode) {
}
});
}
离开副房间流程
-
场景八:已加入副房间的用户需要退出副房间时,可调用 RCRTCEngine 的
leaveOtherRoom(String roomId, boolean notifyFinished, IRCRTCResultCallback callBack)方法。提示该方法会自动取消订阅已订阅的副房间所有用户的音视频资源,上层无需手动取消订阅。 当
notifyFinished为false时,仅表示调用方离开副房间;其他用户会在 IRCRTCOtherRoomEventsListener 中收到onUserLeft回调。
@Override
public void onUserLeft(RCRTCOtherRoom rcrtcBaseRoom, RCRTCRemoteUser rcrtcRemoteUser) {
}
-
当
notifyFinished为true时,其他用户会在 IRCRTCOtherRoomEventsListener 中收到onUserLeft,并在 IRCRTCRoomEventsListener 中收到onFinishOtherRoom回调。Java/**
* 用户离开房间
*
* @param rcrtcBaseRoom 加入的其他房间对象
* @param rcrtcRemoteUser 远端用户
*/
@Override
public void onUserLeft(RCRTCOtherRoom rcrtcBaseRoom, RCRTCRemoteUser rcrtcRemoteUser) {
}Java/**
* 收到结束跨房间连麦的通知
*
* @param roomId 结束连麦的房间 ID
* @param userId 发起结束连麦的用户 ID
*/
@Override
public void onFinishOtherRoom(String roomId, String userId) {
super.onFinishOtherRoom(roomId, userId);
}
被服务端踢出房间流程
通过调用服务端 API 可以将指定房间的指定用户踢出该房间。
-
在踢出某个用户之前,建议先通过服务下发消息让该客户端执行结束跨房间连麦,然后再从主房间踢出违禁用户。
-
被踢出的房间是该用户加入的主房间时,RongRTCLib 内部会调用
RCRTCEngine.getInstance().leaveOtherRoom,先退出已加入的副房间,再退出主房间并销毁资源。UI 层无需再次调用离开主/副房间的方法,只需处理上层逻辑。 -
被踢出的房间是该 用户加入的副房间时,服务端操作离开房间,并取消订阅已订阅的该副房间内用户的音视频资源。在 IRCRTCOtherRoomEventsListener 的
onKickedByServer(RCRTCOtherRoom rcrtcBaseRoom)回调中返回房间相关信息,UI 层无需再次调用离开副房间的方法,只需处理上层逻辑。
/**
* 被服务端踢下线
* <p>如果用户在房间内,收到服务器封禁通知时,SDK 会关闭音视频连接并释放资源,将用户踢出房间,并回调通知用户。</p>
*
* @param rcrtcBaseRoom 加入的其他房间对象
*/
@Override
public void onKickedByServer(RCRTCOtherRoom rcrtcBaseRoom) {
super.onKickedByServer(rcrtcBaseRoom);
}