1 /*
2 * Copyright 2022 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 #include "le_audio_utils.h"
18
19 #include <bluetooth/log.h>
20
21 #include <cstdint>
22 #include <sstream>
23 #include <string>
24 #include <type_traits>
25 #include <vector>
26
27 #include "audio_hal_client/audio_hal_client.h"
28 #include "common/strings.h"
29 #include "hardware/bt_le_audio.h"
30 #include "le_audio/codec_manager.h"
31 #include "le_audio_types.h"
32
33 using bluetooth::common::ToString;
34 using bluetooth::le_audio::types::AudioContexts;
35 using bluetooth::le_audio::types::LeAudioContextType;
36
37 namespace std {
38 template <>
39 struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
40 template <>
41 struct formatter<audio_content_type_t> : enum_formatter<audio_content_type_t> {};
42 template <>
43 struct formatter<audio_source_t> : enum_formatter<audio_source_t> {};
44 template <>
45 struct formatter<audio_devices_t> : enum_formatter<audio_devices_t> {};
46 } // namespace std
47
48 namespace bluetooth::le_audio {
49 namespace utils {
50
51 /* The returned LeAudioContextType should have its entry in the
52 * AudioSetConfigurationProvider's ContextTypeToScenario mapping table.
53 * Otherwise the AudioSetConfigurationProvider will fall back
54 * to default scenario.
55 */
AudioContentToLeAudioContext(audio_content_type_t content_type,audio_usage_t usage)56 LeAudioContextType AudioContentToLeAudioContext(audio_content_type_t content_type,
57 audio_usage_t usage) {
58 /* Check audio attribute usage of stream */
59 switch (usage) {
60 case AUDIO_USAGE_MEDIA:
61 return LeAudioContextType::MEDIA;
62 case AUDIO_USAGE_ASSISTANT:
63 return LeAudioContextType::VOICEASSISTANTS;
64 case AUDIO_USAGE_VOICE_COMMUNICATION:
65 case AUDIO_USAGE_CALL_ASSISTANT:
66 return LeAudioContextType::CONVERSATIONAL;
67 case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
68 if (content_type == AUDIO_CONTENT_TYPE_SPEECH) {
69 return LeAudioContextType::CONVERSATIONAL;
70 }
71
72 if (content_type == AUDIO_CONTENT_TYPE_SONIFICATION) {
73 return LeAudioContextType::RINGTONE;
74 }
75
76 return LeAudioContextType::SOUNDEFFECTS;
77 case AUDIO_USAGE_GAME:
78 return LeAudioContextType::GAME;
79 case AUDIO_USAGE_NOTIFICATION:
80 return LeAudioContextType::NOTIFICATIONS;
81 case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
82 return LeAudioContextType::RINGTONE;
83 case AUDIO_USAGE_ALARM:
84 return LeAudioContextType::ALERTS;
85 case AUDIO_USAGE_EMERGENCY:
86 return LeAudioContextType::EMERGENCYALARM;
87 case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
88 return LeAudioContextType::INSTRUCTIONAL;
89 case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
90 return LeAudioContextType::SOUNDEFFECTS;
91 default:
92 break;
93 }
94
95 return LeAudioContextType::MEDIA;
96 }
97
usageToString(audio_usage_t usage)98 static std::string usageToString(audio_usage_t usage) {
99 switch (usage) {
100 case AUDIO_USAGE_UNKNOWN:
101 return "USAGE_UNKNOWN";
102 case AUDIO_USAGE_MEDIA:
103 return "USAGE_MEDIA";
104 case AUDIO_USAGE_VOICE_COMMUNICATION:
105 return "USAGE_VOICE_COMMUNICATION";
106 case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
107 return "USAGE_VOICE_COMMUNICATION_SIGNALLING";
108 case AUDIO_USAGE_ALARM:
109 return "USAGE_ALARM";
110 case AUDIO_USAGE_NOTIFICATION:
111 return "USAGE_NOTIFICATION";
112 case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
113 return "USAGE_NOTIFICATION_TELEPHONY_RINGTONE";
114 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
115 return "USAGE_NOTIFICATION_COMMUNICATION_REQUEST";
116 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
117 return "USAGE_NOTIFICATION_COMMUNICATION_INSTANT";
118 case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
119 return "USAGE_NOTIFICATION_COMMUNICATION_DELAYED";
120 case AUDIO_USAGE_NOTIFICATION_EVENT:
121 return "USAGE_NOTIFICATION_EVENT";
122 case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
123 return "USAGE_ASSISTANCE_ACCESSIBILITY";
124 case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
125 return "USAGE_ASSISTANCE_NAVIGATION_GUIDANCE";
126 case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
127 return "USAGE_ASSISTANCE_SONIFICATION";
128 case AUDIO_USAGE_GAME:
129 return "USAGE_GAME";
130 case AUDIO_USAGE_ASSISTANT:
131 return "USAGE_ASSISTANT";
132 case AUDIO_USAGE_CALL_ASSISTANT:
133 return "USAGE_CALL_ASSISTANT";
134 case AUDIO_USAGE_EMERGENCY:
135 return "USAGE_EMERGENCY";
136 case AUDIO_USAGE_SAFETY:
137 return "USAGE_SAFETY";
138 case AUDIO_USAGE_VEHICLE_STATUS:
139 return "USAGE_VEHICLE_STATUS";
140 case AUDIO_USAGE_ANNOUNCEMENT:
141 return "USAGE_ANNOUNCEMENT";
142 default:
143 return "unknown usage ";
144 }
145 }
146
contentTypeToString(audio_content_type_t content_type)147 static std::string contentTypeToString(audio_content_type_t content_type) {
148 switch (content_type) {
149 case AUDIO_CONTENT_TYPE_UNKNOWN:
150 return "CONTENT_TYPE_UNKNOWN";
151 case AUDIO_CONTENT_TYPE_SPEECH:
152 return "CONTENT_TYPE_SPEECH";
153 case AUDIO_CONTENT_TYPE_MUSIC:
154 return "CONTENT_TYPE_MUSIC";
155 case AUDIO_CONTENT_TYPE_MOVIE:
156 return "CONTENT_TYPE_MOVIE";
157 case AUDIO_CONTENT_TYPE_SONIFICATION:
158 return "CONTENT_TYPE_SONIFICATION";
159 default:
160 return "unknown content type ";
161 }
162 }
163
audioSourceToStr(audio_source_t source)164 static const char* audioSourceToStr(audio_source_t source) {
165 const char* strArr[] = {"AUDIO_SOURCE_DEFAULT", "AUDIO_SOURCE_MIC",
166 "AUDIO_SOURCE_VOICE_UPLINK", "AUDIO_SOURCE_VOICE_DOWNLINK",
167 "AUDIO_SOURCE_VOICE_CALL", "AUDIO_SOURCE_CAMCORDER",
168 "AUDIO_SOURCE_VOICE_RECOGNITION", "AUDIO_SOURCE_VOICE_COMMUNICATION",
169 "AUDIO_SOURCE_REMOTE_SUBMIX", "AUDIO_SOURCE_UNPROCESSED",
170 "AUDIO_SOURCE_VOICE_PERFORMANCE"};
171
172 if (static_cast<uint32_t>(source) < (sizeof(strArr) / sizeof(strArr[0]))) {
173 return strArr[source];
174 }
175 return "UNKNOWN";
176 }
177
isMetadataTagPresent(const char * tags,const char * tag)178 static bool isMetadataTagPresent(const char* tags, const char* tag) {
179 std::istringstream iss(tags);
180 std::string t;
181 while (std::getline(iss, t, AUDIO_ATTRIBUTES_TAGS_SEPARATOR)) {
182 log::verbose("Tag {}", t);
183 if (t.compare(tag) == 0) {
184 return true;
185 }
186 }
187 return false;
188 }
189
GetAudioContextsFromSourceMetadata(const std::vector<struct playback_track_metadata_v7> & source_metadata)190 AudioContexts GetAudioContextsFromSourceMetadata(
191 const std::vector<struct playback_track_metadata_v7>& source_metadata) {
192 AudioContexts track_contexts;
193 for (const auto& entry : source_metadata) {
194 auto track = entry.base;
195 if (track.content_type == 0 && track.usage == 0) {
196 continue;
197 }
198
199 log::info("usage={}({}), content_type={}({}), gain={:f}, tag:{}", usageToString(track.usage),
200 track.usage, contentTypeToString(track.content_type), track.content_type, track.gain,
201 entry.tags);
202
203 if (isMetadataTagPresent(entry.tags, "VX_AOSP_SAMPLESOUND")) {
204 track_contexts.set(LeAudioContextType::SOUNDEFFECTS);
205 } else {
206 track_contexts.set(AudioContentToLeAudioContext(track.content_type, track.usage));
207 }
208 }
209 return track_contexts;
210 }
211
GetAudioContextsFromSinkMetadata(const std::vector<struct record_track_metadata_v7> & sink_metadata)212 AudioContexts GetAudioContextsFromSinkMetadata(
213 const std::vector<struct record_track_metadata_v7>& sink_metadata) {
214 AudioContexts all_track_contexts;
215
216 for (const auto& entry : sink_metadata) {
217 auto track = entry.base;
218 if (track.source == AUDIO_SOURCE_INVALID) {
219 continue;
220 }
221 LeAudioContextType track_context;
222
223 log::debug(
224 "source={}(0x{:02x}), gain={:f}, destination device=0x{:08x}, "
225 "destination device address={:32s}",
226 audioSourceToStr(track.source), track.source, track.gain, track.dest_device,
227 track.dest_device_address);
228
229 if (track.source == AUDIO_SOURCE_MIC) {
230 track_context = LeAudioContextType::LIVE;
231
232 } else if (track.source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
233 track_context = LeAudioContextType::CONVERSATIONAL;
234
235 } else {
236 /* Fallback to voice assistant
237 * This will handle also a case when the device is
238 * AUDIO_SOURCE_VOICE_RECOGNITION
239 */
240 track_context = LeAudioContextType::VOICEASSISTANTS;
241 log::warn(
242 "Could not match the recording track type to group available "
243 "context. Using context {}.",
244 ToString(track_context));
245 }
246
247 all_track_contexts.set(track_context);
248 }
249
250 log::info("Allowed contexts from sink metadata: {} (0x{:08x})",
251 bluetooth::common::ToString(all_track_contexts), all_track_contexts.value());
252 return all_track_contexts;
253 }
254
translateBluetoothCodecFormatToCodecType(uint8_t codec_format)255 bluetooth::le_audio::btle_audio_codec_index_t translateBluetoothCodecFormatToCodecType(
256 uint8_t codec_format) {
257 switch (codec_format) {
258 case types::kLeAudioCodingFormatLC3:
259 return bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3;
260 }
261 return bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_INVALID;
262 }
263
translateToBtLeAudioCodecConfigSampleRate(uint32_t sample_rate)264 bluetooth::le_audio::btle_audio_sample_rate_index_t translateToBtLeAudioCodecConfigSampleRate(
265 uint32_t sample_rate) {
266 log::info("{}", sample_rate);
267 switch (sample_rate) {
268 case LeAudioCodecConfiguration::kSampleRate8000:
269 return LE_AUDIO_SAMPLE_RATE_INDEX_8000HZ;
270 case LeAudioCodecConfiguration::kSampleRate16000:
271 return LE_AUDIO_SAMPLE_RATE_INDEX_16000HZ;
272 case LeAudioCodecConfiguration::kSampleRate24000:
273 return LE_AUDIO_SAMPLE_RATE_INDEX_24000HZ;
274 case LeAudioCodecConfiguration::kSampleRate32000:
275 return LE_AUDIO_SAMPLE_RATE_INDEX_32000HZ;
276 case LeAudioCodecConfiguration::kSampleRate44100:
277 return LE_AUDIO_SAMPLE_RATE_INDEX_44100HZ;
278 case LeAudioCodecConfiguration::kSampleRate48000:
279 return LE_AUDIO_SAMPLE_RATE_INDEX_48000HZ;
280 }
281
282 return LE_AUDIO_SAMPLE_RATE_INDEX_NONE;
283 }
284
translateToBtLeAudioCodecConfigBitPerSample(uint8_t bits_per_sample)285 bluetooth::le_audio::btle_audio_bits_per_sample_index_t translateToBtLeAudioCodecConfigBitPerSample(
286 uint8_t bits_per_sample) {
287 switch (bits_per_sample) {
288 case 16:
289 return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_16;
290 case 24:
291 return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_24;
292 case 32:
293 return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_32;
294 }
295 return bluetooth::le_audio::LE_AUDIO_BITS_PER_SAMPLE_INDEX_NONE;
296 }
297
translateToBtLeAudioCodecConfigChannelCount(uint8_t channel_count)298 bluetooth::le_audio::btle_audio_channel_count_index_t translateToBtLeAudioCodecConfigChannelCount(
299 uint8_t channel_count) {
300 switch (channel_count) {
301 case 1:
302 return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_1;
303 case 2:
304 return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_2;
305 }
306 return bluetooth::le_audio::LE_AUDIO_CHANNEL_COUNT_INDEX_NONE;
307 }
308
translateToBtLeAudioCodecConfigFrameDuration(int frame_duration)309 bluetooth::le_audio::btle_audio_frame_duration_index_t translateToBtLeAudioCodecConfigFrameDuration(
310 int frame_duration) {
311 switch (frame_duration) {
312 case 7500:
313 return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_7500US;
314 case 10000:
315 return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_10000US;
316 }
317 return bluetooth::le_audio::LE_AUDIO_FRAME_DURATION_INDEX_NONE;
318 }
319
fillStreamParamsToBtLeAudioCodecConfig(const std::vector<struct types::AseConfiguration> & confs,bluetooth::le_audio::btle_audio_codec_config_t & out_config)320 void fillStreamParamsToBtLeAudioCodecConfig(
321 const std::vector<struct types::AseConfiguration>& confs,
322 bluetooth::le_audio::btle_audio_codec_config_t& out_config) {
323 if (confs.size() == 0) {
324 log::warn("Stream params are null");
325 return;
326 }
327
328 auto config = confs.at(0).codec;
329
330 out_config.codec_type = translateBluetoothCodecFormatToCodecType(config.id.coding_format);
331 if (out_config.codec_type != bluetooth::le_audio::LE_AUDIO_CODEC_INDEX_SOURCE_LC3) {
332 return;
333 }
334
335 out_config.sample_rate =
336 translateToBtLeAudioCodecConfigSampleRate(config.GetSamplingFrequencyHz());
337 out_config.bits_per_sample =
338 translateToBtLeAudioCodecConfigBitPerSample(config.GetBitsPerSample());
339 out_config.frame_duration =
340 translateToBtLeAudioCodecConfigFrameDuration(config.GetDataIntervalUs());
341 out_config.octets_per_frame = config.GetOctetsPerFrame();
342 out_config.channel_count =
343 translateToBtLeAudioCodecConfigChannelCount(config.GetChannelCountPerIsoStream());
344 }
345
is_known_codec(const types::LeAudioCodecId & codec_id)346 static bool is_known_codec(const types::LeAudioCodecId& codec_id) {
347 switch (codec_id.coding_format) {
348 case types::kLeAudioCodingFormatLC3:
349 return true;
350 }
351 return false;
352 }
353
fillRemotePacsCapabilitiesToBtLeAudioCodecConfig(const struct types::acs_ac_record & record,std::vector<bluetooth::le_audio::btle_audio_codec_config_t> & vec)354 static void fillRemotePacsCapabilitiesToBtLeAudioCodecConfig(
355 const struct types::acs_ac_record& record,
356 std::vector<bluetooth::le_audio::btle_audio_codec_config_t>& vec) {
357 if (!utils::IsCodecUsingLtvFormat(record.codec_id)) {
358 log::warn(
359 "Unknown codec capability format. Unable to report known codec "
360 "parameters.");
361 return;
362 }
363 log::assert_that(!record.codec_spec_caps.IsEmpty(),
364 "Codec specific capabilities are not parsed appropriately.");
365
366 const struct types::LeAudioCoreCodecCapabilities capa =
367 record.codec_spec_caps.GetAsCoreCodecCapabilities();
368 for (uint8_t freq_bit = codec_spec_conf::kLeAudioSamplingFreq8000Hz;
369 freq_bit <= codec_spec_conf::kLeAudioSamplingFreq384000Hz; freq_bit++) {
370 if (!capa.IsSamplingFrequencyConfigSupported(freq_bit)) {
371 continue;
372 }
373 for (uint8_t fd_bit = codec_spec_conf::kLeAudioCodecFrameDur7500us;
374 fd_bit <= codec_spec_conf::kLeAudioCodecFrameDur10000us; fd_bit++) {
375 if (!capa.IsFrameDurationConfigSupported(fd_bit)) {
376 continue;
377 }
378 if (!capa.HasSupportedAudioChannelCounts()) {
379 bluetooth::le_audio::btle_audio_codec_config_t config = {
380 .codec_type = utils::translateBluetoothCodecFormatToCodecType(
381 record.codec_id.coding_format),
382 .sample_rate = utils::translateToBtLeAudioCodecConfigSampleRate(
383 types::LeAudioCoreCodecConfig::GetSamplingFrequencyHz(freq_bit)),
384 .bits_per_sample = utils::translateToBtLeAudioCodecConfigBitPerSample(16),
385 .channel_count = utils::translateToBtLeAudioCodecConfigChannelCount(1),
386 .frame_duration = utils::translateToBtLeAudioCodecConfigFrameDuration(
387 types::LeAudioCoreCodecConfig::GetFrameDurationUs(fd_bit)),
388 };
389 vec.push_back(config);
390 } else {
391 for (int chan_bit = 1; chan_bit <= 2; chan_bit++) {
392 if (!capa.IsAudioChannelCountsSupported(chan_bit)) {
393 continue;
394 }
395
396 bluetooth::le_audio::btle_audio_codec_config_t config = {
397 .codec_type = utils::translateBluetoothCodecFormatToCodecType(
398 record.codec_id.coding_format),
399 .sample_rate = utils::translateToBtLeAudioCodecConfigSampleRate(
400 types::LeAudioCoreCodecConfig::GetSamplingFrequencyHz(freq_bit)),
401 .bits_per_sample = utils::translateToBtLeAudioCodecConfigBitPerSample(16),
402 .channel_count = utils::translateToBtLeAudioCodecConfigChannelCount(chan_bit),
403 .frame_duration = utils::translateToBtLeAudioCodecConfigFrameDuration(
404 types::LeAudioCoreCodecConfig::GetFrameDurationUs(fd_bit)),
405 };
406 vec.push_back(config);
407 }
408 }
409 }
410 }
411 }
412
GetRemoteBtLeAudioCodecConfigFromPac(const types::PublishedAudioCapabilities & group_pacs)413 std::vector<bluetooth::le_audio::btle_audio_codec_config_t> GetRemoteBtLeAudioCodecConfigFromPac(
414 const types::PublishedAudioCapabilities& group_pacs) {
415 std::vector<bluetooth::le_audio::btle_audio_codec_config_t> vec;
416
417 for (auto& [handles, pacs_record] : group_pacs) {
418 for (auto& pac : pacs_record) {
419 if (!is_known_codec(pac.codec_id)) {
420 continue;
421 }
422
423 fillRemotePacsCapabilitiesToBtLeAudioCodecConfig(pac, vec);
424 }
425 }
426 return vec;
427 }
428
IsCodecUsingLtvFormat(const types::LeAudioCodecId & codec_id)429 bool IsCodecUsingLtvFormat(const types::LeAudioCodecId& codec_id) {
430 if (codec_id == types::LeAudioCodecIdLc3) {
431 return true;
432 }
433 return false;
434 }
435
436 ::bluetooth::le_audio::LeAudioCodecConfiguration
GetAudioSessionCodecConfigFromAudioSetConfiguration(const bluetooth::le_audio::types::AudioSetConfiguration & audio_set_conf,uint8_t remote_direction)437 GetAudioSessionCodecConfigFromAudioSetConfiguration(
438 const bluetooth::le_audio::types::AudioSetConfiguration& audio_set_conf,
439 uint8_t remote_direction) {
440 /* Note: For now we expect that each ASE in a particular direction needs
441 * exactly the same audio codec parameters.
442 */
443
444 LeAudioCodecConfiguration group_config = {0, 0, 0, 0};
445 for (const auto& conf : audio_set_conf.confs.get(remote_direction)) {
446 if (group_config.sample_rate != 0 &&
447 conf.codec.GetSamplingFrequencyHz() != group_config.sample_rate) {
448 log::warn(
449 "Stream configuration could not be determined (multiple, different "
450 "sampling frequencies) for remote_direction: {:#x}",
451 remote_direction);
452 break;
453 }
454 group_config.sample_rate = conf.codec.GetSamplingFrequencyHz();
455
456 if (group_config.data_interval_us != 0 &&
457 conf.codec.GetDataIntervalUs() != group_config.data_interval_us) {
458 log::warn(
459 "Stream configuration could not be determined (multiple, different "
460 "data intervals) for remote_direction: {:#x}",
461 remote_direction);
462 break;
463 }
464 group_config.data_interval_us = conf.codec.GetDataIntervalUs();
465
466 if (group_config.bits_per_sample != 0 &&
467 conf.codec.GetBitsPerSample() != group_config.bits_per_sample) {
468 log::warn(
469 "Stream configuration could not be determined (multiple, different "
470 "bits per sample) for remote_direction: {:#x}",
471 remote_direction);
472 break;
473 }
474 group_config.bits_per_sample = conf.codec.GetBitsPerSample();
475 group_config.num_channels += conf.codec.GetChannelCountPerIsoStream();
476 }
477 if (group_config.num_channels > 2) {
478 group_config.num_channels = 2;
479 }
480
481 return group_config;
482 }
483
GetStrategyForAseConfig(const std::vector<le_audio::types::AseConfiguration> & cfgs,uint8_t device_cnt)484 types::LeAudioConfigurationStrategy GetStrategyForAseConfig(
485 const std::vector<le_audio::types::AseConfiguration>& cfgs, uint8_t device_cnt) {
486 if (cfgs.size() == 0) {
487 return types::LeAudioConfigurationStrategy::RFU;
488 }
489
490 /* Banded headphones or the Classic TWS style topology (a single device) */
491 if (device_cnt == 1) {
492 if (cfgs.at(0).codec.GetChannelCountPerIsoStream() == 1) {
493 /* One mono ASE - could be a single channel microphone */
494 if (cfgs.size() == 1) {
495 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
496 }
497
498 /* Each channel on a dedicated ASE - TWS style split channel re-routing */
499 return types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE;
500 }
501
502 /* Banded headphones with 1 ASE - requires two channels per CIS */
503 return types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE;
504 }
505
506 // We need at least 2 ASEs in the group config to set up more than one device
507 if (cfgs.size() == 1) {
508 return types::LeAudioConfigurationStrategy::RFU;
509 }
510
511 /* The common one channel per device topology */
512 return types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE;
513 }
514
IsCodecConfigSupported(const types::LeAudioLtvMap & pacs,const types::LeAudioLtvMap & reqs,uint8_t channel_cnt_per_ase)515 static bool IsCodecConfigSupported(const types::LeAudioLtvMap& pacs,
516 const types::LeAudioLtvMap& reqs, uint8_t channel_cnt_per_ase) {
517 auto caps = pacs.GetAsCoreCodecCapabilities();
518 auto config = reqs.GetAsCoreCodecConfig();
519
520 /* Sampling frequency */
521 if (!caps.HasSupportedSamplingFrequencies() || !config.sampling_frequency) {
522 log::debug("Missing supported sampling frequencies capability");
523 return false;
524 }
525 if (!caps.IsSamplingFrequencyConfigSupported(config.sampling_frequency.value())) {
526 log::debug("Cfg: SamplingFrequency= {:#x}", config.sampling_frequency.value());
527 log::debug("Cap: SupportedSamplingFrequencies= {:#x}",
528 caps.supported_sampling_frequencies.value());
529 log::debug("Sampling frequency not supported");
530 return false;
531 }
532
533 /* Channel counts */
534 if (!caps.IsAudioChannelCountsSupported(channel_cnt_per_ase)) {
535 log::debug("Cfg: Allocated channel count= {:#x}", channel_cnt_per_ase);
536 log::debug("Cap: Supported channel counts= {:#x}",
537 caps.supported_audio_channel_counts.value_or(1));
538 log::debug("Channel count not supported");
539 return false;
540 }
541
542 /* Frame duration */
543 if (!caps.HasSupportedFrameDurations() || !config.frame_duration) {
544 log::debug("Missing supported frame durations capability");
545 return false;
546 }
547 if (!caps.IsFrameDurationConfigSupported(config.frame_duration.value())) {
548 log::debug("Cfg: FrameDuration= {:#x}", config.frame_duration.value());
549 log::debug("Cap: SupportedFrameDurations= {:#x}", caps.supported_frame_durations.value());
550 log::debug("Frame duration not supported");
551 return false;
552 }
553
554 /* Octets per frame */
555 if (!caps.HasSupportedOctetsPerCodecFrame() || !config.octets_per_codec_frame) {
556 log::debug("Missing supported octets per codec frame");
557 return false;
558 }
559 if (!caps.IsOctetsPerCodecFrameConfigSupported(config.octets_per_codec_frame.value())) {
560 log::debug("Cfg: Octets per frame={}", config.octets_per_codec_frame.value());
561 log::debug("Cap: Min octets per frame={}", caps.supported_min_octets_per_codec_frame.value());
562 log::debug("Cap: Max octets per frame={}", caps.supported_max_octets_per_codec_frame.value());
563 log::debug("Octets per codec frame outside the capabilities");
564 return false;
565 }
566
567 return true;
568 }
569
IsCodecConfigSettingSupported(const types::acs_ac_record & pac,const types::CodecConfigSetting & codec_config_setting)570 static bool IsCodecConfigSettingSupported(const types::acs_ac_record& pac,
571 const types::CodecConfigSetting& codec_config_setting) {
572 const auto& codec_id = codec_config_setting.id;
573 if (codec_id != pac.codec_id) {
574 return false;
575 }
576
577 log::debug("Verifying coding format: {:#02x} ", codec_id.coding_format);
578
579 if (utils::IsCodecUsingLtvFormat(codec_id)) {
580 log::assert_that(!pac.codec_spec_caps.IsEmpty(),
581 "Codec specific capabilities are not parsed appropriately.");
582 return IsCodecConfigSupported(pac.codec_spec_caps, codec_config_setting.params,
583 codec_config_setting.GetChannelCountPerIsoStream());
584 }
585
586 log::error("Codec {}, seems to be not supported here.", bluetooth::common::ToString(codec_id));
587 return false;
588 }
589
GetConfigurationSupportedPac(const types::PublishedAudioCapabilities & pacs,const types::CodecConfigSetting & codec_config_setting)590 const struct types::acs_ac_record* GetConfigurationSupportedPac(
591 const types::PublishedAudioCapabilities& pacs,
592 const types::CodecConfigSetting& codec_config_setting) {
593 for (const auto& pac_tuple : pacs) {
594 for (const auto& pac : std::get<1>(pac_tuple)) {
595 if (utils::IsCodecConfigSettingSupported(pac, codec_config_setting)) {
596 return &pac;
597 }
598 };
599 }
600 /* Doesn't match required configuration with any PAC */
601 if (pacs.size() == 0) {
602 log::error("No PAC records");
603 } else {
604 log::error("No matching PAC record");
605 }
606 return nullptr;
607 }
608
IsAseConfigMatchedWithPreferredRequirements(const std::vector<struct types::AseConfiguration> & ase_confs,const std::vector<CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements> & reqs,uint8_t channel_cnt_per_ase)609 bool IsAseConfigMatchedWithPreferredRequirements(
610 const std::vector<struct types::AseConfiguration>& ase_confs,
611 const std::vector<
612 CodecManager::UnicastConfigurationRequirements::DeviceDirectionRequirements>& reqs,
613 uint8_t channel_cnt_per_ase) {
614 if (ase_confs.empty() || reqs.empty() || ase_confs.size() != reqs.size()) {
615 return false;
616 }
617
618 for (auto i = 0; i < static_cast<int>(ase_confs.size()); ++i) {
619 const auto& ase_config = ase_confs.at(i).codec.params.GetAsCoreCodecConfig();
620 const auto& req_config = reqs.at(i).params.GetAsCoreCodecConfig();
621
622 /* Sampling frequency */
623 if (!ase_config.sampling_frequency || !req_config.sampling_frequency) {
624 log::debug("Missing sampling frequencies capability");
625 return false;
626 }
627 if (ase_config.sampling_frequency.value() != req_config.sampling_frequency.value()) {
628 log::debug("Ase cfg: SamplingFrequency= {:#x}", ase_config.sampling_frequency.value());
629 log::debug("Req cfg: SamplingFrequency= {:#x}", req_config.sampling_frequency.value());
630 log::debug("Sampling frequency not supported");
631 return false;
632 }
633
634 /* Channel counts */
635 if (ase_confs.at(i).codec.GetChannelCountPerIsoStream() != channel_cnt_per_ase) {
636 log::debug("Ase cfg: Allocated channel count= {:#x}",
637 ase_confs.at(i).codec.GetChannelCountPerIsoStream());
638 log::debug("Req cfg: Allocated channel counts= {:#x}", channel_cnt_per_ase);
639 log::debug("Channel count not supported");
640 return false;
641 }
642
643 /* Frame duration */
644 if (!ase_config.frame_duration || !req_config.frame_duration) {
645 log::debug("Missing frame duration capability");
646 return false;
647 }
648 if (ase_config.frame_duration.value() != ase_config.frame_duration.value()) {
649 log::debug("Ase cfg: FrameDuration= {:#x}", ase_config.frame_duration.value());
650 log::debug("Req cfg: FrameDuration= {:#x}", req_config.frame_duration.value());
651 log::debug("Frame duration not supported");
652 return false;
653 }
654
655 /* Octets per frame */
656 if (!ase_config.octets_per_codec_frame || !req_config.octets_per_codec_frame) {
657 log::debug("Missing octets per codec frame");
658 return false;
659 }
660 if (ase_config.octets_per_codec_frame.value() != req_config.octets_per_codec_frame.value()) {
661 log::debug("Ase cfg: Octets per frame={}", ase_config.octets_per_codec_frame.value());
662 log::debug("Req cfg: Octets per frame={}", req_config.octets_per_codec_frame.value());
663 return false;
664 }
665 }
666
667 return true;
668 }
669
670 } // namespace utils
671 } // namespace bluetooth::le_audio
672