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
checkIdentical(const sp<AudioProfile> & audioProfile,uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format)193 status_t checkIdentical(const sp<AudioProfile> &audioProfile,
194 uint32_t samplingRate,
195 audio_channel_mask_t channelMask,
196 audio_format_t format) {
197 if(audioProfile->getFormat() == format &&
198 audioProfile->supportsChannels(channelMask) &&
199 audioProfile->supportsRate(samplingRate)) {
200 return NO_ERROR;
201 }
202 return BAD_VALUE;
203 }
204
checkCompatibleSamplingRate(const sp<AudioProfile> & audioProfile,uint32_t samplingRate,uint32_t & updatedSamplingRate)205 status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
206 uint32_t samplingRate,
207 uint32_t &updatedSamplingRate)
208 {
209 ALOG_ASSERT(samplingRate > 0);
210
211 const SampleRateSet sampleRates = audioProfile->getSampleRates();
212 if (sampleRates.empty()) {
213 updatedSamplingRate = samplingRate;
214 return NO_ERROR;
215 }
216
217 // Search for the closest supported sampling rate that is above (preferred)
218 // or below (acceptable) the desired sampling rate, within a permitted ratio.
219 // The sampling rates are sorted in ascending order.
220 auto desiredRate = sampleRates.lower_bound(samplingRate);
221
222 // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
223 if (desiredRate != sampleRates.end()) {
224 if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
225 updatedSamplingRate = *desiredRate;
226 return NO_ERROR;
227 }
228 }
229 // But if we have to up-sample from a lower sampling rate, that's OK.
230 if (desiredRate != sampleRates.begin()) {
231 uint32_t candidate = *(--desiredRate);
232 if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
233 updatedSamplingRate = candidate;
234 return NO_ERROR;
235 }
236 }
237 // leave updatedSamplingRate unmodified
238 return BAD_VALUE;
239 }
240
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)241 status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
242 audio_channel_mask_t channelMask,
243 audio_channel_mask_t &updatedChannelMask,
244 audio_port_type_t portType,
245 audio_port_role_t portRole)
246 {
247 const ChannelMaskSet channelMasks = audioProfile->getChannels();
248 if (channelMasks.empty()) {
249 updatedChannelMask = channelMask;
250 return NO_ERROR;
251 }
252 const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
253 const bool isIndex = audio_channel_mask_get_representation(channelMask)
254 == AUDIO_CHANNEL_REPRESENTATION_INDEX;
255 const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
256 int bestMatch = 0;
257 for (const auto &supported : channelMasks) {
258 if (supported == channelMask) {
259 // Exact matches always taken.
260 updatedChannelMask = channelMask;
261 return NO_ERROR;
262 }
263
264 // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
265 if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
266 // Approximate (best) match:
267 // The match score measures how well the supported channel mask matches the
268 // desired mask, where increasing-is-better.
269 //
270 // TODO: Some tweaks may be needed.
271 // Should be a static function of the data processing library.
272 //
273 // In priority:
274 // match score = 1000 if legacy channel conversion equivalent (always prefer this)
275 // OR
276 // match score += 100 if the channel mask representations match
277 // match score += number of channels matched.
278 // match score += 100 if the channel mask representations DO NOT match
279 // but the profile has positional channel mask and less than 2 channels.
280 // This is for audio HAL convention to not list index masks for less than 2 channels
281 //
282 // If there are no matched channels, the mask may still be accepted
283 // but the playback or record will be silent.
284 const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
285 == AUDIO_CHANNEL_REPRESENTATION_INDEX);
286 const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
287 int match;
288 if (isIndex && isSupportedIndex) {
289 // index equivalence
290 match = 100 + __builtin_popcount(
291 audio_channel_mask_get_bits(channelMask)
292 & audio_channel_mask_get_bits(supported));
293 } else if (isIndex && !isSupportedIndex) {
294 const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
295 match = __builtin_popcount(
296 audio_channel_mask_get_bits(channelMask) & equivalentBits);
297 if (supportedChannelCount <= FCC_2) {
298 match += 100;
299 }
300 } else if (!isIndex && isSupportedIndex) {
301 const uint32_t equivalentBits = (1 << channelCount) - 1;
302 match = __builtin_popcount(
303 equivalentBits & audio_channel_mask_get_bits(supported));
304 } else {
305 // positional equivalence
306 match = 100 + __builtin_popcount(
307 audio_channel_mask_get_bits(channelMask)
308 & audio_channel_mask_get_bits(supported));
309 switch (supported) {
310 case AUDIO_CHANNEL_IN_FRONT_BACK:
311 case AUDIO_CHANNEL_IN_STEREO:
312 if (channelMask == AUDIO_CHANNEL_IN_MONO) {
313 match = 1000;
314 }
315 break;
316 case AUDIO_CHANNEL_IN_MONO:
317 if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
318 || channelMask == AUDIO_CHANNEL_IN_STEREO) {
319 match = 1000;
320 }
321 break;
322 default:
323 break;
324 }
325 }
326 if (match > bestMatch) {
327 bestMatch = match;
328 updatedChannelMask = supported;
329 }
330 }
331 }
332 return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
333 }
334
335 namespace {
336
checkProfile(const AudioProfileVector & audioProfileVector,const uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format,std::function<status_t (const sp<AudioProfile> &,uint32_t,audio_channel_mask_t,audio_format_t)> check)337 status_t checkProfile(const AudioProfileVector& audioProfileVector,
338 const uint32_t samplingRate,
339 audio_channel_mask_t channelMask,
340 audio_format_t format,
341 std::function<status_t(const sp<AudioProfile> &, uint32_t,
342 audio_channel_mask_t, audio_format_t)> check) {
343 if (audioProfileVector.empty()) {
344 return NO_ERROR;
345 }
346
347 for (const auto& profile : audioProfileVector) {
348 if (check(profile, samplingRate, channelMask, format) == NO_ERROR) {
349 return NO_ERROR;
350 }
351 }
352 return BAD_VALUE;
353 }
354
355 } // namespace
356
checkExactProfile(const AudioProfileVector & audioProfileVector,const uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format)357 status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
358 const uint32_t samplingRate,
359 audio_channel_mask_t channelMask,
360 audio_format_t format)
361 {
362 return checkProfile(audioProfileVector, samplingRate, channelMask, format, checkExact);
363 }
364
checkIdenticalProfile(const AudioProfileVector & audioProfileVector,const uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format)365 status_t checkIdenticalProfile(const AudioProfileVector &audioProfileVector,
366 const uint32_t samplingRate,
367 audio_channel_mask_t channelMask,
368 audio_format_t format) {
369 return checkProfile(audioProfileVector, samplingRate, channelMask, format, checkIdentical);
370 }
371
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)372 status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
373 uint32_t &samplingRate,
374 audio_channel_mask_t &channelMask,
375 audio_format_t &format,
376 audio_port_type_t portType,
377 audio_port_role_t portRole)
378 {
379 if (audioProfileVector.empty()) {
380 return NO_ERROR;
381 }
382
383 const bool checkInexact = // when port is input and format is linear pcm
384 portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
385 && audio_is_linear_pcm(format);
386
387 // iterate from best format to worst format (reverse order)
388 for (ssize_t i = audioProfileVector.size() - 1; i >= 0 ; --i) {
389 const sp<AudioProfile> profile = audioProfileVector.at(i);
390 audio_format_t formatToCompare = profile->getFormat();
391 if (formatToCompare == format ||
392 (checkInexact
393 && formatToCompare != AUDIO_FORMAT_DEFAULT
394 && audio_is_linear_pcm(formatToCompare))) {
395 // Compatible profile has been found, checks if this profile has compatible
396 // rate and channels as well
397 audio_channel_mask_t updatedChannels;
398 uint32_t updatedRate;
399 if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
400 portType, portRole) == NO_ERROR &&
401 checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
402 // for inexact checks we take the first linear pcm format due to sorting.
403 format = formatToCompare;
404 channelMask = updatedChannels;
405 samplingRate = updatedRate;
406 return NO_ERROR;
407 }
408 }
409 }
410 return BAD_VALUE;
411 }
412
413 // Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
414 // The result is ordered according to 'order'.
415 template<typename T, typename Order>
intersectFilterAndOrder(const T & input1,const T & input2,const Order & order)416 std::vector<typename T::value_type> intersectFilterAndOrder(
417 const T& input1, const T& input2, const Order& order)
418 {
419 std::set<typename T::value_type> set1{input1.begin(), input1.end()};
420 std::set<typename T::value_type> set2{input2.begin(), input2.end()};
421 std::set<typename T::value_type> common;
422 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
423 std::inserter(common, common.begin()));
424 std::vector<typename T::value_type> result;
425 for (const auto& e : order) {
426 if (common.find(e) != common.end()) result.push_back(e);
427 }
428 return result;
429 }
430
431 // Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
432 // 'comp' is a comparator function.
433 template<typename T, typename Compare>
intersectAndOrder(const T & input1,const T & input2,Compare comp)434 std::vector<typename T::value_type> intersectAndOrder(
435 const T& input1, const T& input2, Compare comp)
436 {
437 std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
438 std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
439 std::vector<typename T::value_type> result;
440 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
441 std::back_inserter(result), comp);
442 return result;
443 }
444
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)445 status_t findBestMatchingOutputConfig(
446 const AudioProfileVector &audioProfileVector,
447 const AudioProfileVector &outputProfileVector,
448 const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
449 const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
450 bool preferHigherSamplingRates,
451 audio_config_base &bestOutputConfig)
452 {
453 auto formats = intersectFilterAndOrder(audioProfileVector.getSupportedFormats(),
454 outputProfileVector.getSupportedFormats(), preferredFormatVector);
455 // Pick the best compatible profile.
456 for (const auto& f : formats) {
457 sp<AudioProfile> inputProfile = audioProfileVector.getFirstValidProfileFor(f);
458 sp<AudioProfile> outputProfile = outputProfileVector.getFirstValidProfileFor(f);
459 if (inputProfile == nullptr || outputProfile == nullptr) {
460 continue;
461 }
462 auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
463 outputProfile->getChannels(), preferredOutputChannelVector);
464 if (channels.empty()) {
465 continue;
466 }
467 auto sampleRates = preferHigherSamplingRates ?
468 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
469 std::greater<typename SampleRateSet::value_type>()) :
470 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
471 std::less<typename SampleRateSet::value_type>());
472 if (sampleRates.empty()) {
473 continue;
474 }
475 ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
476 __func__, *channels.begin(), *sampleRates.begin(), f);
477 bestOutputConfig.format = f;
478 bestOutputConfig.sample_rate = *sampleRates.begin();
479 bestOutputConfig.channel_mask = *channels.begin();
480 return NO_ERROR;
481 }
482 return BAD_VALUE;
483 }
484
485 } // namespace android
486