Android音頻模塊啟動流程分析

注意:本文基於 Android 7.0 進行分析。

1) 設備開機,系統啟動時將執行 /system/etc/init/audioserver.rc ,運行 /system/bin/ 目錄下的 audioserver 服務。audioserver.rc 內容如下:

service audioserver /system/bin/audioserver class main user audioserver # media gid needed for /dev/fm (radio ) and for /data/misc/media (tee) group audio radio camera drmpc inet media mediarm net_bt net_bt_admin net_bw_acct ioprio rt 4 writepid /dev/cpuset/forground/tasks /dev/stune/foreground/tasks

2) audioserver 進程會依次對 AudioFlinger、AudioPolicyService、RadioService、SoundTriggerHwService 進行實例化。如果設備集成了杜比音效,杜比音效的內存管理服務 DolbyMemoryService 也會在這裡進行實例化。frameworks/av/media/audioserver/main_audioserver.cpp 的 main() 函數關鍵代碼如下:

int main(int argc __unused, char** argv){ .... if (doLog && (child = fork()) != 0) { // 啟動 Log 線程 .... } else { .... AudioFlinger::instantiate(); // AudioFlinger 的實例化先於AudioPolicyService AudioPolicyService::instantiate(); RadioService::instantiate();#ifdef DOLBY_ENABLE DolbyMemoryService::instantiate();#endif SoundTriggerHwService::instantiate(); .... }}

3) AudioFlinger 開始構造並調用 AudioFlinger::onFirstRef() 方法進行初始化,這個過程中會初始化 MIXER 和 DUPLICATING 類型的 playback 線程被創建後的等待延時時間,然後創建 PatchPanel 對象,並將系統的音頻模式設置為 AUDIO_MODE_NORMAL。相關代碼位於 frameworks/av/services/audioflinger/audioflinger.cpp。

4) AudioPolicyService 開始構造並調用 AudioPolicyService::onFirstRef() 方法進行初始化,這個過程中會創建 AudioPolicyManager 對象。Android 7.0系統為了兼容老版本系統中的函數調用,提供了 2 種創建 AudioPolicyManager 的方式,默認情況下,我們是使用的新的創建方式。frameworks/av/services/audiopolicy/AudioPolicyService.cpp 的 AudioPolicyService::onFirstRef() 函數關鍵代碼如下:

