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