在直播场景下,最新的 RTCLib 5.1.0及以上版本优化了观众订阅主播音视频资源的方式,导致与 RTCLib 5.1.0(不包含5.1.0) 以下版本观众订阅资源方式存在差异:
RTCLib 5.1.0 以下观众订阅方式:
-
主播端需要先加入RTC 房间,然后再和观众端加入同一个 IM 聊天室
-
主播发布资源后,通过设置 IM 聊天室房间属性的方式,将直播 Url 地址扩散给聊天室内的观众端
-
观众端通过监听 IM 聊天室房间属性更新的回调事件得到直播 Url 地址,然后使用直播 Url 地址进行订阅操作
RTCLib 5.1.0及以上观众订阅方式
-
主播端和观众端只需加入同一个 RTC 房间
-
主播端正常发布资源,RTCLib 内部会自动通知 RTCLib 5.1.+ 以上观众
-
观众端加入房间后,通过 RCRTCRoom#getLiveStreams 方法或 IRCRTCRoomEventsListener#onPublishLiveStreams 回调通知方法获得主播发布的音视频资源,然后使用 RCRTCInputStream 方式进行订阅操作
以上就是新老版本观众订阅主播音视频资源方式的差异之处,如果是由 RTCLib 5.1.0(不包含5.1.0) 以下版本升级到 RTCLib 5.1.0 及以上时,如需要兼容旧版本可以参考下面的兼容方案,
主播端
主播端保留现有的代码逻辑,不需要做任何改动
-
主播端通过
RCRTCLocalUser#publishDefaultStreams
方法发布直播资源后拿到 RCRTCLiveInfo#getLiveUrl 直播Url -
通过
RongIMClient#forceSetChatRoomEntry
方法设置 IM 聊天室自定义属性的方式向 IM 聊天室内的观众端扩散直播Url
观众端
1. 观众端加房间
IM 连接成功并初始化 RCRTCEngine后,观众端需要加入和主播端同一个 IM 聊天室 和 RTC 房间,并且需要注册 IM 聊天室房间属性回调事件用于接收主播端通过设置聊天室房间自定义属性方式扩散的直播Url
示例代码
// IM 聊天室房间属性回调事件
RongIMClient.getInstance().setKVStatusListener(new RongIMClient.KVStatusListener() {
/**
* 加入聊天室成功后,SDK 默认从服务端同步 KV 列表,同步完成后触发
*
* @param roomId 聊天室 Id
*/
@Override
public void onChatRoomKVSync(String roomId) {
}
/**
* 更新时全量返回 KV 属性,更新包含新增、修改
*
* @param roomId 聊天室 Id
* @param chatRoomKvMap 发生变化的 KV
*/
@Override
public void onChatRoomKVUpdate(String roomId, Map<String, String> chatRoomKvMap) {
}
/**
* KV 被删除时触发
*
* @param roomId 聊天室 Id
* @param chatRoomKvMap 被删除的 KV
*/
@Override
public void onChatRoomKVRemove(String roomId, Map<String, String> chatRoomKvMap) {
}
});
//加入 IM 聊天室
RongIMClient.getInstance().joinChatRoom(chatroomId, defMessageCount, new RongIMClient.OperationCallback() {
/**
* 成功回调
*/
@Override
public void onSuccess() {
}
/**
* 失败回调
* @param errorCode 错误码
*/
@Override
public void onError(RongIMClient.ErrorCode errorCode) {
}
});
//加入 RTC 房间
//设置房间配置:包括房间类型以及角色信息
RCRTCRoomConfig roomConfig = Builder.create()
.setLiveRole(RCRTCLiveRole.AUDIENCE)
//根据实际场景,选择音视频直播:LIVE_AUDIO_VIDEO 或音频直播:LIVE_AUDIO
.setRoomType(RCRTCRoomType.LIVE_AUDIO_VIDEO)
.build();
RCRTCEngine.getInstance().joinRoom(roomId, roomConfig, new IRCRTCResultDataCallback<RCRTCRoom>() {
@Override
public void onSuccess(RCRTCRoom data) {
}
@Override
public void onFailed(RTCErrorCode errorCode) {
}
});
2. 观众端订阅资源
观众端在加入 RTC 房间后,订阅资源可以分为两种方式:
使用直播 Url 方式 进行订阅,这种方式是 RTCLib 5.1.0 以下版本使用的,如果房间内只有 RTCLib 5.1.0 以下版本的主播,则只能使用这种方式订阅
使用 RCRTCInputStream 方式订阅,这种方式是 RTCLib 5.1.0 及以上版本才可以使用的
使用直播Url方式订阅,示例代码
// 必须加入 RTC 房间后才可以获得 RCRTCRoom 对象
RCRTCRoom rtcRoom = RCRTCEngine.getInstance().getRoom();
//liveUrl 是通过注册 IM 聊天室自定义属性回调中获取的
rtcRoom.getLocalUser().subscribeLiveUrl(liveUrl,avStreamType,new RCRTCLiveCallback() {
@Override
public void onSuccess() {
//订阅成功,后续会根据订阅的类型,触发 onAudioStreamReceived 和 onVideoStreamReceived方法
}
@Override
public void onVideoStreamReceived(final RCRTCVideoInputStream stream) {
//收到视频流。操作UI需要转到 UI 线程
runOnUiThread(new Runnable() {
@Override
public void run() {
//创建 RCRTCVideoView
RCRTCVideoView videoView = new RCRTCVideoView(getApplicationContext());
//给input stream设置用于显示视频的视图
stream.setVideoView(videoView);
//将 RCRTCVideoView 添加到自己的Layout容器中
mFrameLayout_remote.addView(videoView);
}
});
}
@Override
public void onAudioStreamReceived(RCRTCAudioInputStream stream) {
//收到音频流
}
@Override
public void onFailed(RTCErrorCode errorCode) {
//订阅失败, 详情查看 errorCode
}
});
使用 RCRTCInputStream 方式订阅,示例代码
// 必须加入 RTC 房间后才可以获得 RCRTCRoom 对象
RCRTCRoom rtcRoom = RCRTCEngine.getInstance().getRoom();
List<RCRTCInputStream> liveStreams = rtcRoom.getLiveStreams();
//设置要订阅大流或小流,以及绑定VideoView
for (RCRTCInputStream inputStream : liveStreams) {
if (inputStream.getMediaType() == RCRTCMediaType.VIDEO) {
//选择订阅大流或是小流。默认小流
((RCRTCVideoInputStream) inputStream).setStreamType(RCRTCStreamType.NORMAL);
//创建VideoView并设置到stream
RCRTCVideoView videoView = new RCRTCVideoView(getApplicationContext());
((RCRTCVideoInputStream) inputStream).setVideoView(videoView);
//将VideoView添加至布局
frameyout_remoteUser.addView(videoView);
}
}
//执行订阅资源方法
rtcRoom.getLocalUser().subscribeStreams(liveStreams, new IRCRTCResultCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(RTCErrorCode errorCode) {
}
});