void AudioPolicyService::onFirstRef(){ { .... // start tone playback thread mTonePlaybackThread = new AudioCommandThread(String8("ApmTone", this)); // start audio commands thread mTonePlaybackThread = new AudioCommandThread(String8("ApmAudio", this)); // start output activity command thread mTonePlaybackThread = new AudioCommandThread(String8("ApmOutput", this));#ifdef USE_LEGACY_AUDIO_POLICY // 使用老版本的 audio policy 初始化方式 ....#else // 使用最新的 audio policy 初始化方式 ALOGI("AudioPolicyService CSTOR in new mode"); mAudioPolicyClient = new AudioPolicyClient(this); mAudioPolicyManager =createAudioPolicyManager(mAudioPolicyClient); // 創建 AudioPolicyManager 對象 ....#endif } // load audio processing modules sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects(); { .... mAudioPolicyEffects = audioPolicyEffects; }}

4.1) createAudioPolicyManager() 函數的實現位於 frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp文件中。查看源碼後我們會發現它實際上是直接調用了 AudioPolicyManager 的構造函數。代碼如下:

namespace android {extern "C" AndroidPolicyInterface* createAudioPolicyManager( AudioPolicyInterface *clientInterface){ return new AudioPolicyManager(clientInterface); // 調用 AudioPolicyManager 的構造函數創建對象}}

4.2) AudioPolicyManager 的構造函數將解析音頻策略配置文件,從而獲取到設備所支持的音頻設備信息(包括設備是否支持 Offload、Direct 模式輸出,各輸入輸出 profile 所支持的採樣率、通道數、數據格式等),載入全部 HwModule,為之創建所有非 direct 輸出類型的 outputStream 和所有 inputStream,並創建相應的 playbackThread 或 recordThread 線程。需要注意的是,Android 7.0上的音頻策略配置文件開始使用 XML 格式,其文件名為 audio_policy_configuration.xml,而在之前的版本上音頻策略配置文件為 audio_policy.conf。frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp 中 AudioPolicyManager 構造函數的關鍵代碼如下:

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface) :#ifdef AUDIO_POLICY_TEST Thread(false),#endif //AUDIO_POLICY_TEST mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f), mA2dpSuspended(false), mAudioPortGeneration(1), mBeaconMuteRefCount(0), mBeaconPlayingRefCount(0), mBeaconMuted(false), mTtsOutputAvailable(false), mMasterMono(false){ ....#ifdef USE_XML_AUDIO_POLICY_CONF // 設備使用的配置文件為 audio_policy_configuration.xml mVolumeCurves = new VolumeCurvesCollection(); AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice, speakerDrcEnabled, static_cast<VolumeCurvesCollection *>(mVolumeCurves)); PolicySerializer serializer; // 解析 xml 配置文件,將設備支持的音頻輸出設備保存在 mAvailableOutputDevices 變數中, // 將設備支持的音頻輸入設備保存在 mAvailableInputDevices 變數中,將設備的默認音頻輸出 // 設備保存在 mDefaultOutputDevice 變數中。 if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {#else // 設備使用的配置文件為 audio_policy.conf mVolumeCurves = new StreamDescriptorCollection(); AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice, speakerDrcEnabled); // 優先解析 vendor 目錄下的 conf 配置文件,然後解析 device 目錄下的 conf 配置文件。 // 將設備支持的音頻輸出設備保存在 mAvailableOutputDevices 變數中, // 將設備支持的音頻輸入設備保存在 mAvailableInputDevices 變數中,將設備的默認音頻輸出 // 設備保存在 mDefaultOutputDevice 變數中。 if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) && (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {#endif ALOGE("could not load audio policy configuration file, setting defaults"); config.setDefault(); } // must be done after reading the policy (since conditionned by Speaker Drc Enabling) mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled); // 設置音量調節曲線 .... // 依次載入 HwModule 並打開其所含 profile 的 outputStream 及 inputStream for (size_t i = 0; i < mHwModules.size(); i++) { mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName()); if (mHwModules[i]->mHandle == 0) { ALOGW("could not open HW module %s", mHwModules[i]->getName()); continue; } // open all output streams needed to access attached devices // except for direct output streams that are only opened when they are actually // required by an app. // This also validates mAvailableOutputDevices list // 打開當前 module 下所有非 direct 類型 profile 的 outputStream for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j]; .... // 如果當前操作的 module.profile 是 direct 類型,則不為其打開 outputStream if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { continue; } .... // 獲取採樣率、通道數、數據格式等各音頻參數 sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile, mpClientInterface); const DeviceVector &supportedDevices = outProfile->getSupportedDevices(); const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType); String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress : String8(""); outputDesc->mDevice = profileType; audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = outputDesc->mSamplingRate; config.channel_mask = outputDesc->mChannelMask; config.format = outputDesc->mFormat; audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; // 為當前 module.profile 打開對應的 outputStream 並創建 playbackThread 線程 status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(), &output, &config, &outputDesc->mDevice, address, &outputDesc->mLatency, outputDesc->mFlags); .... } // open input streams needed to access attached devices to validate // mAvailableInputDevices list // 打開當前 module 下所有 profile 的 inputStream for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j]; .... sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile); inputDesc->mDevice = profileType; // 獲取採樣率、通道數、數據格式等各音頻參數 // find the address DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType); // the inputs vector must be of size 1, but we dont want to crash here String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress : String8(""); ALOGV(" for input device 0x%x using address %s", profileType, address.string()); ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!"); audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = inputDesc->mSamplingRate; config.channel_mask = inputDesc->mChannelMask; config.format = inputDesc->mFormat; audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; // 為當前 module.profile 打開對應的 inputStream 並創建 recordThread 線程 status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(), &input, &config, &inputDesc->mDevice, address, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE); .... } } .... updateDevicesAndOutputs(); // 更新系統緩存的音頻輸出設備信息 ....}

5) 至此,Android 系統中音頻模塊的啟動就完成了,兩大關鍵音頻組件 AudioFlinger 和 AudioPolicyService 均已創建並運行,設備所支持的音頻輸入輸出硬體信息也已經被 AudioPolicyManager 所解析。如果此時發生了插入耳機等操作,則 AudioPolicyService 將會接收到底層通知並把 Audio Route 切換到 WiredHeadset 等響應配置;如果此時在 APP 發生了播放音樂的操作,則 AudioFlinger 會接收到上層通知並創建相應 Track。

6) 之後設備開始播放聲音時,音頻數據將從 AudioTrack 傳輸到 AudioFlinger,再傳輸到 Audio HAL,直到最終寫入硬體,這也是一個冗長複雜的過程。關於這個過程,之後我再看要不要單獨寫一篇文章進行介紹,或者想了解這部分流程的朋友們,我也推薦你們閱讀 zyuanyun 寫的《Android 音頻系統:從 AudioTrack 到 AudioFlinger》這篇文章,已經寫得非常清晰。


推薦閱讀:

Android Audio BSP工程師需要清楚的基本知識點

TAG:Android | Android框架 | 音頻 |