音频架构
Audio驱动框架基于HDF驱动框架实现,包含内核态(KHDF),和用户态(UHDF), 对北向提供音频HDI接口
音频框架图

驱动架构主要由以下几部分组成。
- HDI adapter:实现Audio HAL层驱动(HDI接口适配),给Audio服务(frameworks)提供所需的音频硬件驱动能力接口。包含 Audio Manager、Audio Adapter、Audio Control、Audio Capture、Audio Render等接口对象。
- Audio Interface Lib:向下配合内核中的Audio Driver Model使用,实现音频硬件的控制、录音数据的读取、播放数据的写入,向上和上层的Audio HDI Adapter层进行对接。
- ADM(Audio Driver Model):音频驱动框架模型,向上服务于多媒体音频子系统,向下统一接口适配各自的驱动代码。
主要代码目录
- drivers/hdf_core/framework/model/audio及- device/board/xxx/yyy/audio_drivers等: ADM相关驱动,KHDF部分
- drivers/peripheral/audio: audio HAL 实现,UHDF部分
- foundation/multimedia/audio_framework: audio framework 实现
调用流程

Audio Service
目录:foundation/multimedia/audio_framework/services/
client:
 通过 Remote()->SendRequest,和服务端进行通信(IPC),binder
 server:
 server端向上通过IPC与client交互,向下与HAL交互
使用PulseAudio进行音频流管理
 foundation/multimedia/audio_framework/services/audio_service/client/src/audio_service_client.cpp
HAL
HAL简单架构

- alsa adapter(drivers/peripheral/audio/supportlibs/alsa_adapter):
 基于alsa lib(alsa用户态接口库),对alsa接口的封装,向下驱动基于alsa
- adm adapter(drivers/peripheral/audio/supportlibs/adm_adapter):
 基于amate(ADM用户态接口库),对ADM接口的封装,向下驱动基于alsa
- supportlib
 屏蔽声卡访问控制的差异,在用户态实现一套符合 hdi-adapter 规范的访问控制
- hdi-passthrough
 将声卡(片内声卡、usb 声卡、HDMI 声卡等)抽象成 adapter,每个 adapter 都包含 supportlibs 抽象的 audioRender 和 audiocapture,最后通过 audiomanager 管理 adapters。进一步将音频 HDI 接口规范化封装
- hdi-binder
 HDF音频驱动框架最上层的封装,基于C/S的IPC机制
所以,由此可以得到音频驱动适配的几种主流方案:
- 通过”adm adapter”对接自研ADM内核驱动,是目前社区主流方案
- 通过”alsa lib”对接ASLA,是针对已支持ASLA产品的友好适配方案
- 通过自己实现Vendor HAL来对接音频HDI接口,主要针对厂商有自己成熟的音频中间件的情况
目录结构
从下面代码目录结构可以很容易和上面的架构图一一对应
zdd@zdd-PC:~/WorkSpace/OHOS/oh-v3.2.2/drivers/peripheral/audio$ tree -L 2
.
├── audio.gni
├── BUILD.gn
├── bundle.json
├── config
├── hal
│   ├── hdi_binder
│   │   ├── proxy
│   │   └── server
│   ├── hdi_passthrough
│   └── pathselect
├── hdi_service
│   ├── binder
│   ├── BUILD.gn
│   ├── passthrough
│   ├── pathselect
│   └── supportlibs
├── interfaces
│   ├── 2.0
│   └── include
├── supportlibs
│   ├── adm_adapter
│   ├── alsa_adapter
│   ├── BUILD.gn
│   └── interfaces
└── test├── BUILD.gn├── fuzztest├── resource├── sample├── systemtest└── unittest
HAL流程

ADM流程
ADM流程基本上都是基于驱动消息机制(dispatch)实现:drivers/peripheral/audio/supportlibs/adm_adapter/src/audio_interface_lib_common.c
下面看看几种基本的ADM流程:
ADM启动流程

