前言

  一直想总结下Audio子系统的博客,但是各种原因(主要还是自己懒>_<),一直拖到现在才开始重新整理,期间看过H8(Android-4.4),T3(Android-4.4),A64(Android-5.1)上的AudioRecoder录音流程,总的来说,几个平台上的audio系统都差不多,这里还是主要以A64来分析。

=================================================== 我是分割线 ===============================================================================

对于Audio系统大概会分为AudioRecoder/AudioTrack方法,MediaRecoder/MediaPlayer方法,前者直接操作原始数据,后者与系统编解码结合对操作音频格式的文件,本文以AudioRecorder为切入点,来分析整个Audio系统的录音与播放,最终掌握Audio系统的架构,Audio数据的流向,以及怎么更改Audio的录音/播放通路等。

首先,先介绍下Android下Audio系统的一些备用资料,方便后面看代码的时候更好的理解

1.Audio数据是怎么存储的

  每个声卡都有一个硬件缓存区来保存记录下来的样本。当缓存区足够满时,声卡将产生一个中断。内核声卡驱动然后使用直接内存(DMA)访问通道将样本传送到内存中的应用程序缓存区。类似地,对于回放,任何应用程序使用DMA将自己的缓存区数据传送到声卡的硬件缓存区中。这样硬件缓存区是环缓存。也就是说当数据到达缓存区末尾时将重新回到缓存区的起始位置。ALSA维护一个指针来指向硬件缓存以及应用程序缓存区中数据操作的当前位置。从内核外部看,我们只对应用程序的缓存区感兴趣,所以本文只讨论应用程序缓存区。

1、Audio系统架构

Audio系统架构图

Audio系统在Android中负责音频方面的数据流传输和控制功能,也负责音频设备的管理,Audio系统主要分成如下几个层次:

1.Application本地接口(frameworks/base/media/java/android/media)

  AudioTrack/MediaPlayer是Audio输出环节的类;

  AudioRecord/MediaRecorder是Audio输入环节的类;

  其中AudioRecord可以提取pcm原始数据,AudioRecord也只能播放pcm原始数据;

  而MediaRecorder则可以对音频数据进行编码存储为mp3等格式的文件,MediaPlayer则可以解码音频文件类型的文件。

  他们都通过frameworks/base/media/jni下的JNI文件调用libmedia的方法。

2.libmedia库实现(frameworks/av/media/libmedia)

  AudioTrack/MediaPlayer和AudioRecorder/MeidaRecorder分别负责音频数据的输出和输入,即播放和录制;

  AudioSystem负责的是Audio系统的综合管理功能;

  在libmedia库中提供的只是一个Audio系统框架,AudioSystem、 AudioTrack 和AudioRecord分别调用下层的IAudioFlinger、IAudioTrack和IAudioRecord来实现。

3.AudioService的实现 (frameworks/av/services/audioflinger)

  AudioFlinger是Audio系统的中间层,在系统中起到服务作用,它主要实现了libmedia提供的Audio部分接口;AudioFlinger其中的createTrack()创建音频的输出设备IAudioTrack,openRecord()创建音频的输入设备IAudioRecord。

  AudioMixer中实现的是一个Audio系统混音器,它被AudioFlinger调用,一般用于在声音输出之前的处理,提供多通道处理、声音缩放、重取样(AudioResampler)。

  AudioPolicyService是Audio系统的策略控制中心,具有掌管系统中声音设备的选择和切换、音量控制等功能。

  Threads与Tracks则继承AudioFlinger中的方法,同时在读写音频数据也是在这里面完成的。

4.Audio硬件抽象层

  Audio硬件抽象层的接口路径为:hardware/libhardware_legacy/include/hardware/

  函数实现:hardware/libhardware_legacy/audio/

  其中主要的文件为:AudioHardwareBase.h和AudioHardwareInterface.h。

    在AudioHardwareInterface.h中定义了类:AudioStreamOut、AudioStreamIn和AudioHardwareInterface。AudioStreamOut和AudioStreamIn分别对应了音频的输出环节和输入环节,这个AudioHardwareInterface接口中,使用openOutputStream()和openInputStream()函数分别获取AudioStreamOut和AudioStreamIn两个类,它们作为音频输入/输出设备来使用。

    AudioHardwareGeneric.cpp则继承了AudioStreamOut与AudioStreamIn;

    AudioHardwareInterface.cpp则继承了AudioHardwareInterface。

    AudioHardware*最终会调用audio_hw.c中的函数来实现与驱动进行数据交换,audio_hw.c文件位置:hardware/aw/audio/tulip/audio_hw.c

