Android O(8.0) audio write data flow changes (HIDL)

A brief review, Audio write data flow,
AudioTrack->write
AudioFlinger::PlaybackThread::threadLoop_write()
mNormalSink->write
and mNormalSink is actually NBAIO_Sink, the implementation class is: AudioStreamOutSink
then we look directly
frameworks/av/media/libnbaio/AudioStreamOutSink.cpp

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

Sure enough, the mStream type has become StreamOutHalInterface (audio_stream_out type on Android 5.1)

Then, we found that there is an extra folder under 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

Obviously, judging from the way the file names are named, one type ends with Hidl, and the other type ends with Local, obviously! The end of Local should be compatible with the previous method, which is described by Google in the document

https://source.android.com/devices/architecture/hidl/
Using passthrough mode (I translated it as passthrough mode)

The implementation class of StreamOutHalInterface is here:
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl

Continue the write process
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;
See the top of this document:
#include <fmq/MessageQueue.h>
OK. fmq!

First look at WriteCommand

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

At this point, it is obvious to see the traces of Binderization. This is to start cross-process calls!
fmq (Fast Message Queue) is the key to achieve this cross-process!
Compile the output of the hardware/interfaces/audio module:
/out/soong/.intermediates/hardware/interfaces/audio/2.0/[email protected]_genc++/gen/android/hardware/audio/2.0 under the directory:
DeviceAll.cpp DevicesFactoryAll.cpp PrimaryDeviceAll.cpp StreamAll.cpp StreamInAll.cpp StreamOutAll.cpp StreamOutCallbackAll.cpp types.cpp
These files are automatically generated, and then audioflinger can be used to call hal bindery through the libaudiohal module !

Now back to:
/hardware/interfaces/audio/2.0/
There are already a bunch of implemented codes in the default (server side)
or use the write interface as an example:

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

Let's look at doWrite:

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

Um! It is familiar with it! ! !
Next, through the function pointer, go back and forth to find
hardware/qcom/audio/hal/audio_hw.c
the call out_write function, and then call pcm_write to enter the process driven by tinyAlsa. It should be similar to the previous process.

Compared with the previous mechanism of Android O, there is actually an additional process of writing commands into FMQ, and then the FMQ engine takes out commands to respond. This process realizes the binderization of the hal layer.
The various hardware under the hardware/interfaces folder define their own HIDL interfaces, and also specify the version number (versioning).
Through the rc file, it is included in the init.rc file when the system is loaded, and then it is started to realize the system-level service. Always respond to the remote Binder call on the FW side.
FW developers and HW developers only need to understand the interface (name, version number), and then develop. In this way, the separation of FW and HW is realized!

For the knowledge of hidl, wait for the next blog!

Guess you like

Origin blog.csdn.net/bberdong/article/details/78346729