Event Protocol
AI Chat control events are sent through the TiRTC command channel. All payloads are UTF-8 JSON-RPC 2.0 messages, and the AI Chat command word is:
#define TIRTC_AI_SIGNALING 0x2100Message Types
| Type | Signal | Description |
|---|---|---|
| Request | Has an id field | The sender expects a success or error response, such as start_session. |
| Notification | Has no id field | One-way event, such as caption or interrupt. |
Use a string value for id. JSON-RPC responses from the platform do not include method; match them with the original request by id.
Common request:
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "start_session",
"params": {}
}Common success response:
{
"jsonrpc": "2.0",
"id": "req-001",
"result": {}
}Common error response:
{
"jsonrpc": "2.0",
"id": "req-001",
"error": {
"code": -32602,
"message": "Invalid params"
}
}Event Summary
| method | Direction | Type | Description |
|---|---|---|---|
start_session | Device -> Platform | Request | Starts an AI Chat session after TiRTC is connected. |
caption | Platform -> Device | Notification | Sends ASR or TTS captions. |
round_start | Platform -> Device | Notification | Marks the start of one response audio round. |
round_end | Platform -> Device | Notification | Marks the end of one response audio round. |
interrupt | Device -> Platform | Notification | Interrupts the current platform response. |
submit_speech | Device -> Platform | Notification | Manually submits the current uplink speech. |
update_config | Device -> Platform | Request | Updates runtime session context. Currently only extra_params is supported. |
device_action | Platform -> Device | Request | Requests the device to execute a declared capability. |
end_session | Both | Notification | Ends the current session. |
start_session
Direction: device -> Tange platform
The device must send start_session after the TiRTC connection is ready. The platform creates the session, loads device and role configuration, and returns the session ID and audio formats.
{
"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
}
}
}Required fields:
| Field | Required | Description |
|---|---|---|
device_id | Yes | Device ID. |
role_id | Yes | Role ID from role configuration or device-role binding. |
input_audio | No | Uplink audio format. Uses platform defaults (usually pcm) when omitted. We highly recommend passing this explicitly to ensure the server and device have a consistent understanding and avoid compatibility issues. |
output_audio | No | Downlink audio format. Uses platform defaults (usually pcm) when omitted. We highly recommend passing this explicitly to ensure the server and device have a consistent understanding and avoid compatibility issues. |
Both input_audio and output_audio contain:
| Field | Type | Description |
|---|---|---|
codec | string | Audio codec. |
sample_rate | int | Sample rate in Hz. |
channels | int | Number of channels. |
Supported Audio Formats
| codec | Supported sample rates (Hz) | Supported channels |
|---|---|---|
opus | 16000 | 1 |
pcm | 16000, 8000 | 1 |
g711a | 16000, 8000 | 1 |
amr | 8000 (NB), 16000 (WB) | 1 |
Notes:
- The platform ASR / LLM / TTS pipeline runs at 16 kHz mono internally. Uplink audio that does not match the internal format is resampled on the platform side.
- The actual session formats are defined by the
input_audioandoutput_audiofields in thestart_sessionsuccess response. The device must send and decode audio according to those values. - Unsupported codec, sample rate, or channel combinations return a JSON-RPC error with
messageset toInvalid audio format.
Success response:
{
"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
}
}
}caption
Direction: Tange platform -> device
caption sends ASR or TTS text.
{
"jsonrpc": "2.0",
"method": "caption",
"params": {
"text": "Hello, how can I help?",
"emotion": "温和",
"caption_type": 1,
"is_final": true,
"mode": 0,
"utterance_id": 1001,
"seq_num": 3,
"begin_time_ms": 120,
"end_time_ms": 1680
}
}params fields:
| Field | Always present | Description |
|---|---|---|
text | Yes | Plain caption text without internal emotion control markers. |
emotion | No | Emotion of the current TTS caption segment. Returned when emotion recognition is enabled for the role. See the allowed values below. |
caption_type | Yes | Caption source: 0 for ASR user caption, 1 for TTS reply caption. |
is_final | Yes | Whether this is the final caption for the utterance. |
mode | Yes | Delivery mode: 0 for full text, 1 for incremental text. |
utterance_id | Yes | Utterance ID; captions from the same utterance share the same ID. |
seq_num | Yes | Sequence number for ordering within the same utterance. |
begin_time_ms | No | Caption segment start time in milliseconds; may be absent or 0. |
end_time_ms | No | Caption segment end time in milliseconds; may be absent or 0. |
Use caption_type + utterance_id as the caption group key. When mode=1, append text; when mode=0, replace the current text. Mark the group final when is_final=true.
Emotion handling:
- Allowed
emotionvalues are中性,开心,兴奋,温和,安慰,思考,惊讶,严肃,困倦, and困惑. These Chinese strings are the protocol values and must not be translated before comparison. - When emotion recognition is enabled for the role, sentence-level final TTS captions include
emotion. If the emotion cannot be matched reliably, the current caption uses中性. - ASR captions omit
emotion. The field is also omitted when emotion recognition is disabled or not configured. - Treat
emotionas optional and do not discard a caption when it is absent. Existing clients may ignore this field and continue to readtextonly.
round_start and round_end
Direction: Tange platform -> device
round_start marks the start of one response audio round:
{
"jsonrpc": "2.0",
"method": "round_start"
}round_end marks the end:
{
"jsonrpc": "2.0",
"method": "round_end"
}Use these events for UI state and playback state, but play audio according to the actual downlink audio stream.
interrupt
Direction: device -> Tange platform
{
"jsonrpc": "2.0",
"method": "interrupt"
}The historical spelling interupt is also accepted by the platform and has the same effect as interrupt. New integrations should use interrupt.
After sending interrupt, the device should immediately stop playing buffered audio from the old response.
submit_speech
Direction: device -> Tange platform
submit_speech manually submits the current uplink speech. Typical scenarios include push-to-talk release, half-duplex talk, UI confirmation, or local device-side VAD deciding that the user has finished an utterance.
{
"jsonrpc": "2.0",
"method": "submit_speech"
}Notes:
- After
submit_speechis sent, the platform treats the currently received uplink speech as submitted and continues the ASR / LLM / TTS flow. submit_speechdoes not interrupt the current platform response. Useinterruptwhen the device needs to stop an in-progress response.- If the device relies only on cloud VAD to detect the end of speech, this event is usually not required.
update_config
Direction: device -> Tange platform
update_config updates small pieces of runtime context during an active session. Currently only extra_params is supported. It is intended for information such as location or business state that may change during the session. It does not update static settings such as welcome text, voice, or system prompt.
Request:
{
"jsonrpc": "2.0",
"id": "update-config-001",
"method": "update_config",
"params": {
"extra_params": {
"latitude": 39.9800718,
"longitude": 116.309314,
"coordinate_system": "WGS84"
}
}
}Request with an NMEA-0183 RMC sentence:
{
"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 supports the following location fields:
| Field | Type | Description |
|---|---|---|
longitude | number | WGS84 longitude in decimal degrees, in the range [-180, 180]. It must be provided together with latitude. |
latitude | number | WGS84 latitude in decimal degrees, in the range [-90, 90]. It must be provided together with longitude. |
nmea_rmc | string | A complete raw NMEA-0183 GPRMC or GNRMC sentence. |
coordinate_system | string | The coordinate system. Currently fixed to WGS84; all other values are rejected. Required for RMC input, and new devices should also provide it with numeric input. |
Location reporting rules:
- Each update must use exactly one input form: both numeric
latitudeandlongitude, ornmea_rmc. Numeric coordinates andnmea_rmcare mutually exclusive. - Numeric coordinates must be provided as a pair; a latitude or longitude cannot be updated by itself. For backward compatibility, if numeric coordinates omit
coordinate_system, the platform temporarily treats them asWGS84and adds that field. - When using
nmea_rmc, you must also providecoordinate_system: "WGS84". The platform accepts only complete RMC sentences beginning with$GPRMCor$GNRMCand whose positioning status isA. - The RMC sentence must end with
*followed by a two-digit hexadecimal checksum. The platform XORs the ASCII characters between$and*byte by byte (excluding$and*) and rejects a missing, malformed, or mismatched checksum. - RMC latitude uses
ddmm.m...withN/S, and longitude usesdddmm.m...withE/W. Minutes must be less than 60. The platform converts the value usingdegrees + minutes / 60;N/Eis positive andS/Wis negative. - If any field is invalid, the entire update is rejected and the current valid location is not partially overwritten.
- The platform does not convert coordinates based on the type of a user-registered tool. Tools integrating navigation services such as Amap or Baidu Maps must convert WGS84 coordinates to the coordinate system required by their downstream API.
Success response:
{
"jsonrpc": "2.0",
"id": "update-config-001",
"result": {
"success": true,
"message": "更新配置成功"
}
}Error response:
{
"jsonrpc": "2.0",
"id": "update-config-001",
"error": {
"code": -32602,
"message": "update_config only supports extra_params, got \"voice\""
}
}Notes:
- The response is a JSON-RPC response and does not include
method: "config_updated". - Match the response to the
update_configrequest byid. - Any field other than
extra_paramsis rejected.
device_action
Direction: Tange platform -> device
When device capabilities are declared in the role configuration, the platform may send device_action to request the device to perform an action. This message is a JSON-RPC Request. The device must keep the id and return a response with the same id.
Request from platform:
{
"jsonrpc": "2.0",
"id": "device-action-001",
"method": "device_action",
"params": {
"action": "set_light",
"data": {
"power": "on"
}
}
}Success response from device:
{
"jsonrpc": "2.0",
"id": "device-action-001",
"result": {
"ok": true,
"data": {
"power": "on"
}
}
}Error response from device:
{
"jsonrpc": "2.0",
"id": "device-action-001",
"error": {
"code": -32000,
"message": "device is busy"
}
}end_session
Direction: both
end_session ends the current AI Chat session. It may be sent by the device or by the platform when the session should close.
Device to platform:
{
"jsonrpc": "2.0",
"method": "end_session"
}Platform to device:
{
"jsonrpc": "2.0",
"method": "end_session"
}After sending or receiving end_session, stop capture, stop playback, and release local session state. The cleanup flow should be idempotent.
Device Receive Example
#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 is a UTF-8 JSON-RPC string.
* In production code, parse method / params with a JSON library,
* then dispatch to caption, round_start, round_end, interrupt,
* submit_speech, device_action, end_session, and other handlers. */
}Self-Check List
- Use the
0x2100command word. - Ensure every payload is valid UTF-8 JSON.
- Send
start_sessionwith anid, and handle both success and error responses. - Pass a valid
role_id. - Handle incremental and full
captionmodes. - Handle
round_start/round_endstate changes. - Implement immediate local playback stop for
interrupt. - If manual speech submission is needed, implement
submit_speech. - If runtime config updates are needed, match the
update_configJSON-RPC response byid. - If device capability calls are needed, handle
device_actionrequests and responses byid. - Make
end_sessioncleanup idempotent.