xref: /aosp_15_r20/system/media/alsa_utils/alsa_device_profile.c (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1 /*
2  * Copyright (C) 2014 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 LOG_TAG "alsa_device_profile"
18 /*#define LOG_NDEBUG 0*/
19 /*#define LOG_PCM_PARAMS 0*/
20 
21 #include <errno.h>
22 #include <inttypes.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <cutils/properties.h>
26 
27 #include <log/log.h>
28 
29 #include "include/alsa_device_profile.h"
30 #include "include/alsa_format.h"
31 #include "include/alsa_logging.h"
32 
33 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
34 
35 #define PERIOD_DURATION_US (5 * 1000)
36 
37 #define DEFAULT_PERIOD_SIZE 1024
38 
39 static const char * const format_string_map[] = {
40     "AUDIO_FORMAT_PCM_16_BIT",      /* "PCM_FORMAT_S16_LE", */
41     "AUDIO_FORMAT_PCM_32_BIT",      /* "PCM_FORMAT_S32_LE", */
42     "AUDIO_FORMAT_PCM_8_BIT",       /* "PCM_FORMAT_S8", */
43     "AUDIO_FORMAT_PCM_8_24_BIT",    /* "PCM_FORMAT_S24_LE", */
44     "AUDIO_FORMAT_PCM_24_BIT_PACKED"/* "PCM_FORMAT_S24_3LE" */
45 };
46 
47 extern int8_t const pcm_format_value_map[50];
48 
49 /* Sort these in terms of preference (best first).
50    192 kHz is not first because it requires significant resources for possibly worse
51    quality and driver instability (depends on device).
52    The order here determines the default sample rate for the device.
53    AudioPolicyManager may not respect this ordering when picking sample rates.
54    Update MAX_PROFILE_SAMPLE_RATES after changing the array size.
55 
56    TODO: remove 32000, 22050, 12000, 11025?  Each sample rate check
57    requires opening the device which may cause pops. */
58 static const unsigned std_sample_rates[] =
59     {96000, 88200, 192000, 176400, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000};
60 
profile_reset(alsa_device_profile * profile)61 static void profile_reset(alsa_device_profile* profile)
62 {
63     profile->card = profile->device = -1;
64     profile->extra_latency_ms = 0;
65 
66     /* terminate the attribute arrays with invalid values */
67     profile->formats[0] = PCM_FORMAT_INVALID;
68     profile->sample_rates[0] = 0;
69     profile->channel_counts[0] = 0;
70 
71     profile->min_period_size = profile->max_period_size = 0;
72     profile->min_channel_count = profile->max_channel_count = DEFAULT_CHANNEL_COUNT;
73 
74     profile->is_valid = false;
75 }
76 
profile_init(alsa_device_profile * profile,int direction)77 void profile_init(alsa_device_profile* profile, int direction)
78 {
79     profile->direction = direction;
80     profile_reset(profile);
81 }
82 
profile_is_initialized(const alsa_device_profile * profile)83 bool profile_is_initialized(const alsa_device_profile* profile)
84 {
85     return profile->card >= 0 && profile->device >= 0;
86 }
87 
profile_is_valid(const alsa_device_profile * profile)88 bool profile_is_valid(const alsa_device_profile* profile) {
89     return profile->is_valid;
90 }
91 
profile_is_cached_for(const alsa_device_profile * profile,int card,int device)92 bool profile_is_cached_for(const alsa_device_profile* profile, int card, int device) {
93     return card == profile->card && device == profile->device;
94 }
95 
profile_decache(alsa_device_profile * profile)96 void profile_decache(alsa_device_profile* profile) {
97     profile_reset(profile);
98 }
99 
100 /*
101  * Returns the supplied value rounded up to the next even multiple of 16
102  */
round_to_16_mult(unsigned int size)103 static unsigned int round_to_16_mult(unsigned int size)
104 {
105     return (size + 15) & ~15;   /* 0xFFFFFFF0; */
106 }
107 
108 /*
109  * Returns the system defined minimum period size based on the supplied sample rate.
110  */
profile_calc_min_period_size(const alsa_device_profile * profile,unsigned sample_rate)111 unsigned profile_calc_min_period_size(const alsa_device_profile* profile, unsigned sample_rate)
112 {
113     ALOGV("profile_calc_min_period_size(%p, rate:%d)", profile, sample_rate);
114     if (profile == NULL) {
115         return DEFAULT_PERIOD_SIZE;
116     } else {
117         unsigned period_us = property_get_int32("ro.audio.usb.period_us", PERIOD_DURATION_US);
118         unsigned num_sample_frames = ((uint64_t)sample_rate * period_us) / 1000000;
119 
120         if (num_sample_frames < profile->min_period_size) {
121             num_sample_frames = profile->min_period_size;
122         }
123         return round_to_16_mult(num_sample_frames);
124     }
125 }
126 
profile_get_period_size(const alsa_device_profile * profile,unsigned sample_rate)127 unsigned int profile_get_period_size(const alsa_device_profile* profile, unsigned sample_rate)
128 {
129     unsigned int period_size = profile_calc_min_period_size(profile, sample_rate);
130     ALOGV("profile_get_period_size(rate:%d) = %d", sample_rate, period_size);
131     return period_size;
132 }
133 
134 /*
135  * Sample Rate
136  */
profile_get_default_sample_rate(const alsa_device_profile * profile)137 unsigned profile_get_default_sample_rate(const alsa_device_profile* profile)
138 {
139     /*
140      * This is probably a poor algorithm. The default sample rate should be the highest (within
141      * limits) rate that is available for both input and output. HOWEVER, the profile has only
142      * one or the other, so that will need to be done at a higher level, like in the HAL.
143      */
144     /*
145      * TODO this won't be right in general. we should store a preferred rate as we are scanning.
146      * But right now it will return the highest rate, which may be correct.
147      */
148     return profile_is_valid(profile) ? profile->sample_rates[0] : DEFAULT_SAMPLE_RATE;
149 }
150 
profile_get_highest_sample_rate(const alsa_device_profile * profile)151 unsigned profile_get_highest_sample_rate(const alsa_device_profile* profile) {
152     /* The hightest sample rate is always stored in the first element of sample_rates.
153      * Note that profile_reset() initiaizes the first element of samples_rates to 0
154      * Which is what we want to return if the profile had not been read anyway.
155      */
156     return profile->sample_rates[0];
157 }
158 
profile_is_sample_rate_valid(const alsa_device_profile * profile,unsigned rate)159 bool profile_is_sample_rate_valid(const alsa_device_profile* profile, unsigned rate)
160 {
161     if (profile_is_valid(profile)) {
162         size_t index;
163         for (index = 0; profile->sample_rates[index] != 0; index++) {
164             if (profile->sample_rates[index] == rate) {
165                 return true;
166             }
167         }
168 
169         return false;
170     } else {
171         ALOGW("**** PROFILE NOT VALID!");
172         return rate == DEFAULT_SAMPLE_RATE;
173     }
174 }
175 
176 /*
177  * Format
178  */
profile_get_default_format(const alsa_device_profile * profile)179 enum pcm_format profile_get_default_format(const alsa_device_profile* profile)
180 {
181     /*
182      * TODO this won't be right in general. we should store a preferred format as we are scanning.
183      */
184     return profile_is_valid(profile) ? profile->formats[0] : DEFAULT_SAMPLE_FORMAT;
185 }
186 
profile_is_format_valid(const alsa_device_profile * profile,enum pcm_format fmt)187 bool profile_is_format_valid(const alsa_device_profile* profile, enum pcm_format fmt) {
188     if (profile_is_valid(profile)) {
189         size_t index;
190         for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) {
191             if (profile->formats[index] == fmt) {
192                 return true;
193             }
194         }
195 
196         return false;
197     } else {
198         return fmt == DEFAULT_SAMPLE_FORMAT;
199     }
200 }
201 
202 /*
203  * Channels
204  */
profile_get_default_channel_count(const alsa_device_profile * profile)205 unsigned profile_get_default_channel_count(const alsa_device_profile* profile)
206 {
207     return profile_is_valid(profile) ? profile->channel_counts[0] : DEFAULT_CHANNEL_COUNT;
208 }
209 
profile_get_closest_channel_count(const alsa_device_profile * profile,unsigned count)210 unsigned profile_get_closest_channel_count(const alsa_device_profile* profile, unsigned count)
211 {
212     if (profile_is_valid(profile)) {
213         if (count < profile->min_channel_count) {
214             return profile->min_channel_count;
215         } else if (count > profile->max_channel_count) {
216             return profile->max_channel_count;
217         } else {
218             return count;
219         }
220     } else {
221         return 0;
222     }
223 }
224 
profile_is_channel_count_valid(const alsa_device_profile * profile,unsigned count)225 bool profile_is_channel_count_valid(const alsa_device_profile* profile, unsigned count)
226 {
227     if (profile_is_initialized(profile)) {
228         return count >= profile->min_channel_count && count <= profile->max_channel_count;
229     } else {
230         return count == DEFAULT_CHANNEL_COUNT;
231     }
232 }
233 
profile_test_sample_rate(const alsa_device_profile * profile,unsigned rate)234 static bool profile_test_sample_rate(const alsa_device_profile* profile, unsigned rate)
235 {
236     struct pcm_config config = profile->default_config;
237     config.rate = rate;
238     // This method tests whether a sample rate is supported by the USB device
239     // by attempting to open it.
240     //
241     // The profile default_config currently contains the minimum channel count.
242     // As some usb devices cannot sustain the sample rate across all its supported
243     // channel counts, we try the largest usable channel count.  This is
244     // bounded by FCC_LIMIT.
245     //
246     // If config.channels > FCC_LIMIT then we still test it for sample rate compatibility.
247     // It is possible that the USB device does not support less than a certain number
248     // of channels, and that minimum number is > FCC_LIMIT.  Then the default_config
249     // channels will be > FCC_LIMIT (and we still proceed with the test).
250     //
251     // For example, the FocusRite Scarlett 18i20 supports between 16 to 20 playback
252     // channels and between 14 to 18 capture channels.
253     // If FCC_LIMIT is 8, we still need to use and test 16 output channels for playback
254     // and 14 input channels for capture, as that will be the ALSA opening configuration.
255     // The Android USB audio HAL layer will automatically zero pad to accommodate the
256     // 16 playback or 14 capture channel configuration from the (up to FCC_LIMIT)
257     // channels delivered by AudioFlinger.
258     if (config.channels < FCC_LIMIT) {
259         config.channels = profile->max_channel_count;
260         if (config.channels > FCC_LIMIT) config.channels = FCC_LIMIT;
261     }
262     bool works = false; /* let's be pessimistic */
263     struct pcm * pcm = pcm_open(profile->card, profile->device,
264                                 profile->direction, &config);
265 
266     if (pcm != NULL) {
267         works = pcm_is_ready(pcm);
268         pcm_close(pcm);
269     }
270 
271     return works;
272 }
273 
profile_enum_sample_rates(alsa_device_profile * profile,unsigned min,unsigned max)274 static unsigned profile_enum_sample_rates(alsa_device_profile* profile, unsigned min, unsigned max)
275 {
276     unsigned num_entries = 0;
277     unsigned index;
278 
279     for (index = 0; index < ARRAY_SIZE(std_sample_rates) &&
280                     num_entries < ARRAY_SIZE(profile->sample_rates) - 1;
281          index++) {
282         if (std_sample_rates[index] >= min && std_sample_rates[index] <= max
283                 && profile_test_sample_rate(profile, std_sample_rates[index])) {
284             profile->sample_rates[num_entries++] = std_sample_rates[index];
285         }
286     }
287     profile->sample_rates[num_entries] = 0; /* terminate */
288     return num_entries; /* return # of supported rates */
289 }
290 
profile_enum_sample_formats(alsa_device_profile * profile,const struct pcm_mask * mask)291 static unsigned profile_enum_sample_formats(alsa_device_profile* profile,
292         const struct pcm_mask * mask)
293 {
294     const int num_slots = ARRAY_SIZE(mask->bits);
295     const int bits_per_slot = sizeof(mask->bits[0]) * 8;
296 
297     const int table_size = ARRAY_SIZE(pcm_format_value_map);
298 
299     int slot_index, bit_index, table_index;
300     table_index = 0;
301     int num_written = 0;
302     for (slot_index = 0; slot_index < num_slots && table_index < table_size;
303             slot_index++) {
304         unsigned bit_mask = 1;
305         for (bit_index = 0;
306                 bit_index < bits_per_slot && table_index < table_size;
307                 bit_index++) {
308             if ((mask->bits[slot_index] & bit_mask) != 0) {
309                 enum pcm_format format = pcm_format_value_map[table_index];
310                 /* Never return invalid (unrecognized) or 8-bit */
311                 if (format != PCM_FORMAT_INVALID && format != PCM_FORMAT_S8) {
312                     profile->formats[num_written++] = format;
313                     if (num_written == ARRAY_SIZE(profile->formats) - 1) {
314                         /* leave at least one PCM_FORMAT_INVALID at the end */
315                         goto end;
316                     }
317                 }
318             }
319             bit_mask <<= 1;
320             table_index++;
321         }
322     }
323 end:
324     profile->formats[num_written] = PCM_FORMAT_INVALID;
325     return num_written;
326 }
327 
profile_enum_channel_counts(alsa_device_profile * profile,unsigned min,unsigned max)328 static unsigned profile_enum_channel_counts(alsa_device_profile* profile, unsigned min,
329         unsigned max)
330 {
331     /* modify alsa_device_profile.h if you change the std_channel_counts[] array. */
332     // The order of this array controls the order for channel mask generation.
333     // In general, this is just counting from max to min not skipping anything,
334     // but need not be that way.
335     static const unsigned std_channel_counts[FCC_24] = {
336         24, 23, 22, 21, 20, 19, 18, 17,
337         16, 15, 14, 13, 12, 11, 10, 9,
338         8, 7, 6, 5, 4, 3, 2, 1
339     };
340 
341     unsigned num_counts = 0;
342     unsigned index;
343     int max_allowed_index = -1; // index of maximum allowed channel count reported by device.
344     /* TODO write a profile_test_channel_count() */
345     /* Ensure there is at least one invalid channel count to terminate the channel counts array */
346     for (index = 0; index < ARRAY_SIZE(std_channel_counts) &&
347                     num_counts < ARRAY_SIZE(profile->channel_counts) - 1;
348          index++) {
349         const unsigned test_count = std_channel_counts[index];
350         /* TODO Do we want a channel counts test? */
351         if (test_count <= FCC_LIMIT) {
352             if (test_count >= min && test_count <= max /* &&
353                     profile_test_channel_count(profile, channel_counts[index])*/) {
354                 profile->channel_counts[num_counts++] = test_count;
355             }
356             if (max_allowed_index < 0 ||
357                     std_channel_counts[max_allowed_index] < test_count) {
358                 max_allowed_index = index;
359             }
360         }
361     }
362     // if we have no match with the standard counts, we use the largest (preferred) std count.
363     // Note: the usb hal will adjust channel data properly to fit.
364     if (num_counts == 0 && max_allowed_index >= 0) {
365         ALOGW("usb device does not match std channel counts, setting to %d",
366                 std_channel_counts[max_allowed_index]);
367         profile->channel_counts[num_counts++] = std_channel_counts[max_allowed_index];
368     }
369     profile->channel_counts[num_counts] = 0;
370     return num_counts; /* return # of supported counts */
371 }
372 
373 /*
374  * Reads and decodes configuration info from the specified ALSA card/device.
375  */
read_alsa_device_config(alsa_device_profile * profile,struct pcm_config * config)376 static int read_alsa_device_config(alsa_device_profile * profile, struct pcm_config * config)
377 {
378     ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",
379           profile->card, profile->device, profile->direction);
380 
381     if (profile->card < 0 || profile->device < 0) {
382         return -EINVAL;
383     }
384 
385     struct pcm_params * alsa_hw_params =
386         pcm_params_get(profile->card, profile->device, profile->direction);
387     if (alsa_hw_params == NULL) {
388         return -EINVAL;
389     }
390 
391     profile->min_period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE);
392     profile->max_period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE);
393 
394     profile->min_channel_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
395     profile->max_channel_count = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
396 
397     int ret = 0;
398 
399     /*
400      * This Logging will be useful when testing new USB devices.
401      */
402 #ifdef LOG_PCM_PARAMS
403     log_pcm_params(alsa_hw_params);
404 #endif
405 
406     config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
407     // For output devices, let's make sure we choose at least stereo
408     // (assuming the device supports it).
409     if (profile->direction == PCM_OUT &&
410         config->channels < 2 && pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS) >= 2) {
411         config->channels = 2;
412     }
413     config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
414     // Prefer 48K or 44.1K
415     if (config->rate < 48000 &&
416         pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE) >= 48000) {
417         config->rate = 48000;
418     } else if (config->rate < 44100 &&
419                pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE) >= 44100) {
420         config->rate = 44100;
421     }
422     config->period_size = profile_calc_min_period_size(profile, config->rate);
423     config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
424     config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
425 #ifdef LOG_PCM_PARAMS
426     log_pcm_config(config, "read_alsa_device_config");
427 #endif
428     if (config->format == PCM_FORMAT_INVALID) {
429         ret = -EINVAL;
430     }
431 
432     pcm_params_free(alsa_hw_params);
433 
434     return ret;
435 }
436 
profile_fill_builtin_device_info(alsa_device_profile * profile,struct pcm_config * config,unsigned buffer_frame_count)437 bool profile_fill_builtin_device_info(alsa_device_profile* profile, struct pcm_config* config,
438                                       unsigned buffer_frame_count) {
439     if (!profile_is_initialized(profile)) {
440         return false;
441     }
442     profile->extra_latency_ms = property_get_int32(
443             "ro.hardware.audio.tinyalsa.host_latency_ms", 0);
444     profile->default_config.channels = config->channels;
445     profile->default_config.rate = config->rate;
446     profile->default_config.format = config->format;
447     int period_count = property_get_int32(
448             "ro.hardware.audio.tinyalsa.period_count", DEFAULT_PERIOD_COUNT);
449     if (period_count <= 0) period_count = DEFAULT_PERIOD_COUNT;
450     profile->default_config.period_count = period_count;
451     int period_size_multiplier = property_get_int32(
452             "ro.hardware.audio.tinyalsa.period_size_multiplier", 1);
453     if (period_size_multiplier <= 0) period_size_multiplier = 1;
454     profile->default_config.period_size =
455             period_size_multiplier * buffer_frame_count / period_count;
456     profile->min_period_size = profile->max_period_size = profile->default_config.period_size;
457     profile->formats[0] = config->format;
458     profile->formats[1] = PCM_FORMAT_INVALID;
459     profile->channel_counts[0] = config->channels;
460     profile->channel_counts[1] = 0;
461     profile->min_channel_count = profile->max_channel_count = config->channels;
462     profile->sample_rates[0] = config->rate;
463     profile->sample_rates[1] = 0;
464     profile->is_valid = true;
465     return true;
466 }
467 
profile_read_device_info(alsa_device_profile * profile)468 bool profile_read_device_info(alsa_device_profile* profile)
469 {
470     if (!profile_is_initialized(profile)) {
471         return false;
472     }
473 
474     /* let's get some defaults */
475     read_alsa_device_config(profile, &profile->default_config);
476     ALOGV("default_config chans:%d rate:%d format:%d count:%d size:%d",
477           profile->default_config.channels, profile->default_config.rate,
478           profile->default_config.format, profile->default_config.period_count,
479           profile->default_config.period_size);
480 
481     struct pcm_params * alsa_hw_params = pcm_params_get(profile->card,
482                                                         profile->device,
483                                                         profile->direction);
484     if (alsa_hw_params == NULL) {
485         return false;
486     }
487 
488     /* Formats */
489     const struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT);
490     profile_enum_sample_formats(profile, format_mask);
491 
492     /* Channels */
493     profile_enum_channel_counts(
494             profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS),
495             pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS));
496 
497     /* Sample Rates */
498     profile_enum_sample_rates(
499             profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE),
500             pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE));
501 
502     profile->is_valid = true;
503 
504     pcm_params_free(alsa_hw_params);
505     return true;
506 }
507 
profile_get_sample_rate_strs(const alsa_device_profile * profile)508 char * profile_get_sample_rate_strs(const alsa_device_profile* profile)
509 {
510     /* if we assume that rate strings are about 5 characters (48000 is 5), plus ~1 for a
511      * delimiter "|" this buffer has room for about 22 rate strings which seems like
512      * way too much, but it's a stack variable so only temporary.
513      */
514     char buffer[128];
515     buffer[0] = '\0';
516     size_t buffSize = ARRAY_SIZE(buffer);
517     size_t curStrLen = 0;
518 
519     char numBuffer[32];
520 
521     size_t numEntries = 0;
522     size_t index;
523     for (index = 0; profile->sample_rates[index] != 0; index++) {
524         snprintf(numBuffer, sizeof(numBuffer), "%u", profile->sample_rates[index]);
525         // account for both the null, and potentially the bar.
526         if (buffSize - curStrLen < strlen(numBuffer) + (numEntries != 0 ? 2 : 1)) {
527             /* we don't have room for another, so bail at this point rather than
528              * return a malformed rate string
529              */
530             break;
531         }
532         if (numEntries++ != 0) {
533             strlcat(buffer, "|", buffSize);
534         }
535         curStrLen = strlcat(buffer, numBuffer, buffSize);
536     }
537 
538     return strdup(buffer);
539 }
540 
profile_get_format_strs(const alsa_device_profile * profile)541 char * profile_get_format_strs(const alsa_device_profile* profile)
542 {
543     /* if we assume that format strings are about 24 characters (AUDIO_FORMAT_PCM_16_BIT is 23),
544      * plus ~1 for a delimiter "|" this buffer has room for about 10 format strings which seems
545      *  like way too much, but it's a stack variable so only temporary.
546      */
547     char buffer[256];
548     buffer[0] = '\0';
549     size_t buffSize = ARRAY_SIZE(buffer);
550     size_t curStrLen = 0;
551 
552     size_t numEntries = 0;
553     size_t index = 0;
554     for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) {
555         // account for both the null, and potentially the bar.
556         if (buffSize - curStrLen < strlen(format_string_map[profile->formats[index]])
557                                    + (numEntries != 0 ? 2 : 1)) {
558             /* we don't have room for another, so bail at this point rather than
559              * return a malformed rate string
560              */
561             break;
562         }
563         if (numEntries++ != 0) {
564             strlcat(buffer, "|", buffSize);
565         }
566         curStrLen = strlcat(buffer, format_string_map[profile->formats[index]], buffSize);
567     }
568 
569     return strdup(buffer);
570 }
571 
profile_get_channel_count_strs(const alsa_device_profile * profile)572 char * profile_get_channel_count_strs(const alsa_device_profile* profile)
573 {
574     // we use only the canonical even number channel position masks.
575     static const char * const out_chans_strs[] = {
576         [0] = "AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
577         [1] = "AUDIO_CHANNEL_OUT_MONO",
578         [2] = "AUDIO_CHANNEL_OUT_STEREO",
579         [4] = "AUDIO_CHANNEL_OUT_QUAD",
580         [6] = "AUDIO_CHANNEL_OUT_5POINT1",
581         [FCC_8] = "AUDIO_CHANNEL_OUT_7POINT1",
582         [FCC_12] = "AUDIO_CHANNEL_OUT_7POINT1POINT4",
583         [FCC_24] = "AUDIO_CHANNEL_OUT_22POINT2",
584     };
585 
586     static const char * const in_chans_strs[] = {
587         [0] = "AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
588         [1] = "AUDIO_CHANNEL_IN_MONO",
589         [2] = "AUDIO_CHANNEL_IN_STEREO",
590         /* channel counts greater than this not considered */
591     };
592 
593     static const char * const index_chans_strs[] = {
594         [0] = "AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */
595 
596         [1] = "AUDIO_CHANNEL_INDEX_MASK_1",
597         [2] = "AUDIO_CHANNEL_INDEX_MASK_2",
598         [3] = "AUDIO_CHANNEL_INDEX_MASK_3",
599         [4] = "AUDIO_CHANNEL_INDEX_MASK_4",
600         [5] = "AUDIO_CHANNEL_INDEX_MASK_5",
601         [6] = "AUDIO_CHANNEL_INDEX_MASK_6",
602         [7] = "AUDIO_CHANNEL_INDEX_MASK_7",
603         [8] = "AUDIO_CHANNEL_INDEX_MASK_8",
604 
605         [9] = "AUDIO_CHANNEL_INDEX_MASK_9",
606         [10] = "AUDIO_CHANNEL_INDEX_MASK_10",
607         [11] = "AUDIO_CHANNEL_INDEX_MASK_11",
608         [12] = "AUDIO_CHANNEL_INDEX_MASK_12",
609         [13] = "AUDIO_CHANNEL_INDEX_MASK_13",
610         [14] = "AUDIO_CHANNEL_INDEX_MASK_14",
611         [15] = "AUDIO_CHANNEL_INDEX_MASK_15",
612         [16] = "AUDIO_CHANNEL_INDEX_MASK_16",
613 
614         [17] = "AUDIO_CHANNEL_INDEX_MASK_17",
615         [18] = "AUDIO_CHANNEL_INDEX_MASK_18",
616         [19] = "AUDIO_CHANNEL_INDEX_MASK_19",
617         [20] = "AUDIO_CHANNEL_INDEX_MASK_20",
618         [21] = "AUDIO_CHANNEL_INDEX_MASK_21",
619         [22] = "AUDIO_CHANNEL_INDEX_MASK_22",
620         [23] = "AUDIO_CHANNEL_INDEX_MASK_23",
621         [24] = "AUDIO_CHANNEL_INDEX_MASK_24",
622     };
623 
624     const bool isOutProfile = profile->direction == PCM_OUT;
625 
626     const char * const * const chans_strs = isOutProfile ? out_chans_strs : in_chans_strs;
627     size_t chans_strs_size =
628             isOutProfile ? ARRAY_SIZE(out_chans_strs) : ARRAY_SIZE(in_chans_strs);
629     if (chans_strs_size > FCC_LIMIT + 1) chans_strs_size = FCC_LIMIT + 1; // starts with 0.
630 
631     /*
632      * MAX_CHANNEL_NAME_LEN: The longest channel name so far is "AUDIO_CHANNEL_OUT_7POINT1POINT4"
633      * at 31 chars, add 1 for the "|" delimiter, so we allocate 48 chars to be safe.
634      *
635      * We allocate room for channel index and channel position strings (2x).
636      */
637     const size_t MAX_CHANNEL_NAME_LEN = 48;
638     char buffer[MAX_CHANNEL_NAME_LEN * (FCC_LIMIT * 2) + 1];
639     buffer[0] = '\0';
640     size_t buffSize = ARRAY_SIZE(buffer);
641     size_t curStrLen = 0;
642 
643     /* We currently support MONO and STEREO, and always report STEREO but some (many)
644      * USB Audio Devices may only announce support for MONO (a headset mic for example), or
645      * The total number of output channels. SO, if the device itself doesn't explicitly
646      * support STEREO, append to the channel config strings we are generating.
647      *
648      * The MONO and STEREO positional channel masks are provided for legacy compatibility.
649      * For multichannel (n > 2) we only expose channel index masks.
650      */
651     // Always support stereo
652     curStrLen = strlcat(buffer, chans_strs[2], buffSize);
653 
654     size_t index;
655     unsigned channel_count;
656     for (index = 0;
657          (channel_count = profile->channel_counts[index]) != 0;
658          index++) {
659 
660         if (channel_count > FCC_LIMIT) continue;
661 
662         /* we only show positional information for mono (stereo handled already) */
663         if (channel_count < chans_strs_size
664                 && chans_strs[channel_count] != NULL
665                 && channel_count < 2 /* positional only for fewer than 2 channels */) {
666             // account for the '|' and the '\0'
667             if (buffSize - curStrLen < strlen(chans_strs[channel_count]) + 2) {
668                 /* we don't have room for another, so bail at this point rather than
669                  * return a malformed rate string
670                  */
671                 break;
672             }
673 
674             if (curStrLen != 0) strlcat(buffer, "|", buffSize);
675             curStrLen = strlcat(buffer, chans_strs[channel_count], buffSize);
676         }
677 
678         // handle channel index masks for both input and output
679         // +2 to account for the '|' and the '\0'
680          if (buffSize - curStrLen < strlen(index_chans_strs[channel_count]) + 2) {
681              /* we don't have room for another, so bail at this point rather than
682               * return a malformed rate string
683               */
684              break;
685          }
686 
687          if (curStrLen != 0) strlcat(buffer, "|", buffSize);
688          curStrLen = strlcat(buffer, index_chans_strs[channel_count], buffSize);
689     }
690 
691     return strdup(buffer);
692 }
693 
profile_dump(const alsa_device_profile * profile,int fd)694 void profile_dump(const alsa_device_profile* profile, int fd)
695 {
696     if (profile == NULL) {
697         dprintf(fd, "  %s\n", "No USB Profile");
698         return; /* bail early */
699     }
700 
701     if (!profile->is_valid) {
702         dprintf(fd, "  Profile is INVALID");
703     }
704 
705     /* card/device/direction */
706     dprintf(fd, "  card:%d, device:%d - %s\n",
707                 profile->card, profile->device, profile->direction == PCM_OUT ? "OUT" : "IN");
708 
709     /* formats */
710     dprintf(fd, "  Formats: ");
711     for (int fmtIndex = 0;
712           fmtIndex < MAX_PROFILE_FORMATS && profile->formats[fmtIndex] != PCM_FORMAT_INVALID;
713           fmtIndex++) {
714         dprintf(fd, "%d ", profile->formats[fmtIndex]);
715     }
716     dprintf(fd, "\n");
717 
718     /* sample rates */
719     dprintf(fd, "  Rates: ");
720     for (int rateIndex = 0;
721           rateIndex < MAX_PROFILE_SAMPLE_RATES && profile->sample_rates[rateIndex] != 0;
722           rateIndex++) {
723         dprintf(fd, "%u ", profile->sample_rates[rateIndex]);
724     }
725     dprintf(fd, "\n");
726 
727     // channel counts
728     dprintf(fd, "  Channel Counts: ");
729     for (int cntIndex = 0;
730           cntIndex < MAX_PROFILE_CHANNEL_COUNTS && profile->channel_counts[cntIndex] != 0;
731           cntIndex++) {
732         dprintf(fd, "%u ", profile->channel_counts[cntIndex]);
733     }
734     dprintf(fd, "\n");
735 
736     dprintf(fd, "  min/max period size [%u : %u]\n",
737             profile->min_period_size,profile-> max_period_size);
738     dprintf(fd, "  min/max channel count [%u : %u]\n",
739             profile->min_channel_count, profile->max_channel_count);
740 
741     // struct pcm_config default_config;
742     dprintf(fd, "  Default Config:\n");
743     dprintf(fd, "    channels: %d\n", profile->default_config.channels);
744     dprintf(fd, "    rate: %d\n", profile->default_config.rate);
745     dprintf(fd, "    period_size: %d\n", profile->default_config.period_size);
746     dprintf(fd, "    period_count: %d\n", profile->default_config.period_count);
747     dprintf(fd, "    format: %d\n", profile->default_config.format);
748 }
749