Android_P_Audio_系统(1) — Auido 系统简介

1 音频基础

1.1 声音的三要素
1. 音量(Volume

也叫做响度(Loudness),人耳对声音强弱的主观感觉就是响度,响度和声波振动的幅度有关。一般说来,声波振动幅度越大则响度也越大。当我们用较大的力量敲鼓时,鼓膜振动的幅度大,发出的声音响;轻轻敲鼓时,鼓膜振动的幅度小,发出的声音弱。

2. 音调(Pitch)

人耳对声音高低的感觉称为音调(也叫音频),音调主要与声波的频率有关。声波的频率高,则音调也高。当我们分别敲击一个小鼓和一个大鼓时,会感觉它们所发出的声音不同。小鼓被敲击后振动频率快,发出的声音比较清脆,即音调较高;而大鼓被敲击后振动频率较慢,发出的声音比较低沉,即音调较低。

一般音调:儿童 > 女生 > 男生

人耳听觉音频范围是 20Hz-20000Hz (若音频压缩时不在这个范围内的数据就可以砍掉)。

3. 音色(Quality)

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

音色与声波的振动波形有关,或者说与声音的频谱结构有关。

1.2 音频的量化与编码

日常生活中我们听到的声波波形信号都是时间连续的,我们称这种信号为模拟信号,模拟信号需要量化成数字信号(离散、不连续的)以后才能被我们的计算机识别。音频的量化过程可以简单分为以下 5 个步骤:

1) 模拟信号

现实生活中的声音表现为连续的、平滑的波形,其横坐标为时间轴,纵坐标表示声音的强弱。

2) 采样

按照一定的时间间隔在连续的波上进行采样取值,如下图所示取了 10 个样。

3) 量化

将采样得到的值进行量化处理,也就是给纵坐标定一个刻度,记录下每个采样的纵坐标的值。

4) 编码

将每个量化后的样本值转换成二进制编码,可以看到模拟信号经过采样、量化、编码后形成的二进制序列就是数字音频信号。

5) 数字信号

将所有样本二进制编码连起来存储在计算机上就形成了数字信号。

1.3 量化基本概念
1. 采样位数

每个采样点能够表示的数据范围,用多少个 bit 表示。采样位数通常有 8 bits 或 16 bits 两种,采样位数越大,所能记录声音的变化度就越细腻,相应的数据量就越大。8 位字长量化(低品质)和 16 位字长量化(高品质),16 bit 是最常见的采样精度。

采样位数也被叫做采样精度、量化级、量化数据位数等。

2. 采样率

单位时间内对模拟信号的采样次数,也就是采样频率,采样频率越高,声音的还原就越真实越自然,当然数据量就越大。

我们日常生活中常见的采样率:

  • 5kHz:仅能满足人们讲话的声音质量
  • 8KHz:电话所用采样率, 对于人的说话已经足够
  • 22.05KHz:达到 FM 广播的声音品质(适用于语音和中等品质的音乐)
  • 44.1KHz:最常见的采样率标准,理论上的 CD 音质界限,可以达到很好的听觉效果
  • 48KHz:比 CD 音质更加精确一些

对于高于 48KHz 的采样频率人耳已无法辨别出来了,所以在电脑上没有多少使用价值。

3. 声道数

为了播放声音时能够还原真实的声场,在录制声音时在前后左右几个不同的方位同时获取声音,每个方位的声音就是一个声道。声道数是声音录制时的音源数量或回放时相应的扬声器数量,有单声道、双声道、多声道。

4. 码率

也叫比特率,指每秒传送的数据量,单位为 bps(Bit Per Second),码率代表了压缩质量,码率越高,每秒传送的数据就越多,音质就越好。

复制代码
公式:
    码率 = 采样率 * 采样位数 * 声道数

例如:
    CD 音质,采样率 44.1KHz,采样位数 16 bit,立体声(双声道)
    码率 = 44.1 * 1000 * 16 * 2 = 1411200 bps = 176400 Bps

根据上面的码率,录制一分钟需要 176400 Bps * 60秒 / 1024 / 1024 = 10.09MB

5. PCM

PCM(Pulse Code Modulation),即脉冲编码调制,对声音进行采样、量化过程,未经过任何编码和压缩处理。

PCM 数据是最原始的音频数据完全无损,所以 PCM 数据虽然音质优秀但体积庞大,为了解决这个问题先后诞生了一系列的音频格式,这些音频格式运用不同的方法对音频数据进行压缩,通常分为无损压缩(ALAC、APE、FLAC)和有损压缩(MP3、AAC、OGG、WMA)两种。

5. 音频帧

音频数据是流式的,本身没有明确的一帧帧的概念,在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取 2.5ms~60ms 为单位的数据量为一帧音频。这个时间被称之为 "采样时间",其长度没有特别的标准,它是根据编解码器和具体应用的需求来决定的。

例如最常见的音频格式 MP3 的数据通常由两部分组成,一部分为 "ID3" 用来存储歌名、演唱者、专辑、音轨数

等信息,另一部分为音频数据。音频数据部分以帧(frame)为单位存储,每个音频都有自己的帧头,如下图所示就是一个 MP3 文件帧结构图。

MP3 中的每一帧都有自己的帧头,其中存储了采样率等解码必须的信息,所以每一个帧都可以独立于文件存在和播放,这个特性加上高压缩比使得 MP3 文件成为了音频流播放的主流格式。帧头之后存储着音频数据,这些音频数据是若干个 PCM 数据帧经过压缩算法压缩得到的。

1.4 音频编解码器

常见的音频编解码器包括 OPUS、AAC、Vorbis、Speex、iLBC、AMR、G.711 等。目前泛娱乐化直播系统采用 rtmp 协议,支持 AAC 和 Speex。

性能上来看,OPUS > AAC > Vorbis,其它的逐渐被淘汰。

2 Android Audio 系统框架


2.1 Application

常见的音频相关软件有:音乐播放器、视频播放器、电话、录音软件等等

2.2 Framework
1) framework Java 部分

这部分接口直接提供给 Application 层定制开发 Audio 相关功能,相关代码主要在:

PATH:frameworks/base/media/java/android/media

可供使用的 API 有

  • AudioTrack & AudioRecorder:提供声音播放和录制接口
  • MediaPlayer & MediaRecorder:提供声音播放和录制接口,接口更加通用
  • AudioManager、AudioService & AudioSystem:提供声音控制、通道选择、音效设置等功能

AudioRcorder 和 MediaRecorder 主要用于完成音视频数据的采集,而 AudioTrack 和 MediaPlayer 则负责音频数据的输出。

MediaPlayer 能够播放多种格式的声音文件,比如 MP3、AAC、WAV 等,MediaPlayer 的实现包含了 AudioTrack,而 AudioTrack 因为不创建解码器,仅能播放无须解码的 PCM 流(wav 格式)。

2) framework Native 部分
  1. 客户端:
    包含 Java API 接口 AudioTrack、AudioRecord、MediaPlayer、MediaRecord、AudioSystem 对应的 native 实现。在 Android 9.0 代码中,为了显式的区分客户端和服务端, 这部分实现从 libmedia 中分离出来,编译成一个单独的库 libaudioclient.so,代码路径:

PATH: frameworks/av/media/libaudioclient

  1. 服务端:
    包含 Audio 系统中最核心的 AudioFlinger & AudioPolicyService 实现代码,其中 AudioFlinger 是 Audio 系统的工作引擎,管理着系统中的输入输出音频流,并承担音频数据的混音以及读写 Audio 硬件等工作。而 AudioPolicyService 是 Audio 系统的策略控制中心,掌管系统中声音设备的选择和切换、音量控制等功能。两个功能分别被编译成 libaudioflinger 和 libaudiopolicyservice 库,运行在 AudioServer 系统进程中,通过 binder 跨进程向客户端提供服务。代码路径:

PATH: frameworks/av/services/audioflinger(audiopolicy)

2.3 Audio HAL

从整体设计上看,硬件抽象层是 AudioFlinger 直接访问的对象,厂商会在这一层添加自己的实现,桥接硬件驱动和上层框架。

Android Audio 上层设计框架中与硬件抽象层直接交互的只有 AudioFlinger 和 AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式让厂商可以方便地定制自己的策略。抽象层的任务就是提供统一的接口来定义它与 AudioFlinger/AudioPolicyService 之间的通信方式,不论 Audio 系统依赖 ALSA-lib 还是 tinyalsa,都不应该对上层框架造成破坏。下面来介绍 Android Audio Hal 的统一接口设计。

在 Android Audio 系统设计中,无论是上层还是下层都是用一个管理类和输入输出两个类来表示 Audio 系统,输入输出两个类负责数据通道,在各个层级间对应关系:

-- Audio 管理类 Audio 输入 Audio 输出
Java android.media.AudioSystem android.media.AudioRecord android.media.AudioTrack
native AudioSystem AudioRecord AudioTrack
AudioFlinger IAudioFlinger IAudioRecord IAudioTrack
硬件抽象层 AudioHardwareInterface AudioStreamOut AudioStreamIn

在 Android libhardware_legacy 中定义的音频相关的参考硬件抽象层数据结构:

音频设备描述符:

复制代码
struct legacy_audio_device {
    struct audio_hw_device device;
    struct AudioHardwareInterface *hwif;
};

音频输入描述符

复制代码
struct legacy_stream_in {
    struct audio_stream_in stream;
    AudioStreamIn *legacy_in;
};

音频输出描述符:

复制代码
struct legacy_stream_out {
    struct audio_stream_out stream;
    AudioStreamOut *legacy_out;
};

audio_hw_device 和 AudioHardwareInterface、audio_stream_out 和 AudioStreamOut、audio_stream_in 和 AudioStreamIn 定义的接口基本一致,这是为了兼容 Android 先后版本,下面的分析以 AudioHardwareInterface、AudioStreamIn、AudioStreamOut 作为硬件抽象层音频管理和输入输出结构体定义。

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

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

一般情况下用的 ALSA 音频架构

相关推荐
JhonKI3 小时前
【MySQL】存储引擎 - CSV详解
android·数据库·mysql
开开心心_Every3 小时前
手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复
android·windows·python·搜索引擎·智能手机·pdf·音视频
大G哥4 小时前
Kotlin Lambda语法错误修复
android·java·开发语言·kotlin
鸿蒙布道师7 小时前
鸿蒙NEXT开发动画案例2
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
androidwork7 小时前
Kotlin Android工程Mock数据方法总结
android·开发语言·kotlin
xiangxiongfly9159 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢11 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢12 小时前
Android开发报错解决
android
每次的天空13 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空15 小时前
Android学习总结之Binder篇
android·学习·binder