/* * 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. */ #define LOG_TAG "bluetooth" #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 audio_hal_capabilities(0); // capabilities that audio HAL supports and frameworks / Bluetooth SoC / runtime // preference would like to use. std::vector offloading_preference(0); bool sbc_offloading_capability_match(const SbcParameters& sbc_capability, const SbcParameters& sbc_config) { if ((static_cast(sbc_capability.sampleRate & sbc_config.sampleRate) == SampleRate::RATE_UNKNOWN) || (static_cast(sbc_capability.channelMode & sbc_config.channelMode) == SbcChannelMode::UNKNOWN) || (static_cast(sbc_capability.blockLength & sbc_config.blockLength) == static_cast(0)) || (static_cast(sbc_capability.numSubbands & sbc_config.numSubbands) == static_cast(0)) || (static_cast(sbc_capability.allocMethod & sbc_config.allocMethod) == static_cast(0)) || (static_cast(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(aac_capability.objectType & aac_config.objectType) == static_cast(0)) || (static_cast(aac_capability.sampleRate & aac_config.sampleRate) == SampleRate::RATE_UNKNOWN) || (static_cast(aac_capability.channelMode & aac_config.channelMode) == ChannelMode::UNKNOWN) || (aac_capability.variableBitRateEnabled != AacVariableBitRate::ENABLED && aac_config.variableBitRateEnabled != AacVariableBitRate::DISABLED) || (static_cast(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(aptx_capability.sampleRate & aptx_config.sampleRate) == SampleRate::RATE_UNKNOWN) || (static_cast(aptx_capability.channelMode & aptx_config.channelMode) == ChannelMode::UNKNOWN) || (static_cast(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(ldac_capability.sampleRate & ldac_config.sampleRate) == SampleRate::RATE_UNKNOWN) || (static_cast(ldac_capability.channelMode & ldac_config.channelMode) == LdacChannelMode::UNKNOWN) || (static_cast(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& framework_preference) { audio_hal_capabilities = BluetoothAudioClientInterface::GetAudioCapabilities( SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH); uint32_t codec_type_masks = static_cast(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(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