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