OpenHarmony南向之Audio

news2025/1/16 5:14:10

音频架构

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/audiodevice/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机制

所以,由此可以得到音频驱动适配的几种主流方案:

  1. 通过”adm adapter”对接自研ADM内核驱动,是目前社区主流方案
  2. 通过”alsa lib”对接ASLA,是针对已支持ASLA产品的友好适配方案
  3. 通过自己实现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启动流程

  1. 系统启动时Audio模块的Platform、Codec、Dsp、Dai各个驱动首先被加载,各驱动从各自私有配置文件中获取配置信息,并将获取的配置信息保存到各驱动的Data数据结构中。
  2. 各驱动模块调用ADM注册接口将自己添加到各驱动模块的链表中。
  3. ADM模块读取hdf_audio_driver_0和hdf_audio_driver_1配置信息,加载各模块的具体设备。
  4. ADM模块调用各模块的初始化函数对各模块设备进行初始化。
  5. 将初始化成功的音频设备添加到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
                    ...
                ];
                /*
                 sapm
                 reg is 0xFFFF: component has no sapm register bit
                 sapmType, 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播放流程

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

ADM控制流程

  1. 设置音量,首先Interface Lib层通过控制服务下发获取音量范围指令,Control Dispatch控制服务收到指令后进行解析,并调用Codec模块Get函数,获取可设置音量的范围。
  2. 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

  1. 应用开发导读(ArkTS)
  2. 应用开发导读(Java)

HarmonyOS 概念:https://qr21.cn/FV7h05

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. 构建第一个JS应用
  4. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1331711.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java流浪动物保护系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web 流浪动物保护系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql…

Spring Boot实践指南

一.SpringBoot入门案例 SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程 原生开发SpringMVC程序过程 在没有SpringBoot前: 1.入门案例开发步骤 (1)创建新模块,选…

免费更新UltraNews v2.8.0 已注册 – Laravel报纸,博客多语言系统,支持AI作家,内容生成器脚本

UltraNews v2.8.0 已注册 – Laravel报纸,博客多语言系统,支持AI作家,内容生成器脚本 一、概述 在网络内容创作与管理领域,UltraNews v2.8.0以其高度现代化和多功能性而独树一帜。这是一个基于Laravel框架构建的报纸、博客多语言…

计算机网络概述(上)——“计算机网络”

各位CSDN的uu们好呀,好久没有更新小雅兰的计算机网络的专栏啦,而且期末考试也要考计算机网络,所以,小雅兰就来写计算机网络的内容啦!!!下面,让我们进入计算机网络概述的世界吧&#…

智能优化算法应用:基于蛇优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于蛇优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于蛇优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蛇优化算法4.实验参数设定5.算法结果6.参考文…

基于python的excel检查和读写软件

软件版本:python3.6 窗口和界面gui代码: class mygui:def _init_(self):passdef run(self):root Tkinter.Tk()root.title(ExcelRun)max_w, max_h root.maxsize()root.geometry(f500x500{int((max_w - 500) / 2)}{int((max_h - 300) / 2)}) # 居中显示…

C语言易错知识点九(指针(part three))

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载,请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤ 许久不见,甚是想念,本大忙人已经很久没有更新博客了,我想大概我的粉丝们早…

使用ArcMap对工厂选址

文章目录 题目流程1,添加河流数据和高程数据2,对河流数据进行选取3,对高程数据进行选取并划定工厂选址范围3,根据工厂选址要求,获得整体的数据 结果 题目 实验名称:工厂选址 实验目的及要求: 根…

BATDK | 社招一年收割大厂算法offer

面试锦囊之面经分享系列,持续更新中 欢迎后台回复『面试』加入讨论组交流噢 没凑齐battmd是因为头条没面,美团面挂了。4/5的胜率;标题党了,T其实面的是搜狗,但是被腾讯收购,入职流程也走了腾讯的&#xf…

【低照度图像增强系列(1)】传统方法(直方图、图像变换)算法详解与代码实现

前言 ☀️ 在低照度场景下进行目标检测任务,常存在图像RGB特征信息少、提取特征困难、目标识别和定位精度低等问题,给检测带来一定的难度。 🌻使用图像增强模块对原始图像进行画质提升,恢复各类图像信息,再使用目标检…

Kafka日志

位置 server.properties配置文件中通过log.dir指定日志存储目录 log.dir/{topic}-{partition} 核心文件 .log 存储消息的日志文件,固定大小为1G,写满后会新增一个文件,文件名表示当前日志文件记录的第一条消息的偏移量。 .index 以偏移…

Vue+ElementUI+nodejs学生宿舍报修管理系统68ozj

本站是一个B/S模式系统,采用vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得学生宿舍信息管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中…

2023的AI工具集合,google和claude被禁用解决和edge的copilot

一、前言 AI工具集合 首先,OpenAI的ChatGPT以其深度学习模型和强大的语言处理能力引领了AI聊天机器人的潮流。自2022年11月30日上线以来,它创下了100万用户的注册记录,并被广泛应用于全球财富500强公司。为了实现盈利,OpenAI发布…

git入门指南:新手快速上手git(Linux环境如何使用git)

目录 前言 1. 什么是git? 2. git版本控制器 3. git在Linux中的使用 安装git 4. git三板斧 第一招:add 第二招:commit 第三招:push 5. 执行状态 6. 删除 总结 前言 Linux的基本开发工具介绍完毕,接下来介绍一…

Go 泛型发展史与基本介绍

Go 泛型发展史与基本介绍 Go 1.18版本增加了对泛型的支持,泛型也是自 Go 语言开源以来所做的最大改变。 文章目录 Go 泛型发展史与基本介绍一、为什么要加入泛型?二、什么是泛型三、泛型的来源四、为什么需要泛型五、Go 泛型设计的简史六、泛型语法6.1 …

采用SpringBoot框架+原生HTML、JS前后端分离模式开发和部署的电子病历编辑器源码(电子病历评级4级)

概述: 电子病历是指医务人员在医疗活动过程中,使用医疗机构信息系统生成的文字、符号、图表、图形、数据、影像等数字化信息,并能实现存储、管理、传输和重现的医疗记录,是病历的一种记录形式。 医院通过电子病历以电子化方式记录患者就诊的信息,包括&…

神经网络:机器学习基础

【一】什么是模型的偏差和方差? 误差(Error) 偏差(Bias) 方差(Variance) 噪声(Noise),一般地,我们把机器学习模型的预测输出与样本的真实label…

智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.材料生成算法4.实验参数设定5.算法结果6.…

Netty RPC 实现(二)

Netty RPC 实现 概念 RPC,即 Remote Procedure Call(远程过程调用),调用远程计算机上的服务,就像调用本地服务一样。RPC 可以很好的解耦系统,如 WebService 就是一种基于 Http 协议的 RPC。这个 RPC 整体…

生物系统学中的进化树构建和分析R工具包V.PhyloMaker2的介绍和详细使用

V.PhyloMaker2是一个R语言的工具包,专门用于构建和分析生物系统学中的进化树(也称为系统发育树或phylogenetic tree)。以下是对V.PhyloMaker2的一些基本介绍和使用说明: 论文介绍:V.PhyloMaker2: An updated and enla…