OpenHarmony南向之Audio

音频架构

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. ……

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Gradle - 安装、环境变量、配置国内源、常用命令

目录 一、Gradle 1.1、安装&环境变量 1.2、配置国内源 1.3、Gradle 项目文件介绍 1.4、Gradle 中的常用指令 一、Gradle 1.1、安装&环境变量 a)从 Gradle 官网下载对应的版本:Gradle | Releases 这里以 8.0 版本为例,下载附带…

01背包详解,状态设计,滚动数组优化,通用问题求解

文章目录 0/1背包前言一、0/1背包的状态设计1、状态设计2、状态转移方程3、初始状态4、代码实现5、滚动数组优化二维优化为两个一维二维优化为一个一维,倒序递推 二、0/1背包的通用问题求最大值求最小值求方案数 0/1背包 前言 0/1包问题,作为动态规划问…

什么是MVC?MVC框架的优势和特点

目录 一、什么是MVC 二、MVC模式的组成部分和工作原理 1、模型(Model) 2、视图(View) 3、控制器(Controller) 三、MVC模式的工作过程如下: 用户发送请求,请求由控制器处理。 …

少儿编程:从兴趣到升学的关键之路

随着科技的飞速发展,计算机编程已经逐渐渗透到我们生活的方方面面。对于新时代的少儿来说,掌握编程技能不仅可以开拓视野,提高思维能力,还可能成为他们未来升学和就业的重要砝码。6547网将探讨如何将少儿编程从兴趣培养成一种有力…

谷歌推大语言模型VideoPoet:文本图片皆可生成视频和音频

Google Research最近发布了一款名为VideoPoet的大型语言模型(LLM),旨在解决当前视频生成领域的挑战。该领域近年来涌现出许多视频生成模型,但在生成连贯的大运动时仍存在瓶颈。现有领先模型要么生成较小的运动,要么在生…

图像识别与人工智能到底是何关系?有何区别?

图像识别是人工智能领域的一个重要应用领域,它利用人工智能技术和算法来分析和理解图像内容。图像识别是使计算机能够模拟和理解人类视觉系统的能力,并从图像中提取出有用的信息和特征。 人工智能在图像识别中扮演着至关重要的角色,主要体现…

【Sass】网易云动画播放器

简介 仿网易云播放动画 效果图 sass src/assets/style/musicPlay.sass // TODO 音乐播放器动画 // ? 动画停止class >>> .muscic-play-stop // HTML结构 // <div class"music-play"> // <div class"bg-primary"></div>…

二级分销的魅力:无限裂变创造十八亿的流水

有这么一个团队&#xff0c;仅靠这一个二级分销&#xff0c;六个月就打造了十八亿的流水。听着是不是很恐怖&#xff1f;十八亿确实是一个很大的数字&#xff0c;那么这个团队是怎么做到的呢&#xff1f;我们接着往下看。 这是一个销售减脂产品的团队。不靠网店&#xff0c;不…

运行游戏显示缺少d3dx9_42.dll怎么办,三步即可完美解决

在我们使用电脑玩游戏&#xff0c;工作的时候&#xff0c;偶尔会遇到一些错误提示&#xff0c;其中之一就是缺少d3dx9_42.dll。这个错误通常出现在运行某些游戏或应用程序时&#xff0c;它表示计算机缺少了DirectX 9组件中的d3dx9_42.dll文件。为了解决这个问题&#xff0c;下面…

【接口测试】Postman(三)-变量与集合

一、变量 ​ 变量这个概念相信大家都不陌生&#xff0c;因此在这里我们不介绍了。主要说一下在Postman中有哪几类变量&#xff0c;主要包括以下四类&#xff1a; Global&#xff08;全局&#xff09; Environment&#xff08;环境&#xff09; Local&#xff08;本地&#xf…

python打开opencv图像与QImage图像及其转化

目录 1、Qimage图像 2、opencv图像 3、python打开QImage图像通过Qlabel控件显示 4、python打开QImage图像通过opencv显示 5、python打开opencv图像并显示 6、python打开opencv图像通过Qlabel控件显示 1、Qimage图像 QImage是Qt库中用于存储和处理图像的类。它可以存储多种…

微软官方镜像下载大全(windows iso 官方镜像)

原本只是想下一个Windows Server 2022中文版的镜像&#xff0c;后面发现要么就是慢得一批的某盘&#xff0c;要么就是磁力&#xff0c;我想直接下载简简单单&#xff0c;找了一圈没有找到。官网下载需要注册、登录乱七八糟&#xff0c;最终终于找到下载方法了&#xff0c;适用于…

大型语言模型,MirrorBERT — 将模型转换为通用词汇和句子编码器

大型语言模型&#xff0c;MirrorBERT — 将模型转换为通用词汇和句子编码器 一、介绍 BERT 模型在现代 NLP 应用中发挥着基础作用&#xff0c;这已不是什么秘密。尽管它们在下游任务上表现出色&#xff0c;但大多数模型在没有微调的情况下在特定问题上并不是那么完美。从原始预…

(一)深入理解Mysql底层数据结构和算法

什么是索引 索引是帮助MySQL高效获取数据的排好序的数据结构 数据结构有哪些 数据结构模拟网站&#xff1a;Data Structure Visualization 二叉树 不适合做自增ID的数据结构。如下示意图&#xff0c;假设采用二叉树作为表自增主键ID的数据存储结果如下&#xff1a;当查询i…

BUG记录——drawio出现“非绘图文件 (error on line 7355 at column 83: AttValue: ‘ expected)”

BUG现象 drawio出现“非绘图文件 (error on line 7355 at column 83: AttValue: ’ expected)”&#xff0c;如下图&#xff1a; 解决办法 这只是我自己摸索到的解决办法并不一定适用于所以人&#xff0c;对我是适用的。 首先用记事本打开损坏的drawio文件&#xff0c;如下 …

服务器经常死机怎么办?如何处理

关于服务器死机这一话题相信大家是不会陌生的&#xff0c;平时在使用服务器的过程中&#xff0c;或多或少都是会有遇到过。轻则耽误业务开展&#xff0c;重则造成数据丢失&#xff0c;相信每个人都不想碰到服务器死机的情况。下文我也简单的介绍下服务器死机的原因以及对应的预…

多个磁盘做软件raid并解决分区aligned对齐问题

centos 服务器验证创建软件raid10数据盘&#xff0c;该机器缺少raid硬件。只能做软件raid。 /dev/sdd至/dev/sdm共10块8T磁盘&#xff0c;做raid10&#xff1b; 步骤如下&#xff1a; &#xff08;第一步&#xff09;创建raid10 事先不需要对单个磁盘做分区 10个相同数据盘创…

第11章 GUI Page417~418 步骤五 支持方框 使用宏定义

运行效果&#xff1a; 原来的创建item的方式&#xff1a; 使用宏定义的方式&#xff1a;

Corel Painter各版本安装指南

下载链接https://pan.baidu.com/s/1g3xrCkWmOlDwAThOkqpYlg?pwd0531 #2023版本 1.鼠标右击【Corel Painter 2023】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 Corel Painter 2023】。 2.打开解压后的文件夹&#xff0c;双击打开【Setu…

Hadoop入门学习笔记——一、VMware准备Linux虚拟机

视频课程地址&#xff1a;https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接&#xff1a;https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 Hadoop入门学习笔记&#xff08;汇总&#xff09; 目录 一、VMware准备Linux虚拟机1.1. VMware安装Linux虚拟机1.…