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 (size_t i = 0; i < size(); i++) { 237 const sp<AudioProfile> profile = itemAt(i); 238 if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) { 239 return NO_ERROR; 240 } 241 } 242 return BAD_VALUE; 243 } 244 245 status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate, 246 audio_channel_mask_t &channelMask, 247 audio_format_t &format, 248 audio_port_type_t portType, 249 audio_port_role_t portRole) const 250 { 251 if (isEmpty()) { 252 return NO_ERROR; 253 } 254 255 const bool checkInexact = // when port is input and format is linear pcm 256 portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK 257 && audio_is_linear_pcm(format); 258 259 // iterate from best format to worst format (reverse order) 260 for (ssize_t i = size() - 1; i >= 0 ; --i) { 261 const sp<AudioProfile> profile = itemAt(i); 262 audio_format_t formatToCompare = profile->getFormat(); 263 if (formatToCompare == format || 264 (checkInexact 265 && formatToCompare != AUDIO_FORMAT_DEFAULT 266 && audio_is_linear_pcm(formatToCompare))) { 267 // Compatible profile has been found, checks if this profile has compatible 268 // rate and channels as well 269 audio_channel_mask_t updatedChannels; 270 uint32_t updatedRate; 271 if (profile->checkCompatibleChannelMask(channelMask, updatedChannels, 272 portType, portRole) == NO_ERROR && 273 profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) { 274 // for inexact checks we take the first linear pcm format due to sorting. 275 format = formatToCompare; 276 channelMask = updatedChannels; 277 samplingRate = updatedRate; 278 return NO_ERROR; 279 } 280 } 281 } 282 return BAD_VALUE; 283 } 284 285 int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1, 286 const sp<AudioProfile> *profile2) 287 { 288 return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat()); 289 } 290 291 }; // namespace android 292