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