Merge "Add seat memory properties to DefaultProperties.json for CTS tests"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index d4c1e85..d6e6f50 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -148,6 +148,7 @@
vendor_available: true,
srcs: [
"android/hardware/audio/effect/Descriptor.aidl",
+ "android/hardware/audio/effect/IEffect.aidl",
"android/hardware/audio/effect/IFactory.aidl",
],
imports: [
@@ -165,3 +166,19 @@
},
},
}
+
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V1"
+
+cc_defaults {
+ name: "latest_android_hardware_audio_effect_ndk_shared",
+ shared_libs: [
+ latest_android_hardware_audio_effect + "-ndk",
+ ],
+}
+
+cc_defaults {
+ name: "latest_android_hardware_audio_effect_ndk_static",
+ static_libs: [
+ latest_android_hardware_audio_effect + "-ndk",
+ ],
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..7f868ad
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.effect;
+@VintfStability
+interface IEffect {
+ void open();
+ void close();
+ android.hardware.audio.effect.Descriptor getDescriptor();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
index b6c9aab..db06475 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
@@ -35,4 +35,6 @@
@VintfStability
interface IFactory {
android.hardware.audio.effect.Descriptor.Identity[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation);
+ android.hardware.audio.effect.IEffect createEffect(in android.media.audio.common.AudioUuid implUuid);
+ void destroyEffect(in android.hardware.audio.effect.IEffect handle);
}
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..44e916b
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -0,0 +1,63 @@
+/*
+ * 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.effect;
+
+import android.hardware.audio.effect.Descriptor;
+
+/**
+ * Effect interfaces definitions to configure and control the effect instance.
+ */
+@VintfStability
+interface IEffect {
+ /**
+ * Open an effect instance, effect should not start processing data before receive START
+ * command. All necessary information should be allocated and instance should transfer to IDLE
+ * state after open() call has been handled successfully.
+ * After open, the effect instance should be able to handle all IEffect interface calls.
+ *
+ * @throws a EX_UNSUPPORTED_OPERATION if device capability/resource is not enough or system
+ * failure happens.
+ * @note Open an already-opened effect instance should do nothing and not result in throw error.
+ */
+ void open();
+
+ /**
+ * Called by the client to close the effect instance, instance context will be kept after
+ * close, but processing thread should be destroyed and consume no CPU. It is recommended to
+ * close the effect on the client side as soon as it becomes unused, it's client responsibility
+ * to make sure all parameter/buffer is correct if client wants to reopen a closed instance.
+ *
+ * Effect instance close interface should always success unless:
+ * 1. The effect instance is not in a proper state to be closed, for example it's still in
+ * processing state.
+ * 2. There is system/hardware related failure when close.
+ *
+ * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be closed.
+ * @throws EX_UNSUPPORTED_OPERATION if the effect instance failed to close for any other reason.
+ * @note Close an already-closed effect should do nothing and not result in throw error.
+ */
+ void close();
+
+ /**
+ * Return the @c Descriptor of this effect instance.
+ *
+ * Must be available for the effect instance at anytime and should always succeed.
+ *
+ * @return Descriptor The @c Descriptor of this effect instance.
+ */
+ Descriptor getDescriptor();
+}
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index 99c2e6a..4873d3a 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -17,6 +17,7 @@
package android.hardware.audio.effect;
import android.hardware.audio.effect.Descriptor;
+import android.hardware.audio.effect.IEffect;
import android.media.audio.common.AudioUuid;
/**
@@ -42,4 +43,30 @@
*/
Descriptor.Identity[] queryEffects(
in @nullable AudioUuid type, in @nullable AudioUuid implementation);
+
+ /**
+ * Called by the audio framework to create the effect (identified by the implementation UUID
+ * parameter).
+ *
+ * The effect instance should be able to maintain its own context and parameters after creation.
+ *
+ * @param implUuid UUID for the effect implementation which instance will be created based on.
+ * @return The effect instance handle created.
+ * @throws EX_ILLEGAL_ARGUMENT if the implUuid is not valid.
+ * @throws EX_TRANSACTION_FAILED if device capability/resource is not enough to create the
+ * effect instance.
+ */
+ IEffect createEffect(in AudioUuid implUuid);
+
+ /**
+ * Called by the framework to destroy the effect and free up all currently allocated resources.
+ * It is recommended to destroy the effect from the client side as soon as it is becomes unused.
+ *
+ * The client must ensure effect instance is closed before destroy.
+ *
+ * @param handle The handle of effect instance to be destroyed.
+ * @throws EX_ILLEGAL_ARGUMENT if the effect handle is not valid.
+ * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+ */
+ void destroyEffect(in IEffect handle);
}
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 74549d4..1026134 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -16,8 +16,13 @@
#pragma once
+#include <initializer_list>
+#include <type_traits>
+
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <aidl/android/media/audio/common/PcmType.h>
namespace android::hardware::audio::common {
@@ -78,4 +83,34 @@
return 0;
}
+// The helper functions defined below are only applicable to the case when an enum type
+// specifies zero-based bit positions, not bit masks themselves. This is why instantiation
+// is restricted to certain enum types.
+template <typename E>
+using is_bit_position_enum = std::integral_constant<
+ bool, std::is_same_v<E, ::aidl::android::media::audio::common::AudioInputFlags> ||
+ std::is_same_v<E, ::aidl::android::media::audio::common::AudioOutputFlags>>;
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(E flag) {
+ return 1 << static_cast<U>(flag);
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr bool isBitPositionFlagSet(U mask, E flag) {
+ return (mask & makeBitPositionFlagMask(flag)) != 0;
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+ typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) {
+ U result = 0;
+ for (const auto flag : flags) {
+ result |= makeBitPositionFlagMask(flag);
+ }
+ return result;
+}
+
} // namespace android::hardware::audio::common
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 5d63347..53ed908 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -68,6 +68,7 @@
"libbase",
"libbinder_ndk",
"android.hardware.audio.effect-V1-ndk",
+ "libequalizer",
],
cflags: [
"-Wall",
@@ -80,7 +81,10 @@
cc_library_static {
name: "libaudioeffectserviceexampleimpl",
defaults: ["aidlaudioeffectservice_defaults"],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ "include/equalizer-impl/",
+ ],
srcs: [
"EffectFactory.cpp",
],
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index f5d679b..a3e5ff7 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <Utils.h>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
@@ -40,6 +41,7 @@
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::makeBitPositionFlagMask;
namespace aidl::android::hardware::audio::core::internal {
@@ -193,7 +195,7 @@
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
- 1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
+ makeBitPositionFlagMask(AudioOutputFlags::PRIMARY),
false, createPortMixExt(1, 1));
primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(),
standardPcmAudioProfiles.begin(),
@@ -202,9 +204,9 @@
AudioPort compressedOffloadOutMix =
createPort(c.nextPortId++, "compressed offload",
- 1 << static_cast<int32_t>(AudioOutputFlags::DIRECT) |
- 1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD) |
- 1 << static_cast<int32_t>(AudioOutputFlags::NON_BLOCKING),
+ makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
+ AudioOutputFlags::COMPRESS_OFFLOAD,
+ AudioOutputFlags::NON_BLOCKING}),
false, createPortMixExt(1, 1));
compressedOffloadOutMix.profiles.push_back(
createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index a31e23f..ea9d470 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -36,6 +36,8 @@
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
id.uuid = EqualizerUUID;
mIdentityList.push_back(id);
+ // TODO: Add visualizer with default implementation later
+#if 0
id.type = {static_cast<int32_t>(0xd3467faa),
0xacc7,
0x4d34,
@@ -43,6 +45,7 @@
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
id.uuid = VisualizerUUID;
mIdentityList.push_back(id);
+#endif
}
ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type,
@@ -56,4 +59,28 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Factory::createEffect(
+ const AudioUuid& in_impl_uuid,
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return) {
+ LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
+ if (in_impl_uuid == EqualizerUUID) {
+ *_aidl_return = ndk::SharedRefBase::make<Equalizer>();
+ } else {
+ LOG(ERROR) << __func__ << ": UUID "
+ << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Factory::destroyEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle) {
+ if (in_handle) {
+ // TODO: b/245393900 need check the instance state with IEffect.getState before destroy.
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index 3b3c39b..b30f2e7 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -23,10 +23,11 @@
int main() {
// This is a debug implementation, always enable debug logging.
android::base::SetMinimumLogSeverity(::android::base::DEBUG);
- ABinderProcess_setThreadPoolMaxThreadCount(16);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
auto effectFactory =
ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+
std::string serviceName = std::string() + effectFactory->descriptor + "/default";
binder_status_t status =
AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index af033d0..deaca49 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -43,6 +43,7 @@
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::PcmType;
using android::hardware::audio::common::getFrameSizeInBytes;
+using android::hardware::audio::common::isBitPositionFlagSet;
namespace aidl::android::hardware::audio::core {
@@ -125,11 +126,11 @@
}
const auto& flags = portConfigIt->flags.value();
if ((flags.getTag() == AudioIoFlags::Tag::input &&
- (flags.get<AudioIoFlags::Tag::input>() &
- 1 << static_cast<int32_t>(AudioInputFlags::MMAP_NOIRQ)) == 0) ||
+ !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::MMAP_NOIRQ)) ||
(flags.getTag() == AudioIoFlags::Tag::output &&
- (flags.get<AudioIoFlags::Tag::output>() &
- 1 << static_cast<int32_t>(AudioOutputFlags::MMAP_NOIRQ)) == 0)) {
+ !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::MMAP_NOIRQ))) {
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
@@ -478,9 +479,9 @@
<< " does not correspond to an output mix port";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if ((port->flags.get<AudioIoFlags::Tag::output>() &
- 1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0 &&
- !in_args.offloadInfo.has_value()) {
+ const bool isOffload = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD);
+ if (isOffload && !in_args.offloadInfo.has_value()) {
LOG(ERROR) << __func__ << ": port id " << port->id
<< " has COMPRESS_OFFLOAD flag set, requires offload info";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
index 01c0e6e..68bbf5b 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
@@ -2,7 +2,7 @@
class hal
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
- group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+ group audio media
capabilities BLOCK_SUSPEND
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
new file mode 100644
index 0000000..b842149
--- /dev/null
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+ name: "libequalizer",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libstagefright_foundation",
+ ],
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ ],
+ include_dirs: ["hardware/interfaces/audio/aidl/default/include/equalizer-impl"],
+ srcs: [
+ "Equalizer.cpp",
+ ],
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
new file mode 100644
index 0000000..dae3ab7
--- /dev/null
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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_Equalizer"
+#include <android-base/logging.h>
+
+#include "Equalizer.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+Equalizer::Equalizer() {
+ // Implementation UUID
+ mDesc.common.id.uuid = {static_cast<int32_t>(0xce772f20),
+ 0x847d,
+ 0x11df,
+ 0xbb17,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+}
+
+ndk::ScopedAStatus Equalizer::open() {
+ LOG(DEBUG) << __func__;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Equalizer::close() {
+ LOG(DEBUG) << __func__;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Equalizer::getDescriptor(Descriptor* _aidl_return) {
+ LOG(DEBUG) << __func__ << "descriptor " << mDesc.toString();
+ *_aidl_return = mDesc;
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 816cdb1..488edf1 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -229,10 +229,9 @@
}
void setStreamIsConnected(bool connected) {
std::visit(
- [&](auto&& ws) -> bool {
+ [&](auto&& ws) {
auto s = ws.lock();
if (s) s->setIsConnected(connected);
- return !!s;
},
mStream);
}
@@ -253,7 +252,7 @@
}
void insert(int32_t portId, int32_t portConfigId, StreamWrapper sw) {
mStreams.insert(std::pair{portConfigId, sw});
- mStreams.insert(std::pair{portId, sw});
+ mStreams.insert(std::pair{portId, std::move(sw)});
}
void setStreamIsConnected(int32_t portConfigId, bool connected) {
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 7670250..8da5525 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -40,6 +40,28 @@
const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
std::vector<Descriptor::Identity>* out_descriptor) override;
+ /**
+ * @brief Create an effect instance for a certain implementation (identified by UUID).
+ *
+ * @param in_impl_uuid Effect implementation UUID.
+ * @param _aidl_return A pointer to created effect instance.
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus createEffect(
+ const ::aidl::android::media::audio::common::AudioUuid& in_impl_uuid,
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return)
+ override;
+
+ /**
+ * @brief Destroy an effect instance.
+ *
+ * @param in_handle Effect instance handle.
+ * @return ndk::ScopedAStatus
+ */
+ ndk::ScopedAStatus destroyEffect(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle)
+ override;
+
private:
// List of effect descriptors supported by the devices.
std::vector<Descriptor::Identity> mIdentityList;
diff --git a/audio/aidl/default/include/equalizer-impl/Equalizer.h b/audio/aidl/default/include/equalizer-impl/Equalizer.h
index 86f8c3a..44b1d6d 100644
--- a/audio/aidl/default/include/equalizer-impl/Equalizer.h
+++ b/audio/aidl/default/include/equalizer-impl/Equalizer.h
@@ -16,16 +16,28 @@
#pragma once
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <cstdlib>
namespace aidl::android::hardware::audio::effect {
// Equalizer implementation UUID.
static const ::aidl::android::media::audio::common::AudioUuid EqualizerUUID = {
- static_cast<int32_t>(0xce772f20),
- 0x847d,
- 0x11df,
- 0xbb17,
+ static_cast<int32_t>(0x0bed4300),
+ 0xddd6,
+ 0x11db,
+ 0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-} // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
+class Equalizer : public BnEffect {
+ public:
+ Equalizer();
+ ndk::ScopedAStatus open() override;
+ ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+
+ private:
+ // Effect descriptor.
+ Descriptor mDesc = {.common.id.type = EqualizerUUID};
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index e36ab4a..33c5b72 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
#include <chrono>
+#include <Utils.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -39,14 +40,15 @@
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::AudioUsage;
using aidl::android::media::audio::common::Int;
+using android::hardware::audio::common::isBitPositionFlagSet;
// static
std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
const AudioPortConfig& portConfig) {
if (portConfig.flags.has_value() &&
portConfig.flags.value().getTag() == AudioIoFlags::Tag::output &&
- (portConfig.flags.value().get<AudioIoFlags::Tag::output>() &
- 1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) {
+ isBitPositionFlagSet(portConfig.flags.value().get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD)) {
AudioOffloadInfo offloadInfo;
offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
offloadInfo.base.channelMask = portConfig.channelMask.value();
@@ -123,6 +125,23 @@
return result;
}
+std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
+ std::vector<AudioPort> result;
+ const auto mixPorts = getMixPorts(false /*isInput*/);
+ auto offloadPortIt = mixPorts.begin();
+ while (offloadPortIt != mixPorts.end()) {
+ offloadPortIt = std::find_if(offloadPortIt, mixPorts.end(), [&](const AudioPort& port) {
+ return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD) &&
+ (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
+ });
+ if (offloadPortIt == mixPorts.end()) break;
+ result.push_back(*offloadPortIt++);
+ if (singlePort) break;
+ }
+ return result;
+}
+
std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
bool isInput, const AudioPortConfig& mixPortConfig) const {
const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index 552f971..dc109a7 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -48,6 +48,8 @@
std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
return isInput ? getInputMixPorts() : getOutputMixPorts();
}
+ std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
+ bool attachedOnly, bool singlePort) const;
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
new file mode 100644
index 0000000..2fc109a
--- /dev/null
+++ b/audio/aidl/vts/TestUtils.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <iostream>
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest_pred_impl.h>
+
+namespace ndk {
+
+std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
+ str << status.getDescription();
+ return str;
+}
+
+} // namespace ndk
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+ if (status.isOk()) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected the transaction \'" << expr << "\' to succeed\n"
+ << " but it has failed with: " << status;
+}
+
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+ int32_t expected,
+ const ::ndk::ScopedAStatus& status) {
+ if (status.getExceptionCode() == expected) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected the transaction \'" << act_expr << "\' to fail with " << exp_expr
+ << "\n but is has completed with: " << status;
+}
+
+} // namespace detail
+
+} // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define ASSERT_IS_OK(ret) \
+ ASSERT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+#define EXPECT_IS_OK(ret) \
+ EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+// Test that the transaction status is as expected.
+#define ASSERT_STATUS(expected, ret) \
+ ASSERT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+ expected, ret)
+#define EXPECT_STATUS(expected, ret) \
+ EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+ expected, ret)
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index ab70ec4..2381200 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -26,6 +26,7 @@
#include <android-base/logging.h>
#include <StreamWorker.h>
+#include <Utils.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/core/IConfig.h>
@@ -37,6 +38,7 @@
#include "AudioHalBinderServiceUtil.h"
#include "ModuleConfig.h"
+#include "TestUtils.h"
using namespace android;
using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
@@ -64,17 +66,11 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using android::hardware::audio::common::isBitPositionFlagSet;
using android::hardware::audio::common::StreamLogic;
using android::hardware::audio::common::StreamWorker;
using ndk::ScopedAStatus;
-namespace ndk {
-std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
- str << status.getDescription();
- return str;
-}
-} // namespace ndk
-
template <typename T>
auto findById(std::vector<T>& v, int32_t id) {
return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
@@ -97,20 +93,6 @@
return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
}
-template <typename T>
-struct IsInput {
- constexpr operator bool() const;
-};
-
-template <>
-constexpr IsInput<IStreamIn>::operator bool() const {
- return true;
-}
-template <>
-constexpr IsInput<IStreamOut>::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 {
@@ -125,14 +107,10 @@
WithDebugFlags& operator=(const WithDebugFlags&) = delete;
~WithDebugFlags() {
if (mModule != nullptr) {
- ScopedAStatus status = mModule->setModuleDebug(mInitial);
- EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+ EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
}
}
- void SetUp(IModule* module) {
- ScopedAStatus status = module->setModuleDebug(mFlags);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
ModuleDebug& flags() { return mFlags; }
private:
@@ -153,9 +131,7 @@
WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
~WithAudioPortConfig() {
if (mModule != nullptr) {
- ScopedAStatus status = mModule->resetAudioPortConfig(getId());
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; port config id " << getId();
+ EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
}
}
void SetUp(IModule* module) {
@@ -174,9 +150,8 @@
if (mInitialConfig.id == 0) {
AudioPortConfig suggested;
bool applied = false;
- ScopedAStatus status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; Config: " << mInitialConfig.toString();
+ ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
+ << "Config: " << mInitialConfig.toString();
if (!applied && negotiate) {
mInitialConfig = suggested;
ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
@@ -209,9 +184,7 @@
void TearDown() override {
if (module != nullptr) {
- ScopedAStatus status = module->setModuleDebug(ModuleDebug{});
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned when resetting debug flags";
+ EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
}
}
@@ -234,8 +207,7 @@
ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
EXPECT_EQ(config.portId, portConfig.get().portId);
std::vector<AudioPortConfig> retrievedPortConfigs;
- ScopedAStatus status = module->getAudioPortConfigs(&retrievedPortConfigs);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+ ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
const int32_t portConfigId = portConfig.getId();
auto configIt = std::find_if(
retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
@@ -258,10 +230,7 @@
ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
const std::string& errorMessage) {
std::vector<Entity> entities;
- {
- ScopedAStatus status = (module.get()->*getter)(&entities);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
std::transform(entities.begin(), entities.end(),
std::inserter(*entityIds, entityIds->begin()),
[](const auto& entity) { return entity.id; });
@@ -309,16 +278,13 @@
WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
~WithDevicePortConnectedState() {
if (mModule != nullptr) {
- ScopedAStatus status = mModule->disconnectExternalDevice(getId());
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned when disconnecting device port ID " << getId();
+ EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
+ << "when disconnecting device port ID " << getId();
}
}
void SetUp(IModule* module) {
- ScopedAStatus status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned when connecting device port ID & data "
- << mIdAndData.toString();
+ ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+ << "when connecting device port ID & data " << mIdAndData.toString();
ASSERT_NE(mIdAndData.id, getId())
<< "ID of the connected port must not be the same as the ID of the template port";
mModule = module;
@@ -556,9 +522,7 @@
~WithStream() {
if (mStream != nullptr) {
mContext.reset();
- ScopedAStatus status = mStream->close();
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; port config id " << getPortId();
+ EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
}
}
void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
@@ -569,10 +533,8 @@
long bufferSizeFrames);
void SetUp(IModule* module, long bufferSizeFrames) {
ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
- ScopedAStatus status = SetUpNoChecks(module, bufferSizeFrames);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; port config id " << getPortId();
- ASSERT_NE(nullptr, mStream) << "; port config id " << getPortId();
+ ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
+ ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
<< "actual buffer size must be no less than requested";
mContext.emplace(mDescriptor);
@@ -660,8 +622,7 @@
WithAudioPatch& operator=(const WithAudioPatch&) = delete;
~WithAudioPatch() {
if (mModule != nullptr && mPatch.id != 0) {
- ScopedAStatus status = mModule->resetAudioPatch(mPatch.id);
- EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; patch id " << getId();
+ EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
}
}
void SetUpPortConfigs(IModule* module) {
@@ -676,10 +637,8 @@
}
void SetUp(IModule* module) {
ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
- ScopedAStatus status = SetUpNoChecks(module);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; source port config id " << mSrcPortConfig.getId()
- << "; sink port config id " << mSinkPortConfig.getId();
+ ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
+ << "; sink port config id " << mSinkPortConfig.getId();
EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
for (auto latencyMs : mPatch.latenciesMs) {
EXPECT_GT(latencyMs, 0) << "patch id " << getId();
@@ -715,15 +674,9 @@
TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
std::vector<AudioPort> ports1;
- {
- ScopedAStatus status = module->getAudioPorts(&ports1);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&ports1));
std::vector<AudioPort> ports2;
- {
- ScopedAStatus status = module->getAudioPorts(&ports2);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&ports2));
ASSERT_EQ(ports1.size(), ports2.size())
<< "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
std::sort(ports1.begin(), ports1.end());
@@ -733,15 +686,9 @@
TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
std::vector<AudioRoute> routes1;
- {
- ScopedAStatus status = module->getAudioRoutes(&routes1);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routes1));
std::vector<AudioRoute> routes2;
- {
- ScopedAStatus status = module->getAudioRoutes(&routes2);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routes2));
ASSERT_EQ(routes1.size(), routes2.size())
<< "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
std::sort(routes1.begin(), routes1.end());
@@ -751,10 +698,7 @@
TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
std::vector<AudioRoute> routes;
- {
- ScopedAStatus status = module->getAudioRoutes(&routes);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
for (const auto& route : routes) {
std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
EXPECT_NE(0UL, sources.size())
@@ -769,10 +713,7 @@
std::set<int32_t> portIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
std::vector<AudioRoute> routes;
- {
- ScopedAStatus status = module->getAudioRoutes(&routes);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routes));
for (const auto& route : routes) {
EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
<< route.sinkPortId << " sink port id is unknown";
@@ -790,8 +731,7 @@
}
for (const auto portId : portIds) {
std::vector<AudioRoute> routes;
- ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
- EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+ EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
for (const auto& r : routes) {
if (r.sinkPortId != portId) {
const auto& srcs = r.sourcePortIds;
@@ -802,18 +742,14 @@
}
for (const auto portId : GetNonExistentIds(portIds)) {
std::vector<AudioRoute> routes;
- ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port ID " << portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
+ << "port ID " << portId;
}
}
TEST_P(AudioCoreModule, CheckDevicePorts) {
std::vector<AudioPort> ports;
- {
- ScopedAStatus status = module->getAudioPorts(&ports);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
std::optional<int32_t> defaultOutput, defaultInput;
std::set<AudioDevice> inputs, outputs;
const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
@@ -859,17 +795,14 @@
TEST_P(AudioCoreModule, CheckMixPorts) {
std::vector<AudioPort> ports;
- {
- ScopedAStatus status = module->getAudioPorts(&ports);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
std::optional<int32_t> primaryMixPort;
- constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
for (const auto& port : ports) {
if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
if (port.flags.getTag() == AudioIoFlags::Tag::output &&
- ((port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0)) {
+ isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY)) {
EXPECT_FALSE(primaryMixPort.has_value())
<< "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
<< " and " << port.id;
@@ -889,15 +822,13 @@
}
for (const auto portId : portIds) {
AudioPort port;
- ScopedAStatus status = module->getAudioPort(portId, &port);
- EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+ EXPECT_IS_OK(module->getAudioPort(portId, &port));
EXPECT_EQ(portId, port.id);
}
for (const auto portId : GetNonExistentIds(portIds)) {
AudioPort port;
- ScopedAStatus status = module->getAudioPort(portId, &port);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port ID " << portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
+ << "port ID " << portId;
}
}
@@ -929,9 +860,8 @@
portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
// Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
AudioPort connectedPort;
- ScopedAStatus status = module->getAudioPort(connectedPortId, &connectedPort);
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned for getAudioPort port ID " << connectedPortId;
+ EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
+ << "port ID " << connectedPortId;
EXPECT_EQ(portConnected.get(), connectedPort);
const auto& portProfiles = connectedPort.profiles;
EXPECT_NE(0UL, portProfiles.size())
@@ -944,10 +874,7 @@
<< "profiles: " << connectedPort.toString();
std::vector<AudioPort> allPorts;
- {
- ScopedAStatus status = module->getAudioPorts(&allPorts);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&allPorts));
const auto allPortsIt = findById(allPorts, connectedPortId);
EXPECT_NE(allPorts.end(), allPortsIt);
if (allPortsIt != allPorts.end()) {
@@ -965,9 +892,8 @@
args.portConfigId = portConfigId;
args.bufferSizeFrames = kDefaultBufferSizeFrames;
aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
- ScopedAStatus status = module->openInputStream(args, &ret);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " openInputStream returned for port config ID " << portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
+ << "port config ID " << portConfigId;
EXPECT_EQ(nullptr, ret.stream);
}
{
@@ -975,9 +901,8 @@
args.portConfigId = portConfigId;
args.bufferSizeFrames = kDefaultBufferSizeFrames;
aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
- ScopedAStatus status = module->openOutputStream(args, &ret);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " openOutputStream returned for port config ID " << portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "port config ID " << portConfigId;
EXPECT_EQ(nullptr, ret.stream);
}
}
@@ -992,10 +917,7 @@
std::set<int32_t> portIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
std::vector<AudioPortConfig> portConfigs;
- {
- ScopedAStatus status = module->getAudioPortConfigs(&portConfigs);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
for (const auto& config : portConfigs) {
EXPECT_EQ(1UL, portIds.count(config.portId))
<< config.portId << " port id is unknown, config id " << config.id;
@@ -1006,9 +928,8 @@
std::set<int32_t> portConfigIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
- ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port config ID " << portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
}
}
@@ -1016,21 +937,13 @@
// the config does not delete it, but brings it back to the initial config.
TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
std::vector<AudioPortConfig> portConfigsBefore;
- {
- ScopedAStatus status = module->getAudioPortConfigs(&portConfigsBefore);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
// TODO: Change port configs according to port profiles.
for (const auto& c : portConfigsBefore) {
- ScopedAStatus status = module->resetAudioPortConfig(c.id);
- EXPECT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned for port config ID " << c.id;
+ EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
}
std::vector<AudioPortConfig> portConfigsAfter;
- {
- ScopedAStatus status = module->getAudioPortConfigs(&portConfigsAfter);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
for (const auto& c : portConfigsBefore) {
auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
EXPECT_NE(portConfigsAfter.end(), afterIt)
@@ -1052,9 +965,8 @@
portConfig.portId = srcMixPort.value().id;
{
bool applied = true;
- ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << "; Config: " << portConfig.toString();
+ ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "Config: " << portConfig.toString();
EXPECT_FALSE(applied);
}
EXPECT_EQ(0, suggestedConfig.id);
@@ -1108,9 +1020,9 @@
AudioPortConfig portConfig, suggestedConfig;
bool applied;
portConfig.portId = portId;
- ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port ID " << portId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port ID " << portId;
EXPECT_FALSE(suggestedConfig.format.has_value());
EXPECT_FALSE(suggestedConfig.channelMask.has_value());
EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
@@ -1124,9 +1036,9 @@
AudioPortConfig portConfig, suggestedConfig;
bool applied;
portConfig.id = portConfigId;
- ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port config ID " << portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+ << "port config ID " << portConfigId;
EXPECT_FALSE(suggestedConfig.format.has_value());
EXPECT_FALSE(suggestedConfig.channelMask.has_value());
EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
@@ -1147,9 +1059,8 @@
AudioPort portWithData = port;
portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
GenerateUniqueDeviceAddress();
- ScopedAStatus status = module->connectExternalDevice(portWithData, &ignored);
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " returned for static port " << portWithData.toString();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "static port " << portWithData.toString();
}
}
@@ -1163,10 +1074,8 @@
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
ModuleDebug midwayDebugChange = debug.flags();
midwayDebugChange.simulateDeviceConnections = false;
- 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";
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
+ << "when trying to disable connections simulation while having a connected device";
}
TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
@@ -1176,40 +1085,28 @@
for (const auto portId : GetNonExistentIds(portIds)) {
AudioPort invalidPort;
invalidPort.id = portId;
- 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(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for port ID " << portId
- << " when setting DISCONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
+ << "port ID " << portId << ", when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
+ << "port ID " << portId << ", when setting DISCONNECTED state";
}
std::vector<AudioPort> ports;
- {
- ScopedAStatus status = module->getAudioPorts(&ports);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioPorts(&ports));
for (const auto& port : ports) {
if (port.ext.getTag() != AudioPortExt::Tag::device) {
- 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(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for non-device port ID " << port.id
- << " when setting DISCONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "non-device port ID " << port.id << " when setting CONNECTED state";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "non-device port ID " << port.id << " when setting DISCONNECTED state";
} else {
const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
if (devicePort.device.type.connection.empty()) {
- ScopedAStatus status = module->connectExternalDevice(port, &ignored);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for permanently attached device port ID " << port.id
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+ << "for a permanently attached device port ID " << port.id
<< " when setting CONNECTED state";
- status = module->disconnectExternalDevice(port.id);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for permanently attached device port ID " << port.id
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "for a permanently attached device port ID " << port.id
<< " when setting DISCONNECTED state";
}
}
@@ -1225,27 +1122,22 @@
GTEST_SKIP() << "No external devices in the module.";
}
for (const auto& port : ports) {
- ScopedAStatus status = module->disconnectExternalDevice(port.id);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned when disconnecting already disconnected device port ID "
- << port.id;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+ << "when disconnecting already disconnected device port ID " << port.id;
AudioPort portWithData = port;
portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
GenerateUniqueDeviceAddress();
WithDevicePortConnectedState portConnected(portWithData);
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- status = module->connectExternalDevice(portConnected.get(), &ignored);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned when trying to connect a connected device port "
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->connectExternalDevice(portConnected.get(), &ignored))
+ << "when trying to connect a connected device port "
<< portConnected.get().toString();
- status = module->connectExternalDevice(portWithData, &ignored);
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " returned when connecting again the external device "
- << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString();
- if (status.getExceptionCode() == EX_NONE) {
- ADD_FAILURE() << "Returned connected port " << ignored.toString() << " for template "
- << portWithData.toString();
- }
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+ << "when connecting again the external device "
+ << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
+ << "; Returned connected port " << ignored.toString() << " for template "
+ << portWithData.toString();
}
}
@@ -1266,9 +1158,8 @@
// 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()));
- ScopedAStatus status = module->disconnectExternalDevice(portConnected.getId());
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " returned when trying to disconnect device port ID " << port.id
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
+ << "when trying to disconnect device port ID " << port.id
<< " with active configuration " << config.getId();
}
}
@@ -1282,10 +1173,7 @@
}
for (const auto& port : ports) {
std::vector<AudioRoute> routesBefore;
- {
- ScopedAStatus status = module->getAudioRoutes(&routesBefore);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
int32_t connectedPortId;
{
@@ -1293,34 +1181,24 @@
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
connectedPortId = portConnected.getId();
std::vector<AudioRoute> connectedPortRoutes;
- {
- ScopedAStatus status =
- module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes);
- ASSERT_EQ(EX_NONE, status.getExceptionCode())
- << status << " returned when retrieving routes for connected port id "
- << connectedPortId;
- }
+ ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
+ << "when retrieving routes for connected port id " << connectedPortId;
// There must be routes for the port to be useful.
if (connectedPortRoutes.empty()) {
std::vector<AudioRoute> allRoutes;
- ScopedAStatus status = module->getAudioRoutes(&allRoutes);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+ ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
ADD_FAILURE() << " no routes returned for the connected port "
<< portConnected.get().toString()
<< "; all routes: " << android::internal::ToString(allRoutes);
}
}
std::vector<AudioRoute> ignored;
- ScopedAStatus status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored);
- ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned when retrieving routes for released connected port id "
- << connectedPortId;
+ ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
+ << "when retrieving routes for released connected port id " << connectedPortId;
std::vector<AudioRoute> routesAfter;
- {
- ScopedAStatus status = module->getAudioRoutes(&routesAfter);
- ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
- }
+ ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
ASSERT_EQ(routesBefore.size(), routesAfter.size())
<< "Sizes of audio route arrays do not match after creating and "
<< "releasing a connected port";
@@ -1333,8 +1211,6 @@
template <typename Stream>
class AudioStream : public AudioCoreModule {
public:
- static std::string direction(bool capitalize);
-
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
@@ -1351,9 +1227,7 @@
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
heldStream = stream.getSharedPointer();
}
- ScopedAStatus status = heldStream->close();
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " when closing the stream twice";
+ EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
}
void OpenAllConfigs() {
@@ -1375,10 +1249,8 @@
// The buffer size of 1 frame should be impractically small, and thus
// less than any minimum buffer size suggested by any HAL.
for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
- ScopedAStatus status = stream.SetUpNoChecks(module.get(), bufferSize);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " open" << direction(true) << "Stream returned for " << bufferSize
- << " buffer size";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
+ << "for the buffer size " << bufferSize;
EXPECT_EQ(nullptr, stream.get());
}
}
@@ -1392,10 +1264,9 @@
}
WithStream<Stream> stream(portConfig.value());
ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- ScopedAStatus status = stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " open" << direction(true) << "Stream returned for port config ID "
- << stream.getPortId();
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId();
EXPECT_EQ(nullptr, stream.get());
}
@@ -1424,18 +1295,15 @@
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
} else {
ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
- ScopedAStatus status =
- stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " open" << direction(true)
- << "Stream returned for port config ID " << stream.getPortId()
- << ", maxOpenStreamCount is " << maxStreamCount;
+ EXPECT_STATUS(EX_ILLEGAL_STATE,
+ stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+ << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
+ << maxStreamCount;
}
}
}
if (!hasSingleRun) {
- GTEST_SKIP() << "Not enough " << direction(false)
- << " ports to test max open stream count";
+ GTEST_SKIP() << "Not enough ports to test max open stream count";
}
}
@@ -1447,14 +1315,15 @@
EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
}
- void ReadOrWrite(bool useImpl2, bool testObservablePosition) {
+ void ReadOrWrite(bool useSetupSequence2, bool validateObservablePosition) {
const auto allPortConfigs =
moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
if (allPortConfigs.empty()) {
GTEST_SKIP() << "No mix ports have attached devices";
}
for (const auto& portConfig : allPortConfigs) {
- EXPECT_NO_FATAL_FAILURE(ReadOrWriteImpl(portConfig, useImpl2, testObservablePosition))
+ EXPECT_NO_FATAL_FAILURE(
+ ReadOrWriteImpl(portConfig, useSetupSequence2, validateObservablePosition))
<< portConfig.toString();
}
}
@@ -1466,9 +1335,8 @@
}
WithStream<Stream> stream(portConfig.value());
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId());
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " returned for port config ID " << stream.getPortId();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
+ << "port config ID " << stream.getPortId();
}
void SendInvalidCommand() {
@@ -1483,11 +1351,10 @@
WithStream<Stream> stream1(portConfig);
ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
WithStream<Stream> stream2;
- ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
- kDefaultBufferSizeFrames);
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " when opening " << direction(false)
- << " stream twice for the same port config ID " << stream1.getPortId();
+ EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+ kDefaultBufferSizeFrames))
+ << "when opening a stream twice for the same port config ID "
+ << stream1.getPortId();
}
template <class Worker>
@@ -1510,17 +1377,20 @@
EXPECT_GT(frames, framesInitial);
}
- void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useImpl2,
- bool testObservablePosition) {
- if (!useImpl2) {
- ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl1(portConfig, testObservablePosition));
+ void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useSetupSequence2,
+ bool validateObservablePosition) {
+ if (!useSetupSequence2) {
+ ASSERT_NO_FATAL_FAILURE(
+ ReadOrWriteSetupSequence1(portConfig, validateObservablePosition));
} else {
- ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl2(portConfig, testObservablePosition));
+ ASSERT_NO_FATAL_FAILURE(
+ ReadOrWriteSetupSequence2(portConfig, validateObservablePosition));
}
}
// Set up a patch first, then open a stream.
- void ReadOrWriteImpl1(const AudioPortConfig& portConfig, bool testObservablePosition) {
+ void ReadOrWriteSetupSequence1(const AudioPortConfig& portConfig,
+ bool validateObservablePosition) {
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
@@ -1534,13 +1404,14 @@
ASSERT_TRUE(worker.start());
ASSERT_TRUE(worker.waitForAtLeastOneCycle());
- if (testObservablePosition) {
+ if (validateObservablePosition) {
ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
}
}
// Open a stream, then set up a patch for it.
- void ReadOrWriteImpl2(const AudioPortConfig& portConfig, bool testObservablePosition) {
+ void ReadOrWriteSetupSequence2(const AudioPortConfig& portConfig,
+ bool validateObservablePosition) {
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
typename IOTraits<Stream>::Worker worker(*stream.getContext());
@@ -1554,7 +1425,7 @@
ASSERT_TRUE(worker.start());
ASSERT_TRUE(worker.waitForAtLeastOneCycle());
- if (testObservablePosition) {
+ if (validateObservablePosition) {
ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
}
}
@@ -1583,15 +1454,6 @@
using AudioStreamIn = AudioStream<IStreamIn>;
using AudioStreamOut = AudioStream<IStreamOut>;
-template <>
-std::string AudioStreamIn::direction(bool capitalize) {
- return capitalize ? "Input" : "input";
-}
-template <>
-std::string AudioStreamOut::direction(bool capitalize) {
- return capitalize ? "Output" : "output";
-}
-
#define TEST_IO_STREAM(method_name) \
TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
@@ -1609,19 +1471,24 @@
TEST_IO_STREAM(OpenInvalidDirection);
TEST_IO_STREAM(OpenOverMaxCount);
TEST_IO_STREAM(OpenTwiceSamePortConfig);
-TEST_IO_STREAM_2(ReadOrWrite, false, false);
-TEST_IO_STREAM_2(ReadOrWrite, true, false);
-TEST_IO_STREAM_2(ReadOrWrite, false, true);
-TEST_IO_STREAM_2(ReadOrWrite, true, true);
+// Use of constants makes comprehensible test names.
+constexpr bool SetupSequence1 = false;
+constexpr bool SetupSequence2 = true;
+constexpr bool SetupOnly = false;
+constexpr bool ValidateObservablePosition = true;
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, SetupOnly);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, SetupOnly);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, ValidateObservablePosition);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, ValidateObservablePosition);
TEST_IO_STREAM(ResetPortConfigWithOpenStream);
TEST_IO_STREAM(SendInvalidCommand);
TEST_P(AudioStreamOut, OpenTwicePrimary) {
const auto mixPorts = moduleConfig->getMixPorts(false);
auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
- constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
return port.flags.getTag() == AudioIoFlags::Tag::output &&
- (port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0;
+ isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::PRIMARY);
});
if (primaryPortIt == mixPorts.end()) {
GTEST_SKIP() << "No primary mix port";
@@ -1635,19 +1502,14 @@
}
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<int>(AudioOutputFlags::COMPRESS_OFFLOAD);
- return port.flags.getTag() == AudioIoFlags::Tag::output &&
- (port.flags.get<AudioIoFlags::Tag::output>() & compressOffloadFlag) != 0 &&
- !moduleConfig->getAttachedSinkDevicesPortsForMixPort(port).empty();
- });
- if (offloadPortIt == mixPorts.end()) {
+ const auto offloadMixPorts =
+ moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+ if (offloadMixPorts.empty()) {
GTEST_SKIP()
<< "No mix port for compressed offload that could be routed to attached devices";
}
- const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt);
+ const auto portConfig =
+ moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
ASSERT_TRUE(portConfig.has_value())
<< "No profiles specified for the compressed offload mix port";
StreamDescriptor descriptor;
@@ -1657,10 +1519,8 @@
args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
args.bufferSizeFrames = kDefaultBufferSizeFrames;
aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
- ScopedAStatus status = module->openOutputStream(args, &ret);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status
- << " returned when no offload info is provided for a compressed offload mix port";
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+ << "when no offload info is provided for a compressed offload mix port";
}
// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
@@ -1681,9 +1541,8 @@
AudioPatch patch;
patch.sourcePortConfigIds = sources;
patch.sinkPortConfigIds = sinks;
- ScopedAStatus status = module->setAudioPatch(patch, &patch);
- ASSERT_EQ(expectedException, status.getExceptionCode())
- << status << ": patch source ids: " << android::internal::ToString(sources)
+ ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
+ << "patch source ids: " << android::internal::ToString(sources)
<< "; sink ids: " << android::internal::ToString(sinks);
}
@@ -1701,9 +1560,8 @@
patch.get().sinkPortConfigIds.begin(),
patch.get().sinkPortConfigIds.end());
for (const auto portConfigId : sourceAndSinkPortConfigIds) {
- ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
- EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
- << status << " returned for port config ID " << portConfigId;
+ EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
+ << "port config ID " << portConfigId;
}
}
@@ -1748,10 +1606,8 @@
}
WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
- 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 "
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
+ << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
<< srcSinkPair.value().second.toString() << " that does not have a route";
}
@@ -1807,10 +1663,9 @@
for (const auto patchId : GetNonExistentIds(patchIds)) {
AudioPatch patchWithNonExistendId = patch.get();
patchWithNonExistendId.id = patchId;
- ScopedAStatus status =
- module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for patch ID " << patchId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+ module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
+ << "patch ID " << patchId;
}
}
};
@@ -1832,9 +1687,8 @@
std::set<int32_t> patchIds;
ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
for (const auto patchId : GetNonExistentIds(patchIds)) {
- ScopedAStatus status = module->resetAudioPatch(patchId);
- EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
- << status << " returned for patch ID " << patchId;
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
+ << "patch ID " << patchId;
}
}
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index f70948c..9b100b1 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#include <memory>
#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
#define LOG_TAG "VtsHalAudioEffect"
@@ -35,37 +39,88 @@
using ndk::ScopedAStatus;
using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::media::audio::common::AudioUuid;
-namespace ndk {
-std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
- str << status.getDescription();
- return str;
-}
-} // namespace ndk
-
-class EffectFactory : public testing::TestWithParam<std::string> {
+class EffectFactoryHelper {
public:
- void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+ EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
- void TearDown() override {}
-
- void ConnectToService() {
- serviceName = GetParam();
- factory = IFactory::fromBinder(binderUtil.connectToService(serviceName));
- ASSERT_NE(factory, nullptr);
+ void ConnectToFactoryService() {
+ mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
+ ASSERT_NE(mEffectFactory, nullptr);
}
- void RestartService() {
- ASSERT_NE(factory, nullptr);
- factory = IFactory::fromBinder(binderUtil.restartService());
- ASSERT_NE(factory, nullptr);
+ void RestartFactoryService() {
+ ASSERT_NE(mEffectFactory, nullptr);
+ mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
+ ASSERT_NE(mEffectFactory, nullptr);
}
- std::shared_ptr<IFactory> factory;
- std::string serviceName;
+ void QueryAllEffects() {
+ EXPECT_NE(mEffectFactory, nullptr);
+ ScopedAStatus status =
+ mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ }
+
+ void QueryEffects(const std::optional<AudioUuid>& in_type,
+ const std::optional<AudioUuid>& in_instance,
+ std::vector<Descriptor::Identity>* _aidl_return) {
+ EXPECT_NE(mEffectFactory, nullptr);
+ ScopedAStatus status = mEffectFactory->queryEffects(in_type, in_instance, _aidl_return);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ mIds = *_aidl_return;
+ }
+
+ void CreateEffects() {
+ EXPECT_NE(mEffectFactory, nullptr);
+ ScopedAStatus status;
+ for (const auto& id : mIds) {
+ std::shared_ptr<IEffect> effect;
+ status = mEffectFactory->createEffect(id.uuid, &effect);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE) << id.toString();
+ EXPECT_NE(effect, nullptr) << id.toString();
+ mEffectIdMap[effect] = id;
+ }
+ }
+
+ void DestroyEffects() {
+ EXPECT_NE(mEffectFactory, nullptr);
+ ScopedAStatus status;
+ for (const auto& it : mEffectIdMap) {
+ status = mEffectFactory->destroyEffect(it.first);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE) << it.second.toString();
+ }
+ mEffectIdMap.clear();
+ }
+
+ std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
+ const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
+ const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() { return mCompleteIds; }
+ const std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() {
+ return mEffectIdMap;
+ }
+
+ private:
+ std::shared_ptr<IFactory> mEffectFactory;
+ std::string mServiceName;
AudioHalBinderServiceUtil binderUtil;
+ std::vector<Descriptor::Identity> mIds;
+ std::vector<Descriptor::Identity> mCompleteIds;
+ std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
+};
+
+/// Effect factory testing.
+class EffectFactoryTest : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); }
+
+ void TearDown() override { mFactory.DestroyEffects(); }
+
+ EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
+
// TODO: these UUID can get from config file
// ec7178ec-e5e1-4432-a3f4-4657e6795210
const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
@@ -77,25 +132,23 @@
static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
};
-TEST_P(EffectFactory, SetupAndTearDown) {
+TEST_P(EffectFactoryTest, SetupAndTearDown) {
// Intentionally empty test body.
}
-TEST_P(EffectFactory, CanBeRestarted) {
- ASSERT_NO_FATAL_FAILURE(RestartService());
+TEST_P(EffectFactoryTest, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
}
-TEST_P(EffectFactory, QueriedDescriptorList) {
+TEST_P(EffectFactoryTest, QueriedDescriptorList) {
std::vector<Descriptor::Identity> descriptors;
- ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
- EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
EXPECT_NE(static_cast<int>(descriptors.size()), 0);
}
-TEST_P(EffectFactory, DescriptorUUIDNotNull) {
+TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
std::vector<Descriptor::Identity> descriptors;
- ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
- EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
// TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
for (auto& desc : descriptors) {
EXPECT_NE(desc.type, zeroUuid);
@@ -103,28 +156,176 @@
}
}
-TEST_P(EffectFactory, QueriedDescriptorNotExistType) {
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
std::vector<Descriptor::Identity> descriptors;
- ScopedAStatus status = factory->queryEffects(nullUuid, std::nullopt, &descriptors);
- EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
}
-TEST_P(EffectFactory, QueriedDescriptorNotExistInstance) {
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
std::vector<Descriptor::Identity> descriptors;
- ScopedAStatus status = factory->queryEffects(std::nullopt, nullUuid, &descriptors);
- EXPECT_EQ(EX_NONE, status.getExceptionCode());
+ mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
}
-INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactory,
+TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
+ std::vector<Descriptor::Identity> descriptors;
+ mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+ int numIds = static_cast<int>(mFactory.GetEffectIds().size());
+ EXPECT_NE(numIds, 0);
+
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ mFactory.CreateEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ mFactory.DestroyEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+
+ // Create and destroy again
+ mFactory.CreateEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ mFactory.DestroyEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+}
+
+TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
+ std::vector<Descriptor::Identity> descriptors;
+ mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+ int numIds = static_cast<int>(mFactory.GetEffectIds().size());
+ EXPECT_NE(numIds, 0);
+
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+ mFactory.CreateEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), numIds);
+ // Create effect instances of same implementation
+ mFactory.CreateEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 2 * numIds);
+
+ mFactory.CreateEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 3 * numIds);
+
+ mFactory.DestroyEffects();
+ EXPECT_EQ(static_cast<int>(mFactory.GetEffectMap().size()), 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactory);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
+
+/// Effect testing.
+class AudioEffect : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService());
+ ASSERT_NO_FATAL_FAILURE(mFactory.CreateEffects());
+ }
+
+ void TearDown() override {
+ CloseEffects();
+ ASSERT_NO_FATAL_FAILURE(mFactory.DestroyEffects());
+ }
+
+ void OpenEffects() {
+ auto open = [](const std::shared_ptr<IEffect>& effect) {
+ ScopedAStatus status = effect->open();
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ };
+ EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
+ }
+
+ void CloseEffects() {
+ auto close = [](const std::shared_ptr<IEffect>& effect) {
+ ScopedAStatus status = effect->close();
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ };
+ EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+ }
+
+ void GetEffectDescriptors() {
+ auto get = [](const std::shared_ptr<IEffect>& effect) {
+ Descriptor desc;
+ ScopedAStatus status = effect->getDescriptor(&desc);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ };
+ EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+ }
+
+ template <typename Functor>
+ void ForEachEffect(Functor functor) {
+ auto effectMap = mFactory.GetEffectMap();
+ ScopedAStatus status;
+ for (const auto& it : effectMap) {
+ SCOPED_TRACE(it.second.toString());
+ functor(it.first);
+ }
+ }
+
+ EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
+};
+
+TEST_P(AudioEffect, OpenEffectTest) {
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+}
+
+TEST_P(AudioEffect, OpenAndCloseEffect) {
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, CloseUnopenedEffectTest) {
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, DoubleOpenCloseEffects) {
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+
+ EXPECT_NO_FATAL_FAILURE(OpenEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+ EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, GetDescriptors) {
+ EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
+}
+
+TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
+ auto checker = [&](const std::shared_ptr<IEffect>& effect) {
+ Descriptor desc;
+ std::vector<Descriptor::Identity> idList;
+ ScopedAStatus status = effect->getDescriptor(&desc);
+ EXPECT_EQ(status.getExceptionCode(), EX_NONE);
+ mFactory.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
+ EXPECT_EQ(static_cast<int>(idList.size()), 1);
+ };
+ EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
+
+ // Check unique with a set
+ auto stringHash = [](const Descriptor::Identity& id) {
+ return std::hash<std::string>()(id.toString());
+ };
+ auto vec = mFactory.GetCompleteEffectIdList();
+ std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
+ for (auto it : vec) {
+ EXPECT_EQ(static_cast<int>(idSet.count(it)), 0);
+ idSet.insert(it);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
-}
+}
\ No newline at end of file
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 0d3253b..33e211c 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -84,7 +84,10 @@
name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
vendor: true,
defaults: ["vhal_v2_0_target_defaults"],
- cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
+ cflags: [
+ "-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING",
+ "-DENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS",
+ ],
srcs: [
"impl/vhal_v2_0/DefaultVehicleHal.cpp",
"impl/vhal_v2_0/VehicleHalClient.cpp",
@@ -225,6 +228,25 @@
test_suites: ["general-tests"],
}
+cc_test {
+ name: "android.hardware.automotive.vehicle@2.0-default-config-test",
+ vendor: true,
+ defaults: ["vhal_v2_0_target_defaults"],
+ srcs: [
+ "impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp",
+ ],
+ cflags: [
+ "-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING",
+ "-DENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS",
+ ],
+ static_libs: [
+ "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+ "libgtest",
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+}
+
cc_binary {
name: "android.hardware.automotive.vehicle@2.0-default-service",
defaults: ["vhal_v2_0_target_defaults"],
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index edc8949..e803e81 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -1179,6 +1179,47 @@
},
},
#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+#ifdef ENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS
+ {
+ .config =
+ {
+ // SUPPORTED_PROPERTY_IDS
+ .prop = 289476424,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::STATIC,
+ // Fetch 100 configs in one request. This number is just arbitrarily
+ // chosen here. But some HAL impl with bigger config data may need a
+ // smaller number to make sure the configs returned in one request
+ // fits the binder data size limitation.
+ .configArray = {100},
+ },
+ // All supported property IDs. This list is checked by
+ // DefaultConfigSupportedPropertyIds_test.
+ .initialValue =
+ {.int32Values =
+ {291504388, 289472773, 291504390, 289472775, 289407240, 289407241,
+ 289472780, 286261505, 286261506, 289407235, 289472779, 291504647,
+ 289408517, 356518832, 356516106, 291504644, 291504649, 291504656,
+ 291504901, 291504903, 287310600, 291504905, 287310602, 287310603,
+ 291504908, 291504904, 392168201, 392168202, 289408514, 289408001,
+ 287310850, 287310851, 287310853, 289408513, 289475088, 289475104,
+ 289475120, 354419984, 320865540, 320865556, 354419975, 354419976,
+ 354419986, 354419973, 354419974, 354419978, 354419977, 356517120,
+ 356517121, 356582673, 356517139, 289408269, 356517131, 358614275,
+ 291570965, 291505923, 289408270, 289408512, 287310855, 289408000,
+ 289408008, 289408009, 289407747, 291504900, 568332561, 371198722,
+ 373295872, 320867268, 322964416, 290521862, 287310858, 287310859,
+ 289475072, 289475073, 289409539, 299896064, 299896065, 299896066,
+ 299896067, 289410560, 289410561, 289410562, 289410563, 289410576,
+ 289410577, 289410578, 289410579, 289476368, 299895808, 639631617,
+ 627048706, 591397123, 554696964, 289410873, 289410874, 287313669,
+ 299896583, 299896584, 299896585, 299896586, 299896587, 286265121,
+ 286265122, 286265123, 290457094, 290459441, 299896626, 290459443,
+ 289410868, 289476405, 299896630, 289410871, 292556600, 557853201,
+ 559950353, 555756049, 554707473, 289410887, 557846324, 557911861,
+ 568332086, 557846327, 560992056, 289476424}},
+ },
+#endif // ENABLE_GET_PROP_CONFIGS_BY_MULTIPLE_REQUESTS
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp
new file mode 100644
index 0000000..aa05daa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultConfigSupportedPropertyIds_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+#include "vhal_v2_0/DefaultConfig.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+
+using ::testing::ElementsAreArray;
+
+// Test that VHAL_SUPPORTED_PROPERTY_IDS contains all supported property IDs.
+TEST(DefaultConfigSupportedPropertyIdsTest, testIncludeAllSupportedIds) {
+ const int32_t vhalSupportedPropertyIdsPropId = 289476424;
+
+ std::vector<int32_t> allSupportedIds;
+ std::vector<int32_t> configuredSupportedIds;
+
+ for (const auto& property : impl::kVehicleProperties) {
+ int propId = property.config.prop;
+ allSupportedIds.push_back(propId);
+
+ if (propId == vhalSupportedPropertyIdsPropId) {
+ configuredSupportedIds = property.initialValue.int32Values;
+ }
+ }
+
+ ASSERT_THAT(allSupportedIds, ElementsAreArray(configuredSupportedIds));
+}
+
+} // namespace impl
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index 74f5a7a..df5ada6 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -141,7 +141,7 @@
TEST_F(DefaultVhalImplTest, testListProperties) {
std::vector<VehiclePropConfig> configs = mHal->listProperties();
- EXPECT_EQ((size_t)123, configs.size());
+ EXPECT_EQ((size_t)124, configs.size());
}
TEST_F(DefaultVhalImplTest, testGetDefaultPropertyFloat) {
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index d08cb0a..674dd11 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -40,9 +40,13 @@
"aidl_session/BluetoothAudioCodecs.cpp",
"aidl_session/BluetoothAudioSession.cpp",
"aidl_session/HidlToAidlMiddleware.cpp",
+ "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
],
export_include_dirs: ["aidl_session/"],
- header_libs: ["libhardware_headers"],
+ header_libs: [
+ "libhardware_headers",
+ "libxsdc-utils",
+ ],
shared_libs: [
"android.hardware.bluetooth.audio@2.0",
"android.hardware.bluetooth.audio@2.1",
@@ -53,5 +57,15 @@
"liblog",
"android.hardware.bluetooth.audio-V2-ndk",
"libhidlbase",
+ "libxml2",
],
+ generated_sources: ["le_audio_codec_capabilities"],
+ generated_headers: ["le_audio_codec_capabilities"],
+}
+
+xsd_config {
+ name: "le_audio_codec_capabilities",
+ srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
+ package_name: "aidl.android.hardware.bluetooth.audio.setting",
+ api_dir: "le_audio_codec_capabilities/schema",
}
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 036d6cd..855dd28 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -32,6 +32,8 @@
#include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
#include <android-base/logging.h>
+#include "BluetoothLeAudioCodecsProvider.h"
+
namespace aidl {
namespace android {
namespace hardware {
@@ -96,67 +98,6 @@
std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
-static const UnicastCapability kInvalidUnicastCapability = {
- .codecType = CodecType::UNKNOWN};
-
-static const BroadcastCapability kInvalidBroadcastCapability = {
- .codecType = CodecType::UNKNOWN};
-
-// Default Supported Codecs
-// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
-static const Lc3Capabilities kLc3Capability_16_1 = {
- .samplingFrequencyHz = {16000},
- .frameDurationUs = {7500},
- .octetsPerFrame = {30}};
-
-// Default Supported Codecs
-// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
-static const Lc3Capabilities kLc3Capability_16_2 = {
- .samplingFrequencyHz = {16000},
- .frameDurationUs = {10000},
- .octetsPerFrame = {40}};
-
-// Default Supported Codecs
-// LC3 24_2: sample rate: 24 kHz, frame duration: 10 ms, octets per frame: 60
-static const Lc3Capabilities kLc3Capability_24_2 = {
- .samplingFrequencyHz = {24000},
- .frameDurationUs = {10000},
- .octetsPerFrame = {60}};
-
-// Default Supported Codecs
-// LC3 32_2: sample rate: 32 kHz, frame duration: 10 ms, octets per frame: 80
-static const Lc3Capabilities kLc3Capability_32_2 = {
- .samplingFrequencyHz = {32000},
- .frameDurationUs = {10000},
- .octetsPerFrame = {80}};
-
-// Default Supported Codecs
-// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
-static const Lc3Capabilities kLc3Capability_48_4 = {
- .samplingFrequencyHz = {48000},
- .frameDurationUs = {10000},
- .octetsPerFrame = {120}};
-
-static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
- kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2,
- kLc3Capability_16_2, kLc3Capability_16_1};
-
-static AudioLocation stereoAudio = static_cast<AudioLocation>(
- static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
- static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
-static AudioLocation monoAudio = AudioLocation::UNKNOWN;
-
-// Stores the supported setting of audio location, connected device, and the
-// channel count for each device
-std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
- supportedDeviceSetting = {
- // Stereo, two connected device, one for L one for R
- std::make_tuple(stereoAudio, 2, 1),
- // Stereo, one connected device for both L and R
- std::make_tuple(stereoAudio, 1, 2),
- // Mono
- std::make_tuple(monoAudio, 1, 1)};
-
template <class T>
bool BluetoothAudioCodecs::ContainedInVector(
const std::vector<T>& vector, const typename identity<T>::type& target) {
@@ -444,19 +385,6 @@
return false;
}
-UnicastCapability composeUnicastLc3Capability(
- AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
- const Lc3Capabilities& capability) {
- return {
- .codecType = CodecType::LC3,
- .supportedChannel = audioLocation,
- .deviceCount = deviceCnt,
- .channelCountPerDevice = channelCount,
- .leAudioCodecCapabilities =
- UnicastCapability::LeAudioCodecCapabilities(capability),
- };
-}
-
std::vector<LeAudioCodecCapabilitiesSetting>
BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
const SessionType& session_type) {
@@ -470,41 +398,8 @@
}
if (kDefaultOffloadLeAudioCapabilities.empty()) {
- for (auto [audioLocation, deviceCnt, channelCount] :
- supportedDeviceSetting) {
- for (auto capability : supportedLc3CapabilityList) {
- UnicastCapability lc3Capability = composeUnicastLc3Capability(
- audioLocation, deviceCnt, channelCount, capability);
- UnicastCapability lc3MonoDecodeCapability =
- composeUnicastLc3Capability(monoAudio, 1, 1, capability);
-
- // Adds the capability for encode only
- kDefaultOffloadLeAudioCapabilities.push_back(
- {.unicastEncodeCapability = lc3Capability,
- .unicastDecodeCapability = kInvalidUnicastCapability,
- .broadcastCapability = kInvalidBroadcastCapability});
-
- // Adds the capability for decode only
- kDefaultOffloadLeAudioCapabilities.push_back(
- {.unicastEncodeCapability = kInvalidUnicastCapability,
- .unicastDecodeCapability = lc3Capability,
- .broadcastCapability = kInvalidBroadcastCapability});
-
- // Adds the capability for the case that encode and decode exist at the
- // same time(force one active device for decode)
- kDefaultOffloadLeAudioCapabilities.push_back(
- {.unicastEncodeCapability = lc3Capability,
- .unicastDecodeCapability = lc3MonoDecodeCapability,
- .broadcastCapability = kInvalidBroadcastCapability});
-
- // Adds the capability for the case that encode and decode exist at the
- // same time
- kDefaultOffloadLeAudioCapabilities.push_back(
- {.unicastEncodeCapability = lc3Capability,
- .unicastDecodeCapability = lc3Capability,
- .broadcastCapability = kInvalidBroadcastCapability});
- }
- }
+ kDefaultOffloadLeAudioCapabilities =
+ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
}
return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
new file mode 100644
index 0000000..bf49270
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -0,0 +1,312 @@
+/*
+ * 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 "BTAudioCodecsProviderAidl"
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const char* kLeAudioCodecCapabilitiesFile =
+ "/vendor/etc/le_audio_codec_capabilities.xml";
+
+static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
+ static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+ static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
+
+static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
+ if (!leAudioCodecCapabilities.empty()) {
+ return leAudioCodecCapabilities;
+ }
+
+ const auto le_audio_offload_setting =
+ setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
+ if (!le_audio_offload_setting.has_value()) {
+ LOG(ERROR) << __func__ << ": Failed to read "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ std::vector<setting::Scenario> supported_scenarios =
+ GetScenarios(le_audio_offload_setting);
+ if (supported_scenarios.empty()) {
+ LOG(ERROR) << __func__ << ": No scenarios in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateConfigurationsToMap(le_audio_offload_setting);
+ if (configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateCodecConfigurationsToMap(le_audio_offload_setting);
+ if (codec_configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No codec configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
+ if (strategy_configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No strategy configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ leAudioCodecCapabilities =
+ ComposeLeAudioCodecCapabilities(supported_scenarios);
+ return leAudioCodecCapabilities;
+}
+
+std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ std::vector<setting::Scenario> supported_scenarios;
+ if (le_audio_offload_setting->hasScenarioList()) {
+ for (const auto& scenario_list :
+ le_audio_offload_setting->getScenarioList()) {
+ if (!scenario_list.hasScenario()) {
+ continue;
+ }
+ for (const auto& scenario : scenario_list.getScenario()) {
+ if (scenario.hasEncode() && scenario.hasDecode()) {
+ supported_scenarios.push_back(scenario);
+ }
+ }
+ }
+ }
+ return supported_scenarios;
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasConfigurationList()) {
+ for (const auto& configuration_list :
+ le_audio_offload_setting->getConfigurationList()) {
+ if (!configuration_list.hasConfiguration()) {
+ continue;
+ }
+ for (const auto& configuration : configuration_list.getConfiguration()) {
+ if (configuration.hasName() && configuration.hasCodecConfiguration() &&
+ configuration.hasStrategyConfiguration()) {
+ configuration_map_.insert(
+ make_pair(configuration.getName(), configuration));
+ }
+ }
+ }
+ }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasCodecConfigurationList()) {
+ for (const auto& codec_configuration_list :
+ le_audio_offload_setting->getCodecConfigurationList()) {
+ if (!codec_configuration_list.hasCodecConfiguration()) {
+ continue;
+ }
+ for (const auto& codec_configuration :
+ codec_configuration_list.getCodecConfiguration()) {
+ if (IsValidCodecConfiguration(codec_configuration)) {
+ codec_configuration_map_.insert(
+ make_pair(codec_configuration.getName(), codec_configuration));
+ }
+ }
+ }
+ }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasStrategyConfigurationList()) {
+ for (const auto& strategy_configuration_list :
+ le_audio_offload_setting->getStrategyConfigurationList()) {
+ if (!strategy_configuration_list.hasStrategyConfiguration()) {
+ continue;
+ }
+ for (const auto& strategy_configuration :
+ strategy_configuration_list.getStrategyConfiguration()) {
+ if (IsValidStrategyConfiguration(strategy_configuration)) {
+ strategy_configuration_map_.insert(make_pair(
+ strategy_configuration.getName(), strategy_configuration));
+ }
+ }
+ }
+ }
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
+ const std::vector<setting::Scenario>& supported_scenarios) {
+ std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
+ for (const auto& scenario : supported_scenarios) {
+ UnicastCapability unicast_encode_capability =
+ GetUnicastCapability(scenario.getEncode());
+ UnicastCapability unicast_decode_capability =
+ GetUnicastCapability(scenario.getDecode());
+ // encode and decode cannot be unknown at the same time
+ if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
+ unicast_decode_capability.codecType == CodecType::UNKNOWN) {
+ continue;
+ }
+ BroadcastCapability broadcast_capability = {.codecType =
+ CodecType::UNKNOWN};
+ le_audio_codec_capabilities.push_back(
+ {.unicastEncodeCapability = unicast_encode_capability,
+ .unicastDecodeCapability = unicast_decode_capability,
+ .broadcastCapability = broadcast_capability});
+ }
+ return le_audio_codec_capabilities;
+}
+
+UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
+ const std::string& coding_direction) {
+ if (coding_direction == "invalid") {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto configuration_iter = configuration_map_.find(coding_direction);
+ if (configuration_iter == configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto codec_configuration_iter = codec_configuration_map_.find(
+ configuration_iter->second.getCodecConfiguration());
+ if (codec_configuration_iter == codec_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto strategy_configuration_iter = strategy_configuration_map_.find(
+ configuration_iter->second.getStrategyConfiguration());
+ if (strategy_configuration_iter == strategy_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ CodecType codec_type =
+ GetCodecType(codec_configuration_iter->second.getCodec());
+ if (codec_type == CodecType::LC3) {
+ return ComposeUnicastCapability(
+ codec_type,
+ GetAudioLocation(
+ strategy_configuration_iter->second.getAudioLocation()),
+ strategy_configuration_iter->second.getConnectedDevice(),
+ strategy_configuration_iter->second.getChannelCount(),
+ ComposeLc3Capability(codec_configuration_iter->second));
+ }
+ return {.codecType = CodecType::UNKNOWN};
+}
+
+template <class T>
+UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
+ const CodecType& codec_type, const AudioLocation& audio_location,
+ const uint8_t& device_cnt, const uint8_t& channel_count,
+ const T& capability) {
+ return {
+ .codecType = codec_type,
+ .supportedChannel = audio_location,
+ .deviceCount = device_cnt,
+ .channelCountPerDevice = channel_count,
+ .leAudioCodecCapabilities =
+ UnicastCapability::LeAudioCodecCapabilities(capability),
+ };
+}
+
+Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
+ const setting::CodecConfiguration& codec_configuration) {
+ return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
+ .frameDurationUs = {codec_configuration.getFrameDurationUs()},
+ .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
+}
+
+AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
+ const setting::AudioLocation& audio_location) {
+ switch (audio_location) {
+ case setting::AudioLocation::MONO:
+ return kMonoAudio;
+ case setting::AudioLocation::STEREO:
+ return kStereoAudio;
+ default:
+ return AudioLocation::UNKNOWN;
+ }
+}
+
+CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
+ const setting::CodecType& codec_type) {
+ switch (codec_type) {
+ case setting::CodecType::LC3:
+ return CodecType::LC3;
+ default:
+ return CodecType::UNKNOWN;
+ }
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
+ const setting::CodecConfiguration& codec_configuration) {
+ return codec_configuration.hasName() && codec_configuration.hasCodec() &&
+ codec_configuration.hasSamplingFrequency() &&
+ codec_configuration.hasFrameDurationUs() &&
+ codec_configuration.hasOctetsPerCodecFrame();
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
+ const setting::StrategyConfiguration& strategy_configuration) {
+ if (!strategy_configuration.hasName() ||
+ !strategy_configuration.hasAudioLocation() ||
+ !strategy_configuration.hasConnectedDevice() ||
+ !strategy_configuration.hasChannelCount()) {
+ return false;
+ }
+ if (strategy_configuration.getAudioLocation() ==
+ setting::AudioLocation::STEREO) {
+ if ((strategy_configuration.getConnectedDevice() == 2 &&
+ strategy_configuration.getChannelCount() == 1) ||
+ (strategy_configuration.getConnectedDevice() == 1 &&
+ strategy_configuration.getChannelCount() == 2)) {
+ // Stereo
+ // 1. two connected device, one for L one for R
+ // 2. one connected device for both L and R
+ return true;
+ }
+ } else if (strategy_configuration.getAudioLocation() ==
+ setting::AudioLocation::MONO) {
+ if (strategy_configuration.getConnectedDevice() == 1 &&
+ strategy_configuration.getChannelCount() == 1) {
+ // Mono
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
new file mode 100644
index 0000000..402235f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -0,0 +1,87 @@
+/*
+ * 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/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
+#include <android-base/logging.h>
+
+#include <unordered_map>
+
+#include "aidl_android_hardware_bluetooth_audio_setting.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothLeAudioCodecsProvider {
+ public:
+ static std::vector<LeAudioCodecCapabilitiesSetting>
+ GetLeAudioCodecCapabilities();
+
+ private:
+ static inline std::unordered_map<std::string, setting::Configuration>
+ configuration_map_;
+ static inline std::unordered_map<std::string, setting::CodecConfiguration>
+ codec_configuration_map_;
+ static inline std::unordered_map<std::string, setting::StrategyConfiguration>
+ strategy_configuration_map_;
+
+ static std::vector<setting::Scenario> GetScenarios(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+ static void UpdateConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+ static void UpdateCodecConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+ static void UpdateStrategyConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+
+ static std::vector<LeAudioCodecCapabilitiesSetting>
+ ComposeLeAudioCodecCapabilities(
+ const std::vector<setting::Scenario>& supported_scenarios);
+
+ static UnicastCapability GetUnicastCapability(
+ const std::string& coding_direction);
+ template <class T>
+ static inline UnicastCapability ComposeUnicastCapability(
+ const CodecType& codec_type, const AudioLocation& audio_location,
+ const uint8_t& device_cnt, const uint8_t& channel_count,
+ const T& capability);
+
+ static inline Lc3Capabilities ComposeLc3Capability(
+ const setting::CodecConfiguration& codec_configuration);
+
+ static inline AudioLocation GetAudioLocation(
+ const setting::AudioLocation& audio_location);
+ static inline CodecType GetCodecType(const setting::CodecType& codec_type);
+
+ static inline bool IsValidCodecConfiguration(
+ const setting::CodecConfiguration& codec_configuration);
+ static inline bool IsValidStrategyConfiguration(
+ const setting::StrategyConfiguration& strategy_configuration);
+};
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
new file mode 100644
index 0000000..c7904b3
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!---
+ This is an example to configure LE Audio hardware offload supported capability settings
+ In the follow list, there would be only one list in this file. Add element into each list as needed.
+
+ codecConfigurationList:
+ Supported codec capability along with its parameter setting
+
+ strategyConfigurationList:
+ ASE Configuration strategies
+
+ configurationList:
+ For each configuration , there are two attributes
+ - codecConfiguration
+ - strategyConfiguration
+
+ scenarioList:
+ There would be only one `scenarios` group
+ For each scenario, the are two attributes
+ - encode
+ - decode
+ If a scenario is unidirectional, mark another direction as `invalid`
+ The configuration should be chosen from `configurationList`
+-->
+<leAudioOffloadSetting>
+ <scenarioList>
+ <!-- encode only -->
+ <scenario encode="OneChanMono_16_1" decode="invalid"/>
+ <scenario encode="TwoChanStereo_16_1" decode="invalid"/>
+ <scenario encode="OneChanStereo_16_1" decode="invalid"/>
+ <scenario encode="OneChanMono_16_2" decode="invalid"/>
+ <scenario encode="TwoChanStereo_16_2" decode="invalid"/>
+ <scenario encode="OneChanStereo_16_2" decode="invalid"/>
+ <!-- encode and decode -->
+ <scenario encode="OneChanStereo_16_1" decode="OneChanStereo_16_1"/>
+ <scenario encode="OneChanStereo_16_1" decode="OneChanMono_16_1"/>
+ <scenario encode="TwoChanStereo_16_1" decode="OneChanMono_16_1"/>
+ <scenario encode="OneChanMono_16_1" decode="OneChanMono_16_1"/>
+ <scenario encode="OneChanStereo_16_2" decode="OneChanStereo_16_2"/>
+ <scenario encode="OneChanStereo_16_2" decode="OneChanMono_16_2"/>
+ <scenario encode="TwoChanStereo_16_2" decode="OneChanMono_16_2"/>
+ <scenario encode="OneChanMono_16_2" decode="OneChanMono_16_2"/>
+ </scenarioList>
+ <configurationList>
+ <configuration name="OneChanMono_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
+ <configuration name="TwoChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+ <configuration name="OneChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
+ <configuration name="OneChanMono_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
+ <configuration name="TwoChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+ <configuration name="OneChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
+ </configurationList>
+ <codecConfigurationList>
+ <codecConfiguration name="LC3_16k_1" codec="LC3" samplingFrequency="16000" frameDurationUs="7500" octetsPerCodecFrame="30"/>
+ <codecConfiguration name="LC3_16k_2" codec="LC3" samplingFrequency="16000" frameDurationUs="10000" octetsPerCodecFrame="40"/>
+ </codecConfigurationList>
+ <strategyConfigurationList>
+ <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
+ <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
+ <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
+ </strategyConfigurationList>
+</leAudioOffloadSetting>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
new file mode 100644
index 0000000..213e597
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -0,0 +1,74 @@
+<!-- LE Audio Offload Codec Capability Schema -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="leAudioOffloadSetting">
+ <xs:complexType>
+ <xs:element ref="scenarioList" minOccurs="1" maxOccurs="1"/>
+ <xs:element ref="configurationList" minOccurs="1" maxOccurs="1"/>
+ <xs:element ref="codecConfigurationList" minOccurs="1" maxOccurs="1"/>
+ <xs:element ref="strategyConfigurationList" minOccurs="1" maxOccurs="1"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="scenarioList">
+ <xs:complexType>
+ <xs:element ref="scenario" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="configurationList">
+ <xs:complexType>
+ <xs:element ref="configuration" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="codecConfigurationList">
+ <xs:complexType>
+ <xs:element ref="codecConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="strategyConfigurationList">
+ <xs:complexType>
+ <xs:element ref="strategyConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="scenario">
+ <xs:complexType>
+ <xs:attribute name="encode" type="xs:string"/>
+ <xs:attribute name="decode" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="configuration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="codecConfiguration" type="xs:string"/>
+ <xs:attribute name="strategyConfiguration" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="codecConfiguration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="codec" type="codecType"/>
+ <xs:attribute name="pcmBitDepth" type="xs:unsignedByte"/>
+ <xs:attribute name="samplingFrequency" type="xs:int"/>
+ <xs:attribute name="frameDurationUs" type="xs:int"/>
+ <xs:attribute name="octetsPerCodecFrame" type="xs:int"/>
+ <xs:attribute name="codecFrameBlocksPerSdu" type="xs:unsignedByte"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="strategyConfiguration">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="audioLocation" type="audioLocation"/>
+ <xs:attribute name="connectedDevice" type="xs:unsignedByte"/>
+ <xs:attribute name="channelCount" type="xs:unsignedByte"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:simpleType name="audioLocation">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="MONO"/>
+ <xs:enumeration value="STEREO"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="codecType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="LC3"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
new file mode 100644
index 0000000..06aa21a
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -0,0 +1,111 @@
+// Signature format: 2.0
+package aidl.android.hardware.bluetooth.audio.setting {
+
+ public enum AudioLocation {
+ method public String getRawName();
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation MONO;
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation STEREO;
+ }
+
+ public class CodecConfiguration {
+ ctor public CodecConfiguration();
+ method public aidl.android.hardware.bluetooth.audio.setting.CodecType getCodec();
+ method public short getCodecFrameBlocksPerSdu();
+ method public int getFrameDurationUs();
+ method public String getName();
+ method public int getOctetsPerCodecFrame();
+ method public short getPcmBitDepth();
+ method public int getSamplingFrequency();
+ method public void setCodec(aidl.android.hardware.bluetooth.audio.setting.CodecType);
+ method public void setCodecFrameBlocksPerSdu(short);
+ method public void setFrameDurationUs(int);
+ method public void setName(String);
+ method public void setOctetsPerCodecFrame(int);
+ method public void setPcmBitDepth(short);
+ method public void setSamplingFrequency(int);
+ }
+
+ public class CodecConfigurationList {
+ ctor public CodecConfigurationList();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.CodecConfiguration> getCodecConfiguration();
+ }
+
+ public enum CodecType {
+ method public String getRawName();
+ enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType LC3;
+ }
+
+ public class Configuration {
+ ctor public Configuration();
+ method public String getCodecConfiguration();
+ method public String getName();
+ method public String getStrategyConfiguration();
+ method public void setCodecConfiguration(String);
+ method public void setName(String);
+ method public void setStrategyConfiguration(String);
+ }
+
+ public class ConfigurationList {
+ ctor public ConfigurationList();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.Configuration> getConfiguration();
+ }
+
+ public class LeAudioOffloadSetting {
+ ctor public LeAudioOffloadSetting();
+ method public aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList getCodecConfigurationList();
+ method public aidl.android.hardware.bluetooth.audio.setting.ConfigurationList getConfigurationList();
+ method public aidl.android.hardware.bluetooth.audio.setting.ScenarioList getScenarioList();
+ method public aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList getStrategyConfigurationList();
+ method public void setCodecConfigurationList(aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList);
+ method public void setConfigurationList(aidl.android.hardware.bluetooth.audio.setting.ConfigurationList);
+ method public void setScenarioList(aidl.android.hardware.bluetooth.audio.setting.ScenarioList);
+ method public void setStrategyConfigurationList(aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList);
+ }
+
+ public class Scenario {
+ ctor public Scenario();
+ method public String getDecode();
+ method public String getEncode();
+ method public void setDecode(String);
+ method public void setEncode(String);
+ }
+
+ public class ScenarioList {
+ ctor public ScenarioList();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.Scenario> getScenario();
+ }
+
+ public class StrategyConfiguration {
+ ctor public StrategyConfiguration();
+ method public aidl.android.hardware.bluetooth.audio.setting.AudioLocation getAudioLocation();
+ method public short getChannelCount();
+ method public short getConnectedDevice();
+ method public String getName();
+ method public void setAudioLocation(aidl.android.hardware.bluetooth.audio.setting.AudioLocation);
+ method public void setChannelCount(short);
+ method public void setConnectedDevice(short);
+ method public void setName(String);
+ }
+
+ public class StrategyConfigurationList {
+ ctor public StrategyConfigurationList();
+ method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.StrategyConfiguration> getStrategyConfiguration();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfiguration readCodecConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList readCodecConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.Configuration readConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.ConfigurationList readConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.LeAudioOffloadSetting readLeAudioOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.Scenario readScenario(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.ScenarioList readScenarioList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfiguration readStrategyConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList readStrategyConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index d59def7..71243bf 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -16,7 +16,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.audio.effect</name>
<version>6.0</version>
<version>7.0</version>
@@ -37,7 +37,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="aidl" optional="false">
+ <hal format="aidl" optional="true">
<name>android.hardware.audio.effect</name>
<version>1</version>
<interface>
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
index db7e67d..5f0a176 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -259,19 +259,22 @@
for (int i = 0; i < 3; i++) {
const auto& plane = flex.planes[i];
- // must have 8-bit depth
- if (plane.bits_per_component != 8 || plane.bits_used != 8) {
+ // Must be a positive multiple of 8.
+ if (plane.bits_per_component <= 0 || (plane.bits_per_component % 8) != 0) {
return false;
}
-
+ // Must be between 1 and bits_per_component, inclusive.
+ if (plane.bits_used < 1 || plane.bits_used > plane.bits_per_component) {
+ return false;
+ }
if (plane.component == FLEX_COMPONENT_Y) {
// Y must not be interleaved
- if (plane.h_increment != 1) {
+ if (plane.h_increment != 1 && plane.h_increment != 2) {
return false;
}
} else {
// Cb and Cr can be interleaved
- if (plane.h_increment != 1 && plane.h_increment != 2) {
+ if (plane.h_increment != 1 && plane.h_increment != 2 && plane.h_increment != 4) {
return false;
}
}
diff --git a/power/OWNERS b/power/OWNERS
new file mode 100644
index 0000000..7229b22
--- /dev/null
+++ b/power/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 826709
+
+# ADPF virtual team
+lpy@google.com
+wvw@google.com
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index f3cbd78..f2c92ae 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -351,11 +351,11 @@
minDelayAverageInterval / 10);
// fastest rate sampling time is close to spec
- EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ EXPECT_LE(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
minSamplingPeriodInNs / 10);
// slowest rate sampling time is close to spec
- EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+ EXPECT_LE(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
maxSamplingPeriodInNs / 10);
}