/* * Copyright (C) 2022 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 "BTAudioCodecsAidl" #include "BluetoothAudioCodecs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace aidl { namespace android { namespace hardware { namespace bluetooth { namespace audio { static const PcmCapabilities kDefaultSoftwarePcmCapabilities = { .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000}, .channelMode = {ChannelMode::MONO, ChannelMode::STEREO}, .bitsPerSample = {16, 24, 32}, .dataIntervalUs = {}, }; static const SbcCapabilities kDefaultOffloadSbcCapability = { .sampleRateHz = {44100}, .channelMode = {SbcChannelMode::MONO, SbcChannelMode::JOINT_STEREO}, .blockLength = {4, 8, 12, 16}, .numSubbands = {8}, .allocMethod = {SbcAllocMethod::ALLOC_MD_L}, .bitsPerSample = {16}, .minBitpool = 2, .maxBitpool = 53}; static const AacCapabilities kDefaultOffloadAacCapability = { .objectType = {AacObjectType::MPEG2_LC}, .sampleRateHz = {44100}, .channelMode = {ChannelMode::STEREO}, .variableBitRateSupported = true, .bitsPerSample = {16}}; static const LdacCapabilities kDefaultOffloadLdacCapability = { .sampleRateHz = {44100, 48000, 88200, 96000}, .channelMode = {LdacChannelMode::DUAL, LdacChannelMode::STEREO}, .qualityIndex = {LdacQualityIndex::HIGH}, .bitsPerSample = {16, 24, 32}}; static const AptxCapabilities kDefaultOffloadAptxCapability = { .sampleRateHz = {44100, 48000}, .channelMode = {ChannelMode::STEREO}, .bitsPerSample = {16}, }; static const AptxCapabilities kDefaultOffloadAptxHdCapability = { .sampleRateHz = {44100, 48000}, .channelMode = {ChannelMode::STEREO}, .bitsPerSample = {24}, }; static const OpusCapabilities kDefaultOffloadOpusCapability = { .samplingFrequencyHz = {48000}, .frameDurationUs = {10000, 20000}, .channelMode = {ChannelMode::MONO, 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 = {}}, {.codecType = CodecType::OPUS, .capabilities = {}}}; std::vector kDefaultOffloadLeAudioCapabilities; static const UnicastCapability kInvalidUnicastCapability = { .codecType = CodecType::UNKNOWN}; static const BroadcastCapability kInvalidBroadcastCapability = { .codecType = CodecType::UNKNOWN}; // Default Supported Codecs // LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30 static const Lc3Capabilities kLc3Capability_16_1 = { .samplingFrequencyHz = {16000}, .frameDurationUs = {7500}, .octetsPerFrame = {30}}; // Default Supported Codecs // LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40 static const Lc3Capabilities kLc3Capability_16_2 = { .samplingFrequencyHz = {16000}, .frameDurationUs = {10000}, .octetsPerFrame = {40}}; // Default Supported Codecs // LC3 24_2: sample rate: 24 kHz, frame duration: 10 ms, octets per frame: 60 static const Lc3Capabilities kLc3Capability_24_2 = { .samplingFrequencyHz = {24000}, .frameDurationUs = {10000}, .octetsPerFrame = {60}}; // Default Supported Codecs // LC3 32_2: sample rate: 32 kHz, frame duration: 10 ms, octets per frame: 80 static const Lc3Capabilities kLc3Capability_32_2 = { .samplingFrequencyHz = {32000}, .frameDurationUs = {10000}, .octetsPerFrame = {80}}; // Default Supported Codecs // LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120 static const Lc3Capabilities kLc3Capability_48_4 = { .samplingFrequencyHz = {48000}, .frameDurationUs = {10000}, .octetsPerFrame = {120}}; static const std::vector supportedLc3CapabilityList = { kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2, kLc3Capability_16_2, kLc3Capability_16_1}; static AudioLocation stereoAudio = static_cast( static_cast(AudioLocation::FRONT_LEFT) | static_cast(AudioLocation::FRONT_RIGHT)); static AudioLocation monoAudio = AudioLocation::UNKNOWN; // Stores the supported setting of audio location, connected device, and the // channel count for each device std::vector> supportedDeviceSetting = { // Stereo, two connected device, one for L one for R std::make_tuple(stereoAudio, 2, 1), // Stereo, one connected device for both L and R std::make_tuple(stereoAudio, 1, 2), // Mono std::make_tuple(monoAudio, 1, 1)}; template bool BluetoothAudioCodecs::ContainedInVector( const std::vector& vector, const typename identity::type& target) { return std::find(vector.begin(), vector.end(), target) != vector.end(); } bool BluetoothAudioCodecs::IsOffloadSbcConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::sbcConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } const SbcConfiguration sbc_data = codec_specific.get(); if (ContainedInVector(kDefaultOffloadSbcCapability.sampleRateHz, sbc_data.sampleRateHz) && ContainedInVector(kDefaultOffloadSbcCapability.blockLength, sbc_data.blockLength) && ContainedInVector(kDefaultOffloadSbcCapability.numSubbands, sbc_data.numSubbands) && ContainedInVector(kDefaultOffloadSbcCapability.bitsPerSample, sbc_data.bitsPerSample) && ContainedInVector(kDefaultOffloadSbcCapability.channelMode, sbc_data.channelMode) && ContainedInVector(kDefaultOffloadSbcCapability.allocMethod, sbc_data.allocMethod) && sbc_data.minBitpool <= sbc_data.maxBitpool && kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool && kDefaultOffloadSbcCapability.maxBitpool >= sbc_data.maxBitpool) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadAacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aacConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } const AacConfiguration aac_data = codec_specific.get(); if (ContainedInVector(kDefaultOffloadAacCapability.sampleRateHz, aac_data.sampleRateHz) && ContainedInVector(kDefaultOffloadAacCapability.bitsPerSample, aac_data.bitsPerSample) && ContainedInVector(kDefaultOffloadAacCapability.channelMode, aac_data.channelMode) && ContainedInVector(kDefaultOffloadAacCapability.objectType, aac_data.objectType) && (!aac_data.variableBitRateEnabled || kDefaultOffloadAacCapability.variableBitRateSupported)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadLdacConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::ldacConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } const LdacConfiguration ldac_data = codec_specific.get(); if (ContainedInVector(kDefaultOffloadLdacCapability.sampleRateHz, ldac_data.sampleRateHz) && ContainedInVector(kDefaultOffloadLdacCapability.bitsPerSample, ldac_data.bitsPerSample) && ContainedInVector(kDefaultOffloadLdacCapability.channelMode, ldac_data.channelMode) && ContainedInVector(kDefaultOffloadLdacCapability.qualityIndex, ldac_data.qualityIndex)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadAptxConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aptxConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } const AptxConfiguration aptx_data = codec_specific.get(); if (ContainedInVector(kDefaultOffloadAptxCapability.sampleRateHz, aptx_data.sampleRateHz) && ContainedInVector(kDefaultOffloadAptxCapability.bitsPerSample, aptx_data.bitsPerSample) && ContainedInVector(kDefaultOffloadAptxCapability.channelMode, aptx_data.channelMode)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadAptxHdConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::aptxConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } const AptxConfiguration aptx_data = codec_specific.get(); if (ContainedInVector(kDefaultOffloadAptxHdCapability.sampleRateHz, aptx_data.sampleRateHz) && ContainedInVector(kDefaultOffloadAptxHdCapability.bitsPerSample, aptx_data.bitsPerSample) && ContainedInVector(kDefaultOffloadAptxHdCapability.channelMode, aptx_data.channelMode)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadOpusConfigurationValid( const CodecConfiguration::CodecSpecific& codec_specific) { if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::opusConfig) { LOG(WARNING) << __func__ << ": Invalid CodecSpecific=" << codec_specific.toString(); return false; } std::optional opus_data = codec_specific.get(); if (opus_data.has_value() && ContainedInVector(kDefaultOffloadOpusCapability.samplingFrequencyHz, opus_data->samplingFrequencyHz) && ContainedInVector(kDefaultOffloadOpusCapability.frameDurationUs, opus_data->frameDurationUs) && ContainedInVector(kDefaultOffloadOpusCapability.channelMode, opus_data->channelMode)) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << codec_specific.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadLeAudioConfigurationValid( const SessionType& session_type, const LeAudioConfiguration&) { if (session_type != SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH && session_type != SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH && session_type != SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { return false; } return true; } std::vector BluetoothAudioCodecs::GetSoftwarePcmCapabilities() { return {kDefaultSoftwarePcmCapabilities}; } std::vector BluetoothAudioCodecs::GetA2dpOffloadCodecCapabilities( const SessionType& session_type) { if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH && session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { return {}; } 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 .set( kDefaultOffloadSbcCapability); break; case CodecType::AAC: codec_capability.capabilities .set( kDefaultOffloadAacCapability); break; case CodecType::LDAC: codec_capability.capabilities .set( kDefaultOffloadLdacCapability); break; case CodecType::APTX: codec_capability.capabilities .set( kDefaultOffloadAptxCapability); break; case CodecType::APTX_HD: codec_capability.capabilities .set( kDefaultOffloadAptxHdCapability); break; case CodecType::OPUS: codec_capability.capabilities .set( kDefaultOffloadOpusCapability); break; case CodecType::UNKNOWN: case CodecType::VENDOR: case CodecType::LC3: case CodecType::APTX_ADAPTIVE: break; } } return offload_a2dp_codec_capabilities; } bool BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid( const PcmConfiguration& pcm_config) { if (ContainedInVector(kDefaultSoftwarePcmCapabilities.sampleRateHz, pcm_config.sampleRateHz) && ContainedInVector(kDefaultSoftwarePcmCapabilities.bitsPerSample, pcm_config.bitsPerSample) && ContainedInVector(kDefaultSoftwarePcmCapabilities.channelMode, pcm_config.channelMode) // data interval is not checked for now // && pcm_config.dataIntervalUs != 0 ) { return true; } LOG(WARNING) << __func__ << ": Unsupported CodecSpecific=" << pcm_config.toString(); return false; } bool BluetoothAudioCodecs::IsOffloadCodecConfigurationValid( const SessionType& session_type, const CodecConfiguration& codec_config) { if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH && session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) { LOG(ERROR) << __func__ << ": Invalid SessionType=" << toString(session_type); return false; } const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config; switch (codec_config.codecType) { case CodecType::SBC: if (IsOffloadSbcConfigurationValid(codec_specific)) { return true; } break; case CodecType::AAC: if (IsOffloadAacConfigurationValid(codec_specific)) { return true; } break; case CodecType::LDAC: if (IsOffloadLdacConfigurationValid(codec_specific)) { return true; } break; case CodecType::APTX: if (IsOffloadAptxConfigurationValid(codec_specific)) { return true; } break; case CodecType::APTX_HD: if (IsOffloadAptxHdConfigurationValid(codec_specific)) { return true; } break; case CodecType::OPUS: if (IsOffloadOpusConfigurationValid(codec_specific)) { return true; } break; case CodecType::APTX_ADAPTIVE: case CodecType::LC3: case CodecType::UNKNOWN: case CodecType::VENDOR: break; } return false; } UnicastCapability composeUnicastLc3Capability( AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount, const Lc3Capabilities& capability) { return { .codecType = CodecType::LC3, .supportedChannel = audioLocation, .deviceCount = deviceCnt, .channelCountPerDevice = channelCount, .leAudioCodecCapabilities = UnicastCapability::LeAudioCodecCapabilities(capability), }; } std::vector BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities( const SessionType& session_type) { if (session_type != SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH && session_type != SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH && session_type != SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { return std::vector(0); } if (kDefaultOffloadLeAudioCapabilities.empty()) { for (auto [audioLocation, deviceCnt, channelCount] : supportedDeviceSetting) { for (auto capability : supportedLc3CapabilityList) { UnicastCapability lc3Capability = composeUnicastLc3Capability( audioLocation, deviceCnt, channelCount, capability); UnicastCapability lc3MonoDecodeCapability = composeUnicastLc3Capability(monoAudio, 1, 1, capability); // Adds the capability for encode only kDefaultOffloadLeAudioCapabilities.push_back( {.unicastEncodeCapability = lc3Capability, .unicastDecodeCapability = kInvalidUnicastCapability, .broadcastCapability = kInvalidBroadcastCapability}); // Adds the capability for decode only kDefaultOffloadLeAudioCapabilities.push_back( {.unicastEncodeCapability = kInvalidUnicastCapability, .unicastDecodeCapability = lc3Capability, .broadcastCapability = kInvalidBroadcastCapability}); // Adds the capability for the case that encode and decode exist at the // same time kDefaultOffloadLeAudioCapabilities.push_back( {.unicastEncodeCapability = lc3Capability, .unicastDecodeCapability = lc3MonoDecodeCapability, .broadcastCapability = kInvalidBroadcastCapability}); } } } return kDefaultOffloadLeAudioCapabilities; } } // namespace audio } // namespace bluetooth } // namespace hardware } // namespace android } // namespace aidl