[audio] threadLoop_write 到 audio-hal 分析

接上文

https://blog.csdn.net/we1less/article/details/156491150?spm=1001.2014.3001.5502
https://blog.csdn.net/we1less/article/details/156506593?spm=1001.2014.3001.5502


audioflinger

av/services/audioflinger/Threads.cpp threadLoop_write

AudioMixerBase 将mSinkBuffer 填充, mNormalSink 将数据写入到 hal 中

cpp 复制代码
ssize_t PlaybackThread::threadLoop_write()
{
 
    ssize_t bytesWritten;
 
    const size_t offset = mCurrentWriteLength - mBytesRemaining;
 
 
    if (mNormalSink != 0) {
 
        const size_t count = mBytesRemaining / mFrameSize;
 
 
        ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
 
 
    }
    return bytesWritten;
}

看下这个 mNormalSink 是从哪来的

av/services/audioflinger/Threads.cpp mNormalSink

可以看出 mNormalSink 是由 构造 AudioStreamOutSink 赋值而来

cpp 复制代码
/* static */
sp<IAfPlaybackThread> IAfPlaybackThread::createMixerThread(
        const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
        audio_io_handle_t id, bool systemReady, type_t type, audio_config_base_t* mixerConfig) {
    return sp<MixerThread>::make(afThreadCallback, output, id, systemReady, type, mixerConfig);
}
 
MixerThread::MixerThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
        audio_io_handle_t id, bool systemReady, type_t type, audio_config_base_t *mixerConfig)
    :   PlaybackThread(afThreadCallback, output, id, type, systemReady, mixerConfig),
        // mOutputSink below
        // mPipeSink below
        // mNormalSink below
{
    mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
 
    mOutputSink = new AudioStreamOutSink(output->stream);
 
    mNormalSink = mOutputSink;
 
}

av/media/libnbaio/AudioStreamOutSink.cpp write

上文已经得知,在 AudioStreamOutSink 的构造器中保存了output->stream 为mStream 后续的 write 数据就是用 mStream

上文可得知,mStream 是由 AudioStreamOut 构造而来

cpp 复制代码
AudioStreamOutSink::AudioStreamOutSink(sp<StreamOutHalInterface> stream) :
        NBAIO_Sink(),
        mStream(stream),
        mStreamBufferSizeBytes(0)
{
    ALOG_ASSERT(stream != 0);
}

ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
{

    size_t written;

    status_t ret = mStream->write(buffer, count * mFrameSize, &written);

    auto processor = mMelProcessor.load();

    processor->process(buffer, written);

    written /= mFrameSize;

    mFramesWritten += written;

    return written;
}

av/services/audioflinger/datapath/AudioStreamOut.cpp write

上文可得知,这里的 stream 是 StreamOutHalHidl

cpp 复制代码
ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
{
    size_t bytesWritten;

    const status_t result = stream->write(buffer, numBytes, &bytesWritten);

    if (result == OK && bytesWritten > 0 && mHalFrameSize > 0) {
        mFramesWritten += bytesWritten / mHalFrameSize;
    }

    return result == OK ? bytesWritten : result;
}

av/media/libaudiohal/impl/StreamHalHidl.cpp StreamOutHalHidl::write

cpp 复制代码
status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
    status_t status;

    if (!mDataMQ) {

        size_t bufferSize;

        if ((status = getCachedBufferSize(&bufferSize)) != OK) {

            return status;
        }

        if (bytes > bufferSize) bufferSize = bytes;

        if ((status = prepareForWriting(bufferSize)) != OK) {

            return status;
        }
    }

    status = callWriterThread(
            WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
            [&] (const WriteStatus& writeStatus) {

                *written = writeStatus.reply.written;

            });
    
    return status;
}


status_t StreamOutHalHidl::callWriterThread(
        WriteCommand cmd, const char* cmdName,
        const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {

    mCommandMQ->write(&cmd);

    size_t availableToWrite = mDataMQ->availableToWrite();

    mDataMQ->write(data, dataSize);

    mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));

    uint32_t efState = 0;

