分享

Android 音频系统

 yikongzi 2014-04-14
http://blog.csdn.net/droidphone/article/details/7165482
http://www./~tiwai/writing-an-alsa-driver/index.html
http://blog.csdn.net/qianjin0703/article/details/6387662
http://blog.csdn.net/menguio/article/details/6323965

本文基于Freescale IMX平台Codec ALC5625为例。

0. 专用术语

 ASLA - Advanced Sound Linux Architecture

 OSS - 以前的Linux音频体系结构,被ASLA取代并兼容

 Codec - Coder/Decoder

 I2S/PCM/AC97 - Codec与CPU间音频的通信协议/接口/总线

 DAI - Digital Audio Interface 其实就是I2S/PCM/AC97

 DAC - Digit to Analog Conversion

 ADC - Analog to Digit Conversion

 DSP - Digital Signal Processor

 Mixer - 混音器,将来自不同通道的几种音频模拟信号混合成一种模拟信号

 Mute - 消音,屏蔽信号通道

 PCM - Pulse Code Modulation 一种从音频模拟信号转换成数字信号的技术,区别于PCM音频通信协议

 采样频率 - ADC的频率,每秒采样的次数,典型值如44.1KHZ

 量化精度 - 比如24bit,就是将音频模拟信号按照2的24次方进行等分

 SSI - Serial Sound Interface

 DAPM - Dynamic Audio Power Management

 

1. 物理结构

 音频编解码器Codec负责处理音频信息,包括ADC,DAC,Mixer,DSP,输入输出以及音量控制等所有与音频相关的功能。

 Codec与处理器之间通过I2C总线和数字音频接口DAI进行通信。

 I2C总线 - 实现对Codec寄存器数据的读写。

 DAI - 实现音频数据在CPU和Codec间的通信。

以Codec作为研究对象,它的输入有Mic(Microphone),PhoneIn电话信号等,输出有耳机HP(HeadPhone),扬声器Speaker和PhoneOut电话信号。另外需要注意在Codec与CPU端间也有音频数字信号的输入输出。

1) 播放音乐

 

2) 录音

 

3) 电话

--- 打电话 ---                                                           --- 接听---

   

4) 通过蓝牙打电话

--- 打电话 ---                                                           --- 接听---   

 

  

 

 2. 系统架构

  Android的音频系统拥有一个比较标准和健全的架构,从上层应用,java framework服务AudioMananger,本地服务AudioFlinger,抽象层AlsaHAL,本地库,再调用external的 Alsa-lib外部支持库,最后到底层驱动的codec,可谓"五脏俱全"。

 以系统启动AuidoFlinger为例,简要窥探Alsa Sound的组织架构。

Java服务AudioManager作为服务端,本地服务AudioFlinger作为客户端,两者通过Binder机制交互。 AudioFlinger对硬件功能的具体实现(比如setMode设置电话/蓝牙/录音等模式)交给硬件抽象层AlsaHAL完成。抽象层可以调用本地 标准接口,比如mASLADevice->route,或者直接调用Alsa-lib库去操作底层驱动。

 

 Linux的音频驱动结构相对复杂,源码位于内核目录下的/sound/soc/,其中/codec文件夹下存放与平台无关的编解码器驱动,/imx文件夹下存放于freescale imx平台相关的音频驱动,主要可分为SSI驱动和DAI驱动。

以声卡驱动的数据结构为切入点分析,

1) struct snd_soc_codec - 由与平台无关的codec驱动实现。

2) struct snd_soc_platform - 由与imx平台相关的DAI驱动实现,主要实现了音频数据的DMA传输功能。

3) struct snd_soc_dai_link - 将平台相关的DAI与平台无关的codec联系起来。

-------------------------------------------

1.1 音频框架

转载请注明,From LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492

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

1.1.1 Linux下的音频框架

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

一个典型的声卡通常包含三个部分:

·          Connectors

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

·          Audio Circuits

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

·          Interface

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

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

目前市面上声卡的种类众多,既有复杂的高性能的,也有低端的简易的,那么对于一个操作系统来说,它如何管理这些音频设备,并向上层应用提供统一的接口呢?

Android严格来讲只是一个Linux系统,它依赖于内核提供的各种驱动支持,包括音频驱动。因此我们有必要先花点时间来学习下Linux平台下的两种主要的音频驱动架构:

 

·        OSS (Open Sound System)

