760 lines
31 KiB
C++
760 lines
31 KiB
C++
/*
|
|
* 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 "BTAudioAseConfigAidl"
|
|
|
|
#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_scenarios.json"}};
|
|
|
|
/* Implementation */
|
|
|
|
std::vector<LeAudioAseConfigurationSetting>
|
|
AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() {
|
|
AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson();
|
|
return ase_configuration_settings_;
|
|
}
|
|
|
|
void AudioSetConfigurationProviderJson::
|
|
LoadAudioSetConfigurationProviderJson() {
|
|
if (configurations_.empty() || ase_configuration_settings_.empty()) {
|
|
ase_configuration_settings_.clear();
|
|
configurations_.clear();
|
|
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 " << content_file;
|
|
ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content);
|
|
if (!ok) return ok;
|
|
|
|
/* Parse */
|
|
LOG(INFO) << __func__ << ": Parse JSON content";
|
|
ok = configurations_parser_.Parse(configurations_json_content.c_str());
|
|
if (!ok) return ok;
|
|
|
|
/* Import from flatbuffers */
|
|
LOG(INFO) << __func__ << ": Build flat buffer structure";
|
|
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);
|
|
LOG(INFO) << __func__ << ": Loading file " << schema_file;
|
|
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 */
|
|
LOG(INFO) << __func__ << ": Loading file " << content_file;
|
|
std::string scenarios_json_content;
|
|
ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content);
|
|
if (!ok) return ok;
|
|
|
|
/* Parse */
|
|
LOG(INFO) << __func__ << ": Parse json content";
|
|
ok = scenarios_parser_.Parse(scenarios_json_content.c_str());
|
|
if (!ok) return ok;
|
|
|
|
/* Import from flatbuffers */
|
|
LOG(INFO) << __func__ << ": Build flat buffer structure";
|
|
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;
|
|
|
|
LOG(INFO) << __func__ << ": Turn flat buffer into structure";
|
|
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: " << scenario->configurations()->size();
|
|
|
|
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 it = scenario->configurations()->begin();
|
|
it != scenario->configurations()->end(); ++it) {
|
|
auto config_name = it->str();
|
|
auto configuration = configurations_.find(config_name);
|
|
if (configuration == configurations_.end()) continue;
|
|
LOG(DEBUG) << "Getting configuration with name: " << config_name;
|
|
auto [source, sink, flags] = configuration->second;
|
|
// 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
|
|
LOG(DEBUG) << "Pushing configuration to list: " << config_name;
|
|
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
|