枕上从妨一夜睡,灯前读尽十年诗。这篇文章主要讲述Android audio介绍相关的知识,希望能为你提供帮助。
开始这篇文章之前,需要先了解<
Linux音频编程>
1. 架构 在android中,audio以分层的方式实现,从上到下依次为
- 应用框架: 提供android.media API
音频管理器: AudioManager- JNI: 通过调用libmedia库实现android.media所需的接口,在libandroid_runtime.so中体现
音频采集: MediaRecoder, AudioRecord
音频播放: SoundPool, MediaPlayer, AudioTrack
音频编解码: MediaCodec
…
- HAL层: 实现audio_hw_device和audio_policy_hal, 实现与ALSA的音频接口, 实现音频路径的创建和连接
文章图片
2. Audio HAL Audio HAL架构使用的是比较复杂,混合了HIDL和Legacy HAL,笔者看的也是一头雾水
可参考< Android O Treble架构下Hal进程启动及HIDL服务注册过程>
2.1 HAL接口
HAL接口输出文件如下,主要供libaudiohal来使用
android.hardware.audio.common-util.so android.hardware.audio.common@2.0-util.so android.hardware.audio.common@2.0.so android.hardware.audio.common@4.0-util.so android.hardware.audio.common@4.0.so android.hardware.audio.effect@2.0.so android.hardware.audio.effect@4.0.so android.hardware.audio@2.0.so android.hardware.audio@4.0.so
Audio HAL提供的接口(以2.0为例)主要包括
// 音频设备 IDevice.hal |- initCheck() |- setMasterVolume(float): 设置除voice call外其他音频活动的音量 |- getMasterVolume():获取主音量 |- setMicMute(bool):设置麦克风静音状态 |- getMicMute():获取麦克风静音状态 |- setMasterMute(bool):设置静音状态 |- getMasterMute(bool):获取静音状态 |- getInputBufferSize(AudioConfig): 获取音频输入缓冲区大小 |- openOutputStream(*):创建和打开音频硬件输出流 |- openInputStream(*):创建和打开音频硬件输入流 |- supportsAudioPatches(): 判断HAL是否支持AudioPatch |- createAudioPatch(*):为SRC和SINK创建AudioPatch |- releaseAudioPatch(*):释放一个AudioPatch |- getAudioPort(*):获取指定音频端口属性 |- setAudioPortConfig(*):配置音频端口 |- getHwAvSync():获取设备的硬件同步源 |- setScreenState(bool):设置屏幕状态 |- getParameters(vec< string> ): 获取厂商定义的参数值 |- setParameters(vec< ParameterValue> ): 设置厂商定义的参数值// 音频代理 IDevicesFactory.hal |- openDevice(Device):打开一个音频设备// 主音频设备 IPrimaryDevice.hal |- setMasterVolume(float): 设置voice call音量 |- setMode(AudioMode):设置音频模式 |- getBtScoNrecEnabled():获取蓝牙ECNR使能状态 |- setBtScoNrecEnabled():设置蓝牙ECNR使能状态 |- getBtScoWidebandEnabled():获取蓝牙Wideband使能状态 |- setBtScoWidebandEnabled(bool): 设置蓝牙Wideband使能状态 |- getTtyMode():获取当前TTY模式 |- setTtyMode():设置当前TTY模式 |- getHacEnabled():获取HearingAid使能状态 |- setHacEnabled():设置HearingAid使能状态// 音频流 IStream.hal |- getFrameSize():获取帧大小 |- getFrameCount():获取缓冲区帧数 |- getBufferSize():获取流的缓冲区大小 |- getSampleRate():获取采样率(Hz) |- getSupportedSampleRates():获取流支持的支持的采样率(Hz) |- setSampleRate(uint32_t):设置流的采样率 |- getChannelMask():获取流的channel mask |- getSupportedChannelMasks(): 获取流支持的channel mask |- setChannelMask():获取流的channel mask |- getFormat():获取流的音频格式 |- getSupportedFormats():获取流支持的音频格式 |- setFormat():设置流的音频格式 |- getAudioProperties():获取流参数 |- addEffect():添加音效到流 |- removeEffect(uint64_t): 从流上停止某音效 |- standby(uint64_t):让硬件输入输出进入standby模式 |- getDevice():获取流连接的设备 |- setDevice():连接设置到流 |- setConnectedState():通知设备连接状态 |- setHwAvSync(AudioHwSync):设置硬件同步源 |- getParameters(vec< string> ): 获取厂商参数 |- setParameters(vec< ParameterValue> ):设置厂商参数 |- start():开始流操作(mmap模式) |- stop():停止流操作 |- createMmapBuffer():获取audio mmap缓冲区信息 |- getMmapPosition():读取audio mmap缓冲区读写位置 |- close():关闭和释放流// 音频输入流 IStreamIn.hal |- getAudiosource():获取输入流的source描述 |- setGain():设置音频驱动的输入增益 |- prepareForReading():设置必需的传输层以从驱动接收音频缓冲区 |- getInputFramesLost():获取丢失的输入帧的数量 |- getCapturePosition():获取接收到的音频帧数与时钟时间。// 音频输出流 IStreamOut.hal |- getLatency():获取硬件传输延迟(毫秒) |- setVolume(float, float):设置音量, 用于混音后 |- prepareForWriting():设置必需的传输层将音频缓冲区传递给驱动 |- getRenderPosition():获取音频DSP写入DAC的音频帧数 |- getNextWriteTimestamp():获取下一次写入音频驱动时间(微秒) |- setCallback():设置回调接口, 用于非阻塞模式 |- clearCallback():清楚回调 |- supportsPauseAndResume():HAL是否支持暂停和恢复流 |- pause():暂停流 |- resume():恢复流 |- supportsDrain():??? |- drain():??? |- flush():刷新流 |- getPresentationPosition():获取音频帧数// 音频输入流回调 IStreamOutCallback.hal |- onWriteReady():非阻塞写入已完成 |- onDrainReady():Drain(?)完成 |- onError():出错
2.2 HAL服务
Audio HAL服务需要实现hal接口。
这部分通常是由厂商来定制实现,Android有一个默认实现,但是实际没有什么参考意义。
/* * Code:hardware/interfaces/audio/common/all-versions/default/service/service.cpp * Output: /vendor/bin/hw/android.hardware.audio@2.0-service */ main() // 连接至vndservicemanager android::ProcessState::initWithDriver("/dev/vndbinder") android::ProcessState::self()-> startThreadPool()registerPassthroughServiceImplementation< audio::V4_0::IDevicesFactory> () registerPassthroughServiceImplementation< audio::V2_0::IDevicesFactory> ()registerPassthroughServiceImplementation< audio::effect::V4_0::IEffectsFactory> () registerPassthroughServiceImplementation< audio::effect::V2_0::IEffectsFactory> ()registerPassthroughServiceImplementation< soundtrigger::V2_1::ISoundTriggerHw> () registerPassthroughServiceImplementation< soundtrigger::V2_0::ISoundTriggerHw> ()registerPassthroughServiceImplementation< bluetooth::a2dp::V1_0::IBluetoothAudioOffload> ()android::hardware::joinRpcThreadpool()# cat /vendor/etc/init/android.hardware.audio@2.0-service.rc service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service class hal user audioserver oneshot interface android.hardware.audio@4.0::IDevicesFactory default interface android.hardware.audio@2.0::IDevicesFactory default# /vendor/etc/vintf/manifest.xml < manifest version="1.0" type="device" target-level="3"> ... < hal format="hidl"> < name> android.hardware.audio< /name> < transport> hwbinder< /transport> < version> 4.0< /version> < interface> < name> IDevicesFactory< /name> < instance> default< /instance> < /interface> < /hal> ... < /manifest>
2.3 libaudiohal
libaudiohal封装了audio hal的接口,以libaudiohal.so的形式供AudioFlinger使用,而libaudiohal又使用了libaudiohal@4.0和libaudiohal@2.0两个库,同时libaudiohal@4.0和libaudiohal@2.0有分别是audio hal接口的封装
libaudiohal最终提供的是DeviceHalInterface、DevicesFactoryHalInterface和EffectsFactoryHalInterface接口
# tree frameworks/av/media/libaudiohal . +--- 2.0 |+--- Android.bp-- libaudiohal@2.0 +--- 4.0 |+--- Android.bp-- libaudiohal@4.0 +--- Android.bp-- libaudiohal/* * DevicesFactoryHalInterface提供了create和openDevice两个方法 */ DevicesFactoryHalInterface::create() /* * 这里仅仅分析了V2_0版本, V4_0类似 * 提供了两种方式来访问audio hardware *- HIDL:即DevicesFactoryHalHidl, 用于primary, usb和remote_submix *- Legacy: 即DevicesFactoryHalLocal, 用于a2dp */ new DevicesFactoryHalHybrid() new DevicesFactoryHalLocal() new DevicesFactoryHalHidl() hardware::audio::V2_0::IDevicesFactory::getService()DevicesFactoryHalInterface::openDevice(char *name, DeviceHalInterface *device) DevicesFactoryHalHybrid::openDevice(name, device) // 针对hearing_aid和a2dp设备 DevicesFactoryHalLocal::openDevice(name, device) load_audio_interface(name, audio_hw_device_t **dev) new DeviceHalLocal(dev) // 针对其他设备, 包括primary, usb, remote_submix设备 DevicesFactoryHalHidl::openDevice(name, device) // 获取HIDL接口名 nameFromHal(name, IDevicesFactory::Device & ) IDevicesFactory::openDevice() new DeviceHalHidl(IDevice)/* 这里暂不做分析 */ EffectsFactoryHalInterface::create()
3. Native Audio 3.1 audioserver
Native Audio服务在Android N之前存在于mediaserver中,Android N之后由audioserver来启动
audioserver主要启动了两个Native binder服务
- AudioFlinger:音频系统策略的执行者, 负责音频流设备的管理及音频流数据的处理传输, 由libaudioflinger实现具体功能
- AudioPolicyService: 音频系统策略的制定者, 负责音频设备切换的策略抉择、音量调节策略等, 由libaudiopolicyservice实现具体功能
audioserver的启动的详细过程如下
/* * frameworks/av/media/audioserver/audioserver.rc */ # cat audioserver.rc service audioserver /system/bin/audioserver class core user audioserver onrestart restart vendor.audio-hal-2-0 onrestart restart audio-hal-2-0 /* * Code:frameworks/av/media/audioserver/main_audioserver.cpp * Output: /system/bin/audioserver */ main() AudioFlinger::instantiate() BinderService::instantiate() BinderService::publish() IServiceManager sm = defaultServiceManager() sm::addService("media.audio_flinger", new AudioFlinger()) AudioFlinger::onFirstRef() new PatchPanel(this) gAudioFlinger = this; AudioPolicyService::instantiate() sm::addService("media.audio_policy", new AudioPolicyService()) AudioPolicyService::onFirstRef() // Tone播放线程 new AudioCommandThread("ApmTone", this) AudioCommandThread::onFirstRef() Thread::run() AudioCommandThread::threadLoop() // Audio命令线程 new AudioCommandThread("ApmAudio", this) // 输出命令线程 new AudioCommandThread("ApmOutput", this) new AudioPolicyClient(this) createAudioPolicyManager() new AudioPolicyManager(mAudioPolicyClient) AudioPolicyManager::AudioPolicyManager() /* * 当定义了USE_XML_AUDIO_POLICY_CONF = 1 * 加载/odm/etc/audio_policy_configuration.xml */vendor/etc/audio_policy_configuration.xml */system/etc/audio_policy_configuration.xml * 否则加载 */system/etc/audio_policy.conf */vendor/etc/audio_policy.conf */ AudioPolicyManager::loadConfig() deserializeAudioPolicyXmlConfig() // FIXME: Do a lot of things AudioPolicyManager::initialize() new AudioPolicyEffects() new UidPolicy(this) UidPolicy::registerSelf() // Oboe Service AAudioService::instantiate() SoundTriggerHwService::instantiate()
3.2 AudioFlinger
AudioFlinger实现了名为”media.audio_flinger”的binder本地端,而远程端由libaudioclient实现。
// 接口定义 frameworks/av/include/media/IAudioFlinger.h // 实现AudioFlinger本地端 libaudioflinger < ==> frameworks/av/services/audioflinger/* // 实现AudioFlinger远程端 libaudioclient< ==> frameworks/av/media/libaudioclient/*
AudioFlinger主要提供了如下接口
文章图片
3.3 AudioPolicyService
AudioPolicyService实现了名为”media.audio_policy”的binder本地端,而远程端由libaudioclient实现。
// 接口定义 frameworks/av/include/media/IAudioPolicyService.h// 实现AudioPolicyService本地端 libaudiopolicyservice < ==> frameworks/av/services/audiopolicy/* // 实现AudioPolicyService远程端 libaudioclient< ==> frameworks/av/media/libaudioclient/*
AudioPolicyService主要提供了如下接口
3.4 libaudioclient
libaudioclient实现了AudioFlinger和AudioPolicyService的远程端,并实现了如下接口供media JNI使用
// android::media::*< ===> frameworks/av/media/libaudioclient/ // JNI< ===> frameworks/base/core/jni ----------------------------------------------------- | android::media::* | JNI| ----------------------------------------------------- | AudioSystem.cpp| android_media_AudioSystem.cpp | | AudioRecord.cpp| android_media_AudioRecord.cpp | | AudioTrack.cpp| android_media_AudioTrack.cpp| -----------------------------------------------------
3.5 AAudio
AAudio是在Android O版本中引入的全新Android C API。此API专为需要低延迟的高性能音频应用而设计。应用通过读取数据并将数据写入流来与AAudio进行通信。
// 接口定义 frameworks/av/media/libaaudio/include/aaudio/AAudio.h// 实现AAudio服务 libaaudioservice< ==> frameworks/av/services/oboeservice/*// 实现AAudio客户端 libaaudio< ==> frameworks/av/media/libaaudio/*
这部分目前不做分析,似乎是可选功能
4. java Audio【Android audio介绍】在Java层把Audio从功能上分为三类接口
AudioService:负责的是Audio系统的综合管理功能, 对应的API为AudioManager AudioTrack:负责音频数据的输出,即播放 AudioRecorder:负责音频数据的输出和输入,即录制
4.1 AudioService
AudioService由SystemServer启动,继承自IAudioService.Stub(通过IAudioService.aidl自动生成的),AudioService位于IAudioService的Bn端;
AudioManager拥有IAudioService的Bp端,是AudioService在客户端的一个代理,几乎所有客户端对AudioManager进行的请求,最终都会交由AudioService实现
AudioService的功能实现依赖AudioSystem类,AudioSystem是Java层到native层的代理;AudioService将通过AudioSystem与AudioPolicyService以及AudioFlinger进行交互
IAudioService - frameworks/base/media/java/android/media/IAudioService.aidl)
SystemServer::startOtherServices() SystemServiceManager::startService(AudioService.Lifecycle.class) new AudioService() AudioService::onStart() publishBinderService(Context.AUDIO_SERVICE, new AudioService()); // 向servicemanager注册服务 ServiceManager.addService( , , , ) AudioService::onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY) AudioService::systemReady() AudioHandler::handleMessage(MSG_SYSTEM_READY) AudioService::onSystemReady() AudioHandler::onLoadSoundEffects() // Bluetooth releated config AudioService::onIndicateSystemReady() // 位于android_media_AudioSystem.cpp android_media_AudioSystem_systemReady() // 位于AudioSystem.cpp AudioSystem::systemReady()
AudioService主要是作为AudioManager的后端服务存在
@SystemService(Context.AUDIO_SERVICE) public class AudioManager { ... private static IAudioService getService() { if (sService != null) { return sService; } IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); sService = IAudioService.Stub.asInterface(b); return sService; } ... }
AudioService/AudioManager的功能主要包括下面三个方面
- 音量控制 - 音频IO设备的管理 - 音频焦点机制
4.2 AudioTrack
Java层的AudioTrack通过JNI的方式使用android_media_AudioTrack.cpp封装的接口,然后调用到libaudioclient中的的android::media::AudioTrack
文章图片
111
4.3 AudioRecord
Java层的AudioRecord通过JNI的方式使用android_media_AudioRecord.cpp封装的接口
OpenSL ES 和 AAudio
https://www.jianshu.com/p/a676d4d959ae
https://source.android.google.cn/devices/audio/implement
https://blog.csdn.net/Ciellee/article/details/101980726
https://blog.csdn.net/shell812/article/details/73467010
https://www.jianshu.com/p/cf98b3cc6767
https://blog.csdn.net/u013928208/article/details/81667162
< AAudio架构讲解以及实现范例>
推荐阅读
- 清晰架构(Clean Architecture)的Go微服务: 程序容器(Application Container)
- Android 使用 Base64 编码
- Android studio的安装与使用
- MongoDB固定集合-capped collection
- Android中使用AlertDialog实现几种不同的对话框
- 获取应用图标并转为bitmap适配android10
- VS/Xamarin Android开发Follow Me
- Android系统启动过程分析
- 行业整体实力有待提高千亿体育APP定制大放异彩