在音视频流媒体应用中,除了可以收发音视频内容外,可能还需要收发一些与音视频内容同步的文本消息。
你可以 H.264 视频流中插入 SEI (Supplemental Enhancement Information,媒体补充增强信息),并在订阅端接收这些信息。
此外,你也可以通过音频 RTP 扩展头发送数据信息。
在线 K 歌场景中,用于同步歌词,进度等。
连麦 PK 场景中,两个直播主播发起 PK 活动,观众感知当前的流画面是否连麦 PK,加载或卸载 PK 场景。基于 SEI 实时展示 PK 血条。
连麦游戏中
通过 SEI 来传输压缩后的人脸识别算法数据,对端通过这些数据进行相应的特效绘制。
直播答题,主持人口播题目时,题目信息可以同步传到远端,用户可以通过互动提交答案。
观众感知流画面的布局信息,判断有无嘉宾,加载或卸载嘉宾麦位组件。
获取每路流的音量信息,并在合流转推中,显示用户音量。
使用自定义编解码器时,用来传递编码器参数。
使用自定义视频采集时,用来传递摄像头参数。
你已经集成 RTC SDK,实现了基本的音视频通话。
根据你的业务要求,选择适用的实现方案。
通过 SDK 内部视频采集时,可在视频、纯音频应用插入多种客户端的信息,例如歌词、进度、题目等。
在转推直播场景中,通过本方案添加的 SEI 也将被透传到合流中,可用于显示各自的音量、PK 血条等。
确保当前使用内部视频采集模块: VIDEO_SOURCE_TYPE_INTERNAL。默认为内部采集,如果当前为外部采集应先调用 setVideoSourceType 设置视频源及屏幕流。
发送端调用 SEI 发送接口 sendSEIMessage,随视频帧发送 SEI。
对于纯音频应用,SDK 将自动生成视频黑帧,用于携带 SEI 消息。手动发布模式下,需要手动发布该黑帧视频流。
- 支持 4KB 长度
- 支持消息重发
- 以视频 15 fps 为例,同步精度为 0~66 ms,如对精度有更高要求,请参看 通过音频 RTP 扩展头 。
// 创建引擎 EngineConfig config = new EngineConfig(); config.appID = appId; config.context = applicationContext; rtcEngine = RTCEngine.createRTCEngine(config, rtcEngineEventHandler); // 开启音视频采集 rtcEngine.startAudioCapture(); rtcEngine.startVideoCapture(); // 插入 SEI rtcEngine.sendSEIMessage(msg.getBytes(StandardCharsets.UTF_8), 3, SEICountPerFrame.SEI_COUNT_PER_FRAME_SINGLE);
接收端会收到 SEI 回调: onSEIMessageReceived
对于纯音频应用,通过黑帧视频流发送 SEI 数据时。流的发送状态会通过 onSEIStreamUpdate 通知远端用户。 手动订阅模式下,需要订阅该黑帧视频流。
IRTCEngineEventHandler rtcEngineEventHandler = new IRTCEngineEventHandler() { @Override public void onSEIMessageReceived(String streamId, StreamInfo streamInfo, ByteBuffer message) { // 处理接收到的 SEI,以下为示例 Charset charset = Charset.defaultCharset(); String dataString = charset.decode(message).toString(); ToastUtil.showLongToast(SEIMessageActivity.this, "onSEIMessageReceived:" + dataString); } };
纯音频通话应用除了可以采用通用方案通过黑帧发送 SEI,也可以通过音频 RTP 扩展头发送数据信息。本方案可实现比通用方案更高的同步精度,理论上可以做到 0~20ms。

- 支持的最大 SEI 传输长度为 255B,如对消息长度有更高要求,请参看通用方案。
- RTC 用户的 SEI 数据不会推到 CDN 流中。
- 调用频率为单个 SDK 50 次每秒。
private void sendMsg(String msg) { StreamSyncInfoConfig config = new StreamSyncInfoConfig(0, StreamSyncInfoConfig.SyncInfoStreamType.SYNC_INFO_STREAM_TYPE_AUDIO); // 0 表示不重复 rtcEngine.sendStreamSyncInfo(msg.getBytes(StandardCharsets.UTF_8), config); }
IRTCEngineEventHandler rtcEngineEventHandler = new IRTCEngineEventHandler() { @Override public void onStreamSyncInfoReceived(String streamId, StreamInfo streamInfo, StreamSyncInfoConfig.SyncInfoStreamType streamType, ByteBuffer data) { // 处理接收到的 SEI super.onStreamSyncInfoReceived(streamKey, streamType, data); Charset charset = Charset.defaultCharset(); String dataString = charset.decode(data).toString(); } };
随合流视频发送 SEI,适合更新频率低的信息,例如用户主播人数变化后切换布局、放置 PK 血条位置等。
转推直播的集成指南和完整示例代码参见转推直播。本节将着重介绍转推直播中的 SEI 插入和提取。
更新频率高的消息,例如音量、PK 血条等信息,建议在各嘉宾的客户端添加,参考通用方案。
app_data。{ "app_data": "自定义消息", "canvas": { "bgnd": "#000000", "h": 640, "w": 360 }, "regions": [ { "alpha": 1.0, "contentControl": 0, "height": 640, "locationX": 0, "locationY": 50, "renderMode": 1, "uid": "user_343", "width": 360, "zorder": 0 } ], "ts": 1705994199709 }
合流的布局更新通知,也将通过 SEI 。
const list = [ { "lang": "java", "text": `MixedStreamConfig mixedStreamConfig = new MixedStreamConfig(); mixedStreamConfig.userID = localUid; mixedStreamConfig.roomID = roomID; mixedStreamConfig.backgroundColor = "0x00000000"; mixedStreamConfig.regions = getLayoutRegions(); // 合流用户透传的额外数据,通过拉流端 SEI 接收 mixedStreamConfig.userConfigExtraInfo = msg;`, "selected": true, }, { "lang": "swift", "text": `self.mixedStreamConfig?.roomID = roomId! self.mixedStreamConfig?.userID = userId! self.mixedStreamConfig?.backgroundColor = "#FFFFFF" self.mixedStreamConfig?.regions = self.getMixRegions() // 合流用户透传的额外数据,通过拉流端 SEI 接收 self.mixedStreamConfig?.userConfigExtraInfo = msg "" }, { "lang": "cpp", "text": ` bytertc::IMixedStreamConfig* mixed_stream_param = bytertc::IMixedStreamConfig::createMixedStreamConfig(); mixed_stream_param->setUserConfigExtraInfo(app_data.c_str()); //设置SEI信息 mixed_stream_param->setAudioConfig(audioParam); mixed_stream_param->setVideoConfig(videoParam); mixed_stream_param->setLayoutConfig(layouts, 1); mixed_stream_param->setRoomID(m_roomid.c_str()); mixed_stream_param->setUserID(m_uid.c_str());`, }, ] return (<PreCodeTabs list={list} />);
onSEIMessageReceived 回调,如何获取 SEI 信息?只有通过 sendSEIMessage 发送 SEI 消息时,才能通过 onSEIMessageReceived 获取 SEI。
onSEIMessageReceived 回调?在纯音频通话下调用 sendSEIMessage 发送 SEI 时, SDK 将自动生成黑帧视频流。如果当前的发布、订阅模式为手动,需要分别发布和订阅携带 SEI 的黑帧视频流。否则,将无法收到 onSEIMessageReceived 回调。
当前不支持通过服务端 Open API 插入 SEI,仅支持在客户端发送 SEI。具体实现方式,请参考转推直播方案。