Skip to content

收发流消息

流消息是在一条已建立的 TiRTC 连接上,沿指定 stream_id 传输的业务自定义字节数据。它适合表达“这段轻量数据属于某一路流”,例如主视频探针、字幕片段、叠字文本或和某路音视频同步的状态提示。

流消息也是对等能力:发送端和接收端可以是客户端,也可以是设备端。只要两端已经建立连接,Android、iOS、Flutter 和 C 侧拿到的连接对象都可以发送或接收流消息。

如果你需要的是明确的请求/响应、命令编号或业务控制语义,优先看收发命令。如果你还没完成建连,先看连接设备端

先约定 stream_id

stream_id 标识同一条连接里的某一路 stream。流消息是一种带 stream_id 的业务自定义消息帧,不是命令通道。C SDK 当前公开约束是:

  • 取值范围是 015
  • 同一条连接内,音频和视频不能共用同一个 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_MESSAGElength 必须等于 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 文本处理。
  • 发送使用的是否是当前这条连接对应的 connhconn

什么时候改用命令

如果你要表达“请求设备状态”“下发控制指令”“等待对端返回处理结果”,改看收发命令。不要把请求/响应语义硬塞进流消息 payload。

相关文档

TiRTC 开发文档