设备端集成
设备端集成的目标是使用业务服务端下发的 peer_id 和 token 建立 TiRTC 连接,然后完成音频上下行、房间事件处理和离房清理。
本页假定设备端已完成 TiRTC SDK 集成。如果尚未集成,请先参阅 TiRTC 设备端集成文档。
前置条件
调用 TiRtcWhipConnect 前,设备端需先完成 TiRTC 设备端启动流程:
- 调用
TiRtcInit()初始化 SDK。 - 按 TiRTC 设备端接入要求设置
device_secret_key,并调用TiRtcStart(device_id, &callbacks)启动设备端。 - 等待
TIRTC_EVENT_SYS_STARTED后,再调用TiRtcWhipConnect(peer_id, token, ...)加入 Room。
TiRTC 启动流程见 连接设备端。
建连步骤
- 完成 TiRTC 初始化和设备端启动,并等待
TIRTC_EVENT_SYS_STARTED。 - 从业务服务端获取
peer_id和token。 - 调用 TiRTC
TiRtcWhipConnect,并传入业务服务端下发的peer_id和token。 - 等待 TiRTC 返回连接结果。
- 连接完成后发送
join_room,验证通过后再开始发送上行音频。 - 监听下行音频并按
join_room响应中的output_audio解码播放。 - 监听命令通道
0x2200下发的房间快照和成员事件。 - 主动离房时先发送
leave_room,收到房间关闭通知或信令发送完成后进入资源释放流程。
peer_id 和 token 都应原样传入 TiRTC TiRtcWhipConnect 接口。设备端不要解析 peer_id,也不要把它改写成其他地址或参数。
建连示例
设备收到 peer_id 与 token 后,直接调用 TiRTC SDK 建立连接。TiRtcWhipConnect 返回 0 只表示建连请求已提交;真正成功以回调中的 err == 0 为准。
#include "tiRTC.h"
#include <stdbool.h>
#include <string.h>
static tirtc_conn_t g_room_conn = NULL;
static bool g_tirtc_ready = false;
static int room_tirtc_runtime_init(const char *device_id)
{
if (g_tirtc_ready) {
return 0;
}
int ret = TiRtcInit();
if (ret != 0) {
return ret;
}
TIRTCCALLBACKS cbs;
memset(&cbs, 0, sizeof(cbs));
ret = TiRtcStart(device_id, &cbs);
if (ret != 0) {
TiRtcUninit();
return ret;
}
g_tirtc_ready = true;
return 0;
}
static void on_room_whip(int err, tirtc_conn_t hconn, void *user_data)
{
(void)user_data;
if (err != 0) {
/* 建连失败:记录错误码,释放本地房间状态 */
return;
}
g_room_conn = hconn;
/* 建连成功后,开始上行音频并监听命令通道 0x2200 */
}
int start_room_tirtc_connect(const char *device_id,
const char *peer_id,
const char *token)
{
int ret = 0;
if (device_id == NULL || device_id[0] == '\0' ||
peer_id == NULL || peer_id[0] == '\0' ||
token == NULL || token[0] == '\0') {
return -1;
}
ret = room_tirtc_runtime_init(device_id);
if (ret != 0) {
return ret;
}
return TiRtcWhipConnect(peer_id, token, on_room_whip, NULL);
}
void stop_room_tirtc_connect(void)
{
if (g_room_conn != NULL) {
TiRtcClose(g_room_conn);
g_room_conn = NULL;
}
if (g_tirtc_ready) {
TiRtcStop();
TiRtcUninit();
g_tirtc_ready = false;
}
}TiRtcWhipConnect 返回 0 只表示建连请求已提交;真正成功以回调中的 err == 0 为准。设备端应在收到 TIRTC_EVENT_SYS_STARTED 后再发起连接。
发送 join_room
TiRTC 连接建立后,设备必须在 10 秒内通过命令通道 0x2200 发送 JSON-RPC Request。room_id 和 device_id 必须与申请凭证时的值一致。
{
"jsonrpc": "2.0",
"id": 1,
"method": "join_room",
"params": {
"room_id": "room-001",
"device_id": "device-001",
"input_audio": {"codec": "pcm", "sample_rate": 16000, "channels": 1},
"output_audio": {"codec": "g711a", "sample_rate": 16000, "channels": 1}
}
}收到成功响应后设备才算正式加入房间。响应会返回 session_id 及规范化后的实际音频格式;身份或格式校验失败会返回 JSON-RPC 错误。
旧的 start_session 不再兼容。TiRTC 建连后必须先完成 join_room,否则不能发送音频或其他房间信令。
支持的音频格式与采样率
当前 Room 设备链路上下行均支持以下格式:
| codec | 采样率(Hz) | 声道 |
|---|---|---|
opus | 8000、16000 | 1 |
pcm | 8000、16000 | 1 |
g711a | 8000、16000 | 1 |
amr | 8000(AMR-NB)、16000(AMR-WB) | 1 |
设备可在 join_room 中为 input_audio 和 output_audio 分别指定编码和采样率,两者相互独立。设备端必须使用成功响应回显的实际格式,且发送的 media 和 flags 与 input_audio 保持一致。
上行音频示例
设备端在采集线程中按固定周期发送音频帧。推荐 20 ms 一帧。
#include <stdint.h>
#include <string.h>
#include "tiRTC.h"
static const uint8_t kRoomAudioStreamId = 1;
int room_send_audio_opus(tirtc_conn_t hconn,
const void *opus_data,
uint32_t len,
uint32_t ts_ms)
{
TIRTCFRAMEINFO fi;
memset(&fi, 0, sizeof(fi));
fi.stream_id = kRoomAudioStreamId;
fi.media = TIRTC_AUDIO_OPUS;
/* 必须与平台侧配置的上行音频格式保持一致 */
fi.flags = TIRTC_AUDIOSAMPLE_16K16B1C;
fi.ts = ts_ms;
fi.length = len;
return TiRtcSendAudioStream(hconn, &fi, opus_data);
}音频参数需要同时满足:
- 设备实际采集和编码后的数据格式。
- C 语言层设置的
fi.media。 - C 语言层设置的采样规格
fi.flags。
例如:opus/16000/mono 对应 TIRTC_AUDIO_OPUS 与 TIRTC_AUDIOSAMPLE_16K16B1C。
下行音频处理
Room 下行音频通过 TiRTC 音频流下发。设备端应按 join_room 响应中的 output_audio 解码并送入播放链路:
- 按
stream_id过滤房间下行音频流。 - 按音频帧的
media和flags解码,并与output_audio核对。 - 播放链路应支持连续流式播放,不要等待整段音频缓存完成后再播放。
- 收到
room_closed或本地离房时,应及时停止播放并清理缓冲区。
命令通道
Room 使用 TiRTC 命令通道 0x2200 承载 JSON-RPC 2.0 消息:
- 建连完成后,设备端必须先发送
join_room;入房成功后,Room 服务会下发room_snapshot初始化本地成员列表。 - 主动离房时,设备端必须发送不带
id的leave_roomNotification。 - 设备端可发送
get_room_snapshot主动拉取成员列表。 - 本端麦克风状态变化时,设备端可发送
set_mic_state同步on、speaking或off。 - 收到
participant_joined、participant_left、participant_mic_state_changed后更新本地成员状态。 - 收到
room_closed后进入资源释放流程。
详细字段见 房间信令。
命令通道接收示例
下面示例演示命令字过滤和事件分发方式,其中 jsonrpc_method、method_equals 和 handle_* 函数需要由业务代码基于 JSON 库实现。
#include <stdint.h>
#include "tiRTC.h"
#define TIRTC_ROOM_SIGNALING 0x2200
static const char *jsonrpc_method(const void *data, uint32_t len);
static int method_equals(const char *method, const char *expected);
static void handle_room_snapshot(const void *data, uint32_t len);
static void handle_participant_joined(const void *data, uint32_t len);
static void handle_participant_left(const void *data, uint32_t len);
static void handle_participant_mic_state_changed(const void *data, uint32_t len);
static void handle_room_closed(const void *data, uint32_t len);
static void on_room_command(tirtc_conn_t hconn, uint32_t cmdw,
const void *data, uint32_t len)
{
const char *method;
(void)hconn;
if (cmdw != TIRTC_ROOM_SIGNALING || data == NULL || len == 0) {
return;
}
/* data 是 UTF-8 JSON-RPC 字符串。生产代码中请使用 JSON 库解析。 */
method = jsonrpc_method(data, len);
if (method_equals(method, "room_snapshot")) {
handle_room_snapshot(data, len);
return;
}
if (method_equals(method, "participant_joined")) {
handle_participant_joined(data, len);
return;
}
if (method_equals(method, "participant_left")) {
handle_participant_left(data, len);
return;
}
if (method_equals(method, "participant_mic_state_changed")) {
handle_participant_mic_state_changed(data, len);
return;
}
if (method_equals(method, "room_closed")) {
handle_room_closed(data, len);
return;
}
}处理建议:
room_snapshot:以快照为准初始化本地成员列表。participant_joined:把新成员加入本地成员列表。participant_left:从本地成员列表移除离开的成员。participant_mic_state_changed:更新指定成员的麦克风状态。set_mic_state:本端麦克风开关或讲话状态变化时发送;它只同步状态,不代替本地采集和上行控制。room_closed:停止采集和播放,并进入资源释放流程。
资源释放
设备端应把主动离房、网络断开、业务超时和房间关闭通知归口到同一个清理流程:
- 主动离房时,先通过命令通道
0x2200发送不带id的leave_roomNotification。 - 停止采集和播放。
- 关闭 TiRTC 连接。
- 清理本地房间状态和播放缓冲区。
- 丢弃已过期的
token,下次入房重新申请。
最小跑通路径
为了快速排查环境与配置问题,建议先按以下端到端路径验证:
- 服务端请求测试:使用业务服务端调用
POST /v1/token/room,确保能返回有效的peer_id和token。完整字段见 服务端接口。 - 设备端启动测试:确认设备端已完成
TiRtcInit()、TiRtcStart(),并收到TIRTC_EVENT_SYS_STARTED。 - 设备端连接测试:将
device_id、peer_id和token传入start_room_tirtc_connect,观察on_room_whip回调的err是否为0。 - 入房与快照验证:建连成功后发送
join_room,成功响应后设备端应能在命令通道0x2200收到room_snapshot。 - 多设备入房验证:让两个设备使用同一个业务
room_id分别申请凭证并入房,先入房设备应能收到participant_joined。 - 麦克风状态验证:一个设备发送
set_mic_state切换on、speaking、off,其他在线设备应能收到participant_mic_state_changed。 - 音频与离房验证:一个设备持续发送测试音频,另一个设备应能收到下行音频;任一设备发送
leave_room后,其他在线设备应能收到participant_left。