| /* |
| * 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 <aidl/android/hardware/bluetooth/audio/AacCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/AacObjectType.h> |
| #include <aidl/android/hardware/bluetooth/audio/AptxAdaptiveLeCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/AptxAdaptiveLeConfiguration.h> |
| #include <aidl/android/hardware/bluetooth/audio/AptxCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/ChannelMode.h> |
| #include <aidl/android/hardware/bluetooth/audio/LdacCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h> |
| #include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h> |
| #include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h> |
| #include <aidl/android/hardware/bluetooth/audio/OpusCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/OpusConfiguration.h> |
| #include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h> |
| #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h> |
| #include <android-base/logging.h> |
| |
| #include "BluetoothLeAudioCodecsProvider.h" |
| |
| 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<CodecCapabilities> 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<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities; |
| |
| static const UnicastCapability kInvalidUnicastCapability = { |
| .codecType = CodecType::UNKNOWN}; |
| |
| static const AptxAdaptiveLeCapabilities |
| kDefaultOffloadAptxAdaptiveLeCapability_48k = { |
| .samplingFrequencyHz = {48000}, |
| .frameDurationUs = {10000}, |
| .octetsPerFrame = {816}}; |
| |
| static const AptxAdaptiveLeCapabilities |
| kDefaultOffloadAptxAdaptiveLeCapability_96k = { |
| .samplingFrequencyHz = {96000}, |
| .frameDurationUs = {10000}, |
| .octetsPerFrame = {816}}; |
| |
| static const AptxAdaptiveLeCapabilities |
| kDefaultOffloadAptxAdaptiveLeXCapability_48k = { |
| .samplingFrequencyHz = {48000}, |
| .frameDurationUs = {10000}, |
| .octetsPerFrame = {816}}; |
| |
| static const AptxAdaptiveLeCapabilities |
| kDefaultOffloadAptxAdaptiveLeXCapability_96k = { |
| .samplingFrequencyHz = {96000}, |
| .frameDurationUs = {10000}, |
| .octetsPerFrame = {816}}; |
| |
| static const BroadcastCapability kInvalidBroadcastCapability = { |
| .codecType = CodecType::UNKNOWN}; |
| |
| static AudioLocation stereoAudio = static_cast<AudioLocation>( |
| static_cast<uint8_t>(AudioLocation::FRONT_LEFT) | |
| static_cast<uint8_t>(AudioLocation::FRONT_RIGHT)); |
| |
| static const std::vector<AptxAdaptiveLeCapabilities> |
| supportedAptxAdaptiveLeCapabilityList = { |
| kDefaultOffloadAptxAdaptiveLeCapability_48k, |
| kDefaultOffloadAptxAdaptiveLeCapability_96k, |
| kDefaultOffloadAptxAdaptiveLeXCapability_48k, |
| kDefaultOffloadAptxAdaptiveLeXCapability_96k}; |
| |
| // Stores the supported setting of audio location, connected device, and the |
| // channel count for each device |
| std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>> |
| supportedDeviceSetting = { |
| // Stereo, one connected device for both L and R |
| std::make_tuple(stereoAudio, 1, 2), |
| }; |
| |
| template <class T> |
| bool BluetoothAudioCodecs::ContainedInVector( |
| const std::vector<T>& vector, const typename identity<T>::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<CodecConfiguration::CodecSpecific::sbcConfig>(); |
| |
| 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<CodecConfiguration::CodecSpecific::aacConfig>(); |
| |
| 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<CodecConfiguration::CodecSpecific::ldacConfig>(); |
| |
| 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<CodecConfiguration::CodecSpecific::aptxConfig>(); |
| |
| 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<CodecConfiguration::CodecSpecific::aptxConfig>(); |
| |
| 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<OpusConfiguration> opus_data = |
| codec_specific.get<CodecConfiguration::CodecSpecific::opusConfig>(); |
| |
| 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; |
| } |
| |
| std::vector<PcmCapabilities> |
| BluetoothAudioCodecs::GetSoftwarePcmCapabilities() { |
| return {kDefaultSoftwarePcmCapabilities}; |
| } |
| |
| std::vector<CodecCapabilities> |
| 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<CodecCapabilities> offload_a2dp_codec_capabilities = |
| kDefaultOffloadA2dpCodecCapabilities; |
| for (auto& codec_capability : offload_a2dp_codec_capabilities) { |
| switch (codec_capability.codecType) { |
| case CodecType::SBC: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::sbcCapabilities>( |
| kDefaultOffloadSbcCapability); |
| break; |
| case CodecType::AAC: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::aacCapabilities>( |
| kDefaultOffloadAacCapability); |
| break; |
| case CodecType::LDAC: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::ldacCapabilities>( |
| kDefaultOffloadLdacCapability); |
| break; |
| case CodecType::APTX: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::aptxCapabilities>( |
| kDefaultOffloadAptxCapability); |
| break; |
| case CodecType::APTX_HD: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::aptxCapabilities>( |
| kDefaultOffloadAptxHdCapability); |
| break; |
| case CodecType::OPUS: |
| codec_capability.capabilities |
| .set<CodecCapabilities::Capabilities::opusCapabilities>( |
| kDefaultOffloadOpusCapability); |
| break; |
| case CodecType::UNKNOWN: |
| case CodecType::VENDOR: |
| case CodecType::LC3: |
| case CodecType::APTX_ADAPTIVE: |
| case CodecType::APTX_ADAPTIVE_LE: |
| case CodecType::APTX_ADAPTIVE_LEX: |
| 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::APTX_ADAPTIVE_LE: |
| case CodecType::APTX_ADAPTIVE_LEX: |
| case CodecType::LC3: |
| case CodecType::UNKNOWN: |
| case CodecType::VENDOR: |
| break; |
| } |
| return false; |
| } |
| |
| std::vector<LeAudioCodecCapabilitiesSetting> |
| 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<LeAudioCodecCapabilitiesSetting>(0); |
| } |
| |
| if (kDefaultOffloadLeAudioCapabilities.empty()) { |
| auto le_audio_offload_setting = |
| BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile(); |
| kDefaultOffloadLeAudioCapabilities = |
| BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities( |
| le_audio_offload_setting); |
| |
| for (auto [audioLocation, deviceCnt, channelCount] : |
| supportedDeviceSetting) { |
| for (auto capability : supportedAptxAdaptiveLeCapabilityList) { |
| for (auto codec_type : |
| {CodecType::APTX_ADAPTIVE_LE, CodecType::APTX_ADAPTIVE_LEX}) { |
| if (session_type == |
| SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) { |
| UnicastCapability aptx_adaptive_le_cap = { |
| .codecType = codec_type, |
| .supportedChannel = audioLocation, |
| .deviceCount = deviceCnt, |
| .channelCountPerDevice = channelCount, |
| .leAudioCodecCapabilities = |
| UnicastCapability::LeAudioCodecCapabilities(capability), |
| }; |
| |
| // Adds the capability for encode only |
| kDefaultOffloadLeAudioCapabilities.push_back( |
| {.unicastEncodeCapability = aptx_adaptive_le_cap, |
| .unicastDecodeCapability = kInvalidUnicastCapability, |
| .broadcastCapability = kInvalidBroadcastCapability}); |
| } |
| } |
| } |
| } |
| } |
| return kDefaultOffloadLeAudioCapabilities; |
| } |
| |
| } // namespace audio |
| } // namespace bluetooth |
| } // namespace hardware |
| } // namespace android |
| } // namespace aidl |