aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2019-12-18 17:27:58 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-12-18 17:27:58 +0000
commit250f2a29e1082850813c5ede00bdfe782ddd4e41 (patch)
tree90ec5825db7fbc1e28590f16858668ec37815f91
parentd9d2be500c775e0e6fdac0b5108d043d8b43ab0b (diff)
parent74f321c51e2115d0d95d206a2668eccd28224f56 (diff)
downloadbt-250f2a29e1082850813c5ede00bdfe782ddd4e41.tar.gz
Merge "A2DP: HAL codec offloading capabilities check preparation"
-rw-r--r--audio_hal_interface/Android.bp2
-rw-r--r--audio_hal_interface/a2dp_encoding.cc324
-rw-r--r--audio_hal_interface/a2dp_encoding.h5
-rw-r--r--audio_hal_interface/client_interface.cc84
-rw-r--r--audio_hal_interface/client_interface.h9
-rw-r--r--audio_hal_interface/client_interface_unittest.cc474
-rw-r--r--audio_hal_interface/codec_status.cc569
-rw-r--r--audio_hal_interface/codec_status.h60
-rw-r--r--btif/src/btif_av.cc7
9 files changed, 1089 insertions, 445 deletions
diff --git a/audio_hal_interface/Android.bp b/audio_hal_interface/Android.bp
index 1714323a4..7731338af 100644
--- a/audio_hal_interface/Android.bp
+++ b/audio_hal_interface/Android.bp
@@ -13,6 +13,7 @@ cc_library_static {
srcs: [
"a2dp_encoding.cc",
"client_interface.cc",
+ "codec_status.cc",
"hearing_aid_software_encoding.cc",
],
shared_libs: [
@@ -36,6 +37,7 @@ cc_test {
defaults: ["fluoride_defaults"],
include_dirs: [
"system/bt",
+ "system/bt/stack/include",
],
srcs: [
"client_interface_unittest.cc",
diff --git a/audio_hal_interface/a2dp_encoding.cc b/audio_hal_interface/a2dp_encoding.cc
index 1b362e594..e415a7ab5 100644
--- a/audio_hal_interface/a2dp_encoding.cc
+++ b/audio_hal_interface/a2dp_encoding.cc
@@ -16,11 +16,8 @@
#include "a2dp_encoding.h"
#include "client_interface.h"
+#include "codec_status.h"
-#include "a2dp_aac_constants.h"
-#include "a2dp_sbc_constants.h"
-#include "a2dp_vendor_ldac_constants.h"
-#include "bta/av/bta_av_int.h"
#include "btif_a2dp_source.h"
#include "btif_av.h"
#include "btif_av_co.h"
@@ -29,30 +26,23 @@
namespace {
-using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
-using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
-using ::android::hardware::bluetooth::audio::V2_0::CodecType;
-using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
-using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
-using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
-using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
-using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
-using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::bluetooth::audio::AudioCapabilities;
using ::bluetooth::audio::AudioConfiguration;
using ::bluetooth::audio::BitsPerSample;
using ::bluetooth::audio::BluetoothAudioCtrlAck;
using ::bluetooth::audio::ChannelMode;
-using ::bluetooth::audio::CodecConfiguration;
using ::bluetooth::audio::PcmParameters;
using ::bluetooth::audio::SampleRate;
using ::bluetooth::audio::SessionType;
-const CodecConfiguration kInvalidCodecConfiguration = {
- .codecType = CodecType::UNKNOWN,
- .encodedAudioBitrate = 0x00000000,
- .peerMtu = 0xffff,
- .isScmstEnabled = false,
- .config = {}};
+using ::bluetooth::audio::codec::A2dpAacToHalConfig;
+using ::bluetooth::audio::codec::A2dpAptxToHalConfig;
+using ::bluetooth::audio::codec::A2dpCodecToHalBitsPerSample;
+using ::bluetooth::audio::codec::A2dpCodecToHalChannelMode;
+using ::bluetooth::audio::codec::A2dpCodecToHalSampleRate;
+using ::bluetooth::audio::codec::A2dpLdacToHalConfig;
+using ::bluetooth::audio::codec::A2dpSbcToHalConfig;
+using ::bluetooth::audio::codec::CodecConfiguration;
BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack);
@@ -226,301 +216,43 @@ BluetoothAudioCtrlAck a2dp_ack_to_bt_audio_ctrl_ack(tA2DP_CTRL_ACK ack) {
}
}
-SampleRate a2dp_codec_to_hal_sample_rate(
- const btav_a2dp_codec_config_t& a2dp_codec_config) {
- switch (a2dp_codec_config.sample_rate) {
- case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
- return SampleRate::RATE_44100;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
- return SampleRate::RATE_48000;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
- return SampleRate::RATE_88200;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
- return SampleRate::RATE_96000;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
- return SampleRate::RATE_176400;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
- return SampleRate::RATE_192000;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
- return SampleRate::RATE_16000;
- case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
- return SampleRate::RATE_24000;
- default:
- return SampleRate::RATE_UNKNOWN;
- }
-}
-
-BitsPerSample a2dp_codec_to_hal_bits_per_sample(
- const btav_a2dp_codec_config_t& a2dp_codec_config) {
- switch (a2dp_codec_config.bits_per_sample) {
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
- return BitsPerSample::BITS_16;
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
- return BitsPerSample::BITS_24;
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
- return BitsPerSample::BITS_32;
- default:
- return BitsPerSample::BITS_UNKNOWN;
- }
-}
-
-ChannelMode a2dp_codec_to_hal_channel_mode(
- const btav_a2dp_codec_config_t& a2dp_codec_config) {
- switch (a2dp_codec_config.channel_mode) {
- case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
- return ChannelMode::MONO;
- case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
- return ChannelMode::STEREO;
- default:
- return ChannelMode::UNKNOWN;
- }
-}
-
bool a2dp_get_selected_hal_codec_config(CodecConfiguration* codec_config) {
- A2dpCodecConfig* a2dp_codec_configs = bta_av_get_a2dp_current_codec();
- if (a2dp_codec_configs == nullptr) {
+ A2dpCodecConfig* a2dp_config = bta_av_get_a2dp_current_codec();
+ if (a2dp_config == nullptr) {
LOG(WARNING) << __func__ << ": failure to get A2DP codec config";
- *codec_config = kInvalidCodecConfiguration;
+ *codec_config = ::bluetooth::audio::codec::kInvalidCodecConfiguration;
return false;
}
- btav_a2dp_codec_config_t current_codec = a2dp_codec_configs->getCodecConfig();
- tBT_A2DP_OFFLOAD a2dp_offload;
- a2dp_codec_configs->getCodecSpecificConfig(&a2dp_offload);
+ btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig();
switch (current_codec.codec_type) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
[[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_SBC: {
- codec_config->codecType = CodecType::SBC;
- codec_config->config.sbcConfig({});
- auto sbc_config = codec_config->config.sbcConfig();
- sbc_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
- if (sbc_config.sampleRate == SampleRate::RATE_UNKNOWN) {
- LOG(ERROR) << __func__
- << ": Unknown SBC sample_rate=" << current_codec.sample_rate;
+ if (!A2dpSbcToHalConfig(codec_config, a2dp_config)) {
return false;
}
- uint8_t channel_mode = a2dp_offload.codec_info[3] & A2DP_SBC_IE_CH_MD_MSK;
- switch (channel_mode) {
- case A2DP_SBC_IE_CH_MD_JOINT:
- sbc_config.channelMode = SbcChannelMode::JOINT_STEREO;
- break;
- case A2DP_SBC_IE_CH_MD_STEREO:
- sbc_config.channelMode = SbcChannelMode::STEREO;
- break;
- case A2DP_SBC_IE_CH_MD_DUAL:
- sbc_config.channelMode = SbcChannelMode::DUAL;
- break;
- case A2DP_SBC_IE_CH_MD_MONO:
- sbc_config.channelMode = SbcChannelMode::MONO;
- break;
- default:
- LOG(ERROR) << __func__
- << ": Unknown SBC channel_mode=" << channel_mode;
- sbc_config.channelMode = SbcChannelMode::UNKNOWN;
- return false;
- }
- uint8_t block_length =
- a2dp_offload.codec_info[0] & A2DP_SBC_IE_BLOCKS_MSK;
- switch (block_length) {
- case A2DP_SBC_IE_BLOCKS_4:
- sbc_config.blockLength = SbcBlockLength::BLOCKS_4;
- break;
- case A2DP_SBC_IE_BLOCKS_8:
- sbc_config.blockLength = SbcBlockLength::BLOCKS_8;
- break;
- case A2DP_SBC_IE_BLOCKS_12:
- sbc_config.blockLength = SbcBlockLength::BLOCKS_12;
- break;
- case A2DP_SBC_IE_BLOCKS_16:
- sbc_config.blockLength = SbcBlockLength::BLOCKS_16;
- break;
- default:
- LOG(ERROR) << __func__
- << ": Unknown SBC block_length=" << block_length;
- return false;
- }
- uint8_t sub_bands = a2dp_offload.codec_info[0] & A2DP_SBC_IE_SUBBAND_MSK;
- switch (sub_bands) {
- case A2DP_SBC_IE_SUBBAND_4:
- sbc_config.numSubbands = SbcNumSubbands::SUBBAND_4;
- break;
- case A2DP_SBC_IE_SUBBAND_8:
- sbc_config.numSubbands = SbcNumSubbands::SUBBAND_8;
- break;
- default:
- LOG(ERROR) << __func__ << ": Unknown SBC Subbands=" << sub_bands;
- return false;
- }
- uint8_t alloc_method =
- a2dp_offload.codec_info[0] & A2DP_SBC_IE_ALLOC_MD_MSK;
- switch (alloc_method) {
- case A2DP_SBC_IE_ALLOC_MD_S:
- sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_S;
- break;
- case A2DP_SBC_IE_ALLOC_MD_L:
- sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_L;
- break;
- default:
- LOG(ERROR) << __func__
- << ": Unknown SBC alloc_method=" << alloc_method;
- return false;
- }
- sbc_config.minBitpool = a2dp_offload.codec_info[1];
- sbc_config.maxBitpool = a2dp_offload.codec_info[2];
- sbc_config.bitsPerSample =
- a2dp_codec_to_hal_bits_per_sample(current_codec);
- if (sbc_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown SBC bits_per_sample="
- << current_codec.bits_per_sample;
- return false;
- }
- codec_config->config.sbcConfig(sbc_config);
break;
}
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
[[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_AAC: {
- codec_config->codecType = CodecType::AAC;
- codec_config->config.aacConfig({});
- auto aac_config = codec_config->config.aacConfig();
- uint8_t object_type = a2dp_offload.codec_info[0];
- switch (object_type) {
- case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
- aac_config.objectType = AacObjectType::MPEG2_LC;
- break;
- case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
- aac_config.objectType = AacObjectType::MPEG4_LC;
- break;
- case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
- aac_config.objectType = AacObjectType::MPEG4_LTP;
- break;
- case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
- aac_config.objectType = AacObjectType::MPEG4_SCALABLE;
- break;
- default:
- LOG(ERROR) << __func__
- << ": Unknown AAC object_type=" << +object_type;
- return false;
- }
- aac_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
- if (aac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
- LOG(ERROR) << __func__
- << ": Unknown AAC sample_rate=" << current_codec.sample_rate;
- return false;
- }
- aac_config.channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
- if (aac_config.channelMode == ChannelMode::UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown AAC channel_mode="
- << current_codec.channel_mode;
- return false;
- }
- uint8_t vbr_enabled =
- a2dp_offload.codec_info[1] & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
- switch (vbr_enabled) {
- case A2DP_AAC_VARIABLE_BIT_RATE_ENABLED:
- aac_config.variableBitRateEnabled = AacVariableBitRate::ENABLED;
- break;
- case A2DP_AAC_VARIABLE_BIT_RATE_DISABLED:
- aac_config.variableBitRateEnabled = AacVariableBitRate::DISABLED;
- break;
- default:
- LOG(ERROR) << __func__ << ": Unknown AAC VBR=" << +vbr_enabled;
- return false;
- }
- aac_config.bitsPerSample =
- a2dp_codec_to_hal_bits_per_sample(current_codec);
- if (aac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown AAC bits_per_sample="
- << current_codec.bits_per_sample;
+ if (!A2dpAacToHalConfig(codec_config, a2dp_config)) {
return false;
}
- codec_config->config.aacConfig(aac_config);
break;
}
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
[[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD: {
- if (current_codec.codec_type == BTAV_A2DP_CODEC_INDEX_SOURCE_APTX) {
- codec_config->codecType = CodecType::APTX;
- } else {
- codec_config->codecType = CodecType::APTX_HD;
- }
- codec_config->config.aptxConfig({});
- auto aptx_config = codec_config->config.aptxConfig();
- aptx_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
- if (aptx_config.sampleRate == SampleRate::RATE_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown aptX sample_rate="
- << current_codec.sample_rate;
- return false;
- }
- aptx_config.channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
- if (aptx_config.channelMode == ChannelMode::UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown aptX channel_mode="
- << current_codec.channel_mode;
+ if (!A2dpAptxToHalConfig(codec_config, a2dp_config)) {
return false;
}
- aptx_config.bitsPerSample =
- a2dp_codec_to_hal_bits_per_sample(current_codec);
- if (aptx_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown aptX bits_per_sample="
- << current_codec.bits_per_sample;
- return false;
- }
- codec_config->config.aptxConfig(aptx_config);
break;
}
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC: {
- codec_config->codecType = CodecType::LDAC;
- codec_config->config.ldacConfig({});
- auto ldac_config = codec_config->config.ldacConfig();
- ldac_config.sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
- if (ldac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown LDAC sample_rate="
- << current_codec.sample_rate;
+ if (!A2dpLdacToHalConfig(codec_config, a2dp_config)) {
return false;
}
- switch (a2dp_offload.codec_info[7]) {
- case A2DP_LDAC_CHANNEL_MODE_STEREO:
- ldac_config.channelMode = LdacChannelMode::STEREO;
- break;
- case A2DP_LDAC_CHANNEL_MODE_DUAL:
- ldac_config.channelMode = LdacChannelMode::DUAL;
- break;
- case A2DP_LDAC_CHANNEL_MODE_MONO:
- ldac_config.channelMode = LdacChannelMode::MONO;
- break;
- default:
- LOG(ERROR) << __func__ << ": Unknown LDAC channel_mode="
- << a2dp_offload.codec_info[7];
- ldac_config.channelMode = LdacChannelMode::UNKNOWN;
- return false;
- }
- switch (a2dp_offload.codec_info[6]) {
- case A2DP_LDAC_QUALITY_HIGH:
- ldac_config.qualityIndex = LdacQualityIndex::QUALITY_HIGH;
- break;
- case A2DP_LDAC_QUALITY_MID:
- ldac_config.qualityIndex = LdacQualityIndex::QUALITY_MID;
- break;
- case A2DP_LDAC_QUALITY_LOW:
- ldac_config.qualityIndex = LdacQualityIndex::QUALITY_LOW;
- break;
- case A2DP_LDAC_QUALITY_ABR_OFFLOAD:
- ldac_config.qualityIndex = LdacQualityIndex::QUALITY_ABR;
- break;
- default:
- LOG(ERROR) << __func__ << ": Unknown LDAC QualityIndex="
- << a2dp_offload.codec_info[6];
- return false;
- }
- ldac_config.bitsPerSample =
- a2dp_codec_to_hal_bits_per_sample(current_codec);
- if (ldac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
- LOG(ERROR) << __func__ << ": Unknown LDAC bits_per_sample="
- << current_codec.bits_per_sample;
- return false;
- }
- codec_config->config.ldacConfig(ldac_config);
break;
}
case BTAV_A2DP_CODEC_INDEX_MAX:
@@ -528,16 +260,15 @@ bool a2dp_get_selected_hal_codec_config(CodecConfiguration* codec_config) {
default:
LOG(ERROR) << __func__
<< ": Unknown codec_type=" << current_codec.codec_type;
- codec_config->codecType = CodecType::UNKNOWN;
- codec_config->config = {};
+ *codec_config = ::bluetooth::audio::codec::kInvalidCodecConfiguration;
return false;
}
- codec_config->encodedAudioBitrate = a2dp_codec_configs->getTrackBitRate();
+ codec_config->encodedAudioBitrate = a2dp_config->getTrackBitRate();
// Obtain the MTU
RawAddress peer_addr = btif_av_source_active_peer();
tA2DP_ENCODER_INIT_PEER_PARAMS peer_param;
bta_av_co_get_peer_params(peer_addr, &peer_param);
- int effectiveMtu = a2dp_codec_configs->getEffectiveMtu();
+ int effectiveMtu = a2dp_config->getEffectiveMtu();
if (effectiveMtu > 0 && effectiveMtu < peer_param.peer_mtu) {
codec_config->peerMtu = effectiveMtu;
} else {
@@ -558,9 +289,9 @@ bool a2dp_get_selected_hal_pcm_config(PcmParameters* pcm_config) {
}
btav_a2dp_codec_config_t current_codec = a2dp_codec_configs->getCodecConfig();
- pcm_config->sampleRate = a2dp_codec_to_hal_sample_rate(current_codec);
- pcm_config->bitsPerSample = a2dp_codec_to_hal_bits_per_sample(current_codec);
- pcm_config->channelMode = a2dp_codec_to_hal_channel_mode(current_codec);
+ pcm_config->sampleRate = A2dpCodecToHalSampleRate(current_codec);
+ pcm_config->bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
+ pcm_config->channelMode = A2dpCodecToHalChannelMode(current_codec);
return (pcm_config->sampleRate != SampleRate::RATE_UNKNOWN &&
pcm_config->bitsPerSample != BitsPerSample::BITS_UNKNOWN &&
pcm_config->channelMode != ChannelMode::UNKNOWN);
@@ -574,13 +305,18 @@ bool is_hal_2_0_force_disabled() {
}
return btaudio_a2dp_disabled;
}
-
} // namespace
namespace bluetooth {
namespace audio {
namespace a2dp {
+bool update_codec_offloading_capabilities(
+ const std::vector<btav_a2dp_codec_config_t>& framework_preference) {
+ return ::bluetooth::audio::codec::UpdateOffloadingCapabilities(
+ framework_preference);
+}
+
// Checking if new bluetooth_audio is enabled
bool is_hal_2_0_enabled() { return a2dp_hal_clientif != nullptr; }
diff --git a/audio_hal_interface/a2dp_encoding.h b/audio_hal_interface/a2dp_encoding.h
index 7b104ff39..03c94d543 100644
--- a/audio_hal_interface/a2dp_encoding.h
+++ b/audio_hal_interface/a2dp_encoding.h
@@ -16,6 +16,8 @@
#pragma once
+#include <vector>
+
#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
#include "common/message_loop_thread.h"
@@ -23,6 +25,9 @@ namespace bluetooth {
namespace audio {
namespace a2dp {
+bool update_codec_offloading_capabilities(
+ const std::vector<btav_a2dp_codec_config_t>& framework_preference);
+
// Check if new bluetooth_audio is enabled
bool is_hal_2_0_enabled();
diff --git a/audio_hal_interface/client_interface.cc b/audio_hal_interface/client_interface.cc
index 87b39b3e4..fd68a3767 100644
--- a/audio_hal_interface/client_interface.cc
+++ b/audio_hal_interface/client_interface.cc
@@ -207,19 +207,8 @@ BluetoothAudioClientInterface::BluetoothAudioClientInterface(IBluetoothTransport
bluetooth::common::MessageLoopThread* message_loop)
: sink_(sink), provider_(nullptr), session_started_(false), mDataMQ(nullptr),
death_recipient_(new BluetoothAudioDeathRecipient(this, message_loop)) {
- auto service_manager = android::hardware::defaultServiceManager1_2();
- CHECK(service_manager != nullptr);
- size_t instance_count = 0;
- auto listManifestByInterface_cb = [&instance_count](const hidl_vec<android::hardware::hidl_string>& instanceNames) {
- instance_count = instanceNames.size();
- LOG(INFO) << "listManifestByInterface_cb returns " << instance_count << " instance(s)";
- };
- auto hidl_retval = service_manager->listManifestByInterface(kFullyQualifiedInterfaceName, listManifestByInterface_cb);
- if (!hidl_retval.isOk()) {
- LOG(FATAL) << __func__ << ": IServiceManager::listByInterface failure: " << hidl_retval.description();
- }
- if (instance_count > 0) {
- fetch_audio_provider();
+ if (IsSupported()) {
+ FetchAudioProvider();
} else {
LOG(WARNING) << "IBluetoothAudioProvidersFactory not declared";
}
@@ -239,7 +228,57 @@ BluetoothAudioClientInterface::GetAudioCapabilities() const {
return capabilities_;
}
-void BluetoothAudioClientInterface::fetch_audio_provider() {
+bool BluetoothAudioClientInterface::IsSupported() {
+ auto service_manager = android::hardware::defaultServiceManager1_2();
+ CHECK(service_manager != nullptr);
+ size_t instance_count = 0;
+ auto listManifestByInterface_cb =
+ [&instance_count](
+ const hidl_vec<android::hardware::hidl_string>& instanceNames) {
+ instance_count = instanceNames.size();
+ LOG(INFO) << "listManifestByInterface_cb returns " << instance_count
+ << " instance(s)";
+ };
+ auto hidl_retval = service_manager->listManifestByInterface(
+ kFullyQualifiedInterfaceName, listManifestByInterface_cb);
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__ << ": IServiceManager::listByInterface failure: "
+ << hidl_retval.description();
+ return false;
+ }
+ return (instance_count > 0);
+}
+
+std::vector<AudioCapabilities>
+BluetoothAudioClientInterface::GetAudioCapabilities(SessionType session_type) {
+ std::vector<AudioCapabilities> capabilities(0);
+ if (!IsSupported()) return capabilities;
+
+ android::sp<IBluetoothAudioProvidersFactory> providersFactory =
+ IBluetoothAudioProvidersFactory::getService();
+ CHECK(providersFactory != nullptr)
+ << "IBluetoothAudioProvidersFactory::getService() failed";
+ LOG(INFO) << "IBluetoothAudioProvidersFactory::getService() returned "
+ << providersFactory.get()
+ << (providersFactory->isRemote() ? " (remote)" : " (local)");
+
+ auto getProviderCapabilities_cb =
+ [&capabilities](const hidl_vec<AudioCapabilities>& audioCapabilities) {
+ for (auto capability : audioCapabilities) {
+ capabilities.push_back(capability);
+ }
+ };
+ auto hidl_retval = providersFactory->getProviderCapabilities(
+ session_type, getProviderCapabilities_cb);
+ if (!hidl_retval.isOk()) {
+ LOG(FATAL) << __func__
+ << ": BluetoothAudioHal::getProviderCapabilities failure: "
+ << hidl_retval.description();
+ }
+ return capabilities;
+}
+
+void BluetoothAudioClientInterface::FetchAudioProvider() {
if (provider_ != nullptr) {
LOG(WARNING) << __func__ << ": reflash";
}
@@ -251,20 +290,16 @@ void BluetoothAudioClientInterface::fetch_audio_provider() {
<< providersFactory.get()
<< (providersFactory->isRemote() ? " (remote)" : " (local)");
- std::promise<void> getProviderCapabilities_promise;
- auto getProviderCapabilities_future =
- getProviderCapabilities_promise.get_future();
auto getProviderCapabilities_cb =
- [& capabilities = this->capabilities_, &getProviderCapabilities_promise](
+ [& capabilities = this->capabilities_](
const hidl_vec<AudioCapabilities>& audioCapabilities) {
+ capabilities.clear();
for (auto capability : audioCapabilities) {
capabilities.push_back(capability);
}
- getProviderCapabilities_promise.set_value();
};
auto hidl_retval = providersFactory->getProviderCapabilities(
sink_->GetSessionType(), getProviderCapabilities_cb);
- getProviderCapabilities_future.get();
if (!hidl_retval.isOk()) {
LOG(FATAL) << __func__ << ": BluetoothAudioHal::getProviderCapabilities failure: " << hidl_retval.description();
return;
@@ -508,9 +543,12 @@ size_t BluetoothAudioClientInterface::WriteAudioData(uint8_t* p_buf,
void BluetoothAudioClientInterface::RenewAudioProviderAndSession() {
// NOTE: must be invoked on the same thread where this
// BluetoothAudioClientInterface is running
- fetch_audio_provider();
- session_started_ = false;
- StartSession();
+ FetchAudioProvider();
+ if (session_started_) {
+ LOG(INFO) << __func__ << ": Restart the session while audio HAL recovering";
+ session_started_ = false;
+ StartSession();
+ }
}
} // namespace audio
diff --git a/audio_hal_interface/client_interface.h b/audio_hal_interface/client_interface.h
index 8ee2bb110..226ca16aa 100644
--- a/audio_hal_interface/client_interface.h
+++ b/audio_hal_interface/client_interface.h
@@ -18,6 +18,7 @@
#include <time.h>
#include <mutex>
+#include <vector>
#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvider.h>
#include <android/hardware/bluetooth/audio/2.0/types.h>
@@ -35,8 +36,6 @@ using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
-using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
-using ::android::hardware::bluetooth::audio::V2_0::CodecType;
using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider;
using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
@@ -136,6 +135,8 @@ class BluetoothAudioClientInterface {
}
std::vector<AudioCapabilities> GetAudioCapabilities() const;
+ static std::vector<AudioCapabilities> GetAudioCapabilities(
+ SessionType session_type);
bool UpdateAudioConfig(const AudioConfiguration& audioConfig);
@@ -163,8 +164,10 @@ class BluetoothAudioClientInterface {
};
private:
+ static bool IsSupported();
+
// Helper function to connect to an IBluetoothAudioProvider
- void fetch_audio_provider();
+ void FetchAudioProvider();
mutable std::mutex internal_mutex_;
IBluetoothTransportInstance* sink_;
diff --git a/audio_hal_interface/client_interface_unittest.cc b/audio_hal_interface/client_interface_unittest.cc
index fd8c8dca0..f487f85a9 100644
--- a/audio_hal_interface/client_interface_unittest.cc
+++ b/audio_hal_interface/client_interface_unittest.cc
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "client_interface.h"
+#include "codec_status.h"
namespace {
@@ -25,7 +26,6 @@ using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
-using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
using ::android::hardware::bluetooth::audio::V2_0::CodecType;
using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
@@ -38,24 +38,76 @@ using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
using ::bluetooth::audio::AudioCapabilities;
using ::bluetooth::audio::AudioConfiguration;
-using ::bluetooth::audio::BitsPerSample;
using ::bluetooth::audio::BluetoothAudioClientInterface;
using ::bluetooth::audio::BluetoothAudioStatus;
-using ::bluetooth::audio::ChannelMode;
using ::bluetooth::audio::PcmParameters;
-using ::bluetooth::audio::SampleRate;
using ::bluetooth::audio::SessionType;
+using ::bluetooth::audio::codec::A2dpCodecToHalBitsPerSample;
+using ::bluetooth::audio::codec::A2dpCodecToHalChannelMode;
+using ::bluetooth::audio::codec::A2dpCodecToHalSampleRate;
+using ::bluetooth::audio::codec::BitsPerSample;
+using ::bluetooth::audio::codec::ChannelMode;
+using ::bluetooth::audio::codec::CodecConfiguration;
+using ::bluetooth::audio::codec::IsCodecOffloadingEnabled;
+using ::bluetooth::audio::codec::SampleRate;
+using ::bluetooth::audio::codec::UpdateOffloadingCapabilities;
using ::testing::Test;
-constexpr SampleRate kSampleRates[9] = {
- SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000,
- SampleRate::RATE_88200, SampleRate::RATE_96000, SampleRate::RATE_176400,
- SampleRate::RATE_192000, SampleRate::RATE_16000, SampleRate::RATE_24000};
-constexpr BitsPerSample kBitsPerSamples[4] = {
- BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
- BitsPerSample::BITS_32};
-constexpr ChannelMode kChannelModes[3] = {
- ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+struct SampleRatePair {
+ SampleRate hal_sample_rate_;
+ btav_a2dp_codec_sample_rate_t btav_sample_rate_;
+};
+constexpr SampleRatePair kSampleRatePairs[9] = {
+ {.hal_sample_rate_ = SampleRate::RATE_UNKNOWN,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE},
+ {.hal_sample_rate_ = SampleRate::RATE_44100,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_44100},
+ {.hal_sample_rate_ = SampleRate::RATE_48000,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_48000},
+ {.hal_sample_rate_ = SampleRate::RATE_88200,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_88200},
+ {.hal_sample_rate_ = SampleRate::RATE_96000,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_96000},
+ {.hal_sample_rate_ = SampleRate::RATE_176400,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_176400},
+ {.hal_sample_rate_ = SampleRate::RATE_192000,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_192000},
+ {.hal_sample_rate_ = SampleRate::RATE_16000,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_16000},
+ {.hal_sample_rate_ = SampleRate::RATE_24000,
+ .btav_sample_rate_ = BTAV_A2DP_CODEC_SAMPLE_RATE_24000}};
+
+struct BitsPerSamplePair {
+ BitsPerSample hal_bits_per_sample_;
+ btav_a2dp_codec_bits_per_sample_t btav_bits_per_sample_;
+};
+constexpr BitsPerSamplePair kBitsPerSamplePairs[4] = {
+ {.hal_bits_per_sample_ = BitsPerSample::BITS_UNKNOWN,
+ .btav_bits_per_sample_ = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE},
+ {.hal_bits_per_sample_ = BitsPerSample::BITS_16,
+ .btav_bits_per_sample_ = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16},
+ {.hal_bits_per_sample_ = BitsPerSample::BITS_24,
+ .btav_bits_per_sample_ = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24},
+ {.hal_bits_per_sample_ = BitsPerSample::BITS_32,
+ .btav_bits_per_sample_ = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32}};
+
+struct ChannelModePair {
+ ChannelMode hal_channel_mode_;
+ btav_a2dp_codec_channel_mode_t btav_channel_mode_;
+};
+constexpr ChannelModePair kChannelModePairs[3] = {
+ {.hal_channel_mode_ = ChannelMode::UNKNOWN,
+ .btav_channel_mode_ = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE},
+ {.hal_channel_mode_ = ChannelMode::MONO,
+ .btav_channel_mode_ = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO},
+ {.hal_channel_mode_ = ChannelMode::STEREO,
+ .btav_channel_mode_ = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO}};
+
+constexpr btav_a2dp_codec_index_t codec_indexes[] = {
+ BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
+ BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
+ BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, BTAV_A2DP_CODEC_INDEX_SINK_SBC,
+ BTAV_A2DP_CODEC_INDEX_SINK_AAC, BTAV_A2DP_CODEC_INDEX_SINK_LDAC};
constexpr uint16_t kPeerMtus[5] = {660, 663, 883, 1005, 1500};
class TestTransport : public bluetooth::audio::IBluetoothTransportInstance {
@@ -94,15 +146,17 @@ class TestTransport : public bluetooth::audio::IBluetoothTransportInstance {
class BluetoothAudioClientInterfaceTest : public Test {
protected:
- TestTransport* test_transport_;
- BluetoothAudioClientInterface* clientif_;
+ TestTransport* test_transport_ = nullptr;
+ BluetoothAudioClientInterface* clientif_ = nullptr;
static constexpr int kClientIfReturnSuccess = 0;
void SetUp() override {}
void TearDown() override {
+ if (clientif_ != nullptr) delete clientif_;
clientif_ = nullptr;
+ if (test_transport_ != nullptr) delete test_transport_;
test_transport_ = nullptr;
}
@@ -121,8 +175,7 @@ class BluetoothAudioClientInterfaceTest : public Test {
return (is_pcm_config_valid && is_pcm_config_supported);
}
- bool IsOffloadCodecConfigurationSupported(
- const CodecConfiguration& codec_config) {
+ bool IsCodecOffloadingSupported(const CodecConfiguration& codec_config) {
CodecCapabilities codec_capability = {};
for (auto audio_capability : clientif_->GetAudioCapabilities()) {
if (audio_capability.codecCapabilities().codecType ==
@@ -197,18 +250,38 @@ class BluetoothAudioClientInterfaceTest : public Test {
} // namespace
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpCodecToHalPcmConfig) {
+ btav_a2dp_codec_config_t a2dp_codec_config = {};
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ a2dp_codec_config.sample_rate = sample_rate_pair.btav_sample_rate_;
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ a2dp_codec_config.bits_per_sample =
+ bits_per_sample_pair.btav_bits_per_sample_;
+ for (auto channel_mode_pair : kChannelModePairs) {
+ a2dp_codec_config.channel_mode = channel_mode_pair.btav_channel_mode_;
+ EXPECT_EQ(A2dpCodecToHalSampleRate(a2dp_codec_config),
+ sample_rate_pair.hal_sample_rate_);
+ EXPECT_EQ(A2dpCodecToHalBitsPerSample(a2dp_codec_config),
+ bits_per_sample_pair.hal_bits_per_sample_);
+ EXPECT_EQ(A2dpCodecToHalChannelMode(a2dp_codec_config),
+ channel_mode_pair.hal_channel_mode_);
+ } // ChannelMode
+ } // BitsPerSampple
+ } // SampleRate
+}
+
TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpSoftwareSession) {
test_transport_ =
new TestTransport(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
PcmParameters pcm_config = {};
- for (auto sample_rate : kSampleRates) {
- pcm_config.sampleRate = sample_rate;
- for (auto bits_per_sample : kBitsPerSamples) {
- pcm_config.bitsPerSample = bits_per_sample;
- for (auto channel_mode : kChannelModes) {
- pcm_config.channelMode = channel_mode;
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ pcm_config.sampleRate = sample_rate_pair.hal_sample_rate_;
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ pcm_config.bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_;
+ for (auto channel_mode_pair : kChannelModePairs) {
+ pcm_config.channelMode = channel_mode_pair.hal_channel_mode_;
audio_config.pcmConfig(pcm_config);
clientif_->UpdateAudioConfig(audio_config);
if (IsSoftwarePcmParametersSupported(pcm_config)) {
@@ -222,11 +295,36 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpSoftwareSession) {
} // SampleRate
}
-TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
- test_transport_ =
- new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
- clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
- AudioConfiguration audio_config = {};
+struct CodecOffloadingPreference {
+ bool is_target_codec_included_;
+ std::vector<btav_a2dp_codec_config_t> preference_;
+};
+
+std::vector<CodecOffloadingPreference> CodecOffloadingPreferenceGenerator(
+ btav_a2dp_codec_index_t target_codec_index) {
+ std::vector<CodecOffloadingPreference> codec_offloading_preferences = {
+ {.is_target_codec_included_ = false,
+ .preference_ = std::vector<btav_a2dp_codec_config_t>(0)}};
+ btav_a2dp_codec_config_t a2dp_codec_config = {};
+ for (auto codec_index : codec_indexes) {
+ a2dp_codec_config.codec_type = codec_index;
+ auto duplicated_preferences = codec_offloading_preferences;
+ for (auto iter = duplicated_preferences.begin();
+ iter != duplicated_preferences.end(); ++iter) {
+ if (codec_index == target_codec_index) {
+ iter->is_target_codec_included_ = true;
+ }
+ iter->preference_.push_back(a2dp_codec_config);
+ }
+ codec_offloading_preferences.insert(codec_offloading_preferences.end(),
+ duplicated_preferences.begin(),
+ duplicated_preferences.end());
+ }
+ return codec_offloading_preferences;
+}
+
+std::vector<CodecConfiguration> SbcCodecConfigurationsGenerator() {
+ std::vector<CodecConfiguration> sbc_codec_configs;
CodecConfiguration codec_config = {};
SbcBlockLength block_lengths[4] = {
SbcBlockLength::BLOCKS_4, SbcBlockLength::BLOCKS_8,
@@ -235,9 +333,9 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
SbcNumSubbands::SUBBAND_8};
SbcAllocMethod alloc_methods[2] = {SbcAllocMethod::ALLOC_MD_S,
SbcAllocMethod::ALLOC_MD_L};
- for (auto sample_rate : kSampleRates) {
- for (auto bits_per_sample : kBitsPerSamples) {
- for (auto channel_mode : kChannelModes) {
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ for (auto channel_mode_pair : kChannelModePairs) {
for (auto peer_mtu : kPeerMtus) {
for (auto block_length : block_lengths) {
for (auto num_subband : num_subbands) {
@@ -248,25 +346,19 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
// A2DP_SBC_DEFAULT_BITRATE
codec_config.encodedAudioBitrate = 328000;
SbcParameters sbc = {
- .sampleRate = sample_rate,
- .channelMode = (channel_mode == ChannelMode::MONO
+ .sampleRate = sample_rate_pair.hal_sample_rate_,
+ .channelMode = (channel_mode_pair.hal_channel_mode_ ==
+ ChannelMode::MONO
? SbcChannelMode::MONO
: SbcChannelMode::JOINT_STEREO),
.blockLength = block_length,
.numSubbands = num_subband,
.allocMethod = alloc_method,
- .bitsPerSample = bits_per_sample,
+ .bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_,
.minBitpool = 2,
.maxBitpool = 53};
codec_config.config.sbcConfig(sbc);
- audio_config.codecConfig(codec_config);
- clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
- EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
- } else {
- EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
- }
- EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ sbc_codec_configs.push_back(codec_config);
} // SbcAllocMethod
} // SbcNumSubbands
} // SbcBlockLength
@@ -274,22 +366,56 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
} // ChannelMode
} // BitsPerSampple
} // SampleRate
+ return sbc_codec_configs;
}
-TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAacSession) {
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpSbcCodecOffloadingState) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ auto sbc_codec_configs = SbcCodecConfigurationsGenerator();
+ for (auto codec_offloading_preference :
+ CodecOffloadingPreferenceGenerator(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC)) {
+ UpdateOffloadingCapabilities(codec_offloading_preference.preference_);
+ for (CodecConfiguration codec_config : sbc_codec_configs) {
+ if (IsCodecOffloadingSupported(codec_config) &&
+ codec_offloading_preference.is_target_codec_included_) {
+ ASSERT_TRUE(IsCodecOffloadingEnabled(codec_config));
+ } else {
+ ASSERT_FALSE(IsCodecOffloadingEnabled(codec_config));
+ }
+ }
+ }
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
test_transport_ =
new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
+ for (CodecConfiguration codec_config : SbcCodecConfigurationsGenerator()) {
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsCodecOffloadingSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ }
+}
+
+std::vector<CodecConfiguration> AacCodecConfigurationsGenerator() {
+ std::vector<CodecConfiguration> aac_codec_configs;
CodecConfiguration codec_config = {};
AacObjectType object_types[4] = {
AacObjectType::MPEG2_LC, AacObjectType::MPEG4_LC,
AacObjectType::MPEG4_LTP, AacObjectType::MPEG4_SCALABLE};
AacVariableBitRate variable_bitrates[2] = {AacVariableBitRate::DISABLED,
AacVariableBitRate::ENABLED};
- for (auto sample_rate : kSampleRates) {
- for (auto bits_per_sample : kBitsPerSamples) {
- for (auto channel_mode : kChannelModes) {
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ for (auto channel_mode_pair : kChannelModePairs) {
for (auto peer_mtu : kPeerMtus) {
for (auto object_type : object_types) {
for (auto variable_bitrate : variable_bitrates) {
@@ -298,40 +424,68 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAacSession) {
codec_config.isScmstEnabled = false;
// A2DP_AAC_DEFAULT_BITRATE
codec_config.encodedAudioBitrate = 320000;
- AacParameters aac = {.objectType = object_type,
- .sampleRate = sample_rate,
- .channelMode = channel_mode,
- .variableBitRateEnabled = variable_bitrate,
- .bitsPerSample = bits_per_sample};
+ AacParameters aac = {
+ .objectType = object_type,
+ .sampleRate = sample_rate_pair.hal_sample_rate_,
+ .channelMode = channel_mode_pair.hal_channel_mode_,
+ .variableBitRateEnabled = variable_bitrate,
+ .bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_};
codec_config.config.aacConfig(aac);
- audio_config.codecConfig(codec_config);
- clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
- EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
- } else {
- EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
- }
- EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ aac_codec_configs.push_back(codec_config);
} // AacVariableBitRate
} // AacObjectType
} // peerMtu
} // ChannelMode
} // BitsPerSampple
} // SampleRate
+ return aac_codec_configs;
}
-TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadLdacSession) {
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpAacCodecOffloadingState) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ auto aac_codec_configs = AacCodecConfigurationsGenerator();
+ for (auto codec_offloading_preference :
+ CodecOffloadingPreferenceGenerator(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC)) {
+ UpdateOffloadingCapabilities(codec_offloading_preference.preference_);
+ for (CodecConfiguration codec_config : aac_codec_configs) {
+ if (IsCodecOffloadingSupported(codec_config) &&
+ codec_offloading_preference.is_target_codec_included_) {
+ ASSERT_TRUE(IsCodecOffloadingEnabled(codec_config));
+ } else {
+ ASSERT_FALSE(IsCodecOffloadingEnabled(codec_config));
+ }
+ }
+ }
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAacSession) {
test_transport_ =
new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
+ for (CodecConfiguration codec_config : AacCodecConfigurationsGenerator()) {
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsCodecOffloadingSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ }
+}
+
+std::vector<CodecConfiguration> LdacCodecConfigurationsGenerator() {
+ std::vector<CodecConfiguration> ldac_codec_configs;
CodecConfiguration codec_config = {};
LdacQualityIndex quality_indexes[4] = {
LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
- for (auto sample_rate : kSampleRates) {
- for (auto bits_per_sample : kBitsPerSamples) {
- for (auto channel_mode : kChannelModes) {
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ for (auto channel_mode_pair : kChannelModePairs) {
for (auto peer_mtu : kPeerMtus) {
for (auto quality_index : quality_indexes) {
codec_config.codecType = CodecType::LDAC;
@@ -339,58 +493,142 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadLdacSession) {
codec_config.isScmstEnabled = false;
codec_config.encodedAudioBitrate = 990000;
LdacParameters ldac = {
- .sampleRate = sample_rate,
- .channelMode = (channel_mode == ChannelMode::MONO
- ? LdacChannelMode::MONO
- : LdacChannelMode::STEREO),
+ .sampleRate = sample_rate_pair.hal_sample_rate_,
+ .channelMode =
+ (channel_mode_pair.hal_channel_mode_ == ChannelMode::MONO
+ ? LdacChannelMode::MONO
+ : LdacChannelMode::STEREO),
.qualityIndex = quality_index,
- .bitsPerSample = bits_per_sample};
+ .bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_};
codec_config.config.ldacConfig(ldac);
- audio_config.codecConfig(codec_config);
- clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
- EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
- } else {
- EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
- }
- EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ ldac_codec_configs.push_back(codec_config);
} // LdacQualityIndex
} // peerMtu
} // ChannelMode
} // BitsPerSampple
} // SampleRate
+ return ldac_codec_configs;
}
-TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxSession) {
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpLdacCodecOffloadingState) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ auto ldac_codec_configs = LdacCodecConfigurationsGenerator();
+ for (auto codec_offloading_preference :
+ CodecOffloadingPreferenceGenerator(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC)) {
+ UpdateOffloadingCapabilities(codec_offloading_preference.preference_);
+ for (CodecConfiguration codec_config : ldac_codec_configs) {
+ if (IsCodecOffloadingSupported(codec_config) &&
+ codec_offloading_preference.is_target_codec_included_) {
+ ASSERT_TRUE(IsCodecOffloadingEnabled(codec_config));
+ } else {
+ ASSERT_FALSE(IsCodecOffloadingEnabled(codec_config));
+ }
+ }
+ }
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadLdacSession) {
test_transport_ =
new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
+ for (CodecConfiguration codec_config : LdacCodecConfigurationsGenerator()) {
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsCodecOffloadingSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ }
+}
+
+std::vector<CodecConfiguration> AptxCodecConfigurationsGenerator(
+ CodecType codec_type) {
+ std::vector<CodecConfiguration> aptx_codec_configs;
+ if (codec_type != CodecType::APTX && codec_type != CodecType::APTX_HD)
+ return aptx_codec_configs;
CodecConfiguration codec_config = {};
- for (auto sample_rate : kSampleRates) {
- for (auto bits_per_sample : kBitsPerSamples) {
- for (auto channel_mode : kChannelModes) {
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ for (auto channel_mode_pair : kChannelModePairs) {
for (auto peer_mtu : kPeerMtus) {
- codec_config.codecType = CodecType::APTX;
+ codec_config.codecType = codec_type;
codec_config.peerMtu = peer_mtu;
codec_config.isScmstEnabled = false;
- codec_config.encodedAudioBitrate = 352000;
- AptxParameters aptx = {.sampleRate = sample_rate,
- .channelMode = channel_mode,
- .bitsPerSample = bits_per_sample};
+ codec_config.encodedAudioBitrate =
+ (codec_type == CodecType::APTX ? 352000 : 576000);
+ AptxParameters aptx = {
+ .sampleRate = sample_rate_pair.hal_sample_rate_,
+ .channelMode = channel_mode_pair.hal_channel_mode_,
+ .bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_};
codec_config.config.aptxConfig(aptx);
- audio_config.codecConfig(codec_config);
- clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
- EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
- } else {
- EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
- }
- EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ aptx_codec_configs.push_back(codec_config);
} // peerMtu
} // ChannelMode
} // BitsPerSampple
} // SampleRate
+ return aptx_codec_configs;
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpAptxCodecOffloadingState) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ auto aptx_codec_configs = AptxCodecConfigurationsGenerator(CodecType::APTX);
+ for (auto codec_offloading_preference :
+ CodecOffloadingPreferenceGenerator(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX)) {
+ UpdateOffloadingCapabilities(codec_offloading_preference.preference_);
+ for (CodecConfiguration codec_config : aptx_codec_configs) {
+ if (IsCodecOffloadingSupported(codec_config) &&
+ codec_offloading_preference.is_target_codec_included_) {
+ ASSERT_TRUE(IsCodecOffloadingEnabled(codec_config));
+ } else {
+ ASSERT_FALSE(IsCodecOffloadingEnabled(codec_config));
+ }
+ }
+ }
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxSession) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ AudioConfiguration audio_config = {};
+ for (CodecConfiguration codec_config :
+ AptxCodecConfigurationsGenerator(CodecType::APTX)) {
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsCodecOffloadingSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ }
+}
+
+TEST_F(BluetoothAudioClientInterfaceTest, A2dpAptxHdCodecOffloadingState) {
+ test_transport_ =
+ new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
+ auto aptx_hd_codec_configs =
+ AptxCodecConfigurationsGenerator(CodecType::APTX_HD);
+ for (auto codec_offloading_preference : CodecOffloadingPreferenceGenerator(
+ BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD)) {
+ UpdateOffloadingCapabilities(codec_offloading_preference.preference_);
+ for (CodecConfiguration codec_config : aptx_hd_codec_configs) {
+ if (IsCodecOffloadingSupported(codec_config) &&
+ codec_offloading_preference.is_target_codec_included_) {
+ ASSERT_TRUE(IsCodecOffloadingEnabled(codec_config));
+ } else {
+ ASSERT_FALSE(IsCodecOffloadingEnabled(codec_config));
+ }
+ }
+ }
}
TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxHdSession) {
@@ -398,31 +636,17 @@ TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxHdSession) {
new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
- CodecConfiguration codec_config = {};
- for (auto sample_rate : kSampleRates) {
- for (auto bits_per_sample : kBitsPerSamples) {
- for (auto channel_mode : kChannelModes) {
- for (auto peer_mtu : kPeerMtus) {
- codec_config.codecType = CodecType::APTX_HD;
- codec_config.peerMtu = peer_mtu;
- codec_config.isScmstEnabled = false;
- codec_config.encodedAudioBitrate = 576000;
- AptxParameters aptx = {.sampleRate = sample_rate,
- .channelMode = channel_mode,
- .bitsPerSample = bits_per_sample};
- codec_config.config.aptxConfig(aptx);
- audio_config.codecConfig(codec_config);
- clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
- EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
- } else {
- EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
- }
- EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
- } // peerMtu
- } // ChannelMode
- } // BitsPerSampple
- } // SampleRate
+ for (CodecConfiguration codec_config :
+ AptxCodecConfigurationsGenerator(CodecType::APTX_HD)) {
+ audio_config.codecConfig(codec_config);
+ clientif_->UpdateAudioConfig(audio_config);
+ if (IsCodecOffloadingSupported(codec_config)) {
+ EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
+ } else {
+ EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
+ }
+ EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
+ }
}
TEST_F(BluetoothAudioClientInterfaceTest,
@@ -439,7 +663,7 @@ TEST_F(BluetoothAudioClientInterfaceTest,
codec_config.config = {};
audio_config.codecConfig(codec_config);
clientif_->UpdateAudioConfig(audio_config);
- if (IsOffloadCodecConfigurationSupported(codec_config)) {
+ if (IsCodecOffloadingSupported(codec_config)) {
EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
} else {
EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
@@ -454,12 +678,12 @@ TEST_F(BluetoothAudioClientInterfaceTest,
clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
AudioConfiguration audio_config = {};
PcmParameters pcm_config = {};
- for (auto sample_rate : kSampleRates) {
- pcm_config.sampleRate = sample_rate;
- for (auto bits_per_sample : kBitsPerSamples) {
- pcm_config.bitsPerSample = bits_per_sample;
- for (auto channel_mode : kChannelModes) {
- pcm_config.channelMode = channel_mode;
+ for (auto sample_rate_pair : kSampleRatePairs) {
+ pcm_config.sampleRate = sample_rate_pair.hal_sample_rate_;
+ for (auto bits_per_sample_pair : kBitsPerSamplePairs) {
+ pcm_config.bitsPerSample = bits_per_sample_pair.hal_bits_per_sample_;
+ for (auto channel_mode_pair : kChannelModePairs) {
+ pcm_config.channelMode = channel_mode_pair.hal_channel_mode_;
audio_config.pcmConfig(pcm_config);
clientif_->UpdateAudioConfig(audio_config);
if (IsSoftwarePcmParametersSupported(pcm_config)) {
diff --git a/audio_hal_interface/codec_status.cc b/audio_hal_interface/codec_status.cc
new file mode 100644
index 000000000..0819e5c38
--- /dev/null
+++ b/audio_hal_interface/codec_status.cc
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2019 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 "codec_status.h"
+#include "client_interface.h"
+
+#include "a2dp_aac_constants.h"
+#include "a2dp_sbc_constants.h"
+#include "a2dp_vendor_aptx_constants.h"
+#include "a2dp_vendor_aptx_hd_constants.h"
+#include "a2dp_vendor_ldac_constants.h"
+#include "bta/av/bta_av_int.h"
+
+namespace {
+
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+
+// capabilities from BluetoothAudioClientInterface::GetAudioCapabilities()
+std::vector<AudioCapabilities> audio_hal_capabilities(0);
+// capabilities that audio HAL supports and frameworks / Bluetooth SoC / runtime
+// preference would like to use.
+std::vector<AudioCapabilities> offloading_preference(0);
+
+bool sbc_offloading_capability_match(const SbcParameters& sbc_capability,
+ const SbcParameters& sbc_config) {
+ if ((static_cast<SampleRate>(sbc_capability.sampleRate &
+ sbc_config.sampleRate) ==
+ SampleRate::RATE_UNKNOWN) ||
+ (static_cast<SbcChannelMode>(sbc_capability.channelMode &
+ sbc_config.channelMode) ==
+ SbcChannelMode::UNKNOWN) ||
+ (static_cast<SbcBlockLength>(sbc_capability.blockLength &
+ sbc_config.blockLength) ==
+ static_cast<SbcBlockLength>(0)) ||
+ (static_cast<SbcNumSubbands>(sbc_capability.numSubbands &
+ sbc_config.numSubbands) ==
+ static_cast<SbcNumSubbands>(0)) ||
+ (static_cast<SbcAllocMethod>(sbc_capability.allocMethod &
+ sbc_config.allocMethod) ==
+ static_cast<SbcAllocMethod>(0)) ||
+ (static_cast<BitsPerSample>(sbc_capability.bitsPerSample &
+ sbc_config.bitsPerSample) ==
+ BitsPerSample::BITS_UNKNOWN) ||
+ (sbc_config.minBitpool < sbc_capability.minBitpool ||
+ sbc_config.maxBitpool < sbc_config.minBitpool ||
+ sbc_capability.maxBitpool < sbc_config.maxBitpool)) {
+ LOG(WARNING) << __func__ << ": software codec=" << toString(sbc_config)
+ << " capability=" << toString(sbc_capability);
+ return false;
+ }
+ VLOG(1) << __func__ << ": offloading codec=" << toString(sbc_config)
+ << " capability=" << toString(sbc_capability);
+ return true;
+}
+
+bool aac_offloading_capability_match(const AacParameters& aac_capability,
+ const AacParameters& aac_config) {
+ if ((static_cast<AacObjectType>(aac_capability.objectType &
+ aac_config.objectType) ==
+ static_cast<AacObjectType>(0)) ||
+ (static_cast<SampleRate>(aac_capability.sampleRate &
+ aac_config.sampleRate) ==
+ SampleRate::RATE_UNKNOWN) ||
+ (static_cast<ChannelMode>(aac_capability.channelMode &
+ aac_config.channelMode) ==
+ ChannelMode::UNKNOWN) ||
+ (aac_capability.variableBitRateEnabled != AacVariableBitRate::ENABLED &&
+ aac_config.variableBitRateEnabled != AacVariableBitRate::DISABLED) ||
+ (static_cast<BitsPerSample>(aac_capability.bitsPerSample &
+ aac_config.bitsPerSample) ==
+ BitsPerSample::BITS_UNKNOWN)) {
+ LOG(WARNING) << __func__ << ": software codec=" << toString(aac_config)
+ << " capability=" << toString(aac_capability);
+ return false;
+ }
+ VLOG(1) << __func__ << ": offloading codec=" << toString(aac_config)
+ << " capability=" << toString(aac_capability);
+ return true;
+}
+
+bool aptx_offloading_capability_match(const AptxParameters& aptx_capability,
+ const AptxParameters& aptx_config) {
+ if ((static_cast<SampleRate>(aptx_capability.sampleRate &
+ aptx_config.sampleRate) ==
+ SampleRate::RATE_UNKNOWN) ||
+ (static_cast<ChannelMode>(aptx_capability.channelMode &
+ aptx_config.channelMode) ==
+ ChannelMode::UNKNOWN) ||
+ (static_cast<BitsPerSample>(aptx_capability.bitsPerSample &
+ aptx_config.bitsPerSample) ==
+ BitsPerSample::BITS_UNKNOWN)) {
+ LOG(WARNING) << __func__ << ": software codec=" << toString(aptx_config)
+ << " capability=" << toString(aptx_capability);
+ return false;
+ }
+ VLOG(1) << __func__ << ": offloading codec=" << toString(aptx_config)
+ << " capability=" << toString(aptx_capability);
+ return true;
+}
+
+bool ldac_offloading_capability_match(const LdacParameters& ldac_capability,
+ const LdacParameters& ldac_config) {
+ if ((static_cast<SampleRate>(ldac_capability.sampleRate &
+ ldac_config.sampleRate) ==
+ SampleRate::RATE_UNKNOWN) ||
+ (static_cast<LdacChannelMode>(ldac_capability.channelMode &
+ ldac_config.channelMode) ==
+ LdacChannelMode::UNKNOWN) ||
+ (static_cast<BitsPerSample>(ldac_capability.bitsPerSample &
+ ldac_config.bitsPerSample) ==
+ BitsPerSample::BITS_UNKNOWN)) {
+ LOG(WARNING) << __func__ << ": software codec=" << toString(ldac_config)
+ << " capability=" << toString(ldac_capability);
+ return false;
+ }
+ VLOG(1) << __func__ << ": offloading codec=" << toString(ldac_config)
+ << " capability=" << toString(ldac_capability);
+ return true;
+}
+} // namespace
+
+namespace bluetooth {
+namespace audio {
+namespace codec {
+
+const CodecConfiguration kInvalidCodecConfiguration = {
+ .codecType = CodecType::UNKNOWN,
+ .encodedAudioBitrate = 0x00000000,
+ .peerMtu = 0xffff,
+ .isScmstEnabled = false,
+ .config = {}};
+
+SampleRate A2dpCodecToHalSampleRate(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ return SampleRate::RATE_44100;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ return SampleRate::RATE_48000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ return SampleRate::RATE_88200;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ return SampleRate::RATE_96000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ return SampleRate::RATE_176400;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ return SampleRate::RATE_192000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
+ return SampleRate::RATE_16000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
+ return SampleRate::RATE_24000;
+ default:
+ return SampleRate::RATE_UNKNOWN;
+ }
+}
+
+BitsPerSample A2dpCodecToHalBitsPerSample(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return BitsPerSample::BITS_16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return BitsPerSample::BITS_24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return BitsPerSample::BITS_32;
+ default:
+ return BitsPerSample::BITS_UNKNOWN;
+ }
+}
+
+ChannelMode A2dpCodecToHalChannelMode(
+ const btav_a2dp_codec_config_t& a2dp_codec_config) {
+ switch (a2dp_codec_config.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ return ChannelMode::MONO;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ return ChannelMode::STEREO;
+ default:
+ return ChannelMode::UNKNOWN;
+ }
+}
+
+bool A2dpSbcToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config) {
+ btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig();
+ if (current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SOURCE_SBC &&
+ current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SINK_SBC) {
+ *codec_config = {};
+ return false;
+ }
+ tBT_A2DP_OFFLOAD a2dp_offload;
+ a2dp_config->getCodecSpecificConfig(&a2dp_offload);
+ codec_config->codecType = CodecType::SBC;
+ codec_config->config.sbcConfig({});
+ auto sbc_config = codec_config->config.sbcConfig();
+ sbc_config.sampleRate = A2dpCodecToHalSampleRate(current_codec);
+ if (sbc_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown SBC sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ uint8_t channel_mode = a2dp_offload.codec_info[3] & A2DP_SBC_IE_CH_MD_MSK;
+ switch (channel_mode) {
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ sbc_config.channelMode = SbcChannelMode::JOINT_STEREO;
+ break;
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ sbc_config.channelMode = SbcChannelMode::STEREO;
+ break;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ sbc_config.channelMode = SbcChannelMode::DUAL;
+ break;
+ case A2DP_SBC_IE_CH_MD_MONO:
+ sbc_config.channelMode = SbcChannelMode::MONO;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown SBC channel_mode=" << channel_mode;
+ sbc_config.channelMode = SbcChannelMode::UNKNOWN;
+ return false;
+ }
+ uint8_t block_length = a2dp_offload.codec_info[0] & A2DP_SBC_IE_BLOCKS_MSK;
+ switch (block_length) {
+ case A2DP_SBC_IE_BLOCKS_4:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_4;
+ break;
+ case A2DP_SBC_IE_BLOCKS_8:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_8;
+ break;
+ case A2DP_SBC_IE_BLOCKS_12:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_12;
+ break;
+ case A2DP_SBC_IE_BLOCKS_16:
+ sbc_config.blockLength = SbcBlockLength::BLOCKS_16;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown SBC block_length=" << block_length;
+ return false;
+ }
+ uint8_t sub_bands = a2dp_offload.codec_info[0] & A2DP_SBC_IE_SUBBAND_MSK;
+ switch (sub_bands) {
+ case A2DP_SBC_IE_SUBBAND_4:
+ sbc_config.numSubbands = SbcNumSubbands::SUBBAND_4;
+ break;
+ case A2DP_SBC_IE_SUBBAND_8:
+ sbc_config.numSubbands = SbcNumSubbands::SUBBAND_8;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown SBC Subbands=" << sub_bands;
+ return false;
+ }
+ uint8_t alloc_method = a2dp_offload.codec_info[0] & A2DP_SBC_IE_ALLOC_MD_MSK;
+ switch (alloc_method) {
+ case A2DP_SBC_IE_ALLOC_MD_S:
+ sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_S;
+ break;
+ case A2DP_SBC_IE_ALLOC_MD_L:
+ sbc_config.allocMethod = SbcAllocMethod::ALLOC_MD_L;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown SBC alloc_method=" << alloc_method;
+ return false;
+ }
+ sbc_config.minBitpool = a2dp_offload.codec_info[1];
+ sbc_config.maxBitpool = a2dp_offload.codec_info[2];
+ sbc_config.bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
+ if (sbc_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown SBC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.sbcConfig(sbc_config);
+ return true;
+}
+
+bool A2dpAacToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config) {
+ btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig();
+ if (current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SOURCE_AAC &&
+ current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SINK_AAC) {
+ *codec_config = {};
+ return false;
+ }
+ tBT_A2DP_OFFLOAD a2dp_offload;
+ a2dp_config->getCodecSpecificConfig(&a2dp_offload);
+ codec_config->codecType = CodecType::AAC;
+ codec_config->config.aacConfig({});
+ auto aac_config = codec_config->config.aacConfig();
+ uint8_t object_type = a2dp_offload.codec_info[0];
+ switch (object_type) {
+ case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+ aac_config.objectType = AacObjectType::MPEG2_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+ aac_config.objectType = AacObjectType::MPEG4_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+ aac_config.objectType = AacObjectType::MPEG4_LTP;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+ aac_config.objectType = AacObjectType::MPEG4_SCALABLE;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown AAC object_type=" << +object_type;
+ return false;
+ }
+ aac_config.sampleRate = A2dpCodecToHalSampleRate(current_codec);
+ if (aac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown AAC sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ aac_config.channelMode = A2dpCodecToHalChannelMode(current_codec);
+ if (aac_config.channelMode == ChannelMode::UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown AAC channel_mode=" << current_codec.channel_mode;
+ return false;
+ }
+ uint8_t vbr_enabled =
+ a2dp_offload.codec_info[1] & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
+ switch (vbr_enabled) {
+ case A2DP_AAC_VARIABLE_BIT_RATE_ENABLED:
+ aac_config.variableBitRateEnabled = AacVariableBitRate::ENABLED;
+ break;
+ case A2DP_AAC_VARIABLE_BIT_RATE_DISABLED:
+ aac_config.variableBitRateEnabled = AacVariableBitRate::DISABLED;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown AAC VBR=" << +vbr_enabled;
+ return false;
+ }
+ aac_config.bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
+ if (aac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown AAC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.aacConfig(aac_config);
+ return true;
+}
+
+bool A2dpAptxToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config) {
+ btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig();
+ if (current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SOURCE_APTX &&
+ current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD) {
+ *codec_config = {};
+ return false;
+ }
+ tBT_A2DP_OFFLOAD a2dp_offload;
+ a2dp_config->getCodecSpecificConfig(&a2dp_offload);
+ if (current_codec.codec_type == BTAV_A2DP_CODEC_INDEX_SOURCE_APTX) {
+ codec_config->codecType = CodecType::APTX;
+ } else {
+ codec_config->codecType = CodecType::APTX_HD;
+ }
+ codec_config->config.aptxConfig({});
+ auto aptx_config = codec_config->config.aptxConfig();
+ aptx_config.sampleRate = A2dpCodecToHalSampleRate(current_codec);
+ if (aptx_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown aptX sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ aptx_config.channelMode = A2dpCodecToHalChannelMode(current_codec);
+ if (aptx_config.channelMode == ChannelMode::UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown aptX channel_mode=" << current_codec.channel_mode;
+ return false;
+ }
+ aptx_config.bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
+ if (aptx_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown aptX bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.aptxConfig(aptx_config);
+ return true;
+}
+
+bool A2dpLdacToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config) {
+ btav_a2dp_codec_config_t current_codec = a2dp_config->getCodecConfig();
+ if (current_codec.codec_type != BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC) {
+ codec_config = {};
+ return false;
+ }
+ tBT_A2DP_OFFLOAD a2dp_offload;
+ a2dp_config->getCodecSpecificConfig(&a2dp_offload);
+ codec_config->codecType = CodecType::LDAC;
+ codec_config->config.ldacConfig({});
+ auto ldac_config = codec_config->config.ldacConfig();
+ ldac_config.sampleRate = A2dpCodecToHalSampleRate(current_codec);
+ if (ldac_config.sampleRate == SampleRate::RATE_UNKNOWN) {
+ LOG(ERROR) << __func__
+ << ": Unknown LDAC sample_rate=" << current_codec.sample_rate;
+ return false;
+ }
+ switch (a2dp_offload.codec_info[7]) {
+ case A2DP_LDAC_CHANNEL_MODE_STEREO:
+ ldac_config.channelMode = LdacChannelMode::STEREO;
+ break;
+ case A2DP_LDAC_CHANNEL_MODE_DUAL:
+ ldac_config.channelMode = LdacChannelMode::DUAL;
+ break;
+ case A2DP_LDAC_CHANNEL_MODE_MONO:
+ ldac_config.channelMode = LdacChannelMode::MONO;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown LDAC channel_mode="
+ << a2dp_offload.codec_info[7];
+ ldac_config.channelMode = LdacChannelMode::UNKNOWN;
+ return false;
+ }
+ switch (a2dp_offload.codec_info[6]) {
+ case A2DP_LDAC_QUALITY_HIGH:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_HIGH;
+ break;
+ case A2DP_LDAC_QUALITY_MID:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_MID;
+ break;
+ case A2DP_LDAC_QUALITY_LOW:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_LOW;
+ break;
+ case A2DP_LDAC_QUALITY_ABR_OFFLOAD:
+ ldac_config.qualityIndex = LdacQualityIndex::QUALITY_ABR;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ": Unknown LDAC QualityIndex="
+ << a2dp_offload.codec_info[6];
+ return false;
+ }
+ ldac_config.bitsPerSample = A2dpCodecToHalBitsPerSample(current_codec);
+ if (ldac_config.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": Unknown LDAC bits_per_sample="
+ << current_codec.bits_per_sample;
+ return false;
+ }
+ codec_config->config.ldacConfig(ldac_config);
+ return true;
+}
+
+bool UpdateOffloadingCapabilities(
+ const std::vector<btav_a2dp_codec_config_t>& framework_preference) {
+ audio_hal_capabilities = BluetoothAudioClientInterface::GetAudioCapabilities(
+ SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ uint32_t codec_type_masks = static_cast<uint32_t>(CodecType::UNKNOWN);
+ for (auto preference : framework_preference) {
+ switch (preference.codec_type) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ codec_type_masks |= CodecType::SBC;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ codec_type_masks |= CodecType::AAC;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ codec_type_masks |= CodecType::APTX;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ codec_type_masks |= CodecType::APTX_HD;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ codec_type_masks |= CodecType::LDAC;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ [[fallthrough]];
+ case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
+ [[fallthrough]];
+ case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
+ LOG(WARNING) << __func__
+ << ": Ignore sink codec_type=" << preference.codec_type;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ [[fallthrough]];
+ default:
+ LOG(ERROR) << __func__
+ << ": Unknown codec_type=" << preference.codec_type;
+ return false;
+ }
+ }
+ offloading_preference.clear();
+ for (auto capability : audio_hal_capabilities) {
+ if (static_cast<CodecType>(capability.codecCapabilities().codecType &
+ codec_type_masks) != CodecType::UNKNOWN) {
+ LOG(INFO) << __func__
+ << ": enabled offloading capability=" << toString(capability);
+ offloading_preference.push_back(capability);
+ } else {
+ LOG(INFO) << __func__
+ << ": disabled offloading capability=" << toString(capability);
+ }
+ }
+ // TODO: Bluetooth SoC and runtime property
+ return true;
+}
+
+// Check whether this codec is supported by the audio HAL and is allowed to use
+// by prefernece of framework / Bluetooth SoC / runtime property.
+bool IsCodecOffloadingEnabled(const CodecConfiguration& codec_config) {
+ for (auto preference : offloading_preference) {
+ if (codec_config.codecType != preference.codecCapabilities().codecType)
+ continue;
+ auto codec_capability = preference.codecCapabilities();
+ switch (codec_capability.codecType) {
+ case CodecType::SBC: {
+ auto sbc_capability = codec_capability.capabilities.sbcCapabilities();
+ auto sbc_config = codec_config.config.sbcConfig();
+ return sbc_offloading_capability_match(sbc_capability, sbc_config);
+ }
+ case CodecType::AAC: {
+ auto aac_capability = codec_capability.capabilities.aacCapabilities();
+ auto aac_config = codec_config.config.aacConfig();
+ return aac_offloading_capability_match(aac_capability, aac_config);
+ }
+ case CodecType::APTX:
+ [[fallthrough]];
+ case CodecType::APTX_HD: {
+ auto aptx_capability = codec_capability.capabilities.aptxCapabilities();
+ auto aptx_config = codec_config.config.aptxConfig();
+ return aptx_offloading_capability_match(aptx_capability, aptx_config);
+ }
+ case CodecType::LDAC: {
+ auto ldac_capability = codec_capability.capabilities.ldacCapabilities();
+ auto ldac_config = codec_config.config.ldacConfig();
+ return ldac_offloading_capability_match(ldac_capability, ldac_config);
+ }
+ case CodecType::UNKNOWN:
+ [[fallthrough]];
+ default:
+ LOG(ERROR) << __func__ << ": Unknown codecType="
+ << toString(codec_capability.codecType);
+ return false;
+ }
+ }
+ LOG(INFO) << __func__ << ": software codec=" << toString(codec_config);
+ return false;
+}
+
+} // namespace codec
+} // namespace audio
+} // namespace bluetooth
diff --git a/audio_hal_interface/codec_status.h b/audio_hal_interface/codec_status.h
new file mode 100644
index 000000000..e0e074438
--- /dev/null
+++ b/audio_hal_interface/codec_status.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 <vector>
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+
+#include "a2dp_codec_api.h"
+
+namespace bluetooth {
+namespace audio {
+namespace codec {
+
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
+
+extern const CodecConfiguration kInvalidCodecConfiguration;
+
+SampleRate A2dpCodecToHalSampleRate(
+ const btav_a2dp_codec_config_t& a2dp_codec_config);
+BitsPerSample A2dpCodecToHalBitsPerSample(
+ const btav_a2dp_codec_config_t& a2dp_codec_config);
+ChannelMode A2dpCodecToHalChannelMode(
+ const btav_a2dp_codec_config_t& a2dp_codec_config);
+
+bool A2dpSbcToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config);
+bool A2dpAacToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config);
+bool A2dpAptxToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config);
+bool A2dpLdacToHalConfig(CodecConfiguration* codec_config,
+ A2dpCodecConfig* a2dp_config);
+
+bool UpdateOffloadingCapabilities(
+ const std::vector<btav_a2dp_codec_config_t>& framework_preference);
+// Check whether this codec is supported by the audio HAL and is allowed to use
+// by prefernece of framework / Bluetooth SoC / runtime property.
+bool IsCodecOffloadingEnabled(const CodecConfiguration& codec_config);
+
+} // namespace codec
+} // namespace audio
+} // namespace bluetooth
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index b91bc42c9..dbf85945f 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -953,6 +953,13 @@ bt_status_t BtifAvSource::Init(
BTIF_TRACE_DEBUG("a2dp_offload.enable = %d", a2dp_offload_enabled_);
callbacks_ = callbacks;
+ if (a2dp_offload_enabled_) {
+ // TODO: offloading_preference is for framework preference and should be
+ // input from upper-layer
+ std::vector<btav_a2dp_codec_config_t> offloading_preference(0);
+ bluetooth::audio::a2dp::update_codec_offloading_capabilities(
+ offloading_preference);
+ }
bta_av_co_init(codec_priorities);
if (!btif_a2dp_source_init()) {