Android音頻(8)——HAL分析

1、HAL之框架android

1. tiny4412上HAL框架數據結構

audio.primary.tiny4412.so文件的Makefile:
device/friendly-arm/common/libaudio/Android.mk 框架

LOCAL_SRC_FILES:= AudioHardware.cpp LOCAL_MODULE := audio.primary.$(TARGET_DEVICE)    #TARGET_DEVICE就是tiny4412,生成audio.primary.tiny4412.so,其中primary是在 /system/etc/audio_policy.conf中指定的module的名字。 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_STATIC_LIBRARIES:= libmedia_helper LOCAL_SHARED_LIBRARIES:= \ libutils \ liblog \ libhardware_legacy \ # 依賴這個庫 libtinyalsa \ # 依賴這個庫 libaudioutils LOCAL_WHOLE_STATIC_LIBRARIES := libaudiohw_legacy

libaudiohw_legacy依賴文件:函數

hardware/libhardware_legacy/audio/Android.mk LOCAL_SRC_FILES := \ AudioHardwareInterface.cpp \ audio_hw_hal.cpp # 4412的5.0版Android上是這個HAL,其它的可不必定了 LOCAL_MODULE := libaudiohw_legacy LOCAL_MODULE_TAGS := optional LOCAL_STATIC_LIBRARIES := libmedia_helper LOCAL_CFLAGS := -Wno-unused-parameter include $(BUILD_STATIC_LIBRARY)

因此庫文件audio.primary.tiny4412.so至少涉及:
audio_hw_hal.cpp (hardware/libhardware_legacy/audio/audio_hw_hal.cpp)
audioHardwareInterface.cpp (hardware/libhardware_legacy/audio/audioHardwareInterface.cpp)
audioHardware.cpp (device/friendly-arm/common/libaudio/audioHardware.cpp) 生成audio.primary.tiny4412.so
做用:
audio_hw_hal.cpp:向上提供接口的函數
audioHardwareInterface.cpp:向廠商制定訪問硬件接口的函數
audioHardware.cpp:廠商實現的訪問聲卡硬件的文件工具

2. 要先弄清楚其框架,才能看懂其代碼。oop

從圖片上能夠看出,HAL這一層有audio的HAL,也有Audio_policy的HAL。對於Audio_policy的HAL咱們不關係,由於它基本上已經廢棄了。源碼分析

HAL要向上層提供統一的接口,操做硬件也可能有一組接口或一個類,抓住這兩點分析HAL框架。測試

3. 見audio_hw_hal.cpp,向上提供的接口就是struct audio_hw_device,它是對hw_device_t結構的封裝。spa

audio_hw_hal.cpp位於hardware/libhardware_legacy/audio下,既然是舊的,那麼有沒有新的呢?在hardware/libhardware/modules/audio
下有個audio_hw.c文件,它就是新的Audio的HAL文件,可是在5.0板中沒有使用它,它裏面的函數所有爲空。在版本的Android8.0中能夠看出,
這個文件一樣沒有實現,因此libhardware_legacy下的仍是起主打做用。可是在Android8.0中的高通的HAL使用的是新的。指針

4. audio_hw_hal.cpp
a.向上提供接口struct audio_hw_device
b.向下訪問硬件class AudioHardware(實如今device/friendly-arm/common/libaudio/audioHardware.cpp) 由廠商提供,裏面使用到了tinyalsa
庫的接口。可是廠商確定不能隨意去實現硬件的訪問接口,Android指定了一套接口給它。
類的繼承關係:

AudioHardwareInterface    //hardware/AudioHardwareInterface.cpp
 ↑ AudioHardwareBase //hardware/AudioHardwareBase.h 這個應該是audio HAL給廠商定義的接口
 ↑ AudioHardware //device/friendly-arm/common/libaudio/audioHardware.cpp

5. 在廠商的HAL中,AudioHardware (audioHardware.cpp中)表示一個聲卡,它使用audio_stream_out結構來表示輸出,使用audio_stream_in來表示輸入。
audio_stream_out中有write(),audio_stream_in中有read()


