Android音频架构

音频基础知识
声音有哪些重要属性呢?

响度(Loudness)
响度就是人类可以感知到的各种声音的大小,也就是音量。响度与声波的振幅有直接关系。

音调(Pitch)
音调与声音的频率有关系,当声音的频率越大时,人耳所感知到的音调就越高,否则就越低。

音色(Quality)
同一种乐器,使用不同的材质来制作,所表现出来的音色效果是不一样的,这是由物体本身的结构特性所决定的。

如何将各种媒体源数字化呢?

音频采样


将声波波形信号通过ADC转换成计算机支持的二进制的过程叫做音频采样(Audio Sampling)。采样(Sampling)的核心是把连续的模拟信号转换成离散的数字信号。

样本(Sample)
这是我们进行采样的初始资料,比如一段连续的声音波形。

采样器(Sampler)
采样器是将样本转换成终态信号的关键。它可以是一个子系统,也可以指一个操作过程,甚至是一个算法,取决于不同的信号处理场景。理想的采样器要求尽可能不产生信号失真。

量化(Quantization)
采样后的值还需要通过量化,也就是将连续值近似为某个范围内有限多个离散值的处理过程。因为原始数据是模拟的连续信号,而数字信号则是离散的,它的表达范围是有限的,所以量化是必不可少的一个步骤。

编码(Coding)
计算机的世界里,所有数值都是用二进制表示的,因而我们还需要把量化值进行二进制编码。这一步通常与量化同时进行。

奈奎斯特采样理论

“当对被采样的模拟信号进行还原时,其最高频率只有采样频率的一半”。

换句话说,如果我们要完整重构原始的模拟信号,则采样频率就必须是它的两倍以上。比如人的声音范围是2~ 20kHZ,那么选择的采样频率就应该在40kHZ左右,数值太小则声音将产生失真现象,而数值太大也无法明显提升人耳所能感知的音质。

录制过程
音频采集设备(比如Microphone)捕获声音信息。
模拟信号通过模数转换器(ADC)处理成计算机能接受的二进制数据。
根据需求进行必要的渲染处理,比如音效调整、过滤等等。
处理后的音频数据理论上已经可以存储到计算机设备中了,比如硬盘、USB设备等等。不过由于这时的音频数据体积相对庞大,不利于保存和传输,通常还会对其进行压缩处理。比如我们常见的mp3音乐,实际上就是对原始数据采用相应的压缩算法后得到的。压缩过程根据采样率、位深等因素的不同,最终得到的音频文件可能会有一定程度的失真,另外,音视频的编解码既可以由纯软件完成,也同样可以借助于专门的硬件芯片来完成。
回放过程
从存储设备中取出相关文件,并根据录制过程采用的编码方式进行相应的解码。
音频系统为这一播放实例选定最终匹配的音频回放设备。
解码后的数据经过音频系统设计的路径传输。
音频数据信号通过数模转换器(DAC)变换成模拟信号。
模拟信号经过回放设备,还原出原始声音。
Audio框架


APP
厂商根据特定需求自己写的一个音乐播放器软件等等。

Framework
Android也提供了另两个相似功能的类,即AudioTrack和AudioRecorder,MediaPlayerService内部的实现就是通过它们来完成的,只不过MediaPlayer/MediaRecorder提供了更强大的控制功能,相比前者也更易于使用。除此以外,Android系统还为我们控制音频系统提供了AudioManager、AudioService及AudioSystem类。这些都是framework为便利上层应用开发所设计的。

Libraries
framework只是向应用程序提供访问Android库的桥梁,具体功能实现放在库中完成。比如上面的AudioTrack、AudioRecorder、MediaPlayer和MediaRecorder等等在库中都能找到相对应的类。

1、frameworks/av/media/libmedia【libmedia.so】

2、frameworks/av/services/audioflinger【libaudioflinger.so】

3、frameworks/av/media/libmediaplayerservice【libmediaplayerservice.so】

    4.   HAL

从设计上来看,硬件抽象层是AudioFlinger直接访问的对象。这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层模块只需要与它进行交互就可以实现音频相关的功能了。因而我们可以认为AudioFlinger是Android音频系统中真正的“隔离板”,无论下面如何变化,上层的实现都可以保持兼容。