早期Linux版本采用的是OSS框架,它也是Unix及类Unix系统中广泛使用的一种音频体系。OSS既可以指OSS接口本身,也可以用来表示 接口的实现。OSS的作者是Hannu Savolainen,就职于4Front Technologies公司。由于涉及到知识产权问题,OSS后期的支持与改善不是很好,这也是Linux内核最终放弃OSS的一个原因。

另外,OSS在某些方面也遭到了人们的质疑,比如:

对新音频特性的支持不足;

缺乏对最新内核特性的支持等等。

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

表格 13?1 OSS采用的设备节点

设备节点

说明

/dev/dsp

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

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

/dev/mixer

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

/dev/midi00

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

/dev/sequencer

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

更多详情,可以参考OSS的官方说明:http://www./

 

·        ALSA(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主要由下表所示的几个部分组成:

表格 13?2 Alsa-project Package

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)

 

关于ALSA的更多知识,建议大家可以自行参阅相关文档,这对于后面理解整个Audio系统是不无裨益的。

1.1.2 TinyAlsa

一看“Tiny”这个词,大家应该能猜到这是一个ALSA的缩减版本。实际上在Android系统的其它地方也可以看到类似的做法——既想用开源项目,又嫌工程太大太繁琐,怎么办?那就只能瘦身了,于是很多Tiny-XXX就出现了。

在早期版本中,Android系统的音频架构主要是基于ALSA的,其上层实现可以看做是ALSA的一种“应用”。后来可能是由于ALSA所存在的 一些不足,Android后期版本开始不再依赖于ALSA提供的用户空间层的实现,因而我们在它的库文件夹中已经找不到alsa相关的lib了,如下图所 示:

 

 

    

图 13?7 Android4.1与早期版本在音频库上的区别

 

而取代它的是tinyalsa相关的库文件,如下图所示:


 

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

 

 

 

表格 13?3 Tiny-alsa工程文件

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利用到极致。

1.1.3 Android系统上的音频框架

 

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

 


图 13?8 音频系统的雏形框架

 

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

细化的根据自然还是Android的几个层次结构,包括应用层、framework层、库层以及HAL层,如下图所示:

 


图 13?9 音频框架在Android系统中的进一步细化

 

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

·        APP

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

 

·        Framework

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

除此以外,Android系统还为我们控制音频系统提供了AudioManager、AudioService及AudioSystem类。这些都是framework为便利上层应用开发所设计的。

 

·        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服务来与其它系统进程通信。

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

 

·        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等等),如下所示:


 图 13?10 Android音频系统框架全图

 

接下来的小节,我们将分别介绍上述框架图中的几个重点模块,包括 AudioFlinger,AudioTrack/AudioRecorder,AudioManager/AudioPolicyService,并简 单地介绍上层的一些模块如MediaPlayerService等等。

-------------------------------
1、    Gallery应用端表现
    Gallery仅仅提供一个呈现框架,Gallery用来管理所有的视频和图片文件,具有播放、查看、删除等功能。自动搜索本地sdcard存有的 picture和video,并分类将同性质文件picture和video集中在一起,播放时呈现。Gallery内部实现的播放主用是同 MediaPlayer,主要包含了Audio和video的播放功能。
   
    Gallery中增加从指定目录选择播放文件的功能:
方法:首先遍历sdcard下的目录,然后通过选择某个目录,再遍历文件,点击文件播放。
说明:
    定义了两个List表:
    videoPathList:遍历/sdcard下目录,并存于此List。
    videlFileList:遍历相应目录下的文件,并存于此List。
    定义了两个Activity:
    VideoList2Play:实现/sdcard下目录和文件遍历。
    VideoPlayer:利用VideoView类实现视频播放。
    从Gallery的按钮和菜单项着手,将该功能植入Gallery。
    Gallery首次加载的图框上“拍照按钮”,能够找到内部功能实现的类和方法,并可以将该功能加入。
    利用more菜单,增加“选择其它视频”功能,涉及内部类复杂,需进一步研究,暂没有实现。
    利用视频播放是的MovieView中增加“选择其它视频”按钮,当有视频真正在播放时,点击按钮选择其它视频,会有冲突。
