diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv index 56b7926a21..e2da90d5b6 100644 --- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv +++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv @@ -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=""]; // 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) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 51b6085700..e96cf819ab 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -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 dataMQ = nullptr; std::shared_ptr streamAsyncCallback = nullptr; std::shared_ptr 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& in_ids, std::vector* _aidl_return) { @@ -1538,6 +1539,10 @@ ndk::ScopedAStatus Module::getVendorParameters(const std::vector& 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(p, &mVendorDebug.forceSynchronousDrain)) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + } else if (p.id == VendorDebug::kForceDrainToDrainingName) { + if (!extractParameter(p, &mVendorDebug.forceDrainToDraining)) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } } else { allParametersKnown = false; LOG(VERBOSE) << __func__ << ": " << mType << ": unrecognized parameter \"" << p.id diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 3d7f30c268..4525f6a20a 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -382,8 +382,20 @@ bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply const std::string StreamOutWorkerLogic::kThreadName = "writer"; StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { - if (mState == StreamDescriptor::State::DRAINING || - mState == StreamDescriptor::State::TRANSFERRING) { + if (mState == StreamDescriptor::State::DRAINING && mContext->getForceDrainToDraining() && + mOnDrainReadyStatus == OnDrainReadyStatus::UNSENT) { + std::shared_ptr 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::steady_clock::now() - mTransientStateStart); stateDurationMs >= mTransientStateDelayMs) { @@ -396,9 +408,12 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() { // drain or transfer completion. In the stub, we switch unconditionally. if (mState == StreamDescriptor::State::DRAINING) { mState = StreamDescriptor::State::IDLE; - ndk::ScopedAStatus status = asyncCallback->onDrainReady(); - if (!status.isOk()) { - LOG(ERROR) << __func__ << ": error from onDrainReady: " << status; + 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; @@ -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; diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 7e32cf2217..d03598ab75 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -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 diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index f7b926961e..8297fc55c7 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -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 mEventCallback; + + enum OnDrainReadyStatus : int32_t { IGNORE /*used for DRAIN_ALL*/, UNSENT, SENT }; + OnDrainReadyStatus mOnDrainReadyStatus = OnDrainReadyStatus::IGNORE; }; using StreamOutWorker = StreamWorkerImpl; diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp index 6bfba65ae6..6bce1078e4 100644 --- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp @@ -117,6 +117,10 @@ using android::hardware::audio::common::testing::detail::TestExecutionTracer; using ndk::enum_range; using ndk::ScopedAStatus; +static constexpr int32_t kAidlVersion1 = 1; +static constexpr int32_t kAidlVersion2 = 2; +static constexpr int32_t kAidlVersion3 = 3; + template std::set extractIds(const std::vector& v) { std::set ids; @@ -452,7 +456,6 @@ class AudioCoreModuleBase { // This is implemented by the 'StreamFixture' utility class. static constexpr int kNegativeTestBufferSizeFrames = 256; static constexpr int kDefaultLargeBufferSizeFrames = 48000; - static constexpr int32_t kAidlVersion3 = 3; void SetUpImpl(const std::string& moduleName, bool setUpDebug = true) { ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName, setUpDebug)); @@ -582,7 +585,7 @@ class AudioCoreModuleBase { std::unique_ptr debug; std::vector initialPorts; std::vector initialRoutes; - int32_t aidlVersion; + int32_t aidlVersion = -1; }; class WithDevicePortConnectedState { @@ -1837,6 +1840,7 @@ TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) { } TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortAudioGain) { + ASSERT_GE(aidlVersion, kAidlVersion1); if (aidlVersion < kAidlVersion3) { GTEST_SKIP() << "Skip for audio HAL version lower than " << kAidlVersion3; } @@ -4021,6 +4025,7 @@ TEST_P(AudioStreamOut, UpdateOffloadMetadata) { enum { NAMED_CMD_NAME, + NAMED_CMD_MIN_INTERFACE_VERSION, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS, @@ -4028,7 +4033,7 @@ enum { }; enum class StreamTypeFilter { ANY, SYNC, ASYNC }; using NamedCommandSequence = - std::tuple, bool /*validatePositionIncrease*/>; enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ }; using StreamIoTestParameters = @@ -4039,6 +4044,12 @@ class AudioStreamIo : public AudioCoreModuleBase, public: void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get(GetParam()))); + ASSERT_GE(aidlVersion, kAidlVersion1); + if (const int minVersion = + std::get(std::get(GetParam())); + aidlVersion < minVersion) { + GTEST_SKIP() << "Skip for audio HAL version lower than " << minVersion; + } ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); } @@ -4048,6 +4059,20 @@ class AudioStreamIo : public AudioCoreModuleBase, if (allPortConfigs.empty()) { GTEST_SKIP() << "No mix ports have attached devices"; } + const auto& commandsAndStates = + std::get(std::get(GetParam())); + const bool validatePositionIncrease = + std::get(std::get(GetParam())); + auto runStreamIoCommands = [&](const AudioPortConfig& portConfig) { + if (!std::get(GetParam())) { + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates, + validatePositionIncrease)); + } else { + ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates, + validatePositionIncrease)); + } + }; + for (const auto& portConfig : allPortConfigs) { auto port = moduleConfig->getPort(portConfig.portId); ASSERT_TRUE(port.has_value()); @@ -4075,16 +4100,18 @@ class AudioStreamIo : public AudioCoreModuleBase, delayTransientStates.flags().streamTransientStateDelayMs = std::get(std::get(GetParam())); ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get())); - const auto& commandsAndStates = - std::get(std::get(GetParam())); - const bool validatePositionIncrease = - std::get(std::get(GetParam())); - if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates, - validatePositionIncrease)); - } else { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates, - validatePositionIncrease)); + ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig)); + if (aidlVersion >= kAidlVersion3 && isNonBlocking && !IOTraits::is_input) { + // Also try running the same sequence with "aosp.forceDrainToDraining" set. + // This will only work with the default implementation. When it works, the stream + // tries always to move to the 'DRAINING' state after an "early notify" drain. + // This helps to check more paths for our test scenarios. + WithModuleParameter forceDrainToDraining("aosp.forceDrainToDraining", + Boolean{true}); + if (forceDrainToDraining.SetUpNoChecks(module.get(), true /*failureExpected*/) + .isOk()) { + ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig)); + } } if (isNonBlocking) { // Also try running the same sequence with "aosp.forceTransientBurst" set. @@ -4094,13 +4121,7 @@ class AudioStreamIo : public AudioCoreModuleBase, WithModuleParameter forceTransientBurst("aosp.forceTransientBurst", Boolean{true}); if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { - if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( - portConfig, commandsAndStates, validatePositionIncrease)); - } else { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( - portConfig, commandsAndStates, validatePositionIncrease)); - } + ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig)); } } else if (!IOTraits::is_input) { // Also try running the same sequence with "aosp.forceSynchronousDrain" set. @@ -4111,13 +4132,7 @@ class AudioStreamIo : public AudioCoreModuleBase, Boolean{true}); if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/) .isOk()) { - if (!std::get(GetParam())) { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1( - portConfig, commandsAndStates, validatePositionIncrease)); - } else { - ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2( - portConfig, commandsAndStates, validatePositionIncrease)); - } + ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig)); } } } @@ -4570,14 +4585,14 @@ std::shared_ptr makeBurstCommands(bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kReadSeq = - std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true), - true /*validatePositionIncrease*/); + std::make_tuple(std::string("Read"), kAidlVersion1, 0, StreamTypeFilter::ANY, + makeBurstCommands(true), true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteSyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true), - true /*validatePositionIncrease*/); + std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::SYNC, + makeBurstCommands(true), true /*validatePositionIncrease*/); static const NamedCommandSequence kWriteAsyncSeq = - std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false), - true /*validatePositionIncrease*/); + std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::ASYNC, + makeBurstCommands(false), true /*validatePositionIncrease*/); std::shared_ptr makeAsyncDrainCommands(bool isInput) { using State = StreamDescriptor::State; @@ -4606,10 +4621,10 @@ std::shared_ptr makeAsyncDrainCommands(bool isInput) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple( - std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, - makeAsyncDrainCommands(false), false /*validatePositionIncrease*/); + std::string("WriteDrain"), kAidlVersion1, kStreamTransientStateTransitionDelayMs, + StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false), false /*validatePositionIncrease*/); static const NamedCommandSequence kDrainInSeq = - std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY, + std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true), false /*validatePositionIncrease*/); std::shared_ptr makeDrainOutCommands(bool isSync) { @@ -4631,12 +4646,28 @@ std::shared_ptr makeDrainOutCommands(bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kDrainOutSyncSeq = - std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true), - false /*validatePositionIncrease*/); + std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::SYNC, + makeDrainOutCommands(true), false /*validatePositionIncrease*/); static const NamedCommandSequence kDrainOutAsyncSeq = - std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC, + std::make_tuple(std::string("Drain"), kAidlVersion3, 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false), false /*validatePositionIncrease*/); +std::shared_ptr makeDrainEarlyOutCommands() { + using State = StreamDescriptor::State; + auto d = std::make_unique(); + StateDag::Node last = d->makeFinalNode(State::IDLE); + StateDag::Node draining = d->makeNode(State::DRAINING, kDrainReadyEvent, last); + draining.children().push_back(d->makeNode(State::DRAINING, kGetStatusCommand, last)); + StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutEarlyCommand, draining); + StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active); + idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active)); + d->makeNode(State::STANDBY, kStartCommand, idle); + return std::make_shared(std::move(d)); +} +static const NamedCommandSequence kDrainEarlyOutAsyncSeq = + std::make_tuple(std::string("DrainEarly"), kAidlVersion3, 0, StreamTypeFilter::ASYNC, + makeDrainEarlyOutCommands(), false /*validatePositionIncrease*/); + std::shared_ptr makeDrainPauseOutCommands(bool isSync) { using State = StreamDescriptor::State; auto d = std::make_unique(); @@ -4656,12 +4687,33 @@ std::shared_ptr makeDrainPauseOutCommands(bool isSync) { d->makeNode(State::STANDBY, kStartCommand, idle); return std::make_shared(std::move(d)); } -static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple( - std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC, - makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/); -static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple( - std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, - makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainPauseOutSyncSeq = + std::make_tuple(std::string("DrainPause"), kAidlVersion1, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC, + makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/); +static const NamedCommandSequence kDrainPauseOutAsyncSeq = + std::make_tuple(std::string("DrainPause"), kAidlVersion1, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/); + +std::shared_ptr makeDrainEarlyPauseOutCommands() { + using State = StreamDescriptor::State; + auto d = std::make_unique(); + StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand), + std::make_pair(State::DRAIN_PAUSED, kStartCommand), + std::make_pair(State::DRAINING, kPauseCommand), + std::make_pair(State::DRAIN_PAUSED, kBurstCommand)}, + State::TRANSFER_PAUSED); + StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutEarlyCommand, draining); + StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active); + idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutEarlyCommand, draining)); + d->makeNode(State::STANDBY, kStartCommand, idle); + return std::make_shared(std::move(d)); +} +static const NamedCommandSequence kDrainEarlyPauseOutAsyncSeq = + std::make_tuple(std::string("DrainEarlyPause"), kAidlVersion3, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeDrainEarlyPauseOutCommands(), false /*validatePositionIncrease*/); // This sequence also verifies that the capture / presentation position is not reset on standby. std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { @@ -4703,14 +4755,15 @@ std::shared_ptr makeStandbyCommands(bool isInput, bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kStandbyInSeq = - std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY, + std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false), false /*validatePositionIncrease*/); static const NamedCommandSequence kStandbyOutSyncSeq = - std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC, + std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true), false /*validatePositionIncrease*/); -static const NamedCommandSequence kStandbyOutAsyncSeq = std::make_tuple( - std::string("Standby"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, - makeStandbyCommands(false, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kStandbyOutAsyncSeq = + std::make_tuple(std::string("Standby"), kAidlVersion1, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeStandbyCommands(false, false), false /*validatePositionIncrease*/); std::shared_ptr makePauseCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -4745,14 +4798,15 @@ std::shared_ptr makePauseCommands(bool isInput, bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kPauseInSeq = - std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY, + std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::ANY, makePauseCommands(true, false), false /*validatePositionIncrease*/); static const NamedCommandSequence kPauseOutSyncSeq = - std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC, + std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::SYNC, makePauseCommands(false, true), false /*validatePositionIncrease*/); -static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple( - std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, - makePauseCommands(false, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kPauseOutAsyncSeq = + std::make_tuple(std::string("Pause"), kAidlVersion1, kStreamTransientStateTransitionDelayMs, + StreamTypeFilter::ASYNC, makePauseCommands(false, false), + false /*validatePositionIncrease*/); std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { using State = StreamDescriptor::State; @@ -4780,14 +4834,15 @@ std::shared_ptr makeFlushCommands(bool isInput, bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kFlushInSeq = - std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY, + std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::ANY, makeFlushCommands(true, false), false /*validatePositionIncrease*/); static const NamedCommandSequence kFlushOutSyncSeq = - std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC, + std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true), false /*validatePositionIncrease*/); -static const NamedCommandSequence kFlushOutAsyncSeq = std::make_tuple( - std::string("Flush"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, - makeFlushCommands(false, false), false /*validatePositionIncrease*/); +static const NamedCommandSequence kFlushOutAsyncSeq = + std::make_tuple(std::string("Flush"), kAidlVersion1, kStreamTransientStateTransitionDelayMs, + StreamTypeFilter::ASYNC, makeFlushCommands(false, false), + false /*validatePositionIncrease*/); std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { using State = StreamDescriptor::State; @@ -4807,13 +4862,13 @@ std::shared_ptr makeDrainPauseFlushOutCommands(bool isSync) { return std::make_shared(std::move(d)); } static const NamedCommandSequence kDrainPauseFlushOutSyncSeq = - std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true), - false /*validatePositionIncrease*/); + std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC, + makeDrainPauseFlushOutCommands(true), false /*validatePositionIncrease*/); static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq = - std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs, - StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false), - false /*validatePositionIncrease*/); + std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1, + kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC, + makeDrainPauseFlushOutCommands(false), false /*validatePositionIncrease*/); // Note, this isn't the "official" enum printer, it is only used to make the test name suffix. std::string PrintStreamFilterToString(StreamTypeFilter filter) { @@ -4851,9 +4906,10 @@ INSTANTIATE_TEST_SUITE_P( AudioStreamIoOutTest, AudioStreamIoOut, testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)), testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq, - kDrainOutSyncSeq, kDrainPauseOutSyncSeq, - kDrainPauseOutAsyncSeq, kStandbyOutSyncSeq, - kStandbyOutAsyncSeq, + kDrainOutSyncSeq, kDrainOutAsyncSeq, + kDrainEarlyOutAsyncSeq, kDrainPauseOutSyncSeq, + kDrainPauseOutAsyncSeq, kDrainEarlyPauseOutAsyncSeq, + kStandbyOutSyncSeq, kStandbyOutAsyncSeq, kPauseOutSyncSeq, // kPauseOutAsyncSeq, kFlushOutSyncSeq, kFlushOutAsyncSeq, kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),