retry:

    status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);

    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {

        WriteStatus writeStatus;

        writeStatus.retval = Result::NOT_INITIALIZED;

        mStatusMQ->read(&writeStatus);

        if (writeStatus.retval == Result::OK) {

            ret = OK;

            callback(writeStatus);

        } else {

            ret = processReturn(cmdName, writeStatus.retval);
        }

        return ret;
    }

    if (ret == -EAGAIN || ret == -EINTR) {

        goto retry;
    }

    return ret;
}

av/media/libaudiohal/impl/StreamHalHidl.h

cpp 复制代码
typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;

std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;
std::unique_ptr<StatusMQ> mStatusMQ;

libfmq/include/fmq/MessageQueue.h fast message queue 快速共享内存消息队列方案

bash 复制代码
NX563J:/ # ps -A | grep audio
root           491     2          0      0 rescuer_thread      0 S [uaudio_svc]
u0_a153       3329  1024   14529584  77320 SyS_epoll_wait      0 S org.lineageos.audiofx
audioserver   3975     1      53432  18240 binder_ioctl_write_read 0 S android.hardware.audio.service
audioserver   3976     1   11615784  22980 binder_ioctl_write_read 0 S audioserver


NX563J:/ # cat proc/3976/maps | grep Ashmem                                                                                                                                                                       
1|NX563J:/ # cat proc/3976/maps | grep ashmem                                                                                                                                                                     
741dcf7000-741dd00000 rw-s 00000000 00:05 48339                          /dev/ashmem/MemoryHeapBase (deleted)
741de1c000-741de1d000 rw-s 00000000 00:05 72121                          /dev/ashmem/MessageQueue (deleted)
741de64000-741de65000 rw-s 00000000 00:05 72121                          /dev/ashmem/MessageQueue (deleted)
741dec7000-741dec8000 rw-s 00000000 00:05 72121                          /dev/ashmem/MessageQueue (deleted)
741df5f000-741df60000 rw-s 00001000 00:05 72120                          /dev/ashmem/MessageQueue (deleted)
741e0a4000-741e0a6000 rw-s 00000000 00:05 72120                          /dev/ashmem/MessageQueue (deleted)
741e122000-741e127000 rw-s 00000000 00:05 88955                          /dev/ashmem/MemoryHeapBase (deleted)
741e34e000-741e34f000 rw-s 00000000 00:05 72120                          /dev/ashmem/MessageQueue (deleted)
741e34f000-741e350000 rw-s 00000000 00:05 72120                          /dev/ashmem/MessageQueue (deleted)
741e350000-741e355000 rw-s 00000000 00:05 47035                          /dev/ashmem/MemoryHeapBase (deleted)
741e53e000-741e53f000 rw-s 00000000 00:05 72119                          /dev/ashmem/MessageQueue (deleted)
741e540000-741e541000 rw-s 00000000 00:05 72119                          /dev/ashmem/MessageQueue (deleted)
741e541000-741e542000 rw-s 00000000 00:05 72119                          /dev/ashmem/MessageQueue (deleted)
741e547000-741e548000 rw-s 00000000 00:05 60603                          /dev/ashmem/MemoryHeapBase (deleted)
741e548000-741e549000 rw-s 00000000 00:05 62515                          /dev/ashmem/MessageQueue (deleted)
741e549000-741e54a000 rw-s 00000000 00:05 62515                          /dev/ashmem/MessageQueue (deleted)
741e54a000-741e54b000 rw-s 00000000 00:05 62515                          /dev/ashmem/MessageQueue (deleted)
741e54c000-741e54d000 rw-s 00000000 00:05 62514                          /dev/ashmem/MessageQueue (deleted)
741e54d000-741e54e000 rw-s 00000000 00:05 62514                          /dev/ashmem/MessageQueue (deleted)
741e54f000-741e550000 rw-s 00000000 00:05 62514                          /dev/ashmem/MessageQueue (deleted)
741e550000-741e551000 rw-s 00000000 00:05 62514                          /dev/ashmem/MessageQueue (deleted)
741e551000-741e552000 rw-s 00000000 00:05 62513                          /dev/ashmem/MessageQueue (deleted)
741e554000-741e555000 rw-s 00000000 00:05 62513                          /dev/ashmem/MessageQueue (deleted)
741f709000-741f70a000 rw-s 00000000 00:05 62513                          /dev/ashmem/MessageQueue (deleted)
741f70a000-741f70b000 rw-s 00000000 00:05 48109                          /dev/ashmem/MemoryHeapBase (deleted)

