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 26 #include <log/log.h> 27 28 #include "alsa_device_profile.h" 29 #include "format.h" 30 #include "logging.h" 31 32 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 33 34 /*TODO - Evaluate if this value should/can be retrieved from a device-specific property */ 35 #define BUFF_DURATION_MS 5 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 static const unsigned const format_byte_size_map[] = { 48 2, /* PCM_FORMAT_S16_LE */ 49 4, /* PCM_FORMAT_S32_LE */ 50 1, /* PCM_FORMAT_S8 */ 51 4, /* PCM_FORMAT_S24_LE */ 52 3, /* PCM_FORMAT_S24_3LE */ 53 }; 54 55 extern int8_t const pcm_format_value_map[50]; 56 57 /* sort these highest -> lowest (to default to best quality) */ 58 static const unsigned std_sample_rates[] = 59 {48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000}; 60 61 void profile_init(alsa_device_profile* profile, int direction) 62 { 63 profile->card = profile->device = -1; 64 profile->direction = direction; 65 66 /* Fill the attribute arrays with invalid values */ 67 size_t index; 68 for (index = 0; index < ARRAY_SIZE(profile->formats); index++) { 69 profile->formats[index] = PCM_FORMAT_INVALID; 70 } 71 72 for (index = 0; index < ARRAY_SIZE(profile->sample_rates); index++) { 73 profile->sample_rates[index] = 0; 74 } 75 76 for (index = 0; index < ARRAY_SIZE(profile->channel_counts); index++) { 77 profile->channel_counts[index] = 0; 78 } 79 80 profile->min_period_size = profile->max_period_size = 0; 81 profile->min_channel_count = profile->max_channel_count = DEFAULT_CHANNEL_COUNT; 82 83 profile->is_valid = false; 84 } 85 86 bool profile_is_initialized(alsa_device_profile* profile) 87 { 88 return profile->card >= 0 && profile->device >= 0; 89 } 90 91 bool profile_is_valid(alsa_device_profile* profile) { 92 return profile->is_valid; 93 } 94 95 bool profile_is_cached_for(alsa_device_profile* profile, int card, int device) { 96 return card == profile->card && device == profile->device; 97 } 98 99 void profile_decache(alsa_device_profile* profile) { 100 profile->card = profile->device = -1; 101 } 102 103 /* 104 * Returns the supplied value rounded up to the next even multiple of 16 105 */ 106 static unsigned int round_to_16_mult(unsigned int size) 107 { 108 return (size + 15) & ~15; // 0xFFFFFFF0; 109 } 110 111 /* 112 * Returns the system defined minimum period size based on the supplied sample rate. 113 */ 114 unsigned profile_calc_min_period_size(alsa_device_profile* profile, unsigned sample_rate) 115 { 116 ALOGV("profile_calc_min_period_size(%p, rate:%d)", profile, sample_rate); 117 if (profile == NULL) { 118 return DEFAULT_PERIOD_SIZE; 119 } else { 120 unsigned num_sample_frames = (sample_rate * BUFF_DURATION_MS) / 1000; 121 if (num_sample_frames < profile->min_period_size) { 122 num_sample_frames = profile->min_period_size; 123 } 124 return round_to_16_mult(num_sample_frames) * 2; 125 } 126 } 127 128 unsigned int profile_get_period_size(alsa_device_profile* profile, unsigned sample_rate) 129 { 130 // return profile->default_config.period_size; 131 unsigned int period_size = profile_calc_min_period_size(profile, sample_rate); 132 ALOGV("profile_get_period_size(rate:%d) = %d", sample_rate, period_size); 133 return period_size; 134 } 135 136 /* 137 * Sample Rate 138 */ 139 unsigned profile_get_default_sample_rate(alsa_device_profile* profile) 140 { 141 /* 142 * TODO this won't be right in general. we should store a preferred rate as we are scanning. 143 * But right now it will return the highest rate, which may be correct. 144 */ 145 return profile_is_valid(profile) ? profile->sample_rates[0] : DEFAULT_SAMPLE_RATE; 146 } 147 148 bool profile_is_sample_rate_valid(alsa_device_profile* profile, unsigned rate) 149 { 150 if (profile_is_valid(profile)) { 151 size_t index; 152 for (index = 0; profile->sample_rates[index] != 0; index++) { 153 if (profile->sample_rates[index] == rate) { 154 return true; 155 } 156 } 157 158 return false; 159 } else { 160 return rate == DEFAULT_SAMPLE_RATE; 161 } 162 } 163 164 /* 165 * Format 166 */ 167 enum pcm_format profile_get_default_format(alsa_device_profile* profile) 168 { 169 /* 170 * TODO this won't be right in general. we should store a preferred format as we are scanning. 171 */ 172 return profile_is_valid(profile) ? profile->formats[0] : DEFAULT_SAMPLE_FORMAT; 173 } 174 175 bool profile_is_format_valid(alsa_device_profile* profile, enum pcm_format fmt) { 176 if (profile_is_valid(profile)) { 177 size_t index; 178 for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { 179 if (profile->formats[index] == fmt) { 180 return true; 181 } 182 } 183 184 return false; 185 } else { 186 return fmt == DEFAULT_SAMPLE_FORMAT; 187 } 188 } 189 190 /* 191 * Channels 192 */ 193 unsigned profile_get_default_channel_count(alsa_device_profile* profile) 194 { 195 return profile_is_valid(profile) ? profile->channel_counts[0] : DEFAULT_CHANNEL_COUNT; 196 } 197 198 bool profile_is_channel_count_valid(alsa_device_profile* profile, unsigned count) 199 { 200 if (profile_is_initialized(profile)) { 201 return count >= profile->min_channel_count && count <= profile->max_channel_count; 202 } else { 203 return count == DEFAULT_CHANNEL_COUNT; 204 } 205 } 206 207 static bool profile_test_sample_rate(alsa_device_profile* profile, unsigned rate) 208 { 209 struct pcm_config config = profile->default_config; 210 config.rate = rate; 211 212 bool works = false; /* let's be pessimistic */ 213 struct pcm * pcm = pcm_open(profile->card, profile->device, 214 profile->direction, &config); 215 216 if (pcm != NULL) { 217 works = pcm_is_ready(pcm); 218 pcm_close(pcm); 219 } 220 221 return works; 222 } 223 224 static unsigned profile_enum_sample_rates(alsa_device_profile* profile, unsigned min, unsigned max) 225 { 226 unsigned num_entries = 0; 227 unsigned index; 228 229 for (index = 0; index < ARRAY_SIZE(std_sample_rates) && 230 num_entries < ARRAY_SIZE(profile->sample_rates) - 1; 231 index++) { 232 if (std_sample_rates[index] >= min && std_sample_rates[index] <= max 233 && profile_test_sample_rate(profile, std_sample_rates[index])) { 234 profile->sample_rates[num_entries++] = std_sample_rates[index]; 235 } 236 } 237 238 return num_entries; /* return # of supported rates */ 239 } 240 241 static unsigned profile_enum_sample_formats(alsa_device_profile* profile, struct pcm_mask * mask) 242 { 243 const int num_slots = ARRAY_SIZE(mask->bits); 244 const int bits_per_slot = sizeof(mask->bits[0]) * 8; 245 246 const int table_size = ARRAY_SIZE(pcm_format_value_map); 247 248 int slot_index, bit_index, table_index; 249 table_index = 0; 250 int num_written = 0; 251 for (slot_index = 0; slot_index < num_slots && table_index < table_size; 252 slot_index++) { 253 unsigned bit_mask = 1; 254 for (bit_index = 0; 255 bit_index < bits_per_slot && table_index < table_size; 256 bit_index++) { 257 if ((mask->bits[slot_index] & bit_mask) != 0) { 258 enum pcm_format format = pcm_format_value_map[table_index]; 259 /* Never return invalid (unrecognized) or 8-bit */ 260 if (format != PCM_FORMAT_INVALID && format != PCM_FORMAT_S8) { 261 profile->formats[num_written++] = format; 262 if (num_written == ARRAY_SIZE(profile->formats) - 1) { 263 /* leave at least one PCM_FORMAT_INVALID at the end */ 264 return num_written; 265 } 266 } 267 } 268 bit_mask <<= 1; 269 table_index++; 270 } 271 } 272 273 return num_written; 274 } 275 276 static unsigned profile_enum_channel_counts(alsa_device_profile* profile, unsigned min, unsigned max) 277 { 278 // TODO: Don't return MONO even if the device supports it. This causes problems 279 // in AudioPolicyManager. Revisit. 280 static const unsigned std_out_channel_counts[] = {8, 4, 2/*, 1*/}; 281 static const unsigned std_in_channel_counts[] = {8, 4, 2, 1}; 282 283 unsigned * channel_counts = 284 profile->direction == PCM_OUT ? std_out_channel_counts : std_in_channel_counts; 285 unsigned num_channel_counts = 286 profile->direction == PCM_OUT 287 ? ARRAY_SIZE(std_out_channel_counts) : ARRAY_SIZE(std_in_channel_counts); 288 289 unsigned num_counts = 0; 290 unsigned index; 291 /* TODO write a profile_test_channel_count() */ 292 /* Ensure there is at least one invalid channel count to terminate the channel counts array */ 293 for (index = 0; index < num_channel_counts && 294 num_counts < ARRAY_SIZE(profile->channel_counts) - 1; 295 index++) { 296 /* TODO Do we want a channel counts test? */ 297 if (channel_counts[index] >= min && channel_counts[index] <= max /* && 298 profile_test_channel_count(profile, channel_counts[index])*/) { 299 profile->channel_counts[num_counts++] = channel_counts[index]; 300 } 301 } 302 303 return num_counts; /* return # of supported counts */ 304 } 305 306 /* 307 * Reads and decodes configuration info from the specified ALSA card/device. 308 */ 309 static int read_alsa_device_config(alsa_device_profile * profile, struct pcm_config * config) 310 { 311 ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)", 312 profile->card, profile->device, profile->direction); 313 314 if (profile->card < 0 || profile->device < 0) { 315 return -EINVAL; 316 } 317 318 struct pcm_params * alsa_hw_params = 319 pcm_params_get(profile->card, profile->device, profile->direction); 320 if (alsa_hw_params == NULL) { 321 return -EINVAL; 322 } 323 324 profile->min_period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); 325 profile->max_period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE); 326 327 profile->min_channel_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 328 profile->max_channel_count = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 329 330 int ret = 0; 331 332 /* 333 * This Logging will be useful when testing new USB devices. 334 */ 335 #ifdef LOG_PCM_PARAMS 336 log_pcm_params(alsa_hw_params); 337 #endif 338 339 config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 340 config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 341 config->period_size = profile_calc_min_period_size(profile, config->rate); 342 config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS); 343 config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); 344 #ifdef LOG_PCM_PARAMS 345 log_pcm_config(config, "read_alsa_device_config"); 346 #endif 347 if (config->format == PCM_FORMAT_INVALID) { 348 ret = -EINVAL; 349 } 350 351 pcm_params_free(alsa_hw_params); 352 353 return ret; 354 } 355 356 bool profile_read_device_info(alsa_device_profile* profile) 357 { 358 if (!profile_is_initialized(profile)) { 359 return false; 360 } 361 362 /* let's get some defaults */ 363 read_alsa_device_config(profile, &profile->default_config); 364 ALOGV("default_config chans:%d rate:%d format:%d count:%d size:%d", 365 profile->default_config.channels, profile->default_config.rate, 366 profile->default_config.format, profile->default_config.period_count, 367 profile->default_config.period_size); 368 369 struct pcm_params * alsa_hw_params = pcm_params_get(profile->card, 370 profile->device, 371 profile->direction); 372 if (alsa_hw_params == NULL) { 373 return false; 374 } 375 376 /* Formats */ 377 struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT); 378 profile_enum_sample_formats(profile, format_mask); 379 380 /* Channels */ 381 profile_enum_channel_counts( 382 profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), 383 pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); 384 385 /* Sample Rates */ 386 profile_enum_sample_rates( 387 profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), 388 pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); 389 390 profile->is_valid = true; 391 392 return true; 393 } 394 395 char * profile_get_sample_rate_strs(alsa_device_profile* profile) 396 { 397 char buffer[128]; 398 buffer[0] = '\0'; 399 int buffSize = ARRAY_SIZE(buffer); 400 401 char numBuffer[32]; 402 403 int numEntries = 0; 404 unsigned index; 405 for (index = 0; profile->sample_rates[index] != 0; index++) { 406 if (numEntries++ != 0) { 407 strncat(buffer, "|", buffSize); 408 } 409 snprintf(numBuffer, sizeof(numBuffer), "%u", profile->sample_rates[index]); 410 strncat(buffer, numBuffer, buffSize); 411 } 412 413 return strdup(buffer); 414 } 415 416 char * profile_get_format_strs(alsa_device_profile* profile) 417 { 418 /* TODO remove this hack when we have support for input in non PCM16 formats */ 419 if (profile->direction == PCM_IN) { 420 return strdup("AUDIO_FORMAT_PCM_16_BIT"); 421 } 422 423 char buffer[128]; 424 buffer[0] = '\0'; 425 int buffSize = ARRAY_SIZE(buffer); 426 427 int numEntries = 0; 428 unsigned index = 0; 429 for (index = 0; profile->formats[index] != PCM_FORMAT_INVALID; index++) { 430 if (numEntries++ != 0) { 431 strncat(buffer, "|", buffSize); 432 } 433 strncat(buffer, format_string_map[profile->formats[index]], buffSize); 434 } 435 436 return strdup(buffer); 437 } 438 439 char * profile_get_channel_count_strs(alsa_device_profile* profile) 440 { 441 static const char * const out_chans_strs[] = { 442 /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ 443 /* 1 */"AUDIO_CHANNEL_OUT_MONO", 444 /* 2 */"AUDIO_CHANNEL_OUT_STEREO", 445 /* 3 */ /* "AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, 446 /* 4 */"AUDIO_CHANNEL_OUT_QUAD", 447 /* 5 */ /* "AUDIO_CHANNEL_OUT_QUAD|AUDIO_CHANNEL_OUT_FRONT_CENTER" */ NULL, 448 /* 6 */"AUDIO_CHANNEL_OUT_5POINT1", 449 /* 7 */ /* "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_BACK_CENTER" */ NULL, 450 /* 8 */"AUDIO_CHANNEL_OUT_7POINT1", 451 /* channel counts greater than this not considered */ 452 }; 453 454 static const char * const in_chans_strs[] = { 455 /* 0 */"AUDIO_CHANNEL_NONE", /* will never be taken as this is a terminator */ 456 /* 1 */"AUDIO_CHANNEL_IN_MONO", 457 /* 2 */"AUDIO_CHANNEL_IN_STEREO", 458 /* channel counts greater than this not considered */ 459 }; 460 461 const bool isOutProfile = profile->direction == PCM_OUT; 462 const char * const * const names_array = isOutProfile ? out_chans_strs : in_chans_strs; 463 const size_t names_size = isOutProfile ? ARRAY_SIZE(out_chans_strs) 464 : ARRAY_SIZE(in_chans_strs); 465 466 char buffer[256]; /* caution, may need to be expanded */ 467 buffer[0] = '\0'; 468 const int buffer_size = ARRAY_SIZE(buffer); 469 int num_entries = 0; 470 bool stereo_allowed = false; 471 unsigned index; 472 unsigned channel_count; 473 474 for (index = 0; (channel_count = profile->channel_counts[index]) != 0; index++) { 475 stereo_allowed = stereo_allowed || channel_count == 2; 476 if (channel_count < names_size && names_array[channel_count] != NULL) { 477 if (num_entries++ != 0) { 478 strncat(buffer, "|", buffer_size); 479 } 480 strncat(buffer, names_array[channel_count], buffer_size); 481 } 482 } 483 /* emulated modes: 484 * always expose stereo as we can emulate it for PCM_OUT 485 */ 486 if (!stereo_allowed && isOutProfile) { 487 if (num_entries++ != 0) { 488 strncat(buffer, "|", buffer_size); 489 } 490 strncat(buffer, names_array[2], buffer_size); /* stereo */ 491 } 492 return strdup(buffer); 493 } 494