- 系统启动时Audio模块的Platform、Codec、Dsp、Dai各个驱动首先被加载,各驱动从各自私有配置文件中获取配置信息,并将获取的配置信息保存到各驱动的Data数据结构中。
- 各驱动模块调用ADM注册接口将自己添加到各驱动模块的链表中。
- ADM模块读取hdf_audio_driver_0和hdf_audio_driver_1配置信息,加载各模块的具体设备。
- ADM模块调用各模块的初始化函数对各模块设备进行初始化。
- 将初始化成功的音频设备添加到cardManager链表。
HCS
以rk3568平台,结合上面的启动流程看看audio相关的hcs文件
- device_info.hcs:
...
audio :: host {hostName = "audio_host";priority = 110;device_dai0 :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "DAI_RK3568";serviceName = "dai_service";deviceMatchAttr = "hdf_dai_driver";}}device_codec_0 :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "CODEC_RK809";serviceName = "codec_service_0";deviceMatchAttr = "hdf_codec_driver_0";}}device_codec_1 :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "CODEC_RK817";serviceName = "codec_service_1";deviceMatchAttr = "hdf_codec_driver_1";}}device_dsp :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "DSP_RK3568";serviceName = "dsp_service_0";deviceMatchAttr = "hdf_dsp_driver";}}device_dma :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "DMA_RK3568";serviceName = "dma_service_0";deviceMatchAttr = "hdf_dma_driver";}}device_audio :: device {device0 :: deviceNode {policy = 2;priority = 60;preload = 0;permission = 0666;moduleName = "HDF_AUDIO";deviceMatchAttr = "hdf_audio_driver_0";serviceName = "hdf_audio_codec_primary_dev0";}device1 :: deviceNode {policy = 2;priority = 60;preload = 0;permission = 0666;moduleName = "HDF_AUDIO";deviceMatchAttr = "hdf_audio_driver_1";serviceName = "hdf_audio_codec_primary_dev11";}}device_stream :: device {device0 :: deviceNode {policy = 2;priority = 80;preload = 0;permission = 0666;moduleName = "HDF_AUDIO_STREAM";serviceName = "hdf_audio_render";}device1 :: deviceNode {policy = 2;priority = 80;preload = 0;permission = 0666;moduleName = "HDF_AUDIO_STREAM";serviceName = "hdf_audio_capture";}}device_control :: device {device0 :: deviceNode {policy = 2;priority = 80;preload = 0;permission = 0666;moduleName = "HDF_AUDIO_CONTROL";serviceName = "hdf_audio_control";}}device_analog_headset :: device {device0 :: deviceNode {policy = 1;priority = 90;preload = 0;permission = 0666;moduleName = "AUDIO_ANALOG_HEADSET";serviceName = "analog_headset_service";deviceMatchAttr = "analog_headset_attr";}}}
...
- audio_config.hcs:
hcs
root {platform {template card_controller {match_attr = "";serviceName = "";codecName = "";platformName = "";cpuDaiName = "";codecDaiName = "";dspName = "";dspDaiName = "";}controller_0x120c1000 :: card_controller {match_attr = "hdf_audio_driver_0";serviceName = "hdf_audio_codec_primary_dev0";codecName = "codec_service_0";platformName = "dma_service_0";cpuDaiName = "dai_service";codecDaiName = "codec_dai";dspName = "dsp_service_0";dspDaiName = "dsp_dai";}controller_0x120c1001 :: card_controller {match_attr = "hdf_audio_driver_1";serviceName = "hdf_audio_codec_primary_dev11";codecName = "codec_service_1";platformName = "dma_service_0";cpuDaiName = "dai_service";codecDaiName = "rk817_dai";dspName = "dsp_service_0";dspDaiName = "dsp_dai";}}
}
- codec_config.hcs
Code
root {platform {template codec_controller {match_attr = "";serviceName = "";codecDaiName = "";}controller_0x120c1030 :: codec_controller {match_attr = "hdf_codec_driver_0";serviceName = "codec_service_0";codecDaiName = "codec_dai";regConfig {/* reg, value */initSeqConfig = [0x13,    0xf4,...];controlsConfig = [/*array index, iface, mixer/mux, enable,*/0,  2,  0,  1,...];/* reg, rreg, shift, rshift, min, max, mask, invert, value */ctrlParamsSeqConfig = [0x31,    0x32,    0,    0,    0x00,    0xFF,   0xFF,   1,    0x00, // DACL/R Playback Volume...];/* reg, rreg, shift, rshift, min, max, mask, invert, value */daiParamsSeqConfig = [0x45,    0x45,    0,     0,    0x0,   0xFF,    0xFF,   0,     0x0C, // PLL_PREDIV_BIT...];ctrlSapmParamsSeqConfig = [0x27,    0x27,    5,     5,    0x00,    0x1,    0x1,    1,    0x00,     //LPGA MIC  -- connect MIC1...];/*sapmreg is 0xFFFF: component has no sapm register bitsapmType, compNameIndex, reg, mask, shift, invert, kcontrolNews, kcontrolsNum*/sapmComponent = [10,      0,       0x18,       0x1,     7,     1,     0,     0,  //ADCL...];/*array index, iface, mixer/mux, enable*/sapmConfig = [0,     2,    0,    1,...];}}controller_0x120c1031 :: codec_controller {match_attr = "hdf_codec_driver_1";serviceName = "codec_service_1";codecDaiName = "rk817_dai";}}
}
ADM播放流程

- 播放音频时,Interface Lib层通过播放流服务下发Render Open指令,Audio Stream Dispatch服务收到指令后分别调用各模块的函数接口对指令进行下发。
- Interface Lib层通过控制服务下发通路选择指令,Control Dispatch控制服务收到指令后调用Dai模块接口设置通路。
- Interface Lib层通过播放流服务下发硬件参数,Audio Stream Dispatch服务收到参数后分别调用各模块参数设置接口,对硬件参数进行设置。
- Interface Lib层通过播放流服务下发播放启动指令,Audio Stream Dispatch服务收到指令后分别调用各模块启动接口,对各模块进行启动设置。
- Interface Lib层通过播放流服务下发音频数据,Audio Stream Dispatch服务收到数据后调用Platform AudioPcmWrite接口将音频数据传给Dma。
- Interface Lib层通过播放流服务下发播放停止指令,Audio Stream Dispatch服务收到指令后分别调用各模块停止接口,对各模块进行停止设置。
- Interface Lib层通过播放流服务下发Render Close指令,Audio Stream Dispatch服务收到指令后调用Platform AudioRenderClose对已申请资源进行释放。
ADM控制流程

- 设置音量,首先Interface Lib层通过控制服务下发获取音量范围指令,Control Dispatch控制服务收到指令后进行解析,并调用Codec模块Get函数,获取可设置音量的范围。
- Interface Lib层通过控制服务下发设置音量指令,Control Dispatch控制服务收到指令后进行解析,并调用Codec模块Set函数设置音量。
分布式音频组件
分布式音频是指多个设备之间音频外设跨设备协同使用的能力,如将设备A的音频通过设备B的Speaker进行播音,或者设备A使用设备B的Mic进行录音。
分布式音频不直接向应用提供接口,应用可以通过音频框架的接口来调用分布式音频能力,使用方式与本地音频一致。
概念说明
主控端(source) :分布式音频控制端设备,向被控端设备发送指令,实现在被控端设备上音频播放和录制的功能;
被控端(sink) :分布式音频被控制端设备,接收来自主控端设备的指令,使本地音频外设为主控端设备所用,用来播音或录音。

 为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
《鸿蒙 (Harmony OS)开发学习手册》
入门必看:https://qr21.cn/FV7h05
- 应用开发导读(ArkTS)
- 应用开发导读(Java)

HarmonyOS 概念:https://qr21.cn/FV7h05
- 系统定义
- 技术架构
- 技术特性
- 系统安全

如何快速入门:https://qr21.cn/FV7h05
- 基本概念
- 构建第一个ArkTS应用
- 构建第一个JS应用
- ……

开发基础知识:https://qr21.cn/FV7h05
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……

基于ArkTS 开发:https://qr21.cn/FV7h05
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ……
