diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2019-12-18 17:27:58 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-12-18 17:27:58 +0000 |
commit | 250f2a29e1082850813c5ede00bdfe782ddd4e41 (patch) | |
tree | 90ec5825db7fbc1e28590f16858668ec37815f91 | |
parent | d9d2be500c775e0e6fdac0b5108d043d8b43ab0b (diff) | |
parent | 74f321c51e2115d0d95d206a2668eccd28224f56 (diff) | |
download | bt-250f2a29e1082850813c5ede00bdfe782ddd4e41.tar.gz |
Merge "A2DP: HAL codec offloading capabilities check preparation"
-rw-r--r-- | audio_hal_interface/Android.bp | 2 | ||||
-rw-r--r-- | audio_hal_interface/a2dp_encoding.cc | 324 | ||||
-rw-r--r-- | audio_hal_interface/a2dp_encoding.h | 5 | ||||
-rw-r--r-- | audio_hal_interface/client_interface.cc | 84 | ||||
-rw-r--r-- | audio_hal_interface/client_interface.h | 9 | ||||
-rw-r--r-- | audio_hal_interface/client_interface_unittest.cc | 474 | ||||
-rw-r--r-- | audio_hal_interface/codec_status.cc | 569 | ||||
-rw-r--r-- | audio_hal_interface/codec_status.h | 60 | ||||
-rw-r--r-- | btif/src/btif_av.cc | 7 |
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()) { |