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

Commit 06191eda authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge "audio: Allow Stream SM to stay in DRAINING state for early notify" into main

parents f5dcb1fe e87a1b96
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ digraph stream_out_async_state_machine {
    PAUSED -> ACTIVE [label="start"];                 // consumer -> active
    PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
    DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
    DRAINING -> DRAINING [label="←IStreamCallback.onDrainReady"];  // allowed for `DRAIN_EARLY_NOTIFY`
    DRAINING -> IDLE [label="<empty buffer>"];        // allowed for `DRAIN_EARLY_NOTIFY`
    DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
    DRAINING -> ACTIVE [label="burst"];               // full write
    DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
+12 −3
Original line number Diff line number Diff line
@@ -207,9 +207,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};
    StreamContext::DebugParameters params{
            mDebug.streamTransientStateDelayMs, mVendorDebug.forceTransientBurst,
            mVendorDebug.forceSynchronousDrain, mVendorDebug.forceDrainToDraining};
    std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
    std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
    std::shared_ptr<ISoundDose> soundDose;
@@ -1524,6 +1524,7 @@ 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) {
@@ -1538,6 +1539,10 @@ 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 << "\"";
@@ -1578,6 +1583,10 @@ 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
+24 −5
Original line number Diff line number Diff line
@@ -382,7 +382,19 @@ bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply
const std::string StreamOutWorkerLogic::kThreadName = "writer";

StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
    if (mState == StreamDescriptor::State::DRAINING ||
    if (mState == StreamDescriptor::State::DRAINING && mContext->getForceDrainToDraining() &&
        mOnDrainReadyStatus == OnDrainReadyStatus::UNSENT) {
        std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
        if (asyncCallback != nullptr) {
            ndk::ScopedAStatus status = asyncCallback->onDrainReady();
            if (!status.isOk()) {
                LOG(ERROR) << __func__ << ": error from onDrainReady: " << 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);
@@ -396,10 +408,13 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                // drain or transfer completion. In the stub, we switch unconditionally.
                if (mState == StreamDescriptor::State::DRAINING) {
                    mState = StreamDescriptor::State::IDLE;
                    if (mOnDrainReadyStatus != OnDrainReadyStatus::SENT) {
                        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();
@@ -537,6 +552,10 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
                            mState = StreamDescriptor::State::IDLE;
                        } else {
                            switchToTransientState(StreamDescriptor::State::DRAINING);
                            mOnDrainReadyStatus =
                                    mode == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY
                                            ? OnDrainReadyStatus::UNSENT
                                            : OnDrainReadyStatus::IGNORE;
                        }
                    } else {
                        LOG(ERROR) << __func__ << ": drain failed: " << status;
+2 −0
Original line number Diff line number Diff line
@@ -148,8 +148,10 @@ class Module : public BnModule {
    struct VendorDebug {
        static const std::string kForceTransientBurstName;
        static const std::string kForceSynchronousDrainName;
        static const std::string kForceDrainToDrainingName;
        bool forceTransientBurst = false;
        bool forceSynchronousDrain = false;
        bool forceDrainToDraining = false;
    };
    // ids of device ports created at runtime via 'connectExternalDevice'.
    // Also stores a list of ids of mix ports with dynamic profiles that were populated from
+8 −0
Original line number Diff line number Diff line
@@ -78,6 +78,10 @@ class StreamContext {
        bool forceTransientBurst = false;
        // Force the "drain" command to be synchronous, going directly to the IDLE state.
        bool forceSynchronousDrain = false;
        // Force the "drain early notify" command to keep the SM in the DRAINING state
        // after sending 'onDrainReady' callback. The SM moves to IDLE after
        // 'transientStateDelayMs'.
        bool forceDrainToDraining = false;
    };

    StreamContext() = default;
@@ -119,6 +123,7 @@ class StreamContext {
    ::aidl::android::media::audio::common::AudioIoFlags getFlags() const { return mFlags; }
    bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
    bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
    bool getForceDrainToDraining() const { return mDebugParameters.forceDrainToDraining; }
    size_t getFrameSize() const;
    int getInternalCommandCookie() const { return mInternalCommandCookie; }
    int32_t getMixPortHandle() const { return mMixPortHandle; }
@@ -301,6 +306,9 @@ class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
    bool write(size_t clientSize, StreamDescriptor::Reply* reply);

    std::shared_ptr<IStreamOutEventCallback> mEventCallback;

    enum OnDrainReadyStatus : int32_t { IGNORE /*used for DRAIN_ALL*/, UNSENT, SENT };
    OnDrainReadyStatus mOnDrainReadyStatus = OnDrainReadyStatus::IGNORE;
};
using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;

Loading