Home | History | Annotate | Download | only in src
      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::AudioProfile"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "AudioProfile.h"
     21 #include "AudioPort.h"
     22 #include "HwModule.h"
     23 #include "AudioGain.h"
     24 #include <utils/SortedVector.h>
     25 #include "TypeConverter.h"
     26 #include <media/AudioResamplerPublic.h>
     27 #include <algorithm>
     28 
     29 namespace android {
     30 
     31 status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
     32                                   audio_format_t format) const
     33 {
     34     if (audio_formats_match(format, mFormat) &&
     35             supportsChannels(channelMask) &&
     36             supportsRate(samplingRate)) {
     37         return NO_ERROR;
     38     }
     39     return BAD_VALUE;
     40 }
     41 
     42 template <typename T>
     43 bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
     44 {
     45     if (left.size() != right.size()) {
     46         return false;
     47     }
     48     for(size_t index = 0; index < right.size(); index++) {
     49         if (left[index] != right[index]) {
     50             return false;
     51         }
     52     }
     53     return true;
     54 }
     55 
     56 bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
     57 {
     58     return (left.getFormat() == compareTo.getFormat()) &&
     59             (left.getChannels() == compareTo.getChannels()) &&
     60             (left.getSampleRates() == compareTo.getSampleRates());
     61 }
     62 
     63 status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
     64                                                    uint32_t &updatedSamplingRate) const
     65 {
     66     ALOG_ASSERT(samplingRate > 0);
     67 
     68     if (mSamplingRates.isEmpty()) {
     69         updatedSamplingRate = samplingRate;
     70         return NO_ERROR;
     71     }
     72 
     73     // Search for the closest supported sampling rate that is above (preferred)
     74     // or below (acceptable) the desired sampling rate, within a permitted ratio.
     75     // The sampling rates are sorted in ascending order.
     76     size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
     77 
     78     // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
     79     if (orderOfDesiredRate < mSamplingRates.size()) {
     80         uint32_t candidate = mSamplingRates[orderOfDesiredRate];
     81         if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
     82             updatedSamplingRate = candidate;
     83             return NO_ERROR;
     84         }
     85     }
     86     // But if we have to up-sample from a lower sampling rate, that's OK.
     87     if (orderOfDesiredRate != 0) {
     88         uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
     89         if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
     90             updatedSamplingRate = candidate;
     91             return NO_ERROR;
     92         }
     93     }
     94     // leave updatedSamplingRate unmodified
     95     return BAD_VALUE;
     96 }
     97 
     98 status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
     99                                                   audio_channel_mask_t &updatedChannelMask,
    100                                                   audio_port_type_t portType,
    101                                                   audio_port_role_t portRole) const
    102 {
    103     if (mChannelMasks.isEmpty()) {
    104         updatedChannelMask = channelMask;
    105         return NO_ERROR;
    106     }
    107     const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
    108     const bool isIndex = audio_channel_mask_get_representation(channelMask)
    109             == AUDIO_CHANNEL_REPRESENTATION_INDEX;
    110     int bestMatch = 0;
    111     for (size_t i = 0; i < mChannelMasks.size(); i ++) {
    112         audio_channel_mask_t supported = mChannelMasks[i];
    113         if (supported == channelMask) {
    114             // Exact matches always taken.
    115             updatedChannelMask = channelMask;
    116             return NO_ERROR;
    117         }
    118 
    119         // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
    120         if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
    121             // Approximate (best) match:
    122             // The match score measures how well the supported channel mask matches the
    123             // desired mask, where increasing-is-better.
    124             //
    125             // TODO: Some tweaks may be needed.
    126             // Should be a static function of the data processing library.
    127             //
    128             // In priority:
    129             // match score = 1000 if legacy channel conversion equivalent (always prefer this)
    130             // OR
    131             // match score += 100 if the channel mask representations match
    132             // match score += number of channels matched.
    133             //
    134             // If there are no matched channels, the mask may still be accepted
    135             // but the playback or record will be silent.
    136             const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
    137                     == AUDIO_CHANNEL_REPRESENTATION_INDEX);
    138             int match;
    139             if (isIndex && isSupportedIndex) {
    140                 // index equivalence
    141                 match = 100 + __builtin_popcount(
    142                         audio_channel_mask_get_bits(channelMask)
    143                             & audio_channel_mask_get_bits(supported));
    144             } else if (isIndex && !isSupportedIndex) {
    145                 const uint32_t equivalentBits =
    146                         (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
    147                 match = __builtin_popcount(
    148                         audio_channel_mask_get_bits(channelMask) & equivalentBits);
    149             } else if (!isIndex && isSupportedIndex) {
    150                 const uint32_t equivalentBits =
    151                         (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
    152                 match = __builtin_popcount(
    153                         equivalentBits & audio_channel_mask_get_bits(supported));
    154             } else {
    155                 // positional equivalence
    156                 match = 100 + __builtin_popcount(
    157                         audio_channel_mask_get_bits(channelMask)
    158                             & audio_channel_mask_get_bits(supported));
    159                 switch (supported) {
    160                 case AUDIO_CHANNEL_IN_FRONT_BACK:
    161                 case AUDIO_CHANNEL_IN_STEREO:
    162                     if (channelMask == AUDIO_CHANNEL_IN_MONO) {
    163                         match = 1000;
    164                     }
    165                     break;
    166                 case AUDIO_CHANNEL_IN_MONO:
    167                     if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
    168                             || channelMask == AUDIO_CHANNEL_IN_STEREO) {
    169                         match = 1000;
    170                     }
    171                     break;
    172                 default:
    173                     break;
    174                 }
    175             }
    176             if (match > bestMatch) {
    177                 bestMatch = match;
    178                 updatedChannelMask = supported;
    179             }
    180         }
    181     }
    182     return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
    183 }
    184 
    185 void AudioProfile::dump(int fd, int spaces) const
    186 {
    187     const size_t SIZE = 256;
    188     char buffer[SIZE];
    189     String8 result;
    190 
    191     snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
    192              mIsDynamicChannels ? "[dynamic channels]" : "",
    193              mIsDynamicRate ? "[dynamic rates]" : "");
    194     result.append(buffer);
    195     if (mName.length() != 0) {
    196         snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
    197         result.append(buffer);
    198     }
    199     std::string formatLiteral;
    200     if (FormatConverter::toString(mFormat, formatLiteral)) {
    201         snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
    202         result.append(buffer);
    203     }
    204     if (!mSamplingRates.isEmpty()) {
    205         snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
    206         result.append(buffer);
    207         for (size_t i = 0; i < mSamplingRates.size(); i++) {
    208             snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
    209             result.append(buffer);
    210             result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
    211         }
    212         result.append("\n");
    213     }
    214 
    215     if (!mChannelMasks.isEmpty()) {
    216         snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
    217         result.append(buffer);
    218         for (size_t i = 0; i < mChannelMasks.size(); i++) {
    219             snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
    220             result.append(buffer);
    221             result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
    222         }
    223         result.append("\n");
    224     }
    225     write(fd, result.string(), result.size());
    226 }
    227 
    228 status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
    229                                                audio_channel_mask_t channelMask,
    230                                                audio_format_t format) const
    231 {
    232     if (isEmpty()) {
    233         return NO_ERROR;
    234     }
    235 
    236     for (const auto& profile : *this) {
    237         if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
    238             return NO_ERROR;
    239         }
    240     }
    241     return BAD_VALUE;
    242 }
    243 
    244 status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
    245                                                     audio_channel_mask_t &channelMask,
    246                                                     audio_format_t &format,
    247                                                     audio_port_type_t portType,
    248                                                     audio_port_role_t portRole) const
    249 {
    250     if (isEmpty()) {
    251         return NO_ERROR;
    252     }
    253 
    254     const bool checkInexact = // when port is input and format is linear pcm
    255             portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
    256             && audio_is_linear_pcm(format);
    257 
    258     // iterate from best format to worst format (reverse order)
    259     for (ssize_t i = size() - 1; i >= 0 ; --i) {
    260         const sp<AudioProfile> profile = itemAt(i);
    261         audio_format_t formatToCompare = profile->getFormat();
    262         if (formatToCompare == format ||
    263                 (checkInexact
    264                         && formatToCompare != AUDIO_FORMAT_DEFAULT
    265                         && audio_is_linear_pcm(formatToCompare))) {
    266             // Compatible profile has been found, checks if this profile has compatible
    267             // rate and channels as well
    268             audio_channel_mask_t updatedChannels;
    269             uint32_t updatedRate;
    270             if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
    271                                                     portType, portRole) == NO_ERROR &&
    272                     profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
    273                 // for inexact checks we take the first linear pcm format due to sorting.
    274                 format = formatToCompare;
    275                 channelMask = updatedChannels;
    276                 samplingRate = updatedRate;
    277                 return NO_ERROR;
    278             }
    279         }
    280     }
    281     return BAD_VALUE;
    282 }
    283 
    284 int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
    285                                        const sp<AudioProfile> *profile2)
    286 {
    287     return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
    288 }
    289 
    290 } // namespace android
    291