轉載請註明出處:http://blog.csdn.net/adits/article/details/8242146
開發環境簡介
1. 主機系統: Unbuntu10.10
2. android系統版本: 4.0.3(Linux kernel 3.0.8)
綜述
android的音頻系統很是龐大複雜:涉及到java應用程序,java框架層,JNI,本地服務(AudioFlinger和AudioPolicyService),硬件抽象層HAL,ALSA-LIB和ALSA-DRIVER。
本文將先分析音頻系統的啓動與模塊加載流程,並具體分析一個JAVA API的調用流程;最後在此基礎上天然地爲android系統添加USB AUDIO設備的放音和錄音功能。
全文可分爲以下幾大部分:
1. 本地服務的啓動流程分析。
1.1 AudioFlinger啓動流程及其所涉及的HAL層模塊啓動流程分析。
1.2 AudioPolicyService啓動流程及其所涉及的HAL層模塊啓動流程分析。
2. JAVA API setDeviceConnectionState()調用流程詳解,同時爲android系統添加USB AUDIO設備的放音和錄音功能。
3. ALSA-LIB淺述以及asound.conf配置文件的書寫。
4. 從新獲取USB AUDIO設備的硬件參數。
詳述
1. 本地服務的啓動流程分析。
AudioFlinger和AudioPolicyService兩大音頻服務都是在android系統啓動時就啓動的。
當linux kenerl啓動完成後,會啓動android的init進程(system/core/init/init.c)。java
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">int main(int argc, char **argv)
- {
- .....
-
- init_parse_config_file("/<span style="< span="" style="word-wrap: break-word;">color:#ff0000;">init.rc");
-
- .....
- }
init.rc文件中保存了許多系統啓動時須要啓動的服務。其中就有多媒體服務mediaserver的啓動:node
- service media /system/bin/mediaserver
此服務在文件frameworks/base/media/mediaserver/main_mediaserver.cpp中定義,而音頻子系統的兩大本地服務AudioFlinger和AudioPolicyService就是在此啓動的。linux
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">int main(int argc, char** argv)
- {
- .....
-
- <span style="color:#ff0000;">AudioFlinger::instantiate(); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
- .....
-
- <span style="color:#ff0000;">AudioPolicyService::instantiate(); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
- .....
- }
1.1 AudioFlinger啓動流程及其所涉及的HAL層模塊啓動流程分析。
根據上文分析,將調用AudioFlinger::instantiate()函數實例化AudioFlinger。可是AudioFlinger.cpp中並無找到此函數,那必然在其父類中。AudioFlinger類有不少父類,一時難以肯定instantiate()到底在哪一個父類中定義的。直接搜索吧!
grep -rn "instantiate" frameworks/base/
很快找到instantiate()函數的定義處在./frameworks/base/include/binder/BinderService.h頭文件中
android
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">template<typename SERVICE>
- class BinderService
- {
- public:
- static status_t publish() {
- sp sm(defaultServiceManager());
- return sm->addService(String16(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">SERVICE::getServiceName()), <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">new SERVICE());
-
- ......
-
- static void instantiate() { publish(); }
-
- .....
- }
- }
這裏用到了模板,須要肯定SERVICE是什麼東東。
AudioFlinger類是在AudioFlinger.h中定義的,而剛好包含了頭文件BinderService.h。數組
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioFlinger :
- public <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">BinderService,
- public BnAudioFlinger
- {
- friend class BinderService;
- public:
- static char const* getServiceName() { return "media.audio_flinger"; }
-
- .....
-
- }
原來AudioFlinger類繼承了BinderService類,同時把本身(AudioFlinger)傳遞給SERVICE。而addService函數第一個參數調用了AudioFlinger類的靜態成員函數getServiceName()獲取AudioFlinger的服務名稱;其第二個參數即是建立了一個AudioFlinger的實例。至此,明白了實例化函數instantiate()就是要向服務管理器註冊的服務是AudioFlinger。
既然此時實例化了AudioFlinger,那麼看看AudioFlinger類的構造函數具體作了哪些初始化工做。架構
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioFlinger::AudioFlinger()
- : BnAudioFlinger(),
- mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
- mBtNrecIsOff(false)
- {
- }
此構造函數作了一些可有可無的事情,無論它。既然AudioFlinger服務是第一次啓動,則將調到函數AudioFlinger::onFirstRef(至於爲何,我尚未搞明白,能夠經過log信息確信確實是這麼回事)。併發
void AudioFlinger::onFirstRef()
{
......
for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
const hw_module_t *mod;
audio_hw_device_t *dev;
rc = load_audio_interface(audio_interfaces[i], &mod,&dev);
.....
mAudioHwDevs.push(dev); // 把經過load_audio_interface()函數得到的設備存入元素爲audio_hw_device_tapp
// 類型的模板變量mAudioHwDevs中
.....
}
看到load_audio_interface()函數的名字,知曉,應當是加載音頻接口的。
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static int load_audio_interface(const char *if_name, const hw_module_t **mod,
- audio_hw_device_t **dev)
- {
- ......
-
- rc = <span style="color:#ff0000;">hw_get_module_by_class(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AUDIO_HARDWARE_MODULE_ID, if_name, mod);
- if (rc)
- goto out;
-
- rc = <span style="color:#ff0000;">audio_hw_device_open(*mod, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">dev);
-
- .....
-
- }
首先經過函數hw_get_module_by_class獲取ID號爲AUDIO_HARDWARE_MODULE_ID的音頻模塊,此ID在頭文件hardware/libhardware/include/hardware/audio.h中定義。此頭文件中定義了一個十分重要的結構體struct audio_hw_device,其中包含了許多函數接口(函數指針):
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct audio_hw_device {
- struct hw_device_t common;
-
-
-
-
-
-
-
- uint32_t (*<span style="color:#ff0000;">get_supported_devices)(const struct audio_hw_device *dev);
-
-
-
-
-
- int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">init_check)(const struct audio_hw_device *dev);
-
- ......
-
-
- int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);
-
- .....
-
-
- int (*<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">open_output_stream)(struct audio_hw_device *dev, uint32_t devices,
- int *format, uint32_t *channels,
- uint32_t *sample_rate,
- struct audio_stream_out **out);
-
- ......
-
-
- int (*open_input_stream)(struct audio_hw_device *dev, uint32_t devices,
- int *format, uint32_t *channels,
- uint32_t *sample_rate,
- audio_in_acoustics_t acoustics,
- struct audio_stream_in **stream_in);
-
- .....
- }
ID爲AUDIO_HARDWARE_MODULE_ID的音頻模塊到底在哪兒定義的那?既然是HAL層模塊,一定在hardware目錄下定義的
- $ grep -rn AUDIO_HARDWARE_MODULE_ID hardware/
- hardware/libhardware_legacy/audio/audio_hw_hal.cpp:602:id: AUDIO_HARDWARE_MODULE_ID,
- hardware/libhardware/modules/audio/audio_hw.c:435: .id = AUDIO_HARDWARE_MODULE_ID,
- hardware/libhardware/include/hardware/audio.h:37:
- #define AUDIO_HARDWARE_MODULE_ID "audio"
從搜索結果發現,AUDIO_HARDWARE_MODULE_ID的音頻模塊有兩處定義,具體用的是哪個那?
先分析下這兩個模塊最終編譯進哪些模塊。
經過查閱Android.mk曉得,audio_hw.c先被編譯進audio_policy.stub模塊,然後被編譯進libhardware模塊;
一樣的,audio_hw_hal.cpp先被編譯進libaudiopolicy_legacy模塊,然後被編譯進libhardware_legacy模塊;
而libhardware和libhardware_legacy模塊都在audioFlinger中用到。
經過log信息,確認使用的是libaudiopolicy_legacy模塊,即具體調到hardware/libhardware_legacy/audio/audio_hw_hal.cpp文件中所定義的模塊了。
在獲取到HAL層音頻模塊後,接下來執行audio_hw_device_open()函數,打開設備。此函數也在audio.h頭文件中定義,函數體以下:
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">
-
- static inline int audio_hw_device_open(const struct hw_module_t* module,
- struct audio_hw_device** device)
- {
- return module->methods->open(module, AUDIO_HARDWARE_INTERFACE,
- (struct hw_device_t**)device);
- }
struct hw_module_t是在hardware/libhardware/include/hardware/hardware.h頭文件中定義的,其中嵌套了struct hw_module_methods_t。此結構體很簡單,只有一個函數指針open
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">typedef struct hw_module_methods_t {
-
- int (*open)(const struct hw_module_t* module, const char* id,
- struct hw_device_t** device);
-
- } hw_module_methods_t;
在肯定具體模塊後,很容易肯定open函數指針的具體實現
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct legacy_audio_module HAL_MODULE_INFO_SYM = {
- module: {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: AUDIO_HARDWARE_MODULE_ID,
- name: "LEGACY Audio HW HAL",
- author: "The Android Open Source Project",
- methods: &<span style="color:#ff0000;">legacy_audio_module_methods,
- dso : NULL,
- reserved : {0},
- },
- },
- };
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static struct hw_module_methods_t legacy_audio_module_methods = {
- open: <span style="color:#ff0000;">legacy_adev_open
- };
open()的實現就是legacy_adev_open()函數了!
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">static int legacy_adev_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
- {
- struct legacy_audio_device *ladev;
- int ret;
-
- if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
- return -EINVAL;
-
- .....
-
- ladev->device.get_supported_devices = adev_get_supported_devices;
- ladev->device.init_check = <span style="color:#ff0000;">adev_init_check;
-
- .....
-
- ladev->device.open_output_stream = <span style="color:#ff0000;">adev_open_output_stream;
- ladev->device.close_output_stream = adev_close_output_stream;
- ladev->device.open_input_stream = adev_open_input_stream;
- ladev->device.close_input_stream = adev_close_input_stream;
-
- .....
-
- ladev->hwif = <span style="color:#ff0000;">createAudioHardware();
-
- .....
- <span style="color:#ff0000;">*device = &ladev->device.common; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
-
- return 0;
- }
這裏主要作了一些初始化工做,即給函數指針提供具體實現函數;但createAudioHardware()應該作了更多的事情。
先從函數createAudioHardware()的返回值入手。struct legacy_audio_device的定義以下:
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">struct legacy_audio_device {
- struct audio_hw_device device;
-
- struct AudioHardwareInterface *hwif;
- };
原來createAudioHardware()的返回值是一個硬件設備接口AudioHardwareInterface。
類AudioHardwareInterface正好在audio_hw_hal.cpp文件中所包含的頭文件hardware_legacy/AudioHardwareInterface.h中定義的虛類(結構體能調到類,仍是頭一遭見到,雖然結構體和類長得很象)。那麼我很想知道createAudioHardware()具體作了哪些事情。
首先須要肯定函數createAudioHardware()的定義在哪兒?有幾處定義?調用的具體是哪個?
AudioHardwareInterface.h頭文件中對createAudioHardware函數的聲明,沒有包含在任何類中,而僅僅包含在名字空間android_audio_legacy中,這和audio_hw_hal.cpp同在一個名字空間中。
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">namespace android_audio_legacy {
-
- .....
-
- extern "C" AudioHardwareInterface* createAudioHardware(void);
- };
經搜索,發現createAudioHardware()函數有四處定義。
- <span style=< span="" style="word-wrap: break-word;">"font-size:24px;">$ grep -rn createAudioHardware hardware/ --exclude-dir=.svn
- hardware/alsa_sound/AudioHardwareALSA.cpp:45:
- android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
- hardware/msm7k/libaudio-qsd8k/AudioHardware.cpp:2021:
- extern "C" AudioHardwareInterface* createAudioHardware(void) {
- hardware/msm7k/libaudio-qdsp5v2/AudioHardware.cpp:337:
- extern "C" AudioHardwareInterface* createAudioHardware(void) {
- hardware/msm7k/libaudio/AudioHardware.cpp:1132:
- extern "C" AudioHardwareInterface* createAudioHardware(void) {
只有AudioHardwareALSA.cpp文件中包含了頭文件hardware_legacy/AudioHardwareInterface.h,而且返回值是android_audio_legacy名字空間的AudioHardwareInterface類對象。則createAudioHardware函數的具體實現極可能是它了,經過log信息證實了這一點。
進入AudioHardwareALSA.cpp,不難看出,此函數,最後會經過執行代碼以下代碼建立AudioHardwareALSA類對象。
- "font-size:24px;">return new AudioHardwareALSA();
AudioHardwareALSA類的構造函數以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioHardwareALSA::AudioHardwareALSA() :
- mALSADevice(0),
- mAcousticDevice(0)
- {
- ......
-
- int err = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">hw_get_module(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSA_HARDWARE_MODULE_ID,
- (hw_module_t const**)<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&module);
-
- if (err == 0) {
- hw_device_t* device;
- err = <span style="color:#ff0000;">module->methods->open(module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSA_HARDWARE_NAME, &device);
- if (err == 0) {
- mALSADevice = (alsa_device_t *)device;
- <span style="color:#ff0000;">mALSADevice->init(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mALSADevice, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mDeviceList);
-
- .....
-
- err = hw_get_module(ACOUSTICS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&module);
-
- if (err == 0) {
- hw_device_t* device;
- err = module->methods->open(module, ACOUSTICS_HARDWARE_NAME, &device);
-
- .....
- }
宏ALSA_HARDWARE_MODULE_ID是在頭文件hardware/alsa_sound/AudioHardwareALSA.h中定義的。
模塊所對應的結構體類型爲hw_module_t,在頭文件hardware/libhardware/include/hardware/hardware.h中定義。
在構造函數中,首先調用函數hw_get_module()獲取ID爲ALSA_HARDWARE_MODULE_ID的ALSA硬件模塊,看來即將進入龐大而又功能強大的ALSA音頻子系統了!
通過搜索,很快肯定ID爲ALSA_HARDWARE_MODULE_ID的ALSA硬件抽象層的具體實如今文件hardware/alsa_sound/alsa_default.cpp中。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">$ grep -rn ALSA_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svn
- hardware/alsa_sound/AudioHardwareALSA.h:39:#define ALSA_HARDWARE_MODULE_ID "alsa"
- hardware/alsa_sound/alsa_default.cpp:59:
- id : ALSA_HARDWARE_MODULE_ID,
- hardware/alsa_sound/AudioHardwareALSA.cpp:150:
- int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
則很快找到此模塊的具體內容以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">extern "C" const hw_module_t HAL_MODULE_INFO_SYM = {
- tag : HARDWARE_MODULE_TAG,
- version_major : 1,
- version_minor : 0,
- id : ALSA_HARDWARE_MODULE_ID,
- name : "ALSA module",
- author : "Wind River",
- methods : &<span style="color:#ff0000;">s_module_methods,
- dso : 0,
- reserved : { 0, },
- };
s_module_methods函數的實現以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static hw_module_methods_t s_module_methods = {
- open : s_device_open
- };
s_device_open函數的實現以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int s_device_open(const hw_module_t* module, const char* name, <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">//有些困惑,
-
- hw_device_t** device) <span style="color:#3333ff;"><span style=< span="" style="word-wrap: break-word;">"background-color: rgb(255, 255, 255);">
- {
- alsa_device_t *dev;
- dev = (alsa_device_t *) malloc(sizeof(*dev));
- if (!dev) return -ENOMEM;
-
- memset(dev, 0, sizeof(*dev));
-
-
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (hw_module_t *) module;
- dev->common.close = s_device_close;
- dev->init = <span style="color:#ff0000;">s_init;
- dev->open = <span style="color:#ff0000;">s_open;
- dev->close = s_close;
- dev->route = <span style="color:#ff0000;">s_route;
-
- <span style="color:#ff0000;">*device = &dev->common; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
- return 0;
- }
通過上述分析,知道了module->methods->open函數具體調用流程了。
而後對ALSA硬件抽象層模塊作了初始化的工做。
這裏用到一個結構體變量mALSADevice,它在頭文件hardware/alsa_sound/AudioHardwareALSA.h中定義的struct alsa_device_t變量。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct alsa_device_t {
- hw_device_t common;
-
- status_t (*init)(alsa_device_t *, ALSAHandleList &);
- status_t (*open)(alsa_handle_t *, uint32_t, int);
- status_t (*close)(alsa_handle_t *);
- status_t (*route)(alsa_handle_t *, uint32_t, int);
- };
此結構體僅僅提供了一些函數調用接口,在這裏都有了具體的實現。則mALSADevice->init()將調到s_init()函數中。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static status_t s_init(alsa_device_t *module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">ALSAHandleList &list)
- {
- list.clear();
-
- snd_pcm_uframes_t bufferSize = <span style="color:#ff0000;">_defaultsOut.bufferSize;
-
- for (size_t i = 1; (bufferSize & ~i) != 0; i <<= 1)
- bufferSize &= ~i;
-
- _defaultsOut.module = module;
- _defaultsOut.bufferSize = bufferSize;
-
- <span style="color:#ff0000;">list.push_back(_defaultsOut);
-
- bufferSize = <span style="color:#ff0000;">_defaultsIn.bufferSize;
-
- .....
-
- <span style="color:#ff0000;">list.push_back(_defaultsIn);
-
- .....
- }
這裏會把_defaultsOut和_defaultsIn東東保存在ALSA句柄列表ALSAHandleList中。
首先須要明確_defaultsOut和_defaultsIn具體是什麼東東。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static alsa_handle_t _defaultsOut = {
- module : 0,
- devices : android_audio_legacy::AudioSystem::DEVICE_OUT_ALL, <span style="color:#3333ff;">
-
- curDev : 0,
- curMode : 0,
- handle : 0, <span style="color:#3333ff;">
- format : SND_PCM_FORMAT_S16_LE,
- channels : 2,
- sampleRate : DEFAULT_SAMPLE_RATE,
- latency : 200000,
- bufferSize : DEFAULT_SAMPLE_RATE / 5,
- modPrivate : 0,
- };
-
- static alsa_handle_t _defaultsIn = {
- module : 0,
- devices : android_audio_legacy::AudioSystem::DEVICE_IN_ALL, <span style="color:#3333ff;">
-
- curDev : 0,
- curMode : 0,
- handle : 0, <span style="color:#3333ff;">
- format : SND_PCM_FORMAT_S16_LE,
- channels : 2, <span style="color:#3333ff;">
-
- sampleRate : DEFAULT_SAMPLE_RATE, <span style="color:#3333ff;">
-
- <span style="color:#000000;">latency : 250000,
- bufferSize : 2048,
- modPrivate : 0,
- };
那ALSAHandleList又是什麼東東?
ALSAHandleList在頭文件hardware/alsa_sound/AudioHardwareALSA.h中定義的List模板變量。
typedef List ALSAHandleList;
原來就是struct asla_handle_t的一個列表而已,而_defaultsOut和_defaultsIn正是這樣的結構體變量。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct alsa_handle_t {
- alsa_device_t * module;
- uint32_t devices;
- uint32_t curDev;
- int curMode;
- snd_pcm_t * handle; <span style="color:#3333ff;">
- snd_pcm_format_t format;
- <span style="color:#ff0000;"> uint32_t channels;
- uint32_t sampleRate;
- unsigned int latency;
- unsigned int bufferSize;
- void * modPrivate;
- };
ALSA硬件抽象層正是這樣得到了輸出音頻通道和輸入音頻通道的相關初始化硬件參數,之後在使用中並不試圖改變這些硬件參數(針對真能手機和平板來講,也倒是不須要改變)。所以,在擴展android系統功能,爲其添加對USB AUDIO設備的支持時,就不得不考慮時事改變channels和sampleRate這兩個硬件參數的值。
至此,AudioFlinger服務首次啓動過程分析完畢!
1.2 AudioPolicyService啓動流程及其所涉及的HAL層模塊啓動流程分析。
AudioPolicyService服務的啓動流程相似於AudioFlinger服務的啓動過程,將簡要分析。
先看下AudioPolicyService類的定義(AudioPolicyService.h)(提供此類的定義,主要是爲下面instantiate()函數服務的):
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioPolicyService :
- public <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">BinderService, <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
- public BnAudioPolicyService,
-
- public IBinder::DeathRecipient
- {
- friend class BinderService;
-
- public:
-
- static const char *<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">getServiceName() { return "media.audio_policy"; }
-
- .....
- }
根據前面的分析,曉得將經過調用以下代碼啓動AudioPolicyService服務。
- "http://www.w3.org/1999/xhtml" style="font-size:24px;">AudioPolicyService::instantiate();
此代碼最後將調到AudioPolicyService類的構造函數
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">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);
-
-
- mTonePlaybackThread = new AudioCommandThread(String8(""));
-
- mAudioCommandThread = new <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AudioCommandThread(String8("ApmCommandThread"));
-
-
- rc = <span style="color:#ff0000;">hw_get_module(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
- if (rc)
- return;
-
- rc = <span style="color:#ff0000;">audio_policy_dev_open(module, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&mpAudioPolicyDev);
- LOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
- if (rc)
- return;
-
- rc = <span style="color:#ff0000;">mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, <strong style=< span="" style="word-wrap: break-word;">"background-color: rgb(192, 192, 192);"><span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&aps_ops, this,
- <span style="color:#ff0000;">&mpAudioPolicy);
- LOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
- if (rc)
- return;
-
- rc = <span style="color:#ff0000;">mpAudioPolicy->init_check(mpAudioPolicy);
-
- .....
-
- }
(1)首先開啓了放音線程和音頻命令線程。這些工做都是經過建立AudioCommandThread線程類對象完成。
AudioCommandThread類在頭文件frameworks/base/services/audioflinger/AudioPolicyService.h中定義
- "http://www.w3.org/1999/xhtml" style="font-size:24px;">class AudioCommandThread : public Thread {
是AudioPolicyService類的私有子類。
AudioCommandThread線程類建立了對象後,將進入死循環中,等待要處理的事件傳來。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">bool AudioPolicyService::AudioCommandThread::threadLoop()
- {
- nsecs_t waitTime = INT64_MAX;
-
- mLock.lock();
- while (!exitPending())
- {
- while(!mAudioCommands.isEmpty()) {
- .....
-
- switch (command->mCommand) {
-
- .....
-
- <span style="color:#ff0000;">case SET_PARAMETERS: {
- ParametersData *data = (ParametersData *)command->mParam;
- LOGV("AudioCommandThread() processing set parameters string %s, io %d",
- data->mKeyValuePairs.string(), data->mIO);
- command->mStatus = <span style="color:#ff0000;">AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
- if (command->mWaitStatus) {
- command->mCond.signal();
- mWaitWorkCV.wait(mLock);
- }
- delete data;
- }break;
-
- .....
- }
這裏只列出了switch語句中的一種狀況的處理代碼,由於後面分析setDeviceConnectionState()函數的調用流程時將用到。
當command->mCommand值爲SET_PARAMETERS時,將調用libmedia庫(frameworks/base/media/libmedia/AudioSystem.cpp)中的函數setParameters()作進一步處理。
(2)而後調用函數hw_get_module()得到ID號爲AUDIO_POLICY_HARDWARE_MODULE_ID的硬件抽象層的音頻策略模塊。宏AUDIO_POLICY_HARDWARE_MODULE_ID在頭文件hardware/libhardware/include/hardware/audio_policy.h中定義。
ID號爲AUDIO_POLICY_HARDWARE_MODULE_ID的模塊也有兩處具體實現,一樣經過log信息,確認調用的是libhardware_legacy模塊中的AUDIO_POLICY_HARDWARE_MODULE_ID子模塊的具體實現。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">$ grep -rn AUDIO_POLICY_HARDWARE_MODULE_ID hardware/ --exclude-dir=.svn
- hardware/libhardware_legacy/audio/audio_policy_hal.cpp:414:
- id: AUDIO_POLICY_HARDWARE_MODULE_ID,
- hardware/libhardware/modules/audio/audio_policy.c:318:
- .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
audio_policy_hal.cpp文件中定義的AUDIO_POLICY_HARDWARE_MODULE_ID模塊以下:
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},
},
},
};
(3)再而後調用audio_policy_dev_open()函數(在頭文件hardware/libhardware/include/hardware/audio_policy.h中定義)。
首先分析函數參數:第一個參數就是上面獲取的模塊,第二個參數mpAudioPolicyDev是struct audio_policy_device 指針變量,在頭文件AudioPolicyService.h中定義。而struct audio_policy_device是在頭文件audio_policy.h中定義的。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct audio_policy_device {
- struct hw_device_t common;
-
- int (*create_audio_policy)(const struct audio_policy_device *device,
- struct audio_policy_service_ops <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;background-color: rgb(153, 153, 153);">*aps_ops,
- void *service,
- struct audio_policy **ap);
- .....
- }
最後看下audio_policy_dev_open()函數的實現
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;"><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">
-
- 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);
- }
由上述分析可知,open函數指針就指向legacy_ap_dev_open()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
- hw_device_t** device) <span style="color:#3333ff;">
- {
- struct legacy_ap_device *dev;
-
- if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)<span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
- 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(module);
- dev->device.common.close = legacy_ap_dev_close;
- dev->device.create_audio_policy = <span style="color:#ff0000;">create_legacy_ap;
- dev->device.destroy_audio_policy = destroy_legacy_ap;
-
- <span style="color:#ff0000;">*device = &dev->device.common; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
- return 0;
- }
(4)再接下來調用的mpAudioPolicyDev->create_audio_policy()函數指針具體就是create_legacy_ap()。
第二個參數&aps_ops是struct audio_policy_service_ops變量,是APS(AudioPolicyService)的操做接口,而且傳遞的是aps_ops的地址,則被調用者使用的將是在APS中函數接口的實現。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">namespace {
- struct audio_policy_service_ops aps_ops = {
- <span style="color:#ff0000;">open_output : aps_open_output,
- open_duplicate_output : aps_open_dup_output,
- close_output : aps_close_output,
- suspend_output : aps_suspend_output,
- restore_output : aps_restore_output,
- open_input : aps_open_input,
- close_input : aps_close_input,
- set_stream_volume : aps_set_stream_volume,
- set_stream_output : aps_set_stream_output,
- <span style="color:#ff0000;">set_parameters : aps_set_parameters,
- get_parameters : aps_get_parameters,
- start_tone : aps_start_tone,
- stop_tone : aps_stop_tone,
- set_voice_volume : aps_set_voice_volume,
- move_effects : aps_move_effects,
- };
- };
struct audio_policy_service_ops在頭文件hardware/libhardware/include/hardware/audio_policy.h中定義,是包含音頻相關控制函數的接口。可見aps_ops接口將爲HAL層提供服務。
第四個參數是&mpAudioPolicy。mpAudioPolicy是struct audio_policy的指針變量(AudioPolicyService.h)。而struct audio_policy也是在audio_policy.h中定義,將要用到的接口以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">struct audio_policy {
-
-
-
-
-
- int (*set_device_connection_state)(struct audio_policy *pol,
- audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address);
-
- .....
-
-
- int (*init_check)(const struct audio_policy *pol);
-
- .....
- }
接下來看看create_audio_policy()函數指針的具體實現:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">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 = <span style="color:#ff0000;">ap_set_device_connection_state;
-
- ......
-
- lap->policy.init_check = ap_init_check;
- lap->policy.get_output = ap_get_output;
- lap->policy.start_output = ap_start_output;
- lap->policy.stop_output = ap_stop_output;
- lap->policy.release_output = ap_release_output;
- lap->policy.get_input = ap_get_input;
- lap->policy.start_input = <span style="color:#ff0000;">ap_start_input;
- lap->policy.stop_input = ap_stop_input;
- lap->policy.release_input = ap_release_input;
-
- .....
- <span style="color:#ff0000;">
- lap->service = service; <span style="color:#3333ff;">
- lap->aps_ops = aps_ops; <span style="color:#3333ff;">
- lap->service_client =
- new AudioPolicyCompatClient(aps_ops, service);
- if (!lap->service_client) {
- ret = -ENOMEM;
- goto err_new_compat_client;
- }
- <span style="color:#ff0000;">
- lap->apm = createAudioPolicyManager(lap->service_client);
-
- ......
-
- <span style="color:#ff0000;">*ap = &lap->policy; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
- ......
- }
此函數中建立了重要對象:AudioPolicyCompatClient類對象和createAudioPolicyManager函數建立音頻策略管理器,須要分析下。
先分析AudioPolicyCompatClient類對象的建立。此類在頭文件hardware/libhardware_legacy/audio/AudioPolicyCompatClient.h中定義。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">namespace android_audio_legacy {
- class AudioPolicyCompatClient : public AudioPolicyClientInterface {
- <span style="color:#3333ff;">
-
-
- public:
- AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,
- void *service) :
- <span style="color:#ff0000;">mServiceOps(serviceOps) , mService(service) {} <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
- ......
-
- private:
- struct audio_policy_service_ops* mServiceOps;
- void* mService;
-
- ......
- }
此構造函數主要初始化兩個私有化變量mServiceOps和mService,並把建立的對象做爲函數createAudioPolicyManager的惟一參數,來建立音頻策略管理器。
然而,函數createAudioPolicyManager有多個定義,搜索結果以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">$ grep -rn createAudioPolicyManager hardware/ --exclude-dir=.svn
- hardware/alsa_sound/AudioPolicyManagerALSA.cpp:31:
- extern "C" android_audio_legacy::AudioPolicyInterface*
- createAudioPolicyManager(
- android_audio_legacy::AudioPolicyClientInterface *clientInterface)
- hardware/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp:24:
- extern "C" AudioPolicyInterface*
- createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
- hardware/msm7k/libaudio-qsd8k/AudioPolicyManager.cpp:39:
- extern "C" AudioPolicyInterface*
- createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
- hardware/msm7k/libaudio-qdsp5v2/AudioPolicyManager.cpp:39:
- extern "C" AudioPolicyInterface*
- createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
- hardware/msm7k/libaudio/AudioPolicyManager.cpp:35:
- extern "C" AudioPolicyInterface*
- createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
函數createAudioPolicyManager雖然有多個定義,可是它們最後將建立AudioPolicyManagerBase類對象,以AudioPolicyManagerALSA類爲例分析
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">AudioPolicyManagerALSA::AudioPolicyManagerALSA(
- android_audio_legacy::AudioPolicyClientInterface *<span style="color:#ff0000;">clientInterface)
- : AudioPolicyManagerBase(<span style="color:#ff0000;">clientInterface) <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
- {
- }
-
- AudioPolicyManagerBase::AudioPolicyManagerBase(
- AudioPolicyClientInterface *clientInterface)
- :
- #ifdef AUDIO_POLICY_TEST
- Thread(false),
- #endif //AUDIO_POLICY_TEST
- mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0),
- mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
- mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
- mA2dpSuspended(false)
- {
- <span style="color:#ff0000;">mpClientInterface = clientInterface; <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
- for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
- mForceUse[i] = AudioSystem::FORCE_NONE;
- }
-
- initializeVolumeCurves();
-
-
- mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
- AudioSystem::DEVICE_OUT_SPEAKER; <span style="color:#3333ff;">
- mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; <span style="color:#3333ff;">
-
- ......
-
- <span style="color:#ff0000;">mHardwareOutput = <span style=< span="" style="word-wrap: break-word;">"color:#cc0000;">mpClientInterface->openOutput(&outputDesc->mDevice,
- &outputDesc->mSamplingRate,
- &outputDesc->mFormat,
- &outputDesc->mChannels,
- &outputDesc->mLatency,
- outputDesc->mFlags);
-
- ......
-
- <span style="color:#ff0000;">setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,
- true);
-
- ......
-
- }
-
mpClientInterface->openOutput()函數先回掉到AudioPolicyCompatClient類的openOutput()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""><span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="">audio_io_handle_t AudioPolicyCompatClient::openOutput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- uint32_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- AudioSystem::output_flags flags)
- {
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mServiceOps->open_output(mService, pDevices, pSamplingRate, pFormat,
- pChannels, pLatencyMs,
- (audio_policy_output_flags_t)flags);
- }
由前面分析可知,在建立AudioPolicyCompatClient類對象時,mServiceOps被初始化爲APS的struct audio_policy_service_ops變量aps_ops;則將回調到ops中的open_output()函數,具體調到aps_open_output()函數:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static audio_io_handle_t aps_open_output(void *service,
- uint32_t *pDevices,
- uint32_t *pSamplingRate,
- uint32_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- audio_policy_output_flags_t flags)
- {
- sp af = AudioSystem::get_audio_flinger();
- if (af == NULL) {
- LOGW("%s: could not get AudioFlinger", __func__);
- return 0;
- }
-
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,
- pLatencyMs, flags);
- }
不難看出,將調到AudioFlinger的openOutput()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">int AudioFlinger::openOutput(uint32_t *pDevices,
- uint32_t *pSamplingRate,
- uint32_t *pFormat,
- uint32_t *pChannels,
- uint32_t *pLatencyMs,
- uint32_t flags)
- {
- ......
-
- audio_hw_device_t *outHwDev;
-
- ......
-
- outHwDev = findSuitableHwDev_l(*pDevices);
- if (outHwDev == NULL)
- return 0;
-
- status = <span style="color:#ff0000;">outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
- &channels, &samplingRate, &outStream);
-
- ......
-
- return 0;
- }
struct audio_hw_device_t是在頭文件hardware/libhardware/include/hardware/audio.h中定義的一個結構體。
- "http://www.w3.org/1999/xhtml" style="font-size:24px;">typedef struct audio_hw_device audio_hw_device_t;
前面在分析AudioFlinger類的load_audio_interface函數時,已經分析過struct audio_hw_device。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
- {
-
- for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- audio_hw_device_t *dev = <span style="color:#ff0000;">mAudioHwDevs[i];
- if ((<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">dev->get_supported_devices(dev) & devices) == devices)
- return dev;
- }
- return NULL;
- }
由前文分析可知,此處的get_supported_devices()函數指針將具體調到audio_hw_hal.cpp文件中的adev_get_supported_devices(),以下所示,這裏列出了系統所支持的全部輸出/輸入音頻設備。所以,咱們要也要仿照此音頻設備的定義名稱,在這裏添加USB AUDIO音頻設備的名稱,以及它們在別處的定義。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
- {
-
-
-
-
-
-
- return (
- AUDIO_DEVICE_OUT_EARPIECE |
- AUDIO_DEVICE_OUT_SPEAKER |
- AUDIO_DEVICE_OUT_WIRED_HEADSET |
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_AUX_DIGITAL |
- AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
- AUDIO_DEVICE_OUT_ALL_SCO |
- AUDIO_DEVICE_OUT_DEFAULT |
-
- AUDIO_DEVICE_IN_COMMUNICATION |
- AUDIO_DEVICE_IN_AMBIENT |
- AUDIO_DEVICE_IN_BUILTIN_MIC |
- AUDIO_DEVICE_IN_WIRED_HEADSET |
- AUDIO_DEVICE_IN_AUX_DIGITAL |
- AUDIO_DEVICE_IN_BACK_MIC |
- AUDIO_DEVICE_IN_ALL_SCO |
- AUDIO_DEVICE_IN_DEFAULT);
- }
當找到合適的設備以後,將調用outHwDev->open_output_stream()函數打開相應設備的輸出流;一樣的道理,將具體調到audio_hw_hal.cpp文件中的adev_open_output_stream()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int adev_open_output_stream(struct audio_hw_device *dev,
- uint32_t devices,
- int *format,
- uint32_t *channels,
- uint32_t *sample_rate,
- struct audio_stream_out **stream_out)
- {
- struct legacy_audio_device *ladev = to_ladev(dev);
- status_t status;
- struct legacy_stream_out *out;
- int ret;
-
- out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
- if (!out)
- return -ENOMEM;
-
- out->legacy_out = <span style="color:#ff0000;">ladev->hwif->openOutputStream(devices, format, channels,
- sample_rate, &status);
-
- ......
- }
由前文分析可知,ladev->hwif具體指AudioHardwareALSA類;則ladev->hwif->openOutputStream()函數調到AudioHardwareALSA::openOutputStream()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">android_audio_legacy::AudioStreamOut *
- AudioHardwareALSA::openOutputStream(uint32_t devices,
- int *format,
- uint32_t *channels,
- uint32_t *sampleRate,
- status_t *status)
- {
- ......
-
-
- for(ALSAHandleList::iterator it = mDeviceList.begin(); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
-
- it != mDeviceList.end(); ++it)
- if (it->devices & devices) {
- err = <span style="color:#ff0000;">mALSADevice->open(&(*it), devices, mode()); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
-
- if (err) break;
- out = <span style="color:#ff0000;">new AudioStreamOutALSA(this, &(*it)); <span style=< span="" style="word-wrap: break-word;">"color:#3333ff;">
-
-
- err = out->set(format, channels, sampleRate);
- break;
- }
-
- ......
- }
由前文對AudioHardwareALSA類的啓動流程分析可知,mDeviceList是用來存儲輸出/輸入音頻通道信息的句柄的。
mALSADevice表示在初始化ALSA設備時所指向的一個具體ALSA設備的操做接口。則mALSADevice->open()函數,將具體調到ALSA模塊的s_open()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static status_t s_open(alsa_handle_t *handle, uint32_t devices, int mode)
- {
-
-
-
-
-
- s_close(handle); <span style="color:#3333ff;">
-
- LOGD("open called for devices %08x in mode %d...", devices, mode);
-
- const char *stream = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">streamName(handle);
- const char *devName = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">deviceName(handle, devices, mode);
-
- int err;
-
- for (;;) {
-
-
-
- err = <span style="color:#ff0000;">snd_pcm_open(<span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">&handle->handle, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">devName, <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">direction(handle),
- <span style="color:#3333ff;">
- SND_PCM_ASYNC);
- if (err == 0) break;
-
-
-
- char *tail = strrchr(devName, '_');
- if (!tail) break;
- *tail = 0;
- }
-
- if (err < 0) {
-
- <span style="color:#ff0000;">devName = "default";
- err = <span style="color:#ff0000;">snd_pcm_open(&handle->handle, devName, direction(handle), 0);
- }
- if (err < 0) {
- LOGE("Failed to Initialize any ALSA %s device: %s",
- stream, strerror(err));
- return NO_INIT;
- }
-
- err = <span style="color:#ff0000;">setHardwareParams(handle);
-
- if (err == NO_ERROR) err = setSoftwareParams(handle);
-
- LOGI("Initialized ALSA %s device %s", stream, devName);
-
- handle->curDev = devices;
- handle->curMode = mode;
-
- return err;
- }
-
(1) 調用函數streamName()函數獲取音頻流名稱。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *streamName(alsa_handle_t *handle)
- {
- return snd_pcm_stream_name(direction(handle));
- }
snd_pcm_stream_name()函數是ALSA-LIB API,在external/alsa-lib/src/pcm/pcm.c文件中定義。
要想得到音頻流名稱,不得不先分析direction()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">snd_pcm_stream_t direction(alsa_handle_t *handle)
- {
- return (handle->devices & android_audio_legacy::AudioSystem::DEVICE_OUT_ALL) ? SND_PCM_STREAM_PLAYBACK
- : SND_PCM_STREAM_CAPTURE;
- }
原來direction()函數就是用來返回PCM流的方向(放音或者錄音)。
direction()函數的返回值將做爲snd_pcm_stream_name()的參數,
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
- {
- if (stream > SND_PCM_STREAM_LAST)
- return NULL;
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">snd_pcm_stream_names[stream];
- }
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static const char *const snd_pcm_stream_names[] = {
- STREAM(PLAYBACK),
- STREAM(CAPTURE),
- };
好吧,音頻流的名稱不是放音就是錄音。
(2)接下來調用deviceName()函數獲取設備名稱。這點很重要,將爲咱們在asound.conf爲新添加的USB AUDIO音頻設備命名提供規則。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">const char *deviceName(alsa_handle_t *handle, uint32_t device, int mode)
- {
- static char <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">devString[ALSA_NAME_MAX];
- int hasDevExt = 0;
-
- strcpy(devString, devicePrefix[direction(handle)]);
-
- for (int dev = 0; device && dev < deviceSuffixLen; dev++)
- if (device & <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">deviceSuffix[dev].device) {
- ALSA_STRCAT (devString, deviceSuffix[dev].suffix);
- device &= ~deviceSuffix[dev].device;
- <span style="color:#ff0000;">hasDevExt = 1;
- }
-
- if (hasDevExt) switch (mode) {
- case android_audio_legacy::AudioSystem::MODE_NORMAL:
- ALSA_STRCAT (devString, "_normal")
- ;
- break;
- case android_audio_legacy::AudioSystem::MODE_RINGTONE:
- ALSA_STRCAT (devString, "_ringtone")
- ;
- break;
- case android_audio_legacy::AudioSystem::MODE_IN_CALL:
- ALSA_STRCAT (devString, "_incall")
- ;
- break;
- };
-
- return devString;
- }
用字符數組devString存儲設備名稱。
首先把設備前綴複製給devString。所以,做爲輸出音頻通道設備的名稱,必以AndroidPlayback爲前綴;做爲輸入音頻通道設備的名稱,必以AndroidCapture爲前綴。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static const char *devicePrefix[SND_PCM_STREAM_LAST + 1] = {
- "AndroidPlayback",
- "AndroidCapture",
- };
接下來從deviceSuffix數組中查找合適的後綴,追加到devString字符數組中。
- "http://www.w3.org/1999/xhtml" style="font-size:24px;">
-
- static const device_suffix_t deviceSuffix[] = {
- {android_audio_legacy::AudioSystem::DEVICE_OUT_EARPIECE, "_Earpiece"},
- {android_audio_legacy::AudioSystem::DEVICE_OUT_SPEAKER, "_Speaker"},
- {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "_Bluetooth"},
- {android_audio_legacy::AudioSystem::DEVICE_OUT_WIRED_HEADSET, "_Headset"},
- {android_audio_legacy::AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "_Bluetooth-A2DP"},
- };
struct device_suffix_t的定義以下:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">struct device_suffix_t {
- const android_audio_legacy::AudioSystem::audio_devices device;
- const char *suffix;
- };
PS: 咱們也要在此數組中添加USB AUDIO音頻設備的相關信息。同時也要在定義了相似DEVICE_OUT_EARPIECE設備的類中定義USB AUDIO音頻設備:
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;"> 1.frameworks/base/media/java/android/media/AudioSystem.java
- 2.frameworks/base/media/java/android/media/AudioManager.java
- 3.hardware/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
- 4.system/core/include/system/audio.h
題外話:android系統中對音頻設備的定義以下(AudioSystem.java):
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style=""> <span style=< span="" style="word-wrap: break-word;">"font-size:24px;"> public static final int DEVICE_OUT_EARPIECE = 0x1; // 0x1 << 0
- public static final int DEVICE_OUT_SPEAKER = 0x2;
- public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
- public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
- public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
- public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
- public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
- public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
- public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
-
- public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
- public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
- public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
- public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
- public static final int DEVICE_OUT_DEFAULT = 0x8000;
-
- public static final int DEVICE_IN_COMMUNICATION = 0x10000;
- public static final int DEVICE_IN_AMBIENT = 0x20000;
- public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000;
- public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000;
- public static final int DEVICE_IN_MIC_ARRAY = 0x100000;
- public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
-
- public static final int DEVICE_IN_WIRED_HEADSET = 0x400000;
- public static final int DEVICE_IN_AUX_DIGITAL = 0x800000;
當設備愈來愈多時,很難保證等號右邊的數字中零的個數不寫錯。採用註釋部分的定義方式較好。
當找到了設備後綴後,將對變量hasDevExt賦值爲1,表示還會有擴展名稱(_normal,_ringtone或者_incall)。
至此,一個設備的PCM節點名稱就造成了!
(3)程序將執行到調用snd_pcm_open() ALSA-LIB API,並把剛纔獲得的設備名稱devName做爲參數之一,調到ALSA-LIB,進而調到ALSA-DRIVER,去打開所指定的音頻設備。若是打開指定的音頻設備失敗了,將打開默認的音頻設備。
(4)若是成功打開音頻設備,程序繼續往下執行,將調用setHardwareParams()函數設置硬件參數。這些硬件參數包括緩衝區大小,採樣率,聲道數和音頻格式等。其實這些硬件參數都在struct alsa_handle_t中定義,在分析初始化函數s_init()函數時已有分析,在默認音頻設備配置_defaultsOut和_defaultsIn中已經指定。
可是,在使用USB AUDIO輸入音頻設備時,默認的輸入音頻配置中的聲道數和採樣率頗有可能與實際使用的USB AUDIO的不一致,致使USB AUDIO設備不可用或者音頻失真。所以,須要在執行setHardwareParams()函數前,而且知道是要打開輸入音頻通道時(輸出音頻通道的硬件參數配置可用),須要檢測時間使用的USB AUDIO音頻設備的這兩個硬件參數,從新對_defaultsIn中聲道數和採樣率進行賦值。將在後面作詳細分析。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t setHardwareParams(alsa_handle_t *handle)
- {
- ......
-
- unsigned int requestedRate = <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">handle->sampleRate;
-
- ......
-
- <span style="color:#ff0000;"> err = snd_pcm_hw_params_set_channels(handle->handle, hardwareParams,
- <span style="color:#ff0000;">handle->channels);
-
- ......
-
- err = <span style="color:#ff0000;">snd_pcm_hw_params_set_rate_near(handle->handle, hardwareParams,
- <span style="color:#ff0000;">&requestedRate, 0);
-
- ......
- }
-
(5)最後程序會執行到設置軟件參數的函數setHardwareParams()中。在添加USB AUDIO音頻設備時,這裏沒有遇到問題,再也不分析。
2. JAVA API setDeviceConnectionState()調用流程詳解。
把最複雜的兩大本地服務分析完後,後面的任務就很輕了!
JAVA API setDeviceConnectionState()在文件frameworks/base/media/java/android/media/AudioSystem.java中定義。
public static native int setDeviceConnectionState(int device, int state, String device_address);
第一個參數就是要打開的音頻設備的標識符,將一路傳遞下去,直到ALSA模塊(alsa_default.cpp);
第二個參數表示第一個參數所指的音頻設備是否可用;
第三個參數表示設備地址,通常爲空。
看到java關鍵字native,曉得將調到對應的JNI(frameworks/base/core/jni/android_media_AudioSystem.cpp)代碼。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int
- android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
- jint device, jint state, jstring device_address)
- {
- const char *c_address = env->GetStringUTFChars(device_address, NULL);
- int status = check_AudioSystem_Command(
- <span style="color:#ff0000;">AudioSystem::setDeviceConnectionState(static_cast (device),
- static_cast (state),
- c_address));
- env->ReleaseStringUTFChars(device_address, c_address);
- return status;
- }
顯然,又調到libmedia庫(frameworks/base/media/libmedia/AudioSystem.cpp)中setDeviceConnectionState()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address)
- {
- const sp& aps = AudioSystem::get_audio_policy_service();
- const char *address = "";
-
- if (aps == 0) return PERMISSION_DENIED;
-
- if (device_address != NULL) {
- address = device_address;
- }
-
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">aps->setDeviceConnectionState(device, state, address);
- }
顯然,調到APS的setDeviceConnectionState()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address)
- {
- ......
-
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,
- state, device_address);
- }
-
根據前面對AudioPolicyService服務的啓動流程分析可知,mpAudioPolicy指向在文件audio_policy_hal.cpp中定義的音頻策略模塊。則mpAudioPolicy->set_device_connection_state()函數具體調到函數ap_set_device_connection_state()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size:24px;">static int ap_set_device_connection_state(struct audio_policy *pol,
- audio_devices_t device,
- audio_policy_dev_state_t state,
- const char *device_address)
- {
- struct legacy_audio_policy *lap = to_lap(pol);
- return <span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">lap->apm->setDeviceConnectionState(
- (AudioSystem::audio_devices)device,
- (AudioSystem::device_connection_state)state,
- device_address);
- }
一樣,由前面對AudioPolicyService服務的啓動流程分析可知,lap->apm指向AudioPolicyManagerBase類對象。則lap->apm->setDeviceConnectionState()函數將調到AudioPolicyManagerBase::setDeviceConnectionState()函數。
- <span xmlns=< span="" style="word-wrap: break-word;">"http://www.w3.org/1999/xhtml" style="font-size: 24px;"><span style=< span="" style="word-wrap: break-word;">"font-size:18px;">status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
- AudioSystem::device_connection_state state,
- const char *device_address)
- {
- ......
-
-
- if (AudioSystem::isOutputDevice(device)) { <span style=< span="" style="word-wrap: break-word;">"font-size:18px;color:#3333ff;">
- <span style="font-size:18px;">
- ......
-
- switch (state)
- {
-
- case AudioSystem::DEVICE_STATE_AVAILABLE:
- if (mAvailableOutputDevices & device) {
- LOGW("setDeviceConnectionState() device already connected: %x", device);
- return INVALID_OPERATION;
- }
- LOGV("setDeviceConnectionState() connecting device %x", device);
-
-
- mAvailableOutputDevices |= device; <span style="color:#3333ff;">
-
- .....
-
-
- case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
- if (!(mAvailableOutputDevices & device)) {
- LOGW("setDeviceConnectionState() device not connected: %x", device);
- return INVALID_OPERATION;
- }
-
-
- LOGV("setDeviceConnectionState() disconnecting device %x", device);
-
- mAvailableOutputDevices &= ~device; <span style="color:#3333ff;">
-
- ......
- }
-
-
- uint32_t newDevice = <span style="color:#ff0000;">getNewDevice(mHardwareOutput, false);
-
- ......
-
- <span style="color:#ff0000;">updateDeviceForStrategy();
- <span style="font-size:24px;"><strong style=< span="" style="word-wrap: break-word;">"background-color: rgb(153, 153, 153);"><span style=< span="" style="word-wrap: break-word;">"color:#ff0000;">setOutputDevice(mHardwareOutput, newDevice);