Skip to content

设备端集成

设备端集成的目标是使用业务服务端下发的 peer_idtoken 建立 TiRTC 连接,发送 start_session 启动会话,然后完成音频上下行、事件处理和会话结束。

本页假定设备端已完成 TiRTC SDK 集成。如果尚未集成,请先参阅 TiRTC 设备端集成文档。

建立 TiRTC 连接

设备收到 peer_idtoken 后,调用 TiRTC SDK 建立连接。

c
#include "tiRTC.h"
#include <stdbool.h>
#include <string.h>

static tirtc_conn_t g_ai_conn = NULL;
static bool g_tirtc_ready = false;

static int ai_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_ai_whip(int err, tirtc_conn_t hconn, void *user_data)
{
    (void)user_data;
    if (err != 0) {
        /* 建连失败:记录错误码,释放本地会话状态 */
        return;
    }

    g_ai_conn = hconn;
    /* 建连成功后,下一步发送 start_session 命令 */
}

int start_ai_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 = ai_tirtc_runtime_init(device_id);
    if (ret != 0) {
        return ret;
    }

    /* 返回 0 表示请求已提交,最终是否成功以 on_ai_whip 回调为准 */
    return TiRtcWhipConnect(peer_id, token, on_ai_whip, NULL);
}

void stop_ai_tirtc_connect(void)
{
    if (g_ai_conn != NULL) {
        TiRtcClose(g_ai_conn);
        g_ai_conn = NULL;
    }

    if (g_tirtc_ready) {
        TiRtcStop();
        TiRtcUninit();
        g_tirtc_ready = false;
    }
}

TiRtcWhipConnect 返回 0 只表示建连请求已提交;真正成功以回调中的 err == 0 为准。

发送 start_session

TiRTC 连接建立后,设备端需要通过命令通道发送 start_session。关于详细字段格式和默认值说明,请参考 事件协议

role_id 为必传字段,必须使用业务服务端下发的本次会话角色 ID。

json
{
  "jsonrpc": "2.0",
  "id": "start-session-001",
  "method": "start_session",
  "params": {
    "device_id": "DEMO_DEVICE_01",
    "role_id": "role_xxx",
    "input_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    },
    "output_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    }
  }
}

收到成功响应后,设备应以响应中的 input_audiooutput_audio 作为本次会话实际音频格式,然后开始持续上行音频。

支持的音频格式与采样率

codec采样率(Hz)声道
opus160001
pcm1600080001
g711a1600080001
amr8000(NB)、16000(WB)1

会话实际使用的格式以 start_session 成功响应中的 input_audiooutput_audio 为准。完整说明见 事件协议

上行设备语音

设备端在采集线程中按固定周期发送音频帧,建议单帧时长控制在 100 ms 以内。

c
#include <stdint.h>
#include <string.h>
#include "tiRTC.h"

static const uint8_t kAiAudioStreamId = 1;

int ai_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 = kAiAudioStreamId;
    fi.media = TIRTC_AUDIO_OPUS;
    // 重要:必需设置与 input_audio 一致的音频格式 flags
    fi.flags = TIRTC_AUDIOSAMPLE_16K16B1C;
    fi.ts = ts_ms;
    fi.length = len;
    return TiRtcSendAudioStream(hconn, &fi, opus_data);
}

必须确保 start_session.input_audiofi.mediafi.flags 三者完全对齐,否则可能导致平台侧识别失败或解码异常。

上行设备视频

需要让智能体理解摄像头画面时,在 start_session 成功后继续发送视频帧。平台会把抽取到的画面作为智能体理解当前环境的视觉上下文,回复仍通过原有的下行音频、字幕和事件返回设备。

接入视频前需要确认:

  • 设备摄像头和编码器能够输出完整的 H.264 或 H.265 视频帧。
  • 当前角色使用支持视觉理解的模型,并且已经启用图像输入能力。
  • 设备已经实现音频采集、下行音频播放和会话清理。

媒体流约定

AI 对讲默认使用下面的 stream_id

媒体方向stream_id
麦克风音频设备 -> 平台1
回复音频平台 -> 设备1
摄像头视频设备 -> 平台0

视频必须使用 stream_id = 0,与平台当前的视频接收配置保持一致。同一条 TiRTC 连接内,音频和视频不能共用同一个 stream_id

start_session 只协商音频格式,不返回视频格式。视频编码和 stream_id 按本节约定设置;如果探鸽平台或接入包提供了其他约定,以实际约定为准。

发送视频帧

start_session 成功后启动摄像头和编码器,将每个完整的编码帧填入 TIRTCFRAMEINFO,再调用 TiRtcSendVideoStream()