2、ALSA驱动架构

ALSA架构图

  Audio Codec驱动采用ALSA(Advanced Linux Sound Architecture)架构,驱动包括放音(play),录音(capture),以及对Codec进行各种控制和选择(mixer)功能。

  ASoC--ALSA System on Chip <ALSA与芯片相关的部分>,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系,ASOC将音频系统分为3部分:Machine,Platform和Codec。

  Codec驱动包含了一些音频的控件(Controls),音频接口,DAMP(动态音频电源管理)的定义和某些Codec IO功能,为了保证硬件无关性,任何特定于平台和机器的代码都要移到Platform和Machine驱动中;

  Platform驱动包含了该SoC平台的音频DMA和音频接口的配置和控制(I2S,PCM,AC97等等),它也不能包含任何与板子或机器相关的代码;

  Machine驱动整合Codec驱动和Platform驱动,单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。

3、Audio实现流程分析

3.1.参数介绍

  AudioSource:采样通道,一般为MediaRecorder.AudioSource.MIC;

  SampleRate:采样率,一般在8000Hz~48000Hz之间,不同的硬件设备这个值不同;

  Channel:采样声道数,一般为单通道或立体声,即 AudioFormat.CHANNEL_CONFIGURATION_MONO或 AudioFormat.CHANNEL_CONFIGURATION_STEREO;

  AudioFormat:采样精度,一般为8位或16位,即AudioFormat.ENCODING_16BIT或8BIT;

  bufferSize:缓冲区大小:可以通过getMinBufferSize来获取;

    在Audio系统中,buffer的组成如图所示

    buffer:DMA缓冲区大小

    period: 周期,是每两个硬件中断之间的帧数,即传输多少个采样帧数据,DMA反馈一个中断,一般一个周期包含1024个采样帧,在HAL层中定义。

    frame: 每个采样帧的大小。为一个采样点的字节数*声道数,因为对于多通道的话,用1个采样点的字节数表示不全,因为播放的时候肯定是多个声道的数据都要播放出来才行,所以为了方便,就说1秒钟有多少个frame,这样就能抛开声道数,把意思表达全了。

    sample: 采样声道,一般为2个字节。

3.2.Audio实现流程分析

在APP中开启录音流程如下,包含了音频参数设定、数据采集、释放资源全过程。这里仅详细分析AudioRecorder的实现

3.2.1.AudioRecorder

3.2.2.MediaRecoder

  • new MediaRecorder();
  • MediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  • MediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
  • MediaRecorder.setAudioSamplingRate(44100);
  • MediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
  • MediaRecorder.setAudioEncodingBitRate(96000);
  • MediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
  • MediaRecorder.prepare();
  • MediaRecorder.start();
  • MediaRecorder.stop();
  • MediaRecorder.release();

3.2.3AudioTrack

  • AudioTrack.getMinBufferSize(micRate,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT);
  • new AudioTrack(AudioManager.STREAM_MUSIC, micRate,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT, m_out_buf_size,AudioTrack.MODE_STREAM);
  • AudioTrack.play();
  • AudioTrack.write(bytes_pkg, 0, bytes_pkg.length);
  • AudioTrack.stop();
  • AudioTrack.release();

4.总结

  1.AudioRecord的链路流程

    驱动层注册设备并挂载设备节点,HAL层提供底层读取函数的实现,然后AudioFlinger调用HAL接口把读取到的数据放入FIFO中,然后AudioRecord再从FIFO中把数据读取出来。

  2.AudioTrack的链路流程

    驱动层注册设备并挂载设备节点,HAL层提供底层读取函数的实现 ,然后AudioTrack把数据写入到FIFO中,然后AudioFlinger从FIFO中取出数据,经过AudioMixer混音处理之后调用HAL接口把数据写入到驱动中。

  3.MediaRecord的链路流程

    首先设置文件编码参数,通过AudioFlinger调用HAL接口把读取到的数据放入FIFO中,然后调用AudioRecord再从FIFO中把数据读取出来,然后把数据传给相应的编码器进行编码处理,最后写入到文件中。

陆陆续续花了两个月的碎片时间终于把这个专题写完了,今天一口气都发出来,接下来准备准备,搞一下display驱动方面的东西,感觉又是一条超级超级大工程啊!!由于作者内功有限,若文章中存在错误或不足的地方,还请给位大佬指出,不胜感激!

