blob: 3b47fed5848de5f01bb905577c2c8fc380329d5e [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) :
jiabin9bb3a1e2019-08-19 10:10:17 -070061 mName(""),
Mikhail Naganove50f6282018-07-26 16:20:43 -070062 mFormat(format),
63 mChannelMasks(channelMasks),
64 mSamplingRates(samplingRateCollection) {}
65
jiabin06e4bab2019-07-29 10:13:34 -070066void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
Mikhail Naganove50f6282018-07-26 16:20:43 -070067{
68 if (mIsDynamicChannels) {
69 mChannelMasks = channelMasks;
70 }
71}
72
jiabin06e4bab2019-07-29 10:13:34 -070073void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
Mikhail Naganove50f6282018-07-26 16:20:43 -070074{
75 if (mIsDynamicRate) {
76 mSamplingRates = sampleRates;
77 }
78}
79
80void AudioProfile::clear()
81{
82 if (mIsDynamicChannels) {
83 mChannelMasks.clear();
84 }
85 if (mIsDynamicRate) {
86 mSamplingRates.clear();
87 }
88}
89
jiabin9bb3a1e2019-08-19 10:10:17 -070090void AudioProfile::dump(std::string *dst, int spaces) const
François Gaffie112b0af2015-11-19 16:13:25 +010091{
jiabin9bb3a1e2019-08-19 10:10:17 -070092 dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
François Gaffie112b0af2015-11-19 16:13:25 +010093 mIsDynamicChannels ? "[dynamic channels]" : "",
jiabin9bb3a1e2019-08-19 10:10:17 -070094 mIsDynamicRate ? "[dynamic rates]" : ""));
François Gaffie112b0af2015-11-19 16:13:25 +010095 if (mName.length() != 0) {
jiabin9bb3a1e2019-08-19 10:10:17 -070096 dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +010097 }
98 std::string formatLiteral;
99 if (FormatConverter::toString(mFormat, formatLiteral)) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700100 dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +0100101 }
jiabin06e4bab2019-07-29 10:13:34 -0700102 if (!mSamplingRates.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700103 dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700104 for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700105 dst->append(base::StringPrintf("%d", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700106 dst->append(++it == mSamplingRates.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100107 }
Andy Hungbb54e202018-10-05 11:42:02 -0700108 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100109 }
110
jiabin06e4bab2019-07-29 10:13:34 -0700111 if (!mChannelMasks.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700112 dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700113 for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700114 dst->append(base::StringPrintf("0x%04x", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700115 dst->append(++it == mChannelMasks.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100116 }
Andy Hungbb54e202018-10-05 11:42:02 -0700117 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100118 }
François Gaffie112b0af2015-11-19 16:13:25 +0100119}
120
jiabin49e69a12019-10-15 16:04:13 -0700121bool AudioProfile::equals(const sp<AudioProfile>& other) const
122{
123 return other != nullptr &&
124 mName.compare(other->mName) == 0 &&
125 mFormat == other->getFormat() &&
126 mChannelMasks == other->getChannels() &&
127 mSamplingRates == other->getSampleRates() &&
128 mIsDynamicFormat == other->isDynamicFormat() &&
129 mIsDynamicChannels == other->isDynamicChannels() &&
130 mIsDynamicRate == other->isDynamicRate();
131}
132
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800133AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
134 mName = other.mName;
135 mFormat = other.mFormat;
136 mChannelMasks = other.mChannelMasks;
137 mSamplingRates = other.mSamplingRates;
138 mIsDynamicFormat = other.mIsDynamicFormat;
139 mIsDynamicChannels = other.mIsDynamicChannels;
140 mIsDynamicRate = other.mIsDynamicRate;
141 return *this;
jiabin17058fa2019-10-08 17:33:38 -0700142}
143
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800144status_t AudioProfile::writeToParcel(Parcel *parcel) const {
145 media::AudioProfile parcelable = VALUE_OR_RETURN_STATUS(toParcelable());
146 return parcelable.writeToParcel(parcel);
147 }
148
149ConversionResult<media::AudioProfile>
150AudioProfile::toParcelable() const {
151 media::AudioProfile parcelable;
152 parcelable.name = mName;
153 parcelable.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(mFormat));
154 parcelable.channelMasks = VALUE_OR_RETURN(
155 convertContainer<std::vector<int32_t>>(mChannelMasks,
156 legacy2aidl_audio_channel_mask_t_int32_t));
157 parcelable.samplingRates = VALUE_OR_RETURN(
158 convertContainer<std::vector<int32_t>>(mSamplingRates,
159 convertIntegral<int32_t, uint32_t>));
160 parcelable.isDynamicFormat = mIsDynamicFormat;
161 parcelable.isDynamicChannels = mIsDynamicChannels;
162 parcelable.isDynamicRate = mIsDynamicRate;
163 return parcelable;
164}
165
166status_t AudioProfile::readFromParcel(const Parcel *parcel) {
167 media::AudioProfile parcelable;
168 if (status_t status = parcelable.readFromParcel(parcel); status != OK) {
jiabin17058fa2019-10-08 17:33:38 -0700169 return status;
170 }
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800171 *this = *VALUE_OR_RETURN_STATUS(fromParcelable(parcelable));
172 return OK;
173}
174
175ConversionResult<sp<AudioProfile>>
176AudioProfile::fromParcelable(const media::AudioProfile& parcelable) {
177 sp<AudioProfile> legacy = new AudioProfile();
178 legacy->mName = parcelable.name;
179 legacy->mFormat = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(parcelable.format));
180 legacy->mChannelMasks = VALUE_OR_RETURN(
181 convertContainer<ChannelMaskSet>(parcelable.channelMasks,
182 aidl2legacy_int32_t_audio_channel_mask_t));
183 legacy->mSamplingRates = VALUE_OR_RETURN(
184 convertContainer<SampleRateSet>(parcelable.samplingRates,
185 convertIntegral<uint32_t, int32_t>));
186 legacy->mIsDynamicFormat = parcelable.isDynamicFormat;
187 legacy->mIsDynamicChannels = parcelable.isDynamicChannels;
188 legacy->mIsDynamicRate = parcelable.isDynamicRate;
189 return legacy;
190}
191
192ConversionResult<sp<AudioProfile>>
193aidl2legacy_AudioProfile(const media::AudioProfile& aidl) {
194 return AudioProfile::fromParcelable(aidl);
195}
196
197ConversionResult<media::AudioProfile>
198legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy) {
199 return legacy->toParcelable();
jiabin17058fa2019-10-08 17:33:38 -0700200}
201
jiabin3e277cc2019-09-10 14:27:34 -0700202ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
Mikhail Naganove50f6282018-07-26 16:20:43 -0700203{
jiabin06e4bab2019-07-29 10:13:34 -0700204 ssize_t index = size();
205 push_back(profile);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700206 return index;
207}
208
jiabin3e277cc2019-09-10 14:27:34 -0700209void AudioProfileVector::clearProfiles()
Mikhail Naganove50f6282018-07-26 16:20:43 -0700210{
jiabin06e4bab2019-07-29 10:13:34 -0700211 for (auto it = begin(); it != end();) {
212 if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
213 it = erase(it);
214 } else {
215 (*it)->clear();
216 ++it;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700217 }
Mikhail Naganove50f6282018-07-26 16:20:43 -0700218 }
219}
220
jiabin3e277cc2019-09-10 14:27:34 -0700221sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700222{
jiabin06e4bab2019-07-29 10:13:34 -0700223 for (const auto &profile : *this) {
224 if (profile->isValid()) {
225 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700226 }
227 }
jiabin06e4bab2019-07-29 10:13:34 -0700228 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700229}
230
jiabin3e277cc2019-09-10 14:27:34 -0700231sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700232{
jiabin06e4bab2019-07-29 10:13:34 -0700233 for (const auto &profile : *this) {
234 if (profile->isValid() && profile->getFormat() == format) {
235 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700236 }
237 }
jiabin06e4bab2019-07-29 10:13:34 -0700238 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700239}
240
jiabin3e277cc2019-09-10 14:27:34 -0700241FormatVector AudioProfileVector::getSupportedFormats() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700242{
243 FormatVector supportedFormats;
jiabin06e4bab2019-07-29 10:13:34 -0700244 for (const auto &profile : *this) {
245 if (profile->hasValidFormat()) {
246 supportedFormats.push_back(profile->getFormat());
Mikhail Naganove50f6282018-07-26 16:20:43 -0700247 }
248 }
249 return supportedFormats;
250}
251
jiabin3e277cc2019-09-10 14:27:34 -0700252bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700253{
jiabin06e4bab2019-07-29 10:13:34 -0700254 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700255 if (profile->getFormat() == format && profile->isDynamicChannels()) {
256 return true;
257 }
258 }
259 return false;
260}
261
jiabin3e277cc2019-09-10 14:27:34 -0700262bool AudioProfileVector::hasDynamicFormat() const
jiabin9bb3a1e2019-08-19 10:10:17 -0700263{
264 for (const auto &profile : *this) {
265 if (profile->isDynamicFormat()) {
266 return true;
267 }
268 }
269 return false;
270}
271
jiabin3e277cc2019-09-10 14:27:34 -0700272bool AudioProfileVector::hasDynamicProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700273{
jiabin06e4bab2019-07-29 10:13:34 -0700274 for (const auto &profile : *this) {
275 if (profile->isDynamic()) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700276 return true;
277 }
278 }
279 return false;
280}
281
jiabin3e277cc2019-09-10 14:27:34 -0700282bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700283{
jiabin06e4bab2019-07-29 10:13:34 -0700284 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700285 if (profile->getFormat() == format && profile->isDynamicRate()) {
286 return true;
287 }
288 }
289 return false;
290}
291
jiabinb4fed192020-09-22 14:45:40 -0700292bool AudioProfileVector::contains(const sp<AudioProfile>& profile) const
293{
294 for (const auto& audioProfile : *this) {
295 if (audioProfile->equals(profile)) {
296 return true;
297 }
298 }
299 return false;
300}
301
jiabin3e277cc2019-09-10 14:27:34 -0700302void AudioProfileVector::dump(std::string *dst, int spaces) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700303{
jiabin9bb3a1e2019-08-19 10:10:17 -0700304 dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
Mikhail Naganove50f6282018-07-26 16:20:43 -0700305 for (size_t i = 0; i < size(); i++) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700306 dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
307 std::string profileStr;
308 at(i)->dump(&profileStr, spaces + 8);
309 dst->append(profileStr);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700310 }
311}
312
jiabin17058fa2019-10-08 17:33:38 -0700313status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
314{
315 status_t status = NO_ERROR;
316 if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
317 for (const auto &audioProfile : *this) {
318 if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
319 break;
320 }
321 }
322 return status;
323}
324
325status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
326{
327 status_t status = NO_ERROR;
328 this->clear();
329 if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
330 for (size_t i = 0; i < this->size(); ++i) {
331 this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
332 if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
333 this->clear();
334 break;
335 }
336 }
337 return status;
338}
339
jiabin49e69a12019-10-15 16:04:13 -0700340bool AudioProfileVector::equals(const AudioProfileVector& other) const
341{
342 return std::equal(begin(), end(), other.begin(), other.end(),
343 [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
344 return left->equals(right);
345 });
346}
347
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800348ConversionResult<AudioProfileVector>
349aidl2legacy_AudioProfileVector(const std::vector<media::AudioProfile>& aidl) {
350 return convertContainer<AudioProfileVector>(aidl, aidl2legacy_AudioProfile);
351}
352
353ConversionResult<std::vector<media::AudioProfile>>
354legacy2aidl_AudioProfileVector(const AudioProfileVector& legacy) {
355 return convertContainer<std::vector<media::AudioProfile>>(legacy, legacy2aidl_AudioProfile);
356}
357
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800358} // namespace android