收发命令
命令收发是在一条已建立的 TiRTC 连接上收发业务控制数据的方式。它适合表达“发一个命令,对端按这个命令处理”,例如请求状态、执行控制、回传处理结果。
基于同一条已建立连接,命令收发天然就是双向的:
- 客户端可以向设备端发送命令,设备端按约定处理,并按约定决定是否回发结果。
- 设备端也可以向客户端发送命令,客户端按约定处理,并按约定决定是否回发结果。
它和收发流消息不同:流消息更适合附着在某一条 stream 上发送轻量业务数据;如果你要的是“发一个命令,对端按这个命令处理”,优先用命令收发。
什么时候用命令收发
适合:
- 你要在设备端和客户端之间传递控制类数据。
- 你已经知道这条消息对应什么业务动作,例如“请求状态”或“执行开关”。
- 你希望双方都按约定好的
cmdw进入对应分支。
不适合:
- 你要传的是附着在某一条
stream上的轻量业务数据。 - 你要传大包、离线消息或长期存储的数据。
- 你需要的不是命令语义,而是媒体侧的附带消息能力。
开始前先约定
- 双方已经基于同一条连接互通。设备端已经拿到当前链路对应的
hconn;客户端已经拿到当前链路对应的conn实例。 - 双端已经约定好 payload 格式。下面示例统一使用 UTF-8 文本。
- 双端已经约定好业务使用的
cmdw。 - 如果你的链路里包含设备端 C SDK,自定义
cmdw的原始取值范围是闭区间0x2000到0xFFFFFFFF。
怎么理解 cmdw
在这页里,你可以把 cmdw 直接理解成双方约定好的 32 位字面值。
发送侧传入什么 cmdw,接收侧就会收到同一个 cmdw。TiRTC 负责把这个 cmdw 和对应 payload 传到对端;至于这个值表示“请求”“响应”还是“单向通知”,由你的业务协议自己约定。
客户端向设备端发送命令
下面这组 cmdw 表示“客户端请求设备状态,设备端返回状态结果”:
cmdw | 作用 |
|---|---|
0x2000 | 请求设备状态 |
0x2002 | 返回设备状态结果 |
客户端发送命令并接收结果
下面的片段只保留命令处理本身,默认 conn 已经是当前链路对应的连接实例;iOS 只展示和命令收发直接相关的代码。
kotlin
private const val CMDW_GET_DEVICE_STATUS = 0x2000L
private const val CMDW_DEVICE_STATUS_RESULT = 0x2002L
conn.onCommand =
TiRtcConnCommandListener { cmdw, data ->
if (cmdw == CMDW_DEVICE_STATUS_RESULT) {
val text = data.decodeToString()
Log.i("TiRTC", "device status=$text")
}
}
val code = conn.sendCommand(
cmdw = CMDW_GET_DEVICE_STATUS,
data = "status?".encodeToByteArray(),
)
if (code != 0) {
Log.w("TiRTC", "send command failed code=$code")
}swift
private let CMDW_GET_DEVICE_STATUS: UInt32 = 0x2000
private let CMDW_DEVICE_STATUS_RESULT: UInt32 = 0x2002
func requestDeviceStatus(on conn: TiRtcConn) {
let code = conn.sendCommand(cmdw: CMDW_GET_DEVICE_STATUS, data: Data("status?".utf8))
if code != 0 {
print("send command failed: \(code)")
}
}
func conn(_ conn: TiRtcConn, didReceiveCommand cmdw: UInt32, data: Data) {
if cmdw == CMDW_DEVICE_STATUS_RESULT {
let text = String(decoding: data, as: UTF8.self)
print("device status=\(text)")
}
}dart
import 'dart:convert';
import 'dart:typed_data';
const int cmdwGetDeviceStatus = 0x2000;
const int cmdwDeviceStatusResult = 0x2002;
conn.onCommand = (cmdw, data) {
if (cmdw == cmdwDeviceStatusResult) {
final String text = utf8.decode(data);
debugPrint('device status=$text');
}
};
final int code = conn.sendCommand(
cmdw: cmdwGetDeviceStatus,
data: Uint8List.fromList(utf8.encode('status?')),
);
if (code != 0) {
debugPrint('send command failed: $code');
}设备端接收命令并按约定回发结果
c
#include <stdint.h>
#include <string.h>
enum {
CMDW_GET_DEVICE_STATUS = 0x2000,
CMDW_DEVICE_STATUS_RESULT = 0x2002,
};
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));
}如果这条命令不需要响应,设备端处理完后可以直接结束,不必再回发另一条命令。
设备端向客户端发送命令
下面这组 cmdw 表示“设备端请求客户端状态,客户端返回状态结果”:
cmdw | 作用 |
|---|---|
0x2004 | 请求客户端状态 |
0x2006 | 返回客户端状态结果 |
设备端发送命令并接收结果
c
#include <stdint.h>
#include <stdio.h>
#include <string.h>
enum {
CMDW_GET_CLIENT_STATUS = 0x2004,
CMDW_CLIENT_STATUS_RESULT = 0x2006,
};
static int request_client_status(tirtc_conn_t hconn) {
const char *payload = "client-status?";
return TiRtcSendCommand(
hconn,
CMDW_GET_CLIENT_STATUS,
payload,
(uint32_t)strlen(payload));
}
static void on_command(
tirtc_conn_t hconn,
uint32_t cmdw,
const void *data,
uint32_t len) {
(void)hconn;
if (cmdw != CMDW_CLIENT_STATUS_RESULT || data == NULL) {
return;
}
char text[128] = {0};
uint32_t n = len < (uint32_t)(sizeof(text) - 1)
? len
: (uint32_t)(sizeof(text) - 1);
memcpy(text, data, n);
printf("client status=%s\n", text);
}客户端接收命令并按约定回发结果
下面的片段只保留命令处理本身,默认 conn 已经是当前链路对应的连接实例;iOS 只展示和命令收发直接相关的代码。
kotlin
private const val CMDW_GET_CLIENT_STATUS = 0x2004L
private const val CMDW_CLIENT_STATUS_RESULT = 0x2006L
conn.onCommand =
TiRtcConnCommandListener { cmdw, data ->
if (cmdw == CMDW_GET_CLIENT_STATUS) {
val response = "foreground".encodeToByteArray()
val code = conn.sendCommand(cmdw = CMDW_CLIENT_STATUS_RESULT, data = response)
if (code != 0) {
Log.w("TiRTC", "send response failed code=$code")
}
}
}swift
private let CMDW_GET_CLIENT_STATUS: UInt32 = 0x2004
private let CMDW_CLIENT_STATUS_RESULT: UInt32 = 0x2006
func conn(_ conn: TiRtcConn, didReceiveCommand cmdw: UInt32, data: Data) {
if cmdw == CMDW_GET_CLIENT_STATUS {
let response = Data("foreground".utf8)
let code = conn.sendCommand(cmdw: CMDW_CLIENT_STATUS_RESULT, data: response)
if code != 0 {
print("send response failed: \(code)")
}
}
}dart
import 'dart:convert';
import 'dart:typed_data';
const int cmdwGetClientStatus = 0x2004;
const int cmdwClientStatusResult = 0x2006;
conn.onCommand = (cmdw, data) {
if (cmdw == cmdwGetClientStatus) {
final int code = conn.sendCommand(
cmdw: cmdwClientStatusResult,
data: Uint8List.fromList(utf8.encode('foreground')),
);
if (code != 0) {
debugPrint('send response failed: $code');
}
}
};如果这条命令不需要响应,客户端处理完后也可以直接结束,不必再回发另一条命令。
常见问题
一端已经发送,但另一端没有收到
先检查这三项:
- 双端约定的是否是同一个
cmdw。 - payload 编码是否一致,例如一端按 UTF-8 文本发,另一端却按别的格式解析。
- 当前发送使用的是否是这条链路对应的
hconn或conn。
双端都收到了命令,但分支没有命中
先检查比较的是否就是双方约定好的那个原始 cmdw。
什么时候该看流消息
如果你的数据需要跟某一条 stream 一起理解,而不是表达一个明确的业务命令,改看收发流消息。