1. 程式人生 > >Android O(8.0)音訊write資料流程變化(HIDL)

Android O(8.0)音訊write資料流程變化(HIDL)

簡單回顧下,Audio write資料流程,
AudioTrack->write
AudioFlinger::PlaybackThread::threadLoop_write()
mNormalSink->write
而mNormalSink其實是NBAIO_Sink,實現類是:AudioStreamOutSink
那我們直接看
frameworks/av/media/libnbaio/AudioStreamOutSink.cpp

//AudioStreamOutSink::write節選
status_t ret = mStream->write(buffer, count
* mFrameSize, &written); //AudioStreamOutSink.h sp<StreamOutHalInterface> mStream;

果然,mStream型別變成了StreamOutHalInterface(Android 5.1上是audio_stream_out型別)

然後,我們發現frameworks/av/media/底下多了個資料夾
libaudiohal

Android.mk                DeviceHalLocal.h             DevicesFactoryHalLocal.h  EffectHalHidl.h
EffectsFactoryHalLocal.h StreamHalLocal.h ConversionHelperHidl.cpp DevicesFactoryHalHidl.cpp EffectBufferHalHidl.cpp EffectHalLocal.cpp HalDeathHandlerHidl.cpp ConversionHelperHidl.h DevicesFactoryHalHidl.h EffectBufferHalHidl.h EffectHalLocal.h include DeviceHalHidl.cpp
DevicesFactoryHalHybrid.cpp EffectBufferHalLocal.cpp EffectsFactoryHalHidl.cpp StreamHalHidl.cpp DeviceHalHidl.h DevicesFactoryHalHybrid.h EffectBufferHalLocal.h EffectsFactoryHalHidl.h StreamHalHidl.h DeviceHalLocal.cpp DevicesFactoryHalLocal.cpp EffectHalHidl.cpp EffectsFactoryHalLocal.cpp StreamHalLocal.cpp

很明顯,從檔名命名方式來看,一類是以Hidl結尾,一類是Local結尾,很明顯!Local結尾的應該是相容之前的方式,即谷歌在文件裡描述的

StreamOutHalInterface的實現類就在這底下了:
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl

繼續write流程
StreamOutHalHidl::write
callWriterThread(WriteCommand::WRITE,…

//StreamOutHalHidl::callWriterThread
if (!mCommandMQ->write(&cmd)) {
         ALOGE("command message queue write failed for \"%s\"", cmdName);
         return -EAGAIN;
     }
     if (data != nullptr) {
         size_t availableToWrite = mDataMQ->availableToWrite();
         if (dataSize > availableToWrite) {
             ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
                     (long long)dataSize, (long long)availableToWrite);
             dataSize = availableToWrite;
         }
         if (!mDataMQ->write(data, dataSize)) {
             ALOGE("data message queue write failed for \"%s\"", cmdName);
         }
     }

mDataMQ:
typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
看本檔案的頂部:
#include <fmq/MessageQueue.h>
好吧。fmq!

先看看WriteCommand

//StreamHalHidl.h
using WriteCommand = ::android::hardware::audio::V2_0::IStreamOut::WriteCommand;

到這裡很明顯能看出Binder化的痕跡了。這是要開始跨程序呼叫了!
fmq(Fast Message Queue)就是實現這種跨程序的關鍵!
編譯hardware/interfaces/audio模組的輸出:
/out/soong/.intermediates/hardware/interfaces/audio/2.0/[email protected]_genc++/gen/android/hardware/audio/2.0目錄下面:
DeviceAll.cpp DevicesFactoryAll.cpp PrimaryDeviceAll.cpp StreamAll.cpp StreamInAll.cpp StreamOutAll.cpp StreamOutCallbackAll.cpp types.cpp
這些檔案自動生成出來,然後可以實現audioflinger通過libaudiohal模組,binder化地呼叫hal!

現在回到:
/hardware/interfaces/audio/2.0/
default裡已經有一堆實現好的程式碼了(server端)
還是用write介面舉例:

//WriteThread::threadLoop
case IStreamOut::WriteCommand::WRITE:
    doWrite();

讓我們看看doWrite中:

//StreamOut.cpp
ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
//StreamOut.h
audio_stream_out_t *mStream;

嗯!就是熟悉的它!!!
接下來,通過函式指標,白轉千回找到
hardware/qcom/audio/hal/audio_hw.c
呼叫out_write函式,然後呼叫pcm_write從而進入tinyAlsa驅動的流程就不表了,和以前的流程應該大同小異。

和Android O以前的機制相比,其實多了一個將命令寫入FMQ,然後FMQ引擎取出命令進行響應的過程。這個過程就實現了hal層的binder化。
hardware/interfaces資料夾下的各種硬體,定義了各自的HIDL介面,還要規定版本號(版本化)。
通過rc檔案,在系統載入的時候被include到init.rc檔案裡,然後被啟動,實現系統級別的service。時刻響應FW端的遠端Binder呼叫。
FW開發者和HW開發者各自只需瞭解interface(名字,版本號),然後進行開發。這樣就實現了FW和HW的分離!

關於hidl的知識,等下篇部落格吧!