• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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