收发流消息
流消息是沿指定的 stream_id 传输的业务自定义字节数据。你可以把它理解成“附着在某一条 stream 上的轻量消息帧”:它不是独立的命令通道,也不替代正常的音视频流发布或订阅。
它适合把轻量消息和某一条音视频或某个业务流一起理解,例如探测时间戳、状态提示、字幕片段或叠字文本。
这页只覆盖“连接已经建立之后,如何把设备端和客户端的流消息串起来”。如果你还没完成建连,先看建立连接;如果你需要请求/应答语义、命令编号或业务状态控制,优先看收发命令。
什么时候用流消息
适合:
- 你已经有一条可用连接,只想附带发送少量业务数据。
- 这条消息需要和某个
stream一起理解,例如“这是主视频流的探针消息”。 - 你的业务自己能约定 payload 格式,例如 UTF-8 文本、JSON 或其他自定义二进制格式。
不适合:
- 需要明确的请求/应答关系、命令字或业务状态机。
- 需要传大包、离线消息或长期存储的业务数据。
- 需要替代正常的音视频流发布或订阅流程。
开始前先约定
- 设备端已经完成
TiRtcStart(),并收到TiEVENT_SYS_STARTED。 - 客户端已经完成连接,并持有当前链路对应的
conn实例。 - 双端先约定好 payload 格式。下面示例统一使用 UTF-8 文本,方便直接验证。
- 双端先约定好消息使用的
stream_id。
先理解这条链路
- 设备端发送时,调用
TiRtcSendMessageStream(),并把TIRTCFRAMEINFO.media设为TIRTC_MEDIA_MESSAGE。 - 客户端收到后,会在
onStreamMessage或对应 delegate 回调里拿到streamId、timestampMs和原始字节数据。 - 双端按事先约定的
stream_id和 payload 格式解析这条消息。
设备端发送时通过 TIRTCFRAMEINFO.ts 填入毫秒时间戳;客户端收到时,会在回调参数 timestampMs 里拿到同一个值。TiRTC 会把这个值传到对端,具体业务含义仍由你自己约定。
设备端发送流消息
设备端 C SDK 用 TiRtcSendMessageStream() 发送流消息。关键点只有三个:
media必须是TIRTC_MEDIA_MESSAGE。length必须等于 payload 的实际字节数。- 如果你的业务把消息附着在某一条媒体语义上,就让
stream_id和那一条保持同一套约定;如果只是做独立探针,也可以单独约定一个消息stream_id。
c
#include <stdint.h>
#include <string.h>
static uint32_t now_ms(void);
static int send_probe_message(tirtc_conn_t hconn) {
const char *payload = "device-probe seq=1";
TIRTCFRAMEINFO fi = {
.stream_id = 3,
.media = TIRTC_MEDIA_MESSAGE,
.flags = 0,
.reserved = 0,
.ts = now_ms(),
.length = (uint32_t)strlen(payload),
};
return TiRtcSendMessageStream(hconn, &fi, payload);
}如果 stream_id = 3 代表“主视频相关探针”,那客户端收到 streamId == 3 时,就能按同一套业务约定解析它。
客户端接收设备端流消息
下面只保留和流消息有关的核心代码,默认 conn 已经是当前链路对应的连接实例。
kotlin
conn.onStreamMessage =
TiRtcConnStreamMessageListener { streamId, timestampMs, data ->
val text = data.toString(Charsets.UTF_8)
Log.i(
"TiRTC",
"recv stream message streamId=$streamId timestampMs=$timestampMs text=$text",
)
}swift
final class SessionController: NSObject, TiRtcConnDelegate {
func conn(
_ conn: TiRtcConn,
didReceiveStreamMessage streamId: UInt8,
timestampMs: UInt32,
data: Data
) {
let text = String(decoding: data, as: UTF8.self)
print("recv stream message streamId=\(streamId) timestampMs=\(timestampMs) text=\(text)")
}
}dart
conn.onStreamMessage = (streamId, timestampMs, data) {
final String text = utf8.decode(data);
debugPrint(
'recv stream message streamId=$streamId timestampMs=$timestampMs text=$text',
);
};上面三个示例都假设 payload 是 UTF-8 文本。如果你的业务发的是 JSON 或其他自定义二进制格式,就在回调里按你们自己的协议解析 data。
常见问题
设备端已经发送,但客户端没有收到
先检查三件事:
- 设备端发送时使用的
stream_id,是否和客户端按业务约定解析的是同一条。 - payload 编码是否一致,例如设备端按 UTF-8 文本发,客户端却按二进制结构体读。
- 是否是在当前这条连接已经建立之后才发送。
你其实需要的是命令语义,不是流消息
如果你要的是命令编号、请求应答、乱序响应匹配或明确的业务控制语义,优先走收发命令,不要把这些语义硬塞进流消息 payload。