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