Loading audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading audio/aidl/default/Module.cpp +12 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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 << "\""; Loading Loading @@ -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 Loading audio/aidl/default/Stream.cpp +24 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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; Loading audio/aidl/default/include/core-impl/Module.h +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading audio/aidl/default/include/core-impl/Stream.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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 Loading
audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv +2 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
audio/aidl/default/Module.cpp +12 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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 << "\""; Loading Loading @@ -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 Loading
audio/aidl/default/Stream.cpp +24 −5 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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; Loading
audio/aidl/default/include/core-impl/Module.h +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
audio/aidl/default/include/core-impl/Stream.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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