需改进:研究通过弹出选择对话框方式,可以自由选择/sdcard下的目录和文件,并实现播放。

    Gallery中数据缓存及处理流程
    在应用程序中有三个线程存在:主线程(随activity的声明周期启动销毁)、feed初始化线程(进入程序时只运行一次,用于加载相册初始信息)、feed监听线程(监听相册和相片的变更)。主要流程归纳如下:
    1、首次进入程序Gallery调用onCreate,此时发送初始化消息进入消息队列;然后Gallery调用onResume,向下进入 GridLayer的onResume。MediaFeed对象需要进行初始化,然后才可调用MediaFeed 的onResume;
    2、处理消息队列中的HANDLE_INTENT消息,Gallery处理这个消息会初始化数据源,从而调用GridLayer的 setDataSource方法,这个方法会触发底层MediaFeed的启动方法start,执行完后启动feed监听线程继续执行MediaFeed 的run方法。
    start方法会作两件事:调用自己底层的重新开始方法onResume,onResume中会为图像和视频这两个媒体源分别增加“内容变化监听器”,并 请求刷新这两个媒体源(加入全局的刷新请求列表);启动feed初始化线程mAlbumSourceThread。
    3、其中MediaFeed初始化线程的工作是:调用MediaFeed的loadMediaSets加载相册,它又调用了下层 LocalDataSource中的refresh方法(查询数据库是否有相册变化,新增或修改feed中相应的MediaSet相册的名字)和 loadMediaSets方法(调用下层CacheService.loadMediaSets方法)加载所有相册和相册中的所有相片信息。
    4、MediaFeed监听线程MediaFeed.run()的工作是:根据“内容变化监听器”返回的媒体变动消息(增删改),持续不断的更新 MediaFeed中的相册和相片变量。具体机制如下:如果全局的刷新请求列表中有内容,则调用LocalDataSource.refresh进行相册 信息的更新(其中 LocalDataSource.refresh调用了CacheService的computeDirtySets),然后run遍历每个相册并调用 dataSource.loadItemsForSet()方法为相册加载相片记录。

2、    功能模块说明
1》    层次结构
    分为三层:上层Java应用程、中层Framework层、下层是底层libaries层。整个MediaPlayer在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。

2》    说明
  2.1》Gallery.java中通过Handler实现实现进程间通信,涉及sendInitialMessage()方法;检查存储的媒体文件,涉 及checkStorage()方法;并初始化Data Source,涉及initializeDatasource()方法;判定数据类型后,通过onActivityResult()执行相应的活动。涉及 到图层,GridLayer主图层,同GridDrawManager管理媒体的呈现。
 
 2.2》MediaPlayer的JAVA本地调用部分
    MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的 android_media_MediaPlayer.cpp中的文件中实现。android.media.MediaPlayer中有2部分,一部分供 java上层如VideoView调用,一部分为native方法,调用jni。
    通过MediaPlayerService实现client端和MediaPlayer进行交互和数据通信,其中涉及通过MediaProvider(多 媒体内容提供者)调用数据源,MediaScannerService(多媒体扫描服务)和MediaScannerReceiver检查数据类型(这两 个类之间通过Server和BroadcasterRevceiver,主要的方法scan()、scanFlle()),并将统一类型的文件归类用 MediaStore(多媒体存储)进行数据存储;MediaPlayer.java调用 jni_android_media_MediaPlayer.jni进行同MediaPalyer.cpp实现通信。       
    说明:
·    MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频、视频和图像。
·        MediaScannerReceiver在任何的ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED或 ACTION_MEDIA_SCANNER_SCAN_FILE 意图(intent)发出的时候启动。因为解析媒体文件的元数据或许会需要很长时间,所以MediaScannerReceiver会启动 MediaScannerService。
·        MediaScannerService调用一个公用类MediaScanner进行媒体扫描工作。MediaScannerReceiver维持两种扫 描目录:一种是内部卷(internal volume)指向$(ANDROID_ROOT)/media. 另一种是外部卷(external volume)指向$(EXTERNAL_STORAGE).

3》MediaPlayer
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调 用MediaPlayer实现的,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。Android的媒 体播放功能分成两部分,一部分是媒体播放应用,一部分是媒体播放服务。这两部分分别跑在不同的进程中。媒体播放应用包括Java程序和部分C++代码,媒 体播放服务是C++代码。媒体播放应用和媒体播放服务之间需要通过binder机制来进行相互调用,这些调用包括:
   (1)媒体播放应用向媒体播放服务发控制指令;
   (2)媒体播放服务向媒体播放应用发事件通知(notify)。
