四博 AI 智能音箱方案升级:ESP32-S3/C3 + HFP 耳机 + A2DP 外置音箱 + 开源二次开发
1. 方案背景
传统 AI 智能音箱通常采用"本机麦克风 + 本机喇叭"的固定音频路径。这个方案适合家庭桌面场景,但在以下场景中会遇到明显限制:
- 隐私场景:用户不希望 AI 回答从设备喇叭外放出来。
- 噪音场景:车内、办公室、工厂、展厅等环境噪声较大,本机麦克风拾音效果下降。
- 车机场景:设备本身喇叭功率有限,更适合把 AI 语音输出到车载音响或外置蓝牙音箱。
- 二次开发场景:客户希望基于 ESP32-S3、ESP32-C3、ESP32-C2 等 ESP 系列快速扩展自己的 AI 硬件。
因此,四博 AI 智能音箱方案可以升级为:
ESP32-S3 / ESP32-C3 / ESP32-C2 主控
|
|-- Wi-Fi:连接云端大模型 / 小智后端 / 自建服务器
|-- BLE / BluFi:微信小程序配网、设备绑定
|-- VB6824:离线唤醒、离线命令、降噪、打断
|-- HFP:连接蓝牙耳机,实现耳机采集 + 耳机播放
|-- A2DP:连接外置蓝牙音箱,实现高质量语音输出
|-- I2S / UART:连接音频 Codec、功放或外置蓝牙音频模块
其中,HFP 耳机模式 主要解决隐私和噪声环境问题;A2DP 外置音箱模式主要解决车机、展厅、户外、商用场景的外放需求。
2. 硬件平台选型
四博智联的乐鑫系模组覆盖 ESP8266、ESP32、ESP32-S3、ESP32-C2、ESP32-C3、ESP32-C5、ESP32-C6 等多个系列。模组选型手册中将 ESP32-S3 定位在音视频/AI 市场,ESP32-C3/C2 更偏低成本 Wi-Fi + BLE 物联网场景。
2.1 高配 AI 音箱 / AI 双目 / AI 相机:ESP32-S3
适合场景:
AI 智能音箱
AI 双目机器人
AI 拍学机
AI 相机
带屏 AI 交互终端
车载 AI 语音终端
推荐配置:
主控:ESP32-S3
Flash:8MB / 16MB
PSRAM:建议 8MB
语音芯片:VB6824
音频 Codec:ES8311 / ES8388 / 其他 I2S Codec
功放:NS4150B / 其他 Class-D 功放
网络:Wi-Fi 2.4GHz
配网:BluFi / SoftAP
显示:SPI LCD / RGB LCD
优势:
1. 双核 240MHz,适合音频流、UI、网络任务并行运行
2. 支持 PSRAM,适合 LVGL、音频缓存、图片资源
3. 适合带屏、带表情、带摄像头、带本地动画的 AI 产品
4. 适合品牌客户做完整产品形态
2.2 低成本 AI 音箱 / AI 控制器:ESP32-C3
AI-C3 方案中,AI-02 是 ESP32-C3 与 VB6824 组合的小智 AI 开发板;文档中说明 ESP32-C3 支持 2.4GHz Wi-Fi 和 Bluetooth 5 LE,VB6824 负责离线语音识别、降噪、唤醒和本地命令识别。
推荐配置:
主控:ESP32-C3
Flash:4MB / 8MB / 16MB
语音芯片:VB6824
显示:1.28 寸 LCD 可选
网络:Wi-Fi 2.4GHz
配网:BluFi
应用:低成本 AI 音箱、AI 控制器、语音陪伴硬件
优势:
1. 成本低
2. 功耗低
3. Wi-Fi + BLE 足够完成配网、联网和 AI 通信
4. 适合无屏或小屏 AI 产品
2.3 HFP / A2DP 的关键说明
这里要特别注意:
ESP32-S3 / ESP32-C3 / ESP32-C2 主要是 Wi-Fi + BLE,不支持经典蓝牙 BR/EDR 音频协议栈。
HFP 和 A2DP 属于经典蓝牙音频协议,不能直接只靠 ESP32-S3/C3/C2 内部蓝牙实现。
因此工程上有两种实现方式:
方式 A:使用原始 ESP32 做经典蓝牙音频
ESP32 支持 Classic Bluetooth,可直接做 HFP / A2DP 相关开发,适合需要主控直接跑蓝牙音频协议栈的版本。
ESP32
|-- HFP Client:连接蓝牙耳机
|-- A2DP Sink / Source:连接蓝牙音箱
|-- Wi-Fi:连接 AI 后端
方式 B:ESP32-S3/C3 + 外置蓝牙音频模块
这是更推荐的产品化方式:
ESP32-S3 / ESP32-C3
|
|-- UART / I2S / PCM
|
外置蓝牙音频 SoC
|
|-- HFP 连接蓝牙耳机
|-- A2DP 连接外置蓝牙音箱
这样可以让 ESP32-S3/C3 继续负责:
AI 主控
Wi-Fi 联网
BluFi 配网
MQTT / WebSocket
UI 显示
设备状态管理
OTA
外置蓝牙音频模块负责:
HFP
A2DP
SBC 编解码
蓝牙配对
音频输入输出
产品稳定性会更好,开发复杂度也更低。
3. 系统架构设计
升级后的四博 AI 音箱建议采用分层架构:
┌────────────────────────────────────┐
│ Application │
│ 唤醒 / 对话 / 播放 / 模式切换 / OTA │
└────────────────────────────────────┘
│
┌────────────────────────────────────┐
│ AI Conversation Layer │
│ ASR / LLM / TTS / 小智协议 / WebSocket │
└────────────────────────────────────┘
│
┌────────────────────────────────────┐
│ Audio Router │
│ Local Speaker / HFP Headset / A2DP │
└────────────────────────────────────┘
│
┌────────────────────────────────────┐
│ Audio Driver Layer │
│ I2S Codec / VB6824 / BT Audio SoC │
└────────────────────────────────────┘
│
┌────────────────────────────────────┐
│ BSP / HAL │
│ ESP32-S3 / ESP32-C3 / GPIO / NVS │
└────────────────────────────────────┘
核心思想是:
不要把 AI 对话逻辑和音频输出方式绑定死,而是增加 Audio Router。
4. 音频路由抽象设计
4.1 音频输出模式定义
typedef enum {
AUDIO_ROUTE_LOCAL_SPEAKER = 0, // 本机喇叭
AUDIO_ROUTE_HFP_HEADSET, // 蓝牙耳机 HFP
AUDIO_ROUTE_A2DP_SPEAKER, // 外置蓝牙音箱 A2DP
} audio_route_t;
typedef enum {
AUDIO_INPUT_LOCAL_MIC = 0, // 本机麦克风
AUDIO_INPUT_HFP_MIC, // 蓝牙耳机麦克风
AUDIO_INPUT_VB6824, // VB6824 离线语音输入
} audio_input_t;
typedef struct {
audio_route_t output_route;
audio_input_t input_route;
bool privacy_mode;
bool noise_env_mode;
bool car_mode;
} ai_audio_config_t;
4.2 全局音频配置
static ai_audio_config_t g_audio_cfg = {
.output_route = AUDIO_ROUTE_LOCAL_SPEAKER,
.input_route = AUDIO_INPUT_VB6824,
.privacy_mode = false,
.noise_env_mode = false,
.car_mode = false,
};
4.3 音频路由切换接口
esp_err_t ai_audio_set_route(audio_route_t route)
{
switch (route) {
case AUDIO_ROUTE_LOCAL_SPEAKER:
ESP_LOGI("AI_AUDIO", "Switch output to local speaker");
// enable local codec + amp
// disable bt audio output
g_audio_cfg.output_route = route;
break;
case AUDIO_ROUTE_HFP_HEADSET:
ESP_LOGI("AI_AUDIO", "Switch output to HFP headset");
// connect HFP headset or switch SCO audio path
g_audio_cfg.output_route = route;
g_audio_cfg.privacy_mode = true;
break;
case AUDIO_ROUTE_A2DP_SPEAKER:
ESP_LOGI("AI_AUDIO", "Switch output to A2DP speaker");
// connect external A2DP speaker
g_audio_cfg.output_route = route;
g_audio_cfg.car_mode = true;
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
4.4 输入路由切换接口
esp_err_t ai_audio_set_input(audio_input_t input)
{
switch (input) {
case AUDIO_INPUT_LOCAL_MIC:
ESP_LOGI("AI_AUDIO", "Use local microphone");
break;
case AUDIO_INPUT_HFP_MIC:
ESP_LOGI("AI_AUDIO", "Use HFP headset microphone");
g_audio_cfg.noise_env_mode = true;
break;
case AUDIO_INPUT_VB6824:
ESP_LOGI("AI_AUDIO", "Use VB6824 wakeup and offline voice input");
break;
default:
return ESP_ERR_INVALID_ARG;
}
g_audio_cfg.input_route = input;
return ESP_OK;
}
5. HFP 耳机模式设计
HFP 的目标是:
1. AI 回复从蓝牙耳机播放
2. 用户语音从耳机麦克风采集
3. 适合隐私通话、办公室、嘈杂环境
4. 支持按键切换:本机模式 / 耳机模式
5.1 HFP 状态机
typedef enum {
HFP_STATE_IDLE = 0,
HFP_STATE_DISCOVERING,
HFP_STATE_CONNECTING,
HFP_STATE_CONNECTED,
HFP_STATE_AUDIO_OPEN,
HFP_STATE_AUDIO_CLOSING,
HFP_STATE_DISCONNECTED,
} hfp_state_t;
static hfp_state_t g_hfp_state = HFP_STATE_IDLE;
5.2 HFP 事件处理
如果使用原始 ESP32 直接做 HFP,可以使用 ESP-IDF Classic Bluetooth HFP Client 方向开发。下面是工程结构示例:
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_hf_client_api.h"
static const char *TAG = "HFP_CLIENT";
static void hfp_client_cb(esp_hf_client_cb_event_t event,
esp_hf_client_cb_param_t *param)
{
switch (event) {
case ESP_HF_CLIENT_CONNECTION_STATE_EVT:
ESP_LOGI(TAG, "HFP connection state: %d", param->conn_stat.state);
if (param->conn_stat.state == ESP_HF_CLIENT_CONNECTION_STATE_CONNECTED) {
g_hfp_state = HFP_STATE_CONNECTED;
} else if (param->conn_stat.state == ESP_HF_CLIENT_CONNECTION_STATE_DISCONNECTED) {
g_hfp_state = HFP_STATE_DISCONNECTED;
}
break;
case ESP_HF_CLIENT_AUDIO_STATE_EVT:
ESP_LOGI(TAG, "HFP audio state: %d", param->audio_stat.state);
if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED) {
g_hfp_state = HFP_STATE_AUDIO_OPEN;
ai_audio_set_route(AUDIO_ROUTE_HFP_HEADSET);
ai_audio_set_input(AUDIO_INPUT_HFP_MIC);
}
break;
case ESP_HF_CLIENT_BVRA_EVT:
ESP_LOGI(TAG, "Voice recognition activation event");
break;
default:
ESP_LOGI(TAG, "HFP event: %d", event);
break;
}
}
5.3 HFP 初始化
esp_err_t hfp_client_init(void)
{
esp_err_t ret;
ret = esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "release BLE memory failed: %s", esp_err_to_name(ret));
}
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bt controller init failed: %s", esp_err_to_name(ret));
return ret;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bt controller enable failed: %s", esp_err_to_name(ret));
return ret;
}
ret = esp_bluedroid_init();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bluedroid init failed: %s", esp_err_to_name(ret));
return ret;
}
ret = esp_bluedroid_enable();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "bluedroid enable failed: %s", esp_err_to_name(ret));
return ret;
}
esp_hf_client_register_callback(hfp_client_cb);
esp_hf_client_init();
ESP_LOGI(TAG, "HFP client initialized");
return ESP_OK;
}
对于 ESP32-S3 / ESP32-C3 方案,建议把 HFP 放在外置蓝牙音频模块中,ESP 主控通过 UART 控制:
ESP32-S3 UART TX/RX <----> BT Audio SoC
ESP32-S3 I2S <----> BT Audio SoC PCM/I2S Audio
6. A2DP 外置音箱模式设计
A2DP 模式主要用于:
1. 车机应用
2. 外接蓝牙音箱
3. 展厅讲解设备
4. 大音量外放场景
工作方式:
AI TTS PCM/Opus/MP3 数据
|
v
解码为 PCM
|
v
A2DP SBC 编码
|
v
蓝牙音箱播放
如果使用原始 ESP32,可以直接使用 A2DP 相关接口;如果使用 ESP32-S3/C3,则通过外置蓝牙音频 SoC 实现 A2DP。
6.1 A2DP 状态定义
typedef enum {
A2DP_STATE_IDLE = 0,
A2DP_STATE_CONNECTING,
A2DP_STATE_CONNECTED,
A2DP_STATE_STREAMING,
A2DP_STATE_DISCONNECTED,
} a2dp_state_t;
static a2dp_state_t g_a2dp_state = A2DP_STATE_IDLE;
6.2 A2DP 音频写入抽象
typedef struct {
esp_err_t (*start)(void);
esp_err_t (*stop)(void);
int (*write_pcm)(const uint8_t *data, size_t len);
} ai_audio_output_ops_t;
本机喇叭输出:
static int local_speaker_write_pcm(const uint8_t *data, size_t len)
{
size_t bytes_written = 0;
// i2s_channel_write(tx_handle, data, len, &bytes_written, portMAX_DELAY);
return bytes_written;
}
A2DP 输出:
static int a2dp_speaker_write_pcm(const uint8_t *data, size_t len)
{
// 如果是 ESP32 Classic BT:送入 A2DP source ringbuffer
// 如果是外置 BT SoC:通过 I2S/PCM/UART 送入外置模块
return len;
}
统一输出接口:
int ai_audio_write_pcm(const uint8_t *data, size_t len)
{
switch (g_audio_cfg.output_route) {
case AUDIO_ROUTE_LOCAL_SPEAKER:
return local_speaker_write_pcm(data, len);
case AUDIO_ROUTE_HFP_HEADSET:
// HFP SCO 通道通常为窄带/宽带语音,不适合大带宽音乐流
return hfp_write_voice_pcm(data, len);
case AUDIO_ROUTE_A2DP_SPEAKER:
return a2dp_speaker_write_pcm(data, len);
default:
return -1;
}
}
7. AI 对话数据流设计
升级后的 AI 音箱不是简单播放音频,而是完整语音链路:
唤醒词 / 按键
|
采集语音
|
VAD / 降噪 / AEC
|
上传服务器
|
ASR 语音识别
|
LLM 大模型推理
|
TTS 语音合成
|
音频路由
|---------------- 本机喇叭
|---------------- HFP 耳机
|---------------- A2DP 音箱
7.1 对话状态机
typedef enum {
AI_STATE_IDLE = 0,
AI_STATE_WAKEUP,
AI_STATE_LISTENING,
AI_STATE_UPLOADING,
AI_STATE_THINKING,
AI_STATE_SPEAKING,
AI_STATE_INTERRUPTED,
AI_STATE_ERROR,
} ai_state_t;
static ai_state_t g_ai_state = AI_STATE_IDLE;
7.2 对话状态切换
void ai_set_state(ai_state_t state)
{
if (g_ai_state == state) {
return;
}
ESP_LOGI("AI_STATE", "state: %d -> %d", g_ai_state, state);
g_ai_state = state;
switch (state) {
case AI_STATE_WAKEUP:
// 点亮屏幕 / 播放提示音
break;
case AI_STATE_LISTENING:
// 开始录音
break;
case AI_STATE_SPEAKING:
// 根据当前 audio_route 播放 TTS
break;
case AI_STATE_INTERRUPTED:
// 停止播放,重新进入监听
break;
default:
break;
}
}
8. 配网与开源二次开发
四博 AI 开发宝典中已经给出了 ESP-IDF + VSCode 开发环境、示例工程编译、DOIT_AI 工程获取、SoftAP 配网、BluFi 配网、开源后端服务等流程。文档中 DOIT_AI 工程开源地址为 SmartArduino/DOIT_AI,AI-C3 方案还提供 DOIT_AI_BluFi 开源工程用于微信小程序蓝牙配网。
建议二次开发目录结构如下:
components/
ai_audio_router/
ai_audio_router.c
ai_audio_router.h
ai_bt_audio/
ai_hfp_client.c
ai_a2dp_source.c
ai_bt_audio_bridge.c
ai_conversation/
ai_ws_client.c
ai_protocol.c
ai_tts_player.c
board/
board_s3_speaker.c
board_c3_ai02.c
board_c2_ai01.c
main/
app_main.c
8.1 app_main 示例
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
board_init();
wifi_init();
ai_audio_router_init();
ai_conversation_init();
#if CONFIG_AI_USE_BLUFI
blufi_prov_start();
#else
softap_prov_start();
#endif
#if CONFIG_AI_USE_EXTERNAL_BT_AUDIO
bt_audio_bridge_init();
#endif
ai_set_state(AI_STATE_IDLE);
ESP_LOGI("APP", "DOIT AI speaker started");
}
8.2 Kconfig 设计
menu "DOIT AI Audio Upgrade"
config AI_USE_HFP_HEADSET
bool "Enable HFP headset mode"
default y
config AI_USE_A2DP_SPEAKER
bool "Enable A2DP speaker mode"
default y
config AI_USE_EXTERNAL_BT_AUDIO
bool "Use external Bluetooth audio SoC"
default y
config AI_USE_LOCAL_SPEAKER
bool "Enable local speaker"
default y
config AI_DEFAULT_AUDIO_ROUTE
int "Default audio route"
default 0
help
0: Local speaker
1: HFP headset
2: A2DP speaker
endmenu
8.3 sdkconfig.defaults 示例
CONFIG_AI_USE_HFP_HEADSET=y
CONFIG_AI_USE_A2DP_SPEAKER=y
CONFIG_AI_USE_EXTERNAL_BT_AUDIO=y
CONFIG_AI_USE_LOCAL_SPEAKER=y
CONFIG_AI_DEFAULT_AUDIO_ROUTE=0
CONFIG_ESP_WIFI_ENABLED=y
CONFIG_BT_ENABLED=y
CONFIG_FREERTOS_HZ=1000
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
9. 外置蓝牙音频模块 AT 控制示例
如果 ESP32-S3/C3 使用外置蓝牙音频模块,可设计统一 AT 控制层:
9.1 UART 初始化
#define BT_UART_PORT UART_NUM_1
#define BT_UART_TX GPIO_NUM_17
#define BT_UART_RX GPIO_NUM_18
#define BT_UART_BAUD 115200
esp_err_t bt_audio_uart_init(void)
{
uart_config_t cfg = {
.baud_rate = BT_UART_BAUD,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
ESP_ERROR_CHECK(uart_driver_install(BT_UART_PORT, 2048, 2048, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(BT_UART_PORT, &cfg));
ESP_ERROR_CHECK(uart_set_pin(BT_UART_PORT, BT_UART_TX, BT_UART_RX,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
return ESP_OK;
}
9.2 发送 AT 命令
static esp_err_t bt_audio_send_cmd(const char *cmd)
{
if (!cmd) {
return ESP_ERR_INVALID_ARG;
}
uart_write_bytes(BT_UART_PORT, cmd, strlen(cmd));
uart_write_bytes(BT_UART_PORT, "\r\n", 2);
ESP_LOGI("BT_AUDIO", "TX: %s", cmd);
return ESP_OK;
}
9.3 HFP / A2DP 控制命令抽象
esp_err_t bt_audio_enter_hfp_mode(void)
{
bt_audio_send_cmd("AT+MODE=HFP");
bt_audio_send_cmd("AT+PAIR=1");
return ESP_OK;
}
esp_err_t bt_audio_enter_a2dp_mode(void)
{
bt_audio_send_cmd("AT+MODE=A2DP");
bt_audio_send_cmd("AT+PAIR=1");
return ESP_OK;
}
esp_err_t bt_audio_disconnect(void)
{
return bt_audio_send_cmd("AT+DISCONNECT");
}
实际 AT 指令需要根据所选蓝牙音频 SoC 的 SDK 或固件协议修改。
10. 应用场景
10.1 隐私 AI 助手
用户佩戴蓝牙耳机
AI 回复只在耳机中播放
本机喇叭不出声
适合卧室、办公室、学习场景
10.2 噪声环境 AI 交互
耳机麦克风靠近嘴部
远优于桌面设备远场拾音
适合车内、工厂、展会、户外
10.3 车机 AI 语音助手
AI 设备通过 A2DP 输出到车载蓝牙音响
ESP32-S3 负责 Wi-Fi/4G 后端通信
本机可选屏幕显示对话内容、导航提示、状态信息
10.4 B 端定制 AI 硬件
客户可基于 DOIT_AI 开源代码二次开发
可接入小智、豆包、ChatGPT、自建 LLM
可定制唤醒词、外壳、屏幕、按键、音频路径
11. 总结
四博 AI 智能音箱升级方案的核心不是简单增加蓝牙,而是把音频路径从固定的"本机麦克风 + 本机喇叭",升级为灵活可切换的多路音频系统:
本机模式:本机麦克风 + 本机喇叭
耳机模式:HFP 耳机麦克风 + HFP 耳机播放
车机模式:本机/VB6824 输入 + A2DP 外置音箱播放
开发模式:ESP32-S3/C3/C2 开源固件 + 可扩展音频模块
这样既保留了 ESP32-S3/C3 在 AIoT、屏幕交互、Wi-Fi 联网和开源生态上的优势,又通过 HFP/A2DP 扩展解决了隐私、噪声和车机外放等实际落地问题