diff options
author | Bao Do <quocbaodo@google.com> | 2023-12-14 03:01:01 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-12-14 03:01:01 +0000 |
commit | 1dcad7913e04f524205649da248fe1d902e103da (patch) | |
tree | bf7f0f9725b75a4f4858c8efaed8f884df92e154 | |
parent | d011ea3f994bfaaff2c6188844956c70ad4302c1 (diff) | |
parent | 1f2f55d71ccd5c0a9a1c4ea5effb6a4107d245bf (diff) | |
download | interfaces-1dcad7913e04f524205649da248fe1d902e103da.tar.gz |
Parse LE Audio Set Configuration into LeAudioAseConfiguration am: be99419521 am: b1d7914038 am: 1f2f55d71c
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2836199
Change-Id: I957d4c28bd8ff3d6054b23e79fe564afa3285fc9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | bluetooth/audio/utils/Android.bp | 10 | ||||
-rw-r--r-- | bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp | 747 |
2 files changed, 757 insertions, 0 deletions
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp index 16ee70a463..f5f8163a92 100644 --- a/bluetooth/audio/utils/Android.bp +++ b/bluetooth/audio/utils/Android.bp @@ -69,6 +69,12 @@ cc_library_shared { "le_audio_codec_capabilities", "AIDLLeAudioSetConfigSchemas_h", ], + required: [ + "aidl_audio_set_configurations_bfbs", + "aidl_audio_set_configurations_json", + "aidl_audio_set_scenarios_bfbs", + "aidl_audio_set_scenarios_json", + ], } cc_test { @@ -155,6 +161,7 @@ prebuilt_etc { src: ":AIDLLeAudioSetScenariosSchema_bfbs", filename: "aidl_audio_set_scenarios.bfbs", sub_dir: "aidl/le_audio", + vendor: true, } prebuilt_etc { @@ -162,6 +169,7 @@ prebuilt_etc { src: "le_audio_configuration_set/audio_set_scenarios.json", filename: "aidl_audio_set_scenarios.json", sub_dir: "aidl/le_audio", + vendor: true, } prebuilt_etc { @@ -169,6 +177,7 @@ prebuilt_etc { src: ":AIDLLeAudioSetConfigsSchema_bfbs", filename: "aidl_audio_set_configurations.bfbs", sub_dir: "aidl/le_audio", + vendor: true, } prebuilt_etc { @@ -176,4 +185,5 @@ prebuilt_etc { src: "le_audio_configuration_set/audio_set_configurations.json", filename: "aidl_audio_set_configurations.json", sub_dir: "aidl/le_audio", + vendor: true, } diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp new file mode 100644 index 0000000000..56a4e17811 --- /dev/null +++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp @@ -0,0 +1,747 @@ +/* + * Copyright (C) 2023 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 STREAM_TO_UINT8(u8, p) \ + { \ + (u8) = (uint8_t)(*(p)); \ + (p) += 1; \ + } +#define STREAM_TO_UINT16(u16, p) \ + { \ + (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \ + (p) += 2; \ + } +#define STREAM_TO_UINT32(u32, p) \ + { \ + (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \ + ((((uint32_t)(*((p) + 2)))) << 16) + \ + ((((uint32_t)(*((p) + 3)))) << 24)); \ + (p) += 4; \ + } + +#define LOG_TAG "BTAudioCodecsAidl" + +#include "BluetoothLeAudioAseConfigurationSettingProvider.h" + +#include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h> +#include <aidl/android/hardware/bluetooth/audio/AudioContext.h> +#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h> +#include <aidl/android/hardware/bluetooth/audio/CodecId.h> +#include <aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.h> +#include <aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h> +#include <aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h> +#include <aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h> +#include <aidl/android/hardware/bluetooth/audio/Phy.h> +#include <android-base/logging.h> + +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +/* Internal structure definition */ +std::map<std::string, + std::tuple<std::vector<std::optional<AseDirectionConfiguration>>*, + std::vector<std::optional<AseDirectionConfiguration>>*, + ConfigurationFlags*>> + configurations_; + +std::vector<LeAudioAseConfigurationSetting> ase_configuration_settings_; + +constexpr uint8_t kIsoDataPathHci = 0x00; +constexpr uint8_t kIsoDataPathPlatformDefault = 0x01; +constexpr uint8_t kIsoDataPathDisabled = 0xFF; + +constexpr uint8_t kLeAudioDirectionSink = 0x01; +constexpr uint8_t kLeAudioDirectionSource = 0x02; +constexpr uint8_t kLeAudioDirectionBoth = + kLeAudioDirectionSink | kLeAudioDirectionSource; + +/* Sampling Frequencies */ +constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01; +constexpr uint8_t kLeAudioSamplingFreq11025Hz = 0x02; +constexpr uint8_t kLeAudioSamplingFreq16000Hz = 0x03; +constexpr uint8_t kLeAudioSamplingFreq22050Hz = 0x04; +constexpr uint8_t kLeAudioSamplingFreq24000Hz = 0x05; +constexpr uint8_t kLeAudioSamplingFreq32000Hz = 0x06; +constexpr uint8_t kLeAudioSamplingFreq44100Hz = 0x07; +constexpr uint8_t kLeAudioSamplingFreq48000Hz = 0x08; +constexpr uint8_t kLeAudioSamplingFreq88200Hz = 0x09; +constexpr uint8_t kLeAudioSamplingFreq96000Hz = 0x0A; +constexpr uint8_t kLeAudioSamplingFreq176400Hz = 0x0B; +constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C; +constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D; + +/* Frame Durations */ +constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00; +constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01; + +/* Audio Allocations */ +constexpr uint32_t kLeAudioLocationNotAllowed = 0x00000000; +constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001; +constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002; +constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004; +constexpr uint32_t kLeAudioLocationLowFreqEffects1 = 0x00000008; +constexpr uint32_t kLeAudioLocationBackLeft = 0x00000010; +constexpr uint32_t kLeAudioLocationBackRight = 0x00000020; +constexpr uint32_t kLeAudioLocationFrontLeftOfCenter = 0x00000040; +constexpr uint32_t kLeAudioLocationFrontRightOfCenter = 0x00000080; +constexpr uint32_t kLeAudioLocationBackCenter = 0x00000100; +constexpr uint32_t kLeAudioLocationLowFreqEffects2 = 0x00000200; +constexpr uint32_t kLeAudioLocationSideLeft = 0x00000400; +constexpr uint32_t kLeAudioLocationSideRight = 0x00000800; +constexpr uint32_t kLeAudioLocationTopFrontLeft = 0x00001000; +constexpr uint32_t kLeAudioLocationTopFrontRight = 0x00002000; +constexpr uint32_t kLeAudioLocationTopFrontCenter = 0x00004000; +constexpr uint32_t kLeAudioLocationTopCenter = 0x00008000; +constexpr uint32_t kLeAudioLocationTopBackLeft = 0x00010000; +constexpr uint32_t kLeAudioLocationTopBackRight = 0x00020000; +constexpr uint32_t kLeAudioLocationTopSideLeft = 0x00040000; +constexpr uint32_t kLeAudioLocationTopSideRight = 0x00080000; +constexpr uint32_t kLeAudioLocationTopBackCenter = 0x00100000; +constexpr uint32_t kLeAudioLocationBottomFrontCenter = 0x00200000; +constexpr uint32_t kLeAudioLocationBottomFrontLeft = 0x00400000; +constexpr uint32_t kLeAudioLocationBottomFrontRight = 0x00800000; +constexpr uint32_t kLeAudioLocationFrontLeftWide = 0x01000000; +constexpr uint32_t kLeAudioLocationFrontRightWide = 0x02000000; +constexpr uint32_t kLeAudioLocationLeftSurround = 0x04000000; +constexpr uint32_t kLeAudioLocationRightSurround = 0x08000000; + +constexpr uint32_t kLeAudioLocationAnyLeft = + kLeAudioLocationFrontLeft | kLeAudioLocationBackLeft | + kLeAudioLocationFrontLeftOfCenter | kLeAudioLocationSideLeft | + kLeAudioLocationTopFrontLeft | kLeAudioLocationTopBackLeft | + kLeAudioLocationTopSideLeft | kLeAudioLocationBottomFrontLeft | + kLeAudioLocationFrontLeftWide | kLeAudioLocationLeftSurround; + +constexpr uint32_t kLeAudioLocationAnyRight = + kLeAudioLocationFrontRight | kLeAudioLocationBackRight | + kLeAudioLocationFrontRightOfCenter | kLeAudioLocationSideRight | + kLeAudioLocationTopFrontRight | kLeAudioLocationTopBackRight | + kLeAudioLocationTopSideRight | kLeAudioLocationBottomFrontRight | + kLeAudioLocationFrontRightWide | kLeAudioLocationRightSurround; + +constexpr uint32_t kLeAudioLocationStereo = + kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight; + +/* Octets Per Frame */ +constexpr uint16_t kLeAudioCodecFrameLen30 = 30; +constexpr uint16_t kLeAudioCodecFrameLen40 = 40; +constexpr uint16_t kLeAudioCodecFrameLen60 = 60; +constexpr uint16_t kLeAudioCodecFrameLen80 = 80; +constexpr uint16_t kLeAudioCodecFrameLen100 = 100; +constexpr uint16_t kLeAudioCodecFrameLen120 = 120; + +/* Helper map for matching various sampling frequency notations */ +const std::map<uint8_t, CodecSpecificConfigurationLtv::SamplingFrequency> + sampling_freq_map = { + {kLeAudioSamplingFreq8000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000}, + {kLeAudioSamplingFreq16000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000}, + {kLeAudioSamplingFreq24000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000}, + {kLeAudioSamplingFreq32000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000}, + {kLeAudioSamplingFreq44100Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ44100}, + {kLeAudioSamplingFreq48000Hz, + CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}}; + +/* Helper map for matching various frame durations notations */ +const std::map<uint8_t, CodecSpecificConfigurationLtv::FrameDuration> + frame_duration_map = { + {kLeAudioCodecFrameDur7500us, + CodecSpecificConfigurationLtv::FrameDuration::US7500}, + {kLeAudioCodecFrameDur10000us, + CodecSpecificConfigurationLtv::FrameDuration::US10000}}; + +/* Helper map for matching various audio channel allocation notations */ +std::map<uint32_t, uint32_t> audio_channel_allocation_map = { + {kLeAudioLocationNotAllowed, + CodecSpecificConfigurationLtv::AudioChannelAllocation::NOT_ALLOWED}, + {kLeAudioLocationFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT}, + {kLeAudioLocationFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT}, + {kLeAudioLocationFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER}, + {kLeAudioLocationLowFreqEffects1, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + LOW_FREQUENCY_EFFECTS_1}, + {kLeAudioLocationBackLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_LEFT}, + {kLeAudioLocationBackRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_RIGHT}, + {kLeAudioLocationFrontLeftOfCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + FRONT_LEFT_OF_CENTER}, + {kLeAudioLocationFrontRightOfCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + FRONT_RIGHT_OF_CENTER}, + {kLeAudioLocationBackCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_CENTER}, + {kLeAudioLocationLowFreqEffects2, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + LOW_FREQUENCY_EFFECTS_2}, + {kLeAudioLocationSideLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_LEFT}, + {kLeAudioLocationSideRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_RIGHT}, + {kLeAudioLocationTopFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_LEFT}, + {kLeAudioLocationTopFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_RIGHT}, + {kLeAudioLocationTopFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_CENTER}, + {kLeAudioLocationTopCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_CENTER}, + {kLeAudioLocationTopBackLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_LEFT}, + {kLeAudioLocationTopBackRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_RIGHT}, + {kLeAudioLocationTopSideLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_LEFT}, + {kLeAudioLocationTopSideRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_RIGHT}, + {kLeAudioLocationTopBackCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_CENTER}, + {kLeAudioLocationBottomFrontCenter, + CodecSpecificConfigurationLtv::AudioChannelAllocation:: + BOTTOM_FRONT_CENTER}, + {kLeAudioLocationBottomFrontLeft, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_LEFT}, + {kLeAudioLocationBottomFrontRight, + CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_RIGHT}, + {kLeAudioLocationFrontLeftWide, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT_WIDE}, + {kLeAudioLocationFrontRightWide, + CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT_WIDE}, + {kLeAudioLocationLeftSurround, + CodecSpecificConfigurationLtv::AudioChannelAllocation::LEFT_SURROUND}, + {kLeAudioLocationRightSurround, + CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND}, +}; + +static const std::vector< + std::pair<const char* /*schema*/, const char* /*content*/>> + kLeAudioSetConfigs = {{"/vendor/etc/aidl/le_audio/" + "aidl_audio_set_configurations.bfbs", + "/vendor/etc/aidl/le_audio/" + "aidl_audio_set_configurations.json"}}; +static const std::vector< + std::pair<const char* /*schema*/, const char* /*content*/>> + kLeAudioSetScenarios = {{"/vendor/etc/aidl/le_audio/" + "aidl_audio_set_scenarios.bfbs", + "/vendor/etc/aidl/le_audio/" + "aidl_audio_set_configurations.json"}}; + +/* Implementation */ + +std::vector<LeAudioAseConfigurationSetting> +AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() { + AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson(); + return ase_configuration_settings_; +} + +void AudioSetConfigurationProviderJson:: + LoadAudioSetConfigurationProviderJson() { + if (configurations_.empty() && ase_configuration_settings_.empty()) { + auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios, + CodecLocation::HOST); + if (!loaded) + LOG(ERROR) << ": Unable to load le audio set configuration files."; + } else + LOG(INFO) << ": Reusing loaded le audio set configuration"; +} + +const le_audio::CodecSpecificConfiguration* +AudioSetConfigurationProviderJson::LookupCodecSpecificParam( + const flatbuffers::Vector<flatbuffers::Offset< + le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes type) { + auto it = std::find_if( + flat_codec_specific_params->cbegin(), flat_codec_specific_params->cend(), + [&type](const auto& csc) { return (csc->type() == type); }); + return (it != flat_codec_specific_params->cend()) ? *it : nullptr; +} + +void AudioSetConfigurationProviderJson::populateAudioChannelAllocation( + CodecSpecificConfigurationLtv::AudioChannelAllocation& + audio_channel_allocation, + uint32_t audio_location) { + audio_channel_allocation.bitmask = 0; + for (auto [allocation, bitmask] : audio_channel_allocation_map) { + if (audio_location & allocation) + audio_channel_allocation.bitmask |= bitmask; + } +} + +void AudioSetConfigurationProviderJson::populateConfigurationData( + LeAudioAseConfiguration& ase, + const flatbuffers::Vector< + flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>* + flat_codec_specific_params) { + uint8_t sampling_frequency = 0; + uint8_t frame_duration = 0; + uint32_t audio_channel_allocation = 0; + uint16_t octets_per_codec_frame = 0; + uint8_t codec_frames_blocks_per_sdu = 0; + + auto param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(sampling_frequency, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(frame_duration, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio:: + CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT32(audio_channel_allocation, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT16(octets_per_codec_frame, ptr); + } + + param = LookupCodecSpecificParam( + flat_codec_specific_params, + le_audio:: + CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU); + if (param) { + auto ptr = param->compound_value()->value()->data(); + STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr); + } + + // Make the correct value + ase.codecConfiguration = std::vector<CodecSpecificConfigurationLtv>(); + + auto sampling_freq_it = sampling_freq_map.find(sampling_frequency); + if (sampling_freq_it != sampling_freq_map.end()) + ase.codecConfiguration.push_back(sampling_freq_it->second); + auto frame_duration_it = frame_duration_map.find(frame_duration); + if (frame_duration_it != frame_duration_map.end()) + ase.codecConfiguration.push_back(frame_duration_it->second); + + CodecSpecificConfigurationLtv::AudioChannelAllocation channel_allocation; + populateAudioChannelAllocation(channel_allocation, audio_channel_allocation); + ase.codecConfiguration.push_back(channel_allocation); + + auto octet_structure = CodecSpecificConfigurationLtv::OctetsPerCodecFrame(); + octet_structure.value = octets_per_codec_frame; + ase.codecConfiguration.push_back(octet_structure); + + auto frame_sdu_structure = + CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU(); + frame_sdu_structure.value = codec_frames_blocks_per_sdu; + ase.codecConfiguration.push_back(frame_sdu_structure); + // TODO: Channel count +} + +void AudioSetConfigurationProviderJson::populateAseConfiguration( + LeAudioAseConfiguration& ase, + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg) { + // Target latency + switch (qos_cfg->target_latency()) { + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_BALANCED_RELIABILITY: + ase.targetLatency = + LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY; + break; + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_HIGH_RELIABILITY: + ase.targetLatency = + LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY; + break; + case le_audio::AudioSetConfigurationTargetLatency:: + AudioSetConfigurationTargetLatency_LOW: + ase.targetLatency = LeAudioAseConfiguration::TargetLatency::LOWER; + break; + default: + ase.targetLatency = LeAudioAseConfiguration::TargetLatency::UNDEFINED; + break; + }; + + ase.targetPhy = Phy::TWO_M; + // Making CodecId + if (flat_subconfig->codec_id()->coding_format() == + (uint8_t)CodecId::Core::LC3) { + ase.codecId = CodecId::Core::LC3; + } else { + auto vendorC = CodecId::Vendor(); + vendorC.codecId = flat_subconfig->codec_id()->vendor_codec_id(); + vendorC.id = flat_subconfig->codec_id()->vendor_company_id(); + ase.codecId = vendorC; + } + // Codec configuration data + populateConfigurationData(ase, flat_subconfig->codec_configuration()); +} + +void AudioSetConfigurationProviderJson::populateAseQosConfiguration( + LeAudioAseQosConfiguration& qos, + const le_audio::QosConfiguration* qos_cfg) { + qos.maxTransportLatencyMs = qos_cfg->max_transport_latency(); + qos.retransmissionNum = qos_cfg->retransmission_number(); +} + +// Parse into AseDirectionConfiguration +AseDirectionConfiguration +AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig( + const le_audio::AudioSetSubConfiguration* flat_subconfig, + const le_audio::QosConfiguration* qos_cfg, CodecLocation location) { + AseDirectionConfiguration direction_conf; + + LeAudioAseConfiguration ase; + LeAudioAseQosConfiguration qos; + LeAudioDataPathConfiguration path; + + // Translate into LeAudioAseConfiguration + populateAseConfiguration(ase, flat_subconfig, qos_cfg); + + // Translate into LeAudioAseQosConfiguration + populateAseQosConfiguration(qos, qos_cfg); + + // Translate location to data path id + switch (location) { + case CodecLocation::ADSP: + path.isoDataPathConfiguration.isTransparent = true; + path.dataPathId = kIsoDataPathPlatformDefault; + break; + case CodecLocation::HOST: + path.isoDataPathConfiguration.isTransparent = true; + path.dataPathId = kIsoDataPathHci; + break; + case CodecLocation::CONTROLLER: + path.isoDataPathConfiguration.isTransparent = false; + path.dataPathId = kIsoDataPathPlatformDefault; + break; + } + + direction_conf.aseConfiguration = ase; + direction_conf.qosConfiguration = qos; + direction_conf.dataPathConfiguration = path; + + return direction_conf; +} + +// Parse into AseDirectionConfiguration and the ConfigurationFlags +// and put them in the given list. +void AudioSetConfigurationProviderJson::processSubconfig( + const le_audio::AudioSetSubConfiguration* subconfig, + const le_audio::QosConfiguration* qos_cfg, + std::vector<std::optional<AseDirectionConfiguration>>& + directionAseConfiguration, + CodecLocation location) { + directionAseConfiguration.push_back( + SetConfigurationFromFlatSubconfig(subconfig, qos_cfg, location)); +} + +void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat( + const le_audio::AudioSetConfiguration* flat_cfg, + std::vector<const le_audio::CodecConfiguration*>* codec_cfgs, + std::vector<const le_audio::QosConfiguration*>* qos_cfgs, + CodecLocation location, + std::vector<std::optional<AseDirectionConfiguration>>& + sourceAseConfiguration, + std::vector<std::optional<AseDirectionConfiguration>>& sinkAseConfiguration, + ConfigurationFlags& /*configurationFlags*/) { + if (flat_cfg == nullptr) { + LOG(ERROR) << "flat_cfg cannot be null"; + return; + } + std::string codec_config_key = flat_cfg->codec_config_name()->str(); + auto* qos_config_key_array = flat_cfg->qos_config_name(); + + constexpr std::string_view default_qos = "QoS_Config_Balanced_Reliability"; + + std::string qos_sink_key(default_qos); + std::string qos_source_key(default_qos); + + /* We expect maximum two QoS settings. First for Sink and second for Source + */ + if (qos_config_key_array->size() > 0) { + qos_sink_key = qos_config_key_array->Get(0)->str(); + if (qos_config_key_array->size() > 1) { + qos_source_key = qos_config_key_array->Get(1)->str(); + } else { + qos_source_key = qos_sink_key; + } + } + + LOG(INFO) << "Audio set config " << flat_cfg->name()->c_str() + << ": codec config " << codec_config_key.c_str() << ", qos_sink " + << qos_sink_key.c_str() << ", qos_source " + << qos_source_key.c_str(); + + // Find the first qos config that match the name + const le_audio::QosConfiguration* qos_sink_cfg = nullptr; + for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) { + if ((*i)->name()->str() == qos_sink_key) { + qos_sink_cfg = *i; + break; + } + } + + const le_audio::QosConfiguration* qos_source_cfg = nullptr; + for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) { + if ((*i)->name()->str() == qos_source_key) { + qos_source_cfg = *i; + break; + } + } + + // First codec_cfg with the same name + const le_audio::CodecConfiguration* codec_cfg = nullptr; + for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) { + if ((*i)->name()->str() == codec_config_key) { + codec_cfg = *i; + break; + } + } + + // Process each subconfig and put it into the correct list + if (codec_cfg != nullptr && codec_cfg->subconfigurations()) { + /* Load subconfigurations */ + for (auto subconfig : *codec_cfg->subconfigurations()) { + if (subconfig->direction() == kLeAudioDirectionSink) { + processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration, + location); + } else { + processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration, + location); + } + } + } else { + if (codec_cfg == nullptr) { + LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str() + << " found"; + } else { + LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str() + << "' has no valid subconfigurations."; + } + } + + // TODO: Populate information for ConfigurationFlags +} + +bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles( + const char* schema_file, const char* content_file, CodecLocation location) { + flatbuffers::Parser configurations_parser_; + std::string configurations_schema_binary_content; + bool ok = flatbuffers::LoadFile(schema_file, true, + &configurations_schema_binary_content); + LOG(INFO) << __func__ << "Loading file " << schema_file; + if (!ok) return ok; + + /* Load the binary schema */ + ok = configurations_parser_.Deserialize( + (uint8_t*)configurations_schema_binary_content.c_str(), + configurations_schema_binary_content.length()); + if (!ok) return ok; + + /* Load the content from JSON */ + std::string configurations_json_content; + LOG(INFO) << __func__ << "Loading file " << schema_file; + ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content); + if (!ok) return ok; + + /* Parse */ + LOG(INFO) << __func__ << "Parse JSON content" << schema_file; + ok = configurations_parser_.Parse(configurations_json_content.c_str()); + if (!ok) return ok; + + /* Import from flatbuffers */ + LOG(INFO) << __func__ << "Build flat buffer structure" << schema_file; + auto configurations_root = le_audio::GetAudioSetConfigurations( + configurations_parser_.builder_.GetBufferPointer()); + if (!configurations_root) return false; + + auto flat_qos_configs = configurations_root->qos_configurations(); + if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0)) + return false; + + LOG(DEBUG) << ": Updating " << flat_qos_configs->size() + << " qos config entries."; + std::vector<const le_audio::QosConfiguration*> qos_cfgs; + for (auto const& flat_qos_cfg : *flat_qos_configs) { + qos_cfgs.push_back(flat_qos_cfg); + } + + auto flat_codec_configs = configurations_root->codec_configurations(); + if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0)) + return false; + + LOG(DEBUG) << ": Updating " << flat_codec_configs->size() + << " codec config entries."; + std::vector<const le_audio::CodecConfiguration*> codec_cfgs; + for (auto const& flat_codec_cfg : *flat_codec_configs) { + codec_cfgs.push_back(flat_codec_cfg); + } + + auto flat_configs = configurations_root->configurations(); + if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false; + + LOG(DEBUG) << ": Updating " << flat_configs->size() << " config entries."; + for (auto const& flat_cfg : *flat_configs) { + // Create 3 vector to use + std::vector<std::optional<AseDirectionConfiguration>> + sourceAseConfiguration; + std::vector<std::optional<AseDirectionConfiguration>> sinkAseConfiguration; + ConfigurationFlags configurationFlags; + PopulateAseConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs, location, + sourceAseConfiguration, + sinkAseConfiguration, configurationFlags); + if (sourceAseConfiguration.empty() && sinkAseConfiguration.empty()) + continue; + configurations_[flat_cfg->name()->str()] = std::make_tuple( + &sourceAseConfiguration, &sinkAseConfiguration, &configurationFlags); + } + + return true; +} + +bool AudioSetConfigurationProviderJson::LoadScenariosFromFiles( + const char* schema_file, const char* content_file) { + flatbuffers::Parser scenarios_parser_; + std::string scenarios_schema_binary_content; + bool ok = flatbuffers::LoadFile(schema_file, true, + &scenarios_schema_binary_content); + if (!ok) return ok; + + /* Load the binary schema */ + ok = scenarios_parser_.Deserialize( + (uint8_t*)scenarios_schema_binary_content.c_str(), + scenarios_schema_binary_content.length()); + if (!ok) return ok; + + /* Load the content from JSON */ + std::string scenarios_json_content; + ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content); + if (!ok) return ok; + + /* Parse */ + ok = scenarios_parser_.Parse(scenarios_json_content.c_str()); + if (!ok) return ok; + + /* Import from flatbuffers */ + auto scenarios_root = le_audio::GetAudioSetScenarios( + scenarios_parser_.builder_.GetBufferPointer()); + if (!scenarios_root) return false; + + auto flat_scenarios = scenarios_root->scenarios(); + if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0)) + return false; + + AudioContext media_context = AudioContext(); + media_context.bitmask = + (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL | + AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM | + AudioContext::UNSPECIFIED | AudioContext::MEDIA); + + AudioContext conversational_context = AudioContext(); + conversational_context.bitmask = + (AudioContext::RINGTONE_ALERTS | AudioContext::CONVERSATIONAL); + + AudioContext live_context = AudioContext(); + live_context.bitmask = AudioContext::LIVE_AUDIO; + + AudioContext game_context = AudioContext(); + game_context.bitmask = AudioContext::GAME; + + AudioContext voice_assistants_context = AudioContext(); + voice_assistants_context.bitmask = AudioContext::VOICE_ASSISTANTS; + + LOG(DEBUG) << ": Updating " << flat_scenarios->size() << " scenarios."; + for (auto const& scenario : *flat_scenarios) { + LOG(DEBUG) << "Scenario " << scenario->name()->c_str() << " configs:"; + + if (!scenario->configurations()) continue; + std::string scenario_name = scenario->name()->c_str(); + AudioContext context; + if (scenario_name == "Media") + context = AudioContext(media_context); + else if (scenario_name == "Conversational") + context = AudioContext(conversational_context); + else if (scenario_name == "Live") + context = AudioContext(live_context); + else if (scenario_name == "Game") + context = AudioContext(game_context); + else if (scenario_name == "VoiceAssistants") + context = AudioContext(voice_assistants_context); + + for (auto config_name : *scenario->configurations()) { + if (configurations_.count(config_name->str()) == 0) continue; + auto [source, sink, flags] = configurations_.at(config_name->str()); + // Each configuration will create a LeAudioAseConfigurationSetting + // with the same {context, packing} + // and different data + LeAudioAseConfigurationSetting setting; + setting.audioContext = context; + // TODO: Packing + setting.sourceAseConfiguration = *source; + setting.sinkAseConfiguration = *sink; + setting.flags = *flags; + // Add to list of setting + ase_configuration_settings_.push_back(setting); + } + } + + return true; +} + +bool AudioSetConfigurationProviderJson::LoadContent( + std::vector<std::pair<const char* /*schema*/, const char* /*content*/>> + config_files, + std::vector<std::pair<const char* /*schema*/, const char* /*content*/>> + scenario_files, + CodecLocation location) { + for (auto [schema, content] : config_files) { + if (!LoadConfigurationsFromFiles(schema, content, location)) return false; + } + + for (auto [schema, content] : scenario_files) { + if (!LoadScenariosFromFiles(schema, content)) return false; + } + return true; +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl |