实机验证通过后,按 Kapi 无屏底座路线补齐 Pendant RTC 吊坠项目的迁移修复。 1. BLE 配网与资源隔离 - sdkconfig.defaults 开启 BT 优先 PSRAM 分配,并将 LWIP socket 上限提升到 20 - sdkconfig.defaults.esp32s3 允许 BSS/NOINIT 放入 PSRAM,释放内部 SRAM 给 BLE/WiFi/RTC - 配网模式 codec 使用 StartOutputOnly(),跳过麦克风 RX DMA 和 ES7210 输入链路 - ResetWifiConfiguration() 改为独立 wifi_reset task,避免在 iot_button/esp_timer 回调中阻塞延时 - WifiBoard 增加 IsWifiConfigMode(),供启动阶段判断是否走配网资源隔离路径 2. 音频底噪与 DMA 残留修复 - AudioCodec 增加 StartOutputOnly(),支持仅启动扬声器输出 - RTC 音频通道打开后灌入 200ms silence PCM,覆盖 I2S DMA 残留数据 - 软退出进入待命前重启 codec output 并再次灌静音,减少待命音/欢迎语前杂音 - box_audio_codec 在无硬件回采时使用 channel_mask=0,避免 I2S slot mask 被错误污染 3. 软件 loopback AEC - 引入 esp_aec 底层同步 API,使用 DAC 输出复制构建 ref ring - 上行 mic PCM 与延迟 ref 做同步消回声,适配无屏无硬件回采的 Pendant 形态 - AEC 采用 lazy init,减少启动阶段对 WiFi/BLE 内部 SRAM 的压力 - ref 静音时直接 passthrough,避免 AI 静音后误压制用户语音 - 在 player_pipeline_write 和 codec->OutputData 两条下行路径都追加 ref hook 4. RTC 连接稳定性与软退出 - VolcRtcProtocol 增加 LeaveRoom(bool notify_closed),支持 stop 房间但保留 rtc_handle - hibernate 路径使用 LeaveRoom(false),避免关闭回调顺手关掉 codec output 导致待命音无声 - LeaveRoom/ForceRebuildEngine 重置 downlink_is_pcm_ 和首包标志,避免本地 Opus 音效被当 PCM 播成杂音 - OpenAudioChannel 连续失败 3 次后 ForceRebuildEngine,清理 RTC SDK 内部异常状态 - 加入 DIAG-RTC socket/heap/PSRAM/RSSI 日志,便于定位 ICE socket 和内存问题 5. Dialog watchdog 与 BOOT 唤醒 - Dialog watchdog 到期不再写 reboot_dlg_idle 后 esp_restart - 新增 EnterIdleHibernate():软退房、清空残留音频队列、关闭麦克风、播放待命音后静默 - 新增 WakeFromHibernate():BOOT 唤醒后复用 RTC engine 并通过 ToggleChatState() 重连 RTC - BOOT 单击优先判断 IsHibernating(),异步唤醒,避免走普通按键状态机 - hibernate 期间禁止 PowerSaveTimer 进入 Light Sleep,保护 I2C/codec 总线 6. 文档与衍生项目沉淀 - 更新石头光源属性检测方案文档 - 将 Pendant 实测通过的软退出、AEC、BLE 配网隔离经验同步到衍生项目移植规则
62 lines
2.2 KiB
C++
62 lines
2.2 KiB
C++
#ifndef _AUDIO_CODEC_H
|
||
#define _AUDIO_CODEC_H
|
||
|
||
#include <freertos/FreeRTOS.h>
|
||
#include <freertos/event_groups.h>
|
||
#include <driver/i2s_std.h>
|
||
|
||
#include <vector>
|
||
#include <string>
|
||
#include <functional>
|
||
|
||
#include "board.h"
|
||
|
||
class AudioCodec {
|
||
public:
|
||
AudioCodec();
|
||
virtual ~AudioCodec();
|
||
|
||
static constexpr int kDefaultOutputVolume = 40; // 默认输出音量 系统默认音量设置为100(最大音量),原来为70 产测固件使用
|
||
inline static int default_output_volume() { return kDefaultOutputVolume; }
|
||
|
||
virtual void SetOutputVolume(int volume);
|
||
virtual void SetOutputVolumeRuntime(int volume);// 运行时设置输出音量
|
||
virtual void EnableInput(bool enable);
|
||
virtual void EnableOutput(bool enable);
|
||
|
||
void Start();
|
||
void StartOutputOnly();
|
||
void OutputData(std::vector<int16_t>& data);
|
||
bool InputData(std::vector<int16_t>& data);
|
||
|
||
inline bool duplex() const { return duplex_; }
|
||
inline bool input_reference() const { return input_reference_; }
|
||
inline int input_sample_rate() const { return input_sample_rate_; }
|
||
inline int output_sample_rate() const { return output_sample_rate_; }
|
||
inline int input_channels() const { return input_channels_; }
|
||
inline int output_channels() const { return output_channels_; }
|
||
inline int output_volume() const { return output_volume_; }
|
||
inline bool input_enabled() const { return input_enabled_; }
|
||
inline bool output_enabled() const { return output_enabled_; }
|
||
|
||
protected:
|
||
i2s_chan_handle_t tx_handle_ = nullptr;
|
||
i2s_chan_handle_t rx_handle_ = nullptr;
|
||
|
||
bool duplex_ = false;
|
||
bool input_reference_ = false;
|
||
bool input_enabled_ = false;
|
||
bool output_enabled_ = false;
|
||
int input_sample_rate_ = 0;
|
||
int output_sample_rate_ = 0;
|
||
int input_channels_ = 1;
|
||
int output_channels_ = 1;
|
||
// int output_volume_ = 60; // 系统默认音量设置为60,原来为70 生产环境需要恢复为60
|
||
int output_volume_ = kDefaultOutputVolume; // 系统默认音量设置为100(最大音量),原来为70 生产测试音量
|
||
|
||
virtual int Read(int16_t* dest, int samples) = 0;
|
||
virtual int Write(const int16_t* data, int samples) = 0;
|
||
};
|
||
|
||
#endif // _AUDIO_CODEC_H
|