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

Commit 53a8d4d6 authored by Kuowei Li's avatar Kuowei Li Committed by Mikhail Naganov
Browse files

audio: fix mmap output

1. add createMmapBuffer() for vendor to override and create mmap fd.
2. add refineMmapPosition() for vendor to override and update
latency in mmap case.
3. fix testcases position check in mmap case.

Bug: 274456992
Bug: 345591089
Test: atest VtsHalAudioCoreTargetTest
Change-Id: Ie63fdd47c0ddc563d84699dfdf6d4e9b72b5af43
parent 56e05036
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioMode.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <aidl/android/media/audio/common/PcmType.h>
@@ -188,4 +189,15 @@ constexpr int32_t frameCountFromDurationMs(int32_t durationMs, int32_t sampleRat
    return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
}

constexpr bool hasMmapFlag(const ::aidl::android::media::audio::common::AudioIoFlags& flags) {
    return (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::input &&
            isBitPositionFlagSet(
                    flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::input>(),
                    ::aidl::android::media::audio::common::AudioInputFlags::MMAP_NOIRQ)) ||
           (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::output &&
            isBitPositionFlagSet(
                    flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::output>(),
                    ::aidl::android::media::audio::common::AudioOutputFlags::MMAP_NOIRQ));
}

}  // namespace aidl::android::hardware::audio::common
+38 −28
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@

using aidl::android::hardware::audio::common::frameCountFromDurationMs;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::isValidAudioMode;
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -205,36 +206,32 @@ ndk::ScopedAStatus Module::createStreamContext(
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    const auto& flags = portConfigIt->flags.value();
    if ((flags.getTag() == AudioIoFlags::Tag::input &&
         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
                               AudioInputFlags::MMAP_NOIRQ)) ||
        (flags.getTag() == AudioIoFlags::Tag::output &&
         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
                               AudioOutputFlags::MMAP_NOIRQ))) {
    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(
            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::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
                asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
            portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
            streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
    if (temp.isValid()) {
        *out_context = std::move(temp);
    } else {
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    } else {
        // TODO: Implement simulation of MMAP buffer allocation
    }
    return ndk::ScopedAStatus::ok();
}

@@ -373,6 +370,13 @@ int32_t Module::getNominalLatencyMs(const AudioPortConfig&) {
    return kLatencyMs;
}

ndk::ScopedAStatus Module::createMmapBuffer(
        const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
        ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
    LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
    std::vector<AudioRoute*> result;
    auto& routes = getConfig().routes;
@@ -866,6 +870,9 @@ 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));
@@ -913,6 +920,9 @@ 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));
+36 −18
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
@@ -84,7 +85,7 @@ bool StreamContext::isValid() const {
        LOG(ERROR) << "frame size is invalid";
        return false;
    }
    if (mDataMQ && !mDataMQ->isValid()) {
    if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
        LOG(ERROR) << "data FMQ is invalid";
        return false;
    }
@@ -116,6 +117,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())) {
        StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
        if (dataMQ == nullptr) return "Data MQ is null";
        if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
@@ -128,6 +130,7 @@ std::string StreamWorkerCommonLogic::init() {
                   std::to_string(dataMQ->getQuantumCount()) +
                   ", size in bytes: " + std::to_string(mDataBufferSize);
        }
    }
    if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
        return "Failed to initialize the driver: " + std::to_string(status);
    }
@@ -136,16 +139,26 @@ std::string StreamWorkerCommonLogic::init() {

void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
                                            bool isConnected) const {
    static const StreamDescriptor::Position kUnknownPosition = {
            .frames = StreamDescriptor::Position::UNKNOWN,
            .timeNs = StreamDescriptor::Position::UNKNOWN};
    reply->status = STATUS_OK;
    if (isConnected) {
        reply->observable.frames = mContext->getFrameCount();
        reply->observable.timeNs = ::android::uptimeNanos();
        if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
            return;
        if (auto status = mDriver->refinePosition(&reply->observable); status != ::android::OK) {
            reply->observable = kUnknownPosition;
        }
    } else {
        reply->observable = reply->hardware = kUnknownPosition;
    }
    if (hasMmapFlag(mContext->getFlags())) {
        if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
            status != ::android::OK) {
            reply->hardware = kUnknownPosition;
            reply->latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
        }
    }
    reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
    reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}

void StreamWorkerCommonLogic::populateReplyWrongState(
@@ -224,7 +237,9 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
                    mState == StreamDescriptor::State::ACTIVE ||
                    mState == StreamDescriptor::State::PAUSED ||
                    mState == StreamDescriptor::State::DRAINING) {
                    if (!read(fmqByteCount, &reply)) {
                    if (hasMmapFlag(mContext->getFlags())) {
                        populateReply(&reply, mIsConnected);
                    } else if (!read(fmqByteCount, &reply)) {
                        mState = StreamDescriptor::State::ERROR;
                    }
                    if (mState == StreamDescriptor::State::IDLE ||
@@ -470,7 +485,9 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                if (mState != StreamDescriptor::State::ERROR &&
                    mState != StreamDescriptor::State::TRANSFERRING &&
                    mState != StreamDescriptor::State::TRANSFER_PAUSED) {
                    if (!write(fmqByteCount, &reply)) {
                    if (hasMmapFlag(mContext->getFlags())) {
                        populateReply(&reply, mIsConnected);
                    } else if (!write(fmqByteCount, &reply)) {
                        mState = StreamDescriptor::State::ERROR;
                    }
                    std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
@@ -657,6 +674,7 @@ ndk::ScopedAStatus StreamCommonImpl::initInstance(
        const std::shared_ptr<StreamCommonInterface>& delegate) {
    mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
    if (!mWorker->start()) {
        LOG(ERROR) << __func__ << ": Worker start error: " << mWorker->getError();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    if (auto flags = getContext().getFlags();
+3 −0
Original line number Diff line number Diff line
@@ -205,6 +205,9 @@ class Module : public BnModule {
    virtual std::unique_ptr<Configuration> initializeConfig();
    virtual int32_t getNominalLatencyMs(
            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
    virtual ndk::ScopedAStatus createMmapBuffer(
            const ::aidl::android::hardware::audio::core::StreamContext& context,
            ::aidl::android::hardware::audio::core::StreamDescriptor* desc);

    // Utility and helper functions accessible to subclasses.
    static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
+7 −0
Original line number Diff line number Diff line
@@ -177,6 +177,11 @@ struct DriverInterface {
    virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
        return ::android::OK;
    }
    // Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
    virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
                                                          int32_t* /*latency*/) {
        return ::android::OK;
    }
    virtual void shutdown() = 0;  // This function is only called once.
};

@@ -241,6 +246,7 @@ struct StreamWorkerInterface {
    virtual bool start() = 0;
    virtual pid_t getTid() = 0;
    virtual void stop() = 0;
    virtual std::string getError() = 0;
};

template <class WorkerLogic>
@@ -260,6 +266,7 @@ class StreamWorkerImpl : public StreamWorkerInterface,
    }
    pid_t getTid() override { return WorkerImpl::getTid(); }
    void stop() override { return WorkerImpl::stop(); }
    std::string getError() override { return WorkerImpl::getError(); }
};

class StreamInWorkerLogic : public StreamWorkerCommonLogic {
Loading