集成 SDK

最近更新时间:2026-04-07 10:43:42

我的收藏

获取 SDK

我们在 GitHub 上提供了完整的开源示例工程,该工程已内置了最新版本的设备端 SDK,此 SDK 会定期更新以支持新特性,您可以直接下载源码进行编译和烧录。
如果您有其他平台的需求,请联系商务进行需求对接。目前已经支持的硬件列表:
序号
芯片平台
网络
操作系统
芯片型号
适配状态
1
乐鑫
Wi-Fi/BLE
RTOS
ESP32 & ESP32 S3 / P4 / C3 / C6 / S2
✅ 已适配
2
归芯
cat.1
RTOS
GX 318 / 308
✅ 已适配
3
移芯
cat.1
RTOS
EC718_S / 718P_M / 618 / 616
✅ 已适配
4
博通集成
Wi-Fi/BLE
RTOS
BK7258
✅ 已适配
5
杰理
Wi-Fi/BLE
RTOS
AC791x
✅ 已适配
6
瑞芯微
Wi-Fi/网口
Linux
RV1106 / RK3588
✅ 已适配
7
arm64
Wi-Fi/网口
Linux
英伟达 orin NX
✅ 已适配

集成说明

我们仅需不到200行代码(Linux sample)即可完成 TWeTalk SDK 的接入,其中核心代码不足100行。具体接入注意事项已在以下代码块中注释说明:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "qcloud_iot_common.h"
#include "utils_log.h"
#include "twetalk_ws.h"
#include "data_template_app.h"

/**
* @brief TWeTalk 实例句柄(由 TWeTalk_WS_Init 创建)
*/
static void *sg_twetalk_handle = NULL;

/**
* @brief 主循环退出标志(信号处理和主线程共享)
*/
static volatile int sg_main_exit = 0;

/**
* @brief MQTT 事件回调(示例中暂不处理具体事件)
*/
static void _mqtt_event_handler(void *client, void *handle_context, MQTTEventMsg *msg)
{
(void)client;
(void)handle_context;
(void)msg;
}

/**
* @brief 组装 MQTT 初始化参数
*/
static void _setup_connect_init_params(MQTTInitParams *init_params, DeviceInfo *device_info)
{
init_params->device_info = device_info;
init_params->event_handle.h_fp = _mqtt_event_handler;
}

/**
* @brief 退出信号处理函数(Ctrl+C)
*/
static void _main_exit(int sig)
{
Log_e("demo exit by signal:%d", sig);
sg_main_exit = 1;
}

/**
* @brief TWeTalk 音频接收回调(按需处理接收音频)
*/
static int _twetalk_recv_audio_cb(uint8_t *recv_data, int recv_len, void *context)
{
(void)recv_data;
(void)recv_len;
(void)context;
return 0;
}

