获取 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);#endifint 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_002INF|2026-03-02 16:54:31.428|network_interface.c|_network_tcp_connect(64): connected with TCP server: VI5C901SKI.iotcloud.tencentdevices.com:1883INF|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 KbytesINF|2026-03-02 16:54:31.640|mqtt_client.c|TCIOT_MQTT_Construct(384): mqtt yield thread createdINF|2026-03-02 16:54:31.640|twetalk_ws_app.c|main(412): Cloud Device Construct SuccessDBG|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=17769INF|2026-03-02 16:54:31.714|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17769DBG|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=17770INF|2026-03-02 16:54:31.917|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17770DBG|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=17771INF|2026-03-02 16:54:32.135|twetalk_ws_app.c|_mqtt_event_handler(87): subscribe success, packet-id=17771DBG|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=17772DBG|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:80DBG|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 : 0INF|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 KbytesINF|2026-03-02 16:54:32.674|twetalk_ws.c|_ws_recv_thread_entry(156): ws recv thread startINF|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。可能的使用场景是:音乐播放模式下,需要暂时关闭空闲检测,当退出音乐播放模式后再打开空闲检测。