Android Audio音频系统之深入浅出

2024-06-07 23:48

本文主要是介绍Android Audio音频系统之深入浅出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、Audio音频架构简介

二、Android Audio系统框架

三、Audio架构以及各层的代码分布图

四、音频框架在Android系统中的进一步细化

五、创建声卡和注册声卡

六、Android Audio系统的结构

七、Audio音频原理介绍

八、Audio音频策略制定与策略执行的调用流程

九、Android AudioPolicyService服务启动过程

十、Android系统中所有的音频接口设备保存到AudioFlinger的成员变量mAudioHwDevs中

十一、audio_policy.conf同时定义了多个audio接口

十二、通过AudioFlinger的loadHwModule加载各audio接口对应的库文件实现调用PlaybackThread播放线程或RecordThread录音线程

十三、AudioFlinger的openInput()方法调用流程分析

十四、AudioFlinger的openOutput()方法的调用流程分析

十五、Audio系统为了能正常播放音频数据,需要创建抽象的音频输出接口对象,打开音频输出过程

十六、打开音频输入的流程

十七、打开音频输出后,在AudioFlinger与AudioPolicyService中的表现形式

十八、打开音频输入后,在AudioFlinger与AudioPolicyService中的表现形式

十九、AudioPolicyService加载完系统定义的所有音频接口,并生成相应的数据对象

二十、AudioPolicyService与AudioTrack和AudioFlinger的关系

二十一、AudioPolicyService注册名为服务的流程

二十二、AudioTrack构造过程

二十三、AudioTrack和AudioFlinger的关系

二十四、audio_policy与AudioPolicyService、AudioPolicyCompatClient之间的关系

 

图片

 

一、Audio音频架构简介

APP

整个音频体系的最上层

 

Framework

MediaPlayer和MediaRecorder、AudioTrack和AudioRecorder,Android系统为控制音频系统提供了AudioManager、AudioService及AudioSystem类,这些都是framework为便利上层应用开发所设计的

 

Libraries

系统服务AudioFlinger和AudioPolicyService(比如:ServiceManager、LocationManagerService、ActivityManagerService等等),音频体系中另一个重要的系统服务是MediaPlayerService

 

HAL

