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