AudioReach

dongwang 发布于 7 天前 20 次阅读


前言

高通新一代音频架构。

应用 / 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的并集的超集,很多都用不到的。