• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
checkExact(uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format) const31 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>
operator ==(const SortedVector<T> & left,const SortedVector<T> & right)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 
operator ==(const AudioProfile & left,const AudioProfile & compareTo)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 
checkCompatibleSamplingRate(uint32_t samplingRate,uint32_t & updatedSamplingRate) const63 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 
checkCompatibleChannelMask(audio_channel_mask_t channelMask,audio_channel_mask_t & updatedChannelMask,audio_port_type_t portType,audio_port_role_t portRole) const98 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 
dump(int fd,int spaces) const185 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 
checkExactProfile(uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format) const228 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 
checkCompatibleProfile(uint32_t & samplingRate,audio_channel_mask_t & channelMask,audio_format_t & format,audio_port_type_t portType,audio_port_role_t portRole) const245 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 
compareFormats(const sp<AudioProfile> * profile1,const sp<AudioProfile> * profile2)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