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

Commit 0f715415 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "audio: Implement compressed offload simulation" into main

parents cf479064 efc2b326
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -184,6 +184,12 @@ constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) {
    return result;
}

template <typename E, typename U = std::underlying_type_t<E>,
          typename = std::enable_if_t<is_bit_position_enum<E>::value>>
constexpr bool areAllBitPositionFlagsSet(U mask, std::initializer_list<E> flags) {
    return (mask & makeBitPositionFlagMask<E>(flags)) == makeBitPositionFlagMask<E>(flags);
}

template <typename E, typename U = std::underlying_type_t<E>,
          typename = std::enable_if_t<is_bit_position_enum<E>::value>>
constexpr bool isAnyBitPositionFlagSet(U mask, std::initializer_list<E> flags) {
+2 −0
Original line number Diff line number Diff line
@@ -77,8 +77,10 @@ cc_library {
        "r_submix/ModuleRemoteSubmix.cpp",
        "r_submix/SubmixRoute.cpp",
        "r_submix/StreamRemoteSubmix.cpp",
        "stub/ApeHeader.cpp",
        "stub/DriverStubImpl.cpp",
        "stub/ModuleStub.cpp",
        "stub/StreamOffloadStub.cpp",
        "stub/StreamStub.cpp",
        "usb/ModuleUsb.cpp",
        "usb/StreamUsb.cpp",
+3 −12
Original line number Diff line number Diff line
@@ -211,9 +211,9 @@ ndk::ScopedAStatus Module::createStreamContext(
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    const auto& flags = portConfigIt->flags.value();
    StreamContext::DebugParameters params{
            mDebug.streamTransientStateDelayMs, mVendorDebug.forceTransientBurst,
            mVendorDebug.forceSynchronousDrain, mVendorDebug.forceDrainToDraining};
    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;
@@ -1546,7 +1546,6 @@ ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {

const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
const std::string Module::VendorDebug::kForceDrainToDrainingName = "aosp.forceDrainToDraining";

ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
                                               std::vector<VendorParameter>* _aidl_return) {
@@ -1561,10 +1560,6 @@ ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& i
            VendorParameter forceSynchronousDrain{.id = id};
            forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
            _aidl_return->push_back(std::move(forceSynchronousDrain));
        } else if (id == VendorDebug::kForceDrainToDrainingName) {
            VendorParameter forceDrainToDraining{.id = id};
            forceDrainToDraining.ext.setParcelable(Boolean{mVendorDebug.forceDrainToDraining});
            _aidl_return->push_back(std::move(forceDrainToDraining));
        } else {
            allParametersKnown = false;
            LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << id << "\"";
@@ -1605,10 +1600,6 @@ ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter
            if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            }
        } else if (p.id == VendorDebug::kForceDrainToDrainingName) {
            if (!extractParameter<Boolean>(p, &mVendorDebug.forceDrainToDraining)) {
                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            }
        } else {
            allParametersKnown = false;
            LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << p.id
+27 −2
Original line number Diff line number Diff line
@@ -21,12 +21,16 @@
#include <android-base/logging.h>

#include "core-impl/ModulePrimary.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::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
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::MicrophoneInfo;
@@ -43,6 +47,17 @@ ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr<ITelephony>* _aid
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus ModulePrimary::calculateBufferSizeFrames(
        const ::aidl::android::media::audio::common::AudioFormatDescription& format,
        int32_t latencyMs, int32_t sampleRateHz, int32_t* bufferSizeFrames) {
    if (format.type != ::aidl::android::media::audio::common::AudioFormatType::PCM &&
        StreamOffloadStub::getSupportedEncodings().count(format.encoding)) {
        *bufferSizeFrames = sampleRateHz / 2;  // 1/2 of a second.
        return ndk::ScopedAStatus::ok();
    }
    return Module::calculateBufferSizeFrames(format, latencyMs, sampleRateHz, bufferSizeFrames);
}

ndk::ScopedAStatus ModulePrimary::createInputStream(StreamContext&& context,
                                                    const SinkMetadata& sinkMetadata,
                                                    const std::vector<MicrophoneInfo>& microphones,
@@ -54,8 +69,18 @@ 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(
                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);
    }
}

int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig&) {
+52 −37
Original line number Diff line number Diff line
@@ -142,12 +142,16 @@ std::string StreamWorkerCommonLogic::init() {
                   ", size in bytes: " + std::to_string(mDataBufferSize);
        }
    }
    if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
    if (::android::status_t status = mDriver->init(this /*DriverCallbackInterface*/);
        status != STATUS_OK) {
        return "Failed to initialize the driver: " + std::to_string(status);
    }
    return "";
}

void StreamWorkerCommonLogic::onBufferStateChange(size_t /*bufferFramesLeft*/) {}
void StreamWorkerCommonLogic::onClipStateChange(size_t /*clipFramesLeft*/, bool /*hasNextClip*/) {}

