blob: f2bed258b00e4c6a29bb3858dfe0e0ee2abf376a [file] [log] [blame]
François Gaffie112b0af2015-11-19 16:13:25 +01001/*
jiabin3e277cc2019-09-10 14:27:34 -07002 * Copyright (C) 2019 The Android Open Source Project
François Gaffie112b0af2015-11-19 16:13:25 +01003 *
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
Mikhail Naganovfa69dc62018-07-27 09:58:58 -070017#include <set>
Mikhail Naganove50f6282018-07-26 16:20:43 -070018
jiabin9bb3a1e2019-08-19 10:10:17 -070019#define LOG_TAG "AudioProfile"
François Gaffie112b0af2015-11-19 16:13:25 +010020//#define LOG_NDEBUG 0
21
jiabin9bb3a1e2019-08-19 10:10:17 -070022#include <android-base/stringprintf.h>
jiabin06e4bab2019-07-29 10:13:34 -070023#include <media/AudioContainers.h>
jiabin9bb3a1e2019-08-19 10:10:17 -070024#include <media/AudioProfile.h>
25#include <media/TypeConverter.h>
Mikhail Naganove50f6282018-07-26 16:20:43 -070026#include <utils/Errors.h>
27
François Gaffie112b0af2015-11-19 16:13:25 +010028namespace android {
29
jiabin9bb3a1e2019-08-19 10:10:17 -070030bool operator == (const AudioProfile &left, const AudioProfile &right)
Mikhail Naganove50f6282018-07-26 16:20:43 -070031{
jiabin9bb3a1e2019-08-19 10:10:17 -070032 return (left.getFormat() == right.getFormat()) &&
33 (left.getChannels() == right.getChannels()) &&
34 (left.getSampleRates() == right.getSampleRates());
Mikhail Naganove50f6282018-07-26 16:20:43 -070035}
36
jiabin9bb3a1e2019-08-19 10:10:17 -070037// static
38sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
Mikhail Naganov21b43362018-06-04 10:37:09 -070039{
jiabin9bb3a1e2019-08-19 10:10:17 -070040 AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
jiabin06e4bab2019-07-29 10:13:34 -070041 ChannelMaskSet(), SampleRateSet());
Mikhail Naganov21b43362018-06-04 10:37:09 -070042 dynamicProfile->setDynamicFormat(true);
43 dynamicProfile->setDynamicChannels(true);
44 dynamicProfile->setDynamicRate(true);
45 return dynamicProfile;
46}
47
Mikhail Naganove50f6282018-07-26 16:20:43 -070048AudioProfile::AudioProfile(audio_format_t format,
49 audio_channel_mask_t channelMasks,
50 uint32_t samplingRate) :
jiabin9bb3a1e2019-08-19 10:10:17 -070051 mName(""),
Mikhail Naganove50f6282018-07-26 16:20:43 -070052 mFormat(format)
53{
jiabin06e4bab2019-07-29 10:13:34 -070054 mChannelMasks.insert(channelMasks);
55 mSamplingRates.insert(samplingRate);
Mikhail Naganove50f6282018-07-26 16:20:43 -070056}
57
58AudioProfile::AudioProfile(audio_format_t format,
jiabin06e4bab2019-07-29 10:13:34 -070059 const ChannelMaskSet &channelMasks,
60 const SampleRateSet &samplingRateCollection) :
jiabin82e56932021-03-05 06:35:19 +000061 AudioProfile(format, channelMasks, samplingRateCollection,
62 AUDIO_ENCAPSULATION_TYPE_NONE) {}
63
64AudioProfile::AudioProfile(audio_format_t format,
65 const ChannelMaskSet &channelMasks,
66 const SampleRateSet &samplingRateCollection,
67 audio_encapsulation_type_t encapsulationType) :
jiabin9bb3a1e2019-08-19 10:10:17 -070068 mName(""),
Mikhail Naganove50f6282018-07-26 16:20:43 -070069 mFormat(format),
70 mChannelMasks(channelMasks),
jiabin82e56932021-03-05 06:35:19 +000071 mSamplingRates(samplingRateCollection),
72 mEncapsulationType(encapsulationType) {}
Mikhail Naganove50f6282018-07-26 16:20:43 -070073
jiabin06e4bab2019-07-29 10:13:34 -070074void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
Mikhail Naganove50f6282018-07-26 16:20:43 -070075{
76 if (mIsDynamicChannels) {
77 mChannelMasks = channelMasks;
78 }
79}
80
jiabin06e4bab2019-07-29 10:13:34 -070081void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
Mikhail Naganove50f6282018-07-26 16:20:43 -070082{
83 if (mIsDynamicRate) {
84 mSamplingRates = sampleRates;
85 }
86}
87
88void AudioProfile::clear()
89{
90 if (mIsDynamicChannels) {
91 mChannelMasks.clear();
92 }
93 if (mIsDynamicRate) {
94 mSamplingRates.clear();
95 }
96}
97
jiabin9bb3a1e2019-08-19 10:10:17 -070098void AudioProfile::dump(std::string *dst, int spaces) const
François Gaffie112b0af2015-11-19 16:13:25 +010099{
jiabin9bb3a1e2019-08-19 10:10:17 -0700100 dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
François Gaffie112b0af2015-11-19 16:13:25 +0100101 mIsDynamicChannels ? "[dynamic channels]" : "",
jiabin9bb3a1e2019-08-19 10:10:17 -0700102 mIsDynamicRate ? "[dynamic rates]" : ""));
François Gaffie112b0af2015-11-19 16:13:25 +0100103 if (mName.length() != 0) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700104 dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +0100105 }
106 std::string formatLiteral;
107 if (FormatConverter::toString(mFormat, formatLiteral)) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700108 dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +0100109 }
jiabin06e4bab2019-07-29 10:13:34 -0700110 if (!mSamplingRates.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700111 dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700112 for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700113 dst->append(base::StringPrintf("%d", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700114 dst->append(++it == mSamplingRates.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100115 }
Andy Hungbb54e202018-10-05 11:42:02 -0700116 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100117 }
118
jiabin06e4bab2019-07-29 10:13:34 -0700119 if (!mChannelMasks.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700120 dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700121 for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700122 dst->append(base::StringPrintf("0x%04x", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700123 dst->append(++it == mChannelMasks.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100124 }
Andy Hungbb54e202018-10-05 11:42:02 -0700125 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100126 }
jiabin82e56932021-03-05 06:35:19 +0000127
128 dst->append(base::StringPrintf(
129 "%*s- encapsulation type: %#x\n", spaces, "", mEncapsulationType));
François Gaffie112b0af2015-11-19 16:13:25 +0100130}
131
jiabin49e69a12019-10-15 16:04:13 -0700132bool 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() &&
jiabin82e56932021-03-05 06:35:19 +0000141 mIsDynamicRate == other->isDynamicRate() &&
142 mEncapsulationType == other->getEncapsulationType();
jiabin49e69a12019-10-15 16:04:13 -0700143}
144
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800145AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
146 mName = other.mName;
147 mFormat = other.mFormat;
148 mChannelMasks = other.mChannelMasks;
149 mSamplingRates = other.mSamplingRates;
jiabin82e56932021-03-05 06:35:19 +0000150 mEncapsulationType = other.mEncapsulationType;
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800151 mIsDynamicFormat = other.mIsDynamicFormat;
152 mIsDynamicChannels = other.mIsDynamicChannels;
153 mIsDynamicRate = other.mIsDynamicRate;
154 return *this;
jiabin17058fa2019-10-08 17:33:38 -0700155}
156
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800157status_t AudioProfile::writeToParcel(Parcel *parcel) const {
158 media::AudioProfile parcelable = VALUE_OR_RETURN_STATUS(toParcelable());
159 return parcelable.writeToParcel(parcel);
160 }
161
162ConversionResult<media::AudioProfile>
163AudioProfile::toParcelable() const {
164 media::AudioProfile parcelable;
165 parcelable.name = mName;
Mikhail Naganovb60bd1b2021-07-15 17:31:43 -0700166 parcelable.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(mFormat));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800167 parcelable.channelMasks = VALUE_OR_RETURN(
Mikhail Naganov2d8df4e2021-06-03 13:59:13 -0700168 convertContainer<std::vector<media::AudioChannelMask>>(
169 mChannelMasks,
170 legacy2aidl_audio_channel_mask_t_AudioChannelMask));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800171 parcelable.samplingRates = VALUE_OR_RETURN(
172 convertContainer<std::vector<int32_t>>(mSamplingRates,
173 convertIntegral<int32_t, uint32_t>));
174 parcelable.isDynamicFormat = mIsDynamicFormat;
175 parcelable.isDynamicChannels = mIsDynamicChannels;
176 parcelable.isDynamicRate = mIsDynamicRate;
jiabin82e56932021-03-05 06:35:19 +0000177 parcelable.encapsulationType = VALUE_OR_RETURN(
178 legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800179 return parcelable;
180}
181
182status_t AudioProfile::readFromParcel(const Parcel *parcel) {
183 media::AudioProfile parcelable;
184 if (status_t status = parcelable.readFromParcel(parcel); status != OK) {
jiabin17058fa2019-10-08 17:33:38 -0700185 return status;
186 }
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800187 *this = *VALUE_OR_RETURN_STATUS(fromParcelable(parcelable));
188 return OK;
189}
190
191ConversionResult<sp<AudioProfile>>
192AudioProfile::fromParcelable(const media::AudioProfile& parcelable) {
193 sp<AudioProfile> legacy = new AudioProfile();
194 legacy->mName = parcelable.name;
Mikhail Naganovb60bd1b2021-07-15 17:31:43 -0700195 legacy->mFormat = VALUE_OR_RETURN(
196 aidl2legacy_AudioFormatDescription_audio_format_t(parcelable.format));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800197 legacy->mChannelMasks = VALUE_OR_RETURN(
198 convertContainer<ChannelMaskSet>(parcelable.channelMasks,
Mikhail Naganov2d8df4e2021-06-03 13:59:13 -0700199 aidl2legacy_AudioChannelMask_audio_channel_mask_t));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800200 legacy->mSamplingRates = VALUE_OR_RETURN(
201 convertContainer<SampleRateSet>(parcelable.samplingRates,
202 convertIntegral<uint32_t, int32_t>));
203 legacy->mIsDynamicFormat = parcelable.isDynamicFormat;
204 legacy->mIsDynamicChannels = parcelable.isDynamicChannels;
205 legacy->mIsDynamicRate = parcelable.isDynamicRate;
jiabin82e56932021-03-05 06:35:19 +0000206 legacy->mEncapsulationType = VALUE_OR_RETURN(
207 aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
208 parcelable.encapsulationType));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800209 return legacy;
210}
211
212ConversionResult<sp<AudioProfile>>
213aidl2legacy_AudioProfile(const media::AudioProfile& aidl) {
214 return AudioProfile::fromParcelable(aidl);
215}
216
217ConversionResult<media::AudioProfile>
218legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy) {
219 return legacy->toParcelable();
jiabin17058fa2019-10-08 17:33:38 -0700220}
221
jiabin3e277cc2019-09-10 14:27:34 -0700222ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
Mikhail Naganove50f6282018-07-26 16:20:43 -0700223{
jiabin06e4bab2019-07-29 10:13:34 -0700224 ssize_t index = size();
225 push_back(profile);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700226 return index;
227}
228
jiabin3e277cc2019-09-10 14:27:34 -0700229void AudioProfileVector::clearProfiles()
Mikhail Naganove50f6282018-07-26 16:20:43 -0700230{
jiabin06e4bab2019-07-29 10:13:34 -0700231 for (auto it = begin(); it != end();) {
232 if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
233 it = erase(it);
234 } else {
235 (*it)->clear();
236 ++it;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700237 }
Mikhail Naganove50f6282018-07-26 16:20:43 -0700238 }
239}
240
jiabin3e277cc2019-09-10 14:27:34 -0700241sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700242{
jiabin06e4bab2019-07-29 10:13:34 -0700243 for (const auto &profile : *this) {
244 if (profile->isValid()) {
245 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700246 }
247 }
jiabin06e4bab2019-07-29 10:13:34 -0700248 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700249}
250
jiabin3e277cc2019-09-10 14:27:34 -0700251sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700252{
jiabin06e4bab2019-07-29 10:13:34 -0700253 for (const auto &profile : *this) {
254 if (profile->isValid() && profile->getFormat() == format) {
255 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700256 }
257 }
jiabin06e4bab2019-07-29 10:13:34 -0700258 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700259}
260
jiabin3e277cc2019-09-10 14:27:34 -0700261FormatVector AudioProfileVector::getSupportedFormats() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700262{
263 FormatVector supportedFormats;
jiabin06e4bab2019-07-29 10:13:34 -0700264 for (const auto &profile : *this) {
265 if (profile->hasValidFormat()) {
266 supportedFormats.push_back(profile->getFormat());
Mikhail Naganove50f6282018-07-26 16:20:43 -0700267 }
268 }
269 return supportedFormats;
270}
271
jiabin3e277cc2019-09-10 14:27:34 -0700272bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700273{
jiabin06e4bab2019-07-29 10:13:34 -0700274 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700275 if (profile->getFormat() == format && profile->isDynamicChannels()) {
276 return true;
277 }
278 }
279 return false;
280}
281
jiabin3e277cc2019-09-10 14:27:34 -0700282bool AudioProfileVector::hasDynamicFormat() const
jiabin9bb3a1e2019-08-19 10:10:17 -0700283{
284 for (const auto &profile : *this) {
285 if (profile->isDynamicFormat()) {
286 return true;
287 }
288 }
289 return false;
290}
291
jiabin3e277cc2019-09-10 14:27:34 -0700292bool AudioProfileVector::hasDynamicProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700293{
jiabin06e4bab2019-07-29 10:13:34 -0700294 for (const auto &profile : *this) {
295 if (profile->isDynamic()) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700296 return true;
297 }
298 }
299 return false;
300}
301
jiabin3e277cc2019-09-10 14:27:34 -0700302bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700303{
jiabin06e4bab2019-07-29 10:13:34 -0700304 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700305 if (profile->getFormat() == format && profile->isDynamicRate()) {
306 return true;
307 }
308 }
309 return false;
310}
311
jiabinb4fed192020-09-22 14:45:40 -0700312bool AudioProfileVector::contains(const sp<AudioProfile>& profile) const
313{
314 for (const auto& audioProfile : *this) {
315 if (audioProfile->equals(profile)) {
316 return true;
317 }
318 }
319 return false;
320}
321
jiabin3e277cc2019-09-10 14:27:34 -0700322void AudioProfileVector::dump(std::string *dst, int spaces) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700323{
jiabin9bb3a1e2019-08-19 10:10:17 -0700324 dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
Mikhail Naganove50f6282018-07-26 16:20:43 -0700325 for (size_t i = 0; i < size(); i++) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700326 dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
327 std::string profileStr;
328 at(i)->dump(&profileStr, spaces + 8);
329 dst->append(profileStr);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700330 }
331}
332
jiabin17058fa2019-10-08 17:33:38 -0700333status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
334{
335 status_t status = NO_ERROR;
336 if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
337 for (const auto &audioProfile : *this) {
338 if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
339 break;
340 }
341 }
342 return status;
343}
344
345status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
346{
347 status_t status = NO_ERROR;
348 this->clear();
349 if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
350 for (size_t i = 0; i < this->size(); ++i) {
351 this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
352 if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
353 this->clear();
354 break;
355 }
356 }
357 return status;
358}
359
jiabin49e69a12019-10-15 16:04:13 -0700360bool AudioProfileVector::equals(const AudioProfileVector& other) const
361{
362 return std::equal(begin(), end(), other.begin(), other.end(),
363 [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
364 return left->equals(right);
365 });
366}
367
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800368ConversionResult<AudioProfileVector>
369aidl2legacy_AudioProfileVector(const std::vector<media::AudioProfile>& aidl) {
370 return convertContainer<AudioProfileVector>(aidl, aidl2legacy_AudioProfile);
371}
372
373ConversionResult<std::vector<media::AudioProfile>>
374legacy2aidl_AudioProfileVector(const AudioProfileVector& legacy) {
375 return convertContainer<std::vector<media::AudioProfile>>(legacy, legacy2aidl_AudioProfile);
376}
377
jiabinbce0c1d2020-10-05 11:20:18 -0700378AudioProfileVector intersectAudioProfiles(const AudioProfileVector& profiles1,
379 const AudioProfileVector& profiles2)
380{
381 std::map<audio_format_t, std::pair<ChannelMaskSet, SampleRateSet>> infos2;
382 for (const auto& profile : profiles2) {
383 infos2.emplace(profile->getFormat(),
384 std::make_pair(profile->getChannels(), profile->getSampleRates()));
385 }
386 AudioProfileVector profiles;
387 for (const auto& profile : profiles1) {
388 const auto it = infos2.find(profile->getFormat());
389 if (it == infos2.end()) {
390 continue;
391 }
392 ChannelMaskSet channelMasks = SetIntersection(profile->getChannels(), it->second.first);
393 if (channelMasks.empty()) {
394 continue;
395 }
396 SampleRateSet sampleRates = SetIntersection(profile->getSampleRates(), it->second.second);
397 if (sampleRates.empty()) {
398 continue;
399 }
400 profiles.push_back(new AudioProfile(profile->getFormat(), channelMasks, sampleRates));
401 }
402 return profiles;
403}
404
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800405} // namespace android