c
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "tiRTC.h"

static const uint8_t kAiVideoStreamId = 0;

/**
 * 向 AI 对讲平台发送一帧 H.264 视频。
 *
 * 返回值大于 0 表示帧已进入发送队列,负数表示 TiRTC 错误码。
 */
int ai_send_video_h264(tirtc_conn_t hconn,
                       const void *frame_data,
                       uint32_t frame_len,
                       uint32_t ts_ms,
                       bool is_key_frame)
{
    TIRTCFRAMEINFO fi;

    if (hconn == NULL || frame_data == NULL || frame_len == 0) {
        return TIRTC_E_INVALID_PARAMETER;
    }

    memset(&fi, 0, sizeof(fi));
    fi.stream_id = kAiVideoStreamId;
    fi.media = TIRTC_VIDEO_H264;
    fi.flags = is_key_frame ? TIRTC_FRAME_FLAG_KEY_FRAME : 0;
    fi.ts = ts_ms;
    fi.length = frame_len;

    return TiRtcSendVideoStream(hconn, &fi, frame_data);
}

如果设备输出 H.265,把 fi.media 改为 TIRTC_VIDEO_H265。不要把 MP4 等容器文件直接作为单帧 payload 发送;应先由编码器或解复用模块输出完整的编码视频帧。

关键帧与发送节奏

  • 每路视频流的第一帧必须是关键帧,并设置 TIRTC_FRAME_FLAG_KEY_FRAME
  • 后续每个关键帧都要设置关键帧标志,普通帧的 flags 设为 0
  • fi.ts 使用单调递增的毫秒时间戳,不要在同一会话中回退。
  • 如果 TiRtcSendVideoStream() 返回 TIRTC_E_BUSY,表示发送缓冲区已满。此时丢弃后续非关键帧,尽快让编码器输出新的关键帧后再恢复发送。
  • 结束会话、连接断开或发生错误时,应同时停止摄像头采集和视频编码,不能继续向旧的 hconn 发送。

视频接入成功信号

  • TiRtcSendVideoStream() 持续返回正数,没有连续出现 TIRTC_E_BUSY 或参数错误。
  • 设备日志能够记录视频 stream_id = 0、编码类型、关键帧标志、时间戳和帧长度。
  • 向智能体询问当前画面内容时,回复能够体现设备摄像头中的可见信息。

视频已发送,但智能体无法理解画面

优先检查:

  • 视频是否使用 stream_id = 0;其他 stream_id 的视频帧会被平台忽略。
  • fi.media 是否为 TIRTC_VIDEO_H264TIRTC_VIDEO_H265
  • 第一帧以及后续关键帧是否设置了 TIRTC_FRAME_FLAG_KEY_FRAME
  • 当前角色是否使用支持视觉理解的模型,并已启用图像输入。
  • payload 是否为完整的编码视频帧,而不是 MP4 文件、RTP 包或不完整的分片。

如果出现 TIRTC_E_BUSY 后视频不再恢复,不要继续堆积普通帧。丢弃普通帧并请求编码器尽快生成关键帧,收到新的关键帧后再恢复发送。

播放下行语音

回复音频会通过 TiRTC 音频流下发。设备端应在音频回调中按 start_session 响应的 output_audio 解码并送入播放链路。

AI 对讲的下行音频默认使用 stream_id = 1。处理建议:

  • stream_id == 1 过滤 AI 对讲音频流。
  • media 和协商的 codec 解码。
  • 播放链路应支持连续流式播放,不要等待整句 TTS 结束后再播放。
  • 如果收到打断或会话结束事件,应及时停止当前播放缓冲。

处理事件

AI 对讲的控制消息、字幕和设备能力调用都通过命令通道发送。详见 事件协议

设备端至少需要实现 start_sessioncaptionround_startround_endinterruptsubmit_speechupdate_configdevice_actionend_session

最小跑通路径

  1. 服务端使用 AppId/AK/SK,通过 TGV1 签名调用 /v1/token/aichat,确保返回 peer_idtoken
  2. 设备端用 peer_idtoken 调用 TiRtcWhipConnect,确认回调 err == 0
  3. 设备端通过命令通道发送 start_session,确认收到包含 session_id 的成功响应。
  4. 设备端发送一小段音频,确认能收到下行 caption 事件。
  5. 如需视频对讲,发送 stream_id = 0 的视频关键帧和后续视频帧,并确认智能体能够理解当前画面。
  6. 测试 interruptend_session,确认音频、摄像头、编码器和连接资源能被正确清理。

AI Chat 文档