Android的音频系统在很长一段时间内都是外界诟病的焦点。的确,早期的Android系统在音频处理上相比于IOS有一定的差距,这也是很多专业的音乐播放软件开发商没有推出Android平台产品的一个重要原因。但这并不代表它的音频框架一无是处,相反,基于Linux系统的Android平台有很多值得我们学习的地方。

2.1 Linux下的音频框架

在计算机发展的早期,电脑的声音处理设备是由一个非常简易的loudspeaker外加发声器(Tone Generator)构成的,功能相对局限。后来人们想到了以plug-in的形式来扩展音频设备,“Sound blaster”就是其中很有名的一个。这种早期的声卡以插件方式连接到电脑主板上,并提供了更多复杂的音频设备。可想而知,独立的硬件设计也意味着成本的增加,于是随着技术的发展,便又出现了板载声卡,也就是我们俗称的“集成声卡”。板载声卡又分为“软声卡”和“硬声卡”。如果声卡本身没有主处理芯片,而只有解码芯片,需要通过CPU运算来执行处理工作,那么就是“软声卡”,反之就是“硬声卡”。通常面向低端市场的计算机都会包含一个集成的声卡设备以降低成本。一个典型的声卡通常包含三个部分:

1、Connectors

用于声卡与外放设备,如扬声器、耳机的连接,又被称为“jacks”

2、Audio Circuits

声卡的主要实现体,它负责信号的放大、混音、以及模拟数字转换等操作

3、Interface

连接声卡与计算机总线的单元,比如PCI总线

我们可以通过“cat/proc/asound/cards”命令来查看计算机中安装的声卡设备,如下例子所示:

目前市面上声卡的种类众多,既有复杂的高性能的,也有低端的简易的,那么对于一个操作系统来说,它如何管理这些音频设备,并向上层应用提供统一的接口呢?Android严格来讲只是一个Linux系统,它依赖于内核提供的各种驱动支持,包括音频驱动。因此我们有必要先花点时间来学习下Linux平台下的两种主要的音频驱动架构。

2.1.1 OSS (Open Sound System)

早期Linux版本采用的是OSS框架,它也是Unix及类Unix系统中广泛使用的一种音频体系。OSS既可以指OSS接口本身,也可以用来表示接口的实现。OSS的作者是Hannu Savolainen,就职于4Front Technologies公司。由于涉及到知识产权问题,OSS后期的支持与改善不是很好,这也是Linux内核最终放弃OSS的一个原因。另外,OSS在某些方面也遭到了人们的质疑,比如:对新音频特性的支持不足;缺乏对最新内核特性的支持等等。

当然,OSS做为Unix下统一音频处理操作的早期实现,本身算是比较成功的。它符合“一切都是文件”的设计理念,而且做为一种体系框架,其更多地只是规定了应用程序与操作系统音频驱动间的交互,因而各个系统可以根据实际的需求进行定制开发。总的来说,OSS使用了如下表所示的设备节点:

设备节点

说明

/dev/dsp

向此文件写数据à输出到外放Speaker

向此文件读数据à从Microphone进行录音

/dev/mixer

混音器,用于对音频设备进行相关设置,比如音量调节

/dev/midi00

第一个MIDI端口,还有midi01,midi02等等

/dev/sequencer

用于访问合成器(synthesizer),常用于游戏等效果的产生

2.1.2ALSA(Advanced Linux Sound Architecture)

ALSA是Linux社区为了取代OSS而提出的一种框架,是一个源代码完全开放的系统(遵循GNU GPL和GNU LGPL)。ALSA在Kernel 2.5版本中被正式引入后,OSS就逐步被排除在内核之外。当然,OSS本身还是在不断维护的,只是不再为Kernel所采用而已。ALSA相对于OSS提供了更多,也更为复杂的API接口,因而开发难度相对来讲加大了一些。为此,ALSA专门提供了一个供开发者使用的工具库,以帮助他们更好地使用ALSA的API。根据官方文档的介绍,ALSA有如下特性:

Ø  高效支持大多数类型的audio interface(不论是消费型或者是专业型的多声道声卡)

Ø  高度模块化的声音驱动

Ø  SMP及线程安全(thread-safe)设计

Ø  在用户空间提供了alsa-lib来简化应用程序的编写

Ø  与OSS API保持兼容,这样子可以保证老的OSS程序在系统中正确运行

ALSA主要由下表所示的几个部分组成:

Element

Description

alsa-driver

内核驱动包

alsa-lib

用户空间的函数库

alsa-utils

包含了很多实用的小程序,比如

alsactl:用于保存设备设置

amixer:是一个命令行程序,用于声量和其它声音控制

alsamixer:amixer的ncurses版

acconnect和aseqview:制作MIDI连接,以及检查已连接的端口列表

aplay和arecord:两个命令行程序,分别用于播放和录制多种格式的音频

alsa-tools

包含一系列工具程序

alsa-firmware

音频固件支持包

alsa-plugins

插件包,比如jack,pulse,maemo

alsa-oss

用于兼容OSS的模拟包

pyalsa

用于编译Python版本的alsa lib

Alsa主要的文件节点如下:

  1. Information Interface (/proc/asound)
  2. Control Interface (/dev/snd/controlCX)
  3. Mixer Interface (/dev/snd/mixerCXDX)
  4. PCM Interface (/dev/snd/pcmCXDX)
  5. Raw MIDI Interface (/dev/snd/midiCXDX)
  6. Sequencer Interface (/dev/snd/seq)
  7. Timer Interface (/dev/snd/timer)
2.1.3 Tinyalsa

一看“Tiny”这个词,大家应该能猜到这是一个ALSA的缩减版本。实际上在Android系统的其它地方也可以看到类似的做法——既想用开源项目,又嫌工程太大太繁琐,怎么办?那就只能瘦身了,于是很多Tiny-XXX就出现了。在早期版本中,Android系统的音频架构主要是基于ALSA的,其上层实现可以看做是ALSA的一种“应用”。后来可能是由于ALSA所存在的一些不足,Android后期版本开始不再依赖于ALSA提供的用户空间层的实现,因而我们在它的库文件夹中已经找不到alsa相关的lib了,而取代它的是tinyalsa相关的库文件。

同时我们可以看到externl目录下多了一个“tinyalsa”文件夹,其中包含了为数不多的几个源码文件,如下所示:

Source File

Description

Android.mk

makefile

mixer.c

Mixer Interface实现

pcm.c

PCM Interface实现

tinycap.c

Caputer工具

tinymix.c

Mixer工具

tinyplay.c

Play工具

include/tinyalsa/asoundlib.h

头文件

可见TinyAlsa与原版Alsa的差异还是相当大的,它只是部分支持了其中的两种Interface,而像Raw MIDI、Sequencer、Timer等Interface则没有涉及到,当然这对于一般的嵌入式设备还是足够了。TinyAlsa作为Alsa-lib的一个替代品,自面世已来得到的公众评价有褒有贬,不能一概而论——对于每个厂商来说,合适自己的就是最好的。而且各厂商也可以在此基础上扩展自己的功能,真正的把ALSA利用到极致。

2.2 Android系统上音频架构

一个好的系统架构,需要尽可能地降低上层与具体硬件的耦合,这既是操作系统的设计目的,对于音频系统也是如此。音频系统的雏形框架可以简单的用下图来表示:

在这个图中,除去Linux本身的Audio驱动外,整个Android音频实现都被看成了User。因而我们可以认为Audio Driver就是上层与硬件间的“隔离板”。但是如果单纯采用上图所示的框架来设计音频系统,对上层应用使用音频功能是不小的负担,显然Android开发团队还会根据自身的实际情况来进一步细化“User”部分。细化的根据自然还是Android的几个层次结构,包括应用层、framework层、库层以及HAL层,如下图所示:

我们可以结合目前已有的知识,想一下每一个层次都会包含哪些模块(先不考虑蓝牙音频部分)?

1、APP

