1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define STREAM_TO_UINT8(u8, p) \
18 { \
19 (u8) = (uint8_t)(*(p)); \
20 (p) += 1; \
21 }
22 #define STREAM_TO_UINT16(u16, p) \
23 { \
24 (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
25 (p) += 2; \
26 }
27 #define STREAM_TO_UINT32(u32, p) \
28 { \
29 (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
30 ((((uint32_t)(*((p) + 2)))) << 16) + \
31 ((((uint32_t)(*((p) + 3)))) << 24)); \
32 (p) += 4; \
33 }
34
35 #define LOG_TAG "BTAudioAseConfigAidl"
36
37 #include "BluetoothLeAudioAseConfigurationSettingProvider.h"
38
39 #include <aidl/android/hardware/bluetooth/audio/AudioConfiguration.h>
40 #include <aidl/android/hardware/bluetooth/audio/AudioContext.h>
41 #include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
42 #include <aidl/android/hardware/bluetooth/audio/CodecId.h>
43 #include <aidl/android/hardware/bluetooth/audio/CodecSpecificCapabilitiesLtv.h>
44 #include <aidl/android/hardware/bluetooth/audio/CodecSpecificConfigurationLtv.h>
45 #include <aidl/android/hardware/bluetooth/audio/ConfigurationFlags.h>
46 #include <aidl/android/hardware/bluetooth/audio/LeAudioAseConfiguration.h>
47 #include <aidl/android/hardware/bluetooth/audio/Phy.h>
48 #include <android-base/logging.h>
49
50 #include <optional>
51
52 #include "flatbuffers/idl.h"
53 #include "flatbuffers/util.h"
54
55 namespace aidl {
56 namespace android {
57 namespace hardware {
58 namespace bluetooth {
59 namespace audio {
60
61 /* Internal structure definition */
62 std::map<std::string,
63 std::tuple<std::vector<std::optional<AseDirectionConfiguration>>,
64 std::vector<std::optional<AseDirectionConfiguration>>,
65 ConfigurationFlags>>
66 configurations_;
67
68 std::vector<std::pair<std::string, LeAudioAseConfigurationSetting>>
69 ase_configuration_settings_;
70
71 constexpr uint8_t kIsoDataPathHci = 0x00;
72 constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
73 constexpr uint8_t kIsoDataPathDisabled = 0xFF;
74
75 constexpr uint8_t kLeAudioDirectionSink = 0x01;
76 constexpr uint8_t kLeAudioDirectionSource = 0x02;
77 constexpr uint8_t kLeAudioDirectionBoth =
78 kLeAudioDirectionSink | kLeAudioDirectionSource;
79
80 /* Sampling Frequencies */
81 constexpr uint8_t kLeAudioSamplingFreq8000Hz = 0x01;
82 constexpr uint8_t kLeAudioSamplingFreq11025Hz = 0x02;
83 constexpr uint8_t kLeAudioSamplingFreq16000Hz = 0x03;
84 constexpr uint8_t kLeAudioSamplingFreq22050Hz = 0x04;
85 constexpr uint8_t kLeAudioSamplingFreq24000Hz = 0x05;
86 constexpr uint8_t kLeAudioSamplingFreq32000Hz = 0x06;
87 constexpr uint8_t kLeAudioSamplingFreq44100Hz = 0x07;
88 constexpr uint8_t kLeAudioSamplingFreq48000Hz = 0x08;
89 constexpr uint8_t kLeAudioSamplingFreq88200Hz = 0x09;
90 constexpr uint8_t kLeAudioSamplingFreq96000Hz = 0x0A;
91 constexpr uint8_t kLeAudioSamplingFreq176400Hz = 0x0B;
92 constexpr uint8_t kLeAudioSamplingFreq192000Hz = 0x0C;
93 constexpr uint8_t kLeAudioSamplingFreq384000Hz = 0x0D;
94
95 /* Frame Durations */
96 constexpr uint8_t kLeAudioCodecFrameDur7500us = 0x00;
97 constexpr uint8_t kLeAudioCodecFrameDur10000us = 0x01;
98 constexpr uint8_t kLeAudioCodecFrameDur20000us = 0x02;
99
100 /* Audio Allocations */
101 constexpr uint32_t kLeAudioLocationMonoAudio = 0x00000000;
102 constexpr uint32_t kLeAudioLocationFrontLeft = 0x00000001;
103 constexpr uint32_t kLeAudioLocationFrontRight = 0x00000002;
104 constexpr uint32_t kLeAudioLocationFrontCenter = 0x00000004;
105 constexpr uint32_t kLeAudioLocationLowFreqEffects1 = 0x00000008;
106 constexpr uint32_t kLeAudioLocationBackLeft = 0x00000010;
107 constexpr uint32_t kLeAudioLocationBackRight = 0x00000020;
108 constexpr uint32_t kLeAudioLocationFrontLeftOfCenter = 0x00000040;
109 constexpr uint32_t kLeAudioLocationFrontRightOfCenter = 0x00000080;
110 constexpr uint32_t kLeAudioLocationBackCenter = 0x00000100;
111 constexpr uint32_t kLeAudioLocationLowFreqEffects2 = 0x00000200;
112 constexpr uint32_t kLeAudioLocationSideLeft = 0x00000400;
113 constexpr uint32_t kLeAudioLocationSideRight = 0x00000800;
114 constexpr uint32_t kLeAudioLocationTopFrontLeft = 0x00001000;
115 constexpr uint32_t kLeAudioLocationTopFrontRight = 0x00002000;
116 constexpr uint32_t kLeAudioLocationTopFrontCenter = 0x00004000;
117 constexpr uint32_t kLeAudioLocationTopCenter = 0x00008000;
118 constexpr uint32_t kLeAudioLocationTopBackLeft = 0x00010000;
119 constexpr uint32_t kLeAudioLocationTopBackRight = 0x00020000;
120 constexpr uint32_t kLeAudioLocationTopSideLeft = 0x00040000;
121 constexpr uint32_t kLeAudioLocationTopSideRight = 0x00080000;
122 constexpr uint32_t kLeAudioLocationTopBackCenter = 0x00100000;
123 constexpr uint32_t kLeAudioLocationBottomFrontCenter = 0x00200000;
124 constexpr uint32_t kLeAudioLocationBottomFrontLeft = 0x00400000;
125 constexpr uint32_t kLeAudioLocationBottomFrontRight = 0x00800000;
126 constexpr uint32_t kLeAudioLocationFrontLeftWide = 0x01000000;
127 constexpr uint32_t kLeAudioLocationFrontRightWide = 0x02000000;
128 constexpr uint32_t kLeAudioLocationLeftSurround = 0x04000000;
129 constexpr uint32_t kLeAudioLocationRightSurround = 0x08000000;
130
131 constexpr uint32_t kLeAudioLocationAnyLeft =
132 kLeAudioLocationFrontLeft | kLeAudioLocationBackLeft |
133 kLeAudioLocationFrontLeftOfCenter | kLeAudioLocationSideLeft |
134 kLeAudioLocationTopFrontLeft | kLeAudioLocationTopBackLeft |
135 kLeAudioLocationTopSideLeft | kLeAudioLocationBottomFrontLeft |
136 kLeAudioLocationFrontLeftWide | kLeAudioLocationLeftSurround;
137
138 constexpr uint32_t kLeAudioLocationAnyRight =
139 kLeAudioLocationFrontRight | kLeAudioLocationBackRight |
140 kLeAudioLocationFrontRightOfCenter | kLeAudioLocationSideRight |
141 kLeAudioLocationTopFrontRight | kLeAudioLocationTopBackRight |
142 kLeAudioLocationTopSideRight | kLeAudioLocationBottomFrontRight |
143 kLeAudioLocationFrontRightWide | kLeAudioLocationRightSurround;
144
145 constexpr uint32_t kLeAudioLocationStereo =
146 kLeAudioLocationFrontLeft | kLeAudioLocationFrontRight;
147
148 /* Octets Per Frame */
149 constexpr uint16_t kLeAudioCodecFrameLen30 = 30;
150 constexpr uint16_t kLeAudioCodecFrameLen40 = 40;
151 constexpr uint16_t kLeAudioCodecFrameLen60 = 60;
152 constexpr uint16_t kLeAudioCodecFrameLen80 = 80;
153 constexpr uint16_t kLeAudioCodecFrameLen100 = 100;
154 constexpr uint16_t kLeAudioCodecFrameLen120 = 120;
155
156 /* Helper map for matching various sampling frequency notations */
157 const std::map<uint8_t, CodecSpecificConfigurationLtv::SamplingFrequency>
158 sampling_freq_map = {
159 {kLeAudioSamplingFreq8000Hz,
160 CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000},
161 {kLeAudioSamplingFreq16000Hz,
162 CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
163 {kLeAudioSamplingFreq24000Hz,
164 CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
165 {kLeAudioSamplingFreq32000Hz,
166 CodecSpecificConfigurationLtv::SamplingFrequency::HZ32000},
167 {kLeAudioSamplingFreq44100Hz,
168 CodecSpecificConfigurationLtv::SamplingFrequency::HZ44100},
169 {kLeAudioSamplingFreq48000Hz,
170 CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000}};
171
172 /* Helper map for matching various frame durations notations */
173 const std::map<uint8_t, CodecSpecificConfigurationLtv::FrameDuration>
174 frame_duration_map = {
175 {kLeAudioCodecFrameDur7500us,
176 CodecSpecificConfigurationLtv::FrameDuration::US7500},
177 {kLeAudioCodecFrameDur10000us,
178 CodecSpecificConfigurationLtv::FrameDuration::US10000},
179 {kLeAudioCodecFrameDur20000us,
180 CodecSpecificConfigurationLtv::FrameDuration::US20000}};
181
182 /* Helper map for matching various audio channel allocation notations */
183 std::map<uint32_t, uint32_t> audio_channel_allocation_map = {
184 {kLeAudioLocationMonoAudio,
185 CodecSpecificConfigurationLtv::AudioChannelAllocation::MONO},
186 {kLeAudioLocationFrontLeft,
187 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT},
188 {kLeAudioLocationFrontRight,
189 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT},
190 {kLeAudioLocationFrontCenter,
191 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER},
192 {kLeAudioLocationLowFreqEffects1,
193 CodecSpecificConfigurationLtv::AudioChannelAllocation::
194 LOW_FREQUENCY_EFFECTS_1},
195 {kLeAudioLocationBackLeft,
196 CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_LEFT},
197 {kLeAudioLocationBackRight,
198 CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_RIGHT},
199 {kLeAudioLocationFrontLeftOfCenter,
200 CodecSpecificConfigurationLtv::AudioChannelAllocation::
201 FRONT_LEFT_OF_CENTER},
202 {kLeAudioLocationFrontRightOfCenter,
203 CodecSpecificConfigurationLtv::AudioChannelAllocation::
204 FRONT_RIGHT_OF_CENTER},
205 {kLeAudioLocationBackCenter,
206 CodecSpecificConfigurationLtv::AudioChannelAllocation::BACK_CENTER},
207 {kLeAudioLocationLowFreqEffects2,
208 CodecSpecificConfigurationLtv::AudioChannelAllocation::
209 LOW_FREQUENCY_EFFECTS_2},
210 {kLeAudioLocationSideLeft,
211 CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_LEFT},
212 {kLeAudioLocationSideRight,
213 CodecSpecificConfigurationLtv::AudioChannelAllocation::SIDE_RIGHT},
214 {kLeAudioLocationTopFrontLeft,
215 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_LEFT},
216 {kLeAudioLocationTopFrontRight,
217 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_RIGHT},
218 {kLeAudioLocationTopFrontCenter,
219 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_FRONT_CENTER},
220 {kLeAudioLocationTopCenter,
221 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_CENTER},
222 {kLeAudioLocationTopBackLeft,
223 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_LEFT},
224 {kLeAudioLocationTopBackRight,
225 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_RIGHT},
226 {kLeAudioLocationTopSideLeft,
227 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_LEFT},
228 {kLeAudioLocationTopSideRight,
229 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_SIDE_RIGHT},
230 {kLeAudioLocationTopBackCenter,
231 CodecSpecificConfigurationLtv::AudioChannelAllocation::TOP_BACK_CENTER},
232 {kLeAudioLocationBottomFrontCenter,
233 CodecSpecificConfigurationLtv::AudioChannelAllocation::
234 BOTTOM_FRONT_CENTER},
235 {kLeAudioLocationBottomFrontLeft,
236 CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_LEFT},
237 {kLeAudioLocationBottomFrontRight,
238 CodecSpecificConfigurationLtv::AudioChannelAllocation::BOTTOM_FRONT_RIGHT},
239 {kLeAudioLocationFrontLeftWide,
240 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT_WIDE},
241 {kLeAudioLocationFrontRightWide,
242 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT_WIDE},
243 {kLeAudioLocationLeftSurround,
244 CodecSpecificConfigurationLtv::AudioChannelAllocation::LEFT_SURROUND},
245 {kLeAudioLocationRightSurround,
246 CodecSpecificConfigurationLtv::AudioChannelAllocation::RIGHT_SURROUND},
247 };
248
249 // Set configuration and scenario files with fallback default
250 static const std::vector<
251 std::pair<const char* /*schema*/, const char* /*content*/>>
252 kLeAudioSetConfigs = {
253 {"/vendor/etc/aidl/le_audio/"
254 "aidl_audio_set_configurations.bfbs",
255 "/vendor/etc/aidl/le_audio/"
256 "aidl_audio_set_configurations.json"},
257
258 {"/vendor/etc/aidl/le_audio/"
259 "aidl_audio_set_configurations.bfbs",
260 "/vendor/etc/aidl/le_audio/"
261 "aidl_default_audio_set_configurations.json"},
262 };
263 static const std::vector<
264 std::pair<const char* /*schema*/, const char* /*content*/>>
265 kLeAudioSetScenarios = {{"/vendor/etc/aidl/le_audio/"
266 "aidl_audio_set_scenarios.bfbs",
267 "/vendor/etc/aidl/le_audio/"
268 "aidl_audio_set_scenarios.json"},
269
270 {"/vendor/etc/aidl/le_audio/"
271 "aidl_audio_set_scenarios.bfbs",
272 "/vendor/etc/aidl/le_audio/"
273 "aidl_default_audio_set_scenarios.json"}};
274
275 /* Implementation */
276
277 std::vector<std::pair<std::string, LeAudioAseConfigurationSetting>>
GetLeAudioAseConfigurationSettings()278 AudioSetConfigurationProviderJson::GetLeAudioAseConfigurationSettings() {
279 AudioSetConfigurationProviderJson::LoadAudioSetConfigurationProviderJson();
280 return ase_configuration_settings_;
281 }
282
283 void AudioSetConfigurationProviderJson::
LoadAudioSetConfigurationProviderJson()284 LoadAudioSetConfigurationProviderJson() {
285 if (configurations_.empty() || ase_configuration_settings_.empty()) {
286 ase_configuration_settings_.clear();
287 configurations_.clear();
288 auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios,
289 CodecLocation::ADSP);
290 if (!loaded)
291 LOG(ERROR) << ": Unable to load le audio set configuration files.";
292 } else
293 LOG(INFO) << ": Reusing loaded le audio set configuration";
294 }
295
296 const le_audio::CodecSpecificConfiguration*
LookupCodecSpecificParam(const flatbuffers::Vector<flatbuffers::Offset<le_audio::CodecSpecificConfiguration>> * flat_codec_specific_params,le_audio::CodecSpecificLtvGenericTypes type)297 AudioSetConfigurationProviderJson::LookupCodecSpecificParam(
298 const flatbuffers::Vector<flatbuffers::Offset<
299 le_audio::CodecSpecificConfiguration>>* flat_codec_specific_params,
300 le_audio::CodecSpecificLtvGenericTypes type) {
301 auto it = std::find_if(
302 flat_codec_specific_params->cbegin(), flat_codec_specific_params->cend(),
303 [&type](const auto& csc) { return (csc->type() == type); });
304 return (it != flat_codec_specific_params->cend()) ? *it : nullptr;
305 }
306
populateAudioChannelAllocation(CodecSpecificConfigurationLtv::AudioChannelAllocation & audio_channel_allocation,uint32_t audio_location)307 void AudioSetConfigurationProviderJson::populateAudioChannelAllocation(
308 CodecSpecificConfigurationLtv::AudioChannelAllocation&
309 audio_channel_allocation,
310 uint32_t audio_location) {
311 audio_channel_allocation.bitmask = 0;
312 for (auto [allocation, bitmask] : audio_channel_allocation_map) {
313 if (audio_location & allocation)
314 audio_channel_allocation.bitmask |= bitmask;
315 }
316 }
317
populateConfigurationData(LeAudioAseConfiguration & ase,const flatbuffers::Vector<flatbuffers::Offset<le_audio::CodecSpecificConfiguration>> * flat_codec_specific_params)318 void AudioSetConfigurationProviderJson::populateConfigurationData(
319 LeAudioAseConfiguration& ase,
320 const flatbuffers::Vector<
321 flatbuffers::Offset<le_audio::CodecSpecificConfiguration>>*
322 flat_codec_specific_params) {
323 uint8_t sampling_frequency = 0;
324 uint8_t frame_duration = 0;
325 uint32_t audio_channel_allocation = 0;
326 uint16_t octets_per_codec_frame = 0;
327 uint8_t codec_frames_blocks_per_sdu = 0;
328
329 auto param = LookupCodecSpecificParam(
330 flat_codec_specific_params,
331 le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_SAMPLING_FREQUENCY);
332 if (param) {
333 auto ptr = param->compound_value()->value()->data();
334 STREAM_TO_UINT8(sampling_frequency, ptr);
335 }
336
337 param = LookupCodecSpecificParam(
338 flat_codec_specific_params,
339 le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_FRAME_DURATION);
340 if (param) {
341 auto ptr = param->compound_value()->value()->data();
342 STREAM_TO_UINT8(frame_duration, ptr);
343 }
344
345 param = LookupCodecSpecificParam(
346 flat_codec_specific_params,
347 le_audio::
348 CodecSpecificLtvGenericTypes_SUPPORTED_AUDIO_CHANNEL_ALLOCATION);
349 if (param) {
350 auto ptr = param->compound_value()->value()->data();
351 STREAM_TO_UINT32(audio_channel_allocation, ptr);
352 }
353
354 param = LookupCodecSpecificParam(
355 flat_codec_specific_params,
356 le_audio::CodecSpecificLtvGenericTypes_SUPPORTED_OCTETS_PER_CODEC_FRAME);
357 if (param) {
358 auto ptr = param->compound_value()->value()->data();
359 STREAM_TO_UINT16(octets_per_codec_frame, ptr);
360 }
361
362 param = LookupCodecSpecificParam(
363 flat_codec_specific_params,
364 le_audio::
365 CodecSpecificLtvGenericTypes_SUPPORTED_CODEC_FRAME_BLOCKS_PER_SDU);
366 if (param) {
367 auto ptr = param->compound_value()->value()->data();
368 STREAM_TO_UINT8(codec_frames_blocks_per_sdu, ptr);
369 }
370
371 // Make the correct value
372 ase.codecConfiguration = std::vector<CodecSpecificConfigurationLtv>();
373
374 auto sampling_freq_it = sampling_freq_map.find(sampling_frequency);
375 if (sampling_freq_it != sampling_freq_map.end())
376 ase.codecConfiguration.push_back(sampling_freq_it->second);
377 auto frame_duration_it = frame_duration_map.find(frame_duration);
378 if (frame_duration_it != frame_duration_map.end())
379 ase.codecConfiguration.push_back(frame_duration_it->second);
380
381 CodecSpecificConfigurationLtv::AudioChannelAllocation channel_allocation;
382 populateAudioChannelAllocation(channel_allocation, audio_channel_allocation);
383 ase.codecConfiguration.push_back(channel_allocation);
384
385 auto octet_structure = CodecSpecificConfigurationLtv::OctetsPerCodecFrame();
386 octet_structure.value = octets_per_codec_frame;
387 ase.codecConfiguration.push_back(octet_structure);
388
389 auto frame_sdu_structure =
390 CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU();
391 frame_sdu_structure.value = codec_frames_blocks_per_sdu;
392 ase.codecConfiguration.push_back(frame_sdu_structure);
393 }
394
populateAseConfiguration(LeAudioAseConfiguration & ase,const le_audio::AudioSetSubConfiguration * flat_subconfig,const le_audio::QosConfiguration * qos_cfg,ConfigurationFlags & configurationFlags)395 void AudioSetConfigurationProviderJson::populateAseConfiguration(
396 LeAudioAseConfiguration& ase,
397 const le_audio::AudioSetSubConfiguration* flat_subconfig,
398 const le_audio::QosConfiguration* qos_cfg,
399 ConfigurationFlags& configurationFlags) {
400 // Target latency
401 switch (qos_cfg->target_latency()) {
402 case le_audio::AudioSetConfigurationTargetLatency::
403 AudioSetConfigurationTargetLatency_BALANCED_RELIABILITY:
404 ase.targetLatency =
405 LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
406 break;
407 case le_audio::AudioSetConfigurationTargetLatency::
408 AudioSetConfigurationTargetLatency_HIGH_RELIABILITY:
409 ase.targetLatency =
410 LeAudioAseConfiguration::TargetLatency::HIGHER_RELIABILITY;
411 break;
412 case le_audio::AudioSetConfigurationTargetLatency::
413 AudioSetConfigurationTargetLatency_LOW:
414 ase.targetLatency = LeAudioAseConfiguration::TargetLatency::LOWER;
415 configurationFlags.bitmask |= ConfigurationFlags::LOW_LATENCY;
416 break;
417 default:
418 ase.targetLatency = LeAudioAseConfiguration::TargetLatency::UNDEFINED;
419 break;
420 };
421
422 ase.targetPhy = Phy::TWO_M;
423 // Making CodecId
424 if (flat_subconfig->codec_id()->coding_format() ==
425 (uint8_t)CodecId::Core::LC3) {
426 ase.codecId = CodecId::Core::LC3;
427 } else {
428 auto vendorC = CodecId::Vendor();
429 vendorC.codecId = flat_subconfig->codec_id()->vendor_codec_id();
430 vendorC.id = flat_subconfig->codec_id()->vendor_company_id();
431 ase.codecId = vendorC;
432 }
433 // Codec configuration data
434 populateConfigurationData(ase, flat_subconfig->codec_configuration());
435 }
436
populateAseQosConfiguration(LeAudioAseQosConfiguration & qos,const le_audio::QosConfiguration * qos_cfg,LeAudioAseConfiguration & ase,uint8_t ase_channel_cnt)437 void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
438 LeAudioAseQosConfiguration& qos, const le_audio::QosConfiguration* qos_cfg,
439 LeAudioAseConfiguration& ase, uint8_t ase_channel_cnt) {
440 std::optional<CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU>
441 frameBlock = std::nullopt;
442 std::optional<CodecSpecificConfigurationLtv::FrameDuration> frameDuration =
443 std::nullopt;
444 std::optional<CodecSpecificConfigurationLtv::OctetsPerCodecFrame> octet =
445 std::nullopt;
446
447 // Hack to put back allocation
448 CodecSpecificConfigurationLtv::AudioChannelAllocation allocation =
449 CodecSpecificConfigurationLtv::AudioChannelAllocation();
450 if (ase_channel_cnt == 1) {
451 allocation.bitmask |=
452 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
453
454 } else {
455 allocation.bitmask |=
456 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
457 CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
458 }
459 for (auto& cfg_ltv : ase.codecConfiguration) {
460 auto tag = cfg_ltv.getTag();
461 if (tag == CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU) {
462 frameBlock =
463 cfg_ltv.get<CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU>();
464 } else if (tag == CodecSpecificConfigurationLtv::frameDuration) {
465 frameDuration =
466 cfg_ltv.get<CodecSpecificConfigurationLtv::frameDuration>();
467 } else if (tag == CodecSpecificConfigurationLtv::octetsPerCodecFrame) {
468 octet = cfg_ltv.get<CodecSpecificConfigurationLtv::octetsPerCodecFrame>();
469 } else if (tag == CodecSpecificConfigurationLtv::audioChannelAllocation) {
470 // Change to the old hack allocation
471 cfg_ltv.set<CodecSpecificConfigurationLtv::audioChannelAllocation>(
472 allocation);
473 }
474 }
475
476 int frameBlockValue = 1;
477 if (frameBlock.has_value()) frameBlockValue = frameBlock.value().value;
478
479 // Populate maxSdu
480 if (octet.has_value()) {
481 qos.maxSdu = ase_channel_cnt * octet.value().value * frameBlockValue;
482 }
483 // Populate sduIntervalUs
484 if (frameDuration.has_value()) {
485 switch (frameDuration.value()) {
486 case CodecSpecificConfigurationLtv::FrameDuration::US7500:
487 qos.sduIntervalUs = 7500;
488 break;
489 case CodecSpecificConfigurationLtv::FrameDuration::US10000:
490 qos.sduIntervalUs = 10000;
491 break;
492 case CodecSpecificConfigurationLtv::FrameDuration::US20000:
493 qos.sduIntervalUs = 20000;
494 break;
495 }
496 qos.sduIntervalUs *= frameBlockValue;
497 }
498 qos.maxTransportLatencyMs = qos_cfg->max_transport_latency();
499 qos.retransmissionNum = qos_cfg->retransmission_number();
500 }
501
502 // Parse into AseDirectionConfiguration
503 AseDirectionConfiguration
SetConfigurationFromFlatSubconfig(const le_audio::AudioSetSubConfiguration * flat_subconfig,const le_audio::QosConfiguration * qos_cfg,CodecLocation location,ConfigurationFlags & configurationFlags)504 AudioSetConfigurationProviderJson::SetConfigurationFromFlatSubconfig(
505 const le_audio::AudioSetSubConfiguration* flat_subconfig,
506 const le_audio::QosConfiguration* qos_cfg, CodecLocation location,
507 ConfigurationFlags& configurationFlags) {
508 AseDirectionConfiguration direction_conf;
509
510 LeAudioAseConfiguration ase;
511 LeAudioAseQosConfiguration qos;
512 LeAudioDataPathConfiguration path;
513
514 // Translate into LeAudioAseConfiguration
515 populateAseConfiguration(ase, flat_subconfig, qos_cfg, configurationFlags);
516
517 // Translate into LeAudioAseQosConfiguration
518 populateAseQosConfiguration(qos, qos_cfg, ase,
519 flat_subconfig->ase_channel_cnt());
520
521 // Translate location to data path id
522 switch (location) {
523 case CodecLocation::ADSP:
524 path.isoDataPathConfiguration.isTransparent = true;
525 path.dataPathId = kIsoDataPathPlatformDefault;
526 break;
527 case CodecLocation::HOST:
528 path.isoDataPathConfiguration.isTransparent = true;
529 path.dataPathId = kIsoDataPathHci;
530 break;
531 case CodecLocation::CONTROLLER:
532 path.isoDataPathConfiguration.isTransparent = false;
533 path.dataPathId = kIsoDataPathPlatformDefault;
534 break;
535 }
536 // Move codecId to iso data path
537 path.isoDataPathConfiguration.codecId = ase.codecId.value();
538
539 direction_conf.aseConfiguration = ase;
540 direction_conf.qosConfiguration = qos;
541 direction_conf.dataPathConfiguration = path;
542
543 return direction_conf;
544 }
545
546 // Parse into AseDirectionConfiguration and the ConfigurationFlags
547 // and put them in the given list.
processSubconfig(const le_audio::AudioSetSubConfiguration * subconfig,const le_audio::QosConfiguration * qos_cfg,std::vector<std::optional<AseDirectionConfiguration>> & directionAseConfiguration,CodecLocation location,ConfigurationFlags & configurationFlags)548 void AudioSetConfigurationProviderJson::processSubconfig(
549 const le_audio::AudioSetSubConfiguration* subconfig,
550 const le_audio::QosConfiguration* qos_cfg,
551 std::vector<std::optional<AseDirectionConfiguration>>&
552 directionAseConfiguration,
553 CodecLocation location, ConfigurationFlags& configurationFlags) {
554 auto ase_cnt = subconfig->ase_cnt();
555 auto config = SetConfigurationFromFlatSubconfig(subconfig, qos_cfg, location,
556 configurationFlags);
557 directionAseConfiguration.push_back(config);
558 // Put the same setting again.
559 if (ase_cnt == 2) directionAseConfiguration.push_back(config);
560 }
561
562 // Comparing if 2 AseDirectionConfiguration is equal.
563 // Configuration are copied in, so we can remove some fields for comparison
564 // without affecting the result.
isAseConfigurationEqual(AseDirectionConfiguration cfg_a,AseDirectionConfiguration cfg_b)565 bool isAseConfigurationEqual(AseDirectionConfiguration cfg_a,
566 AseDirectionConfiguration cfg_b) {
567 // Remove unneeded fields when comparing.
568 cfg_a.aseConfiguration.metadata = std::nullopt;
569 cfg_b.aseConfiguration.metadata = std::nullopt;
570 return cfg_a == cfg_b;
571 }
572
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)573 void AudioSetConfigurationProviderJson::PopulateAseConfigurationFromFlat(
574 const le_audio::AudioSetConfiguration* flat_cfg,
575 std::vector<const le_audio::CodecConfiguration*>* codec_cfgs,
576 std::vector<const le_audio::QosConfiguration*>* qos_cfgs,
577 CodecLocation location,
578 std::vector<std::optional<AseDirectionConfiguration>>&
579 sourceAseConfiguration,
580 std::vector<std::optional<AseDirectionConfiguration>>& sinkAseConfiguration,
581 ConfigurationFlags& configurationFlags) {
582 if (flat_cfg == nullptr) {
583 LOG(ERROR) << "flat_cfg cannot be null";
584 return;
585 }
586 std::string codec_config_key = flat_cfg->codec_config_name()->str();
587 auto* qos_config_key_array = flat_cfg->qos_config_name();
588
589 constexpr std::string_view default_qos = "QoS_Config_Balanced_Reliability";
590
591 std::string qos_sink_key(default_qos);
592 std::string qos_source_key(default_qos);
593
594 /* We expect maximum two QoS settings. First for Sink and second for Source
595 */
596 if (qos_config_key_array->size() > 0) {
597 qos_sink_key = qos_config_key_array->Get(0)->str();
598 if (qos_config_key_array->size() > 1) {
599 qos_source_key = qos_config_key_array->Get(1)->str();
600 } else {
601 qos_source_key = qos_sink_key;
602 }
603 }
604
605 LOG(INFO) << "Audio set config " << flat_cfg->name()->c_str()
606 << ": codec config " << codec_config_key.c_str() << ", qos_sink "
607 << qos_sink_key.c_str() << ", qos_source "
608 << qos_source_key.c_str();
609
610 // Find the first qos config that match the name
611 const le_audio::QosConfiguration* qos_sink_cfg = nullptr;
612 for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
613 if ((*i)->name()->str() == qos_sink_key) {
614 qos_sink_cfg = *i;
615 break;
616 }
617 }
618
619 const le_audio::QosConfiguration* qos_source_cfg = nullptr;
620 for (auto i = qos_cfgs->begin(); i != qos_cfgs->end(); ++i) {
621 if ((*i)->name()->str() == qos_source_key) {
622 qos_source_cfg = *i;
623 break;
624 }
625 }
626
627 // First codec_cfg with the same name
628 const le_audio::CodecConfiguration* codec_cfg = nullptr;
629 for (auto i = codec_cfgs->begin(); i != codec_cfgs->end(); ++i) {
630 if ((*i)->name()->str() == codec_config_key) {
631 codec_cfg = *i;
632 break;
633 }
634 }
635
636 // Process each subconfig and put it into the correct list
637 if (codec_cfg != nullptr && codec_cfg->subconfigurations()) {
638 /* Load subconfigurations */
639 for (auto subconfig : *codec_cfg->subconfigurations()) {
640 if (subconfig->direction() == kLeAudioDirectionSink) {
641 processSubconfig(subconfig, qos_sink_cfg, sinkAseConfiguration,
642 location, configurationFlags);
643 } else {
644 processSubconfig(subconfig, qos_source_cfg, sourceAseConfiguration,
645 location, configurationFlags);
646 }
647 }
648
649 // After putting all subconfig, check if it's an asymmetric configuration
650 // and populate information for ConfigurationFlags
651 if (!sinkAseConfiguration.empty() && !sourceAseConfiguration.empty()) {
652 if (sinkAseConfiguration.size() == sourceAseConfiguration.size()) {
653 for (int i = 0; i < sinkAseConfiguration.size(); ++i) {
654 if (sinkAseConfiguration[i].has_value() !=
655 sourceAseConfiguration[i].has_value()) {
656 // Different configuration: one is not empty and other is.
657 configurationFlags.bitmask |=
658 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
659 } else if (sinkAseConfiguration[i].has_value()) {
660 // Both is not empty, comparing inner fields:
661 if (!isAseConfigurationEqual(sinkAseConfiguration[i].value(),
662 sourceAseConfiguration[i].value())) {
663 configurationFlags.bitmask |=
664 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
665 }
666 }
667 }
668 } else {
669 // Different number of ASE, is a different configuration.
670 configurationFlags.bitmask |=
671 ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS;
672 }
673 }
674 } else {
675 if (codec_cfg == nullptr) {
676 LOG(ERROR) << "No codec config matching key " << codec_config_key.c_str()
677 << " found";
678 } else {
679 LOG(ERROR) << "Configuration '" << flat_cfg->name()->c_str()
680 << "' has no valid subconfigurations.";
681 }
682 }
683 }
684
LoadConfigurationsFromFiles(const char * schema_file,const char * content_file,CodecLocation location)685 bool AudioSetConfigurationProviderJson::LoadConfigurationsFromFiles(
686 const char* schema_file, const char* content_file, CodecLocation location) {
687 flatbuffers::Parser configurations_parser_;
688 std::string configurations_schema_binary_content;
689 bool ok = flatbuffers::LoadFile(schema_file, true,
690 &configurations_schema_binary_content);
691 LOG(INFO) << __func__ << ": Loading file " << schema_file;
692 if (!ok) return ok;
693
694 /* Load the binary schema */
695 ok = configurations_parser_.Deserialize(
696 (uint8_t*)configurations_schema_binary_content.c_str(),
697 configurations_schema_binary_content.length());
698 if (!ok) return ok;
699
700 /* Load the content from JSON */
701 std::string configurations_json_content;
702 LOG(INFO) << __func__ << ": Loading file " << content_file;
703 ok = flatbuffers::LoadFile(content_file, false, &configurations_json_content);
704 if (!ok) return ok;
705
706 /* Parse */
707 LOG(INFO) << __func__ << ": Parse JSON content";
708 ok = configurations_parser_.Parse(configurations_json_content.c_str());
709 if (!ok) return ok;
710
711 /* Import from flatbuffers */
712 LOG(INFO) << __func__ << ": Build flat buffer structure";
713 auto configurations_root = le_audio::GetAudioSetConfigurations(
714 configurations_parser_.builder_.GetBufferPointer());
715 if (!configurations_root) return false;
716
717 auto flat_qos_configs = configurations_root->qos_configurations();
718 if ((flat_qos_configs == nullptr) || (flat_qos_configs->size() == 0))
719 return false;
720
721 LOG(DEBUG) << ": Updating " << flat_qos_configs->size()
722 << " qos config entries.";
723 std::vector<const le_audio::QosConfiguration*> qos_cfgs;
724 for (auto const& flat_qos_cfg : *flat_qos_configs) {
725 qos_cfgs.push_back(flat_qos_cfg);
726 }
727
728 auto flat_codec_configs = configurations_root->codec_configurations();
729 if ((flat_codec_configs == nullptr) || (flat_codec_configs->size() == 0))
730 return false;
731
732 LOG(DEBUG) << ": Updating " << flat_codec_configs->size()
733 << " codec config entries.";
734 std::vector<const le_audio::CodecConfiguration*> codec_cfgs;
735 for (auto const& flat_codec_cfg : *flat_codec_configs) {
736 codec_cfgs.push_back(flat_codec_cfg);
737 }
738
739 auto flat_configs = configurations_root->configurations();
740 if ((flat_configs == nullptr) || (flat_configs->size() == 0)) return false;
741
742 LOG(DEBUG) << ": Updating " << flat_configs->size() << " config entries.";
743 for (auto const& flat_cfg : *flat_configs) {
744 // Create 3 vector to use
745 std::vector<std::optional<AseDirectionConfiguration>>
746 sourceAseConfiguration;
747 std::vector<std::optional<AseDirectionConfiguration>> sinkAseConfiguration;
748 ConfigurationFlags configurationFlags;
749 PopulateAseConfigurationFromFlat(flat_cfg, &codec_cfgs, &qos_cfgs, location,
750 sourceAseConfiguration,
751 sinkAseConfiguration, configurationFlags);
752 if (sourceAseConfiguration.empty() && sinkAseConfiguration.empty())
753 continue;
754 configurations_[flat_cfg->name()->str()] = std::make_tuple(
755 sourceAseConfiguration, sinkAseConfiguration, configurationFlags);
756 }
757
758 return true;
759 }
760
LoadScenariosFromFiles(const char * schema_file,const char * content_file)761 bool AudioSetConfigurationProviderJson::LoadScenariosFromFiles(
762 const char* schema_file, const char* content_file) {
763 flatbuffers::Parser scenarios_parser_;
764 std::string scenarios_schema_binary_content;
765 bool ok = flatbuffers::LoadFile(schema_file, true,
766 &scenarios_schema_binary_content);
767 LOG(INFO) << __func__ << ": Loading file " << schema_file;
768 if (!ok) return ok;
769
770 /* Load the binary schema */
771 ok = scenarios_parser_.Deserialize(
772 (uint8_t*)scenarios_schema_binary_content.c_str(),
773 scenarios_schema_binary_content.length());
774 if (!ok) return ok;
775
776 /* Load the content from JSON */
777 LOG(INFO) << __func__ << ": Loading file " << content_file;
778 std::string scenarios_json_content;
779 ok = flatbuffers::LoadFile(content_file, false, &scenarios_json_content);
780 if (!ok) return ok;
781
782 /* Parse */
783 LOG(INFO) << __func__ << ": Parse json content";
784 ok = scenarios_parser_.Parse(scenarios_json_content.c_str());
785 if (!ok) return ok;
786
787 /* Import from flatbuffers */
788 LOG(INFO) << __func__ << ": Build flat buffer structure";
789 auto scenarios_root = le_audio::GetAudioSetScenarios(
790 scenarios_parser_.builder_.GetBufferPointer());
791 if (!scenarios_root) return false;
792
793 auto flat_scenarios = scenarios_root->scenarios();
794 if ((flat_scenarios == nullptr) || (flat_scenarios->size() == 0))
795 return false;
796
797 LOG(INFO) << __func__ << ": Turn flat buffer into structure";
798 AudioContext media_context = AudioContext();
799 media_context.bitmask =
800 (AudioContext::ALERTS | AudioContext::INSTRUCTIONAL |
801 AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM |
802 AudioContext::UNSPECIFIED | AudioContext::MEDIA |
803 AudioContext::SOUND_EFFECTS);
804
805 AudioContext conversational_context = AudioContext();
806 conversational_context.bitmask =
807 (AudioContext::RINGTONE_ALERTS | AudioContext::CONVERSATIONAL);
808
809 AudioContext live_context = AudioContext();
810 live_context.bitmask = AudioContext::LIVE_AUDIO;
811
812 AudioContext game_context = AudioContext();
813 game_context.bitmask = AudioContext::GAME;
814
815 AudioContext voice_assistants_context = AudioContext();
816 voice_assistants_context.bitmask = AudioContext::VOICE_ASSISTANTS;
817
818 LOG(DEBUG) << "Updating " << flat_scenarios->size() << " scenarios.";
819 for (auto const& scenario : *flat_scenarios) {
820 if (!scenario->configurations()) continue;
821 std::string scenario_name = scenario->name()->c_str();
822 AudioContext context;
823 if (scenario_name == "Media")
824 context = AudioContext(media_context);
825 else if (scenario_name == "Conversational")
826 context = AudioContext(conversational_context);
827 else if (scenario_name == "Live")
828 context = AudioContext(live_context);
829 else if (scenario_name == "Game")
830 context = AudioContext(game_context);
831 else if (scenario_name == "VoiceAssistants")
832 context = AudioContext(voice_assistants_context);
833 LOG(DEBUG) << "Scenario " << scenario->name()->c_str()
834 << " configs: " << scenario->configurations()->size()
835 << " context: " << context.toString();
836
837 for (auto it = scenario->configurations()->begin();
838 it != scenario->configurations()->end(); ++it) {
839 auto config_name = it->str();
840 auto configuration = configurations_.find(config_name);
841 if (configuration == configurations_.end()) continue;
842 LOG(DEBUG) << "Getting configuration with name: " << config_name;
843 auto [source, sink, flags] = configuration->second;
844 // Each configuration will create a LeAudioAseConfigurationSetting
845 // with the same {context, packing}
846 // and different data
847 LeAudioAseConfigurationSetting setting;
848 setting.audioContext = context;
849 // TODO: Packing
850 setting.sourceAseConfiguration = source;
851 setting.sinkAseConfiguration = sink;
852 setting.flags = flags;
853 // Add to list of setting
854 LOG(DEBUG) << "Pushing configuration to list: " << config_name;
855 ase_configuration_settings_.push_back({config_name, setting});
856 }
857 }
858
859 return true;
860 }
861
LoadContent(std::vector<std::pair<const char *,const char * >> config_files,std::vector<std::pair<const char *,const char * >> scenario_files,CodecLocation location)862 bool AudioSetConfigurationProviderJson::LoadContent(
863 std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
864 config_files,
865 std::vector<std::pair<const char* /*schema*/, const char* /*content*/>>
866 scenario_files,
867 CodecLocation location) {
868 bool is_loaded_config = false;
869 for (auto [schema, content] : config_files) {
870 if (LoadConfigurationsFromFiles(schema, content, location)) {
871 is_loaded_config = true;
872 break;
873 }
874 }
875
876 bool is_loaded_scenario = false;
877 for (auto [schema, content] : scenario_files) {
878 if (LoadScenariosFromFiles(schema, content)) {
879 is_loaded_scenario = true;
880 break;
881 }
882 }
883 return is_loaded_config && is_loaded_scenario;
884 }
885
886 } // namespace audio
887 } // namespace bluetooth
888 } // namespace hardware
889 } // namespace android
890 } // namespace aidl
891