PAL 总体架构与模块交互指南
1. 宏观架构:PAL 的世界观
欢迎来到 Qualcomm PAL (Platform Audio Layer) 的世界。为了更好地理解,我们继续使用餐厅的比喻:
- Android HAL (Client):顾客。负责点菜(提需求)。
- Stream (流):订单。记录了顾客要什么(听歌、打电话、录音),并负责整个服务流程的进度。
- Session (会话):厨房。负责真正的制作(DSP 音频处理、混音、重采样)。
- Device (设备):餐桌/外卖窗口。最终呈现声音的地方(喇叭、耳机)。
- ResourceManager (RM):大堂经理。统筹全局,安排哪个订单去哪个厨房,送到哪张桌子,处理突发情况(插队、换桌)。
2. 核心交互流程图
3. 深度解析:一次完整的音频播放
让我们跟踪一次“播放音乐”的全过程,看看各模块如何协作。
第一阶段:创建与建立连接 (Open)
- Client: 调用
pal_stream_open(STREAM_LOW_LATENCY, DEVICE_SPEAKER)。 - Stream: 创建
StreamPCM对象。 - Stream -> RM:
- 调用
rm->getDeviceConfig():经理,Speaker 需要什么参数?(RM 查 XML 返回:48kHz, 24bit)。 - 调用
Session::makeSession(rm):创建一个能处理 PCM 的厨房(通常是SessionAlsaPcm)。 - 调用
rm->registerStream():经理,记下来,现在有一单音乐要播放。
- 调用
- 关联: Stream 内部保存了
Session和Device的指针。连接建立完毕。
第二阶段:启动与资源分配 (Start)
- Client: 调用
pal_stream_start()。 - Stream -> RM: 经理,我要开始播了,可以吗?
- RM:
- 检查并发:现在有电话吗?有语音唤醒吗?(如果有,RM 会通知其他 Stream 暂停或由 DSP 混音)。
- 增加引用计数:Speaker 的使用人数 +1。
- Stream -> Device:
device->start()。- Device: 下发 Mixer Controls (如
"SLIMBUS_0_RX Audio Mixer MultiMedia1"),打通物理通路。
- Device: 下发 Mixer Controls (如
- Stream -> Session:
session->prepare()->session->start()。- Session:
- 从 RM 申请 FrontEnd ID (比如
pcm0p)。 - 从 Device 知道 BackEnd Name (比如
QUAT_TDM_RX_0)。 - 关键动作: 配置 DSP,告诉它“把 PCM0 的数据处理完后,送到 TDM_RX_0 接口”。
- 调用
pcm_start激活内核节点。
- 从 RM 申请 FrontEnd ID (比如
- Session:
第三阶段:数据传输 (Running)
- Client: 循环调用
pal_stream_write(buffer)。 - Stream: 不做处理,直接透传。
- Session: 调用
pcm_write(TinyALSA) 将数据写入共享内存或内核缓冲区。 - DSP/Kernel: 读取数据 -> 音效处理 -> 发送给 Codec -> 喇叭发声。
第四阶段:动态设备切换 (Device Switch)
场景:插耳机
- RM: 收到
ConnectionStateChange事件。 - RM: 扫描所有活跃 Stream,发现
MusicStream在用Speaker。 - RM -> Stream: 强制切换!
- 调用
stream->disconnectStreamDevice(Speaker)。 - 调用
stream->connectStreamDevice(Headphone)。
- 调用
- Stream:
- 暂停 Session 数据写入(防止杂音)。
Device(Speaker)->stop()。Device(Headphone)->start()。Session更新路由配置 (告诉 DSP 换出口)。- 恢复 Session 数据写入。
4. 模块间接口汇总
| 调用方 | 被调用方 | 关键接口 | 目的 |
|---|---|---|---|
| Stream | RM | registerStream | 注册自己,纳入管理 |
| Stream | RM | getDeviceConfig | 获取设备能力 |
| Stream | Session | open,start,write | 控制 DSP 管道 |
| Stream | Device | start,stop | 控制物理硬件开关 |
| RM | Stream | switchDevice | 通知流进行设备切换 |
| Session | RM | allocateFrontEndIds | 申请 PCM 设备号 |
| Session | RM | getVirtualAudioMixer | 获取 Mixer 句柄 |
5. 常见问题 (FAQ)
- Q: 为什么要分 Stream 和 Session?
- A: 解耦。Stream 关注业务(播放/录音/通话),Session 关注底层实现(TinyALSA/GSL/AGM)。如果高通换了底层架构(比如从 ALSA 换到 GSL),只需要重写 Session,Stream 层的业务逻辑不用动。
- Q: ResourceManager 的 XML 到底决定了什么?
- A: 它决定了“静态路由图”。比如:哪个流类型对应哪种 Session 模式?哪个 Device 对应哪个 Backend 接口?所有的硬件拓扑都在 XML 里。
- Q: 为什么会有并发问题?
- A: 硬件资源是有限的。比如 DSP 里的回声消除 (EC) 模块可能只有一个,或者某个 Backend 接口同一时间只能跑一个采样率。RM 的作用就是协调这些冲突。
6. 学习路线建议
- 入门: 先看
Stream模块介绍,理解业务流程。 - 进阶: 结合
ResourceManager 模块介绍和 XML 文件,理解系统是如何配置起来的。 - 深入: 阅读
Session 模块介绍和Device 模块介绍,理解数据到底是怎么送到底层的。 - 实战: 尝试在
resourcemanager.xml中新增一个 Device,并在代码中打通它。