audio: Allow going to 'IDLE' for synchronous drain
For small buffers, the driver can perform draining
synhronously, returning control to the HAL only after
the buffer is empty. This makes going through
the 'DRAINING' state artificial. Thus, we allow going
to the 'IDLE' state directly.
In order to make sure that VTS handles both transitions:
to 'DRAINING' and to 'IDLE', correctly, add an "AOSP as
vendor" parameter "aosp.forceSynchronousDrain" to induce
this behavior in the default implementation.
Bug: 262402957
Test: atest VtsHalAudioCoreTargetTest
Change-Id: Ic8eaee53cb4596afb5317b4b905e004af3f112aa
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 780d6a9..13b04cd 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -140,7 +140,8 @@
!isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::MMAP_NOIRQ))) {
StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
- mVendorDebug.forceTransientBurst};
+ mVendorDebug.forceTransientBurst,
+ mVendorDebug.forceSynchronousDrain};
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
@@ -980,6 +981,7 @@
}
const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
+const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
std::vector<VendorParameter>* _aidl_return) {
@@ -990,6 +992,10 @@
VendorParameter forceTransientBurst{.id = id};
forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
_aidl_return->push_back(std::move(forceTransientBurst));
+ } else if (id == VendorDebug::kForceSynchronousDrainName) {
+ VendorParameter forceSynchronousDrain{.id = id};
+ forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
+ _aidl_return->push_back(std::move(forceSynchronousDrain));
} else {
allParametersKnown = false;
LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
@@ -999,6 +1005,23 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+namespace {
+
+template <typename W>
+bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
+ std::optional<W> value;
+ binder_status_t result = p.ext.getParcelable(&value);
+ if (result == STATUS_OK && value.has_value()) {
+ *v = value.value().value;
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
+ << "\": " << result;
+ return false;
+}
+
+} // namespace
+
ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
bool in_async) {
LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
@@ -1006,13 +1029,11 @@
bool allParametersKnown = true;
for (const auto& p : in_parameters) {
if (p.id == VendorDebug::kForceTransientBurstName) {
- std::optional<Boolean> value;
- binder_status_t result = p.ext.getParcelable(&value);
- if (result == STATUS_OK) {
- mVendorDebug.forceTransientBurst = value.value().value;
- } else {
- LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
- << "\"";
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
} else {