summaryrefslogtreecommitdiff
path: root/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-11-01 21:37:59 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-11-01 21:37:59 +0000
commit972d05917e37e520229d71881940dcdeb11e2964 (patch)
treeb522551f1ea7f066be8bf8d0222da12ea141b666 /bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
parent2d9a2e57719afa1adf94062355d0792bb9b625ee (diff)
parent74f46595794c48c09a0b83eb1e908c168e6f6848 (diff)
Snap for 9239618 from 74f46595794c48c09a0b83eb1e908c168e6f6848 to tm-platform-release
Change-Id: I55dbd72b75ef88ac16d1ee884868b2ef742aafab
Diffstat (limited to 'bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp')
-rw-r--r--bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
new file mode 100644
index 0000000000..bf492706c8
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -0,0 +1,312 @@
+/*
+ * 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 "BTAudioCodecsProviderAidl"
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const char* kLeAudioCodecCapabilitiesFile =
+ "/vendor/etc/le_audio_codec_capabilities.xml";
+
+static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
+ static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+ static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
+
+static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
+ if (!leAudioCodecCapabilities.empty()) {
+ return leAudioCodecCapabilities;
+ }
+
+ const auto le_audio_offload_setting =
+ setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
+ if (!le_audio_offload_setting.has_value()) {
+ LOG(ERROR) << __func__ << ": Failed to read "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ std::vector<setting::Scenario> supported_scenarios =
+ GetScenarios(le_audio_offload_setting);
+ if (supported_scenarios.empty()) {
+ LOG(ERROR) << __func__ << ": No scenarios in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateConfigurationsToMap(le_audio_offload_setting);
+ if (configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateCodecConfigurationsToMap(le_audio_offload_setting);
+ if (codec_configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No codec configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
+ if (strategy_configuration_map_.empty()) {
+ LOG(ERROR) << __func__ << ": No strategy configurations in "
+ << kLeAudioCodecCapabilitiesFile;
+ return {};
+ }
+
+ leAudioCodecCapabilities =
+ ComposeLeAudioCodecCapabilities(supported_scenarios);
+ return leAudioCodecCapabilities;
+}
+
+std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ std::vector<setting::Scenario> supported_scenarios;
+ if (le_audio_offload_setting->hasScenarioList()) {
+ for (const auto& scenario_list :
+ le_audio_offload_setting->getScenarioList()) {
+ if (!scenario_list.hasScenario()) {
+ continue;
+ }
+ for (const auto& scenario : scenario_list.getScenario()) {
+ if (scenario.hasEncode() && scenario.hasDecode()) {
+ supported_scenarios.push_back(scenario);
+ }
+ }
+ }
+ }
+ return supported_scenarios;
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasConfigurationList()) {
+ for (const auto& configuration_list :
+ le_audio_offload_setting->getConfigurationList()) {
+ if (!configuration_list.hasConfiguration()) {
+ continue;
+ }
+ for (const auto& configuration : configuration_list.getConfiguration()) {
+ if (configuration.hasName() && configuration.hasCodecConfiguration() &&
+ configuration.hasStrategyConfiguration()) {
+ configuration_map_.insert(
+ make_pair(configuration.getName(), configuration));
+ }
+ }
+ }
+ }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasCodecConfigurationList()) {
+ for (const auto& codec_configuration_list :
+ le_audio_offload_setting->getCodecConfigurationList()) {
+ if (!codec_configuration_list.hasCodecConfiguration()) {
+ continue;
+ }
+ for (const auto& codec_configuration :
+ codec_configuration_list.getCodecConfiguration()) {
+ if (IsValidCodecConfiguration(codec_configuration)) {
+ codec_configuration_map_.insert(
+ make_pair(codec_configuration.getName(), codec_configuration));
+ }
+ }
+ }
+ }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (le_audio_offload_setting->hasStrategyConfigurationList()) {
+ for (const auto& strategy_configuration_list :
+ le_audio_offload_setting->getStrategyConfigurationList()) {
+ if (!strategy_configuration_list.hasStrategyConfiguration()) {
+ continue;
+ }
+ for (const auto& strategy_configuration :
+ strategy_configuration_list.getStrategyConfiguration()) {
+ if (IsValidStrategyConfiguration(strategy_configuration)) {
+ strategy_configuration_map_.insert(make_pair(
+ strategy_configuration.getName(), strategy_configuration));
+ }
+ }
+ }
+ }
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
+ const std::vector<setting::Scenario>& supported_scenarios) {
+ std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
+ for (const auto& scenario : supported_scenarios) {
+ UnicastCapability unicast_encode_capability =
+ GetUnicastCapability(scenario.getEncode());
+ UnicastCapability unicast_decode_capability =
+ GetUnicastCapability(scenario.getDecode());
+ // encode and decode cannot be unknown at the same time
+ if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
+ unicast_decode_capability.codecType == CodecType::UNKNOWN) {
+ continue;
+ }
+ BroadcastCapability broadcast_capability = {.codecType =
+ CodecType::UNKNOWN};
+ le_audio_codec_capabilities.push_back(
+ {.unicastEncodeCapability = unicast_encode_capability,
+ .unicastDecodeCapability = unicast_decode_capability,
+ .broadcastCapability = broadcast_capability});
+ }
+ return le_audio_codec_capabilities;
+}
+
+UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
+ const std::string& coding_direction) {
+ if (coding_direction == "invalid") {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto configuration_iter = configuration_map_.find(coding_direction);
+ if (configuration_iter == configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto codec_configuration_iter = codec_configuration_map_.find(
+ configuration_iter->second.getCodecConfiguration());
+ if (codec_configuration_iter == codec_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto strategy_configuration_iter = strategy_configuration_map_.find(
+ configuration_iter->second.getStrategyConfiguration());
+ if (strategy_configuration_iter == strategy_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ CodecType codec_type =
+ GetCodecType(codec_configuration_iter->second.getCodec());
+ if (codec_type == CodecType::LC3) {
+ return ComposeUnicastCapability(
+ codec_type,
+ GetAudioLocation(
+ strategy_configuration_iter->second.getAudioLocation()),
+ strategy_configuration_iter->second.getConnectedDevice(),
+ strategy_configuration_iter->second.getChannelCount(),
+ ComposeLc3Capability(codec_configuration_iter->second));
+ }
+ return {.codecType = CodecType::UNKNOWN};
+}
+
+template <class T>
+UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
+ const CodecType& codec_type, const AudioLocation& audio_location,
+ const uint8_t& device_cnt, const uint8_t& channel_count,
+ const T& capability) {
+ return {
+ .codecType = codec_type,
+ .supportedChannel = audio_location,
+ .deviceCount = device_cnt,
+ .channelCountPerDevice = channel_count,
+ .leAudioCodecCapabilities =
+ UnicastCapability::LeAudioCodecCapabilities(capability),
+ };
+}
+
+Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
+ const setting::CodecConfiguration& codec_configuration) {
+ return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
+ .frameDurationUs = {codec_configuration.getFrameDurationUs()},
+ .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
+}
+
+AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
+ const setting::AudioLocation& audio_location) {
+ switch (audio_location) {
+ case setting::AudioLocation::MONO:
+ return kMonoAudio;
+ case setting::AudioLocation::STEREO:
+ return kStereoAudio;
+ default:
+ return AudioLocation::UNKNOWN;
+ }
+}
+
+CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
+ const setting::CodecType& codec_type) {
+ switch (codec_type) {
+ case setting::CodecType::LC3:
+ return CodecType::LC3;
+ default:
+ return CodecType::UNKNOWN;
+ }
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
+ const setting::CodecConfiguration& codec_configuration) {
+ return codec_configuration.hasName() && codec_configuration.hasCodec() &&
+ codec_configuration.hasSamplingFrequency() &&
+ codec_configuration.hasFrameDurationUs() &&
+ codec_configuration.hasOctetsPerCodecFrame();
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
+ const setting::StrategyConfiguration& strategy_configuration) {
+ if (!strategy_configuration.hasName() ||
+ !strategy_configuration.hasAudioLocation() ||
+ !strategy_configuration.hasConnectedDevice() ||
+ !strategy_configuration.hasChannelCount()) {
+ return false;
+ }
+ if (strategy_configuration.getAudioLocation() ==
+ setting::AudioLocation::STEREO) {
+ if ((strategy_configuration.getConnectedDevice() == 2 &&
+ strategy_configuration.getChannelCount() == 1) ||
+ (strategy_configuration.getConnectedDevice() == 1 &&
+ strategy_configuration.getChannelCount() == 2)) {
+ // Stereo
+ // 1. two connected device, one for L one for R
+ // 2. one connected device for both L and R
+ return true;
+ }
+ } else if (strategy_configuration.getAudioLocation() ==
+ setting::AudioLocation::MONO) {
+ if (strategy_configuration.getConnectedDevice() == 1 &&
+ strategy_configuration.getChannelCount() == 1) {
+ // Mono
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
+} // namespace aidl