void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
                                            bool isConnected) const {
    static const StreamDescriptor::Position kUnknownPosition = {
@@ -381,48 +385,60 @@ bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply

const std::string StreamOutWorkerLogic::kThreadName = "writer";

StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
    if (mState == StreamDescriptor::State::DRAINING && mContext->getForceDrainToDraining() &&
        mOnDrainReadyStatus == OnDrainReadyStatus::UNSENT) {
void StreamOutWorkerLogic::onBufferStateChange(size_t bufferFramesLeft) {
    const StreamDescriptor::State state = mState;
    LOG(DEBUG) << __func__ << ": state: " << toString(state)
               << ", bufferFramesLeft: " << bufferFramesLeft;
    if (state == StreamDescriptor::State::TRANSFERRING) {
        mState = StreamDescriptor::State::ACTIVE;
        std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
        if (asyncCallback != nullptr) {
            ndk::ScopedAStatus status = asyncCallback->onDrainReady();
            ndk::ScopedAStatus status = asyncCallback->onTransferReady();
            if (!status.isOk()) {
                LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
                LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
            }
            // This sets the timeout for moving into IDLE on next iterations.
            switchToTransientState(StreamDescriptor::State::DRAINING);
            mOnDrainReadyStatus = OnDrainReadyStatus::SENT;
        }
    } else if (mState == StreamDescriptor::State::DRAINING ||
               mState == StreamDescriptor::State::TRANSFERRING) {
        if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
                    std::chrono::steady_clock::now() - mTransientStateStart);
            stateDurationMs >= mTransientStateDelayMs) {
    }
}

void StreamOutWorkerLogic::onClipStateChange(size_t clipFramesLeft, bool hasNextClip) {
    const DrainState drainState = mDrainState;
    std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
            if (asyncCallback == nullptr) {
                // In blocking mode, mState can only be DRAINING.
                mState = StreamDescriptor::State::IDLE;
            } else {
                // In a real implementation, the driver should notify the HAL about
                // drain or transfer completion. In the stub, we switch unconditionally.
                if (mState == StreamDescriptor::State::DRAINING) {
                    mState = StreamDescriptor::State::IDLE;
                    if (mOnDrainReadyStatus != OnDrainReadyStatus::SENT) {
    LOG(DEBUG) << __func__ << ": drainState: " << drainState << "; clipFramesLeft "
               << clipFramesLeft << "; hasNextClip? " << hasNextClip << "; asyncCallback? "
               << (asyncCallback != nullptr);
    if (drainState != DrainState::NONE && clipFramesLeft == 0) {
        mState =
                hasNextClip ? StreamDescriptor::State::TRANSFERRING : StreamDescriptor::State::IDLE;
        mDrainState = DrainState::NONE;
        if (drainState == DrainState::ALL && asyncCallback != nullptr) {
            LOG(DEBUG) << __func__ << ": sending onDrainReady";
            ndk::ScopedAStatus status = asyncCallback->onDrainReady();
            if (!status.isOk()) {
                LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
            }
                        mOnDrainReadyStatus = OnDrainReadyStatus::SENT;
        }
                } else {
                    mState = StreamDescriptor::State::ACTIVE;
                    ndk::ScopedAStatus status = asyncCallback->onTransferReady();
    } else if (drainState == DrainState::EN && clipFramesLeft > 0) {
        // The stream state does not change, it is still draining.
        mDrainState = DrainState::EN_SENT;
        if (asyncCallback != nullptr) {
            LOG(DEBUG) << __func__ << ": sending onDrainReady";
            ndk::ScopedAStatus status = asyncCallback->onDrainReady();
            if (!status.isOk()) {
                        LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
                LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
            }
        }
    }
}

StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
    // Non-blocking mode is handled within 'onClipStateChange'
    if (std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
        mState == StreamDescriptor::State::DRAINING && asyncCallback == nullptr) {
        if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
                    std::chrono::steady_clock::now() - mTransientStateStart);
            stateDurationMs >= mTransientStateDelayMs) {
            mState = StreamDescriptor::State::IDLE;
            if (mTransientStateDelayMs.count() != 0) {
                LOG(DEBUG) << __func__ << ": switched to state " << toString(mState)
                           << " after a timeout";
@@ -552,10 +568,9 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                            mState = StreamDescriptor::State::IDLE;
                        } else {
                            switchToTransientState(StreamDescriptor::State::DRAINING);
                            mOnDrainReadyStatus =
                                    mode == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY
                                            ? OnDrainReadyStatus::UNSENT
                                            : OnDrainReadyStatus::IGNORE;
                            mDrainState = mode == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY
                                                  ? DrainState::EN
                                                  : DrainState::ALL;
                        }
                    } else {
                        LOG(ERROR) << __func__ << ": drain failed: " << status;
Loading