收发流消息
流消息是在一条已建立的 TiRTC 连接上,沿指定 stream_id 传输的业务自定义字节数据。它适合表达“这段轻量数据属于某一路流”,例如主视频探针、字幕片段、叠字文本或和某路音视频同步的状态提示。
流消息也是对等能力:发送端和接收端可以是客户端,也可以是设备端。只要两端已经建立连接,Android、iOS、Flutter 和 C 侧拿到的连接对象都可以发送或接收流消息。
如果你需要的是明确的请求/响应、命令编号或业务控制语义,优先看收发命令。如果你还没完成建连,先看连接设备端。
先约定 stream_id
stream_id 标识同一条连接里的某一路 stream。流消息是一种带 stream_id 的业务自定义消息帧,不是命令通道。C SDK 当前公开约束是:
- 取值范围是
0到15。 - 同一条连接内,音频和视频不能共用同一个
stream_id。 - 流消息可以放在任意
stream_id上:可以复用某一路已有音视频stream_id,也可以使用双方专门为消息约定的stream_id。
下面示例使用 stream_id = 3 发送一条 UTF-8 文本消息。真实业务里可以换成 JSON、Protobuf 或自定义二进制格式,只要两端约定一致。
发送端:发送流消息
发送端需要提供三件事:stream_id、毫秒时间戳和 payload。
dart
import 'dart:convert';
import 'dart:typed_data';
const int streamIdProbe = 3;
final int timestampMs = DateTime.now().millisecondsSinceEpoch & 0xFFFFFFFF;
final Uint8List payload = Uint8List.fromList(utf8.encode('probe seq=1'));
final int code = conn.sendStreamMessage(
streamId: streamIdProbe,
timestampMs: timestampMs,
data: payload,
);
if (code != 0) {
debugPrint('send stream message failed: $code');
}kotlin
private const val STREAM_ID_PROBE = 3
val timestampMs = System.currentTimeMillis() and 0xFFFF_FFFFL
val payload = "probe seq=1".encodeToByteArray()
val code = conn.sendStreamMessage(
streamId = STREAM_ID_PROBE,
timestampMs = timestampMs,
data = payload,
)
if (code != 0) {
Log.w("TiRTC", "send stream message failed code=$code")
}swift
private let streamIdProbe: UInt8 = 3
let timestampMs = UInt32(truncatingIfNeeded: UInt64(Date().timeIntervalSince1970 * 1000))
let payload = Data("probe seq=1".utf8)
let code = conn.sendStreamMessage(timestampMs: timestampMs, data: payload, streamId: streamIdProbe)
if code != 0 {
print("send stream message failed: \(code)")
}c
#include <stdint.h>
#include <string.h>
#include "tiRTC.h"
static const uint8_t STREAM_ID_PROBE = 3;
static uint32_t now_ms(void);
int send_probe_message(tirtc_conn_t hconn)
{
const char *payload = "probe seq=1";
TIRTCFRAMEINFO fi;
memset(&fi, 0, sizeof(fi));
fi.stream_id = STREAM_ID_PROBE;
fi.media = TIRTC_MEDIA_MESSAGE;
fi.ts = now_ms();
fi.length = (uint32_t)strlen(payload);
return TiRtcSendMessageStream(hconn, &fi, payload);
}设备端 C SDK 发送流消息时,TIRTCFRAMEINFO.media 必须设为 TIRTC_MEDIA_MESSAGE,length 必须等于 payload 的实际字节数。
接收端:接收并解析流消息
接收端会拿到发送端传来的 stream_id、时间戳和 payload。下面示例按 UTF-8 文本解析。
dart
import 'dart:convert';
import 'dart:typed_data';
conn.onStreamMessage = (int streamId, int timestampMs, Uint8List data) {
final String text = utf8.decode(data);
debugPrint('stream=$streamId timestampMs=$timestampMs text=$text');
};kotlin
conn.onStreamMessage = TiRtcConnStreamMessageListener { streamId, timestampMs, data ->
val text = data.toString(Charsets.UTF_8)
Log.i("TiRTC", "stream=$streamId timestampMs=$timestampMs text=$text")
}swift
func conn(_ conn: TiRtcConn, didReceiveStreamMessage timestampMs: UInt32, data: Data, streamId: UInt8) {
let text = String(decoding: data, as: UTF8.self)
print("stream=\(streamId) timestampMs=\(timestampMs) text=\(text)")
}c
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "tiRTC.h"
static void on_message(tirtc_conn_t hconn, const TIRTCFRAMEINFO *fi, void *data)
{
(void)hconn;
if (fi == NULL || data == NULL || fi->media != TIRTC_MEDIA_MESSAGE) {
return;
}
char text[128] = {0};
uint32_t n = fi->length < (uint32_t)(sizeof(text) - 1)
? fi->length
: (uint32_t)(sizeof(text) - 1);
memcpy(text, data, n);
printf("stream=%u timestampMs=%u text=%s\n", fi->stream_id, fi->ts, text);
}常见问题
发送成功,但对端没有按预期解析
先检查这三项:
- 双端使用的是不是同一个
stream_id。 - payload 编码是否一致,例如两端都按 UTF-8 文本处理。
- 发送使用的是否是当前这条连接对应的
conn或hconn。
什么时候改用命令
如果你要表达“请求设备状态”“下发控制指令”“等待对端返回处理结果”,改看收发命令。不要把请求/响应语义硬塞进流消息 payload。