小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

ANDROID音頻系統(tǒng)散記之一:A2dpAudioInterface

 arm_embed 2012-07-31

ANDROID音頻系統(tǒng)散記之一:A2dpAudioInterface

分類(lèi): Android 1835人閱讀 評(píng)論(4) 收藏 舉報(bào)

寫(xiě)在之前


本來(lái)有打算寫(xiě)寫(xiě)Android音頻系統(tǒng)的,但是仔細(xì)研究了如下鏈接的三篇文章,果斷中斷了我的想法。毫不夸張來(lái)說(shuō),這是我看過(guò)的最好的闡述Android音頻系統(tǒng)的文章了,簡(jiǎn)練精辟,將音頻系統(tǒng)各個(gè)方面的重要的脈絡(luò)都描述出來(lái)了。有這三篇文章,理解Android音頻系統(tǒng)何止加快了10倍。

Android Audio System 之一:AudioTrack如何與AudioFlinger交換音頻數(shù)據(jù)

Android Audio System 之二:AudioFlinger

Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager


A2dpAudioInterface


Android音頻系統(tǒng)有兩大服務(wù):一是AudioFlinger,二是AudioPolicyService。AudioFlinger負(fù)責(zé)向下訪問(wèn)AudioHardwareInterface,實(shí)現(xiàn)音頻PCM數(shù)據(jù)的混音/輸入/輸出,實(shí)現(xiàn)音量調(diào)節(jié);AudioPolicyService負(fù)責(zé)音頻輸入輸出設(shè)備的連接狀態(tài),音頻策略調(diào)度即音頻設(shè)備(如本地CODEC、Bluetooth A2DP、Headset)的切換策略(注意它只是負(fù)責(zé)策略,真正的切換操作是在AudioFlinger中的openOutput,畢竟AudioFlinger負(fù)責(zé)操作底層音頻硬件)。AudioPolicyService在以后的章節(jié)詳細(xì)分析,這里主要探討A2DP-Audio是如何注冊(cè)到AudioFlinger中,并簡(jiǎn)要提及音頻PCM數(shù)據(jù)流向。


好的平臺(tái)軟件應(yīng)有這樣的一個(gè)抽象層:向下提供一套固定的接口,不同的硬件設(shè)備根據(jù)這些接口實(shí)現(xiàn)各自的方法,然后注冊(cè)到這個(gè)抽象層中去。這樣對(duì)于上層應(yīng)用而言并沒(méi)有任何區(qū)別,因?yàn)樯蠈又恍枵{(diào)用抽象層接口就行了,不管底層硬件的差異性。AudioFlinger就是這樣的一個(gè)抽象層,無(wú)論底層是ALSA設(shè)備還是BluetoothHeadset,上層都只會(huì)看到AudioFlinger的接口。至于何時(shí)切換到ALSA設(shè)備何時(shí)切換到BluetoothHeadset,這就屬于音頻策略調(diào)度范疇了即AudioPolicyService。


  1. AudioFlinger::AudioFlinger()  
  2.     : BnAudioFlinger(),  
  3.         mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)  
  4. {  
  5.     mHardwareStatus = AUDIO_HW_IDLE;  
  6.   
  7.     mAudioHardware = AudioHardwareInterface::create();  
  8.     ......  
再看AudioHardwareInterface::create():

  1. AudioHardwareInterface* AudioHardwareInterface::create()  
  2. {  
  3.     /* 
  4.      * FIXME: This code needs to instantiate the correct audio device 
  5.      * interface. For now - we use compile-time switches. 
  6.      */  
  7.     AudioHardwareInterface* hw = 0;  
  8.     char value[PROPERTY_VALUE_MAX];  
  9.   
  10. #ifdef GENERIC_AUDIO  
  11.     hw = new AudioHardwareGeneric();  
  12. #else  
  13.     // if running in emulation - use the emulator driver  
  14.     if (property_get("ro.kernel.qemu", value, 0)) {  
  15.         LOGD("Running in emulation - using generic audio driver");  
  16.         hw = new AudioHardwareGeneric();  
  17.     }  
  18.     else {  
  19.         LOGV("Creating Vendor Specific AudioHardware");  
  20.         hw = createAudioHardware();  
  21.     }  
  22. #endif  
  23.     if (hw->initCheck() != NO_ERROR) {  
  24.         LOGW("Using stubbed audio hardware. No sound will be produced.");  
  25.         delete hw;  
  26.         hw = new AudioHardwareStub();  
  27.     }  
  28.       
  29. #ifdef WITH_A2DP  
  30.     hw = new A2dpAudioInterface(hw);  
  31. #endif  
  32.   
  33. #ifdef ENABLE_AUDIO_DUMP  
  34.     // This code adds a record of buffers in a file to write calls made by AudioFlinger.  
  35.     // It replaces the current AudioHardwareInterface object by an intermediate one which  
  36.     // will record buffers in a file (after sending them to hardware) for testing purpose.  
  37.     // This feature is enabled by defining symbol ENABLE_AUDIO_DUMP.  
  38.     // The output file is set with setParameters("test_cmd_file_name=<name>"). Pause are not recorded in the file.  
  39.     LOGV("opening PCM dump interface");  
  40.     hw = new AudioDumpInterface(hw);    // replace interface  
  41. #endif  
  42.     return hw;  
  43. }  
這個(gè)函數(shù)我在ANDROID2.3音頻系統(tǒng)HAL有簡(jiǎn)要的分析,現(xiàn)在我們接著往下看看A2DP的注冊(cè):

hw = new A2dpAudioInterface(hw);

注意紅色部分hw,為什么A2dpAudioInterface還需要createAudioHardware()打開(kāi)的AudioHardwareInterface(我們假設(shè)這是ALSA設(shè)備接口)呢?如我們所知,BluetoothA2DP與ALSA設(shè)備并不走同一套接口,因此Android的設(shè)計(jì)者就把ALSA設(shè)備接口扔到A2DP接口里面管理了。這又是如何管理呢?簡(jiǎn)單來(lái)說(shuō),就是根據(jù)上層傳下來(lái)的參數(shù)devices,判斷devices是否是DEVICE_OUT_BLUETOOTH_A2DP,如果是則走A2DP接口,如果不是則走ALSA設(shè)備接口。例如需要打開(kāi)一個(gè)音頻輸出流時(shí):

  1. AudioStreamOut* A2dpAudioInterface::openOutputStream(  
  2.         uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)  
  3. {  
  4.     if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {  
  5.         LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);  
  6.         return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);  
  7.     }  
  8.   
  9.     status_t err = 0;  
  10.   
  11.     // only one output stream allowed  
  12.     if (mOutput) {  
  13.         if (status)  
  14.             *status = -1;  
  15.         return NULL;  
  16.     }  
  17.   
  18.     // create new output stream  
  19.     A2dpAudioStreamOut* out = new A2dpAudioStreamOut();  
  20.     if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {  
  21.         mOutput = out;  
  22.         mOutput->setBluetoothEnabled(mBluetoothEnabled);  
  23.         mOutput->setSuspended(mSuspended);  
  24.     } else {  
  25.         delete out;  
  26.     }  
  27.   
  28.     if (status)  
  29.         *status = err;  
  30.     return mOutput;  
  31. }  