这是整个音频体系的最上层,因而并不是Android系统实现的重点。比如厂商根据特定需求自己写的一个音乐播放器,游戏中使用到声音,或者调节音频的一类软件等等。

2、Framework

相信大家可以马上想到MediaPlayer和MediaRecorder,因为这是我们在开发音频相关产品时使用最广泛的两个类。实际上,Android也提供了另两个相似功能的类,即AudioTrack和AudioRecorder,MediaPlayerService内部的实现就是通过它们来完成的,只不过MediaPlayer/MediaRecorder提供了更强大的控制功能,相比前者也更易于使用。我们后面还会有详细介绍。除此以外,Android系统还为我们控制音频系统提供了AudioManager、AudioService及AudioSystem类。这些都是framework为便利上层应用开发所设计的。

3、Libraries

我们知道,framework层的很多类,实际上只是应用程序使用Android库文件的“中介”而已。因为上层应用采用java语言编写,它们需要最直接的java接口的支持,这就是framework层存在的意义之一。而作为“中介”,它们并不会真正去实现具体的功能,或者只实现其中的一部分功能,而把主要重心放在库中来完成。比如上面的AudioTrack、AudioRecorder、MediaPlayer和MediaRecorder等等在库中都能找到相对应的类。这一部分代码集中放置在工程的frameworks/av/media/libmedia中,多数是C++语言编写的。

除了上面的类库实现外,音频系统还需要一个“核心中控”,或者用Android中通用的实现来讲,需要一个系统服务(比如ServiceManager、LocationManagerService、ActivityManagerService等等),这就是AudioFlinger和AudioPolicyService。它们的代码放置在frameworks/av/services/audioflinger,生成的最主要的库叫做libaudioflinger。

音频体系中另一个重要的系统服务是MediaPlayerService,它的位置在frameworks/av/media/libmediaplayerservice。

因为涉及到的库和相关类是非常多的,建议大家在理解的时候分为两条线索。

其一,以库为线索。比如AudioPolicyService和AudioFlinger都是在libaudioflinger库中;而AudioTrack、AudioRecorder等一系列实现则在libmedia库中。

其二,以进程为线索。库并不代表一个进程,进程则依赖于库来运行。虽然有的类是在同一个库中实现的,但并不代表它们会在同一个进程中被调用。比如AudioFlinger和AudioPolicyService都驻留于名为mediaserver的系统进程中;而AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder一样实际上只是应用进程的一部分,它们通过binder服务来与其它系统进程通信。

在分析源码的过程中,一定要紧抓这两条线索,才不至于觉得混乱。

4、HAL

