AudioPort.cpp revision 322b4d25387a04c9afebe998326d005bbdf17ede
1/* 2 * Copyright (C) 2015 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 "APM::AudioPort" 18//#define LOG_NDEBUG 0 19 20#include "AudioPort.h" 21#include "HwModule.h" 22#include "AudioGain.h" 23#include "ConfigParsingUtils.h" 24#include "audio_policy_conf.h" 25#include <policy.h> 26 27namespace android { 28 29int32_t volatile AudioPort::mNextUniqueId = 1; 30 31// --- AudioPort class implementation 32 33AudioPort::AudioPort(const String8& name, audio_port_type_t type, 34 audio_port_role_t role) : 35 mName(name), mType(type), mRole(role), mFlags(0) 36{ 37 mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) || 38 ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK)); 39} 40 41void AudioPort::attach(const sp<HwModule>& module) 42{ 43 mModule = module; 44} 45 46audio_port_handle_t AudioPort::getNextUniqueId() 47{ 48 return static_cast<audio_port_handle_t>(android_atomic_inc(&mNextUniqueId)); 49} 50 51audio_module_handle_t AudioPort::getModuleHandle() const 52{ 53 if (mModule == 0) { 54 return 0; 55 } 56 return mModule->mHandle; 57} 58 59uint32_t AudioPort::getModuleVersion() const 60{ 61 if (mModule == 0) { 62 return 0; 63 } 64 return mModule->mHalVersion; 65} 66 67const char *AudioPort::getModuleName() const 68{ 69 if (mModule == 0) { 70 return ""; 71 } 72 return mModule->mName; 73} 74 75void AudioPort::toAudioPort(struct audio_port *port) const 76{ 77 port->role = mRole; 78 port->type = mType; 79 strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN); 80 unsigned int i; 81 for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) { 82 if (mSamplingRates[i] != 0) { 83 port->sample_rates[i] = mSamplingRates[i]; 84 } 85 } 86 port->num_sample_rates = i; 87 for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) { 88 if (mChannelMasks[i] != 0) { 89 port->channel_masks[i] = mChannelMasks[i]; 90 } 91 } 92 port->num_channel_masks = i; 93 for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) { 94 if (mFormats[i] != 0) { 95 port->formats[i] = mFormats[i]; 96 } 97 } 98 port->num_formats = i; 99 100 ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size()); 101 102 for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) { 103 port->gains[i] = mGains[i]->mGain; 104 } 105 port->num_gains = i; 106} 107 108void AudioPort::importAudioPort(const sp<AudioPort> port) { 109 for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) { 110 const uint32_t rate = port->mSamplingRates.itemAt(k); 111 if (rate != 0) { // skip "dynamic" rates 112 bool hasRate = false; 113 for (size_t l = 0 ; l < mSamplingRates.size() ; l++) { 114 if (rate == mSamplingRates.itemAt(l)) { 115 hasRate = true; 116 break; 117 } 118 } 119 if (!hasRate) { // never import a sampling rate twice 120 mSamplingRates.add(rate); 121 } 122 } 123 } 124 for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) { 125 const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k); 126 if (mask != 0) { // skip "dynamic" masks 127 bool hasMask = false; 128 for (size_t l = 0 ; l < mChannelMasks.size() ; l++) { 129 if (mask == mChannelMasks.itemAt(l)) { 130 hasMask = true; 131 break; 132 } 133 } 134 if (!hasMask) { // never import a channel mask twice 135 mChannelMasks.add(mask); 136 } 137 } 138 } 139 for (size_t k = 0 ; k < port->mFormats.size() ; k++) { 140 const audio_format_t format = port->mFormats.itemAt(k); 141 if (format != 0) { // skip "dynamic" formats 142 bool hasFormat = false; 143 for (size_t l = 0 ; l < mFormats.size() ; l++) { 144 if (format == mFormats.itemAt(l)) { 145 hasFormat = true; 146 break; 147 } 148 } 149 if (!hasFormat) { // never import a channel mask twice 150 mFormats.add(format); 151 } 152 } 153 } 154 for (size_t k = 0 ; k < port->mGains.size() ; k++) { 155 sp<AudioGain> gain = port->mGains.itemAt(k); 156 if (gain != 0) { 157 bool hasGain = false; 158 for (size_t l = 0 ; l < mGains.size() ; l++) { 159 if (gain == mGains.itemAt(l)) { 160 hasGain = true; 161 break; 162 } 163 } 164 if (!hasGain) { // never import a gain twice 165 mGains.add(gain); 166 } 167 } 168 } 169} 170 171void AudioPort::clearCapabilities() { 172 mChannelMasks.clear(); 173 mFormats.clear(); 174 mSamplingRates.clear(); 175 mGains.clear(); 176} 177 178void AudioPort::loadSamplingRates(char *name) 179{ 180 char *str = strtok(name, "|"); 181 182 // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling 183 // rates should be read from the output stream after it is opened for the first time 184 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { 185 mSamplingRates.add(0); 186 return; 187 } 188 189 while (str != NULL) { 190 uint32_t rate = atoi(str); 191 if (rate != 0) { 192 ALOGV("loadSamplingRates() adding rate %d", rate); 193 mSamplingRates.add(rate); 194 } 195 str = strtok(NULL, "|"); 196 } 197} 198 199void AudioPort::loadFormats(char *name) 200{ 201 char *str = strtok(name, "|"); 202 203 // by convention, "0' in the first entry in mFormats indicates the supported formats 204 // should be read from the output stream after it is opened for the first time 205 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { 206 mFormats.add(AUDIO_FORMAT_DEFAULT); 207 return; 208 } 209 210 while (str != NULL) { 211 audio_format_t format = (audio_format_t)ConfigParsingUtils::stringToEnum(sFormatNameToEnumTable, 212 ARRAY_SIZE(sFormatNameToEnumTable), 213 str); 214 if (format != AUDIO_FORMAT_DEFAULT) { 215 mFormats.add(format); 216 } 217 str = strtok(NULL, "|"); 218 } 219} 220 221void AudioPort::loadInChannels(char *name) 222{ 223 const char *str = strtok(name, "|"); 224 225 ALOGV("loadInChannels() %s", name); 226 227 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { 228 mChannelMasks.add(0); 229 return; 230 } 231 232 while (str != NULL) { 233 audio_channel_mask_t channelMask = 234 (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable, 235 ARRAY_SIZE(sInChannelsNameToEnumTable), 236 str); 237 if (channelMask != 0) { 238 ALOGV("loadInChannels() adding channelMask %04x", channelMask); 239 mChannelMasks.add(channelMask); 240 } 241 str = strtok(NULL, "|"); 242 } 243} 244 245void AudioPort::loadOutChannels(char *name) 246{ 247 const char *str = strtok(name, "|"); 248 249 ALOGV("loadOutChannels() %s", name); 250 251 // by convention, "0' in the first entry in mChannelMasks indicates the supported channel 252 // masks should be read from the output stream after it is opened for the first time 253 if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) { 254 mChannelMasks.add(0); 255 return; 256 } 257 258 while (str != NULL) { 259 audio_channel_mask_t channelMask = 260 (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable, 261 ARRAY_SIZE(sOutChannelsNameToEnumTable), 262 str); 263 if (channelMask != 0) { 264 mChannelMasks.add(channelMask); 265 } 266 str = strtok(NULL, "|"); 267 } 268 return; 269} 270 271audio_gain_mode_t AudioPort::loadGainMode(char *name) 272{ 273 const char *str = strtok(name, "|"); 274 275 ALOGV("loadGainMode() %s", name); 276 audio_gain_mode_t mode = 0; 277 while (str != NULL) { 278 mode |= (audio_gain_mode_t)ConfigParsingUtils::stringToEnum(sGainModeNameToEnumTable, 279 ARRAY_SIZE(sGainModeNameToEnumTable), 280 str); 281 str = strtok(NULL, "|"); 282 } 283 return mode; 284} 285 286void AudioPort::loadGain(cnode *root, int index) 287{ 288 cnode *node = root->first_child; 289 290 sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask); 291 292 while (node) { 293 if (strcmp(node->name, GAIN_MODE) == 0) { 294 gain->mGain.mode = loadGainMode((char *)node->value); 295 } else if (strcmp(node->name, GAIN_CHANNELS) == 0) { 296 if (mUseInChannelMask) { 297 gain->mGain.channel_mask = 298 (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable, 299 ARRAY_SIZE(sInChannelsNameToEnumTable), 300 (char *)node->value); 301 } else { 302 gain->mGain.channel_mask = 303 (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable, 304 ARRAY_SIZE(sOutChannelsNameToEnumTable), 305 (char *)node->value); 306 } 307 } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) { 308 gain->mGain.min_value = atoi((char *)node->value); 309 } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) { 310 gain->mGain.max_value = atoi((char *)node->value); 311 } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) { 312 gain->mGain.default_value = atoi((char *)node->value); 313 } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) { 314 gain->mGain.step_value = atoi((char *)node->value); 315 } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) { 316 gain->mGain.min_ramp_ms = atoi((char *)node->value); 317 } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) { 318 gain->mGain.max_ramp_ms = atoi((char *)node->value); 319 } 320 node = node->next; 321 } 322 323 ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d", 324 gain->mGain.mode, gain->mGain.channel_mask, gain->mGain.min_value, gain->mGain.max_value); 325 326 if (gain->mGain.mode == 0) { 327 return; 328 } 329 mGains.add(gain); 330} 331 332void AudioPort::loadGains(cnode *root) 333{ 334 cnode *node = root->first_child; 335 int index = 0; 336 while (node) { 337 ALOGV("loadGains() loading gain %s", node->name); 338 loadGain(node, index++); 339 node = node->next; 340 } 341} 342 343status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const 344{ 345 if (mSamplingRates.isEmpty()) { 346 return NO_ERROR; 347 } 348 349 for (size_t i = 0; i < mSamplingRates.size(); i ++) { 350 if (mSamplingRates[i] == samplingRate) { 351 return NO_ERROR; 352 } 353 } 354 return BAD_VALUE; 355} 356 357status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate, 358 uint32_t *updatedSamplingRate) const 359{ 360 if (mSamplingRates.isEmpty()) { 361 return NO_ERROR; 362 } 363 364 // Search for the closest supported sampling rate that is above (preferred) 365 // or below (acceptable) the desired sampling rate, within a permitted ratio. 366 // The sampling rates do not need to be sorted in ascending order. 367 ssize_t maxBelow = -1; 368 ssize_t minAbove = -1; 369 uint32_t candidate; 370 for (size_t i = 0; i < mSamplingRates.size(); i++) { 371 candidate = mSamplingRates[i]; 372 if (candidate == samplingRate) { 373 if (updatedSamplingRate != NULL) { 374 *updatedSamplingRate = candidate; 375 } 376 return NO_ERROR; 377 } 378 // candidate < desired 379 if (candidate < samplingRate) { 380 if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) { 381 maxBelow = i; 382 } 383 // candidate > desired 384 } else { 385 if (minAbove < 0 || candidate < mSamplingRates[minAbove]) { 386 minAbove = i; 387 } 388 } 389 } 390 // This uses hard-coded knowledge about AudioFlinger resampling ratios. 391 // TODO Move these assumptions out. 392 static const uint32_t kMaxDownSampleRatio = 6; // beyond this aliasing occurs 393 static const uint32_t kMaxUpSampleRatio = 256; // beyond this sample rate inaccuracies occur 394 // due to approximation by an int32_t of the 395 // phase increments 396 // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum. 397 if (minAbove >= 0) { 398 candidate = mSamplingRates[minAbove]; 399 if (candidate / kMaxDownSampleRatio <= samplingRate) { 400 if (updatedSamplingRate != NULL) { 401 *updatedSamplingRate = candidate; 402 } 403 return NO_ERROR; 404 } 405 } 406 // But if we have to up-sample from a lower sampling rate, that's OK. 407 if (maxBelow >= 0) { 408 candidate = mSamplingRates[maxBelow]; 409 if (candidate * kMaxUpSampleRatio >= samplingRate) { 410 if (updatedSamplingRate != NULL) { 411 *updatedSamplingRate = candidate; 412 } 413 return NO_ERROR; 414 } 415 } 416 // leave updatedSamplingRate unmodified 417 return BAD_VALUE; 418} 419 420status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const 421{ 422 if (mChannelMasks.isEmpty()) { 423 return NO_ERROR; 424 } 425 426 for (size_t i = 0; i < mChannelMasks.size(); i++) { 427 if (mChannelMasks[i] == channelMask) { 428 return NO_ERROR; 429 } 430 } 431 return BAD_VALUE; 432} 433 434status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) 435 const 436{ 437 if (mChannelMasks.isEmpty()) { 438 return NO_ERROR; 439 } 440 441 const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK; 442 for (size_t i = 0; i < mChannelMasks.size(); i ++) { 443 // FIXME Does not handle multi-channel automatic conversions yet 444 audio_channel_mask_t supported = mChannelMasks[i]; 445 if (supported == channelMask) { 446 return NO_ERROR; 447 } 448 if (isRecordThread) { 449 // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix. 450 // FIXME Abstract this out to a table. 451 if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO) 452 && channelMask == AUDIO_CHANNEL_IN_MONO) || 453 (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK 454 || channelMask == AUDIO_CHANNEL_IN_STEREO))) { 455 return NO_ERROR; 456 } 457 } 458 } 459 return BAD_VALUE; 460} 461 462status_t AudioPort::checkFormat(audio_format_t format) const 463{ 464 if (mFormats.isEmpty()) { 465 return NO_ERROR; 466 } 467 468 for (size_t i = 0; i < mFormats.size(); i ++) { 469 if (mFormats[i] == format) { 470 return NO_ERROR; 471 } 472 } 473 return BAD_VALUE; 474} 475 476 477uint32_t AudioPort::pickSamplingRate() const 478{ 479 // special case for uninitialized dynamic profile 480 if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) { 481 return 0; 482 } 483 484 // For direct outputs, pick minimum sampling rate: this helps ensuring that the 485 // channel count / sampling rate combination chosen will be supported by the connected 486 // sink 487 if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) && 488 (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) { 489 uint32_t samplingRate = UINT_MAX; 490 for (size_t i = 0; i < mSamplingRates.size(); i ++) { 491 if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) { 492 samplingRate = mSamplingRates[i]; 493 } 494 } 495 return (samplingRate == UINT_MAX) ? 0 : samplingRate; 496 } 497 498 uint32_t samplingRate = 0; 499 uint32_t maxRate = MAX_MIXER_SAMPLING_RATE; 500 501 // For mixed output and inputs, use max mixer sampling rates. Do not 502 // limit sampling rate otherwise 503 if (mType != AUDIO_PORT_TYPE_MIX) { 504 maxRate = UINT_MAX; 505 } 506 for (size_t i = 0; i < mSamplingRates.size(); i ++) { 507 if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) { 508 samplingRate = mSamplingRates[i]; 509 } 510 } 511 return samplingRate; 512} 513 514audio_channel_mask_t AudioPort::pickChannelMask() const 515{ 516 // special case for uninitialized dynamic profile 517 if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) { 518 return AUDIO_CHANNEL_NONE; 519 } 520 audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE; 521 522 // For direct outputs, pick minimum channel count: this helps ensuring that the 523 // channel count / sampling rate combination chosen will be supported by the connected 524 // sink 525 if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) && 526 (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) { 527 uint32_t channelCount = UINT_MAX; 528 for (size_t i = 0; i < mChannelMasks.size(); i ++) { 529 uint32_t cnlCount; 530 if (mUseInChannelMask) { 531 cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]); 532 } else { 533 cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]); 534 } 535 if ((cnlCount < channelCount) && (cnlCount > 0)) { 536 channelMask = mChannelMasks[i]; 537 channelCount = cnlCount; 538 } 539 } 540 return channelMask; 541 } 542 543 uint32_t channelCount = 0; 544 uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT; 545 546 // For mixed output and inputs, use max mixer channel count. Do not 547 // limit channel count otherwise 548 if (mType != AUDIO_PORT_TYPE_MIX) { 549 maxCount = UINT_MAX; 550 } 551 for (size_t i = 0; i < mChannelMasks.size(); i ++) { 552 uint32_t cnlCount; 553 if (mUseInChannelMask) { 554 cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]); 555 } else { 556 cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]); 557 } 558 if ((cnlCount > channelCount) && (cnlCount <= maxCount)) { 559 channelMask = mChannelMasks[i]; 560 channelCount = cnlCount; 561 } 562 } 563 return channelMask; 564} 565 566/* format in order of increasing preference */ 567const audio_format_t AudioPort::sPcmFormatCompareTable[] = { 568 AUDIO_FORMAT_DEFAULT, 569 AUDIO_FORMAT_PCM_16_BIT, 570 AUDIO_FORMAT_PCM_8_24_BIT, 571 AUDIO_FORMAT_PCM_24_BIT_PACKED, 572 AUDIO_FORMAT_PCM_32_BIT, 573 AUDIO_FORMAT_PCM_FLOAT, 574}; 575 576int AudioPort::compareFormats(audio_format_t format1, 577 audio_format_t format2) 578{ 579 // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any 580 // compressed format and better than any PCM format. This is by design of pickFormat() 581 if (!audio_is_linear_pcm(format1)) { 582 if (!audio_is_linear_pcm(format2)) { 583 return 0; 584 } 585 return 1; 586 } 587 if (!audio_is_linear_pcm(format2)) { 588 return -1; 589 } 590 591 int index1 = -1, index2 = -1; 592 for (size_t i = 0; 593 (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1)); 594 i ++) { 595 if (sPcmFormatCompareTable[i] == format1) { 596 index1 = i; 597 } 598 if (sPcmFormatCompareTable[i] == format2) { 599 index2 = i; 600 } 601 } 602 // format1 not found => index1 < 0 => format2 > format1 603 // format2 not found => index2 < 0 => format2 < format1 604 return index1 - index2; 605} 606 607audio_format_t AudioPort::pickFormat() const 608{ 609 // special case for uninitialized dynamic profile 610 if (mFormats.size() == 1 && mFormats[0] == 0) { 611 return AUDIO_FORMAT_DEFAULT; 612 } 613 614 audio_format_t format = AUDIO_FORMAT_DEFAULT; 615 audio_format_t bestFormat = 616 AudioPort::sPcmFormatCompareTable[ 617 ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1]; 618 // For mixed output and inputs, use best mixer output format. Do not 619 // limit format otherwise 620 if ((mType != AUDIO_PORT_TYPE_MIX) || 621 ((mRole == AUDIO_PORT_ROLE_SOURCE) && 622 (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) { 623 bestFormat = AUDIO_FORMAT_INVALID; 624 } 625 626 for (size_t i = 0; i < mFormats.size(); i ++) { 627 if ((compareFormats(mFormats[i], format) > 0) && 628 (compareFormats(mFormats[i], bestFormat) <= 0)) { 629 format = mFormats[i]; 630 } 631 } 632 return format; 633} 634 635status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, 636 int index) const 637{ 638 if (index < 0 || (size_t)index >= mGains.size()) { 639 return BAD_VALUE; 640 } 641 return mGains[index]->checkConfig(gainConfig); 642} 643 644void AudioPort::dump(int fd, int spaces) const 645{ 646 const size_t SIZE = 256; 647 char buffer[SIZE]; 648 String8 result; 649 650 if (mName.length() != 0) { 651 snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string()); 652 result.append(buffer); 653 } 654 655 if (mSamplingRates.size() != 0) { 656 snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, ""); 657 result.append(buffer); 658 for (size_t i = 0; i < mSamplingRates.size(); i++) { 659 if (i == 0 && mSamplingRates[i] == 0) { 660 snprintf(buffer, SIZE, "Dynamic"); 661 } else { 662 snprintf(buffer, SIZE, "%d", mSamplingRates[i]); 663 } 664 result.append(buffer); 665 result.append(i == (mSamplingRates.size() - 1) ? "" : ", "); 666 } 667 result.append("\n"); 668 } 669 670 if (mChannelMasks.size() != 0) { 671 snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, ""); 672 result.append(buffer); 673 for (size_t i = 0; i < mChannelMasks.size(); i++) { 674 ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]); 675 676 if (i == 0 && mChannelMasks[i] == 0) { 677 snprintf(buffer, SIZE, "Dynamic"); 678 } else { 679 snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]); 680 } 681 result.append(buffer); 682 result.append(i == (mChannelMasks.size() - 1) ? "" : ", "); 683 } 684 result.append("\n"); 685 } 686 687 if (mFormats.size() != 0) { 688 snprintf(buffer, SIZE, "%*s- formats: ", spaces, ""); 689 result.append(buffer); 690 for (size_t i = 0; i < mFormats.size(); i++) { 691 const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable, 692 ARRAY_SIZE(sFormatNameToEnumTable), 693 mFormats[i]); 694 if (i == 0 && strcmp(formatStr, "") == 0) { 695 snprintf(buffer, SIZE, "Dynamic"); 696 } else { 697 snprintf(buffer, SIZE, "%s", formatStr); 698 } 699 result.append(buffer); 700 result.append(i == (mFormats.size() - 1) ? "" : ", "); 701 } 702 result.append("\n"); 703 } 704 write(fd, result.string(), result.size()); 705 if (mGains.size() != 0) { 706 snprintf(buffer, SIZE, "%*s- gains:\n", spaces, ""); 707 write(fd, buffer, strlen(buffer) + 1); 708 for (size_t i = 0; i < mGains.size(); i++) { 709 mGains[i]->dump(fd, spaces + 2, i); 710 } 711 } 712} 713 714void AudioPort::log(const char* indent) const 715{ 716 ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole); 717} 718 719// --- AudioPortConfig class implementation 720 721AudioPortConfig::AudioPortConfig() 722{ 723 mSamplingRate = 0; 724 mChannelMask = AUDIO_CHANNEL_NONE; 725 mFormat = AUDIO_FORMAT_INVALID; 726 mGain.index = -1; 727} 728 729status_t AudioPortConfig::applyAudioPortConfig( 730 const struct audio_port_config *config, 731 struct audio_port_config *backupConfig) 732{ 733 struct audio_port_config localBackupConfig; 734 status_t status = NO_ERROR; 735 736 localBackupConfig.config_mask = config->config_mask; 737 toAudioPortConfig(&localBackupConfig); 738 739 sp<AudioPort> audioport = getAudioPort(); 740 if (audioport == 0) { 741 status = NO_INIT; 742 goto exit; 743 } 744 if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) { 745 status = audioport->checkExactSamplingRate(config->sample_rate); 746 if (status != NO_ERROR) { 747 goto exit; 748 } 749 mSamplingRate = config->sample_rate; 750 } 751 if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) { 752 status = audioport->checkExactChannelMask(config->channel_mask); 753 if (status != NO_ERROR) { 754 goto exit; 755 } 756 mChannelMask = config->channel_mask; 757 } 758 if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) { 759 status = audioport->checkFormat(config->format); 760 if (status != NO_ERROR) { 761 goto exit; 762 } 763 mFormat = config->format; 764 } 765 if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) { 766 status = audioport->checkGain(&config->gain, config->gain.index); 767 if (status != NO_ERROR) { 768 goto exit; 769 } 770 mGain = config->gain; 771 } 772 773exit: 774 if (status != NO_ERROR) { 775 applyAudioPortConfig(&localBackupConfig); 776 } 777 if (backupConfig != NULL) { 778 *backupConfig = localBackupConfig; 779 } 780 return status; 781} 782 783void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig, 784 const struct audio_port_config *srcConfig) const 785{ 786 if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) { 787 dstConfig->sample_rate = mSamplingRate; 788 if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) { 789 dstConfig->sample_rate = srcConfig->sample_rate; 790 } 791 } else { 792 dstConfig->sample_rate = 0; 793 } 794 if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) { 795 dstConfig->channel_mask = mChannelMask; 796 if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) { 797 dstConfig->channel_mask = srcConfig->channel_mask; 798 } 799 } else { 800 dstConfig->channel_mask = AUDIO_CHANNEL_NONE; 801 } 802 if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) { 803 dstConfig->format = mFormat; 804 if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) { 805 dstConfig->format = srcConfig->format; 806 } 807 } else { 808 dstConfig->format = AUDIO_FORMAT_INVALID; 809 } 810 if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) { 811 dstConfig->gain = mGain; 812 if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) { 813 dstConfig->gain = srcConfig->gain; 814 } 815 } else { 816 dstConfig->gain.index = -1; 817 } 818 if (dstConfig->gain.index != -1) { 819 dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN; 820 } else { 821 dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN; 822 } 823} 824 825}; // namespace android 826