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 61 static void profile_reset(alsa_device_profile* profile) 62 { 63 profile->card = profile->device = -1; 64 65 /* terminate the attribute arrays with invalid values */ 66 profile->formats[0] = PCM_FORMAT_INVALID; 67 profile->sample_rates[0] = 0; 68 profile->channel_counts[0] = 0; 69 70 profile->min_period_size = profile->max_period_size = 0; 71 profile->min_channel_count = profile->max_channel_count = DEFAULT_CHANNEL_COUNT; 72 73 profile->is_valid = false; 74 } 75 76 void profile_init(alsa_device_profile* profile, int direction) 77 { 78 profile->direction = direction; 79 profile_reset(profile); 80 } 81 82 bool profile_is_initialized(const alsa_device_profile* profile) 83 { 84 return profile->card >= 0 && profile->device >= 0; 85 } 86 87 bool profile_is_valid(const alsa_device_profile* profile) { 88 return profile->is_valid; 89 } 90 91 bool profile_is_cached_for(const alsa_device_profile* profile, int card, int device) { 92 return card == profile->card && device == profile->device; 93 } 94 95 void profile_decache(alsa_device_profile* profile) { 96 profile_reset(profile); 97 } 98 99 /* 100 * Returns the supplied value rounded up to the next even multiple of 16 101 */ 102 static unsigned int round_to_16_mult(unsigned int size) 103 { 104 return (size + 15) & ~15; /* 0xFFFFFFF0; */ 105 } 106 107 /* 108 * Returns the system defined minimum period size based on the supplied sample rate. 109 */ 110 unsigned profile_calc_min_period_size(const alsa_device_profile* profile, unsigned sample_rate) 111 { 112 ALOGV("profile_calc_min_period_size(%p, rate:%d)", profile, sample_rate); 113 if (profile == NULL) { 114 return DEFAULT_PERIOD_SIZE; 115 } else { 116 unsigned period_us = property_get_int32("ro.audio.usb.period_us", PERIOD_DURATION_US); 117 unsigned num_sample_frames = ((uint64_t)sample_rate * period_us) / 1000000; 118 119 if (num_sample_frames < profile->min_period_size) { 120 num_sample_frames = profile->min_period_size; 121 } 122 return round_to_16_mult(num_sample_frames); 123 } 124 } 125 126 unsigned int profile_get_period_size(const alsa_device_profile* profile, unsigned sample_rate) 127 { 128 unsigned int period_size = profile_calc_min_period_size(profile, sample_rate); 129 ALOGV("profile_get_period_size(rate:%d) = %d", sample_rate, period_size); 130 return period_size; 131 } 132 133 /* 134 * Sample Rate 135 */ 136 unsigned profile_get_default_sample_rate(const alsa_device_profile* profile) 137 { 138 /* 139 * This is probably a poor algorithm. The default sample rate should be the highest (within 140 * limits) rate that is available for both input and output. HOWEVER, the profile has only 141 * one or the other, so that will need to be done at a higher level, like in the HAL. 142 */ 143 /* 144 * TODO this won't be right in general. we should store a preferred rate as we are scanning. 145 * But right now it will return the highest rate, which may be correct. 146 */ 147 return profile_is_valid(profile) ? profile->sample_rates[0] : DEFAULT_SAMPLE_RATE; 148 } 149 150 unsigned profile_get_highest_sample_rate(const alsa_device_profile* profile) { 151 /* The hightest sample rate is always stored in the first element of sample_rates. 152 * Note that profile_reset() initiaizes the first element of samples_rates to 0 153 * Which is what we want to return if the profile had not been read anyway. 154 */ 155 return profile->sample_rates[0]; 156 } 157 158 bool profile_is_sample_rate_valid(const alsa_device_profile* profile, unsigned rate) 159 { 160 if (profile_is_valid(profile)) { 161 size_t index; 162 for (index = 0; profile->sample_rates[index] != 0; index++) { 163 if (profile->sample_rates[index] == rate) { 164 return true; 165 } 166 } 167 168 return false; 169 } else { 170 ALOGW("**** PROFILE NOT VALID!"); 171 return rate == DEFAULT_SAMPLE_RATE; 172 } 173 } 174 175 /* 176 * Format 177 */ 178 enum pcm_format profile_get_default_format(const alsa_device_profile* profile) 179 { 180 /* 181 * TODO this won't be right in general. we should store a preferred format as we are scanning. 182 */ 183 return profile_is_valid(profile) ? profile->formats[0] : DEFAULT_SAMPLE_FORMAT; 184 } 185 186 bool profile_is_format_valid(const alsa_device_profile* profile, enum pcm_format fmt) { 187 if (profile_is_valid(profile)) { 188 size_t index; 189 for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { 190 if (profile->formats[index] == fmt) { 191 return true; 192 } 193 } 194 195 return false; 196 } else { 197 return fmt == DEFAULT_SAMPLE_FORMAT; 198 } 199 } 200 201 /* 202 * Channels 203 */ 204 unsigned profile_get_default_channel_count(const alsa_device_profile* profile) 205 { 206 return profile_is_valid(profile) ? profile->channel_counts[0] : DEFAULT_CHANNEL_COUNT; 207 } 208 209 unsigned profile_get_closest_channel_count(const alsa_device_profile* profile, unsigned count) 210 { 211 if (profile_is_valid(profile)) { 212 if (count < profile->min_channel_count) { 213 return profile->min_channel_count; 214 } else if (count > profile->max_channel_count) { 215 return profile->max_channel_count; 216 } else { 217 return count; 218 } 219 } else { 220 return 0; 221 } 222 } 223 224 bool profile_is_channel_count_valid(const alsa_device_profile* profile, unsigned count) 225 { 226 if (profile_is_initialized(profile)) { 227 return count >= profile->min_channel_count && count <= profile->max_channel_count; 228 } else { 229 return count == DEFAULT_CHANNEL_COUNT; 230 } 231 } 232 233 static bool profile_test_sample_rate(const alsa_device_profile* profile, unsigned rate) 234 { 235 struct pcm_config config = profile->default_config; 236 config.rate = rate; 237 238 bool works = false; /* let's be pessimistic */ 239 struct pcm * pcm = pcm_open(profile->card, profile->device, 240 profile->direction, &config); 241 242 if (pcm != NULL) { 243 works = pcm_is_ready(pcm); 244 pcm_close(pcm); 245 } 246 247 return works; 248 } 249 250 static unsigned profile_enum_sample_rates(alsa_device_profile* profile, unsigned min, unsigned max) 251 { 252 unsigned num_entries = 0; 253 unsigned index; 254 255 for (index = 0; index < ARRAY_SIZE(std_sample_rates) && 256 num_entries < ARRAY_SIZE(profile->sample_rates) - 1; 257 index++) { 258 if (std_sample_rates[index] >= min && std_sample_rates[index] <= max 259 && profile_test_sample_rate(profile, std_sample_rates[index])) { 260 profile->sample_rates[num_entries++] = std_sample_rates[index]; 261 } 262 } 263 profile->sample_rates[num_entries] = 0; /* terminate */ 264 return num_entries; /* return # of supported rates */ 265 } 266 267 static unsigned profile_enum_sample_formats(alsa_device_profile* profile, struct pcm_mask * mask) 268 { 269 const int num_slots = ARRAY_SIZE(mask->bits); 270 const int bits_per_slot = sizeof(mask->bits[0]) * 8; 271 272 const int table_size = ARRAY_SIZE(pcm_format_value_map); 273 274 int slot_index, bit_index, table_index; 275 table_index = 0; 276 int num_written = 0; 277 for (slot_index = 0; slot_index < num_slots && table_index < table_size; 278 slot_index++) { 279 unsigned bit_mask = 1; 280 for (bit_index = 0; 281 bit_index < bits_per_slot && table_index < table_size; 282 bit_index++) { 283 if ((mask->bits[slot_index] & bit_mask) != 0) { 284 enum pcm_format format = pcm_format_value_map[table_index]; 285 /* Never return invalid (unrecognized) or 8-bit */ 286 if (format != PCM_FORMAT_INVALID && format != PCM_FORMAT_S8) { 287 profile->formats[num_written++] = format; 288 if (num_written == ARRAY_SIZE(profile->formats) - 1) { 289 /* leave at least one PCM_FORMAT_INVALID at the end */ 290 goto end; 291 } 292 } 293 } 294 bit_mask <<= 1; 295 table_index++; 296 } 297 } 298 end: 299 profile->formats[num_written] = PCM_FORMAT_INVALID; 300 return num_written; 301 } 302 303 static unsigned profile_enum_channel_counts(alsa_device_profile* profile, unsigned min, 304 unsigned max) 305 { 306 /* modify alsa_device_profile.h if you change the std_channel_counts[] array. */ 307 static const unsigned std_channel_counts[] = {8, 7, 6, 5, 4, 3, 2, 1}; 308 309 unsigned num_counts = 0; 310 unsigned index; 311 /* TODO write a profile_test_channel_count() */ 312 /* Ensure there is at least one invalid channel count to terminate the channel counts array */ 313 for (index = 0; index < ARRAY_SIZE(std_channel_counts) && 314 num_counts < ARRAY_SIZE(profile->channel_counts) - 1; 315 index++) { 316 /* TODO Do we want a channel counts test? */ 317 if (std_channel_counts[index] >= min && std_channel_counts[index] <= max /* && 318 profile_test_channel_count(profile, channel_counts[index])*/) { 319 profile->channel_counts[num_counts++] = std_channel_counts[index]; 320 } 321 } 322 // if we have no match with the standard counts, we use the largest (preferred) std count. 323 if (num_counts == 0) { 324 ALOGW("usb device does not match std channel counts, setting to %d", 325 std_channel_counts[0]); 326 profile->channel_counts[num_counts++] = std_channel_counts[0]; 327 } 328 profile->channel_counts[num_counts] = 0; 329 return num_counts; /* return # of supported counts */ 330 } 331 332 /* 333 * Reads and decodes configuration info from the specified ALSA card/device. 334 */ 335 static int read_alsa_device_config(alsa_device_profile * profile, struct pcm_config * config) 336 { 337 ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)", 338 profile->card, profile->device, profile->direction); 339 340 if (profile->card < 0 || profile->device < 0) { 341 return -EINVAL; 342 } 343 344 struct pcm_params * alsa_hw_params = 345 pcm_params_get(profile->card, profile->device, profile->direction); 346 if (alsa_hw_params == NULL) { 347 return -EINVAL; 348 } 349 350 profile->min_period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); 351 profile->max_period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); 352 353 profile->min_channel_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 354 profile->max_channel_count = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 355 356 int ret = 0; 357 358 /* 359 * This Logging will be useful when testing new USB devices. 360 */ 361 #ifdef LOG_PCM_PARAMS 362 log_pcm_params(alsa_hw_params); 363 #endif 364 365 config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 366 // For output devices, let's make sure we choose at least stereo 367 // (assuming the device supports it). 368 if (profile->direction == PCM_OUT && 369 config->channels < 2 && pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS) >= 2) { 370 config->channels = 2; 371 } 372 config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 373 // Prefer 48K or 44.1K 374 if (config->rate < 48000 && 375 pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE) >= 48000) { 376 config->rate = 48000; 377 } else if (config->rate < 44100 && 378 pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE) >= 44100) { 379 config->rate = 44100; 380 } 381 config->period_size = profile_calc_min_period_size(profile, config->rate); 382 config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS); 383 config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); 384 #ifdef LOG_PCM_PARAMS 385 log_pcm_config(config, "read_alsa_device_config"); 386 #endif 387 if (config->format == PCM_FORMAT_INVALID) { 388 ret = -EINVAL; 389 } 390 391 pcm_params_free(alsa_hw_params); 392 393 return ret; 394 } 395 396 bool profile_read_device_info(alsa_device_profile* profile) 397 { 398 if (!profile_is_initialized(profile)) { 399 return false; 400 } 401 402 /* let's get some defaults */ 403 read_alsa_device_config(profile, &profile->default_config); 404 ALOGV("default_config chans:%d rate:%d format:%d count:%d size:%d", 405 profile->default_config.channels, profile->default_config.rate, 406 profile->default_config.format, profile->default_config.period_count, 407 profile->default_config.period_size); 408 409 struct pcm_params * alsa_hw_params = pcm_params_get(profile->card, 410 profile->device, 411 profile->direction); 412 if (alsa_hw_params == NULL) { 413 return false; 414 } 415 416 /* Formats */ 417 struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT); 418 profile_enum_sample_formats(profile, format_mask); 419 420 /* Channels */ 421 profile_enum_channel_counts( 422 profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), 423 pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); 424 425 /* Sample Rates */ 426 profile_enum_sample_rates( 427 profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), 428 pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); 429 430 profile->is_valid = true; 431 432 pcm_params_free(alsa_hw_params); 433 return true; 434 } 435 436 char * profile_get_sample_rate_strs(const alsa_device_profile* profile) 437 { 438 /* if we assume that rate strings are about 5 characters (48000 is 5), plus ~1 for a 439 * delimiter "|" this buffer has room for about 22 rate strings which seems like 440 * way too much, but it's a stack variable so only temporary. 441 */ 442 char buffer[128]; 443 buffer[0] = '\0'; 444 size_t buffSize = ARRAY_SIZE(buffer); 445 size_t curStrLen = 0; 446 447 char numBuffer[32]; 448 449 size_t numEntries = 0; 450 size_t index; 451 for (index = 0; profile->sample_rates[index] != 0; index++) { 452 snprintf(numBuffer, sizeof(numBuffer), "%u", profile->sample_rates[index]); 453 // account for both the null, and potentially the bar. 454 if (buffSize - curStrLen < strlen(numBuffer) + (numEntries != 0 ? 2 : 1)) { 455 /* we don't have room for another, so bail at this point rather than 456 * return a malformed rate string 457 */ 458 break; 459 } 460 if (numEntries++ != 0) { 461 strlcat(buffer, "|", buffSize); 462 } 463 curStrLen = strlcat(buffer, numBuffer, buffSize); 464 } 465 466 return strdup(buffer); 467 } 468 469 char * profile_get_format_strs(const alsa_device_profile* profile) 470 { 471 /* if we assume that format strings are about 24 characters (AUDIO_FORMAT_PCM_16_BIT is 23), 472 * plus ~1 for a delimiter "|" this buffer has room for about 10 format strings which seems 473 * like way too much, but it's a stack variable so only temporary. 474 */ 475 char buffer[256]; 476 buffer[0] = '\0'; 477 size_t buffSize = ARRAY_SIZE(buffer); 478 size_t curStrLen = 0; 479 480 size_t numEntries = 0; 481 size_t index = 0; 482 for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { 483 // account for both the null, and potentially the bar. 484 if (buffSize - curStrLen < strlen(format_string_map[profile->formats[index]]) 485 + (numEntries != 0 ? 2 : 1)) { 486 /* we don't have room for another, so bail at this point rather than 487 * return a malformed rate string 488 */ 489 break; 490 } 491 if (numEntries++ != 0) { 492 strlcat(buffer, "|", buffSize); 493 } 494 curStrLen = strlcat(buffer, format_string_map[profile->formats[index]], buffSize); 495 } 496 497 return strdup(buffer); 498 } 499 500 char * profile_get_channel_count_strs(const alsa_device_profile* profile) 501 { 502 // FIXME implicit fixed channel count assumption here (FCC_8). 503 // we use only the canonical even number channel position masks. 504 static const char * const out_chans_strs[] = { 505 /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ 506 /* 1 */"AUDIO_CHANNEL_OUT_MONO", 507 /* 2 */"AUDIO_CHANNEL_OUT_STEREO", 508 /* 3 */ /* "AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, 509 /* 4 */"AUDIO_CHANNEL_OUT_QUAD", 510 /* 5 */ /* "AUDIO_CHANNEL_OUT_QUAD|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, 511 /* 6 */"AUDIO_CHANNEL_OUT_5POINT1", 512 /* 7 */ /* "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_BACK_CENTER" */ NULL, 513 /* 8 */"AUDIO_CHANNEL_OUT_7POINT1", 514 /* channel counts greater than this not considered */ 515 }; 516 517 static const char * const in_chans_strs[] = { 518 /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ 519 /* 1 */"AUDIO_CHANNEL_IN_MONO", 520 /* 2 */"AUDIO_CHANNEL_IN_STEREO", 521 /* channel counts greater than this not considered */ 522 }; 523 524 static const char * const index_chans_strs[] = { 525 /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ 526 /* 1 */"AUDIO_CHANNEL_INDEX_MASK_1", 527 /* 2 */"AUDIO_CHANNEL_INDEX_MASK_2", 528 /* 3 */"AUDIO_CHANNEL_INDEX_MASK_3", 529 /* 4 */"AUDIO_CHANNEL_INDEX_MASK_4", 530 /* 5 */"AUDIO_CHANNEL_INDEX_MASK_5", 531 /* 6 */"AUDIO_CHANNEL_INDEX_MASK_6", 532 /* 7 */"AUDIO_CHANNEL_INDEX_MASK_7", 533 /* 8 */"AUDIO_CHANNEL_INDEX_MASK_8", 534 }; 535 536 const bool isOutProfile = profile->direction == PCM_OUT; 537 538 const char * const * const chans_strs = isOutProfile ? out_chans_strs : in_chans_strs; 539 const size_t chans_strs_size = 540 isOutProfile ? ARRAY_SIZE(out_chans_strs) : ARRAY_SIZE(in_chans_strs); 541 542 /* 543 * If we assume each channel string is 26 chars ("AUDIO_CHANNEL_INDEX_MASK_8" is 26) + 1 for, 544 * the "|" delimiter, then we allocate room for 16 strings. 545 */ 546 char buffer[27 * 16 + 1]; /* caution, may need to be expanded */ 547 buffer[0] = '\0'; 548 size_t buffSize = ARRAY_SIZE(buffer); 549 size_t curStrLen = 0; 550 551 /* We currently support MONO and STEREO, and always report STEREO but some (many) 552 * USB Audio Devices may only announce support for MONO (a headset mic for example), or 553 * The total number of output channels. SO, if the device itself doesn't explicitly 554 * support STEREO, append to the channel config strings we are generating. 555 * 556 * The MONO and STEREO positional channel masks are provided for legacy compatibility. 557 * For multichannel (n > 2) we only expose channel index masks. 558 */ 559 // Always support stereo 560 curStrLen = strlcat(buffer, chans_strs[2], buffSize); 561 562 size_t index; 563 unsigned channel_count; 564 for (index = 0; 565 (channel_count = profile->channel_counts[index]) != 0; 566 index++) { 567 568 /* we only show positional information for mono (stereo handled already) */ 569 if (channel_count < chans_strs_size 570 && chans_strs[channel_count] != NULL 571 && channel_count < 2 /* positional only for fewer than 2 channels */) { 572 // account for the '|' and the '\0' 573 if (buffSize - curStrLen < strlen(chans_strs[channel_count]) + 2) { 574 /* we don't have room for another, so bail at this point rather than 575 * return a malformed rate string 576 */ 577 break; 578 } 579 580 strlcat(buffer, "|", buffSize); 581 curStrLen = strlcat(buffer, chans_strs[channel_count], buffSize); 582 } 583 584 // handle channel index masks for both input and output 585 // +2 to account for the '|' and the '\0' 586 if (buffSize - curStrLen < strlen(index_chans_strs[channel_count]) + 2) { 587 /* we don't have room for another, so bail at this point rather than 588 * return a malformed rate string 589 */ 590 break; 591 } 592 593 strlcat(buffer, "|", buffSize); 594 curStrLen = strlcat(buffer, index_chans_strs[channel_count], buffSize); 595 } 596 597 return strdup(buffer); 598 } 599 600 void profile_dump(const alsa_device_profile* profile, int fd) 601 { 602 if (profile == NULL) { 603 dprintf(fd, " %s\n", "No USB Profile"); 604 return; /* bail early */ 605 } 606 607 if (!profile->is_valid) { 608 dprintf(fd, " Profile is INVALID"); 609 } 610 611 /* card/device/direction */ 612 dprintf(fd, " card:%d, device:%d - %s\n", 613 profile->card, profile->device, profile->direction == PCM_OUT ? "OUT" : "IN"); 614 615 /* formats */ 616 dprintf(fd, " Formats: "); 617 for (int fmtIndex = 0; 618 profile->formats[fmtIndex] != PCM_FORMAT_INVALID && fmtIndex < MAX_PROFILE_FORMATS; 619 fmtIndex++) { 620 dprintf(fd, "%d ", profile->formats[fmtIndex]); 621 } 622 dprintf(fd, "\n"); 623 624 /* sample rates */ 625 dprintf(fd, " Rates: "); 626 for (int rateIndex = 0; 627 profile->sample_rates[rateIndex] != 0 && rateIndex < MAX_PROFILE_SAMPLE_RATES; 628 rateIndex++) { 629 dprintf(fd, "%u ", profile->sample_rates[rateIndex]); 630 } 631 dprintf(fd, "\n"); 632 633 // channel counts 634 dprintf(fd, " Channel Counts: "); 635 for (int cntIndex = 0; 636 profile->channel_counts[cntIndex] != 0 && cntIndex < MAX_PROFILE_CHANNEL_COUNTS; 637 cntIndex++) { 638 dprintf(fd, "%u ", profile->channel_counts[cntIndex]); 639 } 640 dprintf(fd, "\n"); 641 642 dprintf(fd, " min/max period size [%u : %u]\n", 643 profile->min_period_size,profile-> max_period_size); 644 dprintf(fd, " min/max channel count [%u : %u]\n", 645 profile->min_channel_count, profile->max_channel_count); 646 647 // struct pcm_config default_config; 648 dprintf(fd, " Default Config:\n"); 649 dprintf(fd, " channels: %d\n", profile->default_config.channels); 650 dprintf(fd, " rate: %d\n", profile->default_config.rate); 651 dprintf(fd, " period_size: %d\n", profile->default_config.period_size); 652 dprintf(fd, " period_count: %d\n", profile->default_config.period_count); 653 dprintf(fd, " format: %d\n", profile->default_config.format); 654 } 655