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