·    媒体播放服务对外提供多个接口,其中有2个重要的接口:IMediaPlayerService和 IMediaPlayer;IMediaPlayerServer用于创建和管理播放实例,而IMediaPlayer接口则是播放接口,用于实现指定媒 体文件的播放以及播放过程的控制。
·        媒体播放应用向媒体播放服务提供的1个接口:IMediaPlayerClient,用于接收notify()。这些接口需要跨进程调用,涉及到 binder机制(就是让这两部分之间建立联系)。每个接口包括两部分实现,一部分是接口功能的真正实现(BnInterface),这部分运行在接口提 供进程中;另一部分是接口的proxy(BpInterface),这部分运行在调用接口的进程中。

3、    代码框架
 
1》JAVA程序的路径:
packages/apps/Camera/
编译后生成Camera.apk,对应于Camera、Gallery、Camcorder三个应用。

packages/apps/Gallery/src/com/android/camera/gallery、
packages/apps/Gallery3D/src/com/cooliris/app

packages/providers/MediaProvider/
含有类MediaProvider.java、MediaScannerService.java、MediaScannerReceiver.java,
编译后生成MediaProvider.apk。会在开机时扫描本机和sdcard上的媒体文件(图片、视频、音频),并在/data/data /com.android.providers.media/databases 目录下生成internal.db(/system/meida)和external-?.db(/sdcard)两个数据库文件。此后所有的多媒体信息 都从这两个数据库中获取。

2》JAVA Framework的路径:
frameworks/base/core/java/android/provider/MediaStore.java
提供的多媒体数据库,所有多媒体数据信息都可以从这里提取。数据库的操作通过利用ContentResolver调用相关的接口实现。

frameworks/base/media/java/android/media/
提供了android上 多媒体应用层的操作接口。主要说明:
·    MediaPlayer.java:提供了视频、音频、数据流的播放控制等操作的接口。
·    MediaScanner*.java:提供了媒体扫描接口的支持,媒体扫描后加入数据库中,涉及MediaScannerConnection.java和MediaScannerConnectionClient.java。

3》JAVA本地调用部分(JNI):
frameworks/base/media/jni
JAVA本地调用部分。编译后生成的目标是libmedia_jni.so。
·    android_media_MediaPlayer.cpp:JAVA本地调用部分,它定义了一个JNINativeMethod(JAVA本地调用方 法)类型的数据gMethods用来描述接口的关联信息;定义了JNIMediaPlayerListener:MediaPlayerListener 的notify()方法(该方法是调用c++层次的mediaplayer中,实现播放管制)。
·    android_media_MediaScanner.cpp: 媒体扫描相关的本地调用实现。处理路径、文件和Ablum相册内容释放。
·    soundpool/android_media_SoundPool.cpp:定义了音频系统的本地调用实现、MediaPlayer回调方法android_media_callback()。

4》多媒体底层库:
frameworks/base/include/media/、frameworks/base/media/libmedia/
    这里为多媒体的的底层库,编译生成libmedia.so。这个库处于android多媒体架构的核心位置,它对上层提供的接口主要有MediaPlayer、MediaScanner等类。
    android.meida.* 就是通过libmedia_jni.so调用libmedia.so实现的接口实现的。    A》MediaPlayerInterface.h头文件定义了MediaPlayer的底层接口,定义了以下类:
·    MediaPlayerBase:MediaPlayerInterface的抽象基础类,里面包含了音频输出、视频输出、播放控制等的基本接口。
·        MediaPlayerInterface、MediaPlayerHWInterface 继承自MediaPlayerBase针对不同输出作出的扩展。
·        MediaPlayerInterface得到具有相同的播放接口,可以通过继承MediaPlayerInterface的方法,实现增加新的播放器实现。
    B》IMediaPlayer.h定义了BnMediaPlayer本地播放类;IMediaPlayer.cpp定义了BpMediaPlayer代理 类(其中通过remote()->transact()方法发送消息)和实现了BnMediaPlayer:onTransact()的具体方法。
    C》IMediaPlayerClient.h定义了BnMediaPlayerClient本地客户端 类;IMediaPlayerClient.cpp定义了BpMediaPlayerClient代理类(其中通过notify()中的 remote()->transact()方法发送消息)和实现了BnMediaPlayerClient:onTransact()方法。
    D》IMediaPlayerService.h定义了BnMediaPlayerService本地服务端 类;IMediaPlayerService.cpp定义了BpMediaPlayerService代理类(其中通过 remote()->transact()方法发送消息)和实现了BnMediaPlayerService:onTransact()方法。
    E》mediaplayer.h定义了MediaPlayerListener类的notify()方法和类 MediaPlayer:BnMediaPlayerClient;mediaplayer.cpp主要实现了MediaPlayer的数据设置播放和实 现了MediaPlayerListener类的notify()具体方法。

