前言
高通新一代音频架构。
应用 / PulseAudio(module-pal-card)
│ pal_stream_open/start/… (PAL API)
▼
PAL (libpal.so) ← 用户空间控制层
├── session/SessionAgm.cpp ──┐
└── session/SessionAlsaPcm.cpp
│ │
▼ ▼
AGM 驱动(/dev/agm*) ALSA 声卡(/dev/snd/*) ← 内核
│ │
▼ │
GSL ──RPC──► │
│ │
▼ ▼
SPF(ADSP 固件音频图) ← 固件
│
▼
硬件(codec / I2S / SoundWire)
整体就是 AudioReach
本文将以高通Linux项目为例分析学习这套架构。
整体架构
[应用] 播放器 / 录音 / 通话 / 语音助手
| libpulse
v
[PulseAudio 服务端] system.pa: load-module module-qal-card
| module-qal-card.so <- PA 里高通写的模块
v
[PAL] libpal.so <- 包名 qal,真正的音频控制库
| AGM API \ tinyalsa
v v
[AGM] libagm.so [ALSA 前端] libtinyalsa.so
| gsl_* | /dev/snd/*
v v
[传输/服务库] libgsl.so libgpr.so libar_osal.so libacdbdata
| fastrpc / GLINK / QMI
v
[内核] AudioReach DLKM (ASoC + codec + SoundWire + spf-core) + ALSA
|
v
[ADSP 固件] SPF 音频图 (解码/混音/音效/回声消除)
|
v
[硬件] WCD 编解码 / SoundWire / I2S / 功放 / 喇叭麦克风
主线流程
① 应用
paplay / SIMCom_AudioPlayMusic …
│ libpulse (写入 PCM)
▼
② PulseAudio 服务端
sink = low-latency0 (PAL_STREAM_LOW_LATENCY)
活动端口 = speaker
│
▼
③ module-qal-card.so (PA 里高通的 QAL 模块)
- 卡片配置 bengal-scubaidp-snd-card.conf:
[Port speaker] device = PAL_DEVICE_OUT_SPEAKER
[Sink low-latency0] port-names = speaker headset
- qal-utils.c 映射表: "speaker" -> PAL_DEVICE_OUT_SPEAKER
- qal-sink.c:274 pal_sdata->pal_device->id = port_device_data->device
- qal-sink.c:1089 pal_stream_open(attr, 1, pal_device, …)
│
▼
④ PAL libpal.so
pal_stream_open(dev.PAL_DEVICE_OUT_SPEAKER)
-> StreamPCM
-> Device::getInstance() -> Speaker (device/src/Speaker.cpp)
-> Device::configure():
rm->getBackendName(SPEAKER) = "CODEC_DMA-LPAIF_RXTX-RX-0"
SessionAlsaUtils::setDeviceMediaConfig(...) // 配 DSP 后端
rm->getSndDeviceName(SPEAKER) = "speaker"
enableDevice(audioRoute, "speaker")
-> Device::start_l(): 打开后端
│
▼
⑤ audio_route(libaudioroute)
读 /etc/mixer_paths_bengal_scubaidp.xml
应用 <path name="speaker">:
RX_MACRO RX0 MUX = AIF1_PB
RX_CDC_DMA_RX_0 Channels = One
RX INT0_1 MIX1 INP0 = RX0
RX INT0 DEM MUX = CLSH_DSM_OUT
LO_RDAC Switch = 1
SpkrMono WSA_RDAC = Switch
│
▼
⑥ AGM/GSL -> DSP(SPF)
建 graph,媒体流经 AIF1_PB 进 DSP 音频图
│
▼
⑦ 内核 codec / 硬件
LO_RDAC -> LO PGA -> Ext Spk(rouleur) -> 外部功放 -> 扬声器出声
pal
概述
pal是内部带有cs(IPC)架构,但是可以选择直连(进程内调用 libpal.so) 和 IPC(通过 client 走 binder 到 server),本文参考的qcm2290使用的是cs架构。
代码路径
主代码和配方路径:
apps_proc/src/vendor/qcom/opensource/pal/
apps_proc/poky/meta-qti-arpal/recipes/qal/qal_git.bb
头文件配方:
apps_proc/poky/meta-qti-arpal/recipes/qal/qal-headers_git.bb
c端代码:
apps_proc/poky/meta-qti-arpal/recipes/palclient/palclient.bb、.../palserver/palserver.bb
pal/ipc/SwBinders/pal_ipc_*
libpal.so(配方包名 qal) 本体/服务端实现
libpalclient.so 客户端代理
libpalserverwrapper.so 服务端封装
pa
概述
需要注意高通旧的架构是qal ,qualcomm audio library
pal是新的名字 platform audio layer ,就是audioreach
因此本项目用的就是pal
代码路径
主要代码和配方(底层调用的还是pal,pa内部明明仍然是qal,qal和pal两个文件夹内容完全一致):
apps_proc/src/external/pulseaudio/src/modules/qal/module-qal-card/
apps_proc/poky/meta-qti-qmmf/recipes/pulseaudio/recipes/pulseaudio_15.0.bb
配置文件:
.../meta-qti-qmmf/recipes/pulseaudio/recipes/files/system-qcm2290-mtp.pa
.../recipes/files/ar-pulseaudio.service
sink
/ # pactl list sinks short
1 low-latency0 module-qal-card.c s16le 2ch 48000Hz SUSPENDED
2 deep-buffer0 module-qal-card.c s16le 2ch 48000Hz SUSPENDED
3 offload0 module-qal-card.c s16le 2ch 48000Hz SUSPENDED
module-qal-card
config配置选择
apps_proc/src/external/pulseaudio/src/modules/qal/module-qal-card/configs
下面多个配置文件,但是只会选择一个作为配置文件。以声卡名来选择,找不到退回default。
apps_proc/src/external/pulseaudio/src/modules/qal/module-qal-card/qal-config-parser.c中
pa_pal_config_parser_get_conf_file_name就是通过/proc/asound/cards这个路径来获取声卡名字。bengal-scubaidp-snd-card
端口
apps_proc/src/external/pulseaudio/src/modules/qal/module-qal-card/qal-utils.c
port_to_pal_device
apps_proc/src/external/pulseaudio/src/modules/qal/module-qal-card/configs/bengal-scubaidp-snd-card.conf
存放设备端口信息
也可以列出来:可以看到里面五个端口,正好和conf中对应。
# pactl list cards
...
Ports:
speaker: speaker (type: Unknown, priority: 200, latency offset: 0 usec, available)
Part of profile(s): default
handset-mic: builtin mic (type: Unknown, priority: 50, latency offset: 0 usec, available)
Part of profile(s): default
headset-mic: headset input (type: Unknown, priority: 50, latency offset: 0 usec, available)
Part of profile(s): default
headset: headset (type: Unknown, priority: 100, latency offset: 0 usec, available)
Part of profile(s): default
speaker-mic: builtin mic (type: Unknown, priority: 50, latency offset: 0 usec, available)
Part of profile(s): default
代码表中列出来的是设备枚举,conf中列出来的是端口具体属性。
代码表中端口多是因为要汇聚所有config的并集的超集,很多都用不到的。