硬件抽象层是AudioFlinger直接访问的对象,这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层(包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相关的功能了。因而我们可以认为AudioFlinger是Android音频系统中真正的“隔离板”,无论下面如何变化,上层的实现都可以保持兼容。音频方面的硬件抽象层主要分为两部分,即AudioFlinger和AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式来让厂商可以方便地定制出自己的策略,抽象层的任务是将AudioFlinger/AudioPolicyService真正地与硬件设备关联起来

以前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音频系统的时候分为两条线索

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

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

 

二、Android Audio系统框架

图片

 

三、Audio架构以及各层的代码分布图

图片

 

四、音频框架在Android系统中的进一步细化

图片

 

五、创建声卡和注册声卡

图片

 

六、Android Audio系统的结构

图片

 

七、Audio音频原理介绍

AudioFlinger、AudioPolicyService和AudioTrack/AudioRecorder抛开MediaPlayer、MediaRecorder这些与应用开发直接关联的部分,整个音频系统的核心就是由这三者构建而成的。其中前两个都是System Service,驻留在mediaserver进程中,不断地处理AudioTrack/AudioRecorder的请求。音频的回放和录制从大的流程上看都是相似的,所以我们侧重于对AudioTrack的分析

把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来,编译生成的mediaserver将被烧录到设备的/system/bin/mediaserver路径,然后由系统启动时的init进程启动

 

Audio系统的结构

libmedia.so提供Audio接口,这些Audio接口既向上层开放,也向本地代码开放

libaudiofilnger.so提供Audio接口实现

Audio硬件抽象层提供到硬件的接口,供AudioFlinger调用

Audio使用JNI和JAVA对上层提供接口

 

media库中的Audio框架部分

Android 的Audio的核心框架在media库中提供,其中对上面主要实现AudioSystem、AudioTrack和AudioRecorder三个类。提供了IAudioFlinger类接口,在这个类中,可以获得IAudioTrack和IAudioRecorder两个接口,分别用于声音的播放和录制。AudioTrack和AudioRecorder分别通过调用IAudioTrack和IAudioRecorder来实现

 

Audio系统的头文件

路径为:frameworks/base/include/media/

AudioSystem.h

IAudioFlinger.h

AudioTrack.h

IAudioTrack.h

AudioRecorder.h

IAudioRecorder.h

Ixxx的接口通过AudioFlinger来实现,其他接口通过JNI向上层提供接口

 

Audio系统的头文件在frameworks/base/include/media/目录中,主要的头文件如下

AudioSystem.h:media库的Audio部分对上层的总管接口

IAudioFlinger.h:需要下层实现的总管接口

AudioTrack.h:放音部分对上接口

IAudioTrack.h:放音部分需要下层实现的接口

AudioRecorder.h:录音部分对上接口

IAudioRecorder.h:录音部分需要下层实现的接口

IAudioFlinger.h、IAudioTrack.h和IAudioRecorder.h这三个接口通过下层的继承来实现(即:AudioFlinger)

AudioFlinger.h,AudioTrack.h和AudioRecorder.h是对上层提供的接口,它们既供本地程序调用(例如:声音的播放器、录制器等),也可以通过JNI向Java层提供接口

AudioTrack和AudioRecorder都具有start,stop和pause等接口。前者具有write接口,用于声音的播放,后者具有read接口,用于声音的录制

AudioSystem用于Audio系统的控制工作,主要包含一些set和get接口,是一个对上层的类

 

AudioFlinger是Audio系统的核心,来自AudioTrack的数据,最终在这里得到处理并被写入Audio HAL层

MediaPlayer在framework层还是会创建AudioTrack,把解码后的PCM数流传递给AudioTrack,AudioTrack再传递给AudioFlinger进行混音,然后才传递给硬件播放,所以是MediaPlayer包含了AudioTrack。使用AudioTrack播放音乐

MediaPlayer提供了更完整的封装和状态控制,相比MediaPlayer,AudioTrack更为精练、高效,实际上MediaPlayerService的内部实现就是使用了AudioTrack把所有媒体相关的native层服务(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)启动起来,编译生成的mediaserver将被烧录到设备的/system/bin/mediaserver路径,然后由系统启动时的init进程启动

 

两种Audio Hardware HAL接口定义

legacy:hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h

非legacy:hardware/libhardware/include/hardware/audio.h

前者是2.3及之前的音频设备接口定义,后者是4.0的接口定义,为了兼容以前的设计,4.0实现一个中间层:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,结构与其他的audio_hw.c大同小异,差别在于open方法事实上legacy也要封装成非legacy中的audio.h,确切的说需要一个联系legacy interface和not legacy interface的中间层,这里的audio_hw_hal.cpp就充当这样的一个角色了

hardware/libhardware/modules/audio/

createAudioHardware()函数

external/tinyalsa/

mixer.c      类alsa-lib的control,作用音频部件开关、音量调节等

pcm.c        类alsa-lib的pcm,作用音频pcm数据回放录制

上面的hardware/libhardware_legacy/audio/、hardware/libhardware/modules/audio/、device/samsung/tuna/audio/是同层的。之一是legacy audio,用于兼容2.2时代的alsa_sound;之二是stub audio接口;之三是Samsung Tuna的音频抽象层实现。调用层次:AudioFlinger -> audio_hw -> tinyalsa

 

Audio硬件抽象层的实现在各个系统中可能是不同的,需要使用代码去继承相应的类并实现它们,作为Android系统本地框架层和驱动程序接口AudioFlinger继承了libmedia.so(Audio本地框架类)里面的接口,上层调用的只是libmedia.so部分的接口,但实际上调用的内容是libaudioflinger.so,使用JNI和Java对上层提供接口,JNI部分通过调用libmedia.so库提供的接口来实现

Audio硬件抽象层提供到硬件的接口,供AudioFlinger调用,Audio的硬件抽象层实际上是各个平台开发过程中需要主要关注和独立完成的部分,因为Android中的Audio系统不涉及编解码环节,只负责上层系统和底层Audio硬件的交互,所以通常以PCM作为输入/输出格式

IAudioFlinger类接口通过该类可以获得IAudioTrack和IAudioRecorder两个接口,分别用于声音的播放和录制,AudioTrack和AudioRecorder分别通过调用IAudioTrack和IAudioRecorder来实现

 

 硬件抽象层主要实现了AudioStreamInALSA和AudioStreamOutALSA两个类,这两个类又会调用该文件下的 ALSAStreamOps类的方法。AudioStreamInALSA是录音部分调用的路径。在AudioStreamInALSA的构造函数中会对alsa进行一些初始化参数设置,

AudioStreamInALSA的read方法是最主要的方法,audioflinger层的read调用就是对 AudioStreamInALSA的read的调用。由于

录音部分出现单声道和双声道数据传输的问题,修改read方法如下,即可实现了录音功能正常, 避免了在编码的时候修改数据时其他编码仍不能工作的弊端

 

八、Audio音频策略制定与策略执行的调用流程

图片

 

AudioPolicyService是策略的制定者,AudioFlinger则是策略的执行者

AudioTrack是AudioFlinger的客户端,AudioFlinger是Android系统中Audio管理的中枢

在Android中AudioPolicyService最终都会调用到AudioFlinger中去,因为AudioFlinger实际创建并管理了硬件设备

AudioFlinger类是代表整个AudioFlinger服务的类,其余所有的工作类都是通过内部类的方式在其中定义的

 

九、Android AudioPolicyService服务启动过程

AudioPolicyService完成的工作

加载audio_policy.default.so库得到audio_policy_module模块

通过audio_policy_module模块打开audio_policy_device设备

通过audio_policy_device设备创建audio_policy

 

hw_get_module函数加载硬件抽象层模块的过程

audio_policy实现在audio_policy_hal.cpp中,audio_policy_service_ops实现在AudioPolicyService.cpp中。create_audio_policy()函数就是创建并初始化一个legacy_audio_policy对象,AudioPolicyCompatClient是对audio_policy_service_ops的封装类,对外提供audio_policy_service_ops数据结构中定义的接口

 

Android AudioPolicyService服务启动过程

引用AudioPolicyCompatClient对象,这样音频管理器AudioPolicyManager就可以使用audio_policy_service_ops中的接口

优先加载/vendor/etc/audio_policy.conf配置文件,如果该配置文件不存在,则加载/system/etc/audio_policy.conf配置文件,如果该文件还是不存在,则通过函数defaultAudioPolicyConfig()来设置默认音频接口

设置各种音频流对应的音量调节点

通过名称打开对应的音频接口硬件抽象库

打开mAttachedOutputDevices对应的输出

将输出IOProfile封装为AudioOutputDescriptor对象

设置当前音频接口的默认输出设备

打开输出,在AudioFlinger中创建PlaybackThread线程,并返回该线程的id

设置可以使用的输出设备为mAttachedOutputDevices

将输出描述符对象AudioOutputDescriptor及创建的PlaybackThread线程id以键值对形式保存

设置默认输出设备

 

AudioPolicyManagerBase对象构造过程中主要完成以下几个步骤

loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE)加载audio_policy.conf配置文件