基于Allwinner的Audio子系统分析(Android-5.1)的更多相关文章

  1. (一)Audio子系统之AudioRecord.getMinBufferSize

    在文章<基于Allwinner的Audio子系统分析(Android-5.1)>中已经介绍了Audio的系统架构以及应用层调用的流程,接下来,继续分析AudioRecorder方法中的ge ...

  2. (二)Audio子系统之new AudioRecord()

    在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...

  3. (二)Audio子系统之new AudioRecord()(Android4.4)

    在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...

  4. Linux input子系统分析

    输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...

  5. (三)Audio子系统之AudioRecord.startRecording

    在上一篇文章<(二)Audio子系统之new AudioRecord()>中已经介绍了Audio系统如何创建AudioRecord对象以及输入流,并创建了RecordThread线程,接下 ...

  6. (四)Audio子系统之AudioRecord.read

      在上一篇文章<(三)Audio子系统之AudioRecord.startRecording>中已经介绍了AudioRecord如何开始录制音频,接下来,继续分析AudioRecord方 ...

  7. (五)Audio子系统之AudioRecord.stop

    在上一篇文章<(四)Audio子系统之AudioRecord.read>中已经介绍了AudioRecord如何获取音频数据,接下来,继续分析AudioRecord方法中的stop的实现 函 ...

  8. (六)Audio子系统之AudioRecord.release

      在上一篇文章<(五)Audio子系统之AudioRecord.stop>中已经介绍了AudioRecord如何暂停录制,接下来,继续分析AudioRecord方法中的release的实 ...

  9. 从CM刷机过程和原理分析Android系统结构

    前面101篇文章都是分析Android系统源代码,似乎不够接地气. 假设能让Android系统源代码在真实设备上跑跑看效果,那该多好.这不就是传说中的刷ROM吗?刷ROM这个话题是老罗曾经一直避免谈的 ...

随机推荐

  1. centos7安装kubernetes 1.1

    原文地址:http://foxhound.blog.51cto.com/1167932/1717105 前提:centos7 已经update yum update -y 一.创建yum源 maste ...

  2. UVa 1606 Amphiphilic Carbon Molecules (扫描法+极角排序)

    题意:平面上有 n 个点,每个点不是黑的就是白的,现在要放一个隔板,把它们分成两部分,使得一侧的白点数加上另一侧的黑点数最多. 析:这个题很容易想到的就是暴力,不妨假设隔板至少经过两个点,即使不经过也 ...

  3. Linux的系统引导

    启动引导: 1.主机加电自检,加载BIOS信息 2.读取MBR的引导文件[grub lilo] 3.引导linux内核 4.运行第一个进程init pid=1 5.进入相应的运行级别[0-6] 6.运 ...

  4. SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例

    1.前言 本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管理系统实例. 使用技术:SpringBoot.mybatis.shiro.thymeleaf.pagehelp ...

  5. EBS SOA 修改Web Service参数

    l 需求描述 当把PL/SQL声明Load到ISG,生成WSDL并部署完毕后,需要修改PL/SQL的包头声明部分.例如修改某个过程的参数类型,再重新Load,重新生成WSDL,重新部署.我们会发现PL ...

  6. 微信公众开发URL和token填写详解

    微信公众开发URL和token填写详解 方法/步骤     作为一名微信公众号开发者,别人进入你的微信公众号,肯定会看见某些网页,或者给你发某些信息,你需要实时自动回复,所以你需要一个24小时为用户服 ...

  7. 【C++】C++中的操作符重载

    C++中的操作符重载使得对于类对象的操作更加方便和直观,但是对于各种操作符重载的规则以及语法形式,一直以来都是用到哪一个上stackoverflow上查找,在查找了四五次之后,觉得每次麻烦小总结一下. ...

  8. java写入换行符

    写入一个文件,生成文本文档,里面写入1000行字符,但是写出来的没有换行.所以纠结,百度了下,一行完事. String crlf=System.getProperty("line.separ ...

  9. Orchard 介绍

    0.Introduction 下载地址 https://orchard.codeplex.com/ Orchard 是由微软公司创建,基于 ASP.NET MVC 技术的免费开源内容管理系统: 可用于 ...

  10. Oracle数据泵导出导入(expdp/impdp)

    一.创建表空间 create tablespace atp logging datafile 'D:\oracle\oradata\orcl\atp.dbf' size 50m autoextend ...