ESP32-S3 呼微信接通后没声音之解决办法

发布时间:2026/11/3 19:22:20

ESP32-S3 呼微信接通后没声音之解决办法 ESP32-S3 呼微信接通后没声音之解决办法上一篇移芯 EC718PM 上说话一卡一卡之解决办法本文代码来自开源仓库github.com/tangeai/xiaotai-esp32主工程lckfb-szpi-esp32s3-tirtc/。代码有节选常量和结构没改。把微信语音通话接进开发板最气人的一步连得上却没声音。信令显示一切正常手机端来电能收到、能接听WHIP 也报成功结果两边都不出声随后界面自动回到首页。这个现象在starter_runtime.c里有明确的注释答案/* * WHIP 成功仅表示传输连接建立。微信 VoIP 与参考工程一致必须 * 再等待服务端的 0x2000 / CALL_CONNECTED收到后才允许启动 Opus * 媒体过早发音频会被服务端关闭表现为无声后自动回首页。 */遇到这个现象可以先查媒体是不是启动得太早——源码注释直接点名了这个原因。这篇把设备呼叫微信的信令流程走一遍标出每一步会踩的坑。一、先得让平台知道你会 VoIPprofile 上报设备开机后第一件相关的事是把 VoIP 能力上报给平台拨号排在它后面。starter_runtime.c把设备信息拼成 JSON发到/v1/device/profile关键的一段是profiles里的voip屏幕 320×240、单声道音频、上下行媒体类型intprofile_lengthsnprintf(profile,sizeof(profile),{\hardware\:{\chip_model\:\%s\,\board_model\:\%s\},\firmware_version\:\%s\,\profiles\:{...\voip\:{\screen_width\:320,\screen_height\:240,\audio_rate\:%u,\audio_channels\:1,\down_audio_mt\:\%s\,\up_video_mt\:\none\,\down_video_mt\:\none\,...上报成功后有一行日志ESP_LOGI(TAG,device profile accepted api/v1/device/profile scenesstream,call,voip; WeChat calling is ready);没上报成功就拨号呼叫会在本地直接被拒连请求都发不出去if(contact-sourceSTARTER_CONTACT_WECHAT!s_voip_profile_ready){ESP_LOGW(TAG,WeChat call blocked until VoIP profile is reported);returnfalse;}MQTT 侧同样拦了一遍——收到微信来电但 profile 没就绪忽略这条信令并重新请求 profileif(wechatstrcmp(signal,call_incoming)0!s_voip_profile_ready){ESP_LOGW(TAG,ignoring WeChat call before VoIP profile readiness);cJSON_Delete(root);request_voip_profile();return;}所以排查微信呼叫打不出去第一件事是看串口里有没有WeChat calling is ready这行。重试间隔是 15 秒VOIP_PROFILE_RETRY_MS 15000网络慢时要等。二、拨号微信和设备互呼走的是两条路点联系人呼叫后begin_call_common()先结束当前会话并清理连接结束 AI 会话、关掉是否允许 H5 连接的开关、断开旧连接然后递增用来区分新旧通话的编号。之后按联系人类型分两条路if(s_call_wechat){(void)snprintf(body,sizeof(body),{\device_id\:\%s\,\wx_app_id\:\%s\,\wx_user_openid\:\%s\,\wx_model_id\:\%s\,\wx_room_type\:\%s\,\wx_version_type\:0},s_device_id,s_call_wx_app_id,s_call_peer_id,s_call_wx_model_id,video?video:voice);servicePLATFORM_SERVICE_VOIP;path/v1/voip/device/call;stageCALL_HTTP_VOIP_DIAL;}else{esp_err_terrsubmit_device_call();...}微信走/v1/voip/device/call设备互呼走/v1/call/request。注意一个容易想错的点微信拨号的 HTTP 响应在代码里只读取了call_id真正建连要用的 peer、token 要等 MQTT 的call_incoming推过来if(event-commandCALL_HTTP_VOIP_DIAL){(void)copy_json_string(data,call_id,s_call_id,sizeof(s_call_id),false);cJSON_Delete(root);/* 真正 peer/token/room 来自匹配的 MQTT call_incoming。 */s_deadline_msnow_ms()CALL_CONNECT_TIMEOUT_MS;return;}也就是说主叫流程是HTTP 拨号 → 等 MQTT 回铃回铃里才带建连要用的凭据。等不到回铃HTTP 侧再成功也没用。三、WHIP 建连在本工程放在独立任务里注释点名了原因MQTT 的call_incoming微信侧字段是wx_room_id/peer_id/token解析完就该发起 WHIP 建连了。这里有个栈深度的坑注释写得很直白/* * MQTT call_incoming 的解析帧里有多组 1 KiB peer/token 临时缓冲。不能在 * 该深栈函数中再进入 TiRtcWhipConnect否则 SDK 的握手栈会压穿 * starter_session。下一轮事件在解析帧已退出后才提交 WHIP。 */所以 WHIP 不在 MQTT 回调里调而是 calloc 一个请求对象丢给独立任务去执行。任务本体很短调starter_tirtc_voip_connect(peer_id, token, generation)把连接结果写入EVENT_VOIP_CONNECT_RESULT事件再放入队列然后删掉自己。两个细节值得抄走。第一任务栈从 PSRAM 分配MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT不动内部那块本来就紧张的 RAM——启动时仓库专门给 TiRTC 预留了一段连续的内部堆留给这类握手。第二这个任务用xTaskCreateWithCaps创建结束时对应vTaskDeleteWithCaps注释里提醒普通vTaskDelete会把静态注册的栈和 TCB 每次漏掉一份。四、最大的坑WHIP 成功只算一半WHIP 建连成功事件进来状态还是接通中if(event-modeSTARTER_TIRTC_VOIP){s_call_waiting_confirmtrue;s_deadline_msnow_ms()VOIP_CONNECTED_WAIT_TIMEOUT_MS;ESP_LOGI(TAG,VoIP WHIP connected; awaiting CALL_CONNECTED generation%lu,(unsignedlong)s_connection_generation);return;}注意s_call_waiting_confirm true和那行日志WHIP 成功只表示传输连接建立。真正的接通确认是服务端下发的0x2000CALL_COMMAND_CONNECT收到它才允许启动 Opus 媒体。命令字一共两个0x2000接通、0x2001挂断挂断那条同样从这条消息通道进来。if(event-command!CALL_COMMAND_CONNECT||state!STARTER_RUNTIME_CALL_CONNECTING||!s_call_waiting_confirm){return;}...starter_tirtc_mode_tmodes_call_wechat?STARTER_TIRTC_VOIP:STARTER_TIRTC_CALL;if(starter_media_start(mode,s_connection_generation)!ESP_OK){finish_session(ESP_ERR_INVALID_STATE);return;}s_call_waiting_confirmfalse;s_deadline_ms0;publish_state(STARTER_RUNTIME_CALL_ACTIVE);把这两个时序搞反就是开头那个现象媒体先起来服务端不认把会话关掉手机端表现为无声后自动回首页。等0x2000的超时是 35 秒VOIP_CONNECTED_WAIT_TIMEOUT_MS 35000。设备互呼非微信还要更严一层主叫要等对方已接听加P2P 已连上两个条件都满足、并且拿到非零连接编号才启动媒体。条件没齐就不开等齐了才开if(s_call_wechat||!s_call_outgoing||state!STARTER_RUNTIME_CALL_CONNECTING||!s_call_peer_answered||!s_call_p2p_connected||s_connection_generation0U){return;}五、被叫侧回铃不能当成新来电主叫微信时MQTT 会推一条回铃。这条回铃的字段跟真实来电几乎一样不处理就可能弹两次来电界面。代码用四个条件识别这是我自己外呼的回铃/* 微信外呼的 MQTT 回铃是同一流程不再弹一次来电。 */bool outgoing_wechatwechatstateSTARTER_RUNTIME_CALL_CONNECTINGs_call_wechats_call_outgoing(from_device[0]\0||strcmp(from_device,s_device_id)0)(s_call_id[0]\0||call_id[0]\0||strcmp(s_call_id,call_id)0);紧挨着还有一条防护已经取消的外呼迟到的回推不能再显示成来电。这条判断要求消息来自微信、from_device是本机而且不符合前面的外呼回铃条件——四个条件都查了只要有一条对不上就当垃圾消息丢掉。两种判定写在同一个函数里相隔不到 10 行处理的都是同一种消息自己外呼产生的回铃。另外两类来电会被直接拒掉一是房间类型超出 voice/audio 的范围S3 只做语音注释原话是避免出现’能接听却无视频’的假能力二是忙线。拒接时微信侧带原因码本工程用到的取值不支持的房间类型传 7忙线传 8。六、音频流号对不上订阅就收不到还有一处跟有连接没声音直接相关TiRTC 收到音频订阅回调时按当前模式和流号过滤。微信 VoIP 的音频流号是 10#defineAI_AUDIO_STREAM1U#defineCALL_AUDIO_STREAM10Ubool accepted(modeSTARTER_TIRTC_H5stream_idH5_AUDIO_STREAM)||((modeSTARTER_TIRTC_AI||modeSTARTER_TIRTC_ROOM)stream_idAI_AUDIO_STREAM)||((modeSTARTER_TIRTC_VOIP||modeSTARTER_TIRTC_CALL)stream_idCALL_AUDIO_STREAM);...ESP_LOGI(TAG,audio subscribe mode%d stream%u accepted%d,(int)mode,(unsigned)stream_id,accepted);模式不对或流号不对accepted0对面说什么你都收不到——这是另一类单向无声的来源连接是通的订阅没过。看这行日志能直接定位。自己跑一遍微信通话要在真实设备上验证模拟器没有微信链路绑定的微信账号授权也过不去所以这篇的验证点全部依赖实机。路径需要什么做什么设备模拟器一台电脑不用装 ESP-IDF拉tirtc-server-example仓库thing-connect/device-sim/device-sim-py/下跑device_sim_main.py --mac AA:BB:CC:DD:EE:FF验证的是通话流程框架微信链路验不了浏览器烧固件立创实战派 ESP32-S3 V1.0.1/N16R8 USB 线不用装 ESP-IDFRelease 页下载*-full-16MB.bin浏览器打开 espressif.github.io/esptool-js地址填0x0Flash 三项都选keep烧完连XiaoTai-XXXX热点浏览器开 192.168.6.1 配网改代码自己编ESP-IDF 环境在starter_runtime.c的信令路径里加日志重新编译对着本文对照看本文的验证点在串口日志按信令顺序profile 上报成功device profile accepted api/v1/device/profile scenesstream,call,voip; WeChat calling is ready——没有这行后面全免。拨号提交[DEBUG-call] dial submitted target... typewechat stage...WHIP 完成[DEBUG-voip] WHIP worker completed generation... rc0等确认VoIP WHIP connected; awaiting CALL_CONNECTED generation...——这行出现后要等到第 5 步那行订阅日志才算真接通。订阅通过audio subscribe mode3 stream10 accepted1mode 3 是 VOIP。accepted0表示当前模式和流号的组合没通过检查。诚实限制微信链路有两端设备侧日志只能看到设备这一半服务端怎么处理0x2000仓库里看不到只能从行为反推。另外信令的时延跟网络有关本文不测时延。代码仓库github.com/tangeai/xiaotai-esp32本文代码都在lckfb-szpi-esp32s3-tirtc/components/starter_runtime/src/starter_runtime.c与components/starter_tirtc/src/starter_tirtc.c。国内访问慢可以用 Gitee 镜像gitee.com/tange-ai/xiaotai-esp32。代码开源、可自由取用。手边没有板子也能先看效果。把微信通话接进自己设备时先查这几件事先确认 profile 上报成功没有WeChat calling is ready就别往下查。WHIP 成功不是接通。等0x2000再启动媒体等确认的超时是 35 秒。主叫微信时建连凭据在 MQTT 回铃里拨号 HTTP 的响应在代码里只读了call_id。别在 MQTT 解析函数没返回时直接调 SDK 握手本工程的做法是独立任务加 PSRAM 栈。收不到对方声音先看audio subscribe ... accepted这行检查当前模式和流号的组合。挂断要走统一的通话结束函数媒体、连接、H5 连接开关、超时定时器一起复位漏一样就是下次通话的隐患。
延伸阅读

更多相关文章

2026/11/3 19:22:20

中亚跨境物流避坑指南:渠道选型、密度计费与清关实操全拆解

中亚跨境物流避坑指南:渠道选型、密度计费与清关实操全拆解 做跨境供应链这几年,接触过上百位发中亚、俄线的卖家和采购商,发现 90% 的新手第一次发货都会踩同一个坑:只看单价,忽略计费规则、清关能力和渠道稳定性&…

2026/11/3 19:22:20

知漫剧解决人物漂移:角色锁定与素材库双保险

AI 漫剧连载生产中,人物形象漂移是长期困扰创作者的难点,反复调试提示词也很难稳住人设。知漫剧(zz.jiaxunai.cn)依托角色锁定机制与素材库管理形成双重保障,在批量生产漫剧时稳定角色外观,搭配全链路工作台…

2026/11/3 19:17:20

Godot 入门(07):InputMap,让键盘管住小人

坐标搞明白晒,小人仲系个钉子户,钉喺 (96,64) 郁都唔郁。 这回给它接上键盘。 顺手堵咗个新手最常犯嘅毛病:按住唔放,人物一路跑飞。 一、先别写代码,先去配键 新手容易犯一个毛病,一上手就在脚本里写 if Input.is_key_pressed(KEY_W)。能跑,真的能跑。 但这条路走不远…

2026/11/3 20:02:24

HDMI转MIPI桥接选型:IT6616的4K带宽与lane配置

简介:联阳IT6616芯片数据手册面向硬件工程师、嵌入式显示方案开发者及HDMI-to-MIPI桥接选型人员,聚焦HDMI 1.4转MIPI CSI/DSI的低功耗、高质量视频转换需求,也可为替代TC358743XBG/TC358749XBG、LT6911C等方案提供器件级参考。压缩包内仅含1个…

2026/11/3 20:02:24

会话Cookie缺少HttpOnly告警:原理、修复与验证实战

“会话cookie中缺少HttpOnly属性”——这句话第一次出现在扫描报告里的时候,大多数人的第一反应都是:这玩意儿听着就不严重。它不像注入类问题那样能直接拖库,也不像反序列化那样一眼就是高危,就安安静静躺在中危列表里&#xff0…

2026/11/3 20:02:24

风电与储能协同调频技术解析

1. 风电调频:被低估的电网稳定器当大多数人提起风力发电机组时,第一反应往往是"靠天吃饭的不稳定电源"。但在这个新能源占比快速提升的时代,我亲眼见证了风电从单纯的"发电宝宝"成长为电网频率守护者的全过程。特别是在四…

2026/11/3 20:02:24

ABAP屏幕编程实战:从SE38/SE51到PBO/PAI与OK_CODE

简介:这份资源面向刚接触 SAP 系统界面开发或需要补齐屏幕设计基础的 ABAP 学习者,聚焦「screen 程序设计」这一核心技能,解决从创建程序、设计 Screen 到处理控件与逻辑流的完整流程掌握问题。压缩包内共 1 个 doc 文件,约 1.66M…

2026/11/3 20:02:24

前端图片上传0KB问题解析与解决方案

1. 前端图片上传0KB问题深度解析最近在VueElementUI项目中处理图片上传时,遇到了一个典型问题:部分用户上传的图片在服务器端显示为0KB的破损文件。这个问题看似简单,实则涉及前端文件处理机制、浏览器API使用规范、前后端交互协议等多个技术…

2026/11/3 19:57:23

Git远程与本地仓库文件传递核心操作指南

1. Git远程与本地仓库文件传递的核心逻辑作为版本控制系统的实际工作场景,Git的远程与本地仓库文件传递是每个开发者必须掌握的生存技能。我在团队协作项目中经历过无数次文件同步需求,从简单的代码推送到复杂的多分支合并,深刻理解这个看似基…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