initializeVolumeCurves()初始化各种音频流对应的音量调节点

加载audio policy硬件抽象库:mpClientInterface->loadHwModule(mHwModules[i]->mName)

打开attached_output_devices输出mpClientInterface->openOutput();

保存输出设备描述符对象addOutput(output, outputDesc);


十、Android系统中所有的音频接口设备保存到AudioFlinger的成员变量mAudioHwDevs中

图片

 

audio_policy.conf文件

从audio_policy.conf文件中可以发现,系统包含了primary、a2dp、usb等音频接口,对应着系统中的audio.<primary/a2dp/usb>.<device>.so。每个音频接口中又包含了若干个outputs & inputs,并且每个output or input又包含了若干个devices,且还有采样频率,声道数等信息。这些devices信息、采样频率信息 & 声道信息等都会保存在各自module的IOProfile中。按上文中audio_policy.conf配置文件所描述,系统最后会生成6个modules(eg.primary,a2dp,hdmi,r_submix,hs_usb & usb)以及7个outputs


十一、audio_policy.conf同时定义了多个audio接口

图片

 

不同的Android产品在音频的设计上通常是存在差异的,而这些差异可以通过Audio的配置文件audio_policy.conf来获得。在Android系统中音频配置文件存放路径有两处,存放地址可以从AudioPolicyManagerBase.cpp文件中获取