5》多媒体服务部分:
frameworks/base/media/libmediaplayerservice/
文件为mediaplayerservice.h和mediaplayerservice.cpp
    这是多媒体的服务部分(提供Media Player执行的Proxy,同Client端建立连接、设置数据源、根据不同类型创建播放),编译生成libmediaplayerservice.so。    
·    MediaPlayerService.cpp 通过instantiate()方法实现了一个名字为media.player的服务,MediaPlayer通过IPC同其实现通讯;
·        根据playerType的类型来决定创建不同的播放器;
·        实现了notify()通知Client端、callbackThread()回调机制、decode解码。

frameworks/base/media/mediaserver/
文件为main_mediaserver.cpp是Mediaplayer Server启动的主程序,涉及AudioFlinger()、AudioPolicyService()、MediaPlayerService()的加载。

6》MediaPlayer生命周期:
 

4、    Audio概念
Audio系统在Android中负责音频方面输入/输出和管理层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置。主要 涉及到AudioManager、AudioTrack、AudioServiece、AudioRecord。主要分成如下几个层次:
(1)media库提供的Audio系统本地部分接口;
(2)AudioFlinger作为Audio系统的中间层;
(3)Audio的硬件抽象层提供底层支持;
(4)Audio接口通过JNI和Java框架提供给上层。
    Audio管理环节    Audio输出    Audio输入
Java层    android.media.
AudioSystem    android.media
AudioTrack    android.media.
AudioRecorder
本地框架层    AudioSystem    AudioTrack    AudioRecorder
AudioFlinger    IAudioFlinger    IAudioTrack    IAudioRecorder
硬件抽象层    AudioHardwareInterface    AudioStreamOut    AudioStreamIn
AudioTrack.java:SoundPool.java 播放android application的生音资源。
AudioRecord.java: 为android applicatio 提供录音设置(sample、chanel等)的接口;
AudioManager.java: 提供了音频音量,以及播放模式(静音、震动等)的控制。
说明:
1》Audio驱动程序(Linux系统,因不同平台而已)
2》Audio硬件抽象层:hardware/libhardware_legacy/include/hardware/
    AudioHardwareInterface.h(定义Audio硬件抽象层的接口),其中三个主要类AuidoStreamOut/AudioStreamIn/AuidoHardwareInterface实现Audio的输出/输入/管理。
    2.1》AudioStreamOut关键接口write(const void* buffer, size_t bytes)/AudioStreamIn关键接口read(void* buffer, size_t bytes),通过定义内存的指针和长度音频数据的输出和输入。
    2.2》AudioHardwareInterface使用openOutputStream()和openInputStream()函数来获取AudioStreamOut和AudioStreamIn。
    2.3》AudioHardwareInterface中所涉及的参数是在AudioSystem.h中定义,通过setParameters和getParameters接口设置和获取参数,通过setMode()设置系统模式。
    2.4》Audio中引进了策略管理AudioPolicyInterface,目的是将Audio核心部分和辅助性功能分离。
3》AudioFlinger的实现方式
    3.1》通用方式AndroidHardwareGeneric实现基于特定驱动的通用Audio硬件抽象层。
    3.2》桩实现方式AndroidHardwareStub,实现Audio硬件抽象层的一个桩,是个空操作,保证没有Audio设备时系统正常工作。
    3.3》AudioDumpInterface实现以文件为输入输出的Audio硬件抽象层,以文件模拟Audio硬件流的输入输出环节。

Audio代码分布:
(1)    Java部分:frameworks/base/media/java/android/media
与audio相关的java package是android.media,主要包含audio manager和audio系统的几个类,这部分主要给上层的AP部分提供audio相关的接口。
(2)    JNI部分: frameworks/base/core/jni
Android系统会生成一个libandroid_runtime.so,audio的JNI是其中的一个部分。
(3)    audio frameworks
头文件路径:frameworks/base/include/media/
代码路径:frameworks/base/media/libmedia/
Audio本地框架是media库的一部分,本部分的内容被编译成库libmedia.so,提供audio部分的接口(其中包括基于binder的IPC机制)。
(4)    Audio Flinger:frameworks/base/libs/audioflinger
这部分内容被编译成库libaudioflinger.so,它是audio系统的本地服务部分。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多