blob: 2d44f4a0c662cfbcb9e52e9aa712d87f11f27c9f [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
Mikhail Naganov57bd06f2021-08-10 16:41:54 -070030using media::audio::common::AudioChannelLayout;
31
jiabin9bb3a1e2019-08-19 10:10:17 -070032bool operator == (const AudioProfile &left, const AudioProfile &right)
Mikhail Naganove50f6282018-07-26 16:20:43 -070033{
jiabin9bb3a1e2019-08-19 10:10:17 -070034 return (left.getFormat() == right.getFormat()) &&
35 (left.getChannels() == right.getChannels()) &&
36 (left.getSampleRates() == right.getSampleRates());
Mikhail Naganove50f6282018-07-26 16:20:43 -070037}
38
jiabin9bb3a1e2019-08-19 10:10:17 -070039// static
40sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
Mikhail Naganov21b43362018-06-04 10:37:09 -070041{
jiabin9bb3a1e2019-08-19 10:10:17 -070042 AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
jiabin06e4bab2019-07-29 10:13:34 -070043 ChannelMaskSet(), SampleRateSet());
Mikhail Naganov21b43362018-06-04 10:37:09 -070044 dynamicProfile->setDynamicFormat(true);
45 dynamicProfile->setDynamicChannels(true);
46 dynamicProfile->setDynamicRate(true);
47 return dynamicProfile;
48}
49
Mikhail Naganove50f6282018-07-26 16:20:43 -070050AudioProfile::AudioProfile(audio_format_t format,
51 audio_channel_mask_t channelMasks,
52 uint32_t samplingRate) :
jiabin9bb3a1e2019-08-19 10:10:17 -070053 mName(""),
Mikhail Naganove50f6282018-07-26 16:20:43 -070054 mFormat(format)
55{
jiabin06e4bab2019-07-29 10:13:34 -070056 mChannelMasks.insert(channelMasks);
57 mSamplingRates.insert(samplingRate);
Mikhail Naganove50f6282018-07-26 16:20:43 -070058}
59
60AudioProfile::AudioProfile(audio_format_t format,
jiabin06e4bab2019-07-29 10:13:34 -070061 const ChannelMaskSet &channelMasks,
62 const SampleRateSet &samplingRateCollection) :
jiabin82e56932021-03-05 06:35:19 +000063 AudioProfile(format, channelMasks, samplingRateCollection,
64 AUDIO_ENCAPSULATION_TYPE_NONE) {}
65
66AudioProfile::AudioProfile(audio_format_t format,
67 const ChannelMaskSet &channelMasks,
68 const SampleRateSet &samplingRateCollection,
69 audio_encapsulation_type_t encapsulationType) :
jiabin9bb3a1e2019-08-19 10:10:17 -070070 mName(""),
Mikhail Naganove50f6282018-07-26 16:20:43 -070071 mFormat(format),
72 mChannelMasks(channelMasks),
jiabin82e56932021-03-05 06:35:19 +000073 mSamplingRates(samplingRateCollection),
74 mEncapsulationType(encapsulationType) {}
Mikhail Naganove50f6282018-07-26 16:20:43 -070075
jiabin06e4bab2019-07-29 10:13:34 -070076void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
Mikhail Naganove50f6282018-07-26 16:20:43 -070077{
78 if (mIsDynamicChannels) {
79 mChannelMasks = channelMasks;
80 }
81}
82
jiabin06e4bab2019-07-29 10:13:34 -070083void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
Mikhail Naganove50f6282018-07-26 16:20:43 -070084{
85 if (mIsDynamicRate) {
86 mSamplingRates = sampleRates;
87 }
88}
89
90void AudioProfile::clear()
91{
92 if (mIsDynamicChannels) {
93 mChannelMasks.clear();
94 }
95 if (mIsDynamicRate) {
96 mSamplingRates.clear();
97 }
98}
99
jiabin9bb3a1e2019-08-19 10:10:17 -0700100void AudioProfile::dump(std::string *dst, int spaces) const
François Gaffie112b0af2015-11-19 16:13:25 +0100101{
jiabin9bb3a1e2019-08-19 10:10:17 -0700102 dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
François Gaffie112b0af2015-11-19 16:13:25 +0100103 mIsDynamicChannels ? "[dynamic channels]" : "",
jiabin9bb3a1e2019-08-19 10:10:17 -0700104 mIsDynamicRate ? "[dynamic rates]" : ""));
François Gaffie112b0af2015-11-19 16:13:25 +0100105 if (mName.length() != 0) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700106 dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +0100107 }
108 std::string formatLiteral;
109 if (FormatConverter::toString(mFormat, formatLiteral)) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700110 dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
François Gaffie112b0af2015-11-19 16:13:25 +0100111 }
jiabin06e4bab2019-07-29 10:13:34 -0700112 if (!mSamplingRates.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700113 dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700114 for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700115 dst->append(base::StringPrintf("%d", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700116 dst->append(++it == mSamplingRates.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100117 }
Andy Hungbb54e202018-10-05 11:42:02 -0700118 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100119 }
120
jiabin06e4bab2019-07-29 10:13:34 -0700121 if (!mChannelMasks.empty()) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700122 dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
jiabin06e4bab2019-07-29 10:13:34 -0700123 for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700124 dst->append(base::StringPrintf("0x%04x", *it));
jiabin06e4bab2019-07-29 10:13:34 -0700125 dst->append(++it == mChannelMasks.end() ? "" : ", ");
François Gaffie112b0af2015-11-19 16:13:25 +0100126 }
Andy Hungbb54e202018-10-05 11:42:02 -0700127 dst->append("\n");
François Gaffie112b0af2015-11-19 16:13:25 +0100128 }
jiabin82e56932021-03-05 06:35:19 +0000129
130 dst->append(base::StringPrintf(
131 "%*s- encapsulation type: %#x\n", spaces, "", mEncapsulationType));
François Gaffie112b0af2015-11-19 16:13:25 +0100132}
133
jiabin49e69a12019-10-15 16:04:13 -0700134bool AudioProfile::equals(const sp<AudioProfile>& other) const
135{
136 return other != nullptr &&
137 mName.compare(other->mName) == 0 &&
138 mFormat == other->getFormat() &&
139 mChannelMasks == other->getChannels() &&
140 mSamplingRates == other->getSampleRates() &&
141 mIsDynamicFormat == other->isDynamicFormat() &&
142 mIsDynamicChannels == other->isDynamicChannels() &&
jiabin82e56932021-03-05 06:35:19 +0000143 mIsDynamicRate == other->isDynamicRate() &&
144 mEncapsulationType == other->getEncapsulationType();
jiabin49e69a12019-10-15 16:04:13 -0700145}
146
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800147AudioProfile& AudioProfile::operator=(const AudioProfile& other) {
148 mName = other.mName;
149 mFormat = other.mFormat;
150 mChannelMasks = other.mChannelMasks;
151 mSamplingRates = other.mSamplingRates;
jiabin82e56932021-03-05 06:35:19 +0000152 mEncapsulationType = other.mEncapsulationType;
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800153 mIsDynamicFormat = other.mIsDynamicFormat;
154 mIsDynamicChannels = other.mIsDynamicChannels;
155 mIsDynamicRate = other.mIsDynamicRate;
156 return *this;
jiabin17058fa2019-10-08 17:33:38 -0700157}
158
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800159ConversionResult<media::AudioProfile>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700160AudioProfile::toParcelable(bool isInput) const {
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800161 media::AudioProfile parcelable;
162 parcelable.name = mName;
Mikhail Naganovb60bd1b2021-07-15 17:31:43 -0700163 parcelable.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(mFormat));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800164 parcelable.channelMasks = VALUE_OR_RETURN(
Mikhail Naganov57bd06f2021-08-10 16:41:54 -0700165 convertContainer<std::vector<AudioChannelLayout>>(
Mikhail Naganov2d8df4e2021-06-03 13:59:13 -0700166 mChannelMasks,
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700167 [isInput](audio_channel_mask_t m) {
168 return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
169 }));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800170 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;
jiabin82e56932021-03-05 06:35:19 +0000176 parcelable.encapsulationType = VALUE_OR_RETURN(
177 legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800178 return parcelable;
179}
180
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800181ConversionResult<sp<AudioProfile>>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700182AudioProfile::fromParcelable(const media::AudioProfile& parcelable, bool isInput) {
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800183 sp<AudioProfile> legacy = new AudioProfile();
184 legacy->mName = parcelable.name;
Mikhail Naganovb60bd1b2021-07-15 17:31:43 -0700185 legacy->mFormat = VALUE_OR_RETURN(
186 aidl2legacy_AudioFormatDescription_audio_format_t(parcelable.format));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800187 legacy->mChannelMasks = VALUE_OR_RETURN(
188 convertContainer<ChannelMaskSet>(parcelable.channelMasks,
Mikhail Naganov57bd06f2021-08-10 16:41:54 -0700189 [isInput](const AudioChannelLayout& l) {
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700190 return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
191 }));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800192 legacy->mSamplingRates = VALUE_OR_RETURN(
193 convertContainer<SampleRateSet>(parcelable.samplingRates,
194 convertIntegral<uint32_t, int32_t>));
195 legacy->mIsDynamicFormat = parcelable.isDynamicFormat;
196 legacy->mIsDynamicChannels = parcelable.isDynamicChannels;
197 legacy->mIsDynamicRate = parcelable.isDynamicRate;
jiabin82e56932021-03-05 06:35:19 +0000198 legacy->mEncapsulationType = VALUE_OR_RETURN(
199 aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
200 parcelable.encapsulationType));
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800201 return legacy;
202}
203
204ConversionResult<sp<AudioProfile>>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700205aidl2legacy_AudioProfile(const media::AudioProfile& aidl, bool isInput) {
206 return AudioProfile::fromParcelable(aidl, isInput);
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800207}
208
209ConversionResult<media::AudioProfile>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700210legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy, bool isInput) {
211 return legacy->toParcelable(isInput);
jiabin17058fa2019-10-08 17:33:38 -0700212}
213
jiabin3e277cc2019-09-10 14:27:34 -0700214ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
Mikhail Naganove50f6282018-07-26 16:20:43 -0700215{
jiabin06e4bab2019-07-29 10:13:34 -0700216 ssize_t index = size();
217 push_back(profile);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700218 return index;
219}
220
jiabin3e277cc2019-09-10 14:27:34 -0700221void AudioProfileVector::clearProfiles()
Mikhail Naganove50f6282018-07-26 16:20:43 -0700222{
jiabin06e4bab2019-07-29 10:13:34 -0700223 for (auto it = begin(); it != end();) {
224 if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
225 it = erase(it);
226 } else {
227 (*it)->clear();
228 ++it;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700229 }
Mikhail Naganove50f6282018-07-26 16:20:43 -0700230 }
231}
232
jiabin3e277cc2019-09-10 14:27:34 -0700233sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700234{
jiabin06e4bab2019-07-29 10:13:34 -0700235 for (const auto &profile : *this) {
236 if (profile->isValid()) {
237 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700238 }
239 }
jiabin06e4bab2019-07-29 10:13:34 -0700240 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700241}
242
jiabin3e277cc2019-09-10 14:27:34 -0700243sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700244{
jiabin06e4bab2019-07-29 10:13:34 -0700245 for (const auto &profile : *this) {
246 if (profile->isValid() && profile->getFormat() == format) {
247 return profile;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700248 }
249 }
jiabin06e4bab2019-07-29 10:13:34 -0700250 return nullptr;
Mikhail Naganove50f6282018-07-26 16:20:43 -0700251}
252
jiabin3e277cc2019-09-10 14:27:34 -0700253FormatVector AudioProfileVector::getSupportedFormats() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700254{
255 FormatVector supportedFormats;
jiabin06e4bab2019-07-29 10:13:34 -0700256 for (const auto &profile : *this) {
257 if (profile->hasValidFormat()) {
258 supportedFormats.push_back(profile->getFormat());
Mikhail Naganove50f6282018-07-26 16:20:43 -0700259 }
260 }
261 return supportedFormats;
262}
263
jiabin3e277cc2019-09-10 14:27:34 -0700264bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700265{
jiabin06e4bab2019-07-29 10:13:34 -0700266 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700267 if (profile->getFormat() == format && profile->isDynamicChannels()) {
268 return true;
269 }
270 }
271 return false;
272}
273
jiabin3e277cc2019-09-10 14:27:34 -0700274bool AudioProfileVector::hasDynamicFormat() const
jiabin9bb3a1e2019-08-19 10:10:17 -0700275{
276 for (const auto &profile : *this) {
277 if (profile->isDynamicFormat()) {
278 return true;
279 }
280 }
281 return false;
282}
283
jiabin3e277cc2019-09-10 14:27:34 -0700284bool AudioProfileVector::hasDynamicProfile() const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700285{
jiabin06e4bab2019-07-29 10:13:34 -0700286 for (const auto &profile : *this) {
287 if (profile->isDynamic()) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700288 return true;
289 }
290 }
291 return false;
292}
293
jiabin3e277cc2019-09-10 14:27:34 -0700294bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700295{
jiabin06e4bab2019-07-29 10:13:34 -0700296 for (const auto &profile : *this) {
Mikhail Naganove50f6282018-07-26 16:20:43 -0700297 if (profile->getFormat() == format && profile->isDynamicRate()) {
298 return true;
299 }
300 }
301 return false;
302}
303
jiabinb4fed192020-09-22 14:45:40 -0700304bool AudioProfileVector::contains(const sp<AudioProfile>& profile) const
305{
306 for (const auto& audioProfile : *this) {
307 if (audioProfile->equals(profile)) {
308 return true;
309 }
310 }
311 return false;
312}
313
jiabin3e277cc2019-09-10 14:27:34 -0700314void AudioProfileVector::dump(std::string *dst, int spaces) const
Mikhail Naganove50f6282018-07-26 16:20:43 -0700315{
jiabin9bb3a1e2019-08-19 10:10:17 -0700316 dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
Mikhail Naganove50f6282018-07-26 16:20:43 -0700317 for (size_t i = 0; i < size(); i++) {
jiabin9bb3a1e2019-08-19 10:10:17 -0700318 dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
319 std::string profileStr;
320 at(i)->dump(&profileStr, spaces + 8);
321 dst->append(profileStr);
Mikhail Naganove50f6282018-07-26 16:20:43 -0700322 }
323}
324
jiabin49e69a12019-10-15 16:04:13 -0700325bool AudioProfileVector::equals(const AudioProfileVector& other) const
326{
327 return std::equal(begin(), end(), other.begin(), other.end(),
328 [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
329 return left->equals(right);
330 });
331}
332
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800333ConversionResult<AudioProfileVector>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700334aidl2legacy_AudioProfileVector(const std::vector<media::AudioProfile>& aidl, bool isInput) {
335 return convertContainer<AudioProfileVector>(aidl,
336 [isInput](const media::AudioProfile& p) {
337 return aidl2legacy_AudioProfile(p, isInput);
338 });
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800339}
340
341ConversionResult<std::vector<media::AudioProfile>>
Mikhail Naganovde3fa182021-07-30 15:06:42 -0700342legacy2aidl_AudioProfileVector(const AudioProfileVector& legacy, bool isInput) {
343 return convertContainer<std::vector<media::AudioProfile>>(legacy,
344 [isInput](const sp<AudioProfile>& p) {
345 return legacy2aidl_AudioProfile(p, isInput);
346 });
Ytai Ben-Tsvi50e016a2020-11-12 14:26:12 -0800347}
348
jiabinbce0c1d2020-10-05 11:20:18 -0700349AudioProfileVector intersectAudioProfiles(const AudioProfileVector& profiles1,
350 const AudioProfileVector& profiles2)
351{
352 std::map<audio_format_t, std::pair<ChannelMaskSet, SampleRateSet>> infos2;
353 for (const auto& profile : profiles2) {
354 infos2.emplace(profile->getFormat(),
355 std::make_pair(profile->getChannels(), profile->getSampleRates()));
356 }
357 AudioProfileVector profiles;
358 for (const auto& profile : profiles1) {
359 const auto it = infos2.find(profile->getFormat());
360 if (it == infos2.end()) {
361 continue;
362 }
363 ChannelMaskSet channelMasks = SetIntersection(profile->getChannels(), it->second.first);
364 if (channelMasks.empty()) {
365 continue;
366 }
367 SampleRateSet sampleRates = SetIntersection(profile->getSampleRates(), it->second.second);
368 if (sampleRates.empty()) {
369 continue;
370 }
371 profiles.push_back(new AudioProfile(profile->getFormat(), channelMasks, sampleRates));
372 }
373 return profiles;
374}
375
Mikhail Naganov1b2a7942017-12-08 10:18:09 -0800376} // namespace android