• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 <set>
18 
19 #define LOG_TAG "AudioProfile"
20 //#define LOG_NDEBUG 0
21 
22 #include <android-base/stringprintf.h>
23 #include <media/AudioContainers.h>
24 #include <media/AudioProfile.h>
25 #include <media/TypeConverter.h>
26 #include <utils/Errors.h>
27 
28 namespace android {
29 
30 using media::audio::common::AudioChannelLayout;
31 
operator ==(const AudioProfile & left,const AudioProfile & right)32 bool operator == (const AudioProfile &left, const AudioProfile &right)
33 {
34     return (left.getFormat() == right.getFormat()) &&
35             (left.getChannels() == right.getChannels()) &&
36             (left.getSampleRates() == right.getSampleRates());
37 }
38 
39 // static
createFullDynamic(audio_format_t dynamicFormat)40 sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
41 {
42     AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
43             ChannelMaskSet(), SampleRateSet());
44     dynamicProfile->setDynamicFormat(true);
45     dynamicProfile->setDynamicChannels(true);
46     dynamicProfile->setDynamicRate(true);
47     return dynamicProfile;
48 }
49 
AudioProfile(audio_format_t format,audio_channel_mask_t channelMasks,uint32_t samplingRate)50 AudioProfile::AudioProfile(audio_format_t format,
51                            audio_channel_mask_t channelMasks,
52                            uint32_t samplingRate) :
53         mName(""),
54         mFormat(format)
55 {
56     mChannelMasks.insert(channelMasks);
57     mSamplingRates.insert(samplingRate);
58 }
59 
AudioProfile(audio_format_t format,const ChannelMaskSet & channelMasks,const SampleRateSet & samplingRateCollection)60 AudioProfile::AudioProfile(audio_format_t format,
61                            const ChannelMaskSet &channelMasks,
62                            const SampleRateSet &samplingRateCollection) :
63         AudioProfile(format, channelMasks, samplingRateCollection,
64                      AUDIO_ENCAPSULATION_TYPE_NONE) {}
65 
AudioProfile(audio_format_t format,const ChannelMaskSet & channelMasks,const SampleRateSet & samplingRateCollection,audio_encapsulation_type_t encapsulationType)66 AudioProfile::AudioProfile(audio_format_t format,
67                            const ChannelMaskSet &channelMasks,
68                            const SampleRateSet &samplingRateCollection,
69                            audio_encapsulation_type_t encapsulationType) :
70         mName(""),
71         mFormat(format),
72         mChannelMasks(channelMasks),
73         mSamplingRates(samplingRateCollection),
74         mEncapsulationType(encapsulationType) {}
75 
setChannels(const ChannelMaskSet & channelMasks)76 void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
77 {
78     if (mIsDynamicChannels) {
79         mChannelMasks = channelMasks;
80     }
81 }
82 
setSampleRates(const SampleRateSet & sampleRates)83 void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
84 {
85     if (mIsDynamicRate) {
86         mSamplingRates = sampleRates;
87     }
88 }
89 
clear()90 void AudioProfile::clear()
91 {
92     if (mIsDynamicChannels) {
93         mChannelMasks.clear();
94     }
95     if (mIsDynamicRate) {
96         mSamplingRates.clear();
97     }
98 }
99 
dump(std::string * dst,int spaces) const100 void AudioProfile::dump(std::string *dst, int spaces) const
101 {
102     dst->append(base::StringPrintf("\"%s\"; ", mName.c_str()));
103     dst->append(base::StringPrintf("%s%s%s%s", mIsDynamicFormat ? "[dynamic format]" : "",
104              mIsDynamicChannels ? "[dynamic channels]" : "",
105              mIsDynamicRate ? "[dynamic rates]" : "", isDynamic() ? "; " : ""));
106     dst->append(base::StringPrintf("%s (0x%x)\n", audio_format_to_string(mFormat), mFormat));
107 
108     if (!mSamplingRates.empty()) {
109         dst->append(base::StringPrintf("%*ssampling rates: ", spaces, ""));
110         for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
111             dst->append(base::StringPrintf("%d", *it));
112             dst->append(++it == mSamplingRates.end() ? "" : ", ");
113         }
114         dst->append("\n");
115     }
116 
117     if (!mChannelMasks.empty()) {
118         dst->append(base::StringPrintf("%*schannel masks: ", spaces, ""));
119         for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
120             dst->append(base::StringPrintf("0x%04x", *it));
121             dst->append(++it == mChannelMasks.end() ? "" : ", ");
122         }
123         dst->append("\n");
124     }
125 
126     dst->append(base::StringPrintf(
127              "%*s%s\n", spaces, "", audio_encapsulation_type_to_string(mEncapsulationType)));
128 }
129 
equals(const sp<AudioProfile> & other,bool ignoreDynamicFlags) const130 bool AudioProfile::equals(const sp<AudioProfile>& other, bool ignoreDynamicFlags) const
131 {
132     return other != nullptr &&
133            mName.compare(other->mName) == 0 &&
134            mFormat == other->getFormat() &&
135            mChannelMasks == other->getChannels() &&
136            mSamplingRates == other->getSampleRates() &&
137            (ignoreDynamicFlags ||
138                (mIsDynamicFormat == other->isDynamicFormat() &&
139                mIsDynamicChannels == other->isDynamicChannels() &&
140                mIsDynamicRate == other->isDynamicRate())) &&
141            mEncapsulationType == other->getEncapsulationType();
142 }
143 
operator =(const AudioProfile & other)144 AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
145     mName = other.mName;
146     mFormat = other.mFormat;
147     mChannelMasks = other.mChannelMasks;
148     mSamplingRates = other.mSamplingRates;
149     mEncapsulationType = other.mEncapsulationType;
150     mIsDynamicFormat = other.mIsDynamicFormat;
151     mIsDynamicChannels = other.mIsDynamicChannels;
152     mIsDynamicRate = other.mIsDynamicRate;
153     return *this;
154 }
155 
156 ConversionResult<AudioProfile::Aidl>
toParcelable(bool isInput) const157 AudioProfile::toParcelable(bool isInput) const {
158     media::audio::common::AudioProfile parcelable = VALUE_OR_RETURN(toCommonParcelable(isInput));
159     media::AudioProfileSys parcelableSys;
160     parcelableSys.isDynamicFormat = mIsDynamicFormat;
161     parcelableSys.isDynamicChannels = mIsDynamicChannels;
162     parcelableSys.isDynamicRate = mIsDynamicRate;
163     return std::make_pair(parcelable, parcelableSys);
164 }
165 
fromParcelable(const AudioProfile::Aidl & aidl,bool isInput)166 ConversionResult<sp<AudioProfile>> AudioProfile::fromParcelable(
167         const AudioProfile::Aidl& aidl, bool isInput) {
168     sp<AudioProfile> legacy = VALUE_OR_RETURN(fromCommonParcelable(aidl.first, isInput));
169     const auto& parcelableSys = aidl.second;
170     legacy->mIsDynamicFormat = parcelableSys.isDynamicFormat;
171     legacy->mIsDynamicChannels = parcelableSys.isDynamicChannels;
172     legacy->mIsDynamicRate = parcelableSys.isDynamicRate;
173     return legacy;
174 }
175 
176 ConversionResult<media::audio::common::AudioProfile>
toCommonParcelable(bool isInput) const177 AudioProfile::toCommonParcelable(bool isInput) const {
178     media::audio::common::AudioProfile parcelable;
179     parcelable.name = mName;
180     parcelable.format = VALUE_OR_RETURN(
181             legacy2aidl_audio_format_t_AudioFormatDescription(mFormat));
182     // Note: legacy 'audio_profile' imposes a limit on the number of
183     // channel masks and sampling rates. That's why it's not used here
184     // and conversions are performed directly on the fields instead
185     // of using 'legacy2aidl_audio_profile_AudioProfile' from AidlConversion.
186     parcelable.channelMasks = VALUE_OR_RETURN(
187             convertContainer<std::vector<AudioChannelLayout>>(
188             mChannelMasks,
189             [isInput](audio_channel_mask_t m) {
190                 return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
191             }));
192     parcelable.sampleRates = VALUE_OR_RETURN(
193             convertContainer<std::vector<int32_t>>(mSamplingRates,
194                                                    convertIntegral<int32_t, uint32_t>));
195     parcelable.encapsulationType = VALUE_OR_RETURN(
196             legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
197     return parcelable;
198 }
199 
fromCommonParcelable(const media::audio::common::AudioProfile & aidl,bool isInput)200 ConversionResult<sp<AudioProfile>> AudioProfile::fromCommonParcelable(
201         const media::audio::common::AudioProfile& aidl, bool isInput) {
202     sp<AudioProfile> legacy = new AudioProfile();
203     legacy->mName = aidl.name;
204     legacy->mFormat = VALUE_OR_RETURN(
205             aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
206     legacy->mChannelMasks = VALUE_OR_RETURN(
207             convertContainer<ChannelMaskSet>(aidl.channelMasks,
208             [isInput](const AudioChannelLayout& l) {
209                 return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
210             }));
211     legacy->mSamplingRates = VALUE_OR_RETURN(
212             convertContainer<SampleRateSet>(aidl.sampleRates,
213                                             convertIntegral<uint32_t, int32_t>));
214     legacy->mEncapsulationType = VALUE_OR_RETURN(
215             aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
216                     aidl.encapsulationType));
217     return legacy;
218 }
219 
220 ConversionResult<sp<AudioProfile>>
aidl2legacy_AudioProfile(const AudioProfile::Aidl & aidl,bool isInput)221 aidl2legacy_AudioProfile(const AudioProfile::Aidl& aidl, bool isInput) {
222     return AudioProfile::fromParcelable(aidl, isInput);
223 }
224 
225 ConversionResult<AudioProfile::Aidl>
legacy2aidl_AudioProfile(const sp<AudioProfile> & legacy,bool isInput)226 legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy, bool isInput) {
227     return legacy->toParcelable(isInput);
228 }
229 
230 ConversionResult<sp<AudioProfile>>
aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile & aidl,bool isInput)231 aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile& aidl, bool isInput) {
232     return AudioProfile::fromCommonParcelable(aidl, isInput);
233 }
234 
235 ConversionResult<media::audio::common::AudioProfile>
legacy2aidl_AudioProfile_common(const sp<AudioProfile> & legacy,bool isInput)236 legacy2aidl_AudioProfile_common(const sp<AudioProfile>& legacy, bool isInput) {
237     return legacy->toCommonParcelable(isInput);
238 }
239 
add(const sp<AudioProfile> & profile)240 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
241 {
242     ssize_t index = size();
243     push_back(profile);
244     return index;
245 }
246 
clearProfiles()247 void AudioProfileVector::clearProfiles()
248 {
249     for (auto it = begin(); it != end();) {
250         if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
251             it = erase(it);
252         } else {
253             (*it)->clear();
254             ++it;
255         }
256     }
257 }
258 
getFirstValidProfile() const259 sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
260 {
261     for (const auto &profile : *this) {
262         if (profile->isValid()) {
263             return profile;
264         }
265     }
266     return nullptr;
267 }
268 
getFirstValidProfileFor(audio_format_t format) const269 sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
270 {
271     for (const auto &profile : *this) {
272         if (profile->isValid() && profile->getFormat() == format) {
273             return profile;
274         }
275     }
276     return nullptr;
277 }
278 
getSupportedFormats() const279 FormatVector AudioProfileVector::getSupportedFormats() const
280 {
281     FormatVector supportedFormats;
282     for (const auto &profile : *this) {
283         if (profile->hasValidFormat()) {
284             supportedFormats.push_back(profile->getFormat());
285         }
286     }
287     return supportedFormats;
288 }
289 
hasDynamicChannelsFor(audio_format_t format) const290 bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
291 {
292     for (const auto &profile : *this) {
293         if (profile->getFormat() == format && profile->isDynamicChannels()) {
294             return true;
295         }
296     }
297     return false;
298 }
299 
hasDynamicFormat() const300 bool AudioProfileVector::hasDynamicFormat() const
301 {
302     for (const auto &profile : *this) {
303         if (profile->isDynamicFormat()) {
304             return true;
305         }
306     }
307     return false;
308 }
309 
hasDynamicProfile() const310 bool AudioProfileVector::hasDynamicProfile() const
311 {
312     for (const auto &profile : *this) {
313         if (profile->isDynamic()) {
314             return true;
315         }
316     }
317     return false;
318 }
319 
hasDynamicRateFor(audio_format_t format) const320 bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
321 {
322     for (const auto &profile : *this) {
323         if (profile->getFormat() == format && profile->isDynamicRate()) {
324             return true;
325         }
326     }
327     return false;
328 }
329 
contains(const sp<AudioProfile> & profile,bool ignoreDynamicFlags) const330 bool AudioProfileVector::contains(const sp<AudioProfile>& profile, bool ignoreDynamicFlags) const
331 {
332     for (const auto& audioProfile : *this) {
333         if (audioProfile->equals(profile, ignoreDynamicFlags)) {
334             return true;
335         }
336     }
337     return false;
338 }
339 
dump(std::string * dst,int spaces) const340 void AudioProfileVector::dump(std::string *dst, int spaces) const
341 {
342     dst->append(base::StringPrintf("%*s- Profiles (%zu):\n", spaces - 2, "", size()));
343     for (size_t i = 0; i < size(); i++) {
344         const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1);
345         dst->append(prefix);
346         std::string profileStr;
347         at(i)->dump(&profileStr, prefix.size());
348         dst->append(profileStr);
349     }
350 }
351 
equals(const AudioProfileVector & other) const352 bool AudioProfileVector::equals(const AudioProfileVector& other) const
353 {
354     return std::equal(begin(), end(), other.begin(), other.end(),
355                       [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
356                           return left->equals(right);
357                       });
358 }
359 
addAllValidProfiles(const AudioProfileVector & audioProfiles)360 void AudioProfileVector::addAllValidProfiles(const AudioProfileVector& audioProfiles) {
361     for (const auto& audioProfile : audioProfiles) {
362         if (audioProfile->isValid() && !contains(audioProfile, true /*ignoreDynamicFlags*/)) {
363             add(audioProfile);
364         }
365     }
366 }
367 
368 ConversionResult<AudioProfileVector>
aidl2legacy_AudioProfileVector(const AudioProfileVector::Aidl & aidl,bool isInput)369 aidl2legacy_AudioProfileVector(const AudioProfileVector::Aidl& aidl, bool isInput) {
370     return convertContainers<AudioProfileVector>(aidl.first, aidl.second,
371             [isInput](const media::audio::common::AudioProfile& p,
372                       const media::AudioProfileSys& ps) {
373                 return aidl2legacy_AudioProfile(std::make_pair(p, ps), isInput);
374             });
375 }
376 
377 ConversionResult<AudioProfileVector::Aidl>
legacy2aidl_AudioProfileVector(const AudioProfileVector & legacy,bool isInput)378 legacy2aidl_AudioProfileVector(const AudioProfileVector& legacy, bool isInput) {
379     return convertContainerSplit<
380             std::vector<media::audio::common::AudioProfile>,
381             std::vector<media::AudioProfileSys>>(legacy,
382             [isInput](const sp<AudioProfile>& p) {
383                 return legacy2aidl_AudioProfile(p, isInput);
384             });
385 }
386 
intersectAudioProfiles(const AudioProfileVector & profiles1,const AudioProfileVector & profiles2)387 AudioProfileVector intersectAudioProfiles(const AudioProfileVector& profiles1,
388                                           const AudioProfileVector& profiles2)
389 {
390     std::map<audio_format_t, std::pair<ChannelMaskSet, SampleRateSet>> infos2;
391     for (const auto& profile : profiles2) {
392         infos2.emplace(profile->getFormat(),
393                 std::make_pair(profile->getChannels(), profile->getSampleRates()));
394     }
395     AudioProfileVector profiles;
396     for (const auto& profile : profiles1) {
397         const auto it = infos2.find(profile->getFormat());
398         if (it == infos2.end()) {
399             continue;
400         }
401         ChannelMaskSet channelMasks = SetIntersection(profile->getChannels(), it->second.first);
402         if (channelMasks.empty()) {
403             continue;
404         }
405         SampleRateSet sampleRates = SetIntersection(profile->getSampleRates(), it->second.second);
406         if (sampleRates.empty()) {
407             continue;
408         }
409         profiles.push_back(new AudioProfile(profile->getFormat(), channelMasks, sampleRates));
410     }
411     return profiles;
412 }
413 
414 } // namespace android
415