实测根因 (DIAG 埋点确认): 火山 RTC SDK 启动时一次性申请大量 lwIP socket fd,
默认 CONFIG_LWIP_MAX_SOCKETS=10 不够 SDK 分配, 触发 SocketConnection-Lite.c:191
bind local ip failed → ICE 协商失败 → wait connect bits=0x0 超时.
实测对比:
修复前: 冷启动 RTC join 30+ 秒超时 × 3 次失败
修复后: 冷启动 RTC join 1.6 秒成功, 软退出 + 唤醒重连 2.3 秒成功 ✅
修复内容:
[A] sdkconfig: CONFIG_LWIP_MAX_SOCKETS=10 → 20
根治 lwIP socket fd 不足. 16 是临界值, 20 留 25% 余量应对 burst 场景
(HTTP 重试 / DNS 查询 / NTP 同步并发). 代价: +6 fd × ~200B = 1.2 KB RAM (忽略).
[B] application.h/cc + volc_rtc_protocol.h/cc: 失败 3 次后销毁 + 重建 engine
新增 VolcRtcProtocol::ForceRebuildEngine() public 方法.
OpenAudioChannel 连续失败 3 次时调用 (application.cc:566-573):
- 销毁 rtc_handle_ + reset SDK 内部状态污染
- 等待 2 秒让 lwIP 释放残留 socket fd (TIME_WAIT)
- 触发 Phase 6 重建路径 (rtc_handle_=nullptr → Start())
应对 A 修复后仍可能出现的 SDK 内部状态错乱 (e.g. ICE Agent 异常).
本次实测未触发 (A 已解决主要问题), 但保留作为兜底防御.
[C] volc_rtc_protocol.cc: DIAG_RTC_BIND_ENABLE 一键开关诊断埋点
在 join_room 前/后 + ForceRebuildEngine 前/后打印:
- lwIP socket fd 使用量 (sockets=N/MAX)
- heap free + psram free
- WiFi rssi
- 失败时的 errno + strerror
验证完成后改 0 关闭, 编译器消除 #if 块, 零运行时开销.
文件改动:
sdkconfig | LWIP_MAX_SOCKETS 10→20
main/application.h | +audio_channel_retry_count_
main/application.cc | +重试计数 + static_cast → ForceRebuildEngine 调用
main/protocols/volc_rtc_protocol.h | +ForceRebuildEngine() 声明
main/protocols/volc_rtc_protocol.cc | +DIAG 埋点 + diag_count_used_sockets() + ForceRebuildEngine()
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
81 lines
3.4 KiB
C++
81 lines
3.4 KiB
C++
#ifndef _VOLC_RTC_PROTOCOL_H_
|
||
#define _VOLC_RTC_PROTOCOL_H_
|
||
|
||
#include "protocol.h"
|
||
#include "volc_rtc.h"
|
||
#include "base/volc_device_manager.h"
|
||
#include <freertos/FreeRTOS.h>
|
||
#include <freertos/event_groups.h>
|
||
#include <mutex>
|
||
#include <vector>
|
||
|
||
class VolcRtcProtocol : public Protocol {
|
||
public:
|
||
VolcRtcProtocol();
|
||
~VolcRtcProtocol();
|
||
|
||
void Start() override;
|
||
void SendAudio(const std::vector<uint8_t>& data) override;// 🔊 发送音频数据到RTC
|
||
void SendPcm(const std::vector<uint8_t>& data) override;// 🔊 发送PCM音频数据到RTC
|
||
void SendG711A(const std::vector<uint8_t>& data) override;// 🔊 发送G711A音频数据到RTC
|
||
bool OpenAudioChannel() override;// 🔊 打开音频通道
|
||
void CloseAudioChannel() override;// 🔊 关闭音频通道(仅 stop 媒体流,不退出房间)
|
||
|
||
// Phase 6+:退出 RTC 房间(仅 stop,保留 rtc_handle_ 供唤醒复用)
|
||
// notify_closed=false 时跳过 on_audio_channel_closed_,hibernate 路径用,避免 codec 被回调链关
|
||
// 与 CloseAudioChannel 区别:CloseAudioChannel 只停媒体流,房间仍占用
|
||
void LeaveRoom(bool notify_closed = true) override;
|
||
|
||
// 方案 B: 强制销毁并重建 RTC engine. 当 OpenAudioChannel 连续失败 N 次时调用,
|
||
// 清理 SDK 内部错乱状态 (如 lwIP socket fd 残留 / 内部缓存污染),
|
||
// 触发 Phase 6 的 rtc_handle_=nullptr → Start() 重建路径
|
||
void ForceRebuildEngine();
|
||
|
||
bool IsAudioChannelOpened() const override;// 🔊 检查音频通道是否已打开
|
||
void SendAbortSpeaking(AbortReason reason) override;// 🔊 发送中止通话请求
|
||
void SendStartListening(ListeningMode mode) override;// 🔊 发送开始监听请求
|
||
void SendTextMessage(const std::string& text) override;// 🔊 发送文本消息到RTC
|
||
void SendFunctionResult(const std::string& tool_call_id, const std::string& content) override;// 🔊 发送函数调用结果到RTC
|
||
|
||
/**
|
||
* @brief 设置Agent配置参数(如音色、提示词等)
|
||
* @param params JSON格式的配置参数字符串
|
||
*/
|
||
void SetAgentConfig(const std::string& params);
|
||
|
||
private:
|
||
EventGroupHandle_t event_group_handle_;
|
||
volc_rtc_t rtc_handle_ = nullptr;
|
||
std::mutex rtc_mutex_;
|
||
std::string extra_params_; // 存储额外的Agent配置参数
|
||
|
||
bool is_connected_ = false;
|
||
bool is_audio_channel_opened_ = false;
|
||
bool iot_ready_ = false;
|
||
volc_iot_info_t iot_info_ = {};
|
||
size_t opus_bytes_accum_ = 0;
|
||
size_t pcm_bytes_accum_ = 0;
|
||
size_t g711a_bytes_accum_ = 0;
|
||
size_t down_pcm_bytes_accum_ = 0;
|
||
size_t down_opus_bytes_accum_ = 0;
|
||
int opus_frames_accum_ = 0;
|
||
int pcm_frames_accum_ = 0;
|
||
int g711a_frames_accum_ = 0;
|
||
uint64_t uplink_last_log_us_ = 0;
|
||
std::vector<uint8_t> pcm_pending_;
|
||
std::vector<uint8_t> g711a_pending_;
|
||
bool first_downlink_logged_ = false;
|
||
|
||
static void MessageCallback(void* context, volc_msg_t* message);
|
||
static void DataCallback(void* context, const void* data, size_t len, volc_data_info_t* info);
|
||
|
||
void ParseServerMessage(const char* message);
|
||
void ProcessAudioData(const void* data, int size);
|
||
void SendText(const std::string& text) override;
|
||
void LogUplinkStatsMaybe();// 打印上传统计信息
|
||
void SendCtrl(const std::string& json);// 🔊 发送控制指令到RTC
|
||
void SendFunc(const std::string& json);// 🔊 发送函数调用指令到RTC
|
||
};
|
||
|
||
#endif
|