/**
* @brief 统一处理 TWeTalk 事件
*/
static int _twetalk_handle_event(TWeTalkEventType type, TWeTalkEventMsg *msg)
{
switch (type) {
case TWETALK_EVENT_BOT_START_SPEAKING:
Log_i("bot start speaking");
break;

case TWETALK_EVENT_BOT_STOP_SPEAKING:
Log_i("bot stop speaking");
break;

case TWETALK_EVENT_USR_START_SPEAKING:
Log_i("usr start speaking");
break;

case TWETALK_EVENT_USR_STOP_SPEAKING:
Log_i("usr stop speaking");
break;

case TWETALK_EVENT_BOT_TRANSCRIPTION: {
/**
* SDK 里字幕可能是:
* 1) 短文本:transcription
* 2) 动态分配长文本:long_transcription(is_dynamic=1)
*/
const char *bot_text = (msg->BotTranscription.is_dynamic && msg->BotTranscription.long_transcription)
? msg->BotTranscription.long_transcription
: msg->BotTranscription.transcription;
Log_i("bot: %s", bot_text ? bot_text : "");

/* 若为动态分配文本,使用后释放,避免内存泄漏 */
if (msg->BotTranscription.is_dynamic && msg->BotTranscription.long_transcription) {
TCI_HAL_Free(msg->BotTranscription.long_transcription);
msg->BotTranscription.long_transcription = NULL;
}
} break;

case TWETALK_EVENT_USR_TRANSCRIPTION: {
const char *usr_text = (msg->UsrTranscription.is_dynamic && msg->UsrTranscription.long_transcription)
? msg->UsrTranscription.long_transcription
: msg->UsrTranscription.transcription;
Log_i("usr: %s", usr_text ? usr_text : "");

if (msg->UsrTranscription.is_dynamic && msg->UsrTranscription.long_transcription) {
TCI_HAL_Free(msg->UsrTranscription.long_transcription);
msg->UsrTranscription.long_transcription = NULL;
}
} break;

case TWETALK_EVENT_RECV_USR_CALLING: {
/* 收到小程序呼叫:可按业务策略接听 / 拒接 */
Log_i("calling roomid: %s caller id: %s", msg->RecvCalling.room_id, msg->RecvCalling.caller_id);

/* 新接口要求传 UtilsJsonValue 作为 room_id 参数 */
UtilsJsonValue room_id_val = {
.value = msg->RecvCalling.room_id,
.value_len = (int)strlen(msg->RecvCalling.room_id),
};

/* 这里示例为自动接听 */
TWeTalk_WS_CallResponse(sg_twetalk_handle, TWETALK_EVENT_DEVICE_ANSWER, &room_id_val);
} break;

case TWETALK_EVENT_RECV_USR_ANSWER:
Log_i("user answer called: %s openid: %s", msg->UserAnswer.called, msg->UserAnswer.openid);
break;

case TWETALK_EVENT_RECV_USR_HANGUP:
Log_i("user hangup(%s) called: %s openid: %s",
msg->UserHangup.stream, msg->UserHangup.called, msg->UserHangup.openid);
break;

case TWETALK_EVENT_RECV_ERROR:
/* 业务侧可根据错误码做重连、告警等策略 */
Log_e("recv error: %d", msg->RecvError.code);
TWeTalk_WS_Disconnect(sg_twetalk_handle);
break;

default:
Log_w("unknown event type: %d", type);
break;
}

return 0;
}

/**
* @brief 程序入口
*/
int main(int argc, char **argv)
{
(void)argc;
(void)argv;

#if defined(__linux__) || defined(__APPLE__)
signal(SIGINT, _main_exit);
#endif

int rc = 0;

/* 初始化日志 */
LogHandleFunc func = DEFAULT_LOG_HANDLE_FUNCS;
utils_log_init(func, LOG_LEVEL_DEBUG, 2048);

/* 填写设备三元组 */
DeviceInfo device_info = {
.product_id = "YOUR_PRODUCT_ID",
.device_name = "YOUR_DEVICE_NAME",
.device_secret = "YOUR_DEVICE_SECRET",
.device_version = "1.0.0",
};

/* 初始化 MQTT 连接参数 */
MQTTInitParams init_params = DEFAULT_MQTT_INIT_PARAMS;
_setup_connect_init_params(&init_params, &device_info);

/* 建立 MQTT 连接 */
void *client = TCIOT_MQTT_Construct(&init_params);
if (!client) {
Log_e("MQTT Construct failed!");
utils_log_deinit();
return QCLOUD_ERR_FAILURE;
}
Log_i("Cloud Device Construct Success");

/* 初始化数据模板(TWeTalk 依赖) */
rc = usr_data_template_init(client);
if (rc) {
Log_e("usr data template init failed: %d", rc);
TCIOT_MQTT_Destroy(&client);
utils_log_deinit();
return rc;
}

/* 配置 TWeTalk WebSocket 参数 */
TWeTalkWsInitParams twetalk_params = DEFAULT_TWETALK_WS_INIT_PARAMS;
twetalk_params.mqtt_client = client;
twetalk_params.recv_audio_cb = _twetalk_recv_audio_cb;
twetalk_params.recv_event_cb = NULL; /* 新版推荐用主动拉取事件 */
twetalk_params.context = NULL;
twetalk_params.audio_type = TWETALK_AUDIO_TYPE_PCM;

/* 帧间隔与缓冲大小根据实时性和网络情况调整 */
twetalk_params.frame_interval = 60;
twetalk_params.push_recv_frame_interval = 60;
twetalk_params.ringbuffer_size = 20 * 640;

/* 小程序配置 */
twetalk_params.wxa_appid = "YOUR_WXA_APPID";
twetalk_params.wxa_modelid = "YOUR_WXA_MODELID";

/* 自定义参数(JSON 字符串) */
TCI_HAL_Snprintf(twetalk_params.custom_params, sizeof(twetalk_params.custom_params), "{}");

/* 初始化 TWeTalk */
sg_twetalk_handle = TWeTalk_WS_Init(&twetalk_params);
if (sg_twetalk_handle == NULL) {
Log_e("TWeTalk WebSocket init failed! rc: %d", twetalk_params.error_code);
usr_data_template_deinit(client);
TCIOT_MQTT_Destroy(&client);
utils_log_deinit();
return QCLOUD_ERR_FAILURE;
}

/**
* 主循环:
* - 使用 TWeTalk_WS_GetEvent 拉取事件
* - timeout 属于正常情况,继续轮询
*/
while (!sg_main_exit) {
TWeTalkEventType event_type;
TWeTalkEventMsg event_msg;

rc = TWeTalk_WS_GetEvent(sg_twetalk_handle, &event_type, &event_msg, 200);
if (rc == QCLOUD_ERR_TWETALK_TIMEOUT) {
continue;
}
if (rc != 0) {
Log_e("TWeTalk_WS_GetEvent error: %d", rc);
continue;
}

_twetalk_handle_event(event_type, &event_msg);
}

Log_i("main exit");

/* 释放资源(逆序) */
rc = usr_data_template_deinit(client);
rc |= TWeTalk_WS_Exit(sg_twetalk_handle);
rc |= TCIOT_MQTT_Destroy(&client);

utils_log_deinit();
return rc;
}

