Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e9fcfa5 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge changes from topic "fix-b-274456992-mmap-status" into main

* changes:
  audio: Add stub default MMAP implementation
  audio: Refactor Mmap buffer creation and handling
parents 2da647be 14fee7b0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ cc_library {
        "stub/ApeHeader.cpp",
        "stub/DriverStubImpl.cpp",
        "stub/ModuleStub.cpp",
        "stub/StreamMmapStub.cpp",
        "stub/StreamOffloadStub.cpp",
        "stub/StreamStub.cpp",
        "usb/ModuleUsb.cpp",
+26 −22
Original line number Diff line number Diff line
@@ -214,24 +214,33 @@ ndk::ScopedAStatus Module::createStreamContext(
    StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
                                          mVendorDebug.forceTransientBurst,
                                          mVendorDebug.forceSynchronousDrain};
    std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
    std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
    std::shared_ptr<ISoundDose> soundDose;
    if (!getSoundDose(&soundDose).isOk()) {
        LOG(ERROR) << __func__ << ": could not create sound dose instance";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    if (!hasMmapFlag(flags)) {
        dataMQ = std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames);
        streamAsyncCallback = asyncCallback;
    }
    StreamContext temp(
    StreamContext temp;
    if (hasMmapFlag(flags)) {
        MmapBufferDescriptor mmapDesc;
        RETURN_STATUS_IF_ERROR(
                createMmapBuffer(*portConfigIt, in_bufferSizeFrames, frameSize, &mmapDesc));
        temp = StreamContext(
                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                portConfigIt->format.value(), portConfigIt->channelMask.value(),
                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
                portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(mmapDesc),
                outEventCallback, mSoundDose.getInstance(), params);
    } else {
        temp = StreamContext(
                std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
                portConfigIt->format.value(), portConfigIt->channelMask.value(),
                portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
            portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
            streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
                portConfigIt->ext.get<AudioPortExt::mix>().handle,
                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
    }
    if (temp.isValid()) {
        *out_context = std::move(temp);
    } else {
@@ -394,9 +403,10 @@ ndk::ScopedAStatus Module::calculateBufferSizeFrames(
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ndk::ScopedAStatus Module::createMmapBuffer(
        const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
        ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
ndk::ScopedAStatus Module::createMmapBuffer(const AudioPortConfig& portConfig __unused,
                                            int32_t bufferSizeFrames __unused,
                                            int32_t frameSizeBytes __unused,
                                            MmapBufferDescriptor* desc __unused) {
    LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
@@ -977,9 +987,6 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar
    RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
                                               nullptr, nullptr, &context));
    context.fillDescriptor(&_aidl_return->desc);
    if (hasMmapFlag(context.getFlags())) {
        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
    }
    std::shared_ptr<StreamIn> stream;
    RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
                                             getMicrophoneInfos(), &stream));
@@ -1027,9 +1034,6 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
                                               isNonBlocking ? in_args.callback : nullptr,
                                               in_args.eventCallback, &context));
    context.fillDescriptor(&_aidl_return->desc);
    if (hasMmapFlag(context.getFlags())) {
        RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
    }
    std::shared_ptr<StreamOut> stream;
    RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
                                              in_args.offloadInfo, &stream));
+47 −9
Original line number Diff line number Diff line
@@ -21,18 +21,23 @@
#include <android-base/logging.h>

#include "core-impl/ModulePrimary.h"
#include "core-impl/StreamMmapStub.h"
#include "core-impl/StreamOffloadStub.h"
#include "core-impl/StreamPrimary.h"
#include "core-impl/Telephony.h"

using aidl::android::hardware::audio::common::areAllBitPositionFlagsSet;
using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::AudioOutputFlags;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::MicrophoneInfo;