音频方面的硬件抽象层主要分为两部分,即AudioFlinger和AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式来让厂商可以方便地定制出自己的策略。抽象层的任务是将AudioFlinger/AudioPolicyService真正地与硬件设备关联起来,但又必须提供灵活的结构来应对变化——特别是对于Android这个更新相当频繁的系统。比如以前Android系统中的Audio系统依赖于ALSA-lib,但后期就变为了tinyalsa,这样的转变不应该对上层造成破坏。因而Audio HAL提供了统一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式,这就是audio_hw_device、audio_stream_in及audio_stream_out等等存在的目的,这些Struct数据类型内部大多只是函数指针的定义,是一些“壳”。当AudioFlinger/AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些实现驻留在以audio.primary.*,audio.a2dp.*为名的各种库中)来填充这些“壳”。根据产品的不同,音频设备存在很大差异,在Android的音频架构中,这些问题都是由HAL层的audio.primary等等库来解决的,而不需要大规模地修改上层实现。换句话说,厂商在定制时的重点就是如何提供这部分库的高效实现了。

AudioRcorder和AudioTrack是Audio系统对外提供API类,AudioRcorder主要用于完成音频数据的采集,而AudioTrack则是负责音频数据的输出。AudioFlinger管理着系统中的输入输出音频流,并承担着音频数据的混合,通过读写Audio硬件实现音频数据的输入输出功能;AudioPolicyService是Audio系统的策略控制中心,掌管系统中声音设备的选择和切换、音量控制等。

Audio 系统代码:

(1)Audio 的Java 部分

frameworks/base/media/java/android/media

与Audio 相关的Java包是android.media,主要包含AudioManager和Audio 系统的几个类。

(2)Audio 的JNI 部分

frameworks/base/core/jni

生成库libandroid_runtime.so,Audio 的JNI是其中的一个部分。

(3)Audio 的框架部分

frameworks/base/include/media/

frameworks/base/media/libmedia/

这部分内容被编译成库libmedia.so,实现Audio系统的核心框架,同时提供了IAudioFlinger 类接口。在这个类中,可以获得IAudioTrack 和IAudioRecorder 两个接口,分别用于声音的播放和录制。AudioTrack 和AudioRecorder 分别调用IAudioTrack 和IAudioRecorder 来实现。IAudioFlinger.h、IAudioTrack.h 和IAudioRecorder.h 这三个接口通过下层来实现。AudioSystem.h、AudioTrack.h 和AudioRecorder.h 是对上层提供的接口,它们既供本地程序调用,也可以通过JNI 向Java 层提供接口。从功能上看,AudioSystem 负责的是Audio 系统的综合管理功能,而AudioTrack 和AudioRecorder 分别负责音频数据的输出和输入,即播放和录制。另外一个接口是IAudioFlingerClient,它作为向IAudioFlinger中注册的监听器,相当于使用回调函数获取IAudioFlinger运行时信息。

(4)Audio Flinger

frameworks/base/libs/audioflinger

这部分内容被编译成库libaudioflinger.so,它是Audio系统的本地服务部分。

(5)Audio 的硬件抽象层接口

hardware/libhardware_legacy/include/hardware/

1、Audio使用JNI和Java对上层提供接口,JNI部分通过调用libmedia库提供的接口来实现。

2、 Audio 本地框架类是libmedia.so的一个部分,这些Audio框架类对上层提供接口,由下层的本地代码去实现。

3、AudioFlinger继承libmeida中的接口,提供实现库libaudiofilnger.so。这部分内容没有自己的对外头文件,上层调用的只是libmedia本部分的接口,但实际调用的内容是libaudioflinger.so。

4、Audio的硬件抽象层提供到硬件的接口,供AudioFlinger调用。Audio的硬件抽象层实际上是各个平台开发过程中需要主要关注和独立完成的部分。

在Android的Audio系统中,无论上层还是下层,都使用一个管理类和输出输入两个类来表示整个Audio系统,输出输入两个类负责数据通道。在各个层次之间具有对应关系:

在libhardware_legacy中定义的音频相关的硬件抽象层数据结构legacy_audio_device、legacy_stream_out、legacy_stream_in如下:

音频设备描述符:

struct legacy_audio_device {
    struct audio_hw_device device;
    struct AudioHardwareInterface *hwif;
};
音频输出描述符:

