Android音訊(三)AudioPolicyService
AudioPolicyService是策略的制定者,比如什麼時候開啟音訊介面裝置、某種Stream型別的音訊對應什麼裝置等等。而AudioFlinger則是策略的執行者,例如具體如何與音訊裝置通訊,如何維護現有系統中的音訊裝置,以及多個音訊流的混音如何處理等等都得由它來完成。AudioPolicyService根據使用者配置來指導AudioFlinger載入裝置介面,起到路由功能。
AudioPolicyService啟動過程
AudioPolicyService服務執行在mediaserver程式中,隨著mediaserver程式啟動而啟動。
frameworks\av\media\mediaserver\ Main_mediaserver.cpp
- int main(int argc, char** argv)
- {
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- VolumeManager::instantiate(); // volumemanager have to be started before audioflinger
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- CameraService::instantiate();
- AudioPolicyService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
AudioPolicyService繼承了模板類BinderService,該類用於註冊native service。
frameworks\native\include\binder\ BinderService.h
- template<typename SERVICE>
- class BinderService
- {
- public:
- static status_t publish(bool allowIsolated = false) {
- sp<IServiceManager> sm(defaultServiceManager());
- return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
- }
- static void instantiate() { publish(); }
- };
BinderService是一個模板類,該類的publish函式就是完成向ServiceManager註冊服務。
- static const char *getServiceName() { return "media.audio_policy"; }
AudioPolicyService註冊名為media.audio_policy的服務。
- AudioPolicyService::AudioPolicyService()
- : BnAudioPolicyService() , mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL)
- {
- char value[PROPERTY_VALUE_MAX];
- const struct hw_module_t *module;
- int forced_val;
- int rc;
- Mutex::Autolock _l(mLock);
- // start tone playback thread
- mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
- // start audio commands thread
- mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
- // start output activity command thread
- mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
- /* instantiate the audio policy manager */
- /* 載入audio_policy.default.so庫得到audio_policy_module模組 */
- rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
- if (rc)
- return;
- /* 通過audio_policy_module模組開啟audio_policy_device裝置 */
- rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
- ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
- if (rc)
- return;
- //通過audio_policy_device裝置建立audio_policy
- rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
- &mpAudioPolicy);
- ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
- if (rc)
- return;
- rc = mpAudioPolicy->init_check(mpAudioPolicy);
- ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
- if (rc)
- return;
- /* SPRD: maybe set this property better, but here just change the default value @{ */
- property_get("ro.camera.sound.forced", value, "1");
- forced_val = strtol(value, NULL, 0);
- ALOGV("setForceUse() !forced_val=%d ",!forced_val);
- mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val);
- ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
- // 讀取audio_effects.conf檔案
- if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
- loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
- } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
- loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
- }
- }
- 建立AudioCommandThread (ApmTone、ApmAudio、ApmOutput)
- 載入legacy_ap_module
- 開啟legacy_ap_device
- 建立legacy_audio_policy
- 讀取audio_effects.conf
建立AudioCommandThread執行緒
在AudioPolicyService物件構造過程中,分別建立了ApmTone、ApmAudio、ApmOutput三個AudioCommandThread執行緒:
1、 ApmTone用於播放tone音;
2、 ApmAudio用於執行audio命令;
3、ApmOutput用於執行輸出命令;
在第一次強引用AudioCommandThread執行緒物件時,AudioCommandThread的onFirstRef函式被回撥,在此啟動執行緒
- void AudioPolicyService::AudioCommandThread::onFirstRef()
- {
- run(mName.string(), ANDROID_PRIORITY_AUDIO);
- }
這裡採用非同步方式來執行audio command,當需要執行上表中的命令時,首先將命令投遞到AudioCommandThread的mAudioCommands命令向量表中,然後通過mWaitWorkCV.signal()喚醒AudioCommandThread執行緒,被喚醒的AudioCommandThread執行緒執行完command後,又通過mWaitWorkCV.waitRelative(mLock, waitTime)睡眠等待命令到來。
載入audio_policy_module模組
audio_policy硬體抽象層動態庫位於/system/lib/hw/目錄下,命名為:audio_policy.$(TARGET_BOARD_PLATFORM).so。audiopolicy的硬體抽象層定義在hardware\libhardware_legacy\audio\audio_policy_hal.cpp中,AUDIO_POLICY_HARDWARE_MODULE_ID硬體抽象模組定義如下:
hardware\libhardware_legacy\audio\ audio_policy_hal.cpp【audio_policy.scx15.so】
- struct legacy_ap_module HAL_MODULE_INFO_SYM = {
- module: {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: AUDIO_POLICY_HARDWARE_MODULE_ID,
- name: "LEGACY Audio Policy HAL",
- author: "The Android Open Source Project",
- methods: &legacy_ap_module_methods,
- dso : NULL,
- reserved : {0},
- },
- },
- };
legacy_ap_module繼承於audio_policy_module。
關於hw_get_module函式載入硬體抽象層模組的過程請參考Android硬體抽象Hardware庫載入過程原始碼分析。
開啟audio_policy_device裝置
hardware\libhardware\include\hardware\ audio_policy.h
- static inline int audio_policy_dev_open(const hw_module_t* module,
- struct audio_policy_device** device)
- {
- return module->methods->open(module, AUDIO_POLICY_INTERFACE,
- (hw_device_t**)device);
- }
通過legacy_ap_module模組的open方法來開啟一個legacy_ap_device裝置。
hardware\libhardware_legacy\audio\ audio_policy_hal.cpp
- static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
- {
- struct legacy_ap_device *dev;
- if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
- return -EINVAL;
- dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
- if (!dev)
- return -ENOMEM;
- dev->device.common.tag = HARDWARE_DEVICE_TAG;
- dev->device.common.version = 0;
- dev->device.common.module = const_cast<hw_module_t*>(module);
- dev->device.common.close = legacy_ap_dev_close;
- dev->device.create_audio_policy = create_legacy_ap;
- dev->device.destroy_audio_policy = destroy_legacy_ap;
- *device = &dev->device.common;
- return 0;
- }
開啟得到一個legacy_ap_device裝置,通過該抽象裝置可以建立一個audio_policy物件。
建立audio_policy物件
在開啟legacy_ap_device裝置時,該裝置的create_audio_policy成員初始化為create_legacy_ap函式指標,我們通過legacy_ap_device裝置可以建立一個legacy_audio_policy物件。
- rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
- &mpAudioPolicy);
這裡通過audio_policy_device裝置建立audio策略物件
hardware\libhardware_legacy\audio\ audio_policy_hal.cpp
- static int create_legacy_ap(const struct audio_policy_device *device,
- struct audio_policy_service_ops *aps_ops,
- void *service,
- struct audio_policy **ap)
- {
- struct legacy_audio_policy *lap;
- int ret;
- if (!service || !aps_ops)
- return -EINVAL;
- lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap));
- if (!lap)
- return -ENOMEM;
- lap->policy.set_device_connection_state = ap_set_device_connection_state;
- …
- lap->policy.dump = ap_dump;
- lap->policy.is_offload_supported = ap_is_offload_supported;
- lap->service = service;
- lap->aps_ops = aps_ops;
- lap->service_client = new AudioPolicyCompatClient(aps_ops, service);
- if (!lap->service_client) {
- ret = -ENOMEM;
- goto err_new_compat_client;
- }
- lap->apm = createAudioPolicyManager(lap->service_client);
- if (!lap->apm) {
- ret = -ENOMEM;
- goto err_create_apm;
- }
- *ap = &lap->policy;
- return 0;
- err_create_apm:
- delete lap->service_client;
- err_new_compat_client:
- free(lap);
- *ap = NULL;
- return ret;
- }
audio_policy實現在audio_policy_hal.cpp中,audio_policy_service_ops實現在AudioPolicyService.cpp中。create_audio_policy()函式就是建立並初始化一個legacy_audio_policy物件。
audio_policy與AudioPolicyService、AudioPolicyCompatClient之間的關係如下:
AudioPolicyClient建立
hardware\libhardware_legacy\audio\ AudioPolicyCompatClient.h
- AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,void *service) :
- mServiceOps(serviceOps) , mService(service) {}
AudioPolicyCompatClient是對audio_policy_service_ops的封裝類,對外提供audio_policy_service_ops資料結構中定義的介面。
AudioPolicyManager建立
- extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
- {
- ALOGI("SPRD policy manager created.");
- return new AudioPolicyManagerSPRD(clientInterface);
- }
使用AudioPolicyClientInterface物件來構造AudioPolicyManagerSPRD物件,AudioPolicyManagerSPRD繼承於AudioPolicyManagerBase,而AudioPolicyManagerBase又繼承於AudioPolicyInterface。
hardware\libhardware_legacy\audio\ AudioPolicyManagerBase.cpp
- AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
- :
- #ifdef AUDIO_POLICY_TEST
- Thread(false),
- #endif //AUDIO_POLICY_TEST
- //變數初始化
- mPrimaryOutput((audio_io_handle_t)0),
- mAvailableOutputDevices(AUDIO_DEVICE_NONE),
- mPhoneState(AudioSystem::MODE_NORMAL),
- mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
- mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
- mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
- mSpeakerDrcEnabled(false), mFmOffGoing(false)
- {
- //引用AudioPolicyCompatClient物件,這樣音訊管理器AudioPolicyManager就可以使用audio_policy_service_ops中的介面
- mpClientInterface = clientInterface;
- for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
- mForceUse[i] = AudioSystem::FORCE_NONE;
- }
- mA2dpDeviceAddress = String8("");
- mScoDeviceAddress = String8("");
- mUsbCardAndDevice = String8("");
- /**
- * 優先載入/vendor/etc/audio_policy.conf配置檔案,如果該配置檔案不存在,則
- * 載入/system/etc/audio_policy.conf配置檔案,如果該檔案還是不存在,則通過
- * 函式defaultAudioPolicyConfig()來設定預設音訊介面
- */
- if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
- if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
- ALOGE("could not load audio policy configuration file, setting defaults");
- defaultAudioPolicyConfig();
- }
- }
- //設定各種音訊流對應的音量調節點,must be done after reading the policy
- initializeVolumeCurves();
- // open all output streams needed to access attached devices
- for (size_t i = 0; i < mHwModules.size(); i++) {
- //通過名稱開啟對應的音訊介面硬體抽象庫
- mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
- if (mHwModules[i]->mHandle == 0) {
- ALOGW("could not open HW module %s", mHwModules[i]->mName);
- 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.
- for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
- {
- const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
- //開啟mAttachedOutputDevices對應的輸出
- if ((outProfile->mSupportedDevices & mAttachedOutputDevices) &&
- ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
- //將輸出IOProfile封裝為AudioOutputDescriptor物件
- AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
- //設定當前音訊介面的預設輸出裝置
- outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice & outProfile->mSupportedDevices);
- //開啟輸出,在AudioFlinger中建立PlaybackThread執行緒,並返回該執行緒的id
- audio_io_handle_t output = mpClientInterface->openOutput(
- outProfile->mModule->mHandle,
- &outputDesc->mDevice,
- &outputDesc->mSamplingRate,
- &outputDesc->mFormat,
- &outputDesc->mChannelMask,
- &outputDesc->mLatency,
- outputDesc->mFlags);
- if (output == 0) {
- delete outputDesc;
- } else {
- //設定可以使用的輸出裝置為mAttachedOutputDevices
- mAvailableOutputDevices =(audio_devices_t)(mAvailableOutputDevices | (outProfile->mSupportedDevices & mAttachedOutputDevices));
- if (mPrimaryOutput == 0 && outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
- mPrimaryOutput = output;
- }
- //將輸出描述符物件AudioOutputDescriptor及建立的PlaybackThread執行緒id以鍵值對形式儲存
- addOutput(output, outputDesc);
- //設定預設輸出裝置
- setOutputDevice(output,(audio_devices_t)(mDefaultOutputDevice & outProfile->mSupportedDevices),true);
- }
- }
- }
- }
- ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices),
- "Not output found for attached devices %08x",
- (mAttachedOutputDevices & ~mAvailableOutputDevices));
- ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
- updateDevicesAndOutputs();
- // add for bug158794 start
- char bootvalue[PROPERTY_VALUE_MAX];
- // prop sys.boot_completed will set 1 when system ready (ActivityManagerService.java)...
- property_get("sys.boot_completed", bootvalue, "");
- if (strncmp("1", bootvalue, 1) != 0) {
- startReadingThread();
- }
- // add for bug158794 end
- #ifdef AUDIO_POLICY_TEST
- ...
- #endif //AUDIO_POLICY_TEST
- }
AudioPolicyManagerBase物件構造過程中主要完成以下幾個步驟:
1、 loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE)載入audio_policy.conf配置檔案;
2、 initializeVolumeCurves()初始化各種音訊流對應的音量調節點;
3、 載入audio policy硬體抽象庫:mpClientInterface->loadHwModule(mHwModules[i]->mName)
4、 開啟attached_output_devices輸出:
mpClientInterface->openOutput();
5、 儲存輸出裝置描述符物件:addOutput(output, outputDesc);
讀取audio_policy.conf檔案
Android為每種音訊介面定義了對應的硬體抽象層,且編譯為單獨的so庫。
每種音訊介面定義了不同的輸入輸出,一個介面可以具有多個輸入或者輸出,每個輸入輸出有可以支援不同的音訊裝置。通過讀取audio_policy.conf檔案可以獲取系統支援的音訊介面引數。
audio_policy.conf檔案定義了兩種音訊配置資訊:
1、 當前系統支援的音訊輸入輸出裝置及預設輸入輸出裝置;
這些資訊時通過global_configuration配置項來設定,在global_configuration中定義了三種音訊裝置資訊:
attached_output_devices:已連線的輸出裝置;
default_output_device:預設輸出裝置;
attached_input_devices:已連線的輸入裝置;
1、 系統支援的音訊介面資訊;
audio_policy.conf定義了系統支援的所有音訊介面引數資訊,比如primary、a2dp、usb等,對於primary定義如下:
a2dp定義:
usb定義:
每種音訊介面包含輸入輸出,每種輸入輸出又包含多種輸入輸出配置,每種輸入輸出配置又支援多種音訊裝置。AudioPolicyManagerBase首先載入/vendor/etc/audio_policy.conf,如果該檔案不存在,則加/system/etc/audio_policy.conf。
- status_t AudioPolicyManagerBase::loadAudioPolicyConfig(const char *path)
- {
- cnode *root;
- char *data;
- data = (char *)load_file(path, NULL);
- if (data == NULL) {
- return -ENODEV;
- }
- root = config_node("", "");
- //讀取配置檔案
- config_load(root, data);
- //解析global_configuration
- loadGlobalConfig(root);
- //解析audio_hw_modules
- loadHwModules(root);
- config_free(root);
- free(root);
- free(data);
- ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
- return NO_ERROR;
- }
通過loadGlobalConfig(root)函式來讀取這些全域性配置資訊。
- void AudioPolicyManagerBase::loadGlobalConfig(cnode *root)
- {
- cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
- if (node == NULL) {
- return;
- }
- node = node->first_child;
- while (node) {
- //attached_output_devices AUDIO_DEVICE_OUT_EARPIECE
- if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
- mAttachedOutputDevices = parseDeviceNames((char *)node->value);
- ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
- "loadGlobalConfig() no attached output devices");
- ALOGV("loadGlobalConfig()mAttachedOutputDevices%04x", mAttachedOutputDevices);
- //default_output_device AUDIO_DEVICE_OUT_SPEAKER
- } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
- mDefaultOutputDevice= (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,ARRAY_SIZE(sDeviceNameToEnumTable),(char *)node->value);
- ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NON
相關文章
- 深入剖析Android音訊之AudioPolicyServiceAndroid音訊
- Android WebRTC 音視訊開發總結(三)AndroidWeb
- android音視訊指南-管理音訊焦點Android音訊
- Android音視訊之MediaPlayer音視訊播放Android
- Android音視訊之MediaRecorder音視訊錄製Android
- android 音訊播放 SoundPoolAndroid音訊
- Android 音視訊 - MediaCodec 編解碼音視訊Android
- Android 音視訊開發 視訊編碼,音訊編碼格式Android音訊
- Android音訊處理知識(一)MediaRecorder錄製音訊Android音訊
- Android 音訊應用框架Android音訊框架
- 音訊錄製:三星電腦如何錄製音訊?音訊
- android音視訊指南-處理音訊輸出的變化Android音訊
- Android音訊視覺化操作Android音訊視覺化
- android音視訊指南-MediaPlayer概述Android
- android音視訊指南-MediaRecorder概述Android
- android音訊hal層簡介Android音訊
- ANDROID音訊系統散記之四:4.0音訊系統HAL初探Android音訊
- 使用Octave音訊處理(三):數學技術處理音訊檔案音訊
- Android音視訊處理之MediaMuxerAndroidUX
- Android音視訊之AudioRecordAndroid
- Android 音視訊採集那些事Android
- Android音訊開發之MediaRecorder/MediaPlayerAndroid音訊
- 理解音訊焦點 (第 3/3 部分):三個步驟實現音訊聚焦音訊
- Android音訊開發之AudioRecord錄音實現Android音訊
- Android 音視訊開發 - 使用AudioTrack播放音訊Android音訊
- 第三章 新增背景音樂與音訊剪輯音訊
- Android 音視訊 遇上鎖屏那些事Android
- Android音視訊處理之MediaCodecAndroid
- 音視訊--音訊入門音訊
- 音視訊–音訊入門音訊
- 音訊_錄音音訊
- Android音訊實時傳輸與播放(三):AMR硬編碼與硬解碼Android音訊
- Android MediaCodec硬解碼AAC音訊檔案(實時AAC音訊幀)並播放Android音訊
- 如何做好 Android 端音視訊測試?Android
- android音視訊指南-支援的媒體格式Android
- Android WebRTC 音視訊開發總結(一)AndroidWeb
- 短視訊“音訊化”,音樂“視訊化”音訊
- 音訊 (一) : 音訊基礎知識音訊