Skip to content

收发流消息

流消息是沿指定的 stream_id 传输的业务自定义字节数据。你可以把它理解成“附着在某一条 stream 上的轻量消息帧”:它不是独立的命令通道,也不替代正常的音视频流发布或订阅。

它适合把轻量消息和某一条音视频或某个业务流一起理解,例如探测时间戳、状态提示、字幕片段或叠字文本。

这页只覆盖“连接已经建立之后,如何把设备端和客户端的流消息串起来”。如果你还没完成建连,先看建立连接;如果你需要请求/应答语义、命令编号或业务状态控制,优先看收发命令

什么时候用流消息

适合:

  • 你已经有一条可用连接,只想附带发送少量业务数据。
  • 这条消息需要和某个 stream 一起理解,例如“这是主视频流的探针消息”。
  • 你的业务自己能约定 payload 格式,例如 UTF-8 文本、JSON 或其他自定义二进制格式。

不适合:

  • 需要明确的请求/应答关系、命令字或业务状态机。
  • 需要传大包、离线消息或长期存储的业务数据。
  • 需要替代正常的音视频流发布或订阅流程。

开始前先约定

  • 设备端已经完成 TiRtcStart(),并收到 TiEVENT_SYS_STARTED
  • 客户端已经完成连接,并持有当前链路对应的 conn 实例。
  • 双端先约定好 payload 格式。下面示例统一使用 UTF-8 文本,方便直接验证。
  • 双端先约定好消息使用的 stream_id

先理解这条链路

  1. 设备端发送时,调用 TiRtcSendMessageStream(),并把 TIRTCFRAMEINFO.media 设为 TIRTC_MEDIA_MESSAGE
  2. 客户端收到后,会在 onStreamMessage 或对应 delegate 回调里拿到 streamIdtimestampMs 和原始字节数据。
  3. 双端按事先约定的 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。

相关文档

Ti RTC 开发文档