Android O(8.0)音频write数据流程变化(HIDL)

来源:互联网 发布:威廉.菲德内尔 知乎 编辑:程序博客网 时间:2024/05/20 02:24

简单回顾下,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.hsp<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.hConversionHelperHidl.cpp  DevicesFactoryHalHidl.cpp    EffectBufferHalHidl.cpp   EffectHalLocal.cpp          HalDeathHandlerHidl.cppConversionHelperHidl.h    DevicesFactoryHalHidl.h      EffectBufferHalHidl.h     EffectHalLocal.h            includeDeviceHalHidl.cpp         DevicesFactoryHalHybrid.cpp  EffectBufferHalLocal.cpp  EffectsFactoryHalHidl.cpp   StreamHalHidl.cppDeviceHalHidl.h           DevicesFactoryHalHybrid.h    EffectBufferHalLocal.h    EffectsFactoryHalHidl.h     StreamHalHidl.hDeviceHalLocal.cpp        DevicesFactoryHalLocal.cpp   EffectHalHidl.cpp         EffectsFactoryHalLocal.cpp  StreamHalLocal.cpp

很明显,从文件名命名方式来看,一类是以Hidl结尾,一类是Local结尾,很明显!Local结尾的应该是兼容之前的方式,即谷歌在文档里描述的

https://source.android.com/devices/architecture/hidl/
Using passthrough mode(我翻译为直通模式)

StreamOutHalInterface的实现类就在这底下了:
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl

继续write流程
StreamOutHalHidl::write
callWriterThread(WriteCommand::WRITE,…

//StreamOutHalHidl::callWriterThreadif (!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.husing WriteCommand = ::android::hardware::audio::V2_0::IStreamOut::WriteCommand;

到这里很明显能看出Binder化的痕迹了。这是要开始跨进程调用了!
fmq(Fast Message Queue)就是实现这种跨进程的关键!
编译hardware/interfaces/audio模块的输出:
/out/soong/.intermediates/hardware/interfaces/audio/2.0/android.hardware.audio@2.0_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::threadLoopcase IStreamOut::WriteCommand::WRITE:    doWrite();

让我们看看doWrite中:

//StreamOut.cppssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);//StreamOut.haudio_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的知识,等下篇博客吧!

原创粉丝点击