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 #include <algorithm> 18 #include <set> 19 #include <string> 20 21 #define LOG_TAG "APM::AudioProfile" 22 //#define LOG_NDEBUG 0 23 24 #include <media/AudioResamplerPublic.h> 25 #include <utils/Errors.h> 26 27 #include "AudioGain.h" 28 #include "AudioPort.h" 29 #include "AudioProfile.h" 30 #include "HwModule.h" 31 #include "TypeConverter.h" 32 33 namespace android { 34 35 ChannelsVector ChannelsVector::asInMask() const 36 { 37 ChannelsVector inMaskVector; 38 for (const auto& channel : *this) { 39 if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) { 40 inMaskVector.add(audio_channel_mask_out_to_in(channel)); 41 } 42 } 43 return inMaskVector; 44 } 45 46 ChannelsVector ChannelsVector::asOutMask() const 47 { 48 ChannelsVector outMaskVector; 49 for (const auto& channel : *this) { 50 if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) { 51 outMaskVector.add(audio_channel_mask_in_to_out(channel)); 52 } 53 } 54 return outMaskVector; 55 } 56 57 bool operator == (const AudioProfile &left, const AudioProfile &compareTo) 58 { 59 return (left.getFormat() == compareTo.getFormat()) && 60 (left.getChannels() == compareTo.getChannels()) && 61 (left.getSampleRates() == compareTo.getSampleRates()); 62 } 63 64 static AudioProfile* createFullDynamicImpl() 65 { 66 AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat, 67 ChannelsVector(), SampleRateVector()); 68 dynamicProfile->setDynamicFormat(true); 69 dynamicProfile->setDynamicChannels(true); 70 dynamicProfile->setDynamicRate(true); 71 return dynamicProfile; 72 } 73 74 // static 75 sp<AudioProfile> AudioProfile::createFullDynamic() 76 { 77 static sp<AudioProfile> dynamicProfile = createFullDynamicImpl(); 78 return dynamicProfile; 79 } 80 81 AudioProfile::AudioProfile(audio_format_t format, 82 audio_channel_mask_t channelMasks, 83 uint32_t samplingRate) : 84 mName(String8("")), 85 mFormat(format) 86 { 87 mChannelMasks.add(channelMasks); 88 mSamplingRates.add(samplingRate); 89 } 90 91 AudioProfile::AudioProfile(audio_format_t format, 92 const ChannelsVector &channelMasks, 93 const SampleRateVector &samplingRateCollection) : 94 mName(String8("")), 95 mFormat(format), 96 mChannelMasks(channelMasks), 97 mSamplingRates(samplingRateCollection) {} 98 99 void AudioProfile::setChannels(const ChannelsVector &channelMasks) 100 { 101 if (mIsDynamicChannels) { 102 mChannelMasks = channelMasks; 103 } 104 } 105 106 void AudioProfile::setSampleRates(const SampleRateVector &sampleRates) 107 { 108 if (mIsDynamicRate) { 109 mSamplingRates = sampleRates; 110 } 111 } 112 113 void AudioProfile::clear() 114 { 115 if (mIsDynamicChannels) { 116 mChannelMasks.clear(); 117 } 118 if (mIsDynamicRate) { 119 mSamplingRates.clear(); 120 } 121 } 122 123 status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask, 124 audio_format_t format) const 125 { 126 if (audio_formats_match(format, mFormat) && 127 supportsChannels(channelMask) && 128 supportsRate(samplingRate)) { 129 return NO_ERROR; 130 } 131 return BAD_VALUE; 132 } 133 134 status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate, 135 uint32_t &updatedSamplingRate) const 136 { 137 ALOG_ASSERT(samplingRate > 0); 138 139 if (mSamplingRates.isEmpty()) { 140 updatedSamplingRate = samplingRate; 141 return NO_ERROR; 142 } 143 144 // Search for the closest supported sampling rate that is above (preferred) 145 // or below (acceptable) the desired sampling rate, within a permitted ratio. 146 // The sampling rates are sorted in ascending order. 147 size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate); 148 149 // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum. 150 if (orderOfDesiredRate < mSamplingRates.size()) { 151 uint32_t candidate = mSamplingRates[orderOfDesiredRate]; 152 if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) { 153 updatedSamplingRate = candidate; 154 return NO_ERROR; 155 } 156 } 157 // But if we have to up-sample from a lower sampling rate, that's OK. 158 if (orderOfDesiredRate != 0) { 159 uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1]; 160 if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) { 161 updatedSamplingRate = candidate; 162 return NO_ERROR; 163 } 164 } 165 // leave updatedSamplingRate unmodified 166 return BAD_VALUE; 167 } 168 169 status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask, 170 audio_channel_mask_t &updatedChannelMask, 171 audio_port_type_t portType, 172 audio_port_role_t portRole) const 173 { 174 if (mChannelMasks.isEmpty()) { 175 updatedChannelMask = channelMask; 176 return NO_ERROR; 177 } 178 const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK; 179 const bool isIndex = audio_channel_mask_get_representation(channelMask) 180 == AUDIO_CHANNEL_REPRESENTATION_INDEX; 181 const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask); 182 int bestMatch = 0; 183 for (size_t i = 0; i < mChannelMasks.size(); i ++) { 184 audio_channel_mask_t supported = mChannelMasks[i]; 185 if (supported == channelMask) { 186 // Exact matches always taken. 187 updatedChannelMask = channelMask; 188 return NO_ERROR; 189 } 190 191 // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support 192 if (isRecordThread && supported != AUDIO_CHANNEL_NONE) { 193 // Approximate (best) match: 194 // The match score measures how well the supported channel mask matches the 195 // desired mask, where increasing-is-better. 196 // 197 // TODO: Some tweaks may be needed. 198 // Should be a static function of the data processing library. 199 // 200 // In priority: 201 // match score = 1000 if legacy channel conversion equivalent (always prefer this) 202 // OR 203 // match score += 100 if the channel mask representations match 204 // match score += number of channels matched. 205 // match score += 100 if the channel mask representations DO NOT match 206 // but the profile has positional channel mask and less than 2 channels. 207 // This is for audio HAL convention to not list index masks for less than 2 channels 208 // 209 // If there are no matched channels, the mask may still be accepted 210 // but the playback or record will be silent. 211 const bool isSupportedIndex = (audio_channel_mask_get_representation(supported) 212 == AUDIO_CHANNEL_REPRESENTATION_INDEX); 213 const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported); 214 int match; 215 if (isIndex && isSupportedIndex) { 216 // index equivalence 217 match = 100 + __builtin_popcount( 218 audio_channel_mask_get_bits(channelMask) 219 & audio_channel_mask_get_bits(supported)); 220 } else if (isIndex && !isSupportedIndex) { 221 const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ; 222 match = __builtin_popcount( 223 audio_channel_mask_get_bits(channelMask) & equivalentBits); 224 if (supportedChannelCount <= FCC_2) { 225 match += 100; 226 } 227 } else if (!isIndex && isSupportedIndex) { 228 const uint32_t equivalentBits = (1 << channelCount) - 1; 229 match = __builtin_popcount( 230 equivalentBits & audio_channel_mask_get_bits(supported)); 231 } else { 232 // positional equivalence 233 match = 100 + __builtin_popcount( 234 audio_channel_mask_get_bits(channelMask) 235 & audio_channel_mask_get_bits(supported)); 236 switch (supported) { 237 case AUDIO_CHANNEL_IN_FRONT_BACK: 238 case AUDIO_CHANNEL_IN_STEREO: 239 if (channelMask == AUDIO_CHANNEL_IN_MONO) { 240 match = 1000; 241 } 242 break; 243 case AUDIO_CHANNEL_IN_MONO: 244 if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK 245 || channelMask == AUDIO_CHANNEL_IN_STEREO) { 246 match = 1000; 247 } 248 break; 249 default: 250 break; 251 } 252 } 253 if (match > bestMatch) { 254 bestMatch = match; 255 updatedChannelMask = supported; 256 } 257 } 258 } 259 return bestMatch > 0 ? NO_ERROR : BAD_VALUE; 260 } 261 262 void AudioProfile::dump(String8 *dst, int spaces) const 263 { 264 dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "", 265 mIsDynamicChannels ? "[dynamic channels]" : "", 266 mIsDynamicRate ? "[dynamic rates]" : ""); 267 if (mName.length() != 0) { 268 dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string()); 269 } 270 std::string formatLiteral; 271 if (FormatConverter::toString(mFormat, formatLiteral)) { 272 dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str()); 273 } 274 if (!mSamplingRates.isEmpty()) { 275 dst->appendFormat("%*s- sampling rates:", spaces, ""); 276 for (size_t i = 0; i < mSamplingRates.size(); i++) { 277 dst->appendFormat("%d", mSamplingRates[i]); 278 dst->append(i == (mSamplingRates.size() - 1) ? "" : ", "); 279 } 280 dst->append("\n"); 281 } 282 283 if (!mChannelMasks.isEmpty()) { 284 dst->appendFormat("%*s- channel masks:", spaces, ""); 285 for (size_t i = 0; i < mChannelMasks.size(); i++) { 286 dst->appendFormat("0x%04x", mChannelMasks[i]); 287 dst->append(i == (mChannelMasks.size() - 1) ? "" : ", "); 288 } 289 dst->append("\n"); 290 } 291 } 292 293 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile) 294 { 295 ssize_t index = Vector::add(profile); 296 // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry. 297 // TODO: compareFormats could be a lambda to convert between pointer-to-format to format: 298 // [](const audio_format_t *format1, const audio_format_t *format2) { 299 // return compareFormats(*format1, *format2); 300 // } 301 sort(compareFormats); 302 return index; 303 } 304 305 ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd) 306 { 307 // Check valid profile to add: 308 if (!profileToAdd->hasValidFormat()) { 309 return -1; 310 } 311 if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) { 312 FormatVector formats; 313 formats.add(profileToAdd->getFormat()); 314 setFormats(FormatVector(formats)); 315 return 0; 316 } 317 if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) { 318 setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat()); 319 return 0; 320 } 321 if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) { 322 setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat()); 323 return 0; 324 } 325 // Go through the list of profile to avoid duplicates 326 for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) { 327 const sp<AudioProfile> &profile = itemAt(profileIndex); 328 if (profile->isValid() && profile == profileToAdd) { 329 // Nothing to do 330 return profileIndex; 331 } 332 } 333 profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal 334 return add(profileToAdd); 335 } 336 337 status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate, 338 audio_channel_mask_t channelMask, 339 audio_format_t format) const 340 { 341 if (isEmpty()) { 342 return NO_ERROR; 343 } 344 345 for (const auto& profile : *this) { 346 if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) { 347 return NO_ERROR; 348 } 349 } 350 return BAD_VALUE; 351 } 352 353 status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate, 354 audio_channel_mask_t &channelMask, 355 audio_format_t &format, 356 audio_port_type_t portType, 357 audio_port_role_t portRole) const 358 { 359 if (isEmpty()) { 360 return NO_ERROR; 361 } 362 363 const bool checkInexact = // when port is input and format is linear pcm 364 portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK 365 && audio_is_linear_pcm(format); 366 367 // iterate from best format to worst format (reverse order) 368 for (ssize_t i = size() - 1; i >= 0 ; --i) { 369 const sp<AudioProfile> profile = itemAt(i); 370 audio_format_t formatToCompare = profile->getFormat(); 371 if (formatToCompare == format || 372 (checkInexact 373 && formatToCompare != AUDIO_FORMAT_DEFAULT 374 && audio_is_linear_pcm(formatToCompare))) { 375 // Compatible profile has been found, checks if this profile has compatible 376 // rate and channels as well 377 audio_channel_mask_t updatedChannels; 378 uint32_t updatedRate; 379 if (profile->checkCompatibleChannelMask(channelMask, updatedChannels, 380 portType, portRole) == NO_ERROR && 381 profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) { 382 // for inexact checks we take the first linear pcm format due to sorting. 383 format = formatToCompare; 384 channelMask = updatedChannels; 385 samplingRate = updatedRate; 386 return NO_ERROR; 387 } 388 } 389 } 390 return BAD_VALUE; 391 } 392 393 void AudioProfileVector::clearProfiles() 394 { 395 for (size_t i = size(); i != 0; ) { 396 sp<AudioProfile> profile = itemAt(--i); 397 if (profile->isDynamicFormat() && profile->hasValidFormat()) { 398 removeAt(i); 399 continue; 400 } 401 profile->clear(); 402 } 403 } 404 405 // Returns an intersection between two possibly unsorted vectors and the contents of 'order'. 406 // The result is ordered according to 'order'. 407 template<typename T, typename Order> 408 std::vector<typename T::value_type> intersectFilterAndOrder( 409 const T& input1, const T& input2, const Order& order) 410 { 411 std::set<typename T::value_type> set1{input1.begin(), input1.end()}; 412 std::set<typename T::value_type> set2{input2.begin(), input2.end()}; 413 std::set<typename T::value_type> common; 414 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), 415 std::inserter(common, common.begin())); 416 std::vector<typename T::value_type> result; 417 for (const auto& e : order) { 418 if (common.find(e) != common.end()) result.push_back(e); 419 } 420 return result; 421 } 422 423 // Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering. 424 // 'comp' is a comparator function. 425 template<typename T, typename Compare> 426 std::vector<typename T::value_type> intersectAndOrder( 427 const T& input1, const T& input2, Compare comp) 428 { 429 std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp}; 430 std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp}; 431 std::vector<typename T::value_type> result; 432 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), 433 std::back_inserter(result), comp); 434 return result; 435 } 436 437 status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles, 438 const std::vector<audio_format_t>& preferredFormats, 439 const std::vector<audio_channel_mask_t>& preferredOutputChannels, 440 bool preferHigherSamplingRates, 441 audio_config_base *bestOutputConfig) const 442 { 443 auto formats = intersectFilterAndOrder(getSupportedFormats(), 444 outputProfiles.getSupportedFormats(), preferredFormats); 445 // Pick the best compatible profile. 446 for (const auto& f : formats) { 447 sp<AudioProfile> inputProfile = getFirstValidProfileFor(f); 448 sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f); 449 if (inputProfile == nullptr || outputProfile == nullptr) { 450 continue; 451 } 452 auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(), 453 outputProfile->getChannels(), preferredOutputChannels); 454 if (channels.empty()) { 455 continue; 456 } 457 auto sampleRates = preferHigherSamplingRates ? 458 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(), 459 std::greater<typename SampleRateVector::value_type>()) : 460 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(), 461 std::less<typename SampleRateVector::value_type>()); 462 if (sampleRates.empty()) { 463 continue; 464 } 465 ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.", 466 __func__, *channels.begin(), *sampleRates.begin(), f); 467 bestOutputConfig->format = f; 468 bestOutputConfig->sample_rate = *sampleRates.begin(); 469 bestOutputConfig->channel_mask = *channels.begin(); 470 return NO_ERROR; 471 } 472 return BAD_VALUE; 473 } 474 475 sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const 476 { 477 for (size_t i = 0; i < size(); i++) { 478 if (itemAt(i)->isValid()) { 479 return itemAt(i); 480 } 481 } 482 return 0; 483 } 484 485 sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const 486 { 487 for (size_t i = 0; i < size(); i++) { 488 if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) { 489 return itemAt(i); 490 } 491 } 492 return 0; 493 } 494 495 FormatVector AudioProfileVector::getSupportedFormats() const 496 { 497 FormatVector supportedFormats; 498 for (size_t i = 0; i < size(); i++) { 499 if (itemAt(i)->hasValidFormat()) { 500 supportedFormats.add(itemAt(i)->getFormat()); 501 } 502 } 503 return supportedFormats; 504 } 505 506 bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const 507 { 508 for (size_t i = 0; i < size(); i++) { 509 sp<AudioProfile> profile = itemAt(i); 510 if (profile->getFormat() == format && profile->isDynamicChannels()) { 511 return true; 512 } 513 } 514 return false; 515 } 516 517 bool AudioProfileVector::hasDynamicProfile() const 518 { 519 for (size_t i = 0; i < size(); i++) { 520 if (itemAt(i)->isDynamic()) { 521 return true; 522 } 523 } 524 return false; 525 } 526 527 bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const 528 { 529 for (size_t i = 0; i < size(); i++) { 530 sp<AudioProfile> profile = itemAt(i); 531 if (profile->getFormat() == format && profile->isDynamicRate()) { 532 return true; 533 } 534 } 535 return false; 536 } 537 538 void AudioProfileVector::setFormats(const FormatVector &formats) 539 { 540 // Only allow to change the format of dynamic profile 541 sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat); 542 if (dynamicFormatProfile == 0) { 543 return; 544 } 545 for (size_t i = 0; i < formats.size(); i++) { 546 sp<AudioProfile> profile = new AudioProfile(formats[i], 547 dynamicFormatProfile->getChannels(), 548 dynamicFormatProfile->getSampleRates()); 549 profile->setDynamicFormat(true); 550 profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels()); 551 profile->setDynamicRate(dynamicFormatProfile->isDynamicRate()); 552 add(profile); 553 } 554 } 555 556 void AudioProfileVector::dump(String8 *dst, int spaces) const 557 { 558 dst->appendFormat("%*s- Profiles:\n", spaces, ""); 559 for (size_t i = 0; i < size(); i++) { 560 dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i); 561 itemAt(i)->dump(dst, spaces + 8); 562 } 563 } 564 565 sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const 566 { 567 for (size_t i = 0; i < size(); i++) { 568 if (itemAt(i)->getFormat() == format) { 569 return itemAt(i); 570 } 571 } 572 return 0; 573 } 574 575 void AudioProfileVector::setSampleRatesFor( 576 const SampleRateVector &sampleRates, audio_format_t format) 577 { 578 for (size_t i = 0; i < size(); i++) { 579 sp<AudioProfile> profile = itemAt(i); 580 if (profile->getFormat() == format && profile->isDynamicRate()) { 581 if (profile->hasValidRates()) { 582 // Need to create a new profile with same format 583 sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(), 584 sampleRates); 585 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning 586 add(profileToAdd); 587 } else { 588 profile->setSampleRates(sampleRates); 589 } 590 return; 591 } 592 } 593 } 594 595 void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format) 596 { 597 for (size_t i = 0; i < size(); i++) { 598 sp<AudioProfile> profile = itemAt(i); 599 if (profile->getFormat() == format && profile->isDynamicChannels()) { 600 if (profile->hasValidChannels()) { 601 // Need to create a new profile with same format 602 sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks, 603 profile->getSampleRates()); 604 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning 605 add(profileToAdd); 606 } else { 607 profile->setChannels(channelMasks); 608 } 609 return; 610 } 611 } 612 } 613 614 // static 615 int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1, 616 const sp<AudioProfile> *profile2) 617 { 618 return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat()); 619 } 620 621 } // namespace android 622