NX563J:/ # cat proc/3975/maps | grep ashmem                                                                                                                                                                       
e74df000-e74e0000 rw-s 00000000 00:05 72121                              /dev/ashmem/MessageQueue (deleted)
e74e0000-e74e1000 rw-s 00000000 00:05 72121                              /dev/ashmem/MessageQueue (deleted)
e74e1000-e74e2000 rw-s 00000000 00:05 72121                              /dev/ashmem/MessageQueue (deleted)
e74e2000-e74e3000 rw-s 00001000 00:05 72120                              /dev/ashmem/MessageQueue (deleted)
e74e3000-e74e5000 rw-s 00000000 00:05 72120                              /dev/ashmem/MessageQueue (deleted)
e74e5000-e74e6000 rw-s 00000000 00:05 72120                              /dev/ashmem/MessageQueue (deleted)
e74e6000-e74e7000 rw-s 00000000 00:05 72120                              /dev/ashmem/MessageQueue (deleted)
e74e7000-e74e8000 rw-s 00000000 00:05 72119                              /dev/ashmem/MessageQueue (deleted)
e74e8000-e74e9000 rw-s 00000000 00:05 72119                              /dev/ashmem/MessageQueue (deleted)
e74e9000-e74ea000 rw-s 00000000 00:05 72119                              /dev/ashmem/MessageQueue (deleted)
e74fe000-e74ff000 rw-s 00000000 00:05 62515                              /dev/ashmem/MessageQueue (deleted)
e74ff000-e7500000 rw-s 00000000 00:05 62515                              /dev/ashmem/MessageQueue (deleted)
e7500000-e7501000 rw-s 00000000 00:05 62515                              /dev/ashmem/MessageQueue (deleted)
e7501000-e7502000 rw-s 00000000 00:05 62514                              /dev/ashmem/MessageQueue (deleted)
e75bb000-e75bc000 rw-s 00000000 00:05 62514                              /dev/ashmem/MessageQueue (deleted)
e75bc000-e75bd000 rw-s 00000000 00:05 62514                              /dev/ashmem/MessageQueue (deleted)
e75be000-e75bf000 rw-s 00000000 00:05 62514                              /dev/ashmem/MessageQueue (deleted)
e75bf000-e75c0000 rw-s 00000000 00:05 62513                              /dev/ashmem/MessageQueue (deleted)
e75c0000-e75c1000 rw-s 00000000 00:05 62513                              /dev/ashmem/MessageQueue (deleted)
e75c1000-e75c2000 rw-s 00000000 00:05 62513                              /dev/ashmem/MessageQueue (deleted)
e787c000-e787d000 rw-s 00000000 00:05 49782                              /dev/ashmem/MessageQueue (deleted)
e787d000-e787e000 rw-s 00000000 00:05 49782                              /dev/ashmem/MessageQueue (deleted)
e787e000-e787f000 rw-s 00000000 00:05 49782                              /dev/ashmem/MessageQueue (deleted)
e79a6000-e79a7000 rw-s 00000000 00:05 49782                              /dev/ashmem/MessageQueue (deleted)
e7a76000-e7a77000 rw-s 00001000 00:05 40712                              /dev/ashmem/MessageQueue (deleted)
e7a77000-e7a79000 rw-s 00000000 00:05 40712                              /dev/ashmem/MessageQueue (deleted)
e7a79000-e7a7a000 rw-s 00000000 00:05 40712                              /dev/ashmem/MessageQueue (deleted)
e7a7a000-e7a7b000 rw-s 00000000 00:05 40712                              /dev/ashmem/MessageQueue (deleted)