接入流程分析

SDK 在初始化前,请保证网络已经正常连接。
需要将设备三元组(如何获取设备三元组)填入 DeviceInfo 中,这是设备和平台鉴权的唯一凭证。且设备密钥需妥善保存,避免泄漏。
运行 TWeTalk_WS_Init 后,SDK 会尝试连接 TWeTalk 智能体,连接成功后会播报一段音频作为开场白(在控制台可以关闭),此时会进入 _twetalk_recv_audio_cb 回调来接收音频。可以将此音频直接送 Opus 解码播放。
可以调用 TWeTalk_WS_SendAudio 来发送本地录音数据,智能体会做相应的响应。
如果做 UI 展示或者其他逻辑需要关注 _twetalk_recv_event_cb 中的相关事件。

运行日志分析

设备初始化

INF|2026-03-02 16:54:31.385|mqtt_client.c|_qcloud_iot_mqtt_client_init(250): SDK_Ver: 4.1.0-, Product_ID: VI5C901SKI, Device_Name: aitalk_002
INF|2026-03-02 16:54:31.428|network_interface.c|_network_tcp_connect(64): connected with TCP server: VI5C901SKI.iotcloud.tencentdevices.com:1883
INF|2026-03-02 16:54:31.640|mqtt_client.c|TCIOT_MQTT_Construct(367): mqtt connect with id: 0iST3 success
[INF] created task _mqtt_yield_thread thread_id 0x16d49f000 stack_size : 16 Kbytes
INF|2026-03-02 16:54:31.640|mqtt_client.c|TCIOT_MQTT_Construct(384): mqtt yield thread created
INF|2026-03-02 16:54:31.640|twetalk_ws_app.c|main(412): Cloud Device Construct Success
DBG|2026-03-02 16:54:31.640|mqtt_client.c|_mqtt_yield_thread(62): start mqtt_yield_thread...
DBG|2026-03-02 16:54:31.640|mqtt_client_subscribe.c|qcloud_iot_mqtt_subscribe(350): subscribe topic_name=$thing/down/property/VI5C901SKI/aitalk_002|packet_id=17769
INF|2026-03-02 16:54:31.714|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17769
DBG|2026-03-02 16:54:31.841|mqtt_client_subscribe.c|qcloud_iot_mqtt_subscribe(350): subscribe topic_name=$thing/down/action/VI5C901SKI/aitalk_002|packet_id=17770
INF|2026-03-02 16:54:31.917|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17770
DBG|2026-03-02 16:54:32.046|mqtt_client_subscribe.c|qcloud_iot_mqtt_subscribe(350): subscribe topic_name=$twecall/down/service/VI5C901SKI/aitalk_002|packet_id=17771
INF|2026-03-02 16:54:32.135|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17771
DBG|2026-03-02 16:54:32.247|mqtt_client_publish.c|qcloud_iot_mqtt_publish(265): publish qos=1|packet_id=17772|topic_name=$twecall/up/service/VI5C901SKI/aitalk_002|payload={"method":"query_websocket_url","clientToken":"ws-846930886","params":{"connect_type":"talk"}}
DBG|2026-03-02 16:54:32.247|twetalk_mqtt.c|query_websocket_url(247): wait query_websocket_url reply....
INF|2026-03-02 16:54:32.310|twetalk_ws_app.c|_mqtt_event_handler(111): publish success, packet-id=17772
DBG|2026-03-02 16:54:32.396|twetalk_mqtt.c|_twecall_message_cb(59): twecall message arrived: {"method":"query_websocket_url_reply","clientToken":"ws-846930886","code":0,"status":"","params":{"token":"6e308a79161511f1bd9c525400e7e4b9","websocket_url":"ws://iot-twetalk.tencentiotcloud.com/ws","websocket_port":80}}

