開始這篇文章之前,可以先了解<Linux音頻編程>
1. 架構
在Android中,Audio整體架構如下
2. Java Audio
在Java層把Audio從功能上分為三類接口
AudioService: 負責的是Audio系統的綜合管理功能, 包括音量控制、音頻IO設備的管理、音頻焦點機制
AudioTrack: 負責音頻數據的輸出,即播放
AudioRecorder: 負責音頻數據的輸出和輸入,即錄制
2.1 AudioService
AudioService由SystemServer啟動,實現了IAudioService的Bn端;AudioManager則實現了IAudioService的Bp端
AudioService的功能實現依賴Java AudioSystem類,AudioSystem是Native AudioSystem在Java層的封裝和代理
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()
AudioTrack通過JNI的方式使用android_media_AudioTrack.cpp封裝的接口,進而使用到Native AudioTrack提供的接口
AudioRecord通過JNI的方式使用android_media_AudioRecord.cpp封裝的接口,進而使用到Native AudioRecord提供的接口
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()
// 加載音頻設備, 如primary,usb,a2dp等
AudioPolicyClient::loadHwModule()
AudioFlinger::loadHwModule()
AudioFlinger::loadHwModule_l()
DevicesFactoryHalInterface::openDevice() new AudioPolicyEffects() new UidPolicy(this) UidPolicy::registerSelf() // Oboe Service AAudioService::instantiate() SoundTriggerHwService::instantiate()
3.2 AudioFlinger
AudioFlinger實現了名為”media.audio_flinger”的binder本地端,而遠程端由libaudioclient的IAudioFlinger實現。
// 接口定義 frameworks/av/include/media/IAudioFlinger.h // 實現AudioFlinger本地端 libaudioflinger <==> frameworks/av/services/audioflinger/* // 實現AudioFlinger遠程端 libaudioclient <==> frameworks/av/media/libaudioclient/*
AudioFlinger主要提供了如下接口
在AudioFliger中,將DeviceHalInterface抽象為AudioHwDevice(音頻設備)和AudioStreamOut(音頻輸出流)
3.3 AudioPolicyService
AudioPolicyService實現了名為”media.audio_policy”的binder本地端,而遠程端由libaudioclient的IAudioPolicyService實現。
// 接口定義 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. Audio HAL
Audio HAL架構比較復雜,混合了HIDL和Legacy HAL,目前已經有一套成熟的框架
可參考<Android O Treble架構下Hal進程啟動及HIDL服務注冊過程>
對廠商來說,實現以so庫的方式音頻接口,並在音頻政策配置文件(audio_policy_configuration.xml)進行配置,系統就會自動加載對應音頻設備
4.1 音頻接口
HAL接口定義在hardware/libhardware/include/hardware/audio.h文件中
- audio_hw_device: 音頻設備 - audio_stream_out: 輸出流 - audio_stream_in: 輸入流 - audio_stream: 音頻流
下面是當前已經實現或可參考的音頻設備
默認主設備: hardware/libhardware/modules/audio 車載主設備: device/generic/car/emulator/audio/driver USB設備: hardware/libhardware/modules/usbaudio RemoteSubmix設備: hardware/libhardware/modules/audio_remote_submix 藍牙A2DP設備: system/bt/audio_a2dp_hw
4.2 HAL接口
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(): 出錯
4.3 HAL服務
Audio HAL服務對HAL接口和音頻接口進行了HIDL方式地封裝
/* * 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>
4.4 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()
參考:
<Android音頻>