WiFi 音箱方案 (wifi_soundbox)
WiFi 智能音箱(大屏音箱 / 网络音频 / 带屏故事机)完整 SDK 方案,基于 AC792N 系列(wl83 平台)双核浮点 DSP,运行在 uC/OS 之上,集成了 WiFi 网络音频、蓝牙、音频 DSP 处理、UI 显示(LVGL)与智能语音等能力,构建目标为 ac792n_wifi_soundbox。
Purpose and Scope
本文档面向 sdk/apps/wifi_soundbox/ 目录下的 WiFi 音箱方案,系统性地说明该方案的:
- 应用入口与系统任务/中断注册(
app_main.c、app_msg.c) - 应用级配置体系(
include/app_config.h→board/wl83/sdk_config.h→board/wl83/board_config.h) - 板级开发与构建配置(
board/wl83/下的 Makefile、Code::Blocks 工程、chip_cfg、sdk_config) - 音频特性模块(
audio/下的麦克风音效、场景切换、提示音表、音量同步) - 构建入口与工程定义(
project.jlproj、make ac792n_wifi_soundbox)
同一仓库中的其他方案(WiFi 摄像头、婴儿监护器、demo 等)不在本文档范围内:
- 对于 WiFi 摄像头方案,参见
sdk/apps/wifi_camera/及其对应文档页。 - 对于 婴儿监护器方案,参见
sdk/apps/wifi_bbm/及其对应文档页。 - 对于芯片平台(wl83 双核 DSP、内存与外设驱动)的通用说明,参见芯片平台相关文档页。
Overview
方案定位
根据 README.md 的描述,wifi_soundbox 方案面向 大屏智能音箱、网络音频、带屏故事机 等产品形态。它是一个典型的"带屏 + 网络 + 语音"综合方案:既具备传统蓝牙音箱的 A2DP/AVRCP 播放能力,又具备基于 WiFi 的在线音乐/网络音频能力,同时通过 LVGL 渲染 UI、通过 KWS(关键词唤醒)与智能语音提供交互。
该方案建立在 wl83 平台(AC7921A/AC7922A/AC7922C/AC7923A/AC7923B/AC7923C/AC7925A/AC7925B/AC7925C/AC7926A)之上,芯片为 双核浮点 DSP @ 320MHz,支持 wifi_camera / wifi_soundbox / wifi_bbm / demo 四种应用形态共用同一套芯片与 SDK 基础。
工程与构建入口
project.jlproj 将该工程的 SDK 类型定义为 wifi_soundbox、产品类型为 "音箱",默认编译变体指向 .\sdk\apps\wifi_soundbox\board\wl83,构建任务名为 ac792n_wifi_soundbox:
{
"type": "音箱",
"sdk": "wifi_soundbox",
"singleSeries": false,
"defaultVariant": {
"path": ".\\sdk\\apps\\wifi_soundbox\\board\\wl83",
"task": "ac792n_wifi_soundbox"
}
}
Sources:
命令行构建方式(README.md):
make ac792n_wifi_soundbox
方案目录结构
sdk/apps/wifi_soundbox/
├── app_main.c # 应用主入口:中断表、系统任务表、外设/模块初始化
├── app_msg.c # 应用消息分发与处理
├── include/
│ └── app_config.h # 应用级配置:音频源、资源分区、UI/音频预留区
├── audio/
│ ├── mic_effect.c # 麦克风音效处理
│ ├── scene_switch.c # 场景切换
│ ├── tone_table.c # 提示音(Tone)表
│ └── vol_sync.c # 音量同步
└── board/wl83/ # wl83 板级支持
├── AC792N_WIFI_SOUNDBOX.cbp # Code::Blocks 工程文件
├── Makefile # 构建脚本
├── board_config.h # 板级配置(引脚/外设)
├── board_develop.c # 板级初始化实现
├── board_develop_AC7922C.h / AC7925A.h / AC7925B.h / AC7926A.h # 各型号板级差异
├── chip_cfg.h # 芯片配置
├── include_dir.txt # 头文件搜索路径清单
├── jlstream_node_cfg.h # jlstream 音频节点配置
└── sdk_config.c / sdk_config.h # SDK 功能开关总配置
Architecture
下图展示了 wifi_soundbox 方案的整体分层架构:从编译期配置(.cbp / Makefile / sdk_config)到应用层(app_main、app_msg),再到音频/网络/蓝牙/显示等子系统,最终落到 wl83 芯片与 RTOS 之上。
flowchart TD
subgraph sg_Build["构建与配置层"]
CBP["AC792N_WIFI_SOUNDBOX.cbp<br/>Code::Blocks 工程"]
MK["board/wl83/Makefile<br/>make ac792n_wifi_soundbox"]
JL["project.jlproj<br/>sdk=wifi_soundbox, type=音箱"]
APP_CFG["include/app_config.h<br/>应用资源与音频源配置"]
SDK_CFG["board/wl83/sdk_config.h<br/>SDK 功能开关"]
BRD_CFG["board/wl83/board_config.h<br/>板级外设配置"]
end
subgraph sg_App["应用层"]
APP_MAIN["app_main.c<br/>中断表 + task_info_table + 模块初始化"]
APP_MSG["app_msg.c<br/>消息分发"]
end
subgraph sg_Feature["特性模块 (audio/)"]
MIC["mic_effect.c<br/>麦克风音效"]
SCENE["scene_switch.c<br/>场景切换"]
TONE["tone_table.c<br/>提示音表"]
VOL["vol_sync.c<br/>音量同步"]
end
subgraph sg_Subsys["子系统 (apps/common + include_lib)"]
NET["WiFi / 网络音频<br/>(net_event, pjsip, net_music)"]
BT["蓝牙<br/>(bt_event, a2dp_dec, rcsp)"]
AUDIO["音频 DSP<br/>(dac, aec, mic_effect, jlstream)"]
UI["UI 显示<br/>(LVGL / freetype / rlottie)"]
VOICE["智能语音<br/>(kws, smart_voice, audio_vad)"]
end
subgraph sg_Platform["平台层 (wl83)"]
RTOS["uC/OS + 系统任务<br/>(app_core, sys_event, systimer...)"]
DSP["双核浮点 DSP @ 320MHz"]
FLASH[("Flash / SDNAND 资源分区")]
end
JL --> MK
CBP --> MK
APP_CFG --> SDK_CFG --> BRD_CFG
MK --> APP_MAIN
APP_MAIN --> APP_MSG
APP_MAIN --> MIC
APP_MAIN --> SCENE
APP_MAIN --> TONE
APP_MAIN --> VOL
APP_MSG --> NET
APP_MSG --> BT
APP_MAIN --> AUDIO
APP_MAIN --> UI
APP_MAIN --> VOICE
NET --> RTOS
BT --> RTOS
AUDIO --> RTOS
UI --> RTOS
VOICE --> RTOS
RTOS --> DSP
APP_CFG --> FLASH
架构说明:
- 构建与配置层是整个方案的"入口开关":
.cbp工程通过-DCONFIG_WIFI_SOUNDBOX_PROJECT_ENABLE等宏把 SDK 编译成音箱形态;app_config.h→sdk_config.h→board_config.h的三级配置链从"应用需求"逐级落到"芯片外设"。 - 应用层只负责两件事:注册中断与任务(
app_main.c),以及把事件(按键/蓝牙/设备/网络)分发给各功能模块(app_msg.c)。 - 特性模块是方案独有的差异化能力:麦克风音效、场景切换、提示音表与音量同步,直接服务于"音箱"的产品体验。
- 子系统全部来自
apps/common与include_lib(蓝牙协议栈 BTStack、网络栈 pjlib/pjsip、LVGL 等),方案通过条件编译宏决定启用哪些子系统。 - 平台层最终由 uC/OS 调度这些任务到 wl83 双核 DSP 上运行,Flash/SDNAND 分区由
app_config.h的资源预留宏定义。
应用入口与系统任务(app_main.c)
app_main.c 是方案的运行起点,它承载了三类静态定义:中断注册表、系统任务表、以及由系统框架调用的初始化函数。理解这个文件就等于理解整个方案的"调度骨架"。
中断注册表(irq_info_table)
方案通过 irq_info_table[] 显式声明中断号、优先级(0-7)以及注册到哪个 CPU 核:
const struct irq_info irq_info_table[] = {
//中断号 //优先级0-7 //注册的cpu(0或1)
#ifdef CONFIG_IPMASK_ENABLE
//不可屏蔽中断方法:支持写flash,但中断函数和调用函数和const要全部放在内部ram
#if 0 //如下,SPI1使用不可屏蔽中断设置
{ IRQ_SPI1_IDX, 7, 1 },//中断强制注册到cpu0/1
#endif
#endif
{ IRQ_BT_TIMEBASE_IDX, 5, 0 },
{ IRQ_BLE_RX_IDX, 5, 0 },
{ IRQ_BLE_EVENT_IDX, 5, 0 },
{ IRQ_BT_CLKN_IDX, 5, 0 },
{ IRQ_BREDR_IDX, 5, 0 },
#if CPU_CORE_NUM == 1
{ IRQ_SOFT5_IDX, 6, 0 }, //此中断强制注册到cpu0
{ IRQ_SOFT4_IDX, 6, 1 }, //此中断强制注册到cpu1
{ -2, -2, -2 }, //如果加入了该行, 那么只有该行之前的中断注册到对应核, 其他所有中断强制注册到CPU0
#endif
{ -1, -1, -1 },
};
Source: app_main.c
设计意图分析:
- 蓝牙相关中断(
IRQ_BT_TIMEBASE_IDX、IRQ_BLE_RX_IDX、IRQ_BLE_EVENT_IDX、IRQ_BT_CLKN_IDX、IRQ_BREDR_IDX)统一注册到 CPU0、优先级 5,保证蓝牙基带时序的确定性——蓝牙协议对时基中断的抖动极其敏感,必须固定核并给予较高优先级。 - 当
CPU_CORE_NUM == 1时,IRQ_SOFT5_IDX强制到 CPU0、IRQ_SOFT4_IDX强制到 CPU1,用于核间软中断通信;哨兵行{ -2, -2, -2 }之后的所有中断全部强制注册到 CPU0,这是为了在单核运行模式下把关键中断收敛到一个核上,避免中断分布导致不可预期的竞争。 - 表尾
{ -1, -1, -1 }是数组终止标记。
系统任务表(task_info_table)
app_main.c 为每个系统任务预先静态分配 TCB、栈与消息队列(静态分配避免了运行时 malloc 的不确定性,这对音频实时性至关重要):
/*创建使用 os_task_create_static 或者task_create 接口的 静态任务堆栈*/
#define SYS_TIMER_STK_SIZE 512
#define SYS_TIMER_Q_SIZE 256
static u8 sys_timer_tcb_stk_q[sizeof(StaticTask_t) + SYS_TIMER_STK_SIZE * 4 + sizeof(struct task_queue) + SYS_TIMER_Q_SIZE] ALIGNE(4);
#define APP_CORE_STK_SIZE 2048
#define APP_CORE_Q_SIZE 1024
static u8 app_core_tcb_stk_q[sizeof(StaticTask_t) + APP_CORE_STK_SIZE * 4 + sizeof(struct task_queue) + APP_CORE_Q_SIZE] ALIGNE(4);
Source: app_main.c
随后 task_info_table[] 以"任务名 + 优先级 + 栈大小 + 队列大小 + 静态内存块"的形式注册全部任务:
const struct task_info task_info_table[] = {
{ "app_core", 15, APP_CORE_STK_SIZE, APP_CORE_Q_SIZE, app_core_tcb_stk_q },
{ "sys_event", 29, SYS_EVENT_STK_SIZE, 0, sys_event_tcb_stk_q },
{ "systimer", 14, SYSTIMER_STK_SIZE, 0, systimer_tcb_stk_q },
{ "sys_timer", 9, SYS_TIMER_STK_SIZE, SYS_TIMER_Q_SIZE, sys_timer_tcb_stk_q },
{ "thread_fork_kill", 25, 256, 0 },
{ "dlog", 1, 256, 128 },
...
{ "jlstream", 23, 768, 128 },
{ "a2dp_dec", 24, 768, 0 },
/* file dec任务不打断jlstream任务运行,故优先级低于jlstream */
{ "file_dec", 24, 768, 0 },
...
/* 麦克风音效任务优先级要高 */
{ "mic_effect", 26, 768, 0 },
/* 为了防止dac buf太大,通话一开始一直解码,导致编码输入数据需要很大的缓存,这里提高编码的优先级 */
{ "audio_enc", 26, 768, 128 },
{ "aec", 26, 768, 128 },
...
{ "dac", 22, 256, 128 },
{ "kws", 3, 256, 64 },
{ "smart_voice", 11, 512, 128 },
...
{ "usb_msd", 1, 512, 128 },
{ "uda_main", 2, 7000, 0 },
{ "update", 21, 512, 32 },
...
#if RCSP_MODE
{"rcsp", 17, 768, 128 },
...
#endif
};
Source: app_main.c
关键任务与设计意图:
| 任务 | 优先级 | 栈 | 职责与设计意图 |
|---|---|---|---|
app_core | 15 | 2048 | 应用主循环,消费 APP_CORE_Q_SIZE=1024 的消息队列,处理按键/蓝牙/网络/设备事件 |
sys_event | 29 | 512 | 系统事件分发(最高优先级之一),保证系统事件不被音频任务饿死 |
jlstream | 23 | 768 | jlstream 音频流(网络流/文件流)解码搬运 |
a2dp_dec | 24 | 768 | 蓝牙 A2DP 解码;注释明确"file_dec 不打断 jlstream 运行,故优先级低于 jlstream"——这是为了在网络音频播放时优先保证流的连续性 |
mic_effect | 26 | 768 | 麦克风音效,注释明确"麦克风音效任务优先级要高"——保证人声处理的实时性 |
audio_enc / aec | 26 | 768 | 音频编码与回声消除,注释解释了"提高编码优先级以避免 DAC 缓冲过大"的设计权衡 |
dac | 22 | 256 | DAC 输出 |
kws | 3 | 256 | 关键词唤醒(低优先级,功耗友好) |
smart_voice | 11 | 512 | 智能语音 |
uda_main | 2 | 7000 | 升级主任务(大栈,因为升级流程涉及文件系统与网络栈) |
update / dw_update | 21 | 512 | 升级辅助任务 |
rcsp | 17 | 768 | 杰理 RCSP 私有协议(APP 控制/OTA/文件传输),条件编译 RCSP_MODE |
优先级数值越小优先级越低(uC/OS 约定,dlog=1 最低,sys_event=29 最高)。音频链路任务集中在 22-26 区间、系统事件 29、应用 15,形成"系统事件 > 音频实时链路 > 应用逻辑 > 低优先级杂务"的调度层级。
核心数据流与运行流程
事件驱动模型
app_main.c 同时包含 event/key_event.h、event/bt_event.h、event/device_event.h、event/net_event.h 四类事件头文件,说明方案的运行模型是 事件驱动 + 消息队列:外设中断/协议栈回调产生事件,sys_event 任务将事件投递到 app_core 的消息队列,app_msg.c 负责分发处理。
sequenceDiagram
participant HW as 外设/协议栈<br/>(按键/蓝牙/WiFi/USB)
participant ISR as 中断服务程序<br/>(irq_info_table 注册)
participant SE as sys_event 任务<br/>(优先级29)
participant AC as app_core 任务<br/>(优先级15, Q=1024)
participant AM as app_msg.c<br/>消息分发
participant MOD as 功能模块<br/>(mic_effect/scene/tone/vol_sync...)
HW->>ISR: 硬件中断 (BT/BLE/网络/按键)
ISR->>SE: 产生系统事件
SE->>AC: 投递到 app_core 消息队列
AC->>AM: 取出消息
AM->>MOD: 按事件类型分发 (key/bt/device/net)
MOD-->>AM: 处理结果
AM-->>AC: 继续取下一个消息
音频数据流
方案的核心是音频:网络音频/文件解码/BT A2DP → DAC 输出;麦克风 → AEC 回声消除 → mic_effect 音效 → 编码/上行。任务优先级设计(dac=22、jlstream=23、file_dec/a2dp_dec=24、audio_enc/aec/mic_effect=26)确保实时链路不被低优先级任务打断。
flowchart LR
subgraph sg_In["输入源"]
S1["网络流 (jlstream)"]
S2["本地文件 (file_dec)"]
S3["蓝牙 A2DP (a2dp_dec)"]
S4["麦克风 (aud_capture)"]
end
subgraph sg_Proc["处理"]
P1["aec 回声消除"]
P2["mic_effect 音效"]
P3["audio_enc 编码"]
P4["dac 输出"]
P5["scene_switch 场景切换"]
end
subgraph sg_Out["输出"]
O1["扬声器 (DAC)"]
O2["上行/通话"]
O3["vol_sync 音量同步"]
end
S1 --> P4
S2 --> P4
S3 --> P4
S4 --> P1 --> P2 --> P3
P4 --> O1
P3 --> O2
P5 --> P4
P4 --> O3
注:以上任务与模块关系依据 app_main.c 中的任务表及注释整理;音频节点拓扑的最终定义位于
board/wl83/jlstream_node_cfg.h与audio_config.h。
配置体系
三级配置链
方案通过"应用配置 → SDK 配置 → 板级配置"三级头文件链完成从产品需求到硬件引脚的落地:
include/app_config.h— 应用级配置:音频采样源、资源分区、UI/音频预留区(产品生命周期最大情况定义)board/wl83/sdk_config.h— SDK 功能开关:蓝牙、网络、RCSP、LE Audio 等模块级使能board/wl83/board_config.h— 板级配置:引脚复用、外设(DAC/ADC/IIS/USB/Flash)、板型差异
app_config.h 首先定义音频编码采样源枚举,并声明解码播放走 DAC:
#define AUDIO_ENC_SAMPLE_SOURCE_MIC 0
#define AUDIO_ENC_SAMPLE_SOURCE_PLNK0 1
#define AUDIO_ENC_SAMPLE_SOURCE_PLNK1 2
#define AUDIO_ENC_SAMPLE_SOURCE_IIS0 3
#define AUDIO_ENC_SAMPLE_SOURCE_IIS1 4
#define AUDIO_ENC_SAMPLE_SOURCE_LINEIN 5
#define CONFIG_AUDIO_DEC_PLAY_SOURCE "dac"
#include "sdk_config.h"
#include "board_config.h"
Source: app_config.h
设计意图: 编码采样源枚举允许同一套编码框架(audio_enc 任务)灵活切换输入——麦克风、两个 P-Link 端口、两路 IIS、LineIn——音箱产品的通话/录音/伴奏场景都依赖这个抽象。
功能开关的级联覆盖
app_config.h 还演示了"上层关闭功能时自动收紧下层"的级联覆盖模式:
#ifndef CONFIG_BT_ENABLE
#undef TCFG_APP_BT_EN
#define TCFG_APP_BT_EN 0
#endif
#ifndef CONFIG_NET_ENABLE
#undef TCFG_APP_NET_MUSIC_EN
#define TCFG_APP_NET_MUSIC_EN 0
#endif
#if !defined TCFG_PC_ENABLE || !TCFG_PC_ENABLE
#undef TCFG_APP_PC_EN
#define TCFG_APP_PC_EN 0
#endif
Source: app_config.h
设计意图: 当 SDK 级宏(CONFIG_BT_ENABLE、CONFIG_NET_ENABLE)被关闭时,应用层对应功能自动失效,避免"SDK 未编译蓝牙但应用仍尝试初始化蓝牙"的编译/运行错误。这是典型的防御性配置设计——功能开关只在最底层(sdk_config)定义一次真值,上层全部以"未定义即禁用"的规则级联。
Flash / SDNAND 资源分区
app_config.h 中针对 CONFIG_SDFILE_EXT_ENABLE(SDNAND 扩展文件系统)定义了详细的分区参数,包括 16MB Flash 容量、HFS/HFAT/FAT1 三段布局及簇大小自适应计算(CONFIG_SDNAND_HFAT_CLUSTER_SIZE 依据分区长度在 0x1~0x40 之间取档,保证簇大小与分区规模匹配、减少内部碎片)。
同时,文件头部注释清晰描述了 Flash 尾部预留区布局:末尾 4K 保留给配置存储(禁止覆盖),其前依次是 UI 资源包(CONFIG_UI_PACKRES_LEN)与音频资源包(CONFIG_AUDIO_PACKRES_LEN):
/*
#------------------------------|
# (其他预留区配置项) |
#------------------------------|<----CONFIG_UI_PACKRES_ADR - CONFIG_AUDIO_PACKRES_LEN = CONFIG_AUDIO_PACKRES_ADR
# (CONFIG_AUDIO_PACKRES_LEN) |
#------------------------------|<----__FLASH_SIZE__ - 0x1000 - CONFIG_UI_PACKRES_LEN = CONFIG_UI_PACKRES_ADR
# (CONFIG_UI_PACKRES_LEN) |
#------------------------------|<----__FLASH_SIZE__ - 0x1000
# (4K Reserved) |
#------------------------------+<----__FLASH_SIZE__
*/
Source: app_config.h
设计意图: 预留区地址由 __FLASH_SIZE__ 从尾部倒推计算,而不是从头部顺序分配——这样 UI/音频资源包扩容时不需要搬动前面的固件分区,只需调整长度宏即可,适合产品生命周期内 UI 资源反复增删的迭代节奏。
构建系统与工程编译宏
Code::Blocks 工程(AC792N_WIFI_SOUNDBOX.cbp)
方案以 Code::Blocks 工程文件描述编译参数。编译器为 pi32v2_r3_empty_compiler,输出 sdk.elf(../../../../cpu/wl83/tools/sdk.elf),优化级别 -Oz(尺寸优先)、开启 LTO(-flto)、-ffunction-sections / -fdata-sections 便于链接期裁剪。工程通过 -D 宏直接定义了方案形态:
<Add option="-DCONFIG_RELEASE_ENABLE" />
<Add option="-DCONFIG_CPU_WL83" />
<Add option="-DMAX_AUDIO_ADC_CHANNEL_NUM=2" />
<Add option="-DCONFIG_UCOS_ENABLE" />
<Add option="-DCONFIG_THREAD_ENABLE" />
<Add option="-D__GCC_PI32V2__" />
<Add option="-DCONFIG_NEW_ECC_ENABLE" />
<Add option="-DCONFIG_WIFI_SOUNDBOX_PROJECT_ENABLE" />
<Add option="-DVM_MAX_PAGE_ALIGN_SIZE_CONFIG=64*1024" />
<Add option="-DVM_MAX_SECTOR_ALIGN_SIZE_CONFIG=64*1024" />
<Add option="-DVM_ITEM_MAX_NUM=256" />
<Add option="-DPJ_LINUX=1" />
<Add option="-DPJ_M_I386=1" />
<Add option="-DRLOTTIE_COMMIT_HASH="492fbb753924ae7cad27072a2b6ddedde88dc4bd"" />
<Add option="-DFREETYPE_COMMIT_HASH="ef54557bda3b17da1b7e42e8e207efd1842bcc05"" />
<Add option="-DFT2_BUILD_LIBRARY" />
<Add option="-DLVGL_COMMIT_HASH="release/v8.4_2409c8dfc6b8d9ae3f7970e1c333e743e0fd2911"" />
Source: AC792N_WIFI_SOUNDBOX.cbp
编译宏含义:
| 宏 | 含义 |
|---|---|
CONFIG_WIFI_SOUNDBOX_PROJECT_ENABLE | 方案标识宏:把 SDK 编译为 wifi_soundbox 音箱形态,是区分于 wifi_camera / wifi_bbm 的关键 |
CONFIG_CPU_WL83 | 目标芯片平台 wl83 |
CONFIG_UCOS_ENABLE / CONFIG_THREAD_ENABLE | 启用 uC/OS 与线程接口(对应 task_info_table 的调度) |
MAX_AUDIO_ADC_CHANNEL_NUM=2 | 最多 2 路 ADC 音频采样通道 |
CONFIG_NEW_ECC_ENABLE | 启用新版 ECC(Flash 坏块/纠错管理) |
VM_MAX_PAGE_ALIGN_SIZE_CONFIG=64*1024、VM_MAX_SECTOR_ALIGN_SIZE_CONFIG=64*1024、VM_ITEM_MAX_NUM=256 | 虚拟机(VM,掉电保存的参数存储)页/扇区对齐与条目上限 |
PJ_LINUX=1 / PJ_M_I386=1 | pjlib(SIP/网络协议栈)以 Linux 兼容模式编译 |
LVGL_COMMIT_HASH / FREETYPE_COMMIT_HASH / RLOTTIE_COMMIT_HASH | UI 渲染依赖的第三方库版本锁定(LVGL v8.4、FreeType、Rlottie 动效) |
工程同时引入了完整的三方依赖头文件路径:蓝牙(btstack、btctrler)、网络(pjsip、pjmedia、pjnath)、米家(mijia)、支付宝(alipay)、RCSP(杰理私有协议,含 rcsp_update 升级、file_transfer 文件传输、external_flash 等子模块)、USB(device/host)、更新(update)。
Source: AC792N_WIFI_SOUNDBOX.cbp
特性模块(audio/)
方案差异化的音频体验由 audio/ 目录四个模块提供:
| 文件 | 职责 | 说明 |
|---|---|---|
mic_effect.c | 麦克风音效 | 与 mic_effect 任务(优先级 26)配套,提供人声美化/混响等处理 |
scene_switch.c | 场景切换 | 在不同音频场景(音乐/通话/提示音)间切换 DAC 通路与处理链 |
tone_table.c | 提示音表 | 定义按键音/状态提示音的音符与时长表 |
vol_sync.c | 音量同步 | 在蓝牙音量、网络音量、本地音量之间同步,保证多音源切换时音量一致 |
这些模块由 app_main.c 引用(#include "mic_effect.h"、#include "audio_config.h"),并与 app_msg.c 的消息分发协同:例如按键事件触发 tone_table 播放提示音,蓝牙事件触发 vol_sync 同步音量,通话事件触发 scene_switch 切换场景。
配置选项速查
| 配置项(宏) | 位置 | 默认/取值 | 说明 |
|---|---|---|---|
CONFIG_WIFI_SOUNDBOX_PROJECT_ENABLE | .cbp | 定义 | 方案标识,启用音箱形态 |
CONFIG_CPU_WL83 | .cbp | 定义 | wl83 平台 |
MAX_AUDIO_ADC_CHANNEL_NUM | .cbp | 2 | ADC 采样通道数上限 |
VM_MAX_PAGE_ALIGN_SIZE_CONFIG | .cbp | 64*1024 | VM 页对齐大小 |
VM_MAX_SECTOR_ALIGN_SIZE_CONFIG | .cbp | 64*1024 | VM 扇区对齐大小 |
VM_ITEM_MAX_NUM | .cbp | 256 | VM 条目上限 |
CONFIG_AUDIO_DEC_PLAY_SOURCE | app_config.h | "dac" | 解码播放输出设备 |
AUDIO_ENC_SAMPLE_SOURCE_* | app_config.h | 0-5 | 编码采样源:MIC/PLNK0/PLNK1/IIS0/IIS1/LINEIN |
TCFG_APP_BT_EN | app_config.h | 1/0 | 蓝牙功能(受 CONFIG_BT_ENABLE 级联控制) |
TCFG_APP_NET_MUSIC_EN | app_config.h | 1/0 | 网络音乐(受 CONFIG_NET_ENABLE 级联控制) |
TCFG_APP_PC_EN | app_config.h | 1/0 | PC 模式(受 TCFG_PC_ENABLE 级联控制) |
CONFIG_SDFILE_EXT_ENABLE | app_config.h | 条件定义 | 启用 SDNAND 扩展文件系统与分区 |
__FLASH_SIZE__ | app_config.h | 16*1024*1024 | Flash 总容量(SDNAND 模式) |
CONFIG_UI_PACKRES_LEN / CONFIG_AUDIO_PACKRES_LEN | app_config.h | 按产品定义 | UI/音频资源包长度(预留区倒推) |
TCFG_LOCAL_TWS_ENABLE | sdk_config.h | 0/1 | 本地 TWS 双音箱 |
TCFG_LE_AUDIO_STREAM_ENABLE | sdk_config.h | 0/1 | LE Audio 流(wireless_trans.h) |
THIRD_PARTY_PROTOCOLS_SEL & MULTI_BOX_ADV_EN | sdk_config.h | 位掩码 | 多音箱广播(multi_box_adv) |
RCSP_MODE / RCSP_FILE_OPT | sdk_config.h | 0/1 | RCSP 协议及文件传输/升级 |
TEE_ENABLE | sdk_config.h | 0/1 | TEE 安全核任务(tee_core0/1) |
表中
sdk_config.h项依据app_main.c的条件编译引用(app_main.c)整理;board/wl83/sdk_config.h为最终真值定义处。
失败模式、边界情况与并发
任务调度与优先级倒置风险
task_info_table中音频任务(dac=22、jlstream=23、mic_effect/audio_enc/aec=26)优先级高于应用任务app_core=15。若应用层在回调中执行阻塞操作(如 Flash 擦写、文件系统 IO),会延迟音频任务——源码通过注释明确"file_dec 不打断 jlstream"、"提高编码优先级避免 DAC 缓冲过大",说明设计者已按实时性排序优先级;扩展时新增任务应遵循"音频链路 > 应用逻辑 > 低优先级杂务"的层级,避免在app_core或更低优先级任务中做长阻塞。kws=3(关键词唤醒)与smart_voice=11优先级很低,这是功耗优先的设计:唤醒监听只在空闲时运行;若产品需要"随时唤醒",需评估唤醒延迟是否可接受。
中断与任务并发
- 蓝牙中断全部固定 CPU0(优先级 5),
CPU_CORE_NUM == 1时哨兵行{ -2, -2, -2 }之后的中断强制收敛到 CPU0。扩展提示:若新增外设中断(如 SPI 触摸屏),需在irq_info_table中显式声明核与优先级,否则按哨兵规则默认注册到 CPU0,可能与蓝牙中断产生竞争。 - 单核模式下
IRQ_SOFT5/IRQ_SOFT4分别注册到 CPU0/CPU1 用于核间通信,核间共享数据必须使用系统提供的临界区/信号量原语,不要直接跨核访问静态缓冲区。
资源边界
app_core消息队列仅 1024 字节,高频率事件(如持续按键、网络状态抖动)可能造成队列溢出丢消息;sys_event等无队列任务依赖事件优先级抢占,阻塞其处理会引发系统事件堆积。- Flash 尾部 4K 为配置存储保留区,禁止覆盖(
app_config.h注释明确说明);UI/音频资源包长度按"产品生命周期最大情况"定义,改小长度宏会压缩预留区,需确认不会与固件分区重叠。
条件编译的级联风险
app_config.h 采用"未定义即禁用"的级联规则(CONFIG_BT_ENABLE → TCFG_APP_BT_EN 等)。注意:#ifndef CONFIG_BT_ENABLE 的判断意味着"只要该宏被定义(即使为 0),应用开关就保持原值"——修改 sdk_config.h 时若以 #define CONFIG_BT_ENABLE 0 方式关闭功能,应用层开关不会被自动清零,需要同步修改应用配置。
性能与运维考量
- 编译期优化:
-Oz(尺寸优先)+ LTO +-ffunction-sections/-fdata-sections面向 Flash 容量敏感的音箱产品;-Wframe-larger-than=2560告警阈值提示栈帧过大的函数(配合task_info_table的静态栈,避免栈溢出越界到相邻任务)。 - 静态资源预分配:所有关键任务(
app_core、sys_event、systimer、sys_timer)的 TCB/栈/队列均为静态数组,运行时零动态分配,保证长时间运行的稳定性——这对音箱这类 7x24 待机产品至关重要。 - 升级链路:
uda_main(7000 字节大栈)、update、dw_update、rcsp(RCSP 升级/文件传输)等任务构成 OTA 能力;升级过程中update/dw_update与音频任务并发,若升级失败需回滚,依赖 Flash ECC(CONFIG_NEW_ECC_ENABLE)与 VM 配置存储。
扩展点
- 新增音频场景:在
audio/scene_switch.c的场景枚举中扩展,并在app_msg.c的事件分发中接入触发条件;同步调整jlstream_node_cfg.h的音频节点拓扑。 - 新增音源:
app_config.h的AUDIO_ENC_SAMPLE_SOURCE_*枚举已预留 PLNK0/1、IIS0/1、LINEIN 等输入,编码侧无需改动,只需在板级(board_config.h/board_develop.c)使能对应输入通路。 - 自定义提示音:修改
audio/tone_table.c的音符-时长表,无需改动播放框架。 - 新增产品型号:
board/wl83/下已存在board_develop_AC7922C.h、board_develop_AC7925A.h、board_develop_AC7925B.h、board_develop_AC7926A.h等多型号差异头文件,新型号以相同模式增加板级头文件并在board_develop.c中按芯片型号条件编译。 - 接入第三方协议:工程已预置 mijia(米家)、alipay(支付宝)、RCSP 等协议头文件路径,通过
THIRD_PARTY_PROTOCOLS_SEL位掩码(如MULTI_BOX_ADV_EN多音箱广播)按位启用。
测试与验证
- 构建验证:
make ac792n_wifi_soundbox产出cpu/wl83/tools/sdk.elf(.cbp 中output定义),配合工程工具链完成编译/烧录。 - 功能验证建议覆盖:蓝牙 A2DP 播放与音量同步(
vol_sync)、网络音频播放(jlstream优先级验证)、通话回声消除(aec)、麦克风音效(mic_effect)、按键提示音(tone_table)、场景切换(scene_switch)、RCSP OTA 升级链路。 - 压力测试关注点:
app_core队列(1024 字节)在连续按键/网络事件下的丢包情况;Flash 尾部 4K 配置区的掉电写保护;多任务并发下的栈边界(-Wframe-larger-than告警对应函数)。
Related Links
- sdk/apps/wifi_soundbox/app_main.c — 方案入口:中断表、任务表与初始化
- sdk/apps/wifi_soundbox/include/app_config.h — 应用配置:音频源、资源分区、预留区布局
- sdk/apps/wifi_soundbox/board/wl83/AC792N_WIFI_SOUNDBOX.cbp — Code::Blocks 工程与编译宏
- sdk/apps/wifi_soundbox/board/wl83/Makefile — 构建脚本
- sdk/apps/wifi_soundbox/board/wl83/sdk_config.h — SDK 功能开关总配置
- sdk/apps/wifi_soundbox/board/wl83/board_config.h — 板级外设配置
- sdk/apps/wifi_soundbox/app_msg.c — 消息分发
- README.md — SDK 总览(wl83 平台、各方案构建命令)
- project.jlproj — 工程定义(sdk=wifi_soundbox、默认变体)