Loading audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h +27 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,15 @@ static inline bool isOutputDevice(const std::string& device) { return isOutputDevice(stringToAudioDevice(device)); } static inline bool isTelephonyDevice(AudioDevice device) { return device == AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX || device == AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX; } static inline bool isTelephonyDevice(const std::string& device) { return isTelephonyDevice(stringToAudioDevice(device)); } static inline bool maybeVendorExtension(const std::string& s) { // Only checks whether the string starts with the "vendor prefix". static const std::string vendorPrefix = "VX_"; Loading Loading @@ -260,6 +269,24 @@ static inline bool isUnknownAudioUsage(const std::string& usage) { return stringToAudioUsage(usage) == AudioUsage::UNKNOWN; } static inline bool isLinearPcm(AudioFormat format) { switch (format) { case AudioFormat::AUDIO_FORMAT_PCM_16_BIT: case AudioFormat::AUDIO_FORMAT_PCM_8_BIT: case AudioFormat::AUDIO_FORMAT_PCM_32_BIT: case AudioFormat::AUDIO_FORMAT_PCM_8_24_BIT: case AudioFormat::AUDIO_FORMAT_PCM_FLOAT: case AudioFormat::AUDIO_FORMAT_PCM_24_BIT_PACKED: return true; default: return false; } } static inline bool isLinearPcm(const std::string& format) { return isLinearPcm(stringToAudioFormat(format)); } } // namespace android::audio::policy::configuration::V7_0 #endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0__ENUMS_H audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +7 −37 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { .tags = {}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}}; #endif EventFlag* efGroup; for (auto microphone : microphones) { #if MAJOR_VERSION <= 6 if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) { Loading @@ -96,44 +95,15 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { config, flags, initMetadata, cb); }, config, &res, &suggestedConfig)); StreamReader reader(stream.get(), stream->getBufferSize()); ASSERT_TRUE(reader.start()); reader.pause(); // This ensures that at least one read has happened. EXPECT_FALSE(reader.hasError()); hidl_vec<MicrophoneInfo> activeMicrophones; Result readRes; typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ; typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; std::unique_ptr<CommandMQ> commandMQ; std::unique_ptr<DataMQ> dataMQ; size_t frameSize = stream->getFrameSize(); size_t frameCount = stream->getBufferSize() / frameSize; ASSERT_OK(stream->prepareForReading( frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto) { readRes = r; if (readRes == Result::OK) { commandMQ.reset(new CommandMQ(c)); dataMQ.reset(new DataMQ(d)); if (dataMQ->isValid() && dataMQ->getEventFlagWord()) { EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup); } } })); ASSERT_OK(readRes); IStreamIn::ReadParameters params; params.command = IStreamIn::ReadCommand::READ; ASSERT_TRUE(commandMQ != nullptr); ASSERT_TRUE(commandMQ->isValid()); ASSERT_TRUE(commandMQ->write(¶ms)); efGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); uint32_t efState = 0; efGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { ASSERT_OK(stream->getActiveMicrophones(returnIn(res, activeMicrophones))); ASSERT_OK(res); ASSERT_NE(0U, activeMicrophones.size()); } helper.close(true /*clear*/, &res); ASSERT_OK(res); if (efGroup) { EventFlag::deleteEventFlag(&efGroup); } EXPECT_NE(0U, activeMicrophones.size()); } } } Loading audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +304 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <android-base/chrono_utils.h> #include "Generators.h" // pull in all the <= 6.0 tests Loading Loading @@ -487,3 +489,305 @@ TEST_P(SingleConfigInputStreamTest, UpdateInvalidSinkMetadata) { << ::testing::PrintToString(metadata); } } static const std::vector<DeviceConfigParameter>& getOutputDevicePcmOnlyConfigParameters() { static const std::vector<DeviceConfigParameter> parameters = [] { auto allParams = getOutputDeviceConfigParameters(); std::vector<DeviceConfigParameter> pcmParams; std::copy_if(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 and HW A/V Sync profiles use special writing protocols. && std::find_if(flags.begin(), flags.end(), [](const auto& flag) { return flag == toString(xsd::AudioInOutFlag:: AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) || flag == toString(xsd::AudioInOutFlag:: AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }) == flags.end() && !getCachedPolicyConfig() .getAttachedSinkDeviceForMixPort( std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(cfg)), std::get<PARAM_PORT_NAME>(cfg)) .empty(); }); return pcmParams; }(); return parameters; } class PcmOnlyConfigOutputStreamTest : public OutputStreamTest { public: void TearDown() override { releasePatchIfNeeded(); OutputStreamTest::TearDown(); } bool canQueryPresentationPosition() const { auto maybeSinkAddress = getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName()); // Returning 'true' when no sink is found so the test can fail later with a more clear // problem description. return !maybeSinkAddress.has_value() || !xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType); } void createPatchIfNeeded() { auto maybeSinkAddress = getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName()); ASSERT_TRUE(maybeSinkAddress.has_value()) << "No sink device found for mix port " << getMixPortName() << " (module " << getDeviceName() << ")"; if (areAudioPatchesSupported()) { AudioPortConfig source; source.base.format.value(getConfig().base.format); source.base.sampleRateHz.value(getConfig().base.sampleRateHz); source.base.channelMask.value(getConfig().base.channelMask); source.ext.mix({}); source.ext.mix().ioHandle = helper.getIoHandle(); source.ext.mix().useCase.stream({}); AudioPortConfig sink; sink.ext.device(maybeSinkAddress.value()); EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source}, hidl_vec<AudioPortConfig>{sink}, returnIn(res, mPatchHandle))); mHasPatch = res == Result::OK; } else { EXPECT_OK(stream->setDevices({maybeSinkAddress.value()})); } } void releasePatchIfNeeded() { if (areAudioPatchesSupported()) { if (mHasPatch) { EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle)); mHasPatch = false; } } else { EXPECT_OK(stream->setDevices({address})); } } const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); } void waitForPresentationPositionAdvance(StreamWriter& writer, uint64_t* firstPosition = nullptr, uint64_t* lastPosition = nullptr) { static constexpr int kWriteDurationUs = 50 * 1000; static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000}; uint64_t framesInitial; TimeSpec ts; // 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 { ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts))); ASSERT_RESULT(okOrInvalidState, res); } while (res != Result::OK); uint64_t frames = framesInitial; bool timedOut = false; for (android::base::Timer elapsed; frames <= framesInitial && !writer.hasError() && !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) { usleep(kWriteDurationUs); ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, ts))); ASSERT_RESULT(Result::OK, res); } EXPECT_FALSE(timedOut); EXPECT_FALSE(writer.hasError()); EXPECT_GT(frames, framesInitial); if (firstPosition) *firstPosition = framesInitial; if (lastPosition) *lastPosition = frames; } private: AudioPatchHandle mPatchHandle = {}; bool mHasPatch = false; }; TEST_P(PcmOnlyConfigOutputStreamTest, Write) { doc::test("Check that output streams opened for PCM output accepts audio data"); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); EXPECT_TRUE(writer.waitForAtLeastOneCycle()); } TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionAdvancesWithWrites) { doc::test("Check that the presentation position advances with writes"); if (!canQueryPresentationPosition()) { GTEST_SKIP() << "Presentation position retrieval is not possible"; } ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded()); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); ASSERT_TRUE(writer.waitForAtLeastOneCycle()); ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer)); writer.stop(); releasePatchIfNeeded(); } TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionPreservedOnStandby) { doc::test("Check that the presentation position does not reset on standby"); if (!canQueryPresentationPosition()) { GTEST_SKIP() << "Presentation position retrieval is not possible"; } ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded()); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); ASSERT_TRUE(writer.waitForAtLeastOneCycle()); uint64_t framesInitial; ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, nullptr, &framesInitial)); writer.pause(); ASSERT_OK(stream->standby()); writer.resume(); uint64_t frames; ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames)); EXPECT_GT(frames, framesInitial); writer.stop(); releasePatchIfNeeded(); } INSTANTIATE_TEST_CASE_P(PcmOnlyConfigOutputStream, PcmOnlyConfigOutputStreamTest, ::testing::ValuesIn(getOutputDevicePcmOnlyConfigParameters()), &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigOutputStreamTest); static const std::vector<DeviceConfigParameter>& getInputDevicePcmOnlyConfigParameters() { static const std::vector<DeviceConfigParameter> parameters = [] { auto allParams = getInputDeviceConfigParameters(); std::vector<DeviceConfigParameter> pcmParams; std::copy_if( 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. && std::find(flags.begin(), flags.end(), toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_MMAP_NOIRQ)) == flags.end() && !getCachedPolicyConfig() .getAttachedSourceDeviceForMixPort( std::get<PARAM_DEVICE_NAME>( std::get<PARAM_DEVICE>(cfg)), std::get<PARAM_PORT_NAME>(cfg)) .empty(); }); return pcmParams; }(); return parameters; } class PcmOnlyConfigInputStreamTest : public InputStreamTest { public: void TearDown() override { releasePatchIfNeeded(); InputStreamTest::TearDown(); } void createPatchIfNeeded() { auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort( getDeviceName(), getMixPortName()); ASSERT_TRUE(maybeSourceAddress.has_value()) << "No source device found for mix port " << getMixPortName() << " (module " << getDeviceName() << ")"; if (areAudioPatchesSupported()) { AudioPortConfig source; source.ext.device(maybeSourceAddress.value()); AudioPortConfig sink; sink.base.format.value(getConfig().base.format); sink.base.sampleRateHz.value(getConfig().base.sampleRateHz); sink.base.channelMask.value(getConfig().base.channelMask); sink.ext.mix({}); sink.ext.mix().ioHandle = helper.getIoHandle(); sink.ext.mix().useCase.source(toString(xsd::AudioSource::AUDIO_SOURCE_MIC)); EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source}, hidl_vec<AudioPortConfig>{sink}, returnIn(res, mPatchHandle))); mHasPatch = res == Result::OK; } else { EXPECT_OK(stream->setDevices({maybeSourceAddress.value()})); } } void releasePatchIfNeeded() { if (areAudioPatchesSupported()) { if (mHasPatch) { EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle)); mHasPatch = false; } } else { EXPECT_OK(stream->setDevices({address})); } } const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); } private: AudioPatchHandle mPatchHandle = {}; bool mHasPatch = false; }; TEST_P(PcmOnlyConfigInputStreamTest, Read) { doc::test("Check that input streams opened for PCM input retrieve audio data"); StreamReader reader(stream.get(), stream->getBufferSize()); ASSERT_TRUE(reader.start()); EXPECT_TRUE(reader.waitForAtLeastOneCycle()); } TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionAdvancesWithReads) { doc::test("Check that the capture position advances with reads"); 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(); } TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionPreservedOnStandby) { doc::test("Check that the capture position does not reset on standby"); 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); 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); EXPECT_GT(frames, framesInitial); reader.stop(); releasePatchIfNeeded(); } INSTANTIATE_TEST_CASE_P(PcmOnlyConfigInputStream, PcmOnlyConfigInputStreamTest, ::testing::ValuesIn(getInputDevicePcmOnlyConfigParameters()), &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigInputStreamTest); audio/core/all-versions/vts/functional/7.0/Generators.cpp +12 −12 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool one if (isOffload) { config.offloadInfo.info(generateOffloadInfo(config.base)); } result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); if (oneProfilePerDevice) break; } if (oneProfilePerDevice) break; Loading Loading @@ -160,7 +160,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters if (isOffload) { config.offloadInfo.info(generateOffloadInfo(validBase)); } result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; Loading @@ -168,7 +168,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters if (isOffload) { config.offloadInfo.info(generateOffloadInfo(validBase)); } result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } if (generateInvalidFlags) { AudioConfig config{.base = validBase}; Loading @@ -176,32 +176,32 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters config.offloadInfo.info(generateOffloadInfo(validBase)); } std::vector<AudioInOutFlag> flags = {"random_string", ""}; result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); } if (isOffload) { { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().base.channelMask = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().base.format = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().streamType = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().usage = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } hasOffloadConfig = true; } else { Loading Loading @@ -234,7 +234,7 @@ std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneP auto configs = combineAudioConfig(profile.getChannelMasks(), profile.getSamplingRates(), profile.getFormat()); for (const auto& config : configs) { result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); if (oneProfilePerDevice) break; } if (oneProfilePerDevice) break; Loading Loading @@ -285,17 +285,17 @@ const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters( { AudioConfig config{.base = validBase}; config.base.channelMask = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.base.format = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } if (generateInvalidFlags) { AudioConfig config{.base = validBase}; std::vector<AudioInOutFlag> flags = {"random_string", ""}; result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); } hasConfig = true; break; Loading audio/core/all-versions/vts/functional/7.0/PolicyConfig.cpp 0 → 100644 +215 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h +27 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,15 @@ static inline bool isOutputDevice(const std::string& device) { return isOutputDevice(stringToAudioDevice(device)); } static inline bool isTelephonyDevice(AudioDevice device) { return device == AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX || device == AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX; } static inline bool isTelephonyDevice(const std::string& device) { return isTelephonyDevice(stringToAudioDevice(device)); } static inline bool maybeVendorExtension(const std::string& s) { // Only checks whether the string starts with the "vendor prefix". static const std::string vendorPrefix = "VX_"; Loading Loading @@ -260,6 +269,24 @@ static inline bool isUnknownAudioUsage(const std::string& usage) { return stringToAudioUsage(usage) == AudioUsage::UNKNOWN; } static inline bool isLinearPcm(AudioFormat format) { switch (format) { case AudioFormat::AUDIO_FORMAT_PCM_16_BIT: case AudioFormat::AUDIO_FORMAT_PCM_8_BIT: case AudioFormat::AUDIO_FORMAT_PCM_32_BIT: case AudioFormat::AUDIO_FORMAT_PCM_8_24_BIT: case AudioFormat::AUDIO_FORMAT_PCM_FLOAT: case AudioFormat::AUDIO_FORMAT_PCM_24_BIT_PACKED: return true; default: return false; } } static inline bool isLinearPcm(const std::string& format) { return isLinearPcm(stringToAudioFormat(format)); } } // namespace android::audio::policy::configuration::V7_0 #endif // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0__ENUMS_H
audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp +7 −37 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { .tags = {}, .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}}; #endif EventFlag* efGroup; for (auto microphone : microphones) { #if MAJOR_VERSION <= 6 if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) { Loading @@ -96,44 +95,15 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) { config, flags, initMetadata, cb); }, config, &res, &suggestedConfig)); StreamReader reader(stream.get(), stream->getBufferSize()); ASSERT_TRUE(reader.start()); reader.pause(); // This ensures that at least one read has happened. EXPECT_FALSE(reader.hasError()); hidl_vec<MicrophoneInfo> activeMicrophones; Result readRes; typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ; typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; std::unique_ptr<CommandMQ> commandMQ; std::unique_ptr<DataMQ> dataMQ; size_t frameSize = stream->getFrameSize(); size_t frameCount = stream->getBufferSize() / frameSize; ASSERT_OK(stream->prepareForReading( frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto) { readRes = r; if (readRes == Result::OK) { commandMQ.reset(new CommandMQ(c)); dataMQ.reset(new DataMQ(d)); if (dataMQ->isValid() && dataMQ->getEventFlagWord()) { EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup); } } })); ASSERT_OK(readRes); IStreamIn::ReadParameters params; params.command = IStreamIn::ReadCommand::READ; ASSERT_TRUE(commandMQ != nullptr); ASSERT_TRUE(commandMQ->isValid()); ASSERT_TRUE(commandMQ->write(¶ms)); efGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); uint32_t efState = 0; efGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { ASSERT_OK(stream->getActiveMicrophones(returnIn(res, activeMicrophones))); ASSERT_OK(res); ASSERT_NE(0U, activeMicrophones.size()); } helper.close(true /*clear*/, &res); ASSERT_OK(res); if (efGroup) { EventFlag::deleteEventFlag(&efGroup); } EXPECT_NE(0U, activeMicrophones.size()); } } } Loading
audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +304 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <android-base/chrono_utils.h> #include "Generators.h" // pull in all the <= 6.0 tests Loading Loading @@ -487,3 +489,305 @@ TEST_P(SingleConfigInputStreamTest, UpdateInvalidSinkMetadata) { << ::testing::PrintToString(metadata); } } static const std::vector<DeviceConfigParameter>& getOutputDevicePcmOnlyConfigParameters() { static const std::vector<DeviceConfigParameter> parameters = [] { auto allParams = getOutputDeviceConfigParameters(); std::vector<DeviceConfigParameter> pcmParams; std::copy_if(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 and HW A/V Sync profiles use special writing protocols. && std::find_if(flags.begin(), flags.end(), [](const auto& flag) { return flag == toString(xsd::AudioInOutFlag:: AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) || flag == toString(xsd::AudioInOutFlag:: AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }) == flags.end() && !getCachedPolicyConfig() .getAttachedSinkDeviceForMixPort( std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(cfg)), std::get<PARAM_PORT_NAME>(cfg)) .empty(); }); return pcmParams; }(); return parameters; } class PcmOnlyConfigOutputStreamTest : public OutputStreamTest { public: void TearDown() override { releasePatchIfNeeded(); OutputStreamTest::TearDown(); } bool canQueryPresentationPosition() const { auto maybeSinkAddress = getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName()); // Returning 'true' when no sink is found so the test can fail later with a more clear // problem description. return !maybeSinkAddress.has_value() || !xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType); } void createPatchIfNeeded() { auto maybeSinkAddress = getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName()); ASSERT_TRUE(maybeSinkAddress.has_value()) << "No sink device found for mix port " << getMixPortName() << " (module " << getDeviceName() << ")"; if (areAudioPatchesSupported()) { AudioPortConfig source; source.base.format.value(getConfig().base.format); source.base.sampleRateHz.value(getConfig().base.sampleRateHz); source.base.channelMask.value(getConfig().base.channelMask); source.ext.mix({}); source.ext.mix().ioHandle = helper.getIoHandle(); source.ext.mix().useCase.stream({}); AudioPortConfig sink; sink.ext.device(maybeSinkAddress.value()); EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source}, hidl_vec<AudioPortConfig>{sink}, returnIn(res, mPatchHandle))); mHasPatch = res == Result::OK; } else { EXPECT_OK(stream->setDevices({maybeSinkAddress.value()})); } } void releasePatchIfNeeded() { if (areAudioPatchesSupported()) { if (mHasPatch) { EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle)); mHasPatch = false; } } else { EXPECT_OK(stream->setDevices({address})); } } const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); } void waitForPresentationPositionAdvance(StreamWriter& writer, uint64_t* firstPosition = nullptr, uint64_t* lastPosition = nullptr) { static constexpr int kWriteDurationUs = 50 * 1000; static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000}; uint64_t framesInitial; TimeSpec ts; // 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 { ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts))); ASSERT_RESULT(okOrInvalidState, res); } while (res != Result::OK); uint64_t frames = framesInitial; bool timedOut = false; for (android::base::Timer elapsed; frames <= framesInitial && !writer.hasError() && !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) { usleep(kWriteDurationUs); ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, ts))); ASSERT_RESULT(Result::OK, res); } EXPECT_FALSE(timedOut); EXPECT_FALSE(writer.hasError()); EXPECT_GT(frames, framesInitial); if (firstPosition) *firstPosition = framesInitial; if (lastPosition) *lastPosition = frames; } private: AudioPatchHandle mPatchHandle = {}; bool mHasPatch = false; }; TEST_P(PcmOnlyConfigOutputStreamTest, Write) { doc::test("Check that output streams opened for PCM output accepts audio data"); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); EXPECT_TRUE(writer.waitForAtLeastOneCycle()); } TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionAdvancesWithWrites) { doc::test("Check that the presentation position advances with writes"); if (!canQueryPresentationPosition()) { GTEST_SKIP() << "Presentation position retrieval is not possible"; } ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded()); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); ASSERT_TRUE(writer.waitForAtLeastOneCycle()); ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer)); writer.stop(); releasePatchIfNeeded(); } TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionPreservedOnStandby) { doc::test("Check that the presentation position does not reset on standby"); if (!canQueryPresentationPosition()) { GTEST_SKIP() << "Presentation position retrieval is not possible"; } ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded()); StreamWriter writer(stream.get(), stream->getBufferSize()); ASSERT_TRUE(writer.start()); ASSERT_TRUE(writer.waitForAtLeastOneCycle()); uint64_t framesInitial; ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, nullptr, &framesInitial)); writer.pause(); ASSERT_OK(stream->standby()); writer.resume(); uint64_t frames; ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames)); EXPECT_GT(frames, framesInitial); writer.stop(); releasePatchIfNeeded(); } INSTANTIATE_TEST_CASE_P(PcmOnlyConfigOutputStream, PcmOnlyConfigOutputStreamTest, ::testing::ValuesIn(getOutputDevicePcmOnlyConfigParameters()), &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigOutputStreamTest); static const std::vector<DeviceConfigParameter>& getInputDevicePcmOnlyConfigParameters() { static const std::vector<DeviceConfigParameter> parameters = [] { auto allParams = getInputDeviceConfigParameters(); std::vector<DeviceConfigParameter> pcmParams; std::copy_if( 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. && std::find(flags.begin(), flags.end(), toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_MMAP_NOIRQ)) == flags.end() && !getCachedPolicyConfig() .getAttachedSourceDeviceForMixPort( std::get<PARAM_DEVICE_NAME>( std::get<PARAM_DEVICE>(cfg)), std::get<PARAM_PORT_NAME>(cfg)) .empty(); }); return pcmParams; }(); return parameters; } class PcmOnlyConfigInputStreamTest : public InputStreamTest { public: void TearDown() override { releasePatchIfNeeded(); InputStreamTest::TearDown(); } void createPatchIfNeeded() { auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort( getDeviceName(), getMixPortName()); ASSERT_TRUE(maybeSourceAddress.has_value()) << "No source device found for mix port " << getMixPortName() << " (module " << getDeviceName() << ")"; if (areAudioPatchesSupported()) { AudioPortConfig source; source.ext.device(maybeSourceAddress.value()); AudioPortConfig sink; sink.base.format.value(getConfig().base.format); sink.base.sampleRateHz.value(getConfig().base.sampleRateHz); sink.base.channelMask.value(getConfig().base.channelMask); sink.ext.mix({}); sink.ext.mix().ioHandle = helper.getIoHandle(); sink.ext.mix().useCase.source(toString(xsd::AudioSource::AUDIO_SOURCE_MIC)); EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source}, hidl_vec<AudioPortConfig>{sink}, returnIn(res, mPatchHandle))); mHasPatch = res == Result::OK; } else { EXPECT_OK(stream->setDevices({maybeSourceAddress.value()})); } } void releasePatchIfNeeded() { if (areAudioPatchesSupported()) { if (mHasPatch) { EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle)); mHasPatch = false; } } else { EXPECT_OK(stream->setDevices({address})); } } const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); } private: AudioPatchHandle mPatchHandle = {}; bool mHasPatch = false; }; TEST_P(PcmOnlyConfigInputStreamTest, Read) { doc::test("Check that input streams opened for PCM input retrieve audio data"); StreamReader reader(stream.get(), stream->getBufferSize()); ASSERT_TRUE(reader.start()); EXPECT_TRUE(reader.waitForAtLeastOneCycle()); } TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionAdvancesWithReads) { doc::test("Check that the capture position advances with reads"); 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(); } TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionPreservedOnStandby) { doc::test("Check that the capture position does not reset on standby"); 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); 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); EXPECT_GT(frames, framesInitial); reader.stop(); releasePatchIfNeeded(); } INSTANTIATE_TEST_CASE_P(PcmOnlyConfigInputStream, PcmOnlyConfigInputStreamTest, ::testing::ValuesIn(getInputDevicePcmOnlyConfigParameters()), &DeviceConfigParameterToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigInputStreamTest);
audio/core/all-versions/vts/functional/7.0/Generators.cpp +12 −12 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool one if (isOffload) { config.offloadInfo.info(generateOffloadInfo(config.base)); } result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); if (oneProfilePerDevice) break; } if (oneProfilePerDevice) break; Loading Loading @@ -160,7 +160,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters if (isOffload) { config.offloadInfo.info(generateOffloadInfo(validBase)); } result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; Loading @@ -168,7 +168,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters if (isOffload) { config.offloadInfo.info(generateOffloadInfo(validBase)); } result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } if (generateInvalidFlags) { AudioConfig config{.base = validBase}; Loading @@ -176,32 +176,32 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters config.offloadInfo.info(generateOffloadInfo(validBase)); } std::vector<AudioInOutFlag> flags = {"random_string", ""}; result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); } if (isOffload) { { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().base.channelMask = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().base.format = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().streamType = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.offloadInfo.info(generateOffloadInfo(validBase)); config.offloadInfo.info().usage = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } hasOffloadConfig = true; } else { Loading Loading @@ -234,7 +234,7 @@ std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneP auto configs = combineAudioConfig(profile.getChannelMasks(), profile.getSamplingRates(), profile.getFormat()); for (const auto& config : configs) { result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); if (oneProfilePerDevice) break; } if (oneProfilePerDevice) break; Loading Loading @@ -285,17 +285,17 @@ const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters( { AudioConfig config{.base = validBase}; config.base.channelMask = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } { AudioConfig config{.base = validBase}; config.base.format = "random_string"; result.emplace_back(device, config, validFlags); result.emplace_back(device, mixPort.getName(), config, validFlags); } if (generateInvalidFlags) { AudioConfig config{.base = validBase}; std::vector<AudioInOutFlag> flags = {"random_string", ""}; result.emplace_back(device, config, flags); result.emplace_back(device, mixPort.getName(), config, flags); } hasConfig = true; break; Loading
audio/core/all-versions/vts/functional/7.0/PolicyConfig.cpp 0 → 100644 +215 −0 File added.Preview size limit exceeded, changes collapsed. Show changes