av/media/libaudiohal/impl/StreamHalHidl.cpp prepareForWriting

cpp 复制代码
status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {

    std::unique_ptr<CommandMQ> tempCommandMQ;

    std::unique_ptr<DataMQ> tempDataMQ;

    std::unique_ptr<StatusMQ> tempStatusMQ;

    Result retval;

    pid_t halThreadPid, halThreadTid;

    Return<void> ret = mStream->prepareForWriting(
            1, bufferSize,
            [&](Result r,
                    const CommandMQ::Descriptor& commandMQ,
                    const DataMQ::Descriptor& dataMQ,
                    const StatusMQ::Descriptor& statusMQ,
                    const auto& halThreadInfo) {

                retval = r;

                if (retval == Result::OK) {

                    tempCommandMQ.reset(new CommandMQ(commandMQ));

                    tempDataMQ.reset(new DataMQ(dataMQ));

                    tempStatusMQ.reset(new StatusMQ(statusMQ));

                    if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {

                        EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);

                    }


                    halThreadPid = halThreadInfo.pid;
                    halThreadTid = halThreadInfo.tid;

                }
            });
    if (!ret.isOk() || retval != Result::OK) {

        return processReturn("prepareForWriting", ret, retval);

    }

    requestHalThreadPriority(halThreadPid, halThreadTid);

    mCommandMQ = std::move(tempCommandMQ);

    mDataMQ = std::move(tempDataMQ);

    mStatusMQ = std::move(tempStatusMQ);

    mWriterClient = gettid();

    return OK;
}

audio-hal

interfaces/audio/core/all-versions/default/StreamOut.cpp

cpp 复制代码
Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount,
                                          prepareForWriting_cb _hidl_cb) {

    status_t status;

    std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));

    std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));

    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));

    auto tempWriteThread =
            sp<WriteThread>::make(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
                                  tempStatusMQ.get(), tempElfGroup.get());

    tempWriteThread->init();

    status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO);

    mCommandMQ = std::move(tempCommandMQ);

    mDataMQ = std::move(tempDataMQ);

    mStatusMQ = std::move(tempStatusMQ);

    mWriteThread = tempWriteThread;

    _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
             threadInfo);
    return Void();
}

interfaces/audio/core/all-versions/default/StreamOut.cpp

cpp 复制代码
bool WriteThread::threadLoop() {

    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {

        uint32_t efState = 0;

        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);

        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
            continue;  // Nothing to do.
        }

        if (!mCommandMQ->read(&mStatus.replyTo)) {
            continue;  // Nothing to do.
        }

        switch (mStatus.replyTo) {
            case IStreamOut::WriteCommand::WRITE:

                doWrite();

                break;

            case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:

                doGetPresentationPosition();

                break;

            case IStreamOut::WriteCommand::GET_LATENCY:

                doGetLatency();

                break;
        }

        if (!mStatusMQ->write(&mStatus)) {
            ALOGE("status message queue write failed");
        }

        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
    }

    return false;
}

void WriteThread::doWrite() {

    const size_t availToRead = mDataMQ->availableToRead();

    mStatus.retval = Result::OK;

    mStatus.reply.written = 0;

    if (mDataMQ->read(&mBuffer[0], availToRead)) {

        ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);

        if (writeResult >= 0) {

            mStatus.reply.written = writeResult;

        } else {

            mStatus.retval = Stream::analyzeStatus("write", writeResult);

        }
    }
}
相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui