• 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::AudioProfile"
22 //#define LOG_NDEBUG 0
23 
24 #include <media/AudioResamplerPublic.h>
25 #include <utils/Errors.h>
26 
27 #include "AudioGain.h"
28 #include "AudioPort.h"
29 #include "AudioProfile.h"
30 #include "HwModule.h"
31 #include "TypeConverter.h"
32 
33 namespace android {
34 
asInMask() const35 ChannelsVector ChannelsVector::asInMask() const
36 {
37     ChannelsVector inMaskVector;
38     for (const auto& channel : *this) {
39         if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
40             inMaskVector.add(audio_channel_mask_out_to_in(channel));
41         }
42     }
43     return inMaskVector;
44 }
45 
asOutMask() const46 ChannelsVector ChannelsVector::asOutMask() const
47 {
48     ChannelsVector outMaskVector;
49     for (const auto& channel : *this) {
50         if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
51             outMaskVector.add(audio_channel_mask_in_to_out(channel));
52         }
53     }
54     return outMaskVector;
55 }
56 
operator ==(const AudioProfile & left,const AudioProfile & compareTo)57 bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
58 {
59     return (left.getFormat() == compareTo.getFormat()) &&
60             (left.getChannels() == compareTo.getChannels()) &&
61             (left.getSampleRates() == compareTo.getSampleRates());
62 }
63 
createFullDynamicImpl()64 static AudioProfile* createFullDynamicImpl()
65 {
66     AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
67             ChannelsVector(), SampleRateVector());
68     dynamicProfile->setDynamicFormat(true);
69     dynamicProfile->setDynamicChannels(true);
70     dynamicProfile->setDynamicRate(true);
71     return dynamicProfile;
72 }
73 
74 // static
createFullDynamic()75 sp<AudioProfile> AudioProfile::createFullDynamic()
76 {
77     static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
78     return dynamicProfile;
79 }
80 
AudioProfile(audio_format_t format,audio_channel_mask_t channelMasks,uint32_t samplingRate)81 AudioProfile::AudioProfile(audio_format_t format,
82                            audio_channel_mask_t channelMasks,
83                            uint32_t samplingRate) :
84         mName(String8("")),
85         mFormat(format)
86 {
87     mChannelMasks.add(channelMasks);
88     mSamplingRates.add(samplingRate);
89 }
90 
AudioProfile(audio_format_t format,const ChannelsVector & channelMasks,const SampleRateVector & samplingRateCollection)91 AudioProfile::AudioProfile(audio_format_t format,
92                            const ChannelsVector &channelMasks,
93                            const SampleRateVector &samplingRateCollection) :
94         mName(String8("")),
95         mFormat(format),
96         mChannelMasks(channelMasks),
97         mSamplingRates(samplingRateCollection) {}
98 
setChannels(const ChannelsVector & channelMasks)99 void AudioProfile::setChannels(const ChannelsVector &channelMasks)
100 {
101     if (mIsDynamicChannels) {
102         mChannelMasks = channelMasks;
103     }
104 }
105 
setSampleRates(const SampleRateVector & sampleRates)106 void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
107 {
108     if (mIsDynamicRate) {
109         mSamplingRates = sampleRates;
110     }
111 }
112 
clear()113 void AudioProfile::clear()
114 {
115     if (mIsDynamicChannels) {
116         mChannelMasks.clear();
117     }
118     if (mIsDynamicRate) {
119         mSamplingRates.clear();
120     }
121 }
122 
checkExact(uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format) const123 status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
124                                   audio_format_t format) const
125 {
126     if (audio_formats_match(format, mFormat) &&
127             supportsChannels(channelMask) &&
128             supportsRate(samplingRate)) {
129         return NO_ERROR;
130     }
131     return BAD_VALUE;
132 }
133 
checkCompatibleSamplingRate(uint32_t samplingRate,uint32_t & updatedSamplingRate) const134 status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
135                                                    uint32_t &updatedSamplingRate) const
136 {
137     ALOG_ASSERT(samplingRate > 0);
138 
139     if (mSamplingRates.isEmpty()) {
140         updatedSamplingRate = samplingRate;
141         return NO_ERROR;
142     }
143 
144     // Search for the closest supported sampling rate that is above (preferred)
145     // or below (acceptable) the desired sampling rate, within a permitted ratio.
146     // The sampling rates are sorted in ascending order.
147     size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
148 
149     // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
150     if (orderOfDesiredRate < mSamplingRates.size()) {
151         uint32_t candidate = mSamplingRates[orderOfDesiredRate];
152         if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
153             updatedSamplingRate = candidate;
154             return NO_ERROR;
155         }
156     }
157     // But if we have to up-sample from a lower sampling rate, that's OK.
158     if (orderOfDesiredRate != 0) {
159         uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
160         if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
161             updatedSamplingRate = candidate;
162             return NO_ERROR;
163         }
164     }
165     // leave updatedSamplingRate unmodified
166     return BAD_VALUE;
167 }
168 
checkCompatibleChannelMask(audio_channel_mask_t channelMask,audio_channel_mask_t & updatedChannelMask,audio_port_type_t portType,audio_port_role_t portRole) const169 status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
170                                                   audio_channel_mask_t &updatedChannelMask,
171                                                   audio_port_type_t portType,
172                                                   audio_port_role_t portRole) const
173 {
174     if (mChannelMasks.isEmpty()) {
175         updatedChannelMask = channelMask;
176         return NO_ERROR;
177     }
178     const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
179     const bool isIndex = audio_channel_mask_get_representation(channelMask)
180             == AUDIO_CHANNEL_REPRESENTATION_INDEX;
181     const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
182     int bestMatch = 0;
183     for (size_t i = 0; i < mChannelMasks.size(); i ++) {
184         audio_channel_mask_t supported = mChannelMasks[i];
185         if (supported == channelMask) {
186             // Exact matches always taken.
187             updatedChannelMask = channelMask;
188             return NO_ERROR;
189         }
190 
191         // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
192         if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
193             // Approximate (best) match:
194             // The match score measures how well the supported channel mask matches the
195             // desired mask, where increasing-is-better.
196             //
197             // TODO: Some tweaks may be needed.
198             // Should be a static function of the data processing library.
199             //
200             // In priority:
201             // match score = 1000 if legacy channel conversion equivalent (always prefer this)
202             // OR
203             // match score += 100 if the channel mask representations match
204             // match score += number of channels matched.
205             // match score += 100 if the channel mask representations DO NOT match
206             //   but the profile has positional channel mask and less than 2 channels.
207             //   This is for audio HAL convention to not list index masks for less than 2 channels
208             //
209             // If there are no matched channels, the mask may still be accepted
210             // but the playback or record will be silent.
211             const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
212                     == AUDIO_CHANNEL_REPRESENTATION_INDEX);
213             const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
214             int match;
215             if (isIndex && isSupportedIndex) {
216                 // index equivalence
217                 match = 100 + __builtin_popcount(
218                         audio_channel_mask_get_bits(channelMask)
219                             & audio_channel_mask_get_bits(supported));
220             } else if (isIndex && !isSupportedIndex) {
221                 const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
222                 match = __builtin_popcount(
223                         audio_channel_mask_get_bits(channelMask) & equivalentBits);
224                 if (supportedChannelCount <= FCC_2) {
225                     match += 100;
226                 }
227             } else if (!isIndex && isSupportedIndex) {
228                 const uint32_t equivalentBits = (1 << channelCount) - 1;
229                 match = __builtin_popcount(
230                         equivalentBits & audio_channel_mask_get_bits(supported));
231             } else {
232                 // positional equivalence
233                 match = 100 + __builtin_popcount(
234                         audio_channel_mask_get_bits(channelMask)
235                             & audio_channel_mask_get_bits(supported));
236                 switch (supported) {
237                 case AUDIO_CHANNEL_IN_FRONT_BACK:
238                 case AUDIO_CHANNEL_IN_STEREO:
239                     if (channelMask == AUDIO_CHANNEL_IN_MONO) {
240                         match = 1000;
241                     }
242                     break;
243                 case AUDIO_CHANNEL_IN_MONO:
244                     if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
245                             || channelMask == AUDIO_CHANNEL_IN_STEREO) {
246                         match = 1000;
247                     }
248                     break;
249                 default:
250                     break;
251                 }
252             }
253             if (match > bestMatch) {
254                 bestMatch = match;
255                 updatedChannelMask = supported;
256             }
257         }
258     }
259     return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
260 }
261 
dump(String8 * dst,int spaces) const262 void AudioProfile::dump(String8 *dst, int spaces) const
263 {
264     dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
265              mIsDynamicChannels ? "[dynamic channels]" : "",
266              mIsDynamicRate ? "[dynamic rates]" : "");
267     if (mName.length() != 0) {
268         dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
269     }
270     std::string formatLiteral;
271     if (FormatConverter::toString(mFormat, formatLiteral)) {
272         dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
273     }
274     if (!mSamplingRates.isEmpty()) {
275         dst->appendFormat("%*s- sampling rates:", spaces, "");
276         for (size_t i = 0; i < mSamplingRates.size(); i++) {
277             dst->appendFormat("%d", mSamplingRates[i]);
278             dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
279         }
280         dst->append("\n");
281     }
282 
283     if (!mChannelMasks.isEmpty()) {
284         dst->appendFormat("%*s- channel masks:", spaces, "");
285         for (size_t i = 0; i < mChannelMasks.size(); i++) {
286             dst->appendFormat("0x%04x", mChannelMasks[i]);
287             dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
288         }
289         dst->append("\n");
290     }
291 }
292 
add(const sp<AudioProfile> & profile)293 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
294 {
295     ssize_t index = Vector::add(profile);
296     // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
297     // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
298     // [](const audio_format_t *format1, const audio_format_t *format2) {
299     //     return compareFormats(*format1, *format2);
300     // }
301     sort(compareFormats);
302     return index;
303 }
304 
addProfileFromHal(const sp<AudioProfile> & profileToAdd)305 ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
306 {
307     // Check valid profile to add:
308     if (!profileToAdd->hasValidFormat()) {
309         return -1;
310     }
311     if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
312         FormatVector formats;
313         formats.add(profileToAdd->getFormat());
314         setFormats(FormatVector(formats));
315         return 0;
316     }
317     if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
318         setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
319         return 0;
320     }
321     if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
322         setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
323         return 0;
324     }
325     // Go through the list of profile to avoid duplicates
326     for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
327         const sp<AudioProfile> &profile = itemAt(profileIndex);
328         if (profile->isValid() && profile == profileToAdd) {
329             // Nothing to do
330             return profileIndex;
331         }
332     }
333     profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
334     return add(profileToAdd);
335 }
336 
checkExactProfile(uint32_t samplingRate,audio_channel_mask_t channelMask,audio_format_t format) const337 status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
338                                                audio_channel_mask_t channelMask,
339                                                audio_format_t format) const
340 {
341     if (isEmpty()) {
342         return NO_ERROR;
343     }
344 
345     for (const auto& profile : *this) {
346         if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
347             return NO_ERROR;
348         }
349     }
350     return BAD_VALUE;
351 }
352 
checkCompatibleProfile(uint32_t & samplingRate,audio_channel_mask_t & channelMask,audio_format_t & format,audio_port_type_t portType,audio_port_role_t portRole) const353 status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
354                                                     audio_channel_mask_t &channelMask,
355                                                     audio_format_t &format,
356                                                     audio_port_type_t portType,
357                                                     audio_port_role_t portRole) const
358 {
359     if (isEmpty()) {
360         return NO_ERROR;
361     }
362 
363     const bool checkInexact = // when port is input and format is linear pcm
364             portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
365             && audio_is_linear_pcm(format);
366 
367     // iterate from best format to worst format (reverse order)
368     for (ssize_t i = size() - 1; i >= 0 ; --i) {
369         const sp<AudioProfile> profile = itemAt(i);
370         audio_format_t formatToCompare = profile->getFormat();
371         if (formatToCompare == format ||
372                 (checkInexact
373                         && formatToCompare != AUDIO_FORMAT_DEFAULT
374                         && audio_is_linear_pcm(formatToCompare))) {
375             // Compatible profile has been found, checks if this profile has compatible
376             // rate and channels as well
377             audio_channel_mask_t updatedChannels;
378             uint32_t updatedRate;
379             if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
380                                                     portType, portRole) == NO_ERROR &&
381                     profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
382                 // for inexact checks we take the first linear pcm format due to sorting.
383                 format = formatToCompare;
384                 channelMask = updatedChannels;
385                 samplingRate = updatedRate;
386                 return NO_ERROR;
387             }
388         }
389     }
390     return BAD_VALUE;
391 }
392 
clearProfiles()393 void AudioProfileVector::clearProfiles()
394 {
395     for (size_t i = size(); i != 0; ) {
396         sp<AudioProfile> profile = itemAt(--i);
397         if (profile->isDynamicFormat() && profile->hasValidFormat()) {
398             removeAt(i);
399             continue;
400         }
401         profile->clear();
402     }
403 }
404 
405 // Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
406 // The result is ordered according to 'order'.
407 template<typename T, typename Order>
intersectFilterAndOrder(const T & input1,const T & input2,const Order & order)408 std::vector<typename T::value_type> intersectFilterAndOrder(
409         const T& input1, const T& input2, const Order& order)
410 {
411     std::set<typename T::value_type> set1{input1.begin(), input1.end()};
412     std::set<typename T::value_type> set2{input2.begin(), input2.end()};
413     std::set<typename T::value_type> common;
414     std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
415             std::inserter(common, common.begin()));
416     std::vector<typename T::value_type> result;
417     for (const auto& e : order) {
418         if (common.find(e) != common.end()) result.push_back(e);
419     }
420     return result;
421 }
422 
423 // Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
424 // 'comp' is a comparator function.
425 template<typename T, typename Compare>
intersectAndOrder(const T & input1,const T & input2,Compare comp)426 std::vector<typename T::value_type> intersectAndOrder(
427         const T& input1, const T& input2, Compare comp)
428 {
429     std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
430     std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
431     std::vector<typename T::value_type> result;
432     std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
433             std::back_inserter(result), comp);
434     return result;
435 }
436 
findBestMatchingOutputConfig(const AudioProfileVector & outputProfiles,const std::vector<audio_format_t> & preferredFormats,const std::vector<audio_channel_mask_t> & preferredOutputChannels,bool preferHigherSamplingRates,audio_config_base * bestOutputConfig) const437 status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
438             const std::vector<audio_format_t>& preferredFormats,
439             const std::vector<audio_channel_mask_t>& preferredOutputChannels,
440             bool preferHigherSamplingRates,
441             audio_config_base *bestOutputConfig) const
442 {
443     auto formats = intersectFilterAndOrder(getSupportedFormats(),
444             outputProfiles.getSupportedFormats(), preferredFormats);
445     // Pick the best compatible profile.
446     for (const auto& f : formats) {
447         sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
448         sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
449         if (inputProfile == nullptr || outputProfile == nullptr) {
450             continue;
451         }
452         auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
453                 outputProfile->getChannels(), preferredOutputChannels);
454         if (channels.empty()) {
455             continue;
456         }
457         auto sampleRates = preferHigherSamplingRates ?
458                 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
459                         std::greater<typename SampleRateVector::value_type>()) :
460                 intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
461                         std::less<typename SampleRateVector::value_type>());
462         if (sampleRates.empty()) {
463             continue;
464         }
465         ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
466                 __func__, *channels.begin(), *sampleRates.begin(), f);
467         bestOutputConfig->format = f;
468         bestOutputConfig->sample_rate = *sampleRates.begin();
469         bestOutputConfig->channel_mask = *channels.begin();
470         return NO_ERROR;
471     }
472     return BAD_VALUE;
473 }
474 
getFirstValidProfile() const475 sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
476 {
477     for (size_t i = 0; i < size(); i++) {
478         if (itemAt(i)->isValid()) {
479             return itemAt(i);
480         }
481     }
482     return 0;
483 }
484 
getFirstValidProfileFor(audio_format_t format) const485 sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
486 {
487     for (size_t i = 0; i < size(); i++) {
488         if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
489             return itemAt(i);
490         }
491     }
492     return 0;
493 }
494 
getSupportedFormats() const495 FormatVector AudioProfileVector::getSupportedFormats() const
496 {
497     FormatVector supportedFormats;
498     for (size_t i = 0; i < size(); i++) {
499         if (itemAt(i)->hasValidFormat()) {
500             supportedFormats.add(itemAt(i)->getFormat());
501         }
502     }
503     return supportedFormats;
504 }
505 
hasDynamicChannelsFor(audio_format_t format) const506 bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
507 {
508     for (size_t i = 0; i < size(); i++) {
509         sp<AudioProfile> profile = itemAt(i);
510         if (profile->getFormat() == format && profile->isDynamicChannels()) {
511             return true;
512         }
513     }
514     return false;
515 }
516 
hasDynamicProfile() const517 bool AudioProfileVector::hasDynamicProfile() const
518 {
519     for (size_t i = 0; i < size(); i++) {
520         if (itemAt(i)->isDynamic()) {
521             return true;
522         }
523     }
524     return false;
525 }
526 
hasDynamicRateFor(audio_format_t format) const527 bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
528 {
529     for (size_t i = 0; i < size(); i++) {
530         sp<AudioProfile> profile = itemAt(i);
531         if (profile->getFormat() == format && profile->isDynamicRate()) {
532             return true;
533         }
534     }
535     return false;
536 }
537 
setFormats(const FormatVector & formats)538 void AudioProfileVector::setFormats(const FormatVector &formats)
539 {
540     // Only allow to change the format of dynamic profile
541     sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
542     if (dynamicFormatProfile == 0) {
543         return;
544     }
545     for (size_t i = 0; i < formats.size(); i++) {
546         sp<AudioProfile> profile = new AudioProfile(formats[i],
547                 dynamicFormatProfile->getChannels(),
548                 dynamicFormatProfile->getSampleRates());
549         profile->setDynamicFormat(true);
550         profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
551         profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
552         add(profile);
553     }
554 }
555 
dump(String8 * dst,int spaces) const556 void AudioProfileVector::dump(String8 *dst, int spaces) const
557 {
558     dst->appendFormat("%*s- Profiles:\n", spaces, "");
559     for (size_t i = 0; i < size(); i++) {
560         dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
561         itemAt(i)->dump(dst, spaces + 8);
562     }
563 }
564 
getProfileFor(audio_format_t format) const565 sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
566 {
567     for (size_t i = 0; i < size(); i++) {
568         if (itemAt(i)->getFormat() == format) {
569             return itemAt(i);
570         }
571     }
572     return 0;
573 }
574 
setSampleRatesFor(const SampleRateVector & sampleRates,audio_format_t format)575 void AudioProfileVector::setSampleRatesFor(
576         const SampleRateVector &sampleRates, audio_format_t format)
577 {
578     for (size_t i = 0; i < size(); i++) {
579         sp<AudioProfile> profile = itemAt(i);
580         if (profile->getFormat() == format && profile->isDynamicRate()) {
581             if (profile->hasValidRates()) {
582                 // Need to create a new profile with same format
583                 sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
584                         sampleRates);
585                 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
586                 add(profileToAdd);
587             } else {
588                 profile->setSampleRates(sampleRates);
589             }
590             return;
591         }
592     }
593 }
594 
setChannelsFor(const ChannelsVector & channelMasks,audio_format_t format)595 void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
596 {
597     for (size_t i = 0; i < size(); i++) {
598         sp<AudioProfile> profile = itemAt(i);
599         if (profile->getFormat() == format && profile->isDynamicChannels()) {
600             if (profile->hasValidChannels()) {
601                 // Need to create a new profile with same format
602                 sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
603                         profile->getSampleRates());
604                 profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
605                 add(profileToAdd);
606             } else {
607                 profile->setChannels(channelMasks);
608             }
609             return;
610         }
611     }
612 }
613 
614 // static
compareFormats(const sp<AudioProfile> * profile1,const sp<AudioProfile> * profile2)615 int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
616                                        const sp<AudioProfile> *profile2)
617 {
618     return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
619 }
620 
621 } // namespace android
622