Skip to content

事件协议 ​

AI 实时对话引擎在 TiRTC 命令通道上传输控制事件。所有事件均使用 JSON-RPC 2.0,payload 为 UTF-8 JSON,TiRTC 命令字为:

c
#define TIRTC_AI_SIGNALING 0x2100

协议基础 ​

JSON-RPC 消息分为两类:

类型特征说明
Request带 id 字段发送方需要接收方返回成功或失败响应,例如 start_session。
Notification不带 id 字段单向通知,不要求响应,例如 caption 或 interrupt。

id 使用字符串。平台返回的 JSON-RPC 响应不带 method,设备端应使用响应中的 id 匹配原始请求。

通用 Request 结构:

json
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "method": "start_session",
  "params": {}
}

通用成功响应:

json
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "result": {}
}

通用失败响应:

json
{
  "jsonrpc": "2.0",
  "id": "req-001",
  "error": {
    "code": -32602,
    "message": "Invalid params"
  }
}

事件总览 ​

method方向类型说明
start_session设备 -> 平台Request建连后启动 AI 实时对话会话。
caption平台 -> 设备Notification下发 ASR / TTS 字幕。
round_start平台 -> 设备Notification一轮回复音频开始。
round_end平台 -> 设备Notification一轮回复音频结束。
interrupt设备 -> 平台Notification主动打断当前回复。
submit_speech设备 -> 平台Notification手动提交当前上行语音。
update_config设备 -> 平台Request运行时更新会话配置,目前仅支持 extra_params。
device_action平台 -> 设备Request平台请求设备执行声明过的设备能力。
end_session双向Notification结束当前会话。

start_session ​

方向:设备 -> 探鸽平台

TiRTC 连接建立后,设备端必须先发送 start_session,用于创建本次 AI 实时对话会话。探鸽平台收到后会加载设备和角色配置,并返回会话 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
    }
  }
}

params 字段:

字段必填说明
device_id是设备 ID。
role_id是角色 ID,来自探鸽平台角色配置或设备角色绑定查询。
input_audio否设备上行音频格式;不传时使用平台默认值(通常为 pcm)。推荐显式传入,以确保两端理解一致,避免兼容性风险。
output_audio否平台下行音频格式;不传时使用平台默认值(通常为 pcm)。推荐显式传入,以确保两端理解一致,避免兼容性风险。

input_audio 与 output_audio 均包含以下字段:

字段类型说明
codecstring音频编码格式。
sample_rateint采样率(Hz)。
channelsint声道数。

支持的音频格式 ​

codec支持的采样率(Hz)支持的声道
opus160001
pcm16000、80001
g711a16000、80001
amr8000(NB)、16000(WB)1

说明:

  • 平台内部 ASR / LLM / TTS Pipeline 固定为 16 kHz 单声道;与内部格式不一致的上行音频会在平台侧重采样。
  • 会话实际使用的格式以 start_session 成功响应中的 input_audio 和 output_audio 为准;设备端发送音频与解码下行音频时必须与响应一致。
  • 传入不支持的 codec、采样率或声道组合时,平台返回 JSON-RPC error,message 为 Invalid audio format。

成功响应:

json
{
  "jsonrpc": "2.0",
  "id": "start-session-001",
  "result": {
    "session_id": "aivoice-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "input_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    },
    "output_audio": {
      "codec": "opus",
      "sample_rate": 16000,
      "channels": 1
    }
  }
}

失败响应示例:

json
{
  "jsonrpc": "2.0",
  "id": "start-session-001",
  "error": {
    "code": -32602,
    "message": "Invalid audio format"
  }
}

设备收到失败响应后,应停止本次会话启动流程,并释放采集、播放等本地资源。

caption ​

方向:探鸽平台 -> 设备

caption 用于下发字幕。字幕可能来自用户语音识别,也可能来自平台回复内容。

示例:

json
{
  "jsonrpc": "2.0",
  "method": "caption",
  "params": {
    "text": "你好,有什么可以帮您?",
    "emotion": "温和",
    "caption_type": 1,
    "is_final": true,
    "mode": 0,
    "utterance_id": 1001,
    "seq_num": 3,
    "begin_time_ms": 120,
    "end_time_ms": 1680
  }
}

params 字段:

字段必有说明
text是纯字幕正文,不包含服务端内部使用的情绪控制标记。
emotion否当前 TTS 字幕片段的情绪。角色开启情绪识别时返回,合法值见下方说明。
caption_type是字幕来源:0 表示 ASR 用户字幕,1 表示 TTS 回复字幕。
is_final是是否为该段话的最终字幕。
mode是传输模式:0 表示全量文本,1 表示增量文本。
utterance_id是话语 ID,同一段话的字幕共享同一个 ID。
seq_num是序列号,用于同一段话内排序。
begin_time_ms否字幕片段开始时间,单位毫秒;可能为空或为 0。
end_time_ms否字幕片段结束时间,单位毫秒;可能为空或为 0。