namespace aidl::android::hardware::audio::core {
@@ -62,6 +67,11 @@ ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
                                                    const SinkMetadata& sinkMetadata,
                                                    const std::vector<MicrophoneInfo>& microphones,
                                                    std::shared_ptr<StreamIn>* result) {
    if (context.isMmap()) {
        // "Stub" is used because there is no support for MMAP audio I/O on CVD.
        return createStreamInstance<StreamInMmapStub>(result, std::move(context), sinkMetadata,
                                                      microphones);
    }
    return createStreamInstance<StreamInPrimary>(result, std::move(context), sinkMetadata,
                                                 microphones);
}
@@ -69,26 +79,54 @@ ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
ndk::ScopedAStatus ModulePrimary::createOutputStream(
        StreamContext&& context, const SourceMetadata& sourceMetadata,
        const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
    if (!areAllBitPositionFlagsSet(
    if (context.isMmap()) {
        // "Stub" is used because there is no support for MMAP audio I/O on CVD.
        return createStreamInstance<StreamOutMmapStub>(result, std::move(context), sourceMetadata,
                                                       offloadInfo);
    } else if (areAllBitPositionFlagsSet(
                       context.getFlags().get<AudioIoFlags::output>(),
                       {AudioOutputFlags::COMPRESS_OFFLOAD, AudioOutputFlags::NON_BLOCKING})) {
        return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
                                                      offloadInfo);
    } else {
        // "Stub" is used because there is no actual decoder. The stream just
        // extracts the clip duration from the media file header and simulates
        // playback over time.
        return createStreamInstance<StreamOutOffloadStub>(result, std::move(context),
                                                          sourceMetadata, offloadInfo);
    }
    return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
                                                  offloadInfo);
}