在AudioPolicyManager.cpp文件中可以知道系统会首先加载vendor/etc目录下的configure文件,再加载system/etc目录下的configure文件。若这两者加载都发生错误的话,系统会加载default配置文件,并命名为primary module

通过loadGlobalConfig(root)函数来读取这些全局配置信息,通过loadHwModules()函数来加载系统配置的所有audio接口(加载音频接口),由于audio_policy.conf可以定义多个音频接口,因此该函数循环调用loadHwModule()来解析每个音频接口参数信息。Android定义HwModule类来描述每一个audio接口参数,定义IOProfile类来描述输入输出模式配置

/system/etc/audio_policy.conf

/vendor/etc/audio_policy.conf

 

加载audio_module模块

AudioPolicyManager通过读取audio_policy.conf配置文件,可以知道系统当前支持哪些音频接口以及attached的输入输出设备、默认输出设备。接下来就需要加载这些音频接口的硬件抽象库

AudioPolicyClientInterface提供了加载音频接口硬件抽象库的接口函数,AudioPolicyCompatClient通过代理audio_policy_service_ops实现AudioPolicyClientInterface接口

AudioPolicyCompatClient将音频模块加载工作交给audio_policy_service_ops,AudioPolicyService又将其转交给AudioFlinger 

 

当AudioPolicyManagerBase构造时,它会根据用户提供的audio_policy.conf来分析系统中有哪些audio接口(primary,a2dp以及usb),然后通过AudioFlinger::loadHwModule加载各audio接口对应的库文件,并依次打开其中的output(openOutput)和input(openInput)

打开音频输出时创建一个audio_stream_out通道,并创建AudioStreamOut对象以及新建PlaybackThread播放线程

打开音频输入时创建一个audio_stream_in通道,并创建AudioStreamIn对象以及创建RecordThread录音线程 

 

audio_policy.conf文件定义了两种音频配置信息 

当前系统支持的音频输入输出设备及默认输入输出设备,这些信息是通过global_configuration配置项来设置,在global_configuration中定义了三种音频设备信息

attached_output_devices:已连接的输出设备

default_output_device:默认输出设备

attached_input_devices:已连接的输入设备

系统支持的音频接口信息

audio_policy.conf定义了系统支持的所有音频接口参数信息,比如primary、a2dp、usb等

 

每种音频接口包含输入输出,每种输入输出又包含多种输入输出配置,每种输入输出配置又支持多种音频设备。AudioPolicyManagerBase首先加载/vendor/etc/audio_policy.conf,如果该文件不存在,则加载/system/etc/audio_policy.conf

audio_policy.conf同时定义了多个audio 接口,每一个audio接口包含若干output和input,而每个output和input又同时支持多种输入输出模式,每种输入输出模式又支持若干种设备

 

十二、通过AudioFlinger的loadHwModule加载各audio接口对应的库文件实现调用PlaybackThread播放线程或RecordThread录音线程

图片

 

十三、AudioFlinger的openInput()方法调用流程分析

图片

 

十四、AudioFlinger的openOutput()方法的调用流程分析

图片

 

十五、Audio系统为了能正常播放音频数据,需要创建抽象的音频输出接口对象,打开音频输出过程

图片

 

十六、打开音频输入的流程

图片

 

十七、打开音频输出后,在AudioFlinger与AudioPolicyService中的表现形式

图片

 

十八、打开音频输入后,在AudioFlinger与AudioPolicyService中的表现形式

图片

 

十九、AudioPolicyService加载完系统定义的所有音频接口,并生成相应的数据对象

图片

 

二十、AudioPolicyService与AudioTrack和AudioFlinger的关系

图片

 

二十一、AudioPolicyService注册名为服务的流程

图片

 

二十二、AudioTrack构造过程

图片

 

图片

 

图片

 

二十三、AudioTrack和AudioFlinger的关系

图片

 

二十四、audio_policy与AudioPolicyService、AudioPolicyCompatClient之间的关系

图片

 

关注微信公众号,获取更多最新文章

图片

这篇关于Android Audio音频系统之深入浅出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1040648

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

Apple quietly slips WebRTC audio, video into Safari's WebKit spec

转自:http://www.zdnet.com/article/apple-quietly-slips-webrtc-audio-video-into-safaris-webkit-spec/?from=timeline&isappinstalled=0 http://www.zdnet.com/article/apple-quietly-slips-webrtc-audio-video-