aidl/a2dp_provider_info: add unit tests for ProviderInfo
Bug: 315956719
Bug: 305734815
Test: atest bluetooth-test-audio-hal-provider-info
Change-Id: I2f6176d9a00d1326e628f99850b6f7774bdd4aba
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2c95965..adf5edc 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -323,6 +323,9 @@
"name": "bluetooth_le_audio_codec_manager_test"
},
{
+ "name": "bluetooth-test-audio-hal-a2dp-provider-info"
+ },
+ {
"name": "bluetooth_test_gdx_unit"
},
{
diff --git a/system/audio_hal_interface/Android.bp b/system/audio_hal_interface/Android.bp
index c979706..75633f2 100644
--- a/system/audio_hal_interface/Android.bp
+++ b/system/audio_hal_interface/Android.bp
@@ -117,3 +117,74 @@
],
header_libs: ["libbluetooth_headers"],
}
+
+// Bluetooth Audio Provider Info unit tests for target and host
+cc_test {
+ name: "bluetooth-test-audio-hal-a2dp-provider-info",
+ test_suites: ["general-tests"],
+ defaults: [
+ "fluoride_defaults",
+ "latest_android_hardware_bluetooth_audio_ndk_shared",
+ "mts_defaults",
+ ],
+ cflags: [
+ "-DBUILDCFG",
+ "-DUNIT_TESTS",
+ "-Wno-unused-parameter",
+ ],
+ host_supported: true,
+ test_options: {
+ unit_test: true,
+ },
+ include_dirs: [
+ "packages/modules/Bluetooth/system",
+ "packages/modules/Bluetooth/system/gd",
+ "packages/modules/Bluetooth/system/stack/include",
+ ],
+ target: {
+ host: {
+ srcs: [
+ ":BluetoothHostTestingLogCapture",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothAndroidTestingLogCapture",
+ ],
+ },
+ },
+ sanitize: {
+ cfi: true,
+ scs: true,
+ address: true,
+ all_undefined: true,
+ integer_overflow: true,
+ diag: {
+ undefined: true,
+ },
+ },
+ srcs: [
+ ":TestCommonMockFunctions",
+ ":TestMockAudioHalInterface",
+ "aidl/a2dp_provider_info.cc",
+ "aidl/a2dp_provider_info_unittest.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "server_configurable_flags",
+ ],
+ static_libs: [
+ "bluetooth_flags_c_lib",
+ "libbt-common",
+ "libbt_shim_bridge",
+ "libchrome",
+ "libflagtest",
+ "libgmock",
+ "libosi",
+ ],
+ header_libs: ["libbluetooth_headers"],
+}
diff --git a/system/audio_hal_interface/aidl/a2dp_provider_info_unittest.cc b/system/audio_hal_interface/aidl/a2dp_provider_info_unittest.cc
new file mode 100644
index 0000000..5a61a63
--- /dev/null
+++ b/system/audio_hal_interface/aidl/a2dp_provider_info_unittest.cc
@@ -0,0 +1,773 @@
+/*
+ * Copyright 2024 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 "TestAIDLA2dpProviderInfo"
+
+#include "a2dp_provider_info.h"
+
+#include <com_android_bluetooth_flags.h>
+#include <flag_macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "a2dp_constants.h"
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_opus_constants.h"
+#include "avdt_api.h"
+#include "client_interface_aidl.h"
+
+#define TEST_BT com::android::bluetooth::flags
+
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::CodecId;
+using aidl::android::hardware::bluetooth::audio::CodecInfo;
+using bluetooth::audio::aidl::BluetoothAudioClientInterface;
+using bluetooth::audio::aidl::IBluetoothAudioProviderFactory;
+using bluetooth::audio::aidl::SessionType;
+using bluetooth::audio::aidl::a2dp::ProviderInfo;
+using ::testing::_;
+using ::testing::Return;
+using ::testing::Test;
+
+tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) {
+ return (tA2DP_CODEC_TYPE)(p_codec_info[AVDT_CODEC_TYPE_INDEX]);
+}
+
+uint16_t A2DP_VendorCodecGetCodecId(const uint8_t* p_codec_info) {
+ const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_CODEC_ID_START_IDX];
+
+ uint16_t codec_id = (p[0] & 0x00ff) | ((p[1] << 8) & 0xff00);
+
+ return codec_id;
+}
+
+uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info) {
+ const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX];
+
+ uint32_t vendor_id = (p[0] & 0x000000ff) | ((p[1] << 8) & 0x0000ff00) |
+ ((p[2] << 16) & 0x00ff0000) |
+ ((p[3] << 24) & 0xff000000);
+
+ return vendor_id;
+}
+
+class MockBluetoothAudioClientInterface {
+ public:
+ MOCK_METHOD(
+ std::optional<IBluetoothAudioProviderFactory::ProviderInfo>,
+ GetProviderInfo,
+ (SessionType session_type,
+ std::shared_ptr<IBluetoothAudioProviderFactory> provider_factory));
+};
+
+static MockBluetoothAudioClientInterface* mock_bt_audio_client_itf = nullptr;
+
+namespace bluetooth {
+namespace audio {
+namespace aidl {
+
+std::optional<IBluetoothAudioProviderFactory::ProviderInfo>
+BluetoothAudioClientInterface::GetProviderInfo(
+ SessionType session_type,
+ std::shared_ptr<IBluetoothAudioProviderFactory> provider_factory) {
+ return mock_bt_audio_client_itf->GetProviderInfo(session_type,
+ provider_factory);
+}
+
+} // namespace aidl
+} // namespace audio
+} // namespace bluetooth
+
+namespace {
+
+std::vector<uint8_t> test_sbc_codec_info = {0x06, 0x00, 0x00, 0x3f,
+ 0xff, 0x02, 0x25};
+std::vector<uint8_t> test_aac_codec_info = {0x08, 0x00, 0x02, 0x80, 0x01,
+ 0x8c, 0x83, 0xe8, 0x00};
+std::vector<uint8_t> test_opus_codec_info = {0x09, 0x00, 0xff, 0xe0, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x3c};
+std::vector<uint8_t> test_foobar_codec_info = {0x09, 0x00, 0xff, 0x44, 0x33,
+ 0x00, 0x00, 0x22, 0x11, 0x3c};
+
+CodecId::Vendor test_opus_codec_id = {.id = A2DP_OPUS_VENDOR_ID,
+ .codecId = A2DP_OPUS_CODEC_ID};
+CodecId::Vendor test_foobar_codec_id = {.id = 0x00003344, .codecId = 0x1122};
+CodecId::Vendor test_unknown_vendor_codec_id = {.id = 0x12345678,
+ .codecId = 0x1234};
+
+IBluetoothAudioProviderFactory::ProviderInfo test_source_provider_info = {
+ .name = "TEST_PROVIDER_SOURCE_CODECS",
+};
+
+IBluetoothAudioProviderFactory::ProviderInfo test_sink_provider_info = {
+ .name = "TEST_PROVIDER_SINK_CODECS",
+};
+
+class ProviderInfoTest : public Test {
+ public:
+ std::unique_ptr<ProviderInfo> provider_info;
+ MockBluetoothAudioClientInterface client_itf_mock;
+
+ void CreateTestA2dpCodecInfo(CodecInfo& codecInfo, CodecId codecId,
+ std::string codecName,
+ std::vector<uint8_t> capabilities,
+ std::vector<ChannelMode> channelMode,
+ std::vector<int32_t> samplingFrequencyHz,
+ std::vector<int32_t> bitdepth, bool lossless) {
+ codecInfo.id = codecId;
+ codecInfo.name = codecName;
+ codecInfo.transport.set<CodecInfo::Transport::Tag::a2dp>();
+ auto& a2dpInfo = codecInfo.transport.get<CodecInfo::Transport::Tag::a2dp>();
+ a2dpInfo.capabilities.resize(capabilities.size());
+ a2dpInfo.capabilities = capabilities;
+ a2dpInfo.channelMode = channelMode;
+ a2dpInfo.samplingFrequencyHz = samplingFrequencyHz;
+ a2dpInfo.bitdepth = bitdepth;
+ a2dpInfo.lossless = lossless;
+ }
+
+ void GetProviderInfoForTesting(bool include_source_codecs,
+ bool include_sink_codecs) {
+ if (include_source_codecs) {
+ EXPECT_CALL(client_itf_mock,
+ GetProviderInfo(
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH, _))
+ .WillOnce(Return(std::make_optional(test_source_provider_info)));
+ } else {
+ EXPECT_CALL(client_itf_mock,
+ GetProviderInfo(
+ SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH, _));
+ }
+
+ if (include_sink_codecs) {
+ EXPECT_CALL(client_itf_mock,
+ GetProviderInfo(
+ SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, _))
+ .WillOnce(Return(std::make_optional(test_sink_provider_info)));
+ } else {
+ EXPECT_CALL(client_itf_mock,
+ GetProviderInfo(
+ SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, _));
+ }
+
+ provider_info = ProviderInfo::GetProviderInfo(true);
+ if (include_source_codecs || include_sink_codecs) {
+ ASSERT_NE(provider_info, nullptr);
+ } else {
+ ASSERT_EQ(provider_info, nullptr);
+ }
+ }
+
+ protected:
+ void SetUp() override {
+ mock_bt_audio_client_itf = &client_itf_mock;
+
+ auto& codec_info_sbc = test_source_provider_info.codecInfos.emplace_back();
+ CreateTestA2dpCodecInfo(
+ codec_info_sbc, CodecId::A2dp::SBC, std::string("SBC"),
+ std::vector<uint8_t>{0x3f, 0xff, 0x02, 0x25}, /* capabilities */
+ std::vector<ChannelMode>{ChannelMode::MONO, ChannelMode::STEREO,
+ ChannelMode::DUALMONO}, /* channelMode */
+ std::vector<int32_t>{44100, 48000}, /* samplingFrequencyHz */
+ std::vector<int32_t>{16, 24, 32}, /* bitdepth */
+ false /* lossless */
+ );
+
+ auto& codec_info_aac = test_source_provider_info.codecInfos.emplace_back();
+ CreateTestA2dpCodecInfo(
+ codec_info_aac, CodecId::A2dp::AAC, std::string("AAC"),
+ std::vector<uint8_t>{0x80, 0x01, 0x8c, 0x83, 0xe8,
+ 0x00}, /* capabilities */
+ std::vector<ChannelMode>{ChannelMode::MONO, ChannelMode::STEREO,
+ ChannelMode::DUALMONO}, /* channelMode */
+ std::vector<int32_t>{44100, 48000}, /* samplingFrequencyHz */
+ std::vector<int32_t>{16, 24, 32}, /* bitdepth */
+ false /* lossless */
+ );
+
+ auto& codec_info_opus = test_source_provider_info.codecInfos.emplace_back();
+ CreateTestA2dpCodecInfo(
+ codec_info_opus, test_opus_codec_id, std::string("Opus"),
+ std::vector<uint8_t>{0x3c}, /* capabilities */
+ std::vector<ChannelMode>{ChannelMode::MONO, ChannelMode::STEREO,
+ ChannelMode::DUALMONO}, /* channelMode */
+ std::vector<int32_t>{44100, 48000}, /* samplingFrequencyHz */
+ std::vector<int32_t>{16, 24, 32}, /* bitdepth */
+ false /* lossless */
+ );
+
+ auto& codec_info_foobar =
+ test_source_provider_info.codecInfos.emplace_back();
+ CreateTestA2dpCodecInfo(
+ codec_info_foobar, test_foobar_codec_id, std::string("FooBar"),
+ std::vector<uint8_t>{0x3c}, /* capabilities */
+ std::vector<ChannelMode>{ChannelMode::MONO, ChannelMode::STEREO,
+ ChannelMode::DUALMONO}, /* channelMode */
+ std::vector<int32_t>{44100, 48000}, /* samplingFrequencyHz */
+ std::vector<int32_t>{16, 24, 32}, /* bitdepth */
+ false /* lossless */
+ );
+
+ test_sink_provider_info.codecInfos = test_source_provider_info.codecInfos;
+ }
+
+ void TearDown() override {
+ test_source_provider_info.codecInfos.clear();
+ test_sink_provider_info.codecInfos.clear();
+ }
+};
+} // namespace
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetProviderInfoFlagDisabled,
+ REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ EXPECT_CALL(
+ client_itf_mock,
+ GetProviderInfo(SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH, _))
+ .Times(0);
+ EXPECT_CALL(
+ client_itf_mock,
+ GetProviderInfo(SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, _))
+ .Times(0);
+
+ provider_info = ProviderInfo::GetProviderInfo(true);
+ ASSERT_EQ(provider_info, nullptr);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetProviderInfoEmptyProviderInfo,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(false, false);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetProviderInfo,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetCodecSbc,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto received_codec_info_sbc =
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+ ASSERT_TRUE(received_codec_info_sbc.has_value());
+ auto codec_info = received_codec_info_sbc.value();
+ LOG(ERROR) << codec_info->toString();
+ LOG(ERROR) << test_source_provider_info.codecInfos[0].toString();
+ ASSERT_EQ(*codec_info, test_source_provider_info.codecInfos[0]);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetCodecAac,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto received_codec_info_aac =
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+ ASSERT_TRUE(received_codec_info_aac.has_value());
+ auto codec_info = received_codec_info_aac.value();
+ LOG(ERROR) << codec_info->toString();
+ LOG(ERROR) << test_source_provider_info.codecInfos[1].toString();
+ ASSERT_EQ(*codec_info, test_source_provider_info.codecInfos[1]);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetCodecOpus,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto received_codec_info_opus =
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+ ASSERT_TRUE(received_codec_info_opus.has_value());
+ auto codec_info = received_codec_info_opus.value();
+ LOG(ERROR) << codec_info->toString();
+ LOG(ERROR) << test_source_provider_info.codecInfos[2].toString();
+ ASSERT_EQ(*codec_info, test_source_provider_info.codecInfos[2]);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetCodecFoobar,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto received_codec_info_foobar =
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN);
+ ASSERT_TRUE(received_codec_info_foobar.has_value());
+ auto codec_info = received_codec_info_foobar.value();
+ LOG(ERROR) << codec_info->toString();
+ LOG(ERROR) << test_source_provider_info.codecInfos[3].toString();
+ ASSERT_EQ(*codec_info, test_source_provider_info.codecInfos[3]);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestGetCodecNotSupported,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto received_codec_info_not_supported_codec =
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SINK_LDAC);
+ ASSERT_FALSE(received_codec_info_not_supported_codec.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSourceCodecIndexByCodecId,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+ auto codecInfoArray = test_source_provider_info.codecInfos;
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[0].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[1].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[2].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[3].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN);
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_unknown_vendor_codec_id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSourceCodecIndexByVendorAndCodecId,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+ auto codecInfoArray = test_source_provider_info.codecInfos;
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[2].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[3].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN);
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_unknown_vendor_codec_id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSourceCodecIndexByCapabilities,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_sbc_codec_info.data());
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_aac_codec_info.data());
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_opus_codec_info.data());
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_foobar_codec_info.data());
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN);
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ std::vector<uint8_t>({0xde, 0xad, 0xbe, 0xef}).data());
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest,
+ TestSourceCodecIndexByCodecIdAssertNoSources,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(false, true);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+ auto codecInfoArray = test_source_provider_info.codecInfos;
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[0].id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[1].id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[2].id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(codecInfoArray[3].id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt =
+ provider_info->SourceCodecIndex(test_unknown_vendor_codec_id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest,
+ TestSourceCodecIndexByVendorAndCodecIdAssertNoSources,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(false, true);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ 0, static_cast<uint16_t>(CodecId::A2dp::SBC));
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ 0, static_cast<uint16_t>(CodecId::A2dp::AAC));
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ test_opus_codec_id.id, test_opus_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ test_foobar_codec_id.id, test_foobar_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SourceCodecIndex(
+ test_unknown_vendor_codec_id.id, test_unknown_vendor_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSinkCodecIndexByCodecId,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(false, true);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+ auto codecInfoArray = test_sink_provider_info.codecInfos;
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(codecInfoArray[0].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_SBC);
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(codecInfoArray[1].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_AAC);
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(codecInfoArray[2].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(codecInfoArray[3].id);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_EXT_MIN);
+
+ a2dp_codec_index_opt =
+ provider_info->SinkCodecIndex(test_unknown_vendor_codec_id);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSinkCodecIndexByVendorAndCodecId,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(false, true);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_opus_codec_id.id, test_opus_codec_id.codecId);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_foobar_codec_id.id, test_foobar_codec_id.codecId);
+ ASSERT_TRUE(a2dp_codec_index_opt.has_value());
+ ASSERT_EQ(a2dp_codec_index_opt.value(), BTAV_A2DP_CODEC_INDEX_SINK_EXT_MIN);
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_unknown_vendor_codec_id.id, test_unknown_vendor_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest,
+ TestSinkCodecIndexByVendorAndCodecIdAssertNoSinks,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ std::optional<btav_a2dp_codec_index_t> a2dp_codec_index_opt;
+ auto codecInfoArray = test_sink_provider_info.codecInfos;
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ 0, static_cast<uint16_t>(CodecId::A2dp::SBC));
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ 0, static_cast<uint16_t>(CodecId::A2dp::AAC));
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_opus_codec_id.id, test_opus_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_foobar_codec_id.id, test_foobar_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+
+ a2dp_codec_index_opt = provider_info->SinkCodecIndex(
+ test_unknown_vendor_codec_id.id, test_unknown_vendor_codec_id.codecId);
+ ASSERT_FALSE(a2dp_codec_index_opt.has_value());
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestCodecIndexStr,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ auto codecInfoArray = test_source_provider_info.codecInfos;
+
+ ASSERT_EQ(provider_info->CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC),
+ codecInfoArray[0].name);
+
+ ASSERT_EQ(provider_info->CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC),
+ codecInfoArray[1].name);
+
+ ASSERT_EQ(provider_info->CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS),
+ codecInfoArray[2].name);
+
+ ASSERT_EQ(provider_info->CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN),
+ codecInfoArray[3].name);
+
+ ASSERT_EQ(provider_info->CodecIndexStr(static_cast<btav_a2dp_codec_index_t>(
+ test_unknown_vendor_codec_id.id)),
+ std::nullopt);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestSupportsCodec,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, true);
+
+ for (int i = static_cast<int>(BTAV_A2DP_CODEC_INDEX_SOURCE_MIN);
+ i <= static_cast<int>(BTAV_A2DP_CODEC_INDEX_MAX); i++) {
+ switch (i) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN:
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
+ case BTAV_A2DP_CODEC_INDEX_SINK_EXT_MIN:
+ ASSERT_TRUE(provider_info->SupportsCodec(
+ static_cast<btav_a2dp_codec_index_t>(i)));
+ break;
+ default:
+ ASSERT_FALSE(provider_info->SupportsCodec(
+ static_cast<btav_a2dp_codec_index_t>(i)));
+ break;
+ }
+ }
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestBuildCodecCapabilitiesSbc,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ std::vector<uint8_t> sbc_caps = {0x3f, 0xff, 0x02, 0x25};
+ uint8_t result_sbc_codec_info[7];
+
+ ASSERT_TRUE(ProviderInfo::BuildCodecCapabilities(
+ CodecId::A2dp(CodecId::A2dp::SBC), sbc_caps, result_sbc_codec_info));
+ ASSERT_EQ(std::memcmp(result_sbc_codec_info, test_sbc_codec_info.data(),
+ test_sbc_codec_info.size()),
+ 0);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestBuildCodecCapabilitiesAac,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+ std::vector<uint8_t> aac_caps = {0x80, 0x01, 0x8c, 0x83, 0xe8, 0x00};
+ uint8_t result_aac_codec_info[9];
+
+ ASSERT_TRUE(ProviderInfo::BuildCodecCapabilities(
+ CodecId::A2dp(CodecId::A2dp::AAC), aac_caps, result_aac_codec_info));
+ ASSERT_EQ(std::memcmp(result_aac_codec_info, test_aac_codec_info.data(),
+ test_aac_codec_info.size()),
+ 0);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestBuildCodecCapabilitiesOpus,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ std::vector<uint8_t> opus_caps = {0x3c};
+ uint8_t result_opus_codec_info[10];
+
+ ASSERT_TRUE(ProviderInfo::BuildCodecCapabilities(
+ test_opus_codec_id, opus_caps, result_opus_codec_info));
+ ASSERT_EQ(std::memcmp(result_opus_codec_info, test_opus_codec_info.data(),
+ test_opus_codec_info.size()),
+ 0);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestBuildCodecCapabilitiesFoobar,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ std::vector<uint8_t> foobar_caps = {0x3c};
+ uint8_t result_foobar_codec_info[10];
+
+ ASSERT_TRUE(ProviderInfo::BuildCodecCapabilities(
+ test_foobar_codec_id, foobar_caps, result_foobar_codec_info));
+ ASSERT_EQ(std::memcmp(result_foobar_codec_info, test_foobar_codec_info.data(),
+ test_foobar_codec_info.size()),
+ 0);
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestBuildCodecCapabilitiesNotSupported,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ std::vector<uint8_t> foobar_caps = {0x3c};
+ uint8_t result_foobar_codec_info[10];
+
+ ASSERT_FALSE(ProviderInfo::BuildCodecCapabilities(
+ CodecId::Core(CodecId::Core::CVSD), foobar_caps,
+ result_foobar_codec_info));
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestCodecCapabilitiesSbc,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ uint8_t result_codec_info[20];
+ btav_a2dp_codec_config_t result_codec_config;
+ uint64_t result_codec_id;
+
+ ASSERT_TRUE(provider_info->CodecCapabilities(
+ BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, &result_codec_id, result_codec_info,
+ &result_codec_config));
+ ASSERT_EQ(result_codec_id, A2DP_CODEC_ID_SBC);
+ ASSERT_EQ(std::memcmp(result_codec_info, test_sbc_codec_info.data(),
+ test_sbc_codec_info.size()),
+ 0);
+ ASSERT_TRUE(result_codec_config.channel_mode ==
+ (BTAV_A2DP_CODEC_CHANNEL_MODE_MONO |
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO));
+ ASSERT_TRUE(
+ result_codec_config.sample_rate ==
+ (BTAV_A2DP_CODEC_SAMPLE_RATE_44100 | BTAV_A2DP_CODEC_SAMPLE_RATE_48000));
+ ASSERT_TRUE(result_codec_config.bits_per_sample ==
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32));
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestCodecCapabilitiesAac,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ uint8_t result_codec_info[20];
+ btav_a2dp_codec_config_t result_codec_config;
+ uint64_t result_codec_id;
+
+ ASSERT_TRUE(provider_info->CodecCapabilities(
+ BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, &result_codec_id, result_codec_info,
+ &result_codec_config));
+ ASSERT_EQ(result_codec_id, A2DP_CODEC_ID_AAC);
+ ASSERT_EQ(std::memcmp(result_codec_info, test_aac_codec_info.data(),
+ test_aac_codec_info.size()),
+ 0);
+ ASSERT_TRUE(result_codec_config.channel_mode ==
+ (BTAV_A2DP_CODEC_CHANNEL_MODE_MONO |
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO));
+ ASSERT_TRUE(
+ result_codec_config.sample_rate ==
+ (BTAV_A2DP_CODEC_SAMPLE_RATE_44100 | BTAV_A2DP_CODEC_SAMPLE_RATE_48000));
+ ASSERT_TRUE(result_codec_config.bits_per_sample ==
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32));
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestCodecCapabilitiesOpus,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ uint8_t result_codec_info[20];
+ btav_a2dp_codec_config_t result_codec_config;
+ uint64_t result_codec_id;
+
+ ASSERT_TRUE(provider_info->CodecCapabilities(
+ BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS, &result_codec_id, result_codec_info,
+ &result_codec_config));
+ ASSERT_EQ(result_codec_id, A2DP_CODEC_ID_OPUS);
+ ASSERT_EQ(std::memcmp(result_codec_info, test_opus_codec_info.data(),
+ test_opus_codec_info.size()),
+ 0);
+ ASSERT_TRUE(result_codec_config.channel_mode ==
+ (BTAV_A2DP_CODEC_CHANNEL_MODE_MONO |
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO));
+ ASSERT_TRUE(
+ result_codec_config.sample_rate ==
+ (BTAV_A2DP_CODEC_SAMPLE_RATE_44100 | BTAV_A2DP_CODEC_SAMPLE_RATE_48000));
+ ASSERT_TRUE(result_codec_config.bits_per_sample ==
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32));
+}
+
+TEST_F_WITH_FLAGS(ProviderInfoTest, TestCodecCapabilitiesFoobar,
+ REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
+ TEST_BT, a2dp_offload_codec_extensibility))) {
+ GetProviderInfoForTesting(true, false);
+
+ uint8_t result_codec_info[20];
+ btav_a2dp_codec_config_t result_codec_config;
+ uint64_t result_codec_id;
+
+ ASSERT_TRUE(provider_info->CodecCapabilities(
+ BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN, &result_codec_id, result_codec_info,
+ &result_codec_config));
+ ASSERT_EQ(result_codec_id, static_cast<uint64_t>(0x11223344ff));
+ ASSERT_EQ(std::memcmp(result_codec_info, test_foobar_codec_info.data(),
+ test_foobar_codec_info.size()),
+ 0);
+ ASSERT_TRUE(result_codec_config.channel_mode ==
+ (BTAV_A2DP_CODEC_CHANNEL_MODE_MONO |
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO));
+ ASSERT_TRUE(
+ result_codec_config.sample_rate ==
+ (BTAV_A2DP_CODEC_SAMPLE_RATE_44100 | BTAV_A2DP_CODEC_SAMPLE_RATE_48000));
+ ASSERT_TRUE(result_codec_config.bits_per_sample ==
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32));
+}
\ No newline at end of file