blob: 91be3467487f2975cefba95ba33977b7997713c2 [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
jiabin17058fa2019-10-08 17:33:38 -0700133status_t AudioProfile::writeToParcel(Parcel *parcel) const
134{
135 status_t status = NO_ERROR;
136 if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
137 if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
138 std::vector<int> values(mChannelMasks.begin(), mChannelMasks.end());
139 if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
140 values.clear();
141 values.assign(mSamplingRates.begin(), mSamplingRates.end());
142 if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
143 if ((status = parcel->writeBool(mIsDynamicFormat)) != NO_ERROR) return status;
144 if ((status = parcel->writeBool(mIsDynamicChannels)) != NO_ERROR) return status;
145 if ((status = parcel->writeBool(mIsDynamicRate)) != NO_ERROR) return status;
146 return status;
147}
148
149status_t AudioProfile::readFromParcel(const Parcel *parcel)
150{
151 status_t status = NO_ERROR;
152 if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
153 static_assert(sizeof(mFormat) == sizeof(uint32_t));
154 if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
155 return status;
156 }
157 std::vector<int> values;
158 if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
159 mChannelMasks.clear();
160 mChannelMasks.insert(values.begin(), values.end());
161 values.clear();
162 if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
163 mSamplingRates.clear();
164 mSamplingRates.insert(values.begin(), values.end());
165 if ((status = parcel->readBool(&mIsDynamicFormat)) != NO_ERROR) return status;
166 if ((status = parcel->readBool(&mIsDynamicChannels)) != NO_ERROR) return status;
167 if ((status = parcel->readBool(&mIsDynamicRate)) != NO_ERROR) return status;
168 return status;
169}
170
jiabin3e277cc2019-09-10 14:27:34 -0700171ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
Mikhail Naganove50f6282018-07-26 16:20:43 -0700172{
jiabin06e4bab2019-07-29 10:13:34 -0700173 ssize_t index = size();
174 push_back(profile);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700175 return index;
176}
177
jiabin3e277cc2019-09-10 14:27:34 -0700178void AudioProfileVector::clearProfiles()
Mikhail Naganove50f6282018-07-26 16:20:43 -0700179{
jiabin06e4bab2019-07-29 10:13:34 -0700180 for (auto it = begin(); it != end();) {
181 if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
182 it = erase(it);
183 } else {
184 (*it)->clear();
185 ++it;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700186 }
Mikhail Naganove50f6282018-07-26 16:20:43 -0700187 }
188}
189
jiabin3e277cc2019-09-10 14:27:34 -0700190sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700191{
jiabin06e4bab2019-07-29 10:13:34 -0700192 for (const auto &profile : *this) {
193 if (profile->isValid()) {
194 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700195 }
196 }
jiabin06e4bab2019-07-29 10:13:34 -0700197 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700198}
199
jiabin3e277cc2019-09-10 14:27:34 -0700200sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700201{
jiabin06e4bab2019-07-29 10:13:34 -0700202 for (const auto &profile : *this) {
203 if (profile->isValid() && profile->getFormat() == format) {
204 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700205 }
206 }
jiabin06e4bab2019-07-29 10:13:34 -0700207 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700208}
209
jiabin3e277cc2019-09-10 14:27:34 -0700210FormatVector AudioProfileVector::getSupportedFormats() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700211{
212 FormatVector supportedFormats;
jiabin06e4bab2019-07-29 10:13:34 -0700213 for (const auto &profile : *this) {
214 if (profile->hasValidFormat()) {
215 supportedFormats.push_back(profile->getFormat());
Mikhail Naganove50f6282018-07-26 16:20:43 -0700216 }
217 }
218 return supportedFormats;
219}
220
jiabin3e277cc2019-09-10 14:27:34 -0700221bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700222{
jiabin06e4bab2019-07-29 10:13:34 -0700223 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700224 if (profile->getFormat() == format && profile->isDynamicChannels()) {
225 return true;
226 }
227 }
228 return false;
229}
230
jiabin3e277cc2019-09-10 14:27:34 -0700231bool AudioProfileVector::hasDynamicFormat() const
jiabin9bb3a1e2019-08-19 10:10:17 -0700232{
233 for (const auto &profile : *this) {
234 if (profile->isDynamicFormat()) {
235 return true;
236 }
237 }
238 return false;
239}
240
jiabin3e277cc2019-09-10 14:27:34 -0700241bool AudioProfileVector::hasDynamicProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700242{
jiabin06e4bab2019-07-29 10:13:34 -0700243 for (const auto &profile : *this) {
244 if (profile->isDynamic()) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700245 return true;
246 }
247 }
248 return false;
249}
250
jiabin3e277cc2019-09-10 14:27:34 -0700251bool AudioProfileVector::hasDynamicRateFor(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) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700254 if (profile->getFormat() == format && profile->isDynamicRate()) {
255 return true;
256 }
257 }
258 return false;
259}
260
jiabin3e277cc2019-09-10 14:27:34 -0700261void AudioProfileVector::dump(std::string *dst, int spaces) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700262{
jiabin9bb3a1e2019-08-19 10:10:17 -0700263 dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
Mikhail Naganove50f6282018-07-26 16:20:43 -0700264 for (size_t i = 0; i < size(); i++) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700265 dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
266 std::string profileStr;
267 at(i)->dump(&profileStr, spaces + 8);
268 dst->append(profileStr);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700269 }
270}
271
jiabin17058fa2019-10-08 17:33:38 -0700272status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
273{
274 status_t status = NO_ERROR;
275 if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
276 for (const auto &audioProfile : *this) {
277 if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
278 break;
279 }
280 }
281 return status;
282}
283
284status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
285{
286 status_t status = NO_ERROR;
287 this->clear();
288 if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
289 for (size_t i = 0; i < this->size(); ++i) {
290 this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
291 if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
292 this->clear();
293 break;
294 }
295 }
296 return status;
297}
298
jiabin49e69a12019-10-15 16:04:13 -0700299bool AudioProfileVector::equals(const AudioProfileVector& other) const
300{
301 return std::equal(begin(), end(), other.begin(), other.end(),
302 [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
303 return left->equals(right);
304 });
305}
306
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800307} // namespace android