合并建议:

  • 使用 caption_type + utterance_id 作为字幕分组键。
  • mode=1 时,将 text 追加到当前分组。
  • mode=0 时,用 text 替换当前分组内容。
  • is_final=true 时,将当前分组标记为最终文本。

情绪字段处理建议:

  • emotion 的合法值为:中性、开心、兴奋、温和、安慰、思考、惊讶、严肃、困倦、困惑。
  • 当角色开启情绪识别时,句子级最终 TTS 字幕会携带 emotion;无法准确匹配情绪时,当前字幕使用 中性。
  • ASR 字幕、情绪识别关闭或未配置时不携带 emotion。
  • 将 emotion 作为可选字段处理,不要因字段缺失而丢弃字幕。旧客户端可以忽略该字段,继续只读取 text。

ASR 增量示例:

json
{
  "jsonrpc": "2.0",
  "method": "caption",
  "params": {
    "text": "帮我",
    "caption_type": 0,
    "is_final": false,
    "mode": 1,
    "utterance_id": 2001,
    "seq_num": 1
  }
}
json
{
  "jsonrpc": "2.0",
  "method": "caption",
  "params": {
    "text": "帮我打开灯。",
    "caption_type": 0,
    "is_final": true,
    "mode": 0,
    "utterance_id": 2001,
    "seq_num": 3
  }
}

round_start ​

方向:探鸽平台 -> 设备

round_start 表示一轮平台回复音频开始。设备端可用它切换 UI 状态,例如点亮“正在说话”灯效、打开播放状态、启用回声抑制策略等。

示例:

json
{
  "jsonrpc": "2.0",
  "method": "round_start"
}

处理建议:

  • round_start 与 round_end 通常成对出现。
  • 设备端不要仅依赖该事件决定是否播放音频,实际播放仍以音频流为准。
  • 收到 round_start 后,如果用户再次说话或按键打断,可发送 interrupt。

round_end ​

方向:探鸽平台 -> 设备

round_end 表示一轮平台回复音频结束。设备端可用它恢复到等待用户输入状态,或清理本轮播放状态。

示例:

json
{
  "jsonrpc": "2.0",
  "method": "round_end"
}

处理建议:

  • 收到 round_end 后,设备端可以恢复拾音提示、关闭“正在说话”灯效。
  • 打断场景下,平台也会尽快下发 round_end,设备端应停止播放旧轮次缓冲。

interrupt ​

方向:设备 -> 探鸽平台

interrupt 用于主动打断当前回复。典型场景包括用户按键打断、唤醒词打断、业务逻辑要求立即停止当前播报等。

示例:

json
{
  "jsonrpc": "2.0",
  "method": "interrupt"
}

处理建议:

  • 发送后设备端应立即停止播放本地缓存中的旧回复音频。
  • 平台收到后会停止当前输出,并通过后续事件和音频流进入新状态。
  • 如果打断由用户语音触发,设备端也可以继续上行用户新一轮语音。

submit_speech ​

方向:设备 -> 探鸽平台

submit_speech 用于手动提交当前上行语音。典型场景包括按键松开发送、半双工对讲、UI 控件确认发送,或设备端本地 VAD 已判断用户说完一句话。

示例:

json
{
  "jsonrpc": "2.0",
  "method": "submit_speech"
}

处理建议:

  • 发送 submit_speech 后,平台会把当前已收到的上行语音视为已提交,并推动后续 ASR / LLM / TTS 流程。
  • submit_speech 不用于打断平台当前回复;如需停止正在播放或生成的回复,应发送 interrupt。
  • 如果设备端只依赖平台云端 VAD 自动判断语音结束,通常不需要发送该事件。

update_config ​

方向:设备 -> 探鸽平台

update_config 用于在会话运行中更新少量动态上下文。当前仅支持 extra_params,常用于位置、业务状态等会随会话变化的信息。平台会把新的 extra_params 合并到当前会话,不会改写欢迎语、音色、系统提示词等静态配置。

请求示例:

json
{
  "jsonrpc": "2.0",
  "id": "update-config-001",
  "method": "update_config",
  "params": {
    "extra_params": {
      "latitude": 39.9800718,
      "longitude": 116.309314,
      "coordinate_system": "WGS84"
    }
  }
}

NMEA-0183 RMC 请求示例:

json
{
  "jsonrpc": "2.0",
  "id": "update-config-002",
  "method": "update_config",
  "params": {
    "extra_params": {
      "nmea_rmc": "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
      "coordinate_system": "WGS84"
    }
  }
}

extra_params 支持以下位置字段:

字段类型说明
longitudenumberWGS84 十进制度经度,范围为 [-180, 180]。必须与 latitude 同时提供。
latitudenumberWGS84 十进制度纬度,范围为 [-90, 90]。必须与 longitude 同时提供。
nmea_rmcstring完整的 NMEA-0183 GPRMC 或 GNRMC 原始语句。
coordinate_systemstring坐标系,当前固定且只允许 WGS84。RMC 方式必填;新设备使用数值方式时也应显式提供。