从设计上来看,硬件抽象层是AudioFlinger直接访问的对象。这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层(包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相关的功能了。因而我们可以认为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等等库来解决的,而不需要大规模地修改上层实现。换句话说,厂商在定制时的重点就是如何提供这部分库的高效实现了。基于上面的分析,我们给出一个完整的Android音频系统框架来给大家参考(没有列出Linux层的实现,比如ALSADriver等等),如下所示:

每个公司根据自己产品的特点,各自定义符合自己产品的音频架构图。

接下来的小节,我们将分别介绍上述框架图中的几个重点模块,包括AudioFlinger,AudioTrack/AudioRecorder,AudioManager/AudioPo

Android音频系统之二音频框架相关推荐

  1. android多音频输出,基于Android车载系统的多路音频输出的方法、装置及系统与流程...

    本发明涉及Android车载系统领域,特别涉及一种基于Android车载系统的多路音频输出的方法.装置及系统. 背景技术: 车载系统主要由主机.显示屏.操作键盘(遥控器)和天线组成.它实现了野外踏勘. ...

  2. [Android] 输入系统(二)

    在上一篇文章的最后,我们发现InputDispatcher是调用了InputChannel->sendMessage把键值发送出去,那么相应的,也有接收键值的地方.接收函数是InputChann ...

  3. Android 音频系统:从 AudioTrack 到 AudioFlinger(全)

    Android 音频框架概述 Audio 是整个 Android 平台非常重要的一个组成部分,负责音频数据的采集和输出.音频流的控制.音频设备的管理.音量调节等,主要包括如下部分: Audio App ...

  4. 逐步攻略:使用Matlab音频系统工具箱创建自己的VST插件,让音乐编程在Nashville崭新绽放

    第一部分:引言与Matlab音频系统工具箱概览 尊敬的读者,欢迎阅读这篇文章.我作为一个热爱音乐和编程的人,十分激动地在这里和大家分享我最近的一次学习经验.正如标题所述,我们将探索一种崭新的方式来创建 ...

  5. Android输入系统(三)InputReader的加工类型和InputDispatcher的分发过程

    关联系列 解析WMS系列 深入理解JNI系列 输入系统系列 前言 在上一篇文章中,我们学习了输入事件的处理,输入事件会交由InputDispatcher进行分发,那么InputDispatcher是如 ...

  6. Android input 系统InputReader,InputDispatcher线程实例--UI死掉

    Android input 系统InputReader,InputDispatcher线程实例–UI死掉但touch 正常报点 依据 Android input 系统初始化和启动流程中的背景: 做An ...

  7. 理解 Audio 音频系统二 之 audioserver AudioPolicyService

    理解 Audio 音频系统二 之 AudioPolicyService 二.audioserver & AudioPolicyService + AudioPolicy 启动流程总结 1. A ...

  8. Android 9 Audio系统笔记:音频路由实现——从AudioTrack到audiohal

    目录 一.动态路由的初始化 1.获取路由策略 2.向AudioPolicyManager注册路由策略 二.动态路由的路由流程,以AudioTrack创建为例 创建AudioTrack的路由选择 如何定 ...

  9. android 4.0 电话录音,ANDROID音频系统散记之四:4.0音频系统HAL初探

    昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...

  10. Android音频系统之AudioPolicyService

    地址:http://blog.csdn.net/edmond999/article/details/18599327 1.1 AudioPolicy Service 在AudioFlinger小节,我 ...

最新文章

  1. Sql语句在线转java bean https://www.bejson.com/othertools/sql2pojo/
  2. 天梯赛 L1-039 古风排版 (20 分)
  3. table类型数据提交_OGG数据同步异常问题总结
  4. Bugly符号化iOS 崩溃,快速定位crash(上传符号表)
  5. c语言程序设计慕课版答案第6章,C语言程序设计答案黄保和编第6章函数.doc
  6. 嵌入式仿真平台SkyEye的覆盖率分析
  7. 在用c语言写代码是这么找出错误,写代码(C语言)常见粗心小错误
  8. python怎样实现多表连接_Python Day45多表连接查询
  9. java URI 编码解码
  10. 嵌入式基础面八股文——并发,同步,异步,互斥,阻塞,非阻塞的理解(2)
  11. Linux大实验 (图书管理系统)
  12. STM32 Systick定时器在实现1us延时时的问题与解决
  13. iPhone查询商品历史价格详细教程
  14. arduino IED2.0实现Serial.println打印结果
  15. 2022年暑假ACM热身练习3
  16. 将图片内嵌到 exe 文件中
  17. 基于PHP的图书商城系统
  18. java有参构造_java的有参构造有什么用
  19. Win7x64系统过TP的一些尝试和目前遇到的问题
  20. matlab矩阵行位列维,Matlab—基本操作与矩阵输入

热门文章

  1. SpringCachemanager使用Cache(redis作为缓存中间件)
  2. 计算机英语第二版期末翻译试题答案,开放英语I期末翻译测试题
  3. (一)阿里云创建自己的产品和设备
  4. goroutine并发扫描MySQL表_【扫描全能王】【干货】Goroutine Channel
  5. ICC II 2 placement
  6. 参考文献的序号怎么对齐_word序号对齐方式 word中如何让编号自动对齐
  7. 论文写作中插入公式间距变大怎么办?
  8. STM32F103C8T6基于HAL库移植uC/OS-III
  9. 平面向量内积坐标公式推导_平面向量内积的坐标运算与距离公式
  10. 【译学】数据分析手册学习09:举例说明 - 定量定性数据分析的程序和方法 Procedures and Methods