當(dāng)上層傳下來(lái)的devices不屬于A2DP設(shè)備時(shí),則return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);其中mHardwareInterface保存的是ALSA的hw。否則A2dpAudioStreamOut* out = new A2dpAudioStreamOut();為A2DP打開(kāi)一個(gè)音頻輸出流。


liba2dp


到了A2dpAudioInterface這層,就是訪問(wèn)BlueZ的音頻操作接口了,主要是external\bluetooth\bluez\audio\liba2dp.c。liba2dp.c代碼或許很復(fù)雜,我也沒(méi)有深入了解過(guò),但是接口卻非常簡(jiǎn)單易用。看liba2dp.h,僅僅只有幾個(gè)接口:

  1. int a2dp_init(int rate, int channels, a2dpData* dataPtr);  
  2. void a2dp_set_sink(a2dpData data, const char* address);  
  3. int a2dp_write(a2dpData data, const void* buffer, int count);  
  4. int a2dp_stop(a2dpData data);  
  5. void a2dp_cleanup(a2dpData data);  
a2dp_init:根據(jù)傳入來(lái)的采樣率rate,聲道數(shù)channels初始化一個(gè)a2dpData;

a2dp_set_sink:綁定一個(gè)藍(lán)牙地址address到a2dpData上;

a2dp_write:往a2dp寫(xiě)入音頻PCM數(shù)據(jù);

a2dp_stop:停止a2dp播放。


例如,每當(dāng)有音頻PCM數(shù)據(jù)需要送入Bluetooth時(shí):

  1. ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)  
  2. {  
  3.     Mutex::Autolock lock(mLock);  
  4.   
  5.     size_t remaining = bytes;  
  6.     status_t status = -1;  
  7.   
  8.     if (!mBluetoothEnabled || mClosing || mSuspended) {  
  9.         LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \  
  10.                mBluetoothEnabled %d, mClosing %d, mSuspended %d",  
  11.                 mBluetoothEnabled, mClosing, mSuspended);  
  12.         goto Error;  
  13.     }  
  14.   
  15.     status = init();  
  16.     if (status < 0)  
  17.         goto Error;  
  18.   
  19.     while (remaining > 0) {  
  20.         status = a2dp_write(mData, buffer, remaining);  
  21.         if (status <= 0) {  
  22.             LOGE("a2dp_write failed err: %d\n", status);  
  23.             goto Error;  
  24.         }  
  25.         remaining -= status;  
  26.         buffer = ((char *)buffer) + status;  
  27.     }  
  28.   
  29.     mStandby = false;  
  30.   
  31.     return bytes;  
  32.   
  33. Error:  
  34.     // Simulate audio output timing in case of error  
  35.     usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);  
  36.   
  37.     return status;  
  38. }  
核心語(yǔ)句:status = a2dp_write(mData, buffer, remaining); 只需要傳入音頻數(shù)據(jù)的首地址和大小就行了。

該函數(shù)在AudioFlinger::MixerThread::threadLoop()調(diào)用,下面簡(jiǎn)要介紹音頻數(shù)據(jù)從上層到底層硬件設(shè)備的傳輸流向過(guò)程。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多