From f84d6401865ec08fb2cfc823186bb812f1c0fd94 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Thu, 16 Jun 2022 00:35:31 +0000 Subject: [PATCH 1/3] audio: Disable the C++ backend for android.hardware.audio.core android.hardware.audio.core will need to use FMQ, which does not support the C++ backend in the AIDL version. Migrate VTS tests from the C++ backend to the NDK backend. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest Merged-In: Ia5d29126afdb4bb97dd063a032b96ab83b9ce36e Change-Id: Ia5d29126afdb4bb97dd063a032b96ab83b9ce36e (cherry picked from commit 8fcc442416d30980aa4946b6d736c2f96a4e1bc0) --- audio/aidl/Android.bp | 4 + audio/aidl/vts/Android.bp | 8 +- audio/aidl/vts/ModuleConfig.cpp | 26 +- audio/aidl/vts/ModuleConfig.h | 95 ++--- audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp | 401 ++++++++++--------- 5 files changed, 284 insertions(+), 250 deletions(-) diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp index 052411005b..7db50d5ca5 100644 --- a/audio/aidl/Android.bp +++ b/audio/aidl/Android.bp @@ -83,6 +83,10 @@ aidl_interface { ], stability: "vintf", backend: { + // The C++ backend is disabled transitively due to use of FMQ. + cpp: { + enabled: false, + }, java: { platform_apis: true, }, diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index c160d1f5cc..cd5915bbe2 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -18,12 +18,12 @@ cc_test { "VtsHalAudioCoreTargetTest.cpp", ], shared_libs: [ - "libbinder", + "libbinder_ndk", ], static_libs: [ - "android.hardware.audio.common-V1-cpp", - "android.hardware.audio.core-V1-cpp", - "android.media.audio.common.types-V1-cpp", + "android.hardware.audio.common-V1-ndk", + "android.hardware.audio.core-V1-ndk", + "android.media.audio.common.types-V1-ndk", ], test_suites: [ "general-tests", diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index 3f8d0888aa..36b3b1b412 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -16,24 +16,24 @@ #include -#include -#include +#include +#include #include "ModuleConfig.h" using namespace android; -using android::hardware::audio::core::IModule; -using android::media::audio::common::AudioChannelLayout; -using android::media::audio::common::AudioFormatDescription; -using android::media::audio::common::AudioFormatType; -using android::media::audio::common::AudioIoFlags; -using android::media::audio::common::AudioOutputFlags; -using android::media::audio::common::AudioPort; -using android::media::audio::common::AudioPortConfig; -using android::media::audio::common::AudioPortExt; -using android::media::audio::common::AudioProfile; -using android::media::audio::common::Int; +using aidl::android::hardware::audio::core::IModule; +using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioFormatDescription; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioIoFlags; +using aidl::android::media::audio::common::AudioOutputFlags; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortConfig; +using aidl::android::media::audio::common::AudioPortExt; +using aidl::android::media::audio::common::AudioProfile; +using aidl::android::media::audio::common::Int; template auto findById(const std::vector& v, int32_t id) { diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h index 0e2738b306..504c0fdf96 100644 --- a/audio/aidl/vts/ModuleConfig.h +++ b/audio/aidl/vts/ModuleConfig.h @@ -21,67 +21,69 @@ #include #include -#include -#include -#include -#include +#include +#include +#include class ModuleConfig { public: - using SrcSinkPair = std::pair; + using SrcSinkPair = std::pair; using SrcSinkGroup = - std::pair>; + std::pair>; - explicit ModuleConfig(android::hardware::audio::core::IModule* module); - android::binder::Status getStatus() const { return mStatus; } - std::string getError() const { return mStatus.toString8().c_str(); } + explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module); + const ndk::ScopedAStatus& getStatus() const { return mStatus; } + std::string getError() const { return mStatus.getMessage(); } - std::vector getAttachedDevicePorts() const; - std::vector getExternalDevicePorts() const; - std::vector getInputMixPorts() const; - std::vector getOutputMixPorts() const; - std::vector getMixPorts(bool isInput) const { + std::vector getAttachedDevicePorts() const; + std::vector getExternalDevicePorts() const; + std::vector getInputMixPorts() const; + std::vector getOutputMixPorts() const; + std::vector getMixPorts(bool isInput) const { return isInput ? getInputMixPorts() : getOutputMixPorts(); } - std::vector getAttachedDevicesPortsForMixPort( - bool isInput, const android::media::audio::common::AudioPort& mixPort) const { + std::vector getAttachedDevicesPortsForMixPort( + bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const { return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort) : getAttachedSinkDevicesPortsForMixPort(mixPort); } - std::vector getAttachedSinkDevicesPortsForMixPort( - const android::media::audio::common::AudioPort& mixPort) const; - std::vector getAttachedSourceDevicesPortsForMixPort( - const android::media::audio::common::AudioPort& mixPort) const; - std::optional getSourceMixPortForAttachedDevice() - const; + std::vector + getAttachedSinkDevicesPortsForMixPort( + const aidl::android::media::audio::common::AudioPort& mixPort) const; + std::vector + getAttachedSourceDevicesPortsForMixPort( + const aidl::android::media::audio::common::AudioPort& mixPort) const; + std::optional + getSourceMixPortForAttachedDevice() const; std::optional getNonRoutableSrcSinkPair(bool isInput) const; std::optional getRoutableSrcSinkPair(bool isInput) const; std::vector getRoutableSrcSinkGroups(bool isInput) const; - std::vector + std::vector getPortConfigsForAttachedDevicePorts() const { return generateAudioDevicePortConfigs(getAttachedDevicePorts(), false); } - std::vector getPortConfigsForMixPorts() const { + std::vector getPortConfigsForMixPorts() + const { auto inputs = generateInputAudioMixPortConfigs(getInputMixPorts(), false); auto outputs = generateOutputAudioMixPortConfigs(getOutputMixPorts(), false); inputs.insert(inputs.end(), outputs.begin(), outputs.end()); return inputs; } - std::vector getPortConfigsForMixPorts( + std::vector getPortConfigsForMixPorts( bool isInput) const { return isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), false) : generateOutputAudioMixPortConfigs(getOutputMixPorts(), false); } - std::vector getPortConfigsForMixPorts( - bool isInput, const android::media::audio::common::AudioPort& port) const { + std::vector getPortConfigsForMixPorts( + bool isInput, const aidl::android::media::audio::common::AudioPort& port) const { return isInput ? generateInputAudioMixPortConfigs({port}, false) : generateOutputAudioMixPortConfigs({port}, false); } - std::optional getSingleConfigForMixPort( + std::optional getSingleConfigForMixPort( bool isInput) const { const auto config = isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), true) : generateOutputAudioMixPortConfigs(getOutputMixPorts(), true); @@ -93,8 +95,8 @@ class ModuleConfig { return {}; } } - std::optional getSingleConfigForMixPort( - bool isInput, const android::media::audio::common::AudioPort& port) const { + std::optional getSingleConfigForMixPort( + bool isInput, const aidl::android::media::audio::common::AudioPort& port) const { const auto config = isInput ? generateInputAudioMixPortConfigs({port}, true) : generateOutputAudioMixPortConfigs({port}, true); if (!config.empty()) { @@ -104,12 +106,12 @@ class ModuleConfig { } } - std::vector getPortConfigsForDevicePort( - const android::media::audio::common::AudioPort& port) const { + std::vector getPortConfigsForDevicePort( + const aidl::android::media::audio::common::AudioPort& port) const { return generateAudioDevicePortConfigs({port}, false); } - android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort( - const android::media::audio::common::AudioPort& port) const { + aidl::android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort( + const aidl::android::media::audio::common::AudioPort& port) const { const auto config = generateAudioDevicePortConfigs({port}, true); return *config.begin(); } @@ -117,26 +119,29 @@ class ModuleConfig { std::string toString() const; private: - std::vector generateInputAudioMixPortConfigs( - const std::vector& ports, + std::vector + generateInputAudioMixPortConfigs( + const std::vector& ports, bool singleProfile) const; - std::vector generateOutputAudioMixPortConfigs( - const std::vector& ports, + std::vector + generateOutputAudioMixPortConfigs( + const std::vector& ports, bool singleProfile) const; // Unlike MixPorts, the generator for DevicePorts always returns a non-empty // vector for a non-empty input port list. If there are no profiles in the // port, its initial configs are looked up, if there are none, // then an empty config is used, assuming further negotiation via setAudioPortConfig. - std::vector generateAudioDevicePortConfigs( - const std::vector& ports, + std::vector + generateAudioDevicePortConfigs( + const std::vector& ports, bool singleProfile) const; - android::binder::Status mStatus = android::binder::Status::ok(); - std::vector mPorts; - std::vector mInitialConfigs; + ndk::ScopedAStatus mStatus = ndk::ScopedAStatus::ok(); + std::vector mPorts; + std::vector mInitialConfigs; std::set mAttachedSinkDevicePorts; std::set mAttachedSourceDevicePorts; std::set mExternalDevicePorts; - std::vector mRoutes; + std::vector mRoutes; }; diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp index 824ac8d3db..6be4e2f97a 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp @@ -27,41 +27,48 @@ #include #include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include "ModuleConfig.h" using namespace android; -using android::binder::Status; -using android::hardware::audio::common::PlaybackTrackMetadata; -using android::hardware::audio::common::RecordTrackMetadata; -using android::hardware::audio::common::SinkMetadata; -using android::hardware::audio::common::SourceMetadata; -using android::hardware::audio::core::AudioPatch; -using android::hardware::audio::core::AudioRoute; -using android::hardware::audio::core::IModule; -using android::hardware::audio::core::IStreamIn; -using android::hardware::audio::core::IStreamOut; -using android::hardware::audio::core::ModuleDebug; -using android::media::audio::common::AudioContentType; -using android::media::audio::common::AudioDevice; -using android::media::audio::common::AudioDeviceAddress; -using android::media::audio::common::AudioDeviceType; -using android::media::audio::common::AudioFormatType; -using android::media::audio::common::AudioIoFlags; -using android::media::audio::common::AudioOutputFlags; -using android::media::audio::common::AudioPort; -using android::media::audio::common::AudioPortConfig; -using android::media::audio::common::AudioPortDeviceExt; -using android::media::audio::common::AudioPortExt; -using android::media::audio::common::AudioSource; -using android::media::audio::common::AudioUsage; +using aidl::android::hardware::audio::common::PlaybackTrackMetadata; +using aidl::android::hardware::audio::common::RecordTrackMetadata; +using aidl::android::hardware::audio::common::SinkMetadata; +using aidl::android::hardware::audio::common::SourceMetadata; +using aidl::android::hardware::audio::core::AudioPatch; +using aidl::android::hardware::audio::core::AudioRoute; +using aidl::android::hardware::audio::core::IModule; +using aidl::android::hardware::audio::core::IStreamIn; +using aidl::android::hardware::audio::core::IStreamOut; +using aidl::android::hardware::audio::core::ModuleDebug; +using aidl::android::media::audio::common::AudioContentType; +using aidl::android::media::audio::common::AudioDevice; +using aidl::android::media::audio::common::AudioDeviceAddress; +using aidl::android::media::audio::common::AudioDeviceType; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioIoFlags; +using aidl::android::media::audio::common::AudioOutputFlags; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioPortConfig; +using aidl::android::media::audio::common::AudioPortDeviceExt; +using aidl::android::media::audio::common::AudioPortExt; +using aidl::android::media::audio::common::AudioSource; +using aidl::android::media::audio::common::AudioUsage; +using ndk::ScopedAStatus; + +namespace ndk { +std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) { + str << status.getDescription(); + return str; +} +} // namespace ndk template auto findById(std::vector& v, int32_t id) { @@ -85,16 +92,23 @@ AudioDeviceAddress GenerateUniqueDeviceAddress() { return AudioDeviceAddress::make(std::to_string(++nextId)); } -struct AidlDeathRecipient : IBinder::DeathRecipient { +struct AidlDeathRecipient { + const ndk::SpAIBinder binder; + const ndk::ScopedAIBinder_DeathRecipient recipient; std::mutex mutex; std::condition_variable condition; bool fired = false; - wp who; - void binderDied(const wp& who) override { + explicit AidlDeathRecipient(const ndk::SpAIBinder& binder) + : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {} + + binder_status_t linkToDeath() { + return AIBinder_linkToDeath(binder.get(), recipient.get(), this); + } + + void binderDied() { std::unique_lock lock(mutex); fired = true; - this->who = who; condition.notify_one(); }; @@ -103,6 +117,11 @@ struct AidlDeathRecipient : IBinder::DeathRecipient { condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return fired; }); return fired; } + + static void binderDiedCallbackAidl(void* cookie) { + AidlDeathRecipient* self = static_cast(cookie); + self->binderDied(); + } }; template @@ -127,13 +146,13 @@ class WithDebugFlags { : mInitial(initial.mFlags), mFlags(initial.mFlags) {} ~WithDebugFlags() { if (mModule != nullptr) { - Status status = mModule->setModuleDebug(mInitial); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = mModule->setModuleDebug(mInitial); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status; } } void SetUp(IModule* module) { - Status status = module->setModuleDebug(mFlags); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->setModuleDebug(mFlags); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } ModuleDebug& flags() { return mFlags; } @@ -153,8 +172,8 @@ class WithAudioPortConfig { explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {} ~WithAudioPortConfig() { if (mModule != nullptr) { - Status status = mModule->resetAudioPortConfig(getId()); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = mModule->resetAudioPortConfig(getId()); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; port config id " << getId(); } } @@ -174,8 +193,8 @@ class WithAudioPortConfig { if (mInitialConfig.id == 0) { AudioPortConfig suggested; bool applied = false; - Status status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << "; Config: " << mInitialConfig.toString(); if (!applied && negotiate) { mInitialConfig = suggested; @@ -206,25 +225,26 @@ class AudioCoreModule : public testing::TestWithParam { void TearDown() override { if (module != nullptr) { - Status status = module->setModuleDebug(ModuleDebug{}); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->setModuleDebug(ModuleDebug{}); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned when resetting debug flags"; } } void ConnectToService() { - module = android::waitForDeclaredService(String16(GetParam().c_str())); + module = IModule::fromBinder( + ndk::SpAIBinder(AServiceManager_getService(GetParam().c_str()))); ASSERT_NE(module, nullptr); } void RestartService() { ASSERT_NE(module, nullptr); moduleConfig.reset(); - deathHandler = sp::make(); - ASSERT_EQ(NO_ERROR, IModule::asBinder(module)->linkToDeath(deathHandler)); + deathHandler.reset(new AidlDeathRecipient(module->asBinder())); + ASSERT_EQ(STATUS_OK, deathHandler->linkToDeath()); ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1")); EXPECT_TRUE(deathHandler->waitForFired(3000)); - deathHandler = nullptr; + deathHandler.reset(); ASSERT_NO_FATAL_FAILURE(ConnectToService()); } @@ -235,8 +255,8 @@ class AudioCoreModule : public testing::TestWithParam { ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig EXPECT_EQ(config.portId, portConfig.get().portId); std::vector retrievedPortConfigs; - Status status = module->getAudioPortConfigs(&retrievedPortConfigs); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPortConfigs(&retrievedPortConfigs); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; const int32_t portConfigId = portConfig.getId(); auto configIt = std::find_if( retrievedPortConfigs.begin(), retrievedPortConfigs.end(), @@ -256,12 +276,12 @@ class AudioCoreModule : public testing::TestWithParam { template void GetAllEntityIds(std::set* entityIds, - Status (IModule::*getter)(std::vector*), + ScopedAStatus (IModule::*getter)(std::vector*), const std::string& errorMessage) { std::vector entities; { - Status status = (module.get()->*getter)(&entities); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = (module.get()->*getter)(&entities); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } std::transform(entities.begin(), entities.end(), std::inserter(*entityIds, entityIds->begin()), @@ -290,13 +310,13 @@ class AudioCoreModule : public testing::TestWithParam { void SetUpModuleConfig() { if (moduleConfig == nullptr) { moduleConfig = std::make_unique(module.get()); - ASSERT_EQ(Status::EX_NONE, moduleConfig->getStatus().exceptionCode()) + ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode()) << "ModuleConfig init error: " << moduleConfig->getError(); } } - sp module; - sp deathHandler; + std::shared_ptr module; + std::unique_ptr deathHandler; std::unique_ptr moduleConfig; WithDebugFlags debug; }; @@ -308,14 +328,14 @@ class WithDevicePortConnectedState { : mIdAndData(setAudioPortAddress(id, address)) {} ~WithDevicePortConnectedState() { if (mModule != nullptr) { - Status status = mModule->disconnectExternalDevice(getId()); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = mModule->disconnectExternalDevice(getId()); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned when disconnecting device port ID " << getId(); } } void SetUp(IModule* module) { - Status status = module->connectExternalDevice(mIdAndData, &mConnectedPort); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->connectExternalDevice(mIdAndData, &mConnectedPort); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned when connecting device port ID & data " << mIdAndData.toString(); ASSERT_NE(mIdAndData.id, getId()) @@ -344,32 +364,36 @@ class WithStream { explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {} ~WithStream() { if (mStream != nullptr) { - Status status = mStream->close(); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = mStream->close(); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; port config id " << getPortId(); } } void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); } - Status SetUpNoChecks(IModule* module) { return SetUpNoChecks(module, mPortConfig.get()); } - Status SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig); + ScopedAStatus SetUpNoChecks(IModule* module) { + return SetUpNoChecks(module, mPortConfig.get()); + } + ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig); void SetUp(IModule* module) { ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module)); - Status status = SetUpNoChecks(module); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = SetUpNoChecks(module); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << "; port config id " << getPortId(); ASSERT_NE(nullptr, mStream) << "; port config id " << getPortId(); } Stream* get() const { return mStream.get(); } + std::shared_ptr getSharedPointer() const { return mStream; } const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); } int32_t getPortId() const { return mPortConfig.getId(); } private: WithAudioPortConfig mPortConfig; - sp mStream; + std::shared_ptr mStream; }; template <> -Status WithStream::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) { +ScopedAStatus WithStream::SetUpNoChecks(IModule* module, + const AudioPortConfig& portConfig) { RecordTrackMetadata trackMeta; trackMeta.source = AudioSource::MIC; trackMeta.gain = 1.0; @@ -380,7 +404,8 @@ Status WithStream::SetUpNoChecks(IModule* module, const AudioPortConf } template <> -Status WithStream::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) { +ScopedAStatus WithStream::SetUpNoChecks(IModule* module, + const AudioPortConfig& portConfig) { PlaybackTrackMetadata trackMeta; trackMeta.usage = AudioUsage::MEDIA; trackMeta.contentType = AudioContentType::MUSIC; @@ -398,16 +423,15 @@ class WithAudioPatch { : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {} ~WithAudioPatch() { if (mModule != nullptr && mPatch.id != 0) { - Status status = mModule->resetAudioPatch(mPatch.id); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) - << status << "; patch id " << getId(); + ScopedAStatus status = mModule->resetAudioPatch(mPatch.id); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; patch id " << getId(); } } void SetUpPortConfigs(IModule* module) { ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module)); ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module)); } - Status SetUpNoChecks(IModule* module) { + ScopedAStatus SetUpNoChecks(IModule* module) { mModule = module; mPatch.sourcePortConfigIds = std::vector{mSrcPortConfig.getId()}; mPatch.sinkPortConfigIds = std::vector{mSinkPortConfig.getId()}; @@ -415,8 +439,8 @@ class WithAudioPatch { } void SetUp(IModule* module) { ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module)); - Status status = SetUpNoChecks(module); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = SetUpNoChecks(module); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << "; source port config id " << mSrcPortConfig.getId() << "; sink port config id " << mSinkPortConfig.getId(); } @@ -446,13 +470,13 @@ TEST_P(AudioCoreModule, PortIdsAreUnique) { TEST_P(AudioCoreModule, GetAudioPortsIsStable) { std::vector ports1; { - Status status = module->getAudioPorts(&ports1); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&ports1); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } std::vector ports2; { - Status status = module->getAudioPorts(&ports2); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&ports2); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } ASSERT_EQ(ports1.size(), ports2.size()) << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts"; @@ -464,13 +488,13 @@ TEST_P(AudioCoreModule, GetAudioPortsIsStable) { TEST_P(AudioCoreModule, GetAudioRoutesIsStable) { std::vector routes1; { - Status status = module->getAudioRoutes(&routes1); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routes1); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } std::vector routes2; { - Status status = module->getAudioRoutes(&routes2); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routes2); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } ASSERT_EQ(routes1.size(), routes2.size()) << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes"; @@ -482,8 +506,8 @@ TEST_P(AudioCoreModule, GetAudioRoutesIsStable) { TEST_P(AudioCoreModule, GetAudioRoutesAreValid) { std::vector routes; { - Status status = module->getAudioRoutes(&routes); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routes); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } for (const auto& route : routes) { std::set sources(route.sourcePortIds.begin(), route.sourcePortIds.end()); @@ -500,8 +524,8 @@ TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) { ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds)); std::vector routes; { - Status status = module->getAudioRoutes(&routes); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routes); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } for (const auto& route : routes) { EXPECT_EQ(1, portIds.count(route.sinkPortId)) @@ -520,8 +544,8 @@ TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) { } for (const auto portId : portIds) { std::vector routes; - Status status = module->getAudioRoutesForAudioPort(portId, &routes); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status; for (const auto& r : routes) { if (r.sinkPortId != portId) { const auto& srcs = r.sourcePortIds; @@ -532,8 +556,8 @@ TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) { } for (const auto portId : GetNonExistentIds(portIds)) { std::vector routes; - Status status = module->getAudioRoutesForAudioPort(portId, &routes); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port ID " << portId; } } @@ -541,8 +565,8 @@ TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) { TEST_P(AudioCoreModule, CheckDevicePorts) { std::vector ports; { - Status status = module->getAudioPorts(&ports); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&ports); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } std::optional defaultOutput, defaultInput; std::set inputs, outputs; @@ -590,8 +614,8 @@ TEST_P(AudioCoreModule, CheckDevicePorts) { TEST_P(AudioCoreModule, CheckMixPorts) { std::vector ports; { - Status status = module->getAudioPorts(&ports); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&ports); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } std::optional primaryMixPort; constexpr int primaryOutputFlag = 1 << static_cast(AudioOutputFlags::PRIMARY); @@ -619,14 +643,14 @@ TEST_P(AudioCoreModule, GetAudioPort) { } for (const auto portId : portIds) { AudioPort port; - Status status = module->getAudioPort(portId, &port); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPort(portId, &port); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status; EXPECT_EQ(portId, port.id); } for (const auto portId : GetNonExistentIds(portIds)) { AudioPort port; - Status status = module->getAudioPort(portId, &port); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->getAudioPort(portId, &port); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port ID " << portId; } } @@ -653,8 +677,8 @@ TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) { portConnected.get().ext.get().device); // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port. AudioPort connectedPort; - Status status = module->getAudioPort(connectedPortId, &connectedPort); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->getAudioPort(connectedPortId, &connectedPort); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned for getAudioPort port ID " << connectedPortId; EXPECT_EQ(portConnected.get(), connectedPort); const auto& portProfiles = connectedPort.profiles; @@ -669,8 +693,8 @@ TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) { std::vector allPorts; { - Status status = module->getAudioPorts(&allPorts); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&allPorts); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } const auto allPortsIt = findById(allPorts, connectedPortId); EXPECT_NE(allPorts.end(), allPortsIt); @@ -685,16 +709,16 @@ TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) { ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds)); for (const auto portConfigId : GetNonExistentIds(portConfigIds)) { { - sp stream; - Status status = module->openInputStream(portConfigId, {}, &stream); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + std::shared_ptr stream; + ScopedAStatus status = module->openInputStream(portConfigId, {}, &stream); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " openInputStream returned for port config ID " << portConfigId; EXPECT_EQ(nullptr, stream); } { - sp stream; - Status status = module->openOutputStream(portConfigId, {}, {}, &stream); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + std::shared_ptr stream; + ScopedAStatus status = module->openOutputStream(portConfigId, {}, {}, &stream); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " openOutputStream returned for port config ID " << portConfigId; EXPECT_EQ(nullptr, stream); } @@ -711,8 +735,8 @@ TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) { ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds)); std::vector portConfigs; { - Status status = module->getAudioPortConfigs(&portConfigs); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPortConfigs(&portConfigs); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } for (const auto& config : portConfigs) { EXPECT_EQ(1, portIds.count(config.portId)) @@ -724,8 +748,8 @@ TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) { std::set portConfigIds; ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds)); for (const auto portConfigId : GetNonExistentIds(portConfigIds)) { - Status status = module->resetAudioPortConfig(portConfigId); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->resetAudioPortConfig(portConfigId); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port config ID " << portConfigId; } } @@ -735,19 +759,19 @@ TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) { TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) { std::vector portConfigsBefore; { - Status status = module->getAudioPortConfigs(&portConfigsBefore); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPortConfigs(&portConfigsBefore); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } // TODO: Change port configs according to port profiles. for (const auto& c : portConfigsBefore) { - Status status = module->resetAudioPortConfig(c.id); - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->resetAudioPortConfig(c.id); + EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned for port config ID " << c.id; } std::vector portConfigsAfter; { - Status status = module->getAudioPortConfigs(&portConfigsAfter); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPortConfigs(&portConfigsAfter); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } for (const auto& c : portConfigsBefore) { auto afterIt = findById(portConfigsAfter, c.id); @@ -770,8 +794,8 @@ TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) { portConfig.portId = srcMixPort.value().id; { bool applied = true; - Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << "; Config: " << portConfig.toString(); EXPECT_FALSE(applied); } @@ -826,8 +850,8 @@ TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) { AudioPortConfig portConfig, suggestedConfig; bool applied; portConfig.portId = portId; - Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port ID " << portId; EXPECT_FALSE(suggestedConfig.format.has_value()); EXPECT_FALSE(suggestedConfig.channelMask.has_value()); @@ -842,8 +866,8 @@ TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) { AudioPortConfig portConfig, suggestedConfig; bool applied; portConfig.id = portConfigId; - Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port config ID " << portConfigId; EXPECT_FALSE(suggestedConfig.format.has_value()); EXPECT_FALSE(suggestedConfig.channelMask.has_value()); @@ -865,8 +889,8 @@ TEST_P(AudioCoreModule, TryConnectMissingDevice) { AudioPort portWithData = port; portWithData.ext.get().device.address = GenerateUniqueDeviceAddress(); - Status status = module->connectExternalDevice(portWithData, &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = module->connectExternalDevice(portWithData, &ignored); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned for static port " << portWithData.toString(); } } @@ -881,8 +905,8 @@ TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) { ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); ModuleDebug midwayDebugChange = debug.flags(); midwayDebugChange.simulateDeviceConnections = false; - Status status = module->setModuleDebug(midwayDebugChange); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = module->setModuleDebug(midwayDebugChange); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned when trying to disable connections simulation " << "while having a connected device"; } @@ -894,39 +918,39 @@ TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) { for (const auto portId : GetNonExistentIds(portIds)) { AudioPort invalidPort; invalidPort.id = portId; - Status status = module->connectExternalDevice(invalidPort, &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->connectExternalDevice(invalidPort, &ignored); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port ID " << portId << " when setting CONNECTED state"; status = module->disconnectExternalDevice(portId); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for port ID " << portId << " when setting DISCONNECTED state"; } std::vector ports; { - Status status = module->getAudioPorts(&ports); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioPorts(&ports); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } for (const auto& port : ports) { if (port.ext.getTag() != AudioPortExt::Tag::device) { - Status status = module->connectExternalDevice(port, &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->connectExternalDevice(port, &ignored); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for non-device port ID " << port.id << " when setting CONNECTED state"; status = module->disconnectExternalDevice(port.id); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for non-device port ID " << port.id << " when setting DISCONNECTED state"; } else { const auto& devicePort = port.ext.get(); if (devicePort.device.type.connection.empty()) { - Status status = module->connectExternalDevice(port, &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->connectExternalDevice(port, &ignored); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for permanently attached device port ID " << port.id << " when setting CONNECTED state"; status = module->disconnectExternalDevice(port.id); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for permanently attached device port ID " << port.id << " when setting DISCONNECTED state"; } @@ -943,8 +967,8 @@ TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) { GTEST_SKIP() << "No external devices in the module."; } for (const auto& port : ports) { - Status status = module->disconnectExternalDevice(port.id); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->disconnectExternalDevice(port.id); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned when disconnecting already disconnected device port ID " << port.id; AudioPort portWithData = port; @@ -953,14 +977,14 @@ TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) { WithDevicePortConnectedState portConnected(portWithData); ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get())); status = module->connectExternalDevice(portConnected.get(), &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned when trying to connect a connected device port " << portConnected.get().toString(); status = module->connectExternalDevice(portWithData, &ignored); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned when connecting again the external device " << portWithData.ext.get().device.toString(); - if (status.exceptionCode() == Status::EX_NONE) { + if (status.getExceptionCode() == EX_NONE) { ADD_FAILURE() << "Returned connected port " << ignored.toString() << " for template " << portWithData.toString(); } @@ -984,8 +1008,8 @@ TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) { // Our test assumes that 'getAudioPort' returns at least one profile, and it // is not a dynamic profile. ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get())); - Status status = module->disconnectExternalDevice(portConnected.getId()); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = module->disconnectExternalDevice(portConnected.getId()); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned when trying to disconnect device port ID " << port.id << " with active configuration " << config.getId(); } @@ -1001,8 +1025,8 @@ TEST_P(AudioCoreModule, ExternalDevicePortRoutes) { for (const auto& port : ports) { std::vector routesBefore; { - Status status = module->getAudioRoutes(&routesBefore); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routesBefore); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } int32_t connectedPortId; @@ -1012,32 +1036,32 @@ TEST_P(AudioCoreModule, ExternalDevicePortRoutes) { connectedPortId = portConnected.getId(); std::vector connectedPortRoutes; { - Status status = + ScopedAStatus status = module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status << " returned when retrieving routes for connected port id " << connectedPortId; } // There must be routes for the port to be useful. if (connectedPortRoutes.empty()) { std::vector allRoutes; - Status status = module->getAudioRoutes(&allRoutes); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&allRoutes); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; ADD_FAILURE() << " no routes returned for the connected port " << portConnected.get().toString() << "; all routes: " << android::internal::ToString(allRoutes); } } std::vector ignored; - Status status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored); - ASSERT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored); + ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned when retrieving routes for released connected port id " << connectedPortId; std::vector routesAfter; { - Status status = module->getAudioRoutes(&routesAfter); - ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status; + ScopedAStatus status = module->getAudioRoutes(&routesAfter); + ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status; } ASSERT_EQ(routesBefore.size(), routesAfter.size()) << "Sizes of audio route arrays do not match after creating and " @@ -1063,14 +1087,14 @@ class AudioStream : public AudioCoreModule { if (!portConfig.has_value()) { GTEST_SKIP() << "No mix port for attached devices"; } - sp heldStream; + std::shared_ptr heldStream; { WithStream stream(portConfig.value()); ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get())); - heldStream = stream.get(); + heldStream = stream.getSharedPointer(); } - Status status = heldStream->close(); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = heldStream->close(); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " when closing the stream twice"; } @@ -1107,8 +1131,8 @@ class AudioStream : public AudioCoreModule { ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get())); } else { ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get())); - Status status = stream.SetUpNoChecks(module.get()); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = stream.SetUpNoChecks(module.get()); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " open" << direction(true) << "Stream" " returned for port config ID " @@ -1130,8 +1154,8 @@ class AudioStream : public AudioCoreModule { } WithStream stream(portConfig.value()); ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get())); - Status status = stream.SetUpNoChecks(module.get()); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = stream.SetUpNoChecks(module.get()); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " open" << direction(true) << "Stream returned for port config ID " << stream.getPortId(); EXPECT_EQ(nullptr, stream.get()); @@ -1152,8 +1176,8 @@ class AudioStream : public AudioCoreModule { } WithStream stream(portConfig.value()); ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get())); - Status status = module->resetAudioPortConfig(stream.getPortId()); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId()); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned for port config ID " << stream.getPortId(); } @@ -1161,8 +1185,8 @@ class AudioStream : public AudioCoreModule { WithStream stream1(portConfig); ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get())); WithStream stream2; - Status status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig()); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig()); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " when opening " << direction(false) << " stream twice for the same port config ID " << stream1.getPortId(); } @@ -1226,8 +1250,8 @@ class AudioModulePatch : public AudioCoreModule { AudioPatch patch; patch.sourcePortConfigIds = sources; patch.sinkPortConfigIds = sinks; - Status status = module->setAudioPatch(patch, &patch); - ASSERT_EQ(expectedException, status.exceptionCode()) + ScopedAStatus status = module->setAudioPatch(patch, &patch); + ASSERT_EQ(expectedException, status.getExceptionCode()) << status << ": patch source ids: " << android::internal::ToString(sources) << "; sink ids: " << android::internal::ToString(sinks); } @@ -1246,8 +1270,8 @@ class AudioModulePatch : public AudioCoreModule { patch.get().sinkPortConfigIds.begin(), patch.get().sinkPortConfigIds.end()); for (const auto portConfigId : sourceAndSinkPortConfigIds) { - Status status = module->resetAudioPortConfig(portConfigId); - EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode()) + ScopedAStatus status = module->resetAudioPortConfig(portConfigId); + EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " returned for port config ID " << portConfigId; } } @@ -1266,22 +1290,22 @@ class AudioModulePatch : public AudioCoreModule { ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get())); } EXPECT_NO_FATAL_FAILURE( - SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()})); + SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()})); EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper( - Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()}, + EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()}, {sinkPortConfig.getId()})); EXPECT_NO_FATAL_FAILURE( - SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {})); + SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {})); EXPECT_NO_FATAL_FAILURE( - SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, + SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {sinkPortConfig.getId(), sinkPortConfig.getId()})); std::set portConfigIds; ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds)); for (const auto portConfigId : GetNonExistentIds(portConfigIds)) { - EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper( - Status::EX_ILLEGAL_ARGUMENT, {portConfigId}, {sinkPortConfig.getId()})); - EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, + EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId}, + {sinkPortConfig.getId()})); + EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {portConfigId})); } } @@ -1293,8 +1317,8 @@ class AudioModulePatch : public AudioCoreModule { } WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second); ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get())); - Status status = patch.SetUpNoChecks(module.get()); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = patch.SetUpNoChecks(module.get()); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << ": when setting up a patch from " << srcSinkPair.value().first.toString() << " to " << srcSinkPair.value().second.toString() << " that does not have a route"; @@ -1351,8 +1375,9 @@ class AudioModulePatch : public AudioCoreModule { for (const auto patchId : GetNonExistentIds(patchIds)) { AudioPatch patchWithNonExistendId = patch.get(); patchWithNonExistendId.id = patchId; - Status status = module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = + module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for patch ID " << patchId; } } @@ -1375,8 +1400,8 @@ TEST_P(AudioModulePatch, ResetInvalidPatchId) { std::set patchIds; ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds)); for (const auto patchId : GetNonExistentIds(patchIds)) { - Status status = module->resetAudioPatch(patchId); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode()) + ScopedAStatus status = module->resetAudioPatch(patchId); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) << status << " returned for patch ID " << patchId; } } @@ -1400,7 +1425,7 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); } From 16db9b7c97271658c36c07564124436cd58c6b70 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 17 Jun 2022 21:36:18 +0000 Subject: [PATCH 2/3] audio: Improve debug logging in the AIDL version, fix bugs - Make sure the AIDL default implementation has debug output enabled. - Log additional info in the AIDL VTS to facilitate debugging. - Make resource handler classes move-only types. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest Merged-In: I111b72aaf12962f00b4d31b8ac87186bca5eb853 Change-Id: I111b72aaf12962f00b4d31b8ac87186bca5eb853 (cherry picked from commit f82fc6476d8778e7a513056e1d7f7d4ab5aaadfd) --- audio/aidl/default/Module.cpp | 1 + audio/aidl/default/main.cpp | 10 ++-- audio/aidl/vts/ModuleConfig.cpp | 10 ++-- audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp | 55 ++++++++++++++++---- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 961ee84517..1bf7321f15 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -424,6 +424,7 @@ ndk::ScopedAStatus Module::openOutputStream(int32_t in_portConfigId, } ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) { + LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString(); if (in_requested.sourcePortConfigIds.empty()) { LOG(ERROR) << __func__ << ": requested patch has empty sources list"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp index 0de6047f6e..aeb9983b88 100644 --- a/audio/aidl/default/main.cpp +++ b/audio/aidl/default/main.cpp @@ -25,20 +25,22 @@ using aidl::android::hardware::audio::core::Config; using aidl::android::hardware::audio::core::Module; int main() { + // This is a debug implementation, always enable debug logging. + android::base::SetMinimumLogSeverity(::android::base::DEBUG); ABinderProcess_setThreadPoolMaxThreadCount(16); - // make the default config service + // Make the default config service auto config = ndk::SharedRefBase::make(); const std::string configName = std::string() + Config::descriptor + "/default"; binder_status_t status = AServiceManager_addService(config->asBinder().get(), configName.c_str()); - CHECK(status == STATUS_OK); + CHECK_EQ(STATUS_OK, status); - // make the default module + // Make the default module auto moduleDefault = ndk::SharedRefBase::make(); const std::string moduleDefaultName = std::string() + Module::descriptor + "/default"; status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str()); - CHECK(status == STATUS_OK); + CHECK_EQ(STATUS_OK, status); ABinderProcess_joinThreadPool(); return EXIT_FAILURE; // should not reach diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index 36b3b1b412..0e76d9a647 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -251,15 +251,15 @@ std::string ModuleConfig::toString() const { std::string result; result.append("Ports: "); result.append(android::internal::ToString(mPorts)); - result.append("Initial configs: "); + result.append("\nInitial configs: "); result.append(android::internal::ToString(mInitialConfigs)); - result.append("Attached sink device ports: "); + result.append("\nAttached sink device ports: "); result.append(android::internal::ToString(mAttachedSinkDevicePorts)); - result.append("Attached source device ports: "); + result.append("\nAttached source device ports: "); result.append(android::internal::ToString(mAttachedSourceDevicePorts)); - result.append("External device ports: "); + result.append("\nExternal device ports: "); result.append(android::internal::ToString(mExternalDevicePorts)); - result.append("Routes: "); + result.append("\nRoutes: "); result.append(android::internal::ToString(mRoutes)); return result; } diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp index 6be4e2f97a..6c91d247e7 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp @@ -138,12 +138,18 @@ constexpr IsInput::operator bool() const { return false; } +// All 'With*' classes are move-only because they are associated with some +// resource or state of a HAL module. class WithDebugFlags { public: + static WithDebugFlags createNested(const WithDebugFlags& parent) { + return WithDebugFlags(parent.mFlags); + } + WithDebugFlags() {} explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {} - explicit WithDebugFlags(const WithDebugFlags& initial) - : mInitial(initial.mFlags), mFlags(initial.mFlags) {} + WithDebugFlags(const WithDebugFlags&) = delete; + WithDebugFlags& operator=(const WithDebugFlags&) = delete; ~WithDebugFlags() { if (mModule != nullptr) { ScopedAStatus status = mModule->setModuleDebug(mInitial); @@ -170,6 +176,8 @@ class WithAudioPortConfig { public: WithAudioPortConfig() {} explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {} + WithAudioPortConfig(const WithAudioPortConfig&) = delete; + WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete; ~WithAudioPortConfig() { if (mModule != nullptr) { ScopedAStatus status = mModule->resetAudioPortConfig(getId()); @@ -326,6 +334,8 @@ class WithDevicePortConnectedState { explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {} WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address) : mIdAndData(setAudioPortAddress(id, address)) {} + WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete; + WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete; ~WithDevicePortConnectedState() { if (mModule != nullptr) { ScopedAStatus status = mModule->disconnectExternalDevice(getId()); @@ -362,6 +372,8 @@ class WithStream { public: WithStream() {} explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {} + WithStream(const WithStream&) = delete; + WithStream& operator=(const WithStream&) = delete; ~WithStream() { if (mStream != nullptr) { ScopedAStatus status = mStream->close(); @@ -421,6 +433,8 @@ class WithAudioPatch { WithAudioPatch() {} WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig) : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {} + WithAudioPatch(const WithAudioPatch&) = delete; + WithAudioPatch& operator=(const WithAudioPatch&) = delete; ~WithAudioPatch() { if (mModule != nullptr && mPatch.id != 0) { ScopedAStatus status = mModule->resetAudioPatch(mPatch.id); @@ -655,6 +669,12 @@ TEST_P(AudioCoreModule, GetAudioPort) { } } +TEST_P(AudioCoreModule, SetUpModuleConfig) { + ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig()); + // Send the module config to logcat to facilitate failures investigation. + LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString(); +} + // Verify that HAL module reports for a connected device port at least one non-dynamic profile, // that is, a profile with actual supported configuration. // Note: This test relies on simulation of external device connections by the HAL module. @@ -882,7 +902,7 @@ TEST_P(AudioCoreModule, TryConnectMissingDevice) { GTEST_SKIP() << "No external devices in the module."; } AudioPort ignored; - WithDebugFlags doNotSimulateConnections(debug); + WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug); doNotSimulateConnections.flags().simulateDeviceConnections = false; ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get())); for (const auto& port : ports) { @@ -1134,9 +1154,8 @@ class AudioStream : public AudioCoreModule { ScopedAStatus status = stream.SetUpNoChecks(module.get()); EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode()) << status << " open" << direction(true) - << "Stream" - " returned for port config ID " - << stream.getPortId() << ", maxOpenStreamCount is " << maxStreamCount; + << "Stream returned for port config ID " << stream.getPortId() + << ", maxOpenStreamCount is " << maxStreamCount; } } } @@ -1331,11 +1350,12 @@ class AudioModulePatch : public AudioCoreModule { } for (const auto& srcSinkGroup : srcSinkGroups) { const auto& route = srcSinkGroup.first; - std::vector patches; + std::vector> patches; for (const auto& srcSink : srcSinkGroup.second) { if (!route.isExclusive) { - patches.emplace_back(srcSink.first, srcSink.second); - EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1].SetUp(module.get())); + patches.push_back( + std::make_unique(srcSink.first, srcSink.second)); + EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get())); } else { WithAudioPatch patch(srcSink.first, srcSink.second); EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get())); @@ -1423,8 +1443,25 @@ INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch, android::PrintInstanceNameToString); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch); +class TestExecutionTracer : public ::testing::EmptyTestEventListener { + public: + void OnTestStart(const ::testing::TestInfo& test_info) override { + TraceTestState("Started", test_info); + } + + void OnTestEnd(const ::testing::TestInfo& test_info) override { + TraceTestState("Completed", test_info); + } + + private: + static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) { + LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name(); + } +}; + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer()); ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); From 111e0ceab5cc4b9a9d8ee58ac667175832c0edb8 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 17 Jun 2022 21:41:19 +0000 Subject: [PATCH 3/3] audio: Add support for compressed offload - Add compressed offload mix port into default implementation. - Require AudioOffloadInfo to be passed to IModule.openOutputStream for compressed offload port configs. - Update VTS to handle compressed offload. Bug: 205884982 Test: atest VtsHalAudioCoreTargetTest Merged-In: I118b2c04bff12b64a7cac4dc2c88217a6a270046 Change-Id: I118b2c04bff12b64a7cac4dc2c88217a6a270046 (cherry picked from commit 975ea3ae8959b1d9502290ebd5c71fba68645c64) --- .../android/hardware/audio/core/IModule.aidl | 2 + audio/aidl/default/Android.bp | 2 + audio/aidl/default/Configuration.cpp | 49 ++++++-- audio/aidl/default/Module.cpp | 8 ++ audio/aidl/vts/ModuleConfig.cpp | 109 ++++++++---------- audio/aidl/vts/ModuleConfig.h | 38 +++--- audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp | 51 ++++++-- 7 files changed, 161 insertions(+), 98 deletions(-) diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl index f406cd8ee0..802cb2f151 100644 --- a/audio/aidl/android/hardware/audio/core/IModule.aidl +++ b/audio/aidl/android/hardware/audio/core/IModule.aidl @@ -282,6 +282,8 @@ interface IModule { * @throws EX_ILLEGAL_ARGUMENT In the following cases: * - If the port config can not be found by the ID. * - If the port config is not of an output mix port. + * - If the offload info is not provided for an offload + * port configuration. * @throws EX_ILLEGAL_STATE In the following cases: * - If the port config already has a stream opened on it. * - If the limit on the open stream count for the port has diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 4728a89cdd..ad1d9c761a 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -13,6 +13,7 @@ cc_library_static { shared_libs: [ "libbase", "libbinder_ndk", + "libstagefright_foundation", "android.media.audio.common.types-V1-ndk", "android.hardware.audio.core-V1-ndk", ], @@ -37,6 +38,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder_ndk", + "libstagefright_foundation", "android.media.audio.common.types-V1-ndk", "android.hardware.audio.core-V1-ndk", ], diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp index 19d0b3c93f..f5d679bd3e 100644 --- a/audio/aidl/default/Configuration.cpp +++ b/audio/aidl/default/Configuration.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "core-impl/Configuration.h" @@ -42,16 +43,30 @@ using aidl::android::media::audio::common::PcmType; namespace aidl::android::hardware::audio::core::internal { +static void fillProfile(AudioProfile* profile, const std::vector& channelLayouts, + const std::vector& sampleRates) { + for (auto layout : channelLayouts) { + profile->channelMasks.push_back( + AudioChannelLayout::make(layout)); + } + profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end()); +} + static AudioProfile createProfile(PcmType pcmType, const std::vector& channelLayouts, const std::vector& sampleRates) { AudioProfile profile; profile.format.type = AudioFormatType::PCM; profile.format.pcm = pcmType; - for (auto layout : channelLayouts) { - profile.channelMasks.push_back( - AudioChannelLayout::make(layout)); - } - profile.sampleRates.insert(profile.sampleRates.end(), sampleRates.begin(), sampleRates.end()); + fillProfile(&profile, channelLayouts, sampleRates); + return profile; +} + +static AudioProfile createProfile(const std::string& encodingType, + const std::vector& channelLayouts, + const std::vector& sampleRates) { + AudioProfile profile; + profile.format.encoding = encodingType; + fillProfile(&profile, channelLayouts, sampleRates); return profile; } @@ -125,6 +140,8 @@ static AudioRoute createRoute(const std::vector& sources, int32_t sink) // * "primary output", PRIMARY, 1 max open, 1 max active stream // - profile PCM 16-bit; MONO, STEREO; 44100, 48000 // - profile PCM 24-bit; MONO, STEREO; 44100, 48000 +// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream +// - profile MP3; MONO, STEREO; 44100, 48000 // * "loopback output", stream count unlimited // - profile PCM 24-bit; STEREO; 48000 // * "primary input", 2 max open, 2 max active streams @@ -136,8 +153,8 @@ static AudioRoute createRoute(const std::vector& sources, int32_t sink) // - profile PCM 24-bit; STEREO; 48000 // // Routes: -// "primary out" -> "Null" -// "primary out" -> "USB Out" +// "primary out", "compressed offload" -> "Null" +// "primary out", "compressed offload" -> "USB Out" // "loopback out" -> "Loopback Out" // "Zero", "USB In" -> "primary input" // "Loopback In" -> "loopback input" @@ -183,6 +200,18 @@ Configuration& getNullPrimaryConfiguration() { standardPcmAudioProfiles.end()); c.ports.push_back(primaryOutMix); + AudioPort compressedOffloadOutMix = + createPort(c.nextPortId++, "compressed offload", + 1 << static_cast(AudioOutputFlags::DIRECT) | + 1 << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD) | + 1 << static_cast(AudioOutputFlags::NON_BLOCKING), + false, createPortMixExt(1, 1)); + compressedOffloadOutMix.profiles.push_back( + createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG, + {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO}, + {44100, 48000})); + c.ports.push_back(compressedOffloadOutMix); + AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false, createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0)); loopOutDevice.profiles.push_back( @@ -244,8 +273,10 @@ Configuration& getNullPrimaryConfiguration() { c.ports.push_back(usbInDevice); c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles; - c.routes.push_back(createRoute({primaryOutMix.id}, nullOutDevice.id)); - c.routes.push_back(createRoute({primaryOutMix.id}, usbOutDevice.id)); + c.routes.push_back( + createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id)); + c.routes.push_back( + createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id)); c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id)); c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id)); c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id)); diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 1bf7321f15..5b4d48a837 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -405,6 +405,14 @@ ndk::ScopedAStatus Module::openOutputStream(int32_t in_portConfigId, << " does not correspond to an output mix port"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + if (portConfigIt->flags.has_value() && + ((portConfigIt->flags.value().get() & + 1 << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) && + !in_offloadInfo.has_value()) { + LOG(ERROR) << __func__ << ": port config id " << in_portConfigId + << " has COMPRESS_OFFLOAD flag set, requires offload info"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } if (mStreams.count(in_portConfigId) != 0) { LOG(ERROR) << __func__ << ": port config id " << in_portConfigId << " already has a stream opened on it"; diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp index 0e76d9a647..969b0e9051 100644 --- a/audio/aidl/vts/ModuleConfig.cpp +++ b/audio/aidl/vts/ModuleConfig.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -22,19 +23,43 @@ #include "ModuleConfig.h" using namespace android; +using namespace std::chrono_literals; using aidl::android::hardware::audio::core::IModule; using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioEncapsulationMode; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioIoFlags; +using aidl::android::media::audio::common::AudioOffloadInfo; using aidl::android::media::audio::common::AudioOutputFlags; using aidl::android::media::audio::common::AudioPort; using aidl::android::media::audio::common::AudioPortConfig; using aidl::android::media::audio::common::AudioPortExt; using aidl::android::media::audio::common::AudioProfile; +using aidl::android::media::audio::common::AudioUsage; using aidl::android::media::audio::common::Int; +// static +std::optional ModuleConfig::generateOffloadInfoIfNeeded( + const AudioPortConfig& portConfig) { + if (portConfig.flags.has_value() && + portConfig.flags.value().getTag() == AudioIoFlags::Tag::output && + (portConfig.flags.value().get() & + 1 << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) { + AudioOffloadInfo offloadInfo; + offloadInfo.base.sampleRate = portConfig.sampleRate.value().value; + offloadInfo.base.channelMask = portConfig.channelMask.value(); + offloadInfo.base.format = portConfig.format.value(); + offloadInfo.bitRatePerSecond = 256; // Arbitrary value. + offloadInfo.durationUs = std::chrono::microseconds(1min).count(); // Arbitrary value. + offloadInfo.usage = AudioUsage::MEDIA; + offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE; + return offloadInfo; + } + return {}; +} + template auto findById(const std::vector& v, int32_t id) { return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; }); @@ -264,10 +289,10 @@ std::string ModuleConfig::toString() const { return result; } -static std::vector combineAudioConfigs(const AudioPort& port, - const AudioProfile& profile) { - std::vector configs; - configs.reserve(profile.channelMasks.size() * profile.sampleRates.size()); +static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile, + std::vector* result) { + const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size(); + result->reserve(result->capacity() + newConfigCount); for (auto channelMask : profile.channelMasks) { for (auto sampleRate : profile.sampleRates) { AudioPortConfig config{}; @@ -277,66 +302,32 @@ static std::vector combineAudioConfigs(const AudioPort& port, config.sampleRate = sr; config.channelMask = channelMask; config.format = profile.format; + config.flags = port.flags; config.ext = port.ext; - configs.push_back(config); + result->push_back(std::move(config)); } } - return configs; + return newConfigCount; } -std::vector ModuleConfig::generateInputAudioMixPortConfigs( - const std::vector& ports, bool singleProfile) const { +static bool isDynamicProfile(const AudioProfile& profile) { + return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) || + profile.sampleRates.empty() || profile.channelMasks.empty(); +} + +std::vector ModuleConfig::generateAudioMixPortConfigs( + const std::vector& ports, bool isInput, bool singleProfile) const { std::vector result; for (const auto& mixPort : ports) { - if (getAttachedSourceDevicesPortsForMixPort(mixPort).empty()) { - continue; // no attached devices + if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) { + continue; } for (const auto& profile : mixPort.profiles) { - if (profile.format.type == AudioFormatType::DEFAULT || profile.sampleRates.empty() || - profile.channelMasks.empty()) { - continue; // dynamic profile - } - auto configs = combineAudioConfigs(mixPort, profile); - for (auto& config : configs) { - config.flags = mixPort.flags; - result.push_back(config); - if (singleProfile) return result; - } - } - } - return result; -} - -static std::tuple generateOutFlags(const AudioPort& mixPort) { - static const AudioIoFlags offloadFlags = AudioIoFlags::make( - (1 << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD)) | - (1 << static_cast(AudioOutputFlags::DIRECT))); - const bool isOffload = (mixPort.flags.get() & - (1 << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD))) != 0; - return {isOffload ? offloadFlags : mixPort.flags, isOffload}; -} - -std::vector ModuleConfig::generateOutputAudioMixPortConfigs( - const std::vector& ports, bool singleProfile) const { - std::vector result; - for (const auto& mixPort : ports) { - if (getAttachedSinkDevicesPortsForMixPort(mixPort).empty()) { - continue; // no attached devices - } - auto [flags, isOffload] = generateOutFlags(mixPort); - (void)isOffload; - for (const auto& profile : mixPort.profiles) { - if (profile.format.type == AudioFormatType::DEFAULT) continue; - auto configs = combineAudioConfigs(mixPort, profile); - for (auto& config : configs) { - // Some combinations of flags declared in the config file require special - // treatment. - // if (isOffload) { - // config.offloadInfo.info(generateOffloadInfo(config.base)); - // } - config.flags = flags; - result.push_back(config); - if (singleProfile) return result; + if (isDynamicProfile(profile)) continue; + combineAudioConfigs(mixPort, profile, &result); + if (singleProfile && !result.empty()) { + result.resize(1); + return result; } } } @@ -349,9 +340,11 @@ std::vector ModuleConfig::generateAudioDevicePortConfigs( for (const auto& devicePort : ports) { const size_t resultSizeBefore = result.size(); for (const auto& profile : devicePort.profiles) { - auto configs = combineAudioConfigs(devicePort, profile); - result.insert(result.end(), configs.begin(), configs.end()); - if (singleProfile && !result.empty()) return result; + combineAudioConfigs(devicePort, profile, &result); + if (singleProfile && !result.empty()) { + result.resize(1); + return result; + } } if (resultSizeBefore == result.size()) { std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result), diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h index 504c0fdf96..df13430955 100644 --- a/audio/aidl/vts/ModuleConfig.h +++ b/audio/aidl/vts/ModuleConfig.h @@ -23,6 +23,7 @@ #include #include +#include #include class ModuleConfig { @@ -32,6 +33,10 @@ class ModuleConfig { using SrcSinkGroup = std::pair>; + static std::optional + generateOffloadInfoIfNeeded( + const aidl::android::media::audio::common::AudioPortConfig& portConfig); + explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module); const ndk::ScopedAStatus& getStatus() const { return mStatus; } std::string getError() const { return mStatus.getMessage(); } @@ -68,42 +73,34 @@ class ModuleConfig { } std::vector getPortConfigsForMixPorts() const { - auto inputs = generateInputAudioMixPortConfigs(getInputMixPorts(), false); - auto outputs = generateOutputAudioMixPortConfigs(getOutputMixPorts(), false); + auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false); + auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false); inputs.insert(inputs.end(), outputs.begin(), outputs.end()); return inputs; } std::vector getPortConfigsForMixPorts( bool isInput) const { - return isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), false) - : generateOutputAudioMixPortConfigs(getOutputMixPorts(), false); + return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false); } std::vector getPortConfigsForMixPorts( bool isInput, const aidl::android::media::audio::common::AudioPort& port) const { - return isInput ? generateInputAudioMixPortConfigs({port}, false) - : generateOutputAudioMixPortConfigs({port}, false); + return generateAudioMixPortConfigs({port}, isInput, false); } std::optional getSingleConfigForMixPort( bool isInput) const { - const auto config = isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), true) - : generateOutputAudioMixPortConfigs(getOutputMixPorts(), true); - // TODO: Avoid returning configs for offload since they require an extra - // argument to openOutputStream. + const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true); if (!config.empty()) { return *config.begin(); - } else { - return {}; } + return {}; } std::optional getSingleConfigForMixPort( bool isInput, const aidl::android::media::audio::common::AudioPort& port) const { - const auto config = isInput ? generateInputAudioMixPortConfigs({port}, true) - : generateOutputAudioMixPortConfigs({port}, true); + const auto config = generateAudioMixPortConfigs({port}, isInput, true); if (!config.empty()) { return *config.begin(); - } else { - return {}; } + return {}; } std::vector getPortConfigsForDevicePort( @@ -119,13 +116,8 @@ class ModuleConfig { std::string toString() const; private: - std::vector - generateInputAudioMixPortConfigs( - const std::vector& ports, - bool singleProfile) const; - std::vector - generateOutputAudioMixPortConfigs( - const std::vector& ports, + std::vector generateAudioMixPortConfigs( + const std::vector& ports, bool isInput, bool singleProfile) const; // Unlike MixPorts, the generator for DevicePorts always returns a non-empty diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp index 6c91d247e7..bb24365741 100644 --- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp +++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp @@ -403,21 +403,23 @@ class WithStream { std::shared_ptr mStream; }; -template <> -ScopedAStatus WithStream::SetUpNoChecks(IModule* module, - const AudioPortConfig& portConfig) { +SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) { RecordTrackMetadata trackMeta; trackMeta.source = AudioSource::MIC; trackMeta.gain = 1.0; trackMeta.channelMask = portConfig.channelMask.value(); SinkMetadata metadata; metadata.tracks.push_back(trackMeta); - return module->openInputStream(portConfig.id, metadata, &mStream); + return metadata; } template <> -ScopedAStatus WithStream::SetUpNoChecks(IModule* module, - const AudioPortConfig& portConfig) { +ScopedAStatus WithStream::SetUpNoChecks(IModule* module, + const AudioPortConfig& portConfig) { + return module->openInputStream(portConfig.id, GenerateSinkMetadata(portConfig), &mStream); +} + +SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) { PlaybackTrackMetadata trackMeta; trackMeta.usage = AudioUsage::MEDIA; trackMeta.contentType = AudioContentType::MUSIC; @@ -425,7 +427,15 @@ ScopedAStatus WithStream::SetUpNoChecks(IModule* module, trackMeta.channelMask = portConfig.channelMask.value(); SourceMetadata metadata; metadata.tracks.push_back(trackMeta); - return module->openOutputStream(portConfig.id, metadata, {}, &mStream); + return metadata; +} + +template <> +ScopedAStatus WithStream::SetUpNoChecks(IModule* module, + const AudioPortConfig& portConfig) { + return module->openOutputStream(portConfig.id, GenerateSourceMetadata(portConfig), + ModuleConfig::generateOffloadInfoIfNeeded(portConfig), + &mStream); } class WithAudioPatch { @@ -1238,7 +1248,7 @@ TEST_P(AudioStreamOut, OpenTwicePrimary) { auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) { constexpr int primaryOutputFlag = 1 << static_cast(AudioOutputFlags::PRIMARY); return port.flags.getTag() == AudioIoFlags::Tag::output && - ((port.flags.get() & primaryOutputFlag) != 0); + (port.flags.get() & primaryOutputFlag) != 0; }); if (primaryPortIt == mixPorts.end()) { GTEST_SKIP() << "No primary mix port"; @@ -1251,6 +1261,31 @@ TEST_P(AudioStreamOut, OpenTwicePrimary) { EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value())); } +TEST_P(AudioStreamOut, RequireOffloadInfo) { + const auto mixPorts = moduleConfig->getMixPorts(false); + auto offloadPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [&](const AudioPort& port) { + constexpr int compressOffloadFlag = 1 + << static_cast(AudioOutputFlags::COMPRESS_OFFLOAD); + return port.flags.getTag() == AudioIoFlags::Tag::output && + (port.flags.get() & compressOffloadFlag) != 0 && + !moduleConfig->getAttachedSinkDevicesPortsForMixPort(port).empty(); + }); + if (offloadPortIt == mixPorts.end()) { + GTEST_SKIP() + << "No mix port for compressed offload that could be routed to attached devices"; + } + const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt); + ASSERT_TRUE(portConfig.has_value()) + << "No profiles specified for the compressed offload mix port"; + std::shared_ptr ignored; + ScopedAStatus status = module->openOutputStream(portConfig.value().id, + GenerateSourceMetadata(portConfig.value()), + {} /* offloadInfo */, &ignored); + EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode()) + << status + << " returned when no offload info is provided for a compressed offload mix port"; +} + // Tests specific to audio patches. The fixure class is named 'AudioModulePatch' // to avoid clashing with 'AudioPatch' class. class AudioModulePatch : public AudioCoreModule {