Skip to content

收发命令

命令收发是在一条已建立的 TiRTC 连接上发送业务控制数据。它适合表达“让对端做一件事”,例如请求设备状态、下发控制指令、回传处理结果。

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

它和收发流消息不同:流消息附着在某一条 stream_id 上;命令消息不依附音视频流,更适合控制指令和业务状态机。

先约定 cmdw

cmdw 是 command word 的缩写,可以理解成“命令字”:一个由你和对端共同约定的 32 位无符号整数。TiRTC 只负责把这个值和 payload 原样送到对端,不解释它的业务含义。 cmdw 的原始取值范围是闭区间 0x100000xFFFFFFFF

下文用这一组命令字演示请求和响应:

cmdw作用
0x10000请求设备状态
0x10002返回设备状态结果

下面示例统一使用 UTF-8 文本 payload。真实业务里可以换成 JSON、Protobuf 或你自己的二进制格式,只要两端约定一致。

发送端:发送请求命令

发送端只需要拿到当前连接对象,调用对应平台的发送接口,把 cmdw 和 payload 发出去。

dart
import 'dart:convert';
import 'dart:typed_data';

const int cmdwGetDeviceStatus = 0x10000;

final Uint8List payload = Uint8List.fromList(utf8.encode('status?'));
final int code = conn.sendCommand(commandId: cmdwGetDeviceStatus, data: payload);
if (code != 0) {
  debugPrint('send command failed: $code');
}
kotlin
private const val CMDW_GET_DEVICE_STATUS = 0x10000L

val payload = "status?".encodeToByteArray()
val code = conn.sendCommand(command = CMDW_GET_DEVICE_STATUS, data = payload)
if (code != 0) {
  Log.w("TiRTC", "send command failed code=$code")
}
swift
private let CMDW_GET_DEVICE_STATUS: UInt32 = 0x10000

let payload = Data("status?".utf8)
let code = conn.send(commandId: CMDW_GET_DEVICE_STATUS, data: payload)
if code != 0 {
    print("send command failed: \(code)")
}
c
#include <stdint.h>
#include <string.h>

static const uint32_t CMDW_GET_DEVICE_STATUS = 0x10000;

int request_device_status(tirtc_conn_t hconn)
{
    const char *payload = "status?";
    return TiRtcSendCommand(
        hconn,
        CMDW_GET_DEVICE_STATUS,
        payload,
        (uint32_t)strlen(payload));
}

接收端:处理命令并返回结果

接收端在命令回调里判断 cmdw,解析 payload,然后按业务约定决定是否回发另一条命令。下面示例收到 0x10000 后,用 0x10002 返回 device-ok

dart
import 'dart:convert';
import 'dart:typed_data';

const int cmdwGetDeviceStatus = 0x10000;
const int cmdwDeviceStatusResult = 0x10002;

conn.onCommand = (int commandId, Uint8List data) {
  if (commandId != cmdwGetDeviceStatus) return;

  final String request = utf8.decode(data);
  if (request != 'status?') return;

  final Uint8List response = Uint8List.fromList(utf8.encode('device-ok'));
  final int code = conn.sendCommand(commandId: cmdwDeviceStatusResult, data: response);
  if (code != 0) {
    debugPrint('send command response failed: $code');
  }
};
kotlin
private const val CMDW_GET_DEVICE_STATUS = 0x10000L
private const val CMDW_DEVICE_STATUS_RESULT = 0x10002L

conn.onCommand = TiRtcConnCommandListener { command, data ->
  if (command != CMDW_GET_DEVICE_STATUS) return@TiRtcConnCommandListener

  val request = data.decodeToString()
  if (request != "status?") return@TiRtcConnCommandListener

  val response = "device-ok".encodeToByteArray()
  val code = conn.sendCommand(command = CMDW_DEVICE_STATUS_RESULT, data = response)
  if (code != 0) {
    Log.w("TiRTC", "send command response failed code=$code")
  }
}
swift
private let CMDW_GET_DEVICE_STATUS: UInt32 = 0x10000
private let CMDW_DEVICE_STATUS_RESULT: UInt32 = 0x10002

func conn(_ conn: TiRtcConn, didReceiveCommand commandId: UInt32, data: Data) {
    guard commandId == CMDW_GET_DEVICE_STATUS else { return }

    let request = String(decoding: data, as: UTF8.self)
    guard request == "status?" else { return }

    let response = Data("device-ok".utf8)
    let code = conn.send(commandId: CMDW_DEVICE_STATUS_RESULT, data: response)
    if code != 0 {
        print("send command response failed: \(code)")
    }
}
c
#include <stdint.h>
#include <string.h>

static const uint32_t CMDW_GET_DEVICE_STATUS = 0x10000;
static const uint32_t CMDW_DEVICE_STATUS_RESULT = 0x10002;

static void on_command(tirtc_conn_t hconn, uint32_t cmdw, const void *data, uint32_t len)
{
    const char *request = "status?";

    if (cmdw != CMDW_GET_DEVICE_STATUS ||
        data == NULL ||
        len != (uint32_t)strlen(request) ||
        memcmp(data, request, len) != 0) {
        return;
    }

    const char *response = "device-ok";
    TiRtcSendCommand(
        hconn,
        CMDW_DEVICE_STATUS_RESULT,
        response,
        (uint32_t)strlen(response));
}

如果这条命令不需要响应,接收端处理完后可以直接结束,不必再回发另一条命令。需要请求/响应配对、超时重试或乱序应答时,在业务协议里继续定义序号或使用设备端 C SDK 的命令字辅助宏。

常见问题

发送成功,但对端没有进入预期分支

先检查这三项:

  • 双端比较的是不是同一个原始 cmdw,例如都使用 0x10000
  • payload 编码是否一致,例如两端都按 UTF-8 文本处理。
  • 发送使用的是否是当前这条连接对应的 connhconn

cmdw 和客户端 SDK 的 commandId 是不是一回事

是同一个原始值。Flutter 和 iOS 的公开参数名叫 commandId,Android 叫 command,设备端 C SDK 叫 cmdw。写业务协议时建议统一记录为 cmdw,实现时按各平台真实 API 名称传入。

什么时候改用流消息

如果你的数据需要跟某一条 stream_id 一起理解,而不是表达一个明确的业务命令,改看收发流消息

相关文档

TiRTC 开发文档