Merge "Add soft_audio_configuration_changed_cb_ to handle the streamMap changed"
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/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/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/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/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/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/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/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 7184613..2e282e0 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -30,6 +30,7 @@
#include <openssl/ec_key.h>
#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
+#include <optional>
#include <set>
#include <vector>
@@ -73,6 +74,10 @@
return {"locked", "open"};
}
+std::set<std::string> getAttestationIdEntrySet() {
+ return {"brand", "manufacturer", "product", "model", "device"};
+}
+
bytevec string_to_bytevec(const char* s) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
return bytevec(p, p + strlen(s));
@@ -431,7 +436,7 @@
auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
ASSERT_TRUE(deviceInfoMap->asMap());
- checkDeviceInfo(deviceInfoMap->asMap(), deviceInfo.deviceInfo);
+ checkDeviceInfo(*deviceInfoMap->asMap(), deviceInfo.deviceInfo);
auto& signingKey = bccContents->back().pubKey;
deviceInfoMap->asMap()->canonicalize();
auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
@@ -459,72 +464,92 @@
}
}
- void checkType(const cppbor::Map* devInfo, uint8_t majorType, std::string entryName) {
- const auto& val = devInfo->get(entryName);
- ASSERT_TRUE(val) << entryName << " does not exist";
- ASSERT_EQ(val->type(), majorType) << entryName << " has the wrong type.";
+ std::optional<std::string> assertAttribute(const cppbor::Map& devInfo,
+ cppbor::MajorType majorType, std::string entryName) {
+ const auto& val = devInfo.get(entryName);
+ if (!val) return entryName + " is missing.\n";
+ if (val->type() != majorType) return entryName + " has the wrong type.\n";
switch (majorType) {
case cppbor::TSTR:
- EXPECT_GT(val->asTstr()->value().size(), 0);
+ if (val->asTstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
break;
case cppbor::BSTR:
- EXPECT_GT(val->asBstr()->value().size(), 0);
+ if (val->asBstr()->value().size() <= 0) {
+ return entryName + " is present but the value is empty.\n";
+ }
break;
default:
break;
}
+ return {};
}
- void checkDeviceInfo(const cppbor::Map* deviceInfo, bytevec deviceInfoBytes) {
- EXPECT_EQ(deviceInfo->clone()->asMap()->canonicalize().encode(), deviceInfoBytes)
+ void checkType(const cppbor::Map& devInfo, cppbor::MajorType majorType, std::string entryName) {
+ if (auto error = assertAttribute(devInfo, majorType, entryName)) {
+ FAIL() << *error;
+ }
+ }
+
+ void checkDeviceInfo(const cppbor::Map& deviceInfo, bytevec deviceInfoBytes) {
+ EXPECT_EQ(deviceInfo.clone()->asMap()->canonicalize().encode(), deviceInfoBytes)
<< "DeviceInfo ordering is non-canonical.";
- const auto& version = deviceInfo->get("version");
+ const auto& version = deviceInfo.get("version");
ASSERT_TRUE(version);
ASSERT_TRUE(version->asUint());
RpcHardwareInfo info;
provisionable_->getHardwareInfo(&info);
ASSERT_EQ(version->asUint()->value(), info.versionNumber);
std::set<std::string> allowList;
+ std::string problemEntries;
switch (version->asUint()->value()) {
// These fields became mandated in version 2.
case 2:
- checkType(deviceInfo, cppbor::TSTR, "brand");
- checkType(deviceInfo, cppbor::TSTR, "manufacturer");
- checkType(deviceInfo, cppbor::TSTR, "product");
- checkType(deviceInfo, cppbor::TSTR, "model");
- checkType(deviceInfo, cppbor::TSTR, "device");
+ for (auto attId : getAttestationIdEntrySet()) {
+ if (auto errMsg = assertAttribute(deviceInfo, cppbor::TSTR, attId)) {
+ problemEntries += *errMsg;
+ }
+ }
+ EXPECT_EQ("", problemEntries)
+ << problemEntries
+ << "Attestation IDs are missing or malprovisioned. If this test is being "
+ "run against an early proto or EVT build, this error is probably WAI "
+ "and indicates that Device IDs were not provisioned in the factory. If "
+ "this error is returned on a DVT or later build revision, then "
+ "something is likely wrong with the factory provisioning process.";
// TODO: Refactor the KeyMint code that validates these fields and include it here.
checkType(deviceInfo, cppbor::TSTR, "vb_state");
allowList = getAllowedVbStates();
- EXPECT_NE(allowList.find(deviceInfo->get("vb_state")->asTstr()->value()),
+ EXPECT_NE(allowList.find(deviceInfo.get("vb_state")->asTstr()->value()),
allowList.end());
checkType(deviceInfo, cppbor::TSTR, "bootloader_state");
allowList = getAllowedBootloaderStates();
- EXPECT_NE(allowList.find(deviceInfo->get("bootloader_state")->asTstr()->value()),
+ EXPECT_NE(allowList.find(deviceInfo.get("bootloader_state")->asTstr()->value()),
allowList.end());
checkType(deviceInfo, cppbor::BSTR, "vbmeta_digest");
checkType(deviceInfo, cppbor::UINT, "system_patch_level");
checkType(deviceInfo, cppbor::UINT, "boot_patch_level");
checkType(deviceInfo, cppbor::UINT, "vendor_patch_level");
checkType(deviceInfo, cppbor::UINT, "fused");
- EXPECT_LT(deviceInfo->get("fused")->asUint()->value(), 2); // Must be 0 or 1.
+ EXPECT_LT(deviceInfo.get("fused")->asUint()->value(), 2); // Must be 0 or 1.
checkType(deviceInfo, cppbor::TSTR, "security_level");
allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
+ EXPECT_NE(allowList.find(deviceInfo.get("security_level")->asTstr()->value()),
allowList.end());
- if (deviceInfo->get("security_level")->asTstr()->value() == "tee") {
+ if (deviceInfo.get("security_level")->asTstr()->value() == "tee") {
checkType(deviceInfo, cppbor::TSTR, "os_version");
}
break;
case 1:
checkType(deviceInfo, cppbor::TSTR, "security_level");
allowList = getAllowedSecurityLevels();
- EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
+ EXPECT_NE(allowList.find(deviceInfo.get("security_level")->asTstr()->value()),
allowList.end());
if (version->asUint()->value() == 1) {
checkType(deviceInfo, cppbor::TSTR, "att_id_state");
allowList = getAllowedAttIdStates();
- EXPECT_NE(allowList.find(deviceInfo->get("att_id_state")->asTstr()->value()),
+ EXPECT_NE(allowList.find(deviceInfo.get("att_id_state")->asTstr()->value()),
allowList.end());
}
break;
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);
}