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         mName(""),
62         mFormat(format),
63         mChannelMasks(channelMasks),
64         mSamplingRates(samplingRateCollection) {}
65 
setChannels(const ChannelMaskSet & channelMasks)66 void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
67 {
68     if (mIsDynamicChannels) {
69         mChannelMasks = channelMasks;
70     }
71 }
72 
setSampleRates(const SampleRateSet & sampleRates)73 void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
74 {
75     if (mIsDynamicRate) {
76         mSamplingRates = sampleRates;
77     }
78 }
79 
clear()80 void AudioProfile::clear()
81 {
82     if (mIsDynamicChannels) {
83         mChannelMasks.clear();
84     }
85     if (mIsDynamicRate) {
86         mSamplingRates.clear();
87     }
88 }
89 
dump(std::string * dst,int spaces) const90 void AudioProfile::dump(std::string *dst, int spaces) const
91 {
92     dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
93              mIsDynamicChannels ? "[dynamic channels]" : "",
94              mIsDynamicRate ? "[dynamic rates]" : ""));
95     if (mName.length() != 0) {
96         dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
97     }
98     std::string formatLiteral;
99     if (FormatConverter::toString(mFormat, formatLiteral)) {
100         dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
101     }
102     if (!mSamplingRates.empty()) {
103         dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
104         for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
105             dst->append(base::StringPrintf("%d", *it));
106             dst->append(++it == mSamplingRates.end() ? "" : ", ");
107         }
108         dst->append("\n");
109     }
110 
111     if (!mChannelMasks.empty()) {
112         dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
113         for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
114             dst->append(base::StringPrintf("0x%04x", *it));
115             dst->append(++it == mChannelMasks.end() ? "" : ", ");
116         }
117         dst->append("\n");
118     }
119 }
120 
equals(const sp<AudioProfile> & other) const121 bool 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 
writeToParcel(Parcel * parcel) const133 status_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 
readFromParcel(const Parcel * parcel)149 status_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 
add(const sp<AudioProfile> & profile)171 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
172 {
173     ssize_t index = size();
174     push_back(profile);
175     return index;
176 }
177 
clearProfiles()178 void AudioProfileVector::clearProfiles()
179 {
180     for (auto it = begin(); it != end();) {
181         if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
182             it = erase(it);
183         } else {
184             (*it)->clear();
185             ++it;
186         }
187     }
188 }
189 
getFirstValidProfile() const190 sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
191 {
192     for (const auto &profile : *this) {
193         if (profile->isValid()) {
194             return profile;
195         }
196     }
197     return nullptr;
198 }
199 
getFirstValidProfileFor(audio_format_t format) const200 sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
201 {
202     for (const auto &profile : *this) {
203         if (profile->isValid() && profile->getFormat() == format) {
204             return profile;
205         }
206     }
207     return nullptr;
208 }
209 
getSupportedFormats() const210 FormatVector AudioProfileVector::getSupportedFormats() const
211 {
212     FormatVector supportedFormats;
213     for (const auto &profile : *this) {
214         if (profile->hasValidFormat()) {
215             supportedFormats.push_back(profile->getFormat());
216         }
217     }
218     return supportedFormats;
219 }
220 
hasDynamicChannelsFor(audio_format_t format) const221 bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
222 {
223     for (const auto &profile : *this) {
224         if (profile->getFormat() == format && profile->isDynamicChannels()) {
225             return true;
226         }
227     }
228     return false;
229 }
230 
hasDynamicFormat() const231 bool AudioProfileVector::hasDynamicFormat() const
232 {
233     for (const auto &profile : *this) {
234         if (profile->isDynamicFormat()) {
235             return true;
236         }
237     }
238     return false;
239 }
240 
hasDynamicProfile() const241 bool AudioProfileVector::hasDynamicProfile() const
242 {
243     for (const auto &profile : *this) {
244         if (profile->isDynamic()) {
245             return true;
246         }
247     }
248     return false;
249 }
250 
hasDynamicRateFor(audio_format_t format) const251 bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
252 {
253     for (const auto &profile : *this) {
254         if (profile->getFormat() == format && profile->isDynamicRate()) {
255             return true;
256         }
257     }
258     return false;
259 }
260 
dump(std::string * dst,int spaces) const261 void AudioProfileVector::dump(std::string *dst, int spaces) const
262 {
263     dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
264     for (size_t i = 0; i < size(); i++) {
265         dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
266         std::string profileStr;
267         at(i)->dump(&profileStr, spaces + 8);
268         dst->append(profileStr);
269     }
270 }
271 
writeToParcel(Parcel * parcel) const272 status_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 
readFromParcel(const Parcel * parcel)284 status_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 
equals(const AudioProfileVector & other) const299 bool 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 
307 } // namespace android
308