audio: Fix VTS PCM Input tests for certain h/w platforms
Some h/w platforms require more metadata to be provided
for input streams. Otherwise, opening of a stream was
failing internally in the vendor HAL code and capture
position queries were not succeeding.
Bug: 183688436
Test: atest VtsHalAudioV7_0TargetTest
on C1, C2, R3, S4, B5
Change-Id: Icb6d2cdb9150eb65281df2a4bea6dbe1fc6034c2
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 657b42d..0b3098b 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -580,12 +580,19 @@
// Starting / resuming of streams is asynchronous at HAL level.
// Sometimes HAL doesn't have enough information until the audio data actually gets
// consumed by the hardware.
- do {
+ bool timedOut = false;
+ res = Result::INVALID_STATE;
+ for (android::base::Timer elapsed;
+ res != Result::OK && !writer.hasError() &&
+ !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+ usleep(kWriteDurationUs);
ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
ASSERT_RESULT(okOrInvalidState, res);
- } while (res != Result::OK);
+ }
+ ASSERT_FALSE(writer.hasError());
+ ASSERT_FALSE(timedOut);
+
uint64_t frames = framesInitial;
- bool timedOut = false;
for (android::base::Timer elapsed;
frames <= framesInitial && !writer.hasError() &&
!(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
@@ -666,11 +673,18 @@
allParams.begin(), allParams.end(), std::back_inserter(pcmParams), [](auto cfg) {
const auto& flags = std::get<PARAM_FLAGS>(cfg);
return xsd::isLinearPcm(std::get<PARAM_CONFIG>(cfg).base.format)
- // MMAP NOIRQ profiles use different reading protocol.
+ // MMAP NOIRQ profiles use different reading protocol,
+ // reading h/w hotword might require Soundtrigger to be active.
&&
- std::find(flags.begin(), flags.end(),
- toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_MMAP_NOIRQ)) ==
- flags.end() &&
+ std::find_if(
+ flags.begin(), flags.end(),
+ [](const auto& flag) {
+ return flag == toString(
+ xsd::AudioInOutFlag::
+ AUDIO_INPUT_FLAG_MMAP_NOIRQ) ||
+ flag == toString(xsd::AudioInOutFlag::
+ AUDIO_INPUT_FLAG_HW_HOTWORD);
+ }) == flags.end() &&
!getCachedPolicyConfig()
.getAttachedSourceDeviceForMixPort(
std::get<PARAM_DEVICE_NAME>(
@@ -690,6 +704,15 @@
InputStreamTest::TearDown();
}
+ bool canQueryCapturePosition() const {
+ auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
+ getDeviceName(), getMixPortName());
+ // Returning 'true' when no source is found so the test can fail later with a more clear
+ // problem description.
+ return !maybeSourceAddress.has_value() ||
+ !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType);
+ }
+
void createPatchIfNeeded() {
auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
getDeviceName(), getMixPortName());
@@ -714,6 +737,7 @@
EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
}
}
+
void releasePatchIfNeeded() {
if (areAudioPatchesSupported()) {
if (mHasPatch) {
@@ -724,7 +748,42 @@
EXPECT_OK(stream->setDevices({address}));
}
}
- const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }
+
+ void waitForCapturePositionAdvance(StreamReader& reader, uint64_t* firstPosition = nullptr,
+ uint64_t* lastPosition = nullptr) {
+ static constexpr int kReadDurationUs = 50 * 1000;
+ static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
+ uint64_t framesInitial, ts;
+ // Starting / resuming of streams is asynchronous at HAL level.
+ // Sometimes HAL doesn't have enough information until the audio data actually has been
+ // produced by the hardware. Legacy HALs might return NOT_SUPPORTED when they actually
+ // mean INVALID_STATE.
+ bool timedOut = false;
+ res = Result::INVALID_STATE;
+ for (android::base::Timer elapsed;
+ res != Result::OK && !reader.hasError() &&
+ !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+ usleep(kReadDurationUs);
+ ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
+ ASSERT_RESULT(okOrInvalidStateOrNotSupported, res);
+ }
+ ASSERT_FALSE(reader.hasError());
+ ASSERT_FALSE(timedOut);
+
+ uint64_t frames = framesInitial;
+ for (android::base::Timer elapsed;
+ frames <= framesInitial && !reader.hasError() &&
+ !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+ usleep(kReadDurationUs);
+ ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
+ ASSERT_RESULT(Result::OK, res);
+ }
+ EXPECT_FALSE(timedOut);
+ EXPECT_FALSE(reader.hasError());
+ EXPECT_GT(frames, framesInitial);
+ if (firstPosition) *firstPosition = framesInitial;
+ if (lastPosition) *lastPosition = frames;
+ }
private:
AudioPatchHandle mPatchHandle = {};
@@ -740,47 +799,36 @@
TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionAdvancesWithReads) {
doc::test("Check that the capture position advances with reads");
+ if (!canQueryCapturePosition()) {
+ GTEST_SKIP() << "Capture position retrieval is not possible";
+ }
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
StreamReader reader(stream.get(), stream->getBufferSize());
ASSERT_TRUE(reader.start());
EXPECT_TRUE(reader.waitForAtLeastOneCycle());
-
- uint64_t framesInitial, ts;
- ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
- ASSERT_RESULT(Result::OK, res);
-
- EXPECT_TRUE(reader.waitForAtLeastOneCycle());
-
- uint64_t frames;
- ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
- ASSERT_RESULT(Result::OK, res);
- EXPECT_GT(frames, framesInitial);
-
- reader.stop();
- releasePatchIfNeeded();
+ ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader));
}
TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionPreservedOnStandby) {
doc::test("Check that the capture position does not reset on standby");
+ if (!canQueryCapturePosition()) {
+ GTEST_SKIP() << "Capture position retrieval is not possible";
+ }
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
StreamReader reader(stream.get(), stream->getBufferSize());
ASSERT_TRUE(reader.start());
EXPECT_TRUE(reader.waitForAtLeastOneCycle());
- uint64_t framesInitial, ts;
- ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
- ASSERT_RESULT(Result::OK, res);
-
+ uint64_t framesInitial;
+ ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader, nullptr, &framesInitial));
reader.pause();
ASSERT_OK(stream->standby());
reader.resume();
- EXPECT_FALSE(reader.hasError());
uint64_t frames;
- ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
- ASSERT_RESULT(Result::OK, res);
+ ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader, &frames, nullptr));
EXPECT_GT(frames, framesInitial);
reader.stop();
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index ae1467d..aa7fd8e 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1194,7 +1194,17 @@
#if MAJOR_VERSION <= 6
address.device = AudioDevice::IN_DEFAULT;
#elif MAJOR_VERSION >= 7
- address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+ auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
+ getDeviceName(), getMixPortName());
+ if (maybeSourceAddress.has_value() &&
+ !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
+ address = maybeSourceAddress.value();
+ auto& metadata = initMetadata.tracks[0];
+ metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
+ metadata.channelMask = getConfig().base.channelMask;
+ } else {
+ address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+ }
#endif
const AudioConfig& config = getConfig();
auto flags = getInputFlags();
@@ -1212,7 +1222,8 @@
#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
#elif MAJOR_VERSION >= 7
- const SinkMetadata initMetadata = {
+ const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }
+ SinkMetadata initMetadata = {
{{.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
.gain = 1,
.tags = {},