6. Audio HAL的調用流程總結

  上層應用程序調用audio_hw_hal.cpp中的legacy_adev_open()會獲得一個struct audio_hw_device結構體,這個結構體就表明上層使用硬件的接口,這個結構體中有一堆的函數,它們都依賴於廠家提供的struct AudioHardwareInterface結構(在HAL中使用,在廠商代碼中實現,此例中是在audioHardware.cpp中實現的),因爲HAL對上層直接提供的接口中沒有read/write函數,所以,應用程序想要錄音或播放聲音的時候須要先打卡output或input(調用HAL的open_output_stream/open_input_stream),以使用其裏面的write/read函數向聲卡硬件寫音頻數據。

7. HAL相關的數據結構

struct legacy_audio_device { //規範了向上提供的接口
 struct audio_hw_device device; //向上提供的接口依賴廠家提供的這個類來實現
    struct AudioHardwareInterface *hwif; }; 下面的legacy_stream_out和legacy_stream_in也是同理 struct legacy_stream_out { struct audio_stream_out stream; AudioStreamOut *legacy_out; }; struct legacy_stream_in { struct audio_stream_in stream; AudioStreamIn *legacy_in; };

上面的也是Android源碼中經常使用的套路。

8. http://androidxref.com/ 上有各個版本的Android源碼,查看代碼很是方便

9. 因爲有類的繼承關係,SourceInsight工程自動跳轉是不許的。

10. AudioFlinger啓動過程當中,AudioPolicyService構造過程當中會讀取配置文件 /system/etc/audio_policy.conf,該配置文件中有一個module名爲"primary",根據這個名字, 會去 /system/lib/hw 中打開庫文件: audio.primary.XXX.so,好比: audio.primary.tiny4412.so


11. 框架詳細描述
audio HAL中:
b.1 向上提供統一接口: audio_hw_device,裏面設置了各類函數

b.2 這些函數要藉助聲卡的代碼才能實現,聲卡的功能抽象爲AudioHardware對象

b.3 audio_hw_device中的函數只看到各類set, get,沒有看到wirte, read,怎麼播放聲音、錄製聲音?

b.4 要播放聲音,
b.4.1 要先open output:在audio_hw_device中有open_output_stream函數指針

b.4.2 open_output_stream返回一個audio_stream_out結構體,它是向上提供的"播放接口"

b.4.3 audio_stream_out也須要廠家提供的代碼才能實現,廠家提供的代碼抽象爲AudioStreamOutALSA對象

b.5 對於錄製聲音
b.5.1 要先open input:在audio_hw_device中有open_input_stream函數指針

b.5.2 open_input_stream返回一個audio_stream_in結構體,它是向上提供的"錄製接口"

b.5.3 audio_stream_in也須要廠家提供的代碼才能實現,廠家提供的代碼抽象爲AudioStreamInALSA對象

 

2、HAL之調用流程源碼分析

1. HAL文件通常位於/system/lib/hardware下面,音頻中操做硬件的庫文件名稱在(廠商提供的HAL部分)在/system/etc/policy_config中指定,如module name爲primary,
就對應audio.primary.tiny4412.so。

2. 直接使用系統調用控制聲卡的是tinyalsa庫,位於目錄/external/tinyalsa下,編譯生成庫文件libtinyalsa.so(只涉及兩個文件mixer.c,pcm.c),編譯生成工具 tinycap,tinymix,tinypcminfo,tinyplay,可用於直接控制音頻通道,進行錄音播音測試。

tinyalsa中使用
pcm_open()來打開聲卡
pcm_write()來播放音樂
pcm_read()來錄音

3. HAL調用流程源碼分析

a. 肯定HAL文件的名字:
AudioPolicyManager的構造函數讀取配置文件/system/etc/audio_policy.conf肯定名字(這個名字在tiny4412上只是HAL廠商部分編譯生成庫的名字,HAL入口是hardware/libhardware_legacy/audio/audio_hw_hal.cpp)

b. 加載HAL對應的so文件。

c. 打開HAL文件中的open函數,在HAL中會構造audio_hw_device結構體, 該結構體中有各種函數, 特別是 open_output_stream / open_input_stream

AudioFlinger根據audio_hw_device結構體構造一個AudioHwDev對象並放入mAudioHwDevs

d. open output stream: 調用hal結構體audio_hw_device的open_output_stream, 它會構造出一個audio_stream_out結構體, 裏面有write函數

AudioFlinger根據audio_stream_out結構體構造一個MixerThread

e. 播放聲音(這時才真正打開聲卡驅動): thread->threadLoopg_write => stream.write ==> pcm_open, pcm_write

相關文章
相關標籤/搜索