INF|2026-03-02 16:54:32.453|network_interface.c|_network_tcp_connect(64): connected with TCP server: iot-twetalk.tencentiotcloud.com:80
DBG|2026-03-02 16:54:32.673|twetalk_ws.c|_twetalk_ws_connect(450): ws url ws://iot-twetalk.tencentiotcloud.com/ws?productId=VI5C901SKI&deviceName=aitalk_002&token=6e308a79161511f1bd9c525400e7e4b9&language=zh&audioType=pcm&audioInterval=60&customParams=%7B%22user_name%22%3A%22%E5%BC%A0%E4%B8%89%22%2C%20%22user_location%22%3A%22%E8%A5%BF%E5%AE%89%22%2C%20%22%E7%88%B1%E5%A5%BD%22%3A%22%E8%87%AA%E8%A1%8C%E8%BD%A6%22%7D:80 connect : 0
INF|2026-03-02 16:54:32.674|twetalk_ws.c|TWeTalk_WS_Init(613): ai talk use mailqueue(0x103037b40) to recv event
[INF] created task _twetalk_recv_thread thread_id 0x16d4bf000 stack_size : 20 Kbytes
INF|2026-03-02 16:54:32.674|twetalk_ws.c|_ws_recv_thread_entry(156): ws recv thread start
INF|2026-03-02 16:54:32.674|twetalk_ws.c|_ws_send_thread_entry(254): ws send thread start
[INF] created task _twetalk_send_thread thread_id 0x16d4df000 stack_size : 20 Kbytes

╔════════════════════════════════════════════════════════╗
║ TWeTalk Device Information ║
╠════════════════════════════════════════════════════════╣
║ Version : 1.1.7 ║
║ Build Time : Mar 2 2026 16:54:20 ║
║ Device : aitalk_002 ║
║ Product : VI5C901SKI ║
║ Device ID : VI5C901SKI_aitalk_002 ║
╚════════════════════════════════════════════════════════╝

INF|2026-03-02 16:54:32.674|twetalk_ws.c|TWeTalk_WS_Init(672): ai talk init success(0)


SDK 重点功能介绍

TWeTalk_WS_SendTextToLLM

功能
绕过所有语音识别模块,直接发送文本给 LLM,做单次自定义消息传递。
使用场景
示例1:需要文本输入来调用某项工具能力
以微信语音通话为例,当与 TWeTalk 服务端建立连接后,若用户希望直接在设备 UI 上拨打微信联系人(如联系人小明)而非使用语音呼叫,可通过调用特定接口发送文本指令来模拟用户语音输入,从而触发特定工具调用。
TWeTalk_WS_SendTextToLLM(twetalk_handle, "打电话给小明", sizeof("打电话给小明")-1);
示例2:特殊业务动作,需要触发 LLM 做对应回复
以带触摸传感器的 AI 玩具为例,当与 TWeTalk 服务端建立连接时,用户触摸玩具头部传感器后,可以通过业务代码直接向服务端发送以下文本信息,提示 LLM 对用户动作做出相应反馈。
TWeTalk_WS_SendTextToLLM(twetalk_handle, "【物理交互】:用户拍了拍你的头", sizeof("【物理交互】:用户拍了拍你的头")-1);

TWeTalk_WS_EnableIdleDetect

功能
开启或关闭空闲检测,默认是开启空闲检测。当一段时间没有对话时会收到 TWETALK_EVENT_IDLE_DETECT 事件和语音提示。
使用场景
当用户需要关闭空闲检测时,可以调用此 API。可能的使用场景是:音乐播放模式下,需要暂时关闭空闲检测,当退出音乐播放模式后再打开空闲检测。