blob: 85b3e7675a741deefdf26f89e84a6a5ceb3f2b75 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <dlfcn.h>
#include <gtest/gtest.h>
#include <set>
#include <vector>
#include "stack/include/a2dp_aac.h"
#include "stack/include/a2dp_api.h"
#include "stack/include/a2dp_codec_api.h"
#include "stack/include/a2dp_sbc.h"
#include "stack/include/a2dp_vendor.h"
#include "stack/include/a2dp_vendor_opus_constants.h"
#include "stack/include/bt_hdr.h"
namespace {
const uint8_t codec_info_sbc[AVDT_CODEC_SIZE] = {
6, // Length (A2DP_SBC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
0, // Media Codec Type: A2DP_MEDIA_CT_SBC
0x20 | 0x01, // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
// Channel Mode: A2DP_SBC_IE_CH_MD_JOINT
0x10 | 0x04 | 0x01, // Block Length: A2DP_SBC_IE_BLOCKS_16 |
// Subbands: A2DP_SBC_IE_SUBBAND_8 |
// Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
7, // Fake
8, // Fake
9 // Fake
};
const uint8_t codec_info_sbc_capability[AVDT_CODEC_SIZE] = {
6, // Length (A2DP_SBC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
0, // Media Codec Type: A2DP_MEDIA_CT_SBC
0x20 | // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
0x08 | 0x01, // Channel Mode: A2DP_SBC_IE_CH_MD_MONO |
// A2DP_SBC_IE_CH_MD_JOINT
0x80 | 0x40 | 0x20 | 0x10 | // Block Length: A2DP_SBC_IE_BLOCKS_4 |
// A2DP_SBC_IE_BLOCKS_8 |
// A2DP_SBC_IE_BLOCKS_12 |
// A2DP_SBC_IE_BLOCKS_16 |
0x04 | // Subbands: A2DP_SBC_IE_SUBBAND_8 |
0x01, // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
7, // Fake
8, // Fake
9 // Fake
};
const uint8_t codec_info_sbc_sink_capability[AVDT_CODEC_SIZE] = {
6, // Length (A2DP_SBC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
0, // Media Codec Type: A2DP_MEDIA_CT_SBC
0x20 | 0x10 | // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
// A2DP_SBC_IE_SAMP_FREQ_48 |
0x08 | 0x04 | 0x02 | 0x01, // Channel Mode: A2DP_SBC_IE_CH_MD_MONO |
// A2DP_SBC_IE_CH_MD_DUAL |
// A2DP_SBC_IE_CH_MD_STEREO |
// A2DP_SBC_IE_CH_MD_JOINT
0x80 | 0x40 | 0x20 | 0x10 | // Block Length: A2DP_SBC_IE_BLOCKS_4 |
// A2DP_SBC_IE_BLOCKS_8 |
// A2DP_SBC_IE_BLOCKS_12 |
// A2DP_SBC_IE_BLOCKS_16 |
0x08 | 0x04 | // Subbands: A2DP_SBC_IE_SUBBAND_4 |
// A2DP_SBC_IE_SUBBAND_8 |
0x02 | 0x01, // Allocation Method: A2DP_SBC_IE_ALLOC_MD_S |
// A2DP_SBC_IE_ALLOC_MD_L
2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
7, // Fake
8, // Fake
9 // Fake
};
const uint8_t codec_info_aac[AVDT_CODEC_SIZE] = {
8, // Length (A2DP_AAC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
2, // Media Codec Type: A2DP_MEDIA_CT_AAC
0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
0x00 | 0x4, // Variable Bit Rate:
// A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
// Bit Rate: 320000 = 0x4e200
0xe2, // Bit Rate: 320000 = 0x4e200
0x00, // Bit Rate: 320000 = 0x4e200
7, // Unused
8, // Unused
9 // Unused
};
const uint8_t codec_info_aac_vbr[AVDT_CODEC_SIZE] = {
8, // Length (A2DP_AAC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
2, // Media Codec Type: A2DP_MEDIA_CT_AAC
0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
0x80 | 0x4, // Variable Bit Rate:
// A2DP_AAC_VARIABLE_BIT_RATE_ENABLED
// Bit Rate: 320000 = 0x4e200
0xe2, // Bit Rate: 320000 = 0x4e200
0x00, // Bit Rate: 320000 = 0x4e200
7, // Unused
8, // Unused
9 // Unused
};
const uint8_t codec_info_aac_capability[AVDT_CODEC_SIZE] = {
8, // Length (A2DP_AAC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
2, // Media Codec Type: A2DP_MEDIA_CT_AAC
0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
// TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
0x00 | 0x4, // Variable Bit Rate:
// A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
// Bit Rate: 320000 = 0x4e200
0xe2, // Bit Rate: 320000 = 0x4e200
0x00, // Bit Rate: 320000 = 0x4e200
7, // Unused
8, // Unused
9 // Unused
};
const uint8_t codec_info_aac_vbr_capability[AVDT_CODEC_SIZE] = {
8, // Length (A2DP_AAC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
2, // Media Codec Type: A2DP_MEDIA_CT_AAC
0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
// TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
0x80 | 0x4, // Variable Bit Rate:
// A2DP_AAC_VARIABLE_BIT_RATE_ENABLED
// Bit Rate: 320000 = 0x4e200
0xe2, // Bit Rate: 320000 = 0x4e200
0x00, // Bit Rate: 320000 = 0x4e200
7, // Unused
8, // Unused
9 // Unused
};
const uint8_t codec_info_aac_sink_capability[AVDT_CODEC_SIZE] = {
8, // Length (A2DP_AAC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
2, // Media Codec Type: A2DP_MEDIA_CT_AAC
0x80 | 0x40 | 0x20 | 0x10, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC |
// A2DP_AAC_OBJECT_TYPE_MPEG4_LC
// A2DP_AAC_OBJECT_TYPE_MPEG4_LTP
// A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE
0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
0x80 | 0x20 | 0x10 | 0x08 | 0x04, // Sampling Frequency:
// A2DP_AAC_SAMPLING_FREQ_48000 |
// A2DP_AAC_SAMPLING_FREQ_88200 |
// A2DP_AAC_SAMPLING_FREQ_96000 |
// Channels:
// A2DP_AAC_CHANNEL_MODE_MONO |
// A2DP_AAC_CHANNEL_MODE_STEREO
0x80 | 0x4, // Variable Bit Rate:
// A2DP_AAC_VARIABLE_BIT_RATE_ENABLED
// Bit Rate: 320000 = 0x4e200
0xe2, // Bit Rate: 320000 = 0x4e200
0x00, // Bit Rate: 320000 = 0x4e200
7, // Fake
8, // Fake
9 // Fake
};
const uint8_t codec_info_opus[AVDT_CODEC_SIZE] = {
A2DP_OPUS_CODEC_LEN, // Length
AVDT_MEDIA_TYPE_AUDIO << 4, // Media Type
A2DP_MEDIA_CT_NON_A2DP, // Media Codec Type Vendor
(A2DP_OPUS_VENDOR_ID & 0x000000FF),
(A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
(A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
(A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
(A2DP_OPUS_CODEC_ID & 0x00FF),
(A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
A2DP_OPUS_CHANNEL_MODE_STEREO | A2DP_OPUS_20MS_FRAMESIZE |
A2DP_OPUS_SAMPLING_FREQ_48000};
const uint8_t codec_info_opus_capability[AVDT_CODEC_SIZE] = {
A2DP_OPUS_CODEC_LEN, // Length
AVDT_MEDIA_TYPE_AUDIO << 4, // Media Type
A2DP_MEDIA_CT_NON_A2DP, // Media Codec Type Vendor
(A2DP_OPUS_VENDOR_ID & 0x000000FF),
(A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
(A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
(A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
(A2DP_OPUS_CODEC_ID & 0x00FF),
(A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
A2DP_OPUS_CHANNEL_MODE_MONO | A2DP_OPUS_CHANNEL_MODE_STEREO |
A2DP_OPUS_10MS_FRAMESIZE | A2DP_OPUS_20MS_FRAMESIZE |
A2DP_OPUS_SAMPLING_FREQ_48000};
const uint8_t codec_info_opus_sink_capability[AVDT_CODEC_SIZE] = {
A2DP_OPUS_CODEC_LEN, // Length
AVDT_MEDIA_TYPE_AUDIO << 4, // Media Type
A2DP_MEDIA_CT_NON_A2DP, // Media Codec Type Vendor
(A2DP_OPUS_VENDOR_ID & 0x000000FF),
(A2DP_OPUS_VENDOR_ID & 0x0000FF00) >> 8,
(A2DP_OPUS_VENDOR_ID & 0x00FF0000) >> 16,
(A2DP_OPUS_VENDOR_ID & 0xFF000000) >> 24,
(A2DP_OPUS_CODEC_ID & 0x00FF),
(A2DP_OPUS_CODEC_ID & 0xFF00) >> 8,
A2DP_OPUS_CHANNEL_MODE_MONO | A2DP_OPUS_CHANNEL_MODE_STEREO |
A2DP_OPUS_10MS_FRAMESIZE | A2DP_OPUS_20MS_FRAMESIZE |
A2DP_OPUS_SAMPLING_FREQ_48000};
const uint8_t codec_info_non_a2dp[AVDT_CODEC_SIZE] = {
8, // Length
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
0xFF, // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
3, 4, 0, 0, // Vendor ID: LSB first, upper two octets should be 0
7, 8, // Codec ID: LSB first
9 // Fake
};
const uint8_t codec_info_non_a2dp_fake[AVDT_CODEC_SIZE] = {
8, // Length
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
0xFF, // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
3, 4, 0, 0, // Vendor ID: LSB first, upper two octets should be 0
7, 8, // Codec ID: LSB first
10 // Unused
};
static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
static bool has_shared_library(const char* name) {
void* lib_handle = dlopen(name, RTLD_NOW);
if (lib_handle != nullptr) {
dlclose(lib_handle);
return true;
}
return false;
}
} // namespace
class StackA2dpTest : public ::testing::Test {
protected:
StackA2dpTest() {
// Create the set with all supported codecs
for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX;
i++) {
btav_a2dp_codec_index_t codec_index =
static_cast<btav_a2dp_codec_index_t>(i);
bool supported = false;
switch (codec_index) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
// Codec aptX is supported only if the device has the corresponding
// shared library installed.
supported = has_shared_library(APTX_ENCODER_LIB_NAME);
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
// Codec aptX-HD is supported only if the device has the corresponding
// shared library installed.
supported = has_shared_library(APTX_HD_ENCODER_LIB_NAME);
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
// Codec LDAC is supported only if the device has the corresponding
// shared library installed.
supported = has_shared_library(LDAC_ENCODER_LIB_NAME);
break;
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
// Codec LDAC is supported only if the device has the corresponding
// shared library installed.
supported = has_shared_library(LDAC_DECODER_LIB_NAME);
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_MAX:
case BTAV_A2DP_CODEC_INDEX_SOURCE_MAX:
case BTAV_A2DP_CODEC_INDEX_SINK_MAX:
// Needed to avoid using "default:" case so we can capture when
// a new codec is added, and it can be included here.
break;
}
if (supported) {
supported_codecs_.insert(codec_index);
}
}
}
bool has_codec_support(btav_a2dp_codec_index_t codec_index) {
return supported_codecs_.find(codec_index) != supported_codecs_.end();
}
private:
std::set<btav_a2dp_codec_index_t> supported_codecs_;
};
class A2dpCodecConfigTest : public StackA2dpTest {};
TEST_F(StackA2dpTest, test_a2dp_bits_set) {
EXPECT_TRUE(A2DP_BitsSet(0x0) == A2DP_SET_ZERO_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x1) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x2) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x3) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x7f) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x80) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x81) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xc0) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xff) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x8000) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x8001) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xc000) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xffff) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x80000) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x80001) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xc0000) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xfffff) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x80000000) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x80000001) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xc0000000) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xffffffff) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x8000000000000000) == A2DP_SET_ONE_BIT);
EXPECT_TRUE(A2DP_BitsSet(0x8000000000000001) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xc000000000000000) == A2DP_SET_MULTL_BIT);
EXPECT_TRUE(A2DP_BitsSet(0xffffffffffffffff) == A2DP_SET_MULTL_BIT);
}
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_sbc) {
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc));
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc));
EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_sink_capability));
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_non_a2dp));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_non_a2dp));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_non_a2dp));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_non_a2dp));
// Test with invalid SBC codecs
uint8_t codec_info_sbc_invalid[AVDT_CODEC_SIZE];
memset(codec_info_sbc_invalid, 0, sizeof(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_invalid[0] = 0; // Corrupt the Length field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_invalid[1] = 0xff; // Corrupt the Media Type field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
}
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
ASSERT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_vbr));
ASSERT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_vbr_capability));
ASSERT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_vbr));
ASSERT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_vbr_capability));
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
// Test with invalid AAC codecs
uint8_t codec_info_aac_invalid[AVDT_CODEC_SIZE];
memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_invalid[0] = 0; // Corrupt the Length field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_invalid[1] = 0xff; // Corrupt the Media Type field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
}
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_opus) {
ASSERT_TRUE(A2DP_IsVendorSourceCodecValid(codec_info_opus));
ASSERT_TRUE(A2DP_IsVendorSourceCodecValid(codec_info_opus_capability));
ASSERT_TRUE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus));
ASSERT_TRUE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_capability));
ASSERT_TRUE(A2DP_IsVendorSinkCodecValid(codec_info_opus_sink_capability));
ASSERT_TRUE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_sink_capability));
// Test with invalid Opus configuration
uint8_t codec_info_opus_invalid[AVDT_CODEC_SIZE];
memcpy(codec_info_opus_invalid, codec_info_opus, sizeof(codec_info_opus));
codec_info_opus_invalid[0] = 0; // Corrupt the Length field
ASSERT_FALSE(A2DP_IsVendorSourceCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorSinkCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_invalid));
memcpy(codec_info_opus_invalid, codec_info_opus, sizeof(codec_info_opus));
codec_info_opus_invalid[1] = 0xff; // Corrupt the Media Type field
ASSERT_FALSE(A2DP_IsVendorSourceCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorSinkCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorPeerSourceCodecValid(codec_info_opus_invalid));
ASSERT_FALSE(A2DP_IsVendorPeerSinkCodecValid(codec_info_opus_invalid));
}
TEST_F(StackA2dpTest, test_a2dp_get_codec_type) {
tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(codec_info_sbc);
EXPECT_EQ(codec_type, A2DP_MEDIA_CT_SBC);
codec_type = A2DP_GetCodecType(codec_info_aac);
EXPECT_EQ(codec_type, A2DP_MEDIA_CT_AAC);
codec_type = A2DP_GetCodecType(codec_info_opus);
ASSERT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
codec_type = A2DP_GetCodecType(codec_info_non_a2dp);
EXPECT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
}
TEST_F(StackA2dpTest, test_a2dp_is_sink_codec_supported) {
EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_sbc));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac));
// NOTE: The test below should be EXPECT_FALSE.
// However, codec_info_aac_capability is practically same as codec_info_aac,
// therefore we cannot differentiate it as a capability.
EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
}
TEST_F(StackA2dpTest, test_a2dp_is_peer_source_codec_supported) {
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
}
TEST_F(StackA2dpTest, test_init_default_codec) {
uint8_t codec_info_result[AVDT_CODEC_SIZE];
memset(codec_info_result, 0, sizeof(codec_info_result));
A2DP_InitDefaultCodec(codec_info_result);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
}
TEST_F(StackA2dpTest, test_a2dp_uses_rtp_header) {
EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_sbc));
EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_sbc));
EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_aac));
EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_aac));
ASSERT_TRUE(A2DP_VendorUsesRtpHeader(true, codec_info_opus));
ASSERT_TRUE(A2DP_VendorUsesRtpHeader(false, codec_info_opus));
EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_non_a2dp));
EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_non_a2dp));
}
TEST_F(StackA2dpTest, test_a2dp_get_media_type) {
uint8_t codec_info_test[AVDT_CODEC_SIZE];
EXPECT_EQ(A2DP_GetMediaType(codec_info_sbc), AVDT_MEDIA_TYPE_AUDIO);
EXPECT_EQ(A2DP_GetMediaType(codec_info_aac), AVDT_MEDIA_TYPE_AUDIO);
EXPECT_EQ(A2DP_GetMediaType(codec_info_non_a2dp), AVDT_MEDIA_TYPE_AUDIO);
// Prepare fake codec info for video and for multimedia
memset(codec_info_test, 0, sizeof(codec_info_test));
codec_info_test[0] = sizeof(codec_info_test);
codec_info_test[1] = 0x01 << 4;
EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_VIDEO);
codec_info_test[1] = 0x02 << 4;
EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_MULTI);
}
TEST_F(StackA2dpTest, test_a2dp_codec_name) {
uint8_t codec_info_test[AVDT_CODEC_SIZE];
// Explicit tests for known codecs
EXPECT_STREQ(A2DP_CodecName(codec_info_sbc), "SBC");
EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_capability), "SBC");
EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_sink_capability), "SBC");
EXPECT_STREQ(A2DP_CodecName(codec_info_aac), "AAC");
EXPECT_STREQ(A2DP_CodecName(codec_info_aac_capability), "AAC");
EXPECT_STREQ(A2DP_CodecName(codec_info_aac_sink_capability), "AAC");
ASSERT_STREQ(A2DP_CodecName(codec_info_opus), "Opus");
ASSERT_STREQ(A2DP_CodecName(codec_info_opus_capability), "Opus");
ASSERT_STREQ(A2DP_CodecName(codec_info_opus_sink_capability), "Opus");
EXPECT_STREQ(A2DP_CodecName(codec_info_non_a2dp), "UNKNOWN VENDOR CODEC");
// Test all unknown codecs
memcpy(codec_info_test, codec_info_sbc, sizeof(codec_info_sbc));
for (uint8_t codec_type = A2DP_MEDIA_CT_AAC + 1;
codec_type < A2DP_MEDIA_CT_NON_A2DP; codec_type++) {
codec_info_test[2] = codec_type; // Unknown codec type
EXPECT_STREQ(A2DP_CodecName(codec_info_test), "UNKNOWN CODEC");
}
}
TEST_F(StackA2dpTest, test_a2dp_vendor) {
EXPECT_EQ(A2DP_VendorCodecGetVendorId(codec_info_non_a2dp),
(uint32_t)0x00000403);
EXPECT_EQ(A2DP_VendorCodecGetCodecId(codec_info_non_a2dp), (uint16_t)0x0807);
EXPECT_TRUE(A2DP_VendorUsesRtpHeader(true, codec_info_non_a2dp));
EXPECT_TRUE(A2DP_VendorUsesRtpHeader(false, codec_info_non_a2dp));
}
TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_capability));
EXPECT_TRUE(
A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_capability));
EXPECT_TRUE(
A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_sink_capability));
ASSERT_TRUE(
A2DP_VendorCodecTypeEquals(codec_info_opus, codec_info_opus_capability));
ASSERT_TRUE(A2DP_VendorCodecTypeEquals(codec_info_opus,
codec_info_opus_sink_capability));
EXPECT_TRUE(
A2DP_CodecTypeEquals(codec_info_non_a2dp, codec_info_non_a2dp_fake));
EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_non_a2dp));
EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_non_a2dp));
EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_aac));
}
TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
uint8_t codec_info_opus_test[AVDT_CODEC_SIZE];
uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
// Test two identical SBC codecs
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
// Test two identical AAC codecs
memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
// Test two identical Opus codecs
memset(codec_info_opus_test, 0xAB, sizeof(codec_info_opus_test));
memcpy(codec_info_opus_test, codec_info_opus, sizeof(codec_info_opus));
ASSERT_TRUE(A2DP_VendorCodecEquals(codec_info_opus, codec_info_opus_test));
// Test two identical non-A2DP codecs that are not recognized
memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
sizeof(codec_info_non_a2dp));
EXPECT_FALSE(A2DP_CodecEquals(codec_info_non_a2dp, codec_info_non_a2dp_test));
// Test two codecs that have different types
EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_non_a2dp));
ASSERT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_aac));
ASSERT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_opus));
// Test two SBC codecs that are slightly different
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_test[5] = codec_info_sbc[5] + 1;
EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
codec_info_sbc_test[5] = codec_info_sbc[5];
codec_info_sbc_test[6] = codec_info_sbc[6] + 1;
EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
// Test two AAC codecs that are slightly different
memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_test[7] = codec_info_aac[7] + 1;
EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
codec_info_aac_test[7] = codec_info_aac[7];
codec_info_aac_test[8] = codec_info_aac[8] + 1;
EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
// Test two SBC codecs that are identical, but with different fake
// trailer data.
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_test[7] = codec_info_sbc[7] + 1;
EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
// Test two AAC codecs that are identical, but with different fake
// trailer data.
memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_test[9] = codec_info_aac[9] + 1;
EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
}
TEST_F(StackA2dpTest, test_a2dp_get_track_sample_rate) {
EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_sbc), 44100);
EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_aac), 44100);
ASSERT_EQ(A2DP_VendorGetTrackSampleRate(codec_info_opus), 48000);
EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_track_channel_count) {
EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_sbc), 2);
EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_aac), 2);
ASSERT_EQ(A2DP_VendorGetTrackChannelCount(codec_info_opus), 2);
EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_number_of_subbands_sbc) {
EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_sbc), 8);
EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_number_of_blocks_sbc) {
EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_sbc), 16);
EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_allocation_method_code_sbc) {
EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_sbc), 0);
EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_sbc) {
EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_sbc), 3);
EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_sampling_frequency_code_sbc) {
EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_sbc), 2);
EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_min_bitpool_sbc) {
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc), 2);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_capability), 2);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_sink_capability), 2);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_max_bitpool_sbc) {
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc), 53);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_capability), 53);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_sink_capability), 53);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), 3);
ASSERT_EQ(A2DP_VendorGetSinkTrackChannelType(codec_info_opus), 2);
EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_object_type_code_aac) {
EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_sbc), -1);
EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_aac), 0x80);
EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_aac) {
EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_sbc), -1);
EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_aac), 0x04);
EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_variable_bit_rate_support_aac) {
EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_sbc), -1);
EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_aac), 0);
EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_bit_rate_aac) {
EXPECT_EQ(A2DP_GetBitRateAac(codec_info_sbc), -1);
EXPECT_EQ(A2DP_GetBitRateAac(codec_info_aac), 320000);
EXPECT_EQ(A2DP_GetBitRateAac(codec_info_non_a2dp), -1);
}
TEST_F(StackA2dpTest, test_a2dp_get_packet_timestamp) {
uint8_t a2dp_data[1000];
uint32_t timestamp;
uint32_t* p_ts = reinterpret_cast<uint32_t*>(a2dp_data);
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
*p_ts = 0x12345678;
timestamp = 0xFFFFFFFF;
EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_sbc, a2dp_data, &timestamp));
EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
*p_ts = 0x12345678;
timestamp = 0xFFFFFFFF;
EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_aac, a2dp_data, &timestamp));
EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
*p_ts = 0x12345678;
timestamp = 0xFFFFFFFF;
ASSERT_TRUE(
A2DP_VendorGetPacketTimestamp(codec_info_opus, a2dp_data, &timestamp));
ASSERT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
*p_ts = 0x12345678;
timestamp = 0xFFFFFFFF;
EXPECT_FALSE(
A2DP_GetPacketTimestamp(codec_info_non_a2dp, a2dp_data, &timestamp));
}
TEST_F(StackA2dpTest, test_a2dp_build_codec_header) {
uint8_t a2dp_data[1000];
BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(a2dp_data);
const uint16_t BT_HDR_LEN = 500;
const uint16_t BT_HDR_OFFSET = 50;
const uint8_t FRAMES_PER_PACKET = 0xCD;
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
p_buf->len = BT_HDR_LEN;
p_buf->offset = BT_HDR_OFFSET;
EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_sbc, p_buf, FRAMES_PER_PACKET));
EXPECT_EQ(p_buf->offset + 1,
BT_HDR_OFFSET); // Modified by A2DP_SBC_MPL_HDR_LEN
EXPECT_EQ(p_buf->len - 1, BT_HDR_LEN); // Modified by A2DP_SBC_MPL_HDR_LEN
const uint8_t* p =
reinterpret_cast<const uint8_t*>(p_buf + 1) + p_buf->offset;
EXPECT_EQ(
*p, static_cast<uint8_t>(0x0D)); // 0xCD masked with A2DP_SBC_HDR_NUM_MSK
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
p_buf->len = BT_HDR_LEN;
p_buf->offset = BT_HDR_OFFSET;
EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_aac, p_buf, FRAMES_PER_PACKET));
memset(a2dp_data, 0xAB, sizeof(a2dp_data));
p_buf->len = BT_HDR_LEN;
p_buf->offset = BT_HDR_OFFSET;
EXPECT_FALSE(
A2DP_BuildCodecHeader(codec_info_non_a2dp, p_buf, FRAMES_PER_PACKET));
}
TEST_F(StackA2dpTest, test_a2dp_adjust_codec) {
uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
// Test updating a valid SBC codec that doesn't need adjustment
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
EXPECT_TRUE(
memcmp(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc)) == 0);
// Test updating a valid SBC codec that needs adjustment
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_test[6] = 54; // A2DP_SBC_MAX_BITPOOL + 1
EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
EXPECT_TRUE(
memcmp(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc)) == 0);
// Test updating an invalid SBC codec
memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
codec_info_sbc_test[6] = 255; // Invalid MAX_BITPOOL
EXPECT_FALSE(A2DP_AdjustCodec(codec_info_sbc_test));
// Test updating a valid AAC codec that doesn't need adjustment
memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
EXPECT_TRUE(A2DP_AdjustCodec(codec_info_aac_test));
EXPECT_TRUE(
memcmp(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac)) == 0);
// Test updating a non-A2DP codec that is not recognized
memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
sizeof(codec_info_non_a2dp));
EXPECT_FALSE(A2DP_AdjustCodec(codec_info_non_a2dp_test));
}
TEST_F(StackA2dpTest, test_a2dp_source_codec_index) {
// Explicit tests for known Source codecs
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc),
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_sink_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac),
BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_sink_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus),
BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
ASSERT_EQ(A2DP_VendorSourceCodecIndex(codec_info_opus_sink_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_non_a2dp),
BTAV_A2DP_CODEC_INDEX_MAX);
}
TEST_F(StackA2dpTest, test_a2dp_sink_codec_index) {
// Explicit tests for known Sink codecs
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc),
BTAV_A2DP_CODEC_INDEX_SINK_SBC);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc_capability),
BTAV_A2DP_CODEC_INDEX_SINK_SBC);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_sbc_sink_capability),
BTAV_A2DP_CODEC_INDEX_SINK_SBC);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac),
BTAV_A2DP_CODEC_INDEX_SINK_AAC);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac_capability),
BTAV_A2DP_CODEC_INDEX_SINK_AAC);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_aac_sink_capability),
BTAV_A2DP_CODEC_INDEX_SINK_AAC);
ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus),
BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus_capability),
BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
ASSERT_EQ(A2DP_VendorSinkCodecIndex(codec_info_opus_sink_capability),
BTAV_A2DP_CODEC_INDEX_SINK_OPUS);
EXPECT_EQ(A2DP_SinkCodecIndex(codec_info_non_a2dp),
BTAV_A2DP_CODEC_INDEX_MAX);
}
TEST_F(StackA2dpTest, test_a2dp_codec_index_str) {
// Explicit tests for known codecs
EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC), "SBC");
EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_SBC), "SBC SINK");
EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC), "AAC");
ASSERT_STREQ(A2DP_VendorCodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS),
"Opus");
ASSERT_STREQ(A2DP_VendorCodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_OPUS),
"Opus SINK");
// Test that the unknown codec string has not changed
EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_MAX),
"UNKNOWN CODEC INDEX");
// Test that each codec has a known string
for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
if ((i >= BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN &&
i < BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MAX) ||
(i >= BTAV_A2DP_CODEC_INDEX_SINK_EXT_MIN &&
i < BTAV_A2DP_CODEC_INDEX_SINK_EXT_MAX)) {
continue;
}
btav_a2dp_codec_index_t codec_index =
static_cast<btav_a2dp_codec_index_t>(i);
EXPECT_STRNE(A2DP_CodecIndexStr(codec_index), "UNKNOWN CODEC INDEX");
}
}
TEST_F(StackA2dpTest, test_a2dp_init_codec_config) {
AvdtpSepConfig avdt_cfg;
//
// Test for SBC Source
//
memset(&avdt_cfg, 0, sizeof(avdt_cfg));
EXPECT_TRUE(
A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, &avdt_cfg));
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc_capability[0] + 1; i++) {
EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_capability[i]);
}
//
// Test for SBC Sink
//
memset(&avdt_cfg, 0, sizeof(avdt_cfg));
EXPECT_TRUE(A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_SBC, &avdt_cfg));
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc_sink_capability[0] + 1; i++) {
EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_sink_capability[i]);
}
//
// Test for AAC Source
//
memset(&avdt_cfg, 0, sizeof(avdt_cfg));
ASSERT_TRUE(
A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, &avdt_cfg));
// Check the vbr mode status.
bool aac_vbr_mode_enabled =
avdt_cfg.codec_info[6] & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
// Compare the result codec with the local test codec info
if (aac_vbr_mode_enabled) {
for (size_t i = 0; i < codec_info_aac_vbr_capability[0] + 1; i++) {
ASSERT_EQ(avdt_cfg.codec_info[i], codec_info_aac_vbr_capability[i]);
}
} else {
for (size_t i = 0; i < codec_info_aac_capability[0] + 1; i++) {
ASSERT_EQ(avdt_cfg.codec_info[i], codec_info_aac_capability[i]);
}
}
}
TEST_F(A2dpCodecConfigTest, createCodec) {
for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
btav_a2dp_codec_index_t codec_index =
static_cast<btav_a2dp_codec_index_t>(i);
// Ignore codecs that are not supported on the device
if (!has_codec_support(codec_index)) {
continue;
}
A2dpCodecConfig* codec_config = A2dpCodecConfig::createCodec(codec_index);
EXPECT_NE(codec_config, nullptr);
EXPECT_EQ(codec_config->codecIndex(), codec_index);
EXPECT_FALSE(codec_config->name().empty());
EXPECT_NE(codec_config->codecPriority(), BTAV_A2DP_CODEC_PRIORITY_DISABLED);
EXPECT_NE(codec_config->codecPriority(), BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
delete codec_config;
}
}
TEST_F(A2dpCodecConfigTest, setCodecConfig) {
uint8_t codec_info_result[AVDT_CODEC_SIZE];
btav_a2dp_codec_index_t peer_codec_index;
A2dpCodecs* a2dp_codecs =
new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());
A2dpCodecConfig* codec_config;
EXPECT_TRUE(a2dp_codecs->init());
// Create the codec capability - SBC
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc_sink_capability);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config =
a2dp_codecs->findSourceCodecConfig(codec_info_sbc_sink_capability);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setCodecConfig(
codec_info_sbc_sink_capability, true /* is_capability */,
codec_info_result, true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec config - SBC
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_sbc);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setCodecConfig(
codec_info_sbc, false /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
EXPECT_FALSE(codec_config->useRtpHeaderMarkerBit());
// Create the codec config - AAC
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setCodecConfig(
codec_info_aac, false /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
}
EXPECT_TRUE(codec_config->useRtpHeaderMarkerBit());
// Create the codec capability - SBC Sink
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SinkCodecIndex(codec_info_sbc_capability);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_sbc_capability);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
codec_info_sbc_capability, true /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec capability - AAC Sink
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SinkCodecIndex(codec_info_aac_capability);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_aac_capability);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
codec_info_aac_capability, true /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
}
EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec config - SBC Sink
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SinkCodecIndex(codec_info_sbc);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_sbc);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
codec_info_sbc, false /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec config - AAC Sink
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SinkCodecIndex(codec_info_aac);
EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSinkCodecConfig(codec_info_aac);
EXPECT_NE(codec_config, nullptr);
EXPECT_TRUE(a2dp_codecs->setSinkCodecConfig(
codec_info_aac, false /* is_capability */, codec_info_result,
true /* select_current_codec */));
EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
}
EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Test invalid codec info
uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
memset(codec_info_result, 0, sizeof(codec_info_result));
memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
EXPECT_FALSE(a2dp_codecs->setCodecConfig(
codec_info_sbc_test1, true /* is_capability */, codec_info_result,
true /* select_current_codec */));
AvdtpSepConfig avdt_cfg;
memset(&avdt_cfg, 0, sizeof(avdt_cfg));
ASSERT_TRUE(
A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, &avdt_cfg));
bool aac_vbr_mode_enabled =
avdt_cfg.codec_info[6] & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
// Create the codec capability - AAC
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac_sink_capability);
ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config =
a2dp_codecs->findSourceCodecConfig(codec_info_aac_sink_capability);
ASSERT_NE(codec_config, nullptr);
ASSERT_TRUE(a2dp_codecs->setCodecConfig(
codec_info_aac_sink_capability, true /* is_capability */,
codec_info_result, true /* select_current_codec */));
ASSERT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
if (aac_vbr_mode_enabled) {
for (size_t i = 0; i < codec_info_aac_vbr[0] + 1; i++) {
ASSERT_EQ(codec_info_result[i], codec_info_aac_vbr[i]);
}
} else {
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
ASSERT_EQ(codec_info_result[i], codec_info_aac[i]);
}
}
ASSERT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec config - AAC with vbr
memset(codec_info_result, 0, sizeof(codec_info_result));
peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac_vbr);
ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac_vbr);
ASSERT_NE(codec_config, nullptr);
ASSERT_TRUE(a2dp_codecs->setCodecConfig(
codec_info_aac_vbr, false /* is_capability */, codec_info_result,
true /* select_current_codec */));
ASSERT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
// Compare the result codec with the local test codec info
if (aac_vbr_mode_enabled) {
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
ASSERT_EQ(codec_info_result[i], codec_info_aac_vbr[i]);
}
} else {
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
ASSERT_EQ(codec_info_result[i], codec_info_aac[i]);
}
}
ASSERT_TRUE(codec_config->useRtpHeaderMarkerBit());
delete a2dp_codecs;
}
TEST_F(A2dpCodecConfigTest, init) {
std::vector<btav_a2dp_codec_config_t> default_priorities;
A2dpCodecs codecs(default_priorities);
EXPECT_TRUE(codecs.init());
const std::list<A2dpCodecConfig*> orderedSourceCodecs =
codecs.orderedSourceCodecs();
EXPECT_FALSE(orderedSourceCodecs.empty());
const std::list<A2dpCodecConfig*> orderedSinkCodecs =
codecs.orderedSinkCodecs();
EXPECT_FALSE(orderedSinkCodecs.empty());
}