Merge "audio: Add IBluetooth core interface" am: 7d183a48c8

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2239861

Change-Id: Ib83232899075b03f32767f7cc8f4b74c22e78f9a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-01-03 23:33:01 +00:00
committed by Automerger Merge Worker
11 changed files with 452 additions and 2 deletions

View File

@@ -112,6 +112,7 @@ aidl_interface {
"android/hardware/audio/core/AudioMode.aidl",
"android/hardware/audio/core/AudioPatch.aidl",
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IBluetooth.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamCallback.aidl",

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.audio.core;
@VintfStability
interface IBluetooth {
android.hardware.audio.core.IBluetooth.ScoConfig setScoConfig(in android.hardware.audio.core.IBluetooth.ScoConfig config);
android.hardware.audio.core.IBluetooth.HfpConfig setHfpConfig(in android.hardware.audio.core.IBluetooth.HfpConfig config);
@JavaDerive(equals=true, toString=true) @VintfStability
parcelable ScoConfig {
@nullable android.media.audio.common.Boolean isEnabled;
@nullable android.media.audio.common.Boolean isNrecEnabled;
android.hardware.audio.core.IBluetooth.ScoConfig.Mode mode = android.hardware.audio.core.IBluetooth.ScoConfig.Mode.UNSPECIFIED;
@nullable @utf8InCpp String debugName;
@VintfStability
enum Mode {
UNSPECIFIED = 0,
SCO = 1,
SCO_WB = 2,
SCO_SWB = 3,
}
}
@JavaDerive(equals=true, toString=true) @VintfStability
parcelable HfpConfig {
@nullable android.media.audio.common.Boolean isEnabled;
@nullable android.media.audio.common.Int sampleRate;
@nullable android.media.audio.common.Float volume;
const int VOLUME_MIN = 0;
const int VOLUME_MAX = 1;
}
}

View File

@@ -36,6 +36,7 @@ package android.hardware.audio.core;
interface IModule {
void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
@nullable android.hardware.audio.core.ITelephony getTelephony();
@nullable android.hardware.audio.core.IBluetooth getBluetooth();
android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
void disconnectExternalDevice(int portId);
android.hardware.audio.core.AudioPatch[] getAudioPatches();

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.audio.core;
import android.media.audio.common.Boolean;
import android.media.audio.common.Float;
import android.media.audio.common.Int;
/**
* An instance of IBluetooth manages settings for the Hands-Free Profile (HFP)
* and the SCO Link. This interface is optional to implement and provide by the
* vendor. It needs to be provided only if the device actually supports BT SCO
* or HFP.
*/
@VintfStability
interface IBluetooth {
@JavaDerive(equals=true, toString=true)
@VintfStability
parcelable ScoConfig {
/**
* Whether BT SCO is enabled. The client might need to disable it
* when another profile (for example, A2DP) is activated.
*/
@nullable Boolean isEnabled;
/**
* Whether BT SCO Noise Reduction and Echo Cancellation are enabled.
*/
@nullable Boolean isNrecEnabled;
@VintfStability enum Mode { UNSPECIFIED, SCO, SCO_WB, SCO_SWB }
/**
* If set, specifies the SCO mode to use:
* regular, wide band (WB), or super wide band (SWB).
*/
Mode mode = Mode.UNSPECIFIED;
/**
* The name of the BT SCO headset used for debugging purposes. Can be empty.
*/
@nullable @utf8InCpp String debugName;
}
/**
* Set the configuration of Bluetooth SCO.
*
* In the provided parcelable, the client sets zero, one or more parameters
* which have to be updated on the HAL side. The parameters that are left
* unset must retain their current values. It is allowed to change
* parameters while the SCO profile is disabled (isEnabled.value == false).
*
* In the returned parcelable, all parameter fields known to the HAL module
* must be populated to their current values. If the SCO profile is
* currently disabled (isEnabled.value == false), the parameters must
* reflect the last values that were in use.
*
* The client can pass an uninitialized parcelable in order to retrieve the
* current configuration.
*
* @return The current configuration (after update). All fields known to
* the HAL must be populated.
* @param config The configuration to set. Any number of fields may be left
* uninitialized.
* @throws EX_UNSUPPORTED_OPERATION If BT SCO is not supported.
* @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
* values is invalid.
*/
ScoConfig setScoConfig(in ScoConfig config);
@JavaDerive(equals=true, toString=true)
@VintfStability
parcelable HfpConfig {
/**
* Whether BT HFP is enabled.
*/
@nullable Boolean isEnabled;
/**
* The sample rate of BT HFP, in Hertz. Must be a positive number.
*/
@nullable Int sampleRate;
const int VOLUME_MIN = 0;
const int VOLUME_MAX = 1;
/**
* The output volume of BT HFP. 1.0f means unity gain, 0.0f is muted,
* see VOLUME_* constants;
*/
@nullable Float volume;
}
/**
* Set the configuration of Bluetooth HFP.
*
* In the provided parcelable, the client sets zero, one or more parameters
* which have to be updated on the HAL side. The parameters that are left
* unset must retain their current values. It is allowed to change
* parameters while the HFP profile is disabled (isEnabled.value == false).
*
* In the returned parcelable, all parameter fields known to the HAL module
* must be populated to their current values. If the HFP profile is
* currently disabled (isEnabled.value == false), the parameters must
* reflect the last values that were in use.
*
* The client can pass an uninitialized parcelable in order to retrieve the
* current configuration.
*
* @return The current configuration (after update). All fields known to
* the HAL must be populated.
* @param config The configuration to set. Any number of fields may be left
* uninitialized.
* @throws EX_UNSUPPORTED_OPERATION If BT HFP is not supported.
* @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
* values is invalid.
*/
HfpConfig setHfpConfig(in HfpConfig config);
}

View File

@@ -21,6 +21,7 @@ import android.hardware.audio.common.SourceMetadata;
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
import android.hardware.audio.core.IBluetooth;
import android.hardware.audio.core.IStreamCallback;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
@@ -85,6 +86,20 @@ interface IModule {
*/
@nullable ITelephony getTelephony();
/**
* Retrieve the interface to control Bluetooth SCO and HFP.
*
* If the HAL module supports either the SCO Link or Hands-Free Profile
* functionality (or both) for Bluetooth, it must return an instance of the
* IBluetooth interface. The same instance must be returned during the
* lifetime of the HAL module. If the HAL module does not support BT SCO and
* HFP, a null must be returned, without throwing any errors.
*
* @return An instance of the IBluetooth interface implementation.
* @throws EX_ILLEGAL_STATE If there was an error creating an instance.
*/
@nullable IBluetooth getBluetooth();
/**
* Set a device port of an external device into connected state.
*

View File

@@ -62,6 +62,7 @@ cc_library_static {
export_include_dirs: ["include"],
srcs: [
"AudioPolicyConfigXmlConverter.cpp",
"Bluetooth.cpp",
"Config.cpp",
"Configuration.cpp",
"EngineConfigXmlConverter.cpp",

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "AHAL_Bluetooth"
#include <android-base/logging.h>
#include "core-impl/Bluetooth.h"
using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::Float;
using aidl::android::media::audio::common::Int;
namespace aidl::android::hardware::audio::core {
Bluetooth::Bluetooth() {
mScoConfig.isEnabled = Boolean{false};
mScoConfig.isNrecEnabled = Boolean{false};
mScoConfig.mode = ScoConfig::Mode::SCO;
mHfpConfig.isEnabled = Boolean{false};
mHfpConfig.sampleRate = Int{8000};
mHfpConfig.volume = Float{HfpConfig::VOLUME_MAX};
}
ndk::ScopedAStatus Bluetooth::setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) {
if (in_config.isEnabled.has_value()) {
mScoConfig.isEnabled = in_config.isEnabled;
}
if (in_config.isNrecEnabled.has_value()) {
mScoConfig.isNrecEnabled = in_config.isNrecEnabled;
}
if (in_config.mode != ScoConfig::Mode::UNSPECIFIED) {
mScoConfig.mode = in_config.mode;
}
if (in_config.debugName.has_value()) {
mScoConfig.debugName = in_config.debugName;
}
*_aidl_return = mScoConfig;
LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
<< _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Bluetooth::setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) {
if (in_config.sampleRate.has_value() && in_config.sampleRate.value().value <= 0) {
LOG(ERROR) << __func__ << ": invalid sample rate: " << in_config.sampleRate.value().value;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (in_config.volume.has_value() && (in_config.volume.value().value < HfpConfig::VOLUME_MIN ||
in_config.volume.value().value > HfpConfig::VOLUME_MAX)) {
LOG(ERROR) << __func__ << ": invalid volume: " << in_config.volume.value().value;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (in_config.isEnabled.has_value()) {
mHfpConfig.isEnabled = in_config.isEnabled;
}
if (in_config.sampleRate.has_value()) {
mHfpConfig.sampleRate = in_config.sampleRate;
}
if (in_config.volume.has_value()) {
mHfpConfig.volume = in_config.volume;
}
*_aidl_return = mHfpConfig;
LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
<< _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::audio::core

View File

@@ -25,6 +25,7 @@
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include "core-impl/Bluetooth.h"
#include "core-impl/Module.h"
#include "core-impl/SoundDose.h"
#include "core-impl/Telephony.h"
@@ -326,6 +327,18 @@ ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_retur
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
if (mBluetooth == nullptr) {
mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
mBluetoothBinder = mBluetooth->asBinder();
AIBinder_setMinSchedulerPolicy(mBluetoothBinder.get(), SCHED_NORMAL,
ANDROID_PRIORITY_AUDIO);
}
*_aidl_return = mBluetooth;
LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
AudioPort* _aidl_return) {
const int32_t templateId = in_templateIdAndAdditionalData.id;

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/audio/core/BnBluetooth.h>
namespace aidl::android::hardware::audio::core {
class Bluetooth : public BnBluetooth {
public:
Bluetooth();
private:
ndk::ScopedAStatus setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) override;
ndk::ScopedAStatus setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) override;
ScoConfig mScoConfig;
HfpConfig mHfpConfig;
};
} // namespace aidl::android::hardware::audio::core

View File

@@ -39,6 +39,7 @@ class Module : public BnModule {
ndk::ScopedAStatus setModuleDebug(
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
ndk::ScopedAStatus connectExternalDevice(
const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -127,10 +128,12 @@ class Module : public BnModule {
const Type mType;
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
// Since it is required to return the same instance of the ITelephony, even
// if the client has released it on its side, we need to hold it via a strong pointer.
// For the interfaces requiring to return the same instance, we need to hold them
// via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
std::shared_ptr<ITelephony> mTelephony;
ndk::SpAIBinder mTelephonyBinder;
std::shared_ptr<IBluetooth> mBluetooth;
ndk::SpAIBinder mBluetoothBinder;
// ids of ports created at runtime via 'connectExternalDevice'.
std::set<int32_t> mConnectedDevicePorts;
Streams mStreams;

View File

@@ -56,6 +56,7 @@ using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::audio::core::AudioMode;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IBluetooth;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::IStreamCommon;
using aidl::android::hardware::audio::core::IStreamIn;
@@ -85,6 +86,7 @@ using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
using aidl::android::media::audio::common::Float;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::Void;
using android::hardware::audio::common::getChannelCount;
using android::hardware::audio::common::isBitPositionFlagSet;
@@ -1776,6 +1778,89 @@ TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) {
}
}
class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
public:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
ASSERT_IS_OK(module->getBluetooth(&bluetooth));
}
void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
std::shared_ptr<IBluetooth> bluetooth;
};
TEST_P(AudioCoreBluetooth, SameInstance) {
if (bluetooth == nullptr) {
GTEST_SKIP() << "Bluetooth is not supported";
}
std::shared_ptr<IBluetooth> bluetooth2;
EXPECT_IS_OK(module->getBluetooth(&bluetooth2));
ASSERT_NE(nullptr, bluetooth2.get());
EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
<< "getBluetooth must return the same interface instance across invocations";
}
TEST_P(AudioCoreBluetooth, ScoConfig) {
static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
if (bluetooth == nullptr) {
GTEST_SKIP() << "Bluetooth is not supported";
}
ndk::ScopedAStatus status;
IBluetooth::ScoConfig scoConfig;
ASSERT_STATUS(kStatuses, status = bluetooth->setScoConfig({}, &scoConfig));
if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
GTEST_SKIP() << "BT SCO is not supported";
}
EXPECT_TRUE(scoConfig.isEnabled.has_value());
EXPECT_TRUE(scoConfig.isNrecEnabled.has_value());
EXPECT_NE(IBluetooth::ScoConfig::Mode::UNSPECIFIED, scoConfig.mode);
IBluetooth::ScoConfig scoConfig2;
ASSERT_IS_OK(bluetooth->setScoConfig(scoConfig, &scoConfig2));
EXPECT_EQ(scoConfig, scoConfig2);
}
TEST_P(AudioCoreBluetooth, HfpConfig) {
static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
if (bluetooth == nullptr) {
GTEST_SKIP() << "Bluetooth is not supported";
}
ndk::ScopedAStatus status;
IBluetooth::HfpConfig hfpConfig;
ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
GTEST_SKIP() << "BT HFP is not supported";
}
EXPECT_TRUE(hfpConfig.isEnabled.has_value());
EXPECT_TRUE(hfpConfig.sampleRate.has_value());
EXPECT_TRUE(hfpConfig.volume.has_value());
IBluetooth::HfpConfig hfpConfig2;
ASSERT_IS_OK(bluetooth->setHfpConfig(hfpConfig, &hfpConfig2));
EXPECT_EQ(hfpConfig, hfpConfig2);
}
TEST_P(AudioCoreBluetooth, HfpConfigInvalid) {
static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
if (bluetooth == nullptr) {
GTEST_SKIP() << "Bluetooth is not supported";
}
ndk::ScopedAStatus status;
IBluetooth::HfpConfig hfpConfig;
ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
GTEST_SKIP() << "BT HFP is not supported";
}
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
bluetooth->setHfpConfig({.sampleRate = Int{-1}}, &hfpConfig));
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, bluetooth->setHfpConfig({.sampleRate = Int{0}}, &hfpConfig));
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MIN - 1}},
&hfpConfig));
EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MAX + 1}},
&hfpConfig));
}
class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
public:
void SetUp() override {
@@ -1788,6 +1873,17 @@ class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithP
std::shared_ptr<ITelephony> telephony;
};
TEST_P(AudioCoreTelephony, SameInstance) {
if (telephony == nullptr) {
GTEST_SKIP() << "Telephony is not supported";
}
std::shared_ptr<ITelephony> telephony2;
EXPECT_IS_OK(module->getTelephony(&telephony2));
ASSERT_NE(nullptr, telephony2.get());
EXPECT_EQ(telephony->asBinder(), telephony2->asBinder())
<< "getTelephony must return the same interface instance across invocations";
}
TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
if (telephony == nullptr) {
GTEST_SKIP() << "Telephony is not supported";
@@ -3039,6 +3135,17 @@ ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
return ndk::ScopedAStatus::ok();
}
TEST_P(AudioCoreSoundDose, SameInstance) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
}
std::shared_ptr<ISoundDose> soundDose2;
EXPECT_IS_OK(module->getSoundDose(&soundDose2));
ASSERT_NE(nullptr, soundDose2.get());
EXPECT_EQ(soundDose->asBinder(), soundDose2->asBinder())
<< "getSoundDose must return the same interface instance across invocations";
}
TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
if (soundDose == nullptr) {
GTEST_SKIP() << "SoundDose is not supported";
@@ -3085,6 +3192,10 @@ INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothTest, AudioCoreBluetooth,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetooth);
INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);