/* * Copyright 2018 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 "BTAudioProviderSessionCodecsDB" #include "BluetoothAudioSupportedCodecsDB.h" #include namespace android { namespace bluetooth { namespace audio { 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::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; // Default Supported PCM Parameters static const PcmParameters kDefaultSoftwarePcmCapabilities = { .sampleRate = static_cast( SampleRate::RATE_44100 | SampleRate::RATE_48000 | SampleRate::RATE_88200 | SampleRate::RATE_96000 | SampleRate::RATE_16000 | SampleRate::RATE_24000), .channelMode = static_cast(ChannelMode::MONO | ChannelMode::STEREO), .bitsPerSample = static_cast(BitsPerSample::BITS_16 | BitsPerSample::BITS_24 | BitsPerSample::BITS_32)}; // Default Supported Codecs // SBC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(MONO|STEREO) // all blocks | subbands 8 | Loudness static const SbcParameters kDefaultOffloadSbcCapability = { .sampleRate = SampleRate::RATE_44100, .channelMode = static_cast(SbcChannelMode::MONO | SbcChannelMode::JOINT_STEREO), .blockLength = static_cast( SbcBlockLength::BLOCKS_4 | SbcBlockLength::BLOCKS_8 | SbcBlockLength::BLOCKS_12 | SbcBlockLength::BLOCKS_16), .numSubbands = SbcNumSubbands::SUBBAND_8, .allocMethod = SbcAllocMethod::ALLOC_MD_L, .bitsPerSample = BitsPerSample::BITS_16, .minBitpool = 2, .maxBitpool = 53}; // AAC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(STEREO) static const AacParameters kDefaultOffloadAacCapability = { .objectType = AacObjectType::MPEG2_LC, .sampleRate = SampleRate::RATE_44100, .channelMode = ChannelMode::STEREO, .variableBitRateEnabled = AacVariableBitRate::DISABLED, .bitsPerSample = BitsPerSample::BITS_16}; // LDAC: mSampleRate:(44100|48000|88200|96000), mBitsPerSample:(16|24|32), // mChannelMode:(DUAL|STEREO) static const LdacParameters kDefaultOffloadLdacCapability = { .sampleRate = static_cast( SampleRate::RATE_44100 | SampleRate::RATE_48000 | SampleRate::RATE_88200 | SampleRate::RATE_96000), .channelMode = static_cast(LdacChannelMode::DUAL | LdacChannelMode::STEREO), .qualityIndex = LdacQualityIndex::QUALITY_HIGH, .bitsPerSample = static_cast(BitsPerSample::BITS_16 | BitsPerSample::BITS_24 | BitsPerSample::BITS_32)}; // aptX: mSampleRate:(44100|48000), mBitsPerSample:(16), mChannelMode:(STEREO) static const AptxParameters kDefaultOffloadAptxCapability = { .sampleRate = static_cast(SampleRate::RATE_44100 | SampleRate::RATE_48000), .bitsPerSample = BitsPerSample::BITS_16, .channelMode = ChannelMode::STEREO}; // aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24), // mChannelMode:(STEREO) static const AptxParameters kDefaultOffloadAptxHdCapability = { .sampleRate = static_cast(SampleRate::RATE_44100 | SampleRate::RATE_48000), .bitsPerSample = BitsPerSample::BITS_24, .channelMode = ChannelMode::STEREO}; const std::vector kDefaultOffloadA2dpCodecCapabilities = { {.codecType = CodecType::SBC, .capabilities = {}}, {.codecType = CodecType::AAC, .capabilities = {}}, {.codecType = CodecType::LDAC, .capabilities = {}}, {.codecType = CodecType::APTX, .capabilities = {}}, {.codecType = CodecType::APTX_HD, .capabilities = {}}}; static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield) { bool single = false; uint32_t test_bit = 0x00000001; while (test_bit <= bitmasks && test_bit <= bitfield) { if (bitfield & test_bit && bitmasks & test_bit) { if (single) return false; single = true; } if (test_bit == 0x80000000) break; test_bit <<= 1; } return single; } static bool IsOffloadSbcConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific); static bool IsOffloadAacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific); static bool IsOffloadLdacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific); static bool IsOffloadAptxConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific); static bool IsOffloadAptxHdConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific); static bool IsOffloadSbcConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getDiscriminator() != CodecConfiguration::CodecSpecific::hidl_discriminator::sbcConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } const SbcParameters sbc_data = codec_specific.sbcConfig(); if (!IsSingleBit(static_cast(sbc_data.sampleRate), 0xff) || !IsSingleBit(static_cast(sbc_data.channelMode), 0x0f) || !IsSingleBit(static_cast(sbc_data.blockLength), 0xf0) || !IsSingleBit(static_cast(sbc_data.numSubbands), 0x0c) || !IsSingleBit(static_cast(sbc_data.allocMethod), 0x03) || !IsSingleBit(static_cast(sbc_data.bitsPerSample), 0x07) || sbc_data.minBitpool > sbc_data.maxBitpool) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } else if ((sbc_data.sampleRate & kDefaultOffloadSbcCapability.sampleRate) && (sbc_data.channelMode & kDefaultOffloadSbcCapability.channelMode) && (sbc_data.blockLength & kDefaultOffloadSbcCapability.blockLength) && (sbc_data.numSubbands & kDefaultOffloadSbcCapability.numSubbands) && (sbc_data.allocMethod & kDefaultOffloadSbcCapability.allocMethod) && (sbc_data.bitsPerSample & kDefaultOffloadSbcCapability.bitsPerSample) && (kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool && sbc_data.maxBitpool <= kDefaultOffloadSbcCapability.maxBitpool)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << toString(codec_specific); return false; } static bool IsOffloadAacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getDiscriminator() != CodecConfiguration::CodecSpecific::hidl_discriminator::aacConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } const AacParameters aac_data = codec_specific.aacConfig(); if (!IsSingleBit(static_cast(aac_data.objectType), 0xf0) || !IsSingleBit(static_cast(aac_data.sampleRate), 0xff) || !IsSingleBit(static_cast(aac_data.channelMode), 0x03) || !IsSingleBit(static_cast(aac_data.bitsPerSample), 0x07)) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } else if ((aac_data.objectType & kDefaultOffloadAacCapability.objectType) && (aac_data.sampleRate & kDefaultOffloadAacCapability.sampleRate) && (aac_data.channelMode & kDefaultOffloadAacCapability.channelMode) && (aac_data.variableBitRateEnabled == AacVariableBitRate::DISABLED || kDefaultOffloadAacCapability.variableBitRateEnabled == AacVariableBitRate::ENABLED) && (aac_data.bitsPerSample & kDefaultOffloadAacCapability.bitsPerSample)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << toString(codec_specific); return false; } static bool IsOffloadLdacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getDiscriminator() != CodecConfiguration::CodecSpecific::hidl_discriminator::ldacConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } const LdacParameters ldac_data = codec_specific.ldacConfig(); if (!IsSingleBit(static_cast(ldac_data.sampleRate), 0xff) || !IsSingleBit(static_cast(ldac_data.channelMode), 0x07) || (ldac_data.qualityIndex > LdacQualityIndex::QUALITY_LOW && ldac_data.qualityIndex != LdacQualityIndex::QUALITY_ABR) || !IsSingleBit(static_cast(ldac_data.bitsPerSample), 0x07)) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } else if ((ldac_data.sampleRate & kDefaultOffloadLdacCapability.sampleRate) && (ldac_data.channelMode & kDefaultOffloadLdacCapability.channelMode) && (ldac_data.bitsPerSample & kDefaultOffloadLdacCapability.bitsPerSample)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << toString(codec_specific); return false; } static bool IsOffloadAptxConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getDiscriminator() != CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } const AptxParameters aptx_data = codec_specific.aptxConfig(); if (!IsSingleBit(static_cast(aptx_data.sampleRate), 0xff) || !IsSingleBit(static_cast(aptx_data.channelMode), 0x03) || !IsSingleBit(static_cast(aptx_data.bitsPerSample), 0x07)) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } else if ((aptx_data.sampleRate & kDefaultOffloadAptxCapability.sampleRate) && (aptx_data.channelMode & kDefaultOffloadAptxCapability.channelMode) && (aptx_data.bitsPerSample & kDefaultOffloadAptxCapability.bitsPerSample)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << toString(codec_specific); return false; } static bool IsOffloadAptxHdConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getDiscriminator() != CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } const AptxParameters aptx_data = codec_specific.aptxConfig(); if (!IsSingleBit(static_cast(aptx_data.sampleRate), 0xff) || !IsSingleBit(static_cast(aptx_data.channelMode), 0x03) || !IsSingleBit(static_cast(aptx_data.bitsPerSample), 0x07)) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << toString(codec_specific); return false; } else if ((aptx_data.sampleRate & kDefaultOffloadAptxHdCapability.sampleRate) && (aptx_data.channelMode & kDefaultOffloadAptxHdCapability.channelMode) && (aptx_data.bitsPerSample & kDefaultOffloadAptxHdCapability.bitsPerSample)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << toString(codec_specific); return false; } std::vector GetSoftwarePcmCapabilities() { return std::vector(1, kDefaultSoftwarePcmCapabilities); } std::vector GetOffloadCodecCapabilities( const SessionType& session_type) { if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { return std::vector(0); } std::vector offload_a2dp_codec_capabilities = kDefaultOffloadA2dpCodecCapabilities; for (auto& codec_capability : offload_a2dp_codec_capabilities) { switch (codec_capability.codecType) { case CodecType::SBC: codec_capability.capabilities.sbcCapabilities( kDefaultOffloadSbcCapability); break; case CodecType::AAC: codec_capability.capabilities.aacCapabilities( kDefaultOffloadAacCapability); break; case CodecType::LDAC: codec_capability.capabilities.ldacCapabilities( kDefaultOffloadLdacCapability); break; case CodecType::APTX: codec_capability.capabilities.aptxCapabilities( kDefaultOffloadAptxCapability); break; case CodecType::APTX_HD: codec_capability.capabilities.aptxCapabilities( kDefaultOffloadAptxHdCapability); break; case CodecType::UNKNOWN: codec_capability = {}; break; } } return offload_a2dp_codec_capabilities; } bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config) { if ((pcm_config.sampleRate != SampleRate::RATE_44100 && pcm_config.sampleRate != SampleRate::RATE_48000 && pcm_config.sampleRate != SampleRate::RATE_88200 && pcm_config.sampleRate != SampleRate::RATE_96000 && pcm_config.sampleRate != SampleRate::RATE_16000 && pcm_config.sampleRate != SampleRate::RATE_24000) || (pcm_config.bitsPerSample != BitsPerSample::BITS_16 && pcm_config.bitsPerSample != BitsPerSample::BITS_24 && pcm_config.bitsPerSample != BitsPerSample::BITS_32) || (pcm_config.channelMode != ChannelMode::MONO && pcm_config.channelMode != ChannelMode::STEREO)) { LOG(WARNING) << __func__ << ": Invalid PCM Configuration=" << toString(pcm_config); return false; } else if (pcm_config.sampleRate & kDefaultSoftwarePcmCapabilities.sampleRate && pcm_config.bitsPerSample & kDefaultSoftwarePcmCapabilities.bitsPerSample && pcm_config.channelMode & kDefaultSoftwarePcmCapabilities.channelMode) { return true; } LOG(WARNING) << __func__ << ": Unsupported PCM Configuration=" << toString(pcm_config); return false; } bool IsOffloadCodecConfigurationValid(const SessionType& session_type, const CodecConfiguration& codec_config) { if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) { LOG(ERROR) << __func__ << ": Invalid SessionType=" << toString(session_type); return false; } else if (codec_config.encodedAudioBitrate < 0x00000001 || 0x00ffffff < codec_config.encodedAudioBitrate) { LOG(ERROR) << __func__ << ": Unsupported Codec Configuration=" << toString(codec_config); return false; } const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config; switch (codec_config.codecType) { case CodecType::SBC: if (IsOffloadSbcConfigurationValid(codec_specific)) { return true; } return false; case CodecType::AAC: if (IsOffloadAacConfigurationValid(codec_specific)) { return true; } return false; case CodecType::LDAC: if (IsOffloadLdacConfigurationValid(codec_specific)) { return true; } return false; case CodecType::APTX: if (IsOffloadAptxConfigurationValid(codec_specific)) { return true; } return false; case CodecType::APTX_HD: if (IsOffloadAptxHdConfigurationValid(codec_specific)) { return true; } return false; case CodecType::UNKNOWN: return false; } return false; } } // namespace audio } // namespace bluetooth } // namespace android