• 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 #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