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