ndk::ScopedAStatus ModulePrimary::createMmapBuffer(const AudioPortConfig& portConfig,
                                                   int32_t bufferSizeFrames, int32_t frameSizeBytes,
                                                   MmapBufferDescriptor* desc) {
    const size_t bufferSizeBytes = static_cast<size_t>(bufferSizeFrames) * frameSizeBytes;
    // The actual mmap buffer for I/O is created after the stream exits standby, via
    // 'IStreamCommon.createMmapBuffer'. But we must return a valid file descriptor here because
    // 'MmapBufferDescriptor' can not contain a "null" fd.
    const std::string regionName =
            std::string("mmap-sim-o-") +
            std::to_string(portConfig.ext.get<AudioPortExt::Tag::mix>().handle);
    int fd = ashmem_create_region(regionName.c_str(), bufferSizeBytes);
    if (fd < 0) {
        PLOG(ERROR) << __func__ << ": failed to create shared memory region of " << bufferSizeBytes
                    << " bytes";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    desc->sharedMemory.fd = ndk::ScopedFileDescriptor(fd);
    desc->sharedMemory.size = bufferSizeBytes;
    desc->burstSizeFrames = bufferSizeFrames / 2;
    desc->flags = 0;
    LOG(DEBUG) << __func__ << ": " << desc->toString();
    return ndk::ScopedAStatus::ok();
}

int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig&) {
int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig& portConfig) {
    static constexpr int32_t kLowLatencyMs = 5;
    // 85 ms is chosen considering 4096 frames @ 48 kHz. This is the value which allows
    // the virtual Android device implementation to pass CTS. Hardware implementations
    // should have significantly lower latency.
    static constexpr int32_t kLatencyMs = 85;
    return kLatencyMs;
    static constexpr int32_t kStandardLatencyMs = 85;
    return hasMmapFlag(portConfig.flags.value()) ? kLowLatencyMs : kStandardLatencyMs;
}

}  // namespace aidl::android::hardware::audio::core
+23 −12
Original line number Diff line number Diff line
@@ -65,18 +65,26 @@ void StreamContext::fillDescriptor(StreamDescriptor* desc) {
    if (mReplyMQ) {
        desc->reply = mReplyMQ->dupeDesc();
    }
    if (mDataMQ) {
    desc->frameSizeBytes = getFrameSize();
    desc->bufferSizeFrames = getBufferSizeInFrames();
    if (mDataMQ) {
        desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
    } else {
        MmapBufferDescriptor mmapDesc;  // Move-only due to `fd`.
        mmapDesc.sharedMemory.fd = mMmapBufferDesc.sharedMemory.fd.dup();
        mmapDesc.sharedMemory.size = mMmapBufferDesc.sharedMemory.size;
        mmapDesc.burstSizeFrames = mMmapBufferDesc.burstSizeFrames;
        mmapDesc.flags = mMmapBufferDesc.flags;
        desc->audio.set<StreamDescriptor::AudioBuffer::Tag::mmap>(std::move(mmapDesc));
    }
}

size_t StreamContext::getBufferSizeInFrames() const {
    if (mDataMQ) {
        return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
    } else {
        return mMmapBufferDesc.sharedMemory.size / getFrameSize();
    }
    return 0;
}

size_t StreamContext::getFrameSize() const {
@@ -96,9 +104,13 @@ bool StreamContext::isValid() const {
        LOG(ERROR) << "frame size is invalid";
        return false;
    }
    if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
    if (!isMmap() && mDataMQ && !mDataMQ->isValid()) {
        LOG(ERROR) << "data FMQ is invalid";
        return false;
    } else if (isMmap() &&
               (mMmapBufferDesc.sharedMemory.fd.get() == -1 ||
                mMmapBufferDesc.sharedMemory.size == 0 || mMmapBufferDesc.burstSizeFrames == 0)) {
        LOG(ERROR) << "mmap info is invalid" << mMmapBufferDesc.toString();
    }
    return true;
}
@@ -115,6 +127,7 @@ void StreamContext::reset() {
    mCommandMQ.reset();
    mReplyMQ.reset();
    mDataMQ.reset();
    mMmapBufferDesc.sharedMemory.fd.set(-1);
}

pid_t StreamWorkerCommonLogic::getTid() const {
@@ -128,7 +141,7 @@ pid_t StreamWorkerCommonLogic::getTid() const {
std::string StreamWorkerCommonLogic::init() {
    if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
    if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
    if (!hasMmapFlag(mContext->getFlags())) {
    if (!mContext->isMmap()) {
        StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
        if (dataMQ == nullptr) return "Data MQ is null";
        if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
@@ -167,7 +180,7 @@ void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
    } else {
        reply->observable = reply->hardware = kUnknownPosition;
    }
    if (hasMmapFlag(mContext->getFlags())) {
    if (mContext->isMmap()) {
        if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
            status != ::android::OK) {
            reply->hardware = kUnknownPosition;
@@ -252,9 +265,8 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
                    mState == StreamDescriptor::State::ACTIVE ||
                    mState == StreamDescriptor::State::PAUSED ||
                    mState == StreamDescriptor::State::DRAINING) {
                    if (bool success = hasMmapFlag(mContext->getFlags())
                                               ? readMmap(&reply)
                                               : read(fmqByteCount, &reply);
                    if (bool success =
                                mContext->isMmap() ? readMmap(&reply) : read(fmqByteCount, &reply);
                        !success) {
                        mState = StreamDescriptor::State::ERROR;
                    }
@@ -548,8 +560,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                if (mState != StreamDescriptor::State::ERROR &&
                    mState != StreamDescriptor::State::TRANSFERRING &&
                    mState != StreamDescriptor::State::TRANSFER_PAUSED) {
                    if (bool success = hasMmapFlag(mContext->getFlags())
                                               ? writeMmap(&reply)
                    if (bool success = mContext->isMmap() ? writeMmap(&reply)
                                                          : write(fmqByteCount, &reply);
                        !success) {
                        mState = StreamDescriptor::State::ERROR;
+2 −2
Original line number Diff line number Diff line
@@ -212,8 +212,8 @@ class Module : public BnModule {
            const ::aidl::android::media::audio::common::AudioFormatDescription &format,
            int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
    virtual ndk::ScopedAStatus createMmapBuffer(
            const ::aidl::android::hardware::audio::core::StreamContext& context,
            ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig,
            int32_t bufferSizeFrames, int32_t frameSizeBytes, MmapBufferDescriptor* desc);

    // Utility and helper functions accessible to subclasses.
    static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
Loading