1/*
2 * Copyright (C) 2015 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#define LOG_TAG "APM::AudioProfile"
18//#define LOG_NDEBUG 0
19
20#include "AudioProfile.h"
21#include "AudioPort.h"
22#include "HwModule.h"
23#include "AudioGain.h"
24#include <utils/SortedVector.h>
25#include "TypeConverter.h"
26#include <media/AudioResamplerPublic.h>
27#include <algorithm>
28
29namespace android {
30
31status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
32                                  audio_format_t format) const
33{
34    if (audio_formats_match(format, mFormat) &&
35            supportsChannels(channelMask) &&
36            supportsRate(samplingRate)) {
37        return NO_ERROR;
38    }
39    return BAD_VALUE;
40}
41
42template <typename T>
43bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
44{
45    if (left.size() != right.size()) {
46        return false;
47    }
48    for(size_t index = 0; index < right.size(); index++) {
49        if (left[index] != right[index]) {
50            return false;
51        }
52    }
53    return true;
54}
55
56bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
57{
58    return (left.getFormat() == compareTo.getFormat()) &&
59            (left.getChannels() == compareTo.getChannels()) &&
60            (left.getSampleRates() == compareTo.getSampleRates());
61}
62
63status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
64                                                   uint32_t &updatedSamplingRate) const
65{
66    ALOG_ASSERT(samplingRate > 0);
67
68    if (mSamplingRates.isEmpty()) {
69        updatedSamplingRate = samplingRate;
70        return NO_ERROR;
71    }
72
73    // Search for the closest supported sampling rate that is above (preferred)
74    // or below (acceptable) the desired sampling rate, within a permitted ratio.
75    // The sampling rates are sorted in ascending order.
76    size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
77
78    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
79    if (orderOfDesiredRate < mSamplingRates.size()) {
80        uint32_t candidate = mSamplingRates[orderOfDesiredRate];
81        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
82            updatedSamplingRate = candidate;
83            return NO_ERROR;
84        }
85    }
86    // But if we have to up-sample from a lower sampling rate, that's OK.
87    if (orderOfDesiredRate != 0) {
88        uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
89        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
90            updatedSamplingRate = candidate;
91            return NO_ERROR;
92        }
93    }
94    // leave updatedSamplingRate unmodified
95    return BAD_VALUE;
96}
97
98status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
99                                                  audio_channel_mask_t &updatedChannelMask,
100                                                  audio_port_type_t portType,
101                                                  audio_port_role_t portRole) const
102{
103    if (mChannelMasks.isEmpty()) {
104        updatedChannelMask = channelMask;
105        return NO_ERROR;
106    }
107    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
108    const bool isIndex = audio_channel_mask_get_representation(channelMask)
109            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
110    int bestMatch = 0;
111    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
112        audio_channel_mask_t supported = mChannelMasks[i];
113        if (supported == channelMask) {
114            // Exact matches always taken.
115            updatedChannelMask = channelMask;
116            return NO_ERROR;
117        }
118
119        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
120        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
121            // Approximate (best) match:
122            // The match score measures how well the supported channel mask matches the
123            // desired mask, where increasing-is-better.
124            //
125            // TODO: Some tweaks may be needed.
126            // Should be a static function of the data processing library.
127            //
128            // In priority:
129            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
130            // OR
131            // match score += 100 if the channel mask representations match
132            // match score += number of channels matched.
133            //
134            // If there are no matched channels, the mask may still be accepted
135            // but the playback or record will be silent.
136            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
137                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
138            int match;
139            if (isIndex && isSupportedIndex) {
140                // index equivalence
141                match = 100 + __builtin_popcount(
142                        audio_channel_mask_get_bits(channelMask)
143                            & audio_channel_mask_get_bits(supported));
144            } else if (isIndex && !isSupportedIndex) {
145                const uint32_t equivalentBits =
146                        (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
147                match = __builtin_popcount(
148                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
149            } else if (!isIndex && isSupportedIndex) {
150                const uint32_t equivalentBits =
151                        (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
152                match = __builtin_popcount(
153                        equivalentBits & audio_channel_mask_get_bits(supported));
154            } else {
155                // positional equivalence
156                match = 100 + __builtin_popcount(
157                        audio_channel_mask_get_bits(channelMask)
158                            & audio_channel_mask_get_bits(supported));
159                switch (supported) {
160                case AUDIO_CHANNEL_IN_FRONT_BACK:
161                case AUDIO_CHANNEL_IN_STEREO:
162                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
163                        match = 1000;
164                    }
165                    break;
166                case AUDIO_CHANNEL_IN_MONO:
167                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
168                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
169                        match = 1000;
170                    }
171                    break;
172                default:
173                    break;
174                }
175            }
176            if (match > bestMatch) {
177                bestMatch = match;
178                updatedChannelMask = supported;
179            }
180        }
181    }
182    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
183}
184
185void AudioProfile::dump(int fd, int spaces) const
186{
187    const size_t SIZE = 256;
188    char buffer[SIZE];
189    String8 result;
190
191    snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
192             mIsDynamicChannels ? "[dynamic channels]" : "",
193             mIsDynamicRate ? "[dynamic rates]" : "");
194    result.append(buffer);
195    if (mName.length() != 0) {
196        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
197        result.append(buffer);
198    }
199    std::string formatLiteral;
200    if (FormatConverter::toString(mFormat, formatLiteral)) {
201        snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
202        result.append(buffer);
203    }
204    if (!mSamplingRates.isEmpty()) {
205        snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
206        result.append(buffer);
207        for (size_t i = 0; i < mSamplingRates.size(); i++) {
208            snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
209            result.append(buffer);
210            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
211        }
212        result.append("\n");
213    }
214
215    if (!mChannelMasks.isEmpty()) {
216        snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
217        result.append(buffer);
218        for (size_t i = 0; i < mChannelMasks.size(); i++) {
219            snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
220            result.append(buffer);
221            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
222        }
223        result.append("\n");
224    }
225    write(fd, result.string(), result.size());
226}
227
228status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
229                                               audio_channel_mask_t channelMask,
230                                               audio_format_t format) const
231{
232    if (isEmpty()) {
233        return NO_ERROR;
234    }
235
236    for (size_t i = 0; i < size(); i++) {
237        const sp<AudioProfile> profile = itemAt(i);
238        if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
239            return NO_ERROR;
240        }
241    }
242    return BAD_VALUE;
243}
244
245status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
246                                                    audio_channel_mask_t &channelMask,
247                                                    audio_format_t &format,
248                                                    audio_port_type_t portType,
249                                                    audio_port_role_t portRole) const
250{
251    if (isEmpty()) {
252        return NO_ERROR;
253    }
254
255    const bool checkInexact = // when port is input and format is linear pcm
256            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
257            && audio_is_linear_pcm(format);
258
259    // iterate from best format to worst format (reverse order)
260    for (ssize_t i = size() - 1; i >= 0 ; --i) {
261        const sp<AudioProfile> profile = itemAt(i);
262        audio_format_t formatToCompare = profile->getFormat();
263        if (formatToCompare == format ||
264                (checkInexact
265                        && formatToCompare != AUDIO_FORMAT_DEFAULT
266                        && audio_is_linear_pcm(formatToCompare))) {
267            // Compatible profile has been found, checks if this profile has compatible
268            // rate and channels as well
269            audio_channel_mask_t updatedChannels;
270            uint32_t updatedRate;
271            if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
272                                                    portType, portRole) == NO_ERROR &&
273                    profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
274                // for inexact checks we take the first linear pcm format due to sorting.
275                format = formatToCompare;
276                channelMask = updatedChannels;
277                samplingRate = updatedRate;
278                return NO_ERROR;
279            }
280        }
281    }
282    return BAD_VALUE;
283}
284
285int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
286                                       const sp<AudioProfile> *profile2)
287{
288    return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
289}
290
291}; // namespace android
292