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
operator ==(const AudioProfile & left,const AudioProfile & right)30 bool operator == (const AudioProfile &left, const AudioProfile &right)
31 {
32 return (left.getFormat() == right.getFormat()) &&
33 (left.getChannels() == right.getChannels()) &&
34 (left.getSampleRates() == right.getSampleRates());
35 }
36
37 // static
createFullDynamic(audio_format_t dynamicFormat)38 sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
39 {
40 AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
41 ChannelMaskSet(), SampleRateSet());
42 dynamicProfile->setDynamicFormat(true);
43 dynamicProfile->setDynamicChannels(true);
44 dynamicProfile->setDynamicRate(true);
45 return dynamicProfile;
46 }
47
AudioProfile(audio_format_t format,audio_channel_mask_t channelMasks,uint32_t samplingRate)48 AudioProfile::AudioProfile(audio_format_t format,
49 audio_channel_mask_t channelMasks,
50 uint32_t samplingRate) :
51 mName(""),
52 mFormat(format)
53 {
54 mChannelMasks.insert(channelMasks);
55 mSamplingRates.insert(samplingRate);
56 }
57
AudioProfile(audio_format_t format,const ChannelMaskSet & channelMasks,const SampleRateSet & samplingRateCollection)58 AudioProfile::AudioProfile(audio_format_t format,
59 const ChannelMaskSet &channelMasks,
60 const SampleRateSet &samplingRateCollection) :
61 AudioProfile(format, channelMasks, samplingRateCollection,
62 AUDIO_ENCAPSULATION_TYPE_NONE) {}
63
AudioProfile(audio_format_t format,const ChannelMaskSet & channelMasks,const SampleRateSet & samplingRateCollection,audio_encapsulation_type_t encapsulationType)64 AudioProfile::AudioProfile(audio_format_t format,
65 const ChannelMaskSet &channelMasks,
66 const SampleRateSet &samplingRateCollection,
67 audio_encapsulation_type_t encapsulationType) :
68 mName(""),
69 mFormat(format),
70 mChannelMasks(channelMasks),
71 mSamplingRates(samplingRateCollection),
72 mEncapsulationType(encapsulationType) {}
73
setChannels(const ChannelMaskSet & channelMasks)74 void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
75 {
76 if (mIsDynamicChannels) {
77 mChannelMasks = channelMasks;
78 }
79 }
80
setSampleRates(const SampleRateSet & sampleRates)81 void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
82 {
83 if (mIsDynamicRate) {
84 mSamplingRates = sampleRates;
85 }
86 }
87
clear()88 void AudioProfile::clear()
89 {
90 if (mIsDynamicChannels) {
91 mChannelMasks.clear();
92 }
93 if (mIsDynamicRate) {
94 mSamplingRates.clear();
95 }
96 }
97
dump(std::string * dst,int spaces) const98 void AudioProfile::dump(std::string *dst, int spaces) const
99 {
100 dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
101 mIsDynamicChannels ? "[dynamic channels]" : "",
102 mIsDynamicRate ? "[dynamic rates]" : ""));
103 if (mName.length() != 0) {
104 dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
105 }
106 std::string formatLiteral;
107 if (FormatConverter::toString(mFormat, formatLiteral)) {
108 dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
109 }
110 if (!mSamplingRates.empty()) {
111 dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
112 for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
113 dst->append(base::StringPrintf("%d", *it));
114 dst->append(++it == mSamplingRates.end() ? "" : ", ");
115 }
116 dst->append("\n");
117 }
118
119 if (!mChannelMasks.empty()) {
120 dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
121 for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
122 dst->append(base::StringPrintf("0x%04x", *it));
123 dst->append(++it == mChannelMasks.end() ? "" : ", ");
124 }
125 dst->append("\n");
126 }
127
128 dst->append(base::StringPrintf(
129 "%*s- encapsulation type: %#x\n", spaces, "", mEncapsulationType));
130 }
131
equals(const sp<AudioProfile> & other) const132 bool AudioProfile::equals(const sp<AudioProfile>& other) const
133 {
134 return other != nullptr &&
135 mName.compare(other->mName) == 0 &&
136 mFormat == other->getFormat() &&
137 mChannelMasks == other->getChannels() &&
138 mSamplingRates == other->getSampleRates() &&
139 mIsDynamicFormat == other->isDynamicFormat() &&
140 mIsDynamicChannels == other->isDynamicChannels() &&
141 mIsDynamicRate == other->isDynamicRate() &&
142 mEncapsulationType == other->getEncapsulationType();
143 }
144
operator =(const AudioProfile & other)145 AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
146 mName = other.mName;
147 mFormat = other.mFormat;
148 mChannelMasks = other.mChannelMasks;
149 mSamplingRates = other.mSamplingRates;
150 mEncapsulationType = other.mEncapsulationType;
151 mIsDynamicFormat = other.mIsDynamicFormat;
152 mIsDynamicChannels = other.mIsDynamicChannels;
153 mIsDynamicRate = other.mIsDynamicRate;
154 return *this;
155 }
156
writeToParcel(Parcel * parcel) const157 status_t AudioProfile::writeToParcel(Parcel *parcel) const {
158 media::AudioProfile parcelable = VALUE_OR_RETURN_STATUS(toParcelable());
159 return parcelable.writeToParcel(parcel);
160 }
161
162 ConversionResult<media::AudioProfile>
toParcelable() const163 AudioProfile::toParcelable() const {
164 media::AudioProfile parcelable;
165 parcelable.name = mName;
166 parcelable.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(mFormat));
167 parcelable.channelMasks = VALUE_OR_RETURN(
168 convertContainer<std::vector<int32_t>>(mChannelMasks,
169 legacy2aidl_audio_channel_mask_t_int32_t));
170 parcelable.samplingRates = VALUE_OR_RETURN(
171 convertContainer<std::vector<int32_t>>(mSamplingRates,
172 convertIntegral<int32_t, uint32_t>));
173 parcelable.isDynamicFormat = mIsDynamicFormat;
174 parcelable.isDynamicChannels = mIsDynamicChannels;
175 parcelable.isDynamicRate = mIsDynamicRate;
176 parcelable.encapsulationType = VALUE_OR_RETURN(
177 legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
178 return parcelable;
179 }
180
readFromParcel(const Parcel * parcel)181 status_t AudioProfile::readFromParcel(const Parcel *parcel) {
182 media::AudioProfile parcelable;
183 if (status_t status = parcelable.readFromParcel(parcel); status != OK) {
184 return status;
185 }
186 *this = *VALUE_OR_RETURN_STATUS(fromParcelable(parcelable));
187 return OK;
188 }
189
190 ConversionResult<sp<AudioProfile>>
fromParcelable(const media::AudioProfile & parcelable)191 AudioProfile::fromParcelable(const media::AudioProfile& parcelable) {
192 sp<AudioProfile> legacy = new AudioProfile();
193 legacy->mName = parcelable.name;
194 legacy->mFormat = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(parcelable.format));
195 legacy->mChannelMasks = VALUE_OR_RETURN(
196 convertContainer<ChannelMaskSet>(parcelable.channelMasks,
197 aidl2legacy_int32_t_audio_channel_mask_t));
198 legacy->mSamplingRates = VALUE_OR_RETURN(
199 convertContainer<SampleRateSet>(parcelable.samplingRates,
200 convertIntegral<uint32_t, int32_t>));
201 legacy->mIsDynamicFormat = parcelable.isDynamicFormat;
202 legacy->mIsDynamicChannels = parcelable.isDynamicChannels;
203 legacy->mIsDynamicRate = parcelable.isDynamicRate;
204 legacy->mEncapsulationType = VALUE_OR_RETURN(
205 aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
206 parcelable.encapsulationType));
207 return legacy;
208 }
209
210 ConversionResult<sp<AudioProfile>>
aidl2legacy_AudioProfile(const media::AudioProfile & aidl)211 aidl2legacy_AudioProfile(const media::AudioProfile& aidl) {
212 return AudioProfile::fromParcelable(aidl);
213 }
214
215 ConversionResult<media::AudioProfile>
legacy2aidl_AudioProfile(const sp<AudioProfile> & legacy)216 legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy) {
217 return legacy->toParcelable();
218 }
219
add(const sp<AudioProfile> & profile)220 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
221 {
222 ssize_t index = size();
223 push_back(profile);
224 return index;
225 }
226
clearProfiles()227 void AudioProfileVector::clearProfiles()
228 {
229 for (auto it = begin(); it != end();) {
230 if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
231 it = erase(it);
232 } else {
233 (*it)->clear();
234 ++it;
235 }
236 }
237 }
238
getFirstValidProfile() const239 sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
240 {
241 for (const auto &profile : *this) {
242 if (profile->isValid()) {
243 return profile;
244 }
245 }
246 return nullptr;
247 }
248
getFirstValidProfileFor(audio_format_t format) const249 sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
250 {
251 for (const auto &profile : *this) {
252 if (profile->isValid() && profile->getFormat() == format) {
253 return profile;
254 }
255 }
256 return nullptr;
257 }
258
getSupportedFormats() const259 FormatVector AudioProfileVector::getSupportedFormats() const
260 {
261 FormatVector supportedFormats;
262 for (const auto &profile : *this) {
263 if (profile->hasValidFormat()) {
264 supportedFormats.push_back(profile->getFormat());
265 }
266 }
267 return supportedFormats;
268 }
269
hasDynamicChannelsFor(audio_format_t format) const270 bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
271 {
272 for (const auto &profile : *this) {
273 if (profile->getFormat() == format && profile->isDynamicChannels()) {
274 return true;
275 }
276 }
277 return false;
278 }
279
hasDynamicFormat() const280 bool AudioProfileVector::hasDynamicFormat() const
281 {
282 for (const auto &profile : *this) {
283 if (profile->isDynamicFormat()) {
284 return true;
285 }
286 }
287 return false;
288 }
289
hasDynamicProfile() const290 bool AudioProfileVector::hasDynamicProfile() const
291 {
292 for (const auto &profile : *this) {
293 if (profile->isDynamic()) {
294 return true;
295 }
296 }
297 return false;
298 }
299
hasDynamicRateFor(audio_format_t format) const300 bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
301 {
302 for (const auto &profile : *this) {
303 if (profile->getFormat() == format && profile->isDynamicRate()) {
304 return true;
305 }
306 }
307 return false;
308 }
309
contains(const sp<AudioProfile> & profile) const310 bool AudioProfileVector::contains(const sp<AudioProfile>& profile) const
311 {
312 for (const auto& audioProfile : *this) {
313 if (audioProfile->equals(profile)) {
314 return true;
315 }
316 }
317 return false;
318 }
319
dump(std::string * dst,int spaces) const320 void AudioProfileVector::dump(std::string *dst, int spaces) const
321 {
322 dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
323 for (size_t i = 0; i < size(); i++) {
324 dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
325 std::string profileStr;
326 at(i)->dump(&profileStr, spaces + 8);
327 dst->append(profileStr);
328 }
329 }
330
writeToParcel(Parcel * parcel) const331 status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
332 {
333 status_t status = NO_ERROR;
334 if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
335 for (const auto &audioProfile : *this) {
336 if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
337 break;
338 }
339 }
340 return status;
341 }
342
readFromParcel(const Parcel * parcel)343 status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
344 {
345 status_t status = NO_ERROR;
346 this->clear();
347 if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
348 for (size_t i = 0; i < this->size(); ++i) {
349 this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
350 if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
351 this->clear();
352 break;
353 }
354 }
355 return status;
356 }
357
equals(const AudioProfileVector & other) const358 bool AudioProfileVector::equals(const AudioProfileVector& other) const
359 {
360 return std::equal(begin(), end(), other.begin(), other.end(),
361 [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
362 return left->equals(right);
363 });
364 }
365
366 ConversionResult<AudioProfileVector>
aidl2legacy_AudioProfileVector(const std::vector<media::AudioProfile> & aidl)367 aidl2legacy_AudioProfileVector(const std::vector<media::AudioProfile>& aidl) {
368 return convertContainer<AudioProfileVector>(aidl, aidl2legacy_AudioProfile);
369 }
370
371 ConversionResult<std::vector<media::AudioProfile>>
legacy2aidl_AudioProfileVector(const AudioProfileVector & legacy)372 legacy2aidl_AudioProfileVector(const AudioProfileVector& legacy) {
373 return convertContainer<std::vector<media::AudioProfile>>(legacy, legacy2aidl_AudioProfile);
374 }
375
intersectAudioProfiles(const AudioProfileVector & profiles1,const AudioProfileVector & profiles2)376 AudioProfileVector intersectAudioProfiles(const AudioProfileVector& profiles1,
377 const AudioProfileVector& profiles2)
378 {
379 std::map<audio_format_t, std::pair<ChannelMaskSet, SampleRateSet>> infos2;
380 for (const auto& profile : profiles2) {
381 infos2.emplace(profile->getFormat(),
382 std::make_pair(profile->getChannels(), profile->getSampleRates()));
383 }
384 AudioProfileVector profiles;
385 for (const auto& profile : profiles1) {
386 const auto it = infos2.find(profile->getFormat());
387 if (it == infos2.end()) {
388 continue;
389 }
390 ChannelMaskSet channelMasks = SetIntersection(profile->getChannels(), it->second.first);
391 if (channelMasks.empty()) {
392 continue;
393 }
394 SampleRateSet sampleRates = SetIntersection(profile->getSampleRates(), it->second.second);
395 if (sampleRates.empty()) {
396 continue;
397 }
398 profiles.push_back(new AudioProfile(profile->getFormat(), channelMasks, sampleRates));
399 }
400 return profiles;
401 }
402
403 } // namespace android
404