struct legacy_stream_out {
    struct audio_stream_out stream;
    AudioStreamOut *legacy_out;
};
音频输入描述符:

struct legacy_stream_in {
    struct audio_stream_in stream;
    AudioStreamIn *legacy_in;
};


通过上表比较可以看出,audio_hw_device和AudioHardwareInterface、audio_stream_out和AudioStreamOut、audio_stream_in和AudioStreamIn定义的接口基本一致,这是为了兼容Android先前版本。

AudioHardwareInterface.cpp负责实现基础类和管理,而AudioHardwareGeneric.cpp、AudioHardwareStub.cpp、AudioDumpInterface.cpp和A2dpAudioInterface.cpp各自代表一种Auido硬件抽象层的实现。

AudioHardwareGeneric.cpp:实现基于特定驱动的通用Audio硬件抽象层,这是一个真正能够使用的Audio硬件抽象层,但是它需要Android的一种特殊的声音驱动程序的支持。
AudioHardwareStub.cpp:实现Audio硬件抽象层的一个桩,这个实现不操作实际的硬件和文件,它所进行的是空操作。
 AudioDumpInterface.cpp:实现输出到文件的Audio硬件抽象层,支持Audio的输出功能,不支持输入功能。
A2dpAudioInterface.cpp:实现蓝牙音频的Audio硬件抽象层。

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/yangwen123/article/details/39502689

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

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

相关文章

opencv(c++)----图像的读取以及显示

opencv(c)----图像的读取以及显示 imread: 作用:读取图像文件并将其加载到 Mat 对象中。参数: 第一个参数是文件路径,可以是相对路径或绝对路径。第二个参数是读取标志,比如 IMREAD_COLOR 表示以彩色模式读取图像。 返回值&#x…

git config是做什么的?

git config是做什么的? git config作用配置级别三种配置级别的介绍及使用,配置文件说明 使用说明git confi查看参数 默认/不使用这个参数 情况下 Git 使用哪个配置等级? 一些常见的行为查看配置信息设置配置信息删除配置信息 一些常用的配置信…

【计算机网络】【传输层】【习题】

计算机网络-传输层-习题 文章目录 10. 图 5-29 给出了 TCP 连接建立的三次握手与连接释放的四次握手过程。根据 TCP 协议的工作原理,请填写图 5-29 中 ①~⑧ 位置的序号值。答案技巧 注:本文基于《计算机网络》(第5版)吴功宜、吴英…

【二叉搜素树】——LeetCode二叉树问题集锦:6个实用题目和解题思路

文章目录 计算布尔二叉树的值求根节点到叶节点的数字之和二叉树剪枝验证二叉搜索树二叉搜索树中第K小的元素二叉树的所有路径 计算布尔二叉树的值 解题思路: 这是一个二叉树的布尔评估问题。树的每个节点包含一个值,其中叶子节点值为 0 或 1&#xff0…

2023年MathorCup数学建模A题量子计算机在信用评分卡组合优化中的应用解题全过程文档加程序

2023年第十三届MathorCup高校数学建模挑战赛 A题 量子计算机在信用评分卡组合优化中的应用 原题再现: 在银行信用卡或相关的贷款等业务中,对客户授信之前,需要先通过各种审核规则对客户的信用等级进行评定,通过评定后的客户才能…

嵌入式开发套件(golang版本)

1. watchdog(软件看门狗:守护升级) 2. gate(主程序) 3. web(api版本 升级包) OTA 升级流程 watchdog启动后检查守护进程gate是否正在运行,如果没有,api对比版本号&am…

解压专家 2.4.12| 多功能解压缩工具,支持密码共享、音乐播放和歌词匹配。

解压专家是一款功能强大的解压缩软件,提供了类似于WIFI万能钥匙的密码分享功能,帮助用户快速获取共享的解压密码。作为专业的解压缩工具,它支持多种常见和不常见的压缩包格式,如ZIP、RAR、7z、TAR.GZ和ISO等,并且还支持…

并发编程(10)——内存模型和原子操作

文章目录 十、day101. 内存模型基础1.1 对象和内存区域1.2 改动序列 2. 原子操作及其类型2.1 原子操作2.2 原子类型2.3 内存次序2.4 std::atomic_flag2.4.1 自旋锁 2.5 std::atomic&#xff1c;bool&#xff1e;2.6 std::atomic<T*>2.7 标准整数原子类型2.8 std::atomic&…