位置上报规则:

  • 每次更新必须二选一:同时提供数值 latitude、longitude,或者提供 nmea_rmc。数值坐标与 nmea_rmc 不能同时出现。
  • 数值坐标必须成对提供,不能只更新纬度或经度。为兼容旧设备,数值坐标缺少 coordinate_system 时,平台暂按 WGS84 处理并补全该字段。
  • 使用 nmea_rmc 时,必须同时提供 coordinate_system: "WGS84"。平台只接受以 $GPRMC 或 $GNRMC 开头、定位状态为 A 的完整 RMC 语句。
  • RMC 必须以 * 和两位十六进制 checksum 结尾。平台对 $ 与 * 之间的 ASCII 字符逐字节执行 XOR(不包含 $ 和 *),并拒绝缺失、格式错误或不匹配的 checksum。
  • RMC 纬度使用 ddmm.m... 并搭配 N/S,经度使用 dddmm.m... 并搭配 E/W。分钟必须小于 60。平台按“度 + 分 / 60”换算;N/E 为正,S/W 为负。
  • 任一字段无效时,整次更新会被拒绝,当前有效位置不会被部分覆盖。
  • 平台不会根据用户注册工具的类型转换坐标系。接入高德、百度等导航服务的工具需要自行将 WGS84 转换为其下游接口要求的坐标系。

成功响应:

json
{
  "jsonrpc": "2.0",
  "id": "update-config-001",
  "result": {
    "success": true,
    "message": "更新配置成功"
  }
}

失败响应示例:

json
{
  "jsonrpc": "2.0",
  "id": "update-config-001",
  "error": {
    "code": -32602,
    "message": "update_config only supports extra_params, got \"voice\""
  }
}

注意事项:

  • 响应是 JSON-RPC response,不会返回 method: "config_updated"。
  • 设备端应通过响应里的 id 匹配 update_config 请求。
  • 除 extra_params 外的字段会被拒绝。

device_action ​

方向:探鸽平台 -> 设备

当角色配置中声明了设备能力,平台可能通过 device_action 请求设备执行动作。该消息是 JSON-RPC Request,设备必须保留 id 并在执行完成后返回同一个 id 的 response。

平台下发示例:

json
{
  "jsonrpc": "2.0",
  "id": "device-action-001",
  "method": "device_action",
  "params": {
    "action": "set_light",
    "data": {
      "power": "on"
    }
  }
}

设备执行成功响应:

json
{
  "jsonrpc": "2.0",
  "id": "device-action-001",
  "result": {
    "ok": true,
    "data": {
      "power": "on"
    }
  }
}

设备执行失败响应:

json
{
  "jsonrpc": "2.0",
  "id": "device-action-001",
  "error": {
    "code": -32000,
    "message": "device is busy"
  }
}

end_session ​

方向:双向

end_session 用于结束当前 AI 实时对话会话。设备端主动结束、平台策略结束、用户语义触发结束时都可以使用该事件。

设备到平台示例:

json
{
  "jsonrpc": "2.0",
  "method": "end_session"
}

平台到设备示例:

json
{
  "jsonrpc": "2.0",
  "method": "end_session"
}

处理建议:

  • 设备端收到或发送 end_session 后,应停止采集、停止播放,并释放本地会话状态。
  • 结束流程需要可幂等执行,避免重复事件导致崩溃或资源泄漏。
  • 如果需要关闭 TiRTC 连接,可在本地资源释放后断开连接。

设备端接收示例 ​

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

#define TIRTC_AI_SIGNALING 0x2100

static void on_command(tirtc_conn_t hconn, uint32_t cmdw,
                       const void *data, uint32_t len)
{
    (void)hconn;
    if (cmdw != TIRTC_AI_SIGNALING || data == NULL || len == 0) {
        return;
    }

    /* data 是 UTF-8 JSON-RPC 字符串。
     * 生产代码中请使用 JSON 库解析 method / params,
     * 然后分发到 caption、round_start、round_end、interrupt、submit_speech、device_action、end_session 等处理函数。 */
}

自检清单 ​

  • 命令字使用 0x2100。
  • 所有 payload 均为合法 UTF-8 JSON。
  • start_session 带 id,并处理成功/失败响应。
  • role_id 必传且有效。
  • 已处理 caption 的增量和全量模式。
  • 已处理 round_start / round_end 状态切换。
  • 已实现 interrupt 的本地立即停止播放逻辑。
  • 如需手动提交语音,已实现 submit_speech 的发送逻辑。
  • 如需运行时更新配置,已按 id 处理 update_config 的 JSON-RPC response。
  • 如需设备能力调用,已按 id 处理 device_action 请求和响应。
  • 已实现 end_session 的幂等清理逻辑。

AI 实时对话引擎文档