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::AudioProfileVectorHelper"
22 //#define LOG_NDEBUG 0
23
24 #include <media/AudioContainers.h>
25 #include <media/AudioResamplerPublic.h>
26 #include <utils/Errors.h>
27
28 #include "AudioProfileVectorHelper.h"
29 #include "HwModule.h"
30 #include "PolicyAudioPort.h"
31 #include "policy.h"
32
33 namespace android {
34
sortAudioProfiles(AudioProfileVector & audioProfileVector)35 void sortAudioProfiles(AudioProfileVector &audioProfileVector) {
36 std::sort(audioProfileVector.begin(), audioProfileVector.end(),
37 [](const sp<AudioProfile> & a, const sp<AudioProfile> & b)
38 {
39 return PolicyAudioPort::compareFormats(a->getFormat(), b->getFormat()) < 0;
40 });
41 }
42
addAudioProfileAndSort(AudioProfileVector & audioProfileVector,const sp<AudioProfile> & profile)43 ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
44 const sp<AudioProfile> &profile)
45 {
46 ssize_t ret = audioProfileVector.add(profile);
47 // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
48 sortAudioProfiles(audioProfileVector);
49 return ret;
50 }
51
getAudioProfileForFormat(const AudioProfileVector & audioProfileVector,audio_format_t format)52 sp<AudioProfile> getAudioProfileForFormat(const AudioProfileVector &audioProfileVector,
53 audio_format_t format)
54 {
55 for (const auto &profile : audioProfileVector) {
56 if (profile->getFormat() == format) {
57 return profile;
58 }
59 }
60 return nullptr;
61 }
62
setSampleRatesForAudioProfiles(AudioProfileVector & audioProfileVector,const SampleRateSet & sampleRateSet,audio_format_t format)63 void setSampleRatesForAudioProfiles(AudioProfileVector &audioProfileVector,
64 const SampleRateSet &sampleRateSet,
65 audio_format_t format)
66 {
67 for (const auto &profile : audioProfileVector) {
68 if (profile->getFormat() == format && profile->isDynamicRate()) {
69 if (profile->hasValidRates()) {
70 // Need to create a new profile with same format
71 sp<AudioProfile> profileToAdd = new AudioProfile(
72 format, profile->getChannels(), sampleRateSet);
73 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
74 addAudioProfileAndSort(audioProfileVector, profileToAdd);
75 } else {
76 profile->setSampleRates(sampleRateSet);
77 }
78 return;
79 }
80 }
81 }
82
setChannelsForAudioProfiles(AudioProfileVector & audioProfileVector,const ChannelMaskSet & channelMaskSet,audio_format_t format)83 void setChannelsForAudioProfiles(AudioProfileVector &audioProfileVector,
84 const ChannelMaskSet &channelMaskSet,
85 audio_format_t format)
86 {
87 for (const auto &profile : audioProfileVector) {
88 if (profile->getFormat() == format && profile->isDynamicChannels()) {
89 if (profile->hasValidChannels()) {
90 // Need to create a new profile with same format
91 sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMaskSet,
92 profile->getSampleRates());
93 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
94 addAudioProfileAndSort(audioProfileVector, profileToAdd);
95 } else {
96 profile->setChannels(channelMaskSet);
97 }
98 return;
99 }
100 }
101 }
102
addProfilesForFormats(AudioProfileVector & audioProfileVector,const FormatVector & formatVector)103 void addProfilesForFormats(AudioProfileVector &audioProfileVector, const FormatVector &formatVector)
104 {
105 // Only allow to change the format of dynamic profile
106 sp<AudioProfile> dynamicFormatProfile = getAudioProfileForFormat(
107 audioProfileVector, gDynamicFormat);
108 if (!dynamicFormatProfile) {
109 return;
110 }
111 for (const auto &format : formatVector) {
112 sp<AudioProfile> profile = new AudioProfile(format,
113 dynamicFormatProfile->getChannels(),
114 dynamicFormatProfile->getSampleRates());
115 profile->setDynamicFormat(true);
116 profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
117 profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
118 size_t profileIndex = 0;
119 for (; profileIndex < audioProfileVector.size(); profileIndex++) {
120 if (profile->equals(audioProfileVector.at(profileIndex))) {
121 // The dynamic profile is already there
122 break;
123 }
124 }
125 if (profileIndex >= audioProfileVector.size()) {
126 // Only add when the dynamic profile is not there
127 addAudioProfileAndSort(audioProfileVector, profile);
128 }
129 }
130 }
131
addDynamicAudioProfileAndSort(AudioProfileVector & audioProfileVector,const sp<AudioProfile> & profileToAdd)132 void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
133 const sp<AudioProfile> &profileToAdd)
134 {
135 // Check valid profile to add:
136 if (!profileToAdd->hasValidFormat()) {
137 ALOGW("Adding dynamic audio profile without valid format");
138 return;
139 }
140 if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
141 FormatVector formats;
142 formats.push_back(profileToAdd->getFormat());
143 addProfilesForFormats(audioProfileVector, FormatVector(formats));
144 return;
145 }
146 if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
147 setSampleRatesForAudioProfiles(
148 audioProfileVector, profileToAdd->getSampleRates(), profileToAdd->getFormat());
149 return;
150 }
151 if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
152 setChannelsForAudioProfiles(
153 audioProfileVector, profileToAdd->getChannels(), profileToAdd->getFormat());
154 return;
155 }
156 const bool originalIsDynamicFormat = profileToAdd->isDynamicFormat();
157 profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
158 // Go through the list of profile to avoid duplicates
159 for (size_t profileIndex = 0; profileIndex < audioProfileVector.size(); profileIndex++) {
160 const sp<AudioProfile> &profile = audioProfileVector.at(profileIndex);
161 if (profile->isValid() && profile->equals(profileToAdd)) {
162 // The same profile is already there, no need to add.
163 // Reset `isDynamicProfile` as original value.
164 profileToAdd->setDynamicFormat(originalIsDynamicFormat);
165 return;
166 }
167 }
168 profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
169 addAudioProfileAndSort(audioProfileVector, profileToAdd);
170 }
171
appendAudioProfiles(AudioProfileVector & audioProfileVector,const AudioProfileVector & audioProfileVectorToAppend)172 void appendAudioProfiles(AudioProfileVector &audioProfileVector,
173 const AudioProfileVector &audioProfileVectorToAppend)
174 {
175 audioProfileVector.insert(audioProfileVector.end(),
176 audioProfileVectorToAppend.begin(),
177 audioProfileVectorToAppend.end());
178 }
179
checkExact(const sp<AudioProfile> & audioProfile,uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format)180 status_t checkExact(const sp<AudioProfile> &audioProfile,
181 uint32_t samplingRate,
182 audio_channel_mask_t channelMask,
183 audio_format_t format)
184 {
185 if (audio_formats_match(format, audioProfile->getFormat()) &&
186 audioProfile->supportsChannels(channelMask) &&
187 audioProfile->supportsRate(samplingRate)) {
188 return NO_ERROR;
189 }
190 return BAD_VALUE;
191 }
192
checkCompatibleSamplingRate(const sp<AudioProfile> & audioProfile,uint32_t samplingRate,uint32_t & updatedSamplingRate)193 status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
194 uint32_t samplingRate,
195 uint32_t &updatedSamplingRate)
196 {
197 ALOG_ASSERT(samplingRate > 0);
198
199 const SampleRateSet sampleRates = audioProfile->getSampleRates();
200 if (sampleRates.empty()) {
201 updatedSamplingRate = samplingRate;
202 return NO_ERROR;
203 }
204
205 // Search for the closest supported sampling rate that is above (preferred)
206 // or below (acceptable) the desired sampling rate, within a permitted ratio.
207 // The sampling rates are sorted in ascending order.
208 auto desiredRate = sampleRates.lower_bound(samplingRate);
209
210 // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
211 if (desiredRate != sampleRates.end()) {
212 if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
213 updatedSamplingRate = *desiredRate;
214 return NO_ERROR;
215 }
216 }
217 // But if we have to up-sample from a lower sampling rate, that's OK.
218 if (desiredRate != sampleRates.begin()) {
219 uint32_t candidate = *(--desiredRate);
220 if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
221 updatedSamplingRate = candidate;
222 return NO_ERROR;
223 }
224 }
225 // leave updatedSamplingRate unmodified
226 return BAD_VALUE;
227 }
228
checkCompatibleChannelMask(const sp<AudioProfile> & audioProfile,audio_channel_mask_t channelMask,audio_channel_mask_t & updatedChannelMask,audio_port_type_t portType,audio_port_role_t portRole)229 status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
230 audio_channel_mask_t channelMask,
231 audio_channel_mask_t &updatedChannelMask,
232 audio_port_type_t portType,
233 audio_port_role_t portRole)
234 {
235 const ChannelMaskSet channelMasks = audioProfile->getChannels();
236 if (channelMasks.empty()) {
237 updatedChannelMask = channelMask;
238 return NO_ERROR;
239 }
240 const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
241 const bool isIndex = audio_channel_mask_get_representation(channelMask)
242 == AUDIO_CHANNEL_REPRESENTATION_INDEX;
243 const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
244 int bestMatch = 0;
245 for (const auto &supported : channelMasks) {
246 if (supported == channelMask) {
247 // Exact matches always taken.
248 updatedChannelMask = channelMask;
249 return NO_ERROR;
250 }
251
252 // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
253 if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
254 // Approximate (best) match:
255 // The match score measures how well the supported channel mask matches the
256 // desired mask, where increasing-is-better.
257 //
258 // TODO: Some tweaks may be needed.
259 // Should be a static function of the data processing library.
260 //
261 // In priority:
262 // match score = 1000 if legacy channel conversion equivalent (always prefer this)
263 // OR
264 // match score += 100 if the channel mask representations match
265 // match score += number of channels matched.
266 // match score += 100 if the channel mask representations DO NOT match
267 // but the profile has positional channel mask and less than 2 channels.
268 // This is for audio HAL convention to not list index masks for less than 2 channels
269 //
270 // If there are no matched channels, the mask may still be accepted
271 // but the playback or record will be silent.
272 const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
273 == AUDIO_CHANNEL_REPRESENTATION_INDEX);
274 const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
275 int match;
276 if (isIndex && isSupportedIndex) {
277 // index equivalence
278 match = 100 + __builtin_popcount(
279 audio_channel_mask_get_bits(channelMask)
280 & audio_channel_mask_get_bits(supported));
281 } else if (isIndex && !isSupportedIndex) {
282 const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
283 match = __builtin_popcount(
284 audio_channel_mask_get_bits(channelMask) & equivalentBits);
285 if (supportedChannelCount <= FCC_2) {
286 match += 100;
287 }
288 } else if (!isIndex && isSupportedIndex) {
289 const uint32_t equivalentBits = (1 << channelCount) - 1;
290 match = __builtin_popcount(
291 equivalentBits & audio_channel_mask_get_bits(supported));
292 } else {
293 // positional equivalence
294 match = 100 + __builtin_popcount(
295 audio_channel_mask_get_bits(channelMask)
296 & audio_channel_mask_get_bits(supported));
297 switch (supported) {
298 case AUDIO_CHANNEL_IN_FRONT_BACK:
299 case AUDIO_CHANNEL_IN_STEREO:
300 if (channelMask == AUDIO_CHANNEL_IN_MONO) {
301 match = 1000;
302 }
303 break;
304 case AUDIO_CHANNEL_IN_MONO:
305 if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
306 || channelMask == AUDIO_CHANNEL_IN_STEREO) {
307 match = 1000;
308 }
309 break;
310 default:
311 break;
312 }
313 }
314 if (match > bestMatch) {
315 bestMatch = match;
316 updatedChannelMask = supported;
317 }
318 }
319 }
320 return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
321 }
322
checkExactProfile(const AudioProfileVector & audioProfileVector,const uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format)323 status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
324 const uint32_t samplingRate,
325 audio_channel_mask_t channelMask,
326 audio_format_t format)
327 {
328 if (audioProfileVector.empty()) {
329 return NO_ERROR;
330 }
331
332 for (const auto& profile : audioProfileVector) {
333 if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
334 return NO_ERROR;
335 }
336 }
337 return BAD_VALUE;
338 }
339
checkCompatibleProfile(const AudioProfileVector & audioProfileVector,uint32_t & samplingRate,audio_channel_mask_t & channelMask,audio_format_t & format,audio_port_type_t portType,audio_port_role_t portRole)340 status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
341 uint32_t &samplingRate,
342 audio_channel_mask_t &channelMask,
343 audio_format_t &format,
344 audio_port_type_t portType,
345 audio_port_role_t portRole)
346 {
347 if (audioProfileVector.empty()) {
348 return NO_ERROR;
349 }
350
351 const bool checkInexact = // when port is input and format is linear pcm
352 portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
353 && audio_is_linear_pcm(format);
354
355 // iterate from best format to worst format (reverse order)
356 for (ssize_t i = audioProfileVector.size() - 1; i >= 0 ; --i) {
357 const sp<AudioProfile> profile = audioProfileVector.at(i);
358 audio_format_t formatToCompare = profile->getFormat();
359 if (formatToCompare == format ||
360 (checkInexact
361 && formatToCompare != AUDIO_FORMAT_DEFAULT
362 && audio_is_linear_pcm(formatToCompare))) {
363 // Compatible profile has been found, checks if this profile has compatible
364 // rate and channels as well
365 audio_channel_mask_t updatedChannels;
366 uint32_t updatedRate;
367 if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
368 portType, portRole) == NO_ERROR &&
369 checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
370 // for inexact checks we take the first linear pcm format due to sorting.
371 format = formatToCompare;
372 channelMask = updatedChannels;
373 samplingRate = updatedRate;
374 return NO_ERROR;
375 }
376 }
377 }
378 return BAD_VALUE;
379 }
380
381 // Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
382 // The result is ordered according to 'order'.
383 template<typename T, typename Order>
intersectFilterAndOrder(const T & input1,const T & input2,const Order & order)384 std::vector<typename T::value_type> intersectFilterAndOrder(
385 const T& input1, const T& input2, const Order& order)
386 {
387 std::set<typename T::value_type> set1{input1.begin(), input1.end()};
388 std::set<typename T::value_type> set2{input2.begin(), input2.end()};
389 std::set<typename T::value_type> common;
390 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
391 std::inserter(common, common.begin()));
392 std::vector<typename T::value_type> result;
393 for (const auto& e : order) {
394 if (common.find(e) != common.end()) result.push_back(e);
395 }
396 return result;
397 }
398
399 // Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
400 // 'comp' is a comparator function.
401 template<typename T, typename Compare>
intersectAndOrder(const T & input1,const T & input2,Compare comp)402 std::vector<typename T::value_type> intersectAndOrder(
403 const T& input1, const T& input2, Compare comp)
404 {
405 std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
406 std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
407 std::vector<typename T::value_type> result;
408 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
409 std::back_inserter(result), comp);
410 return result;
411 }
412
findBestMatchingOutputConfig(const AudioProfileVector & audioProfileVector,const AudioProfileVector & outputProfileVector,const std::vector<audio_format_t> & preferredFormatVector,const std::vector<audio_channel_mask_t> & preferredOutputChannelVector,bool preferHigherSamplingRates,audio_config_base & bestOutputConfig)413 status_t findBestMatchingOutputConfig(
414 const AudioProfileVector &audioProfileVector,
415 const AudioProfileVector &outputProfileVector,
416 const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
417 const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
418 bool preferHigherSamplingRates,
419 audio_config_base &bestOutputConfig)
420 {
421 auto formats = intersectFilterAndOrder(audioProfileVector.getSupportedFormats(),
422 outputProfileVector.getSupportedFormats(), preferredFormatVector);
423 // Pick the best compatible profile.
424 for (const auto& f : formats) {
425 sp<AudioProfile> inputProfile = audioProfileVector.getFirstValidProfileFor(f);
426 sp<AudioProfile> outputProfile = outputProfileVector.getFirstValidProfileFor(f);
427 if (inputProfile == nullptr || outputProfile == nullptr) {
428 continue;
429 }
430 auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
431 outputProfile->getChannels(), preferredOutputChannelVector);
432 if (channels.empty()) {
433 continue;
434 }
435 auto sampleRates = preferHigherSamplingRates ?
436 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
437 std::greater<typename SampleRateSet::value_type>()) :
438 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
439 std::less<typename SampleRateSet::value_type>());
440 if (sampleRates.empty()) {
441 continue;
442 }
443 ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
444 __func__, *channels.begin(), *sampleRates.begin(), f);
445 bestOutputConfig.format = f;
446 bestOutputConfig.sample_rate = *sampleRates.begin();
447 bestOutputConfig.channel_mask = *channels.begin();
448 return NO_ERROR;
449 }
450 return BAD_VALUE;
451 }
452
453 } // namespace android
454