【Flink】-- flink新版本发布:v2.0-preview1

目录 1、简介 2、非兼容变更 2.1、API 2.2、连接器适配计划 2.3、配置 2.4、其它 3、重要新特性 3.1、存算分离状态管理 3.2、物化表 3.3、批作业的自适应执行 3.4、流式湖仓 4、附加 4.1、非兼容性的 api 程序变更 4.1.2、Removed Classes # 4.1.3、Modified Cl…

ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能

一、简介 本播放器是在vs2019下开发&#xff0c;通过ffmpeg实现拉流解码功能&#xff0c;通过D3D实现视频的渲染功能。截图功能采用libjpeg实现&#xff0c;可以截取jpg图片&#xff0c;图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现&#xff0c…

webpack指南

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;webpack篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来webpack篇专栏内容:webpack-指南 概念 中文&#xff1a; webpack | webpack中文文档 | webpack中文网 英文&…

把越南语翻译成中文一般用什么翻译工具?《越南语翻译通》App或许能满足你的技术痛点需求!

在多语言交流日益频繁的今天&#xff0c;掌握越南语对于商务、旅游或学术交流都是一项重要技能。《越南语翻译通》App应运而生&#xff0c;旨在通过技术手段简化越南语学习和翻译过程&#xff0c;满足用户在不同场景下的需求。 核心技术 《越南语翻译通》App采用了先进的自然语…

Android Framework AMS(16)进程管理

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS 进程方面的知识。关注思维导图中左上侧部分即可。 我们本章节主要是对Android进程管理相关知识有一个基本的了解。先来了解下L…

Rust Struct 属性初始化

结构体是用户定义的数据类型&#xff0c;其中包含定义特定实例的字段。结构有助于实现更容易理解的抽象概念。本文介绍几种初始化结构体对象的方法&#xff0c;包括常规方法、Default特征、第三方包实现以及构建器模式。 Struct声明与初始化 struct Employee {id: i32,name: …

Vue全栈开发旅游网项目(10)-用户管理后端接口开发

1.异步用户登录\登出接口开发 1.设计公共响应数据类型 文件地址&#xff1a;utils/response404.py from django.http import JsonResponseclass BadRequestJsonResponse(JsonResponse):status_code 400def __init__(self, err_list, *args, **kwargs):data {"error_c…

数据结构:队列

目录 概念与结构底层结构的选择队列的实现队列头文件&#xff08;queue.h&#xff09;队列初始化队列的销毁入队列检查队列是否为空出队列查询队列第一个数据查询队列末尾数据查询队列有效数据个数代码试运行 概念与结构 概念&#xff1a;只允许在⼀端进行插⼊数据操作&#x…

Clickhouse集群新建用户、授权以及remote权限问题

新建用户 create user if not exists user on cluster 集群名称 IDENTIFIED WITH plaintext_password BY 密码;给用户授查询、建表、删表的权限 GRANT create table,select,drop table ON 数据库实例.* TO user on cluster 集群名称 ;再其他节点下用户建本地表成功&#…

JavaWeb--MySQL

1. MySQL概述 首先来了解一下什么是数据库。 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 像我们日常访问的电商网站京东&#xff0c;企业内部的管理系统OA、ERP、CRM这类的系统&#xff0c;以及大家每天都会刷的头条、抖音…

i春秋-SQLi(无逗号sql注入,-- -注释)

练习平台地址 竞赛中心 题目描述 后台有获取flag的线索应该是让我们检查源码找到后台 题目内容 空白一片 F12检查源码 发现login.php 访问login.php?id1 F12没有提示尝试sql注入 常规sql注入 //联合注入得到表格列数 1 order by 3 # 1 union select 1,2,3 #&#xff08…

基于Spring Boot的电子商务平台架构

2 相关技术 2.1 SpringBoot框架介绍 Spring Boot是一种不需要代码生成的一种框架&#xff0c;并且可以不需要配置任何的XML文件就可以&#xff0c;因为Spring Boot里面自带了很多接口&#xff0c;只需要配置不同的接口就会自动的应用并且识别需要的依赖&#xff0c;在配置方面非…