From a620ab760b3f1a3d2e3cd28f7a0723f2ee29af04 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 25 Mar 2021 15:00:02 -0700 Subject: [PATCH] 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 --- .../7.0/AudioPrimaryHidlHalTest.cpp | 106 +++++++++++++----- .../vts/functional/AudioPrimaryHidlHalTest.h | 15 ++- 2 files changed, 90 insertions(+), 31 deletions(-) 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 657b42dfe0..0b3098b872 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 @@ class PcmOnlyConfigOutputStreamTest : public OutputStreamTest { // 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 @@ static const std::vector& getInputDevicePcmOnlyConfigPara allParams.begin(), allParams.end(), std::back_inserter(pcmParams), [](auto cfg) { const auto& flags = std::get(cfg); return xsd::isLinearPcm(std::get(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( @@ -690,6 +704,15 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest { 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 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest { EXPECT_OK(stream->setDevices({maybeSourceAddress.value()})); } } + void releasePatchIfNeeded() { if (areAudioPatchesSupported()) { if (mHasPatch) { @@ -724,7 +748,42 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest { EXPECT_OK(stream->setDevices({address})); } } - const std::string& getMixPortName() const { return std::get(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, Read) { 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 ae1467d406..aa7fd8e857 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -1194,7 +1194,17 @@ class InputStreamTest : public OpenStreamTest { #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 @@ class InputStreamTest : public OpenStreamTest { #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(GetParam()); } + SinkMetadata initMetadata = { {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1, .tags = {},