AudioPort.cpp revision 98cc191247388132b6fd8a4ecd07abd6e4c5a0ed
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::AudioPort"
18//#define LOG_NDEBUG 0
19
20#include "AudioPort.h"
21#include "HwModule.h"
22#include "AudioGain.h"
23#include "ConfigParsingUtils.h"
24#include "audio_policy_conf.h"
25
26namespace android {
27
28int32_t volatile AudioPort::mNextUniqueId = 1;
29
30// --- AudioPort class implementation
31
32AudioPort::AudioPort(const String8& name, audio_port_type_t type,
33          audio_port_role_t role, const sp<HwModule>& module) :
34    mName(name), mType(type), mRole(role), mModule(module), mFlags(0), mId(0)
35{
36    mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
37                    ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
38}
39
40void AudioPort::attach(const sp<HwModule>& module)
41{
42    mId = getNextUniqueId();
43    mModule = module;
44}
45
46audio_port_handle_t AudioPort::getNextUniqueId()
47{
48    return static_cast<audio_port_handle_t>(android_atomic_inc(&mNextUniqueId));
49}
50
51void AudioPort::toAudioPort(struct audio_port *port) const
52{
53    port->role = mRole;
54    port->type = mType;
55    strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
56    unsigned int i;
57    for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
58        if (mSamplingRates[i] != 0) {
59            port->sample_rates[i] = mSamplingRates[i];
60        }
61    }
62    port->num_sample_rates = i;
63    for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
64        if (mChannelMasks[i] != 0) {
65            port->channel_masks[i] = mChannelMasks[i];
66        }
67    }
68    port->num_channel_masks = i;
69    for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
70        if (mFormats[i] != 0) {
71            port->formats[i] = mFormats[i];
72        }
73    }
74    port->num_formats = i;
75
76    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
77
78    for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
79        port->gains[i] = mGains[i]->mGain;
80    }
81    port->num_gains = i;
82}
83
84void AudioPort::importAudioPort(const sp<AudioPort> port) {
85    for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
86        const uint32_t rate = port->mSamplingRates.itemAt(k);
87        if (rate != 0) { // skip "dynamic" rates
88            bool hasRate = false;
89            for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
90                if (rate == mSamplingRates.itemAt(l)) {
91                    hasRate = true;
92                    break;
93                }
94            }
95            if (!hasRate) { // never import a sampling rate twice
96                mSamplingRates.add(rate);
97            }
98        }
99    }
100    for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
101        const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
102        if (mask != 0) { // skip "dynamic" masks
103            bool hasMask = false;
104            for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
105                if (mask == mChannelMasks.itemAt(l)) {
106                    hasMask = true;
107                    break;
108                }
109            }
110            if (!hasMask) { // never import a channel mask twice
111                mChannelMasks.add(mask);
112            }
113        }
114    }
115    for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
116        const audio_format_t format = port->mFormats.itemAt(k);
117        if (format != 0) { // skip "dynamic" formats
118            bool hasFormat = false;
119            for (size_t l = 0 ; l < mFormats.size() ; l++) {
120                if (format == mFormats.itemAt(l)) {
121                    hasFormat = true;
122                    break;
123                }
124            }
125            if (!hasFormat) { // never import a channel mask twice
126                mFormats.add(format);
127            }
128        }
129    }
130    for (size_t k = 0 ; k < port->mGains.size() ; k++) {
131        sp<AudioGain> gain = port->mGains.itemAt(k);
132        if (gain != 0) {
133            bool hasGain = false;
134            for (size_t l = 0 ; l < mGains.size() ; l++) {
135                if (gain == mGains.itemAt(l)) {
136                    hasGain = true;
137                    break;
138                }
139            }
140            if (!hasGain) { // never import a gain twice
141                mGains.add(gain);
142            }
143        }
144    }
145}
146
147void AudioPort::clearCapabilities() {
148    mChannelMasks.clear();
149    mFormats.clear();
150    mSamplingRates.clear();
151    mGains.clear();
152}
153
154void AudioPort::loadSamplingRates(char *name)
155{
156    char *str = strtok(name, "|");
157
158    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
159    // rates should be read from the output stream after it is opened for the first time
160    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
161        mSamplingRates.add(0);
162        return;
163    }
164
165    while (str != NULL) {
166        uint32_t rate = atoi(str);
167        if (rate != 0) {
168            ALOGV("loadSamplingRates() adding rate %d", rate);
169            mSamplingRates.add(rate);
170        }
171        str = strtok(NULL, "|");
172    }
173}
174
175void AudioPort::loadFormats(char *name)
176{
177    char *str = strtok(name, "|");
178
179    // by convention, "0' in the first entry in mFormats indicates the supported formats
180    // should be read from the output stream after it is opened for the first time
181    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
182        mFormats.add(AUDIO_FORMAT_DEFAULT);
183        return;
184    }
185
186    while (str != NULL) {
187        audio_format_t format = (audio_format_t)ConfigParsingUtils::stringToEnum(sFormatNameToEnumTable,
188                                                             ARRAY_SIZE(sFormatNameToEnumTable),
189                                                             str);
190        if (format != AUDIO_FORMAT_DEFAULT) {
191            mFormats.add(format);
192        }
193        str = strtok(NULL, "|");
194    }
195}
196
197void AudioPort::loadInChannels(char *name)
198{
199    const char *str = strtok(name, "|");
200
201    ALOGV("loadInChannels() %s", name);
202
203    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
204        mChannelMasks.add(0);
205        return;
206    }
207
208    while (str != NULL) {
209        audio_channel_mask_t channelMask =
210                (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
211                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
212                                                   str);
213        if (channelMask != 0) {
214            ALOGV("loadInChannels() adding channelMask %04x", channelMask);
215            mChannelMasks.add(channelMask);
216        }
217        str = strtok(NULL, "|");
218    }
219}
220
221void AudioPort::loadOutChannels(char *name)
222{
223    const char *str = strtok(name, "|");
224
225    ALOGV("loadOutChannels() %s", name);
226
227    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
228    // masks should be read from the output stream after it is opened for the first time
229    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
230        mChannelMasks.add(0);
231        return;
232    }
233
234    while (str != NULL) {
235        audio_channel_mask_t channelMask =
236                (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
237                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
238                                                   str);
239        if (channelMask != 0) {
240            mChannelMasks.add(channelMask);
241        }
242        str = strtok(NULL, "|");
243    }
244    return;
245}
246
247audio_gain_mode_t AudioPort::loadGainMode(char *name)
248{
249    const char *str = strtok(name, "|");
250
251    ALOGV("loadGainMode() %s", name);
252    audio_gain_mode_t mode = 0;
253    while (str != NULL) {
254        mode |= (audio_gain_mode_t)ConfigParsingUtils::stringToEnum(sGainModeNameToEnumTable,
255                                                ARRAY_SIZE(sGainModeNameToEnumTable),
256                                                str);
257        str = strtok(NULL, "|");
258    }
259    return mode;
260}
261
262void AudioPort::loadGain(cnode *root, int index)
263{
264    cnode *node = root->first_child;
265
266    sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask);
267
268    while (node) {
269        if (strcmp(node->name, GAIN_MODE) == 0) {
270            gain->mGain.mode = loadGainMode((char *)node->value);
271        } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
272            if (mUseInChannelMask) {
273                gain->mGain.channel_mask =
274                        (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
275                                                           ARRAY_SIZE(sInChannelsNameToEnumTable),
276                                                           (char *)node->value);
277            } else {
278                gain->mGain.channel_mask =
279                        (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
280                                                           ARRAY_SIZE(sOutChannelsNameToEnumTable),
281                                                           (char *)node->value);
282            }
283        } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
284            gain->mGain.min_value = atoi((char *)node->value);
285        } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
286            gain->mGain.max_value = atoi((char *)node->value);
287        } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
288            gain->mGain.default_value = atoi((char *)node->value);
289        } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
290            gain->mGain.step_value = atoi((char *)node->value);
291        } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
292            gain->mGain.min_ramp_ms = atoi((char *)node->value);
293        } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
294            gain->mGain.max_ramp_ms = atoi((char *)node->value);
295        }
296        node = node->next;
297    }
298
299    ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
300          gain->mGain.mode, gain->mGain.channel_mask, gain->mGain.min_value, gain->mGain.max_value);
301
302    if (gain->mGain.mode == 0) {
303        return;
304    }
305    mGains.add(gain);
306}
307
308void AudioPort::loadGains(cnode *root)
309{
310    cnode *node = root->first_child;
311    int index = 0;
312    while (node) {
313        ALOGV("loadGains() loading gain %s", node->name);
314        loadGain(node, index++);
315        node = node->next;
316    }
317}
318
319status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
320{
321    if (mSamplingRates.isEmpty()) {
322        return NO_ERROR;
323    }
324
325    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
326        if (mSamplingRates[i] == samplingRate) {
327            return NO_ERROR;
328        }
329    }
330    return BAD_VALUE;
331}
332
333status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
334        uint32_t *updatedSamplingRate) const
335{
336    if (mSamplingRates.isEmpty()) {
337        return NO_ERROR;
338    }
339
340    // Search for the closest supported sampling rate that is above (preferred)
341    // or below (acceptable) the desired sampling rate, within a permitted ratio.
342    // The sampling rates do not need to be sorted in ascending order.
343    ssize_t maxBelow = -1;
344    ssize_t minAbove = -1;
345    uint32_t candidate;
346    for (size_t i = 0; i < mSamplingRates.size(); i++) {
347        candidate = mSamplingRates[i];
348        if (candidate == samplingRate) {
349            if (updatedSamplingRate != NULL) {
350                *updatedSamplingRate = candidate;
351            }
352            return NO_ERROR;
353        }
354        // candidate < desired
355        if (candidate < samplingRate) {
356            if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
357                maxBelow = i;
358            }
359        // candidate > desired
360        } else {
361            if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
362                minAbove = i;
363            }
364        }
365    }
366    // This uses hard-coded knowledge about AudioFlinger resampling ratios.
367    // TODO Move these assumptions out.
368    static const uint32_t kMaxDownSampleRatio = 6;  // beyond this aliasing occurs
369    static const uint32_t kMaxUpSampleRatio = 256;  // beyond this sample rate inaccuracies occur
370                                                    // due to approximation by an int32_t of the
371                                                    // phase increments
372    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
373    if (minAbove >= 0) {
374        candidate = mSamplingRates[minAbove];
375        if (candidate / kMaxDownSampleRatio <= samplingRate) {
376            if (updatedSamplingRate != NULL) {
377                *updatedSamplingRate = candidate;
378            }
379            return NO_ERROR;
380        }
381    }
382    // But if we have to up-sample from a lower sampling rate, that's OK.
383    if (maxBelow >= 0) {
384        candidate = mSamplingRates[maxBelow];
385        if (candidate * kMaxUpSampleRatio >= samplingRate) {
386            if (updatedSamplingRate != NULL) {
387                *updatedSamplingRate = candidate;
388            }
389            return NO_ERROR;
390        }
391    }
392    // leave updatedSamplingRate unmodified
393    return BAD_VALUE;
394}
395
396status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
397{
398    if (mChannelMasks.isEmpty()) {
399        return NO_ERROR;
400    }
401
402    for (size_t i = 0; i < mChannelMasks.size(); i++) {
403        if (mChannelMasks[i] == channelMask) {
404            return NO_ERROR;
405        }
406    }
407    return BAD_VALUE;
408}
409
410status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
411        const
412{
413    if (mChannelMasks.isEmpty()) {
414        return NO_ERROR;
415    }
416
417    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
418    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
419        // FIXME Does not handle multi-channel automatic conversions yet
420        audio_channel_mask_t supported = mChannelMasks[i];
421        if (supported == channelMask) {
422            return NO_ERROR;
423        }
424        if (isRecordThread) {
425            // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
426            // FIXME Abstract this out to a table.
427            if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
428                    && channelMask == AUDIO_CHANNEL_IN_MONO) ||
429                (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
430                    || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
431                return NO_ERROR;
432            }
433        }
434    }
435    return BAD_VALUE;
436}
437
438status_t AudioPort::checkFormat(audio_format_t format) const
439{
440    if (mFormats.isEmpty()) {
441        return NO_ERROR;
442    }
443
444    for (size_t i = 0; i < mFormats.size(); i ++) {
445        if (mFormats[i] == format) {
446            return NO_ERROR;
447        }
448    }
449    return BAD_VALUE;
450}
451
452
453uint32_t AudioPort::pickSamplingRate() const
454{
455    // special case for uninitialized dynamic profile
456    if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
457        return 0;
458    }
459
460    // For direct outputs, pick minimum sampling rate: this helps ensuring that the
461    // channel count / sampling rate combination chosen will be supported by the connected
462    // sink
463    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
464            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
465        uint32_t samplingRate = UINT_MAX;
466        for (size_t i = 0; i < mSamplingRates.size(); i ++) {
467            if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
468                samplingRate = mSamplingRates[i];
469            }
470        }
471        return (samplingRate == UINT_MAX) ? 0 : samplingRate;
472    }
473
474    uint32_t samplingRate = 0;
475    uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
476
477    // For mixed output and inputs, use max mixer sampling rates. Do not
478    // limit sampling rate otherwise
479    if (mType != AUDIO_PORT_TYPE_MIX) {
480        maxRate = UINT_MAX;
481    }
482    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
483        if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
484            samplingRate = mSamplingRates[i];
485        }
486    }
487    return samplingRate;
488}
489
490audio_channel_mask_t AudioPort::pickChannelMask() const
491{
492    // special case for uninitialized dynamic profile
493    if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
494        return AUDIO_CHANNEL_NONE;
495    }
496    audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
497
498    // For direct outputs, pick minimum channel count: this helps ensuring that the
499    // channel count / sampling rate combination chosen will be supported by the connected
500    // sink
501    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
502            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
503        uint32_t channelCount = UINT_MAX;
504        for (size_t i = 0; i < mChannelMasks.size(); i ++) {
505            uint32_t cnlCount;
506            if (mUseInChannelMask) {
507                cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
508            } else {
509                cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
510            }
511            if ((cnlCount < channelCount) && (cnlCount > 0)) {
512                channelMask = mChannelMasks[i];
513                channelCount = cnlCount;
514            }
515        }
516        return channelMask;
517    }
518
519    uint32_t channelCount = 0;
520    uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
521
522    // For mixed output and inputs, use max mixer channel count. Do not
523    // limit channel count otherwise
524    if (mType != AUDIO_PORT_TYPE_MIX) {
525        maxCount = UINT_MAX;
526    }
527    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
528        uint32_t cnlCount;
529        if (mUseInChannelMask) {
530            cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
531        } else {
532            cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
533        }
534        if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
535            channelMask = mChannelMasks[i];
536            channelCount = cnlCount;
537        }
538    }
539    return channelMask;
540}
541
542/* format in order of increasing preference */
543const audio_format_t AudioPort::sPcmFormatCompareTable[] = {
544        AUDIO_FORMAT_DEFAULT,
545        AUDIO_FORMAT_PCM_16_BIT,
546        AUDIO_FORMAT_PCM_8_24_BIT,
547        AUDIO_FORMAT_PCM_24_BIT_PACKED,
548        AUDIO_FORMAT_PCM_32_BIT,
549        AUDIO_FORMAT_PCM_FLOAT,
550};
551
552int AudioPort::compareFormats(audio_format_t format1,
553                                                  audio_format_t format2)
554{
555    // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
556    // compressed format and better than any PCM format. This is by design of pickFormat()
557    if (!audio_is_linear_pcm(format1)) {
558        if (!audio_is_linear_pcm(format2)) {
559            return 0;
560        }
561        return 1;
562    }
563    if (!audio_is_linear_pcm(format2)) {
564        return -1;
565    }
566
567    int index1 = -1, index2 = -1;
568    for (size_t i = 0;
569            (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
570            i ++) {
571        if (sPcmFormatCompareTable[i] == format1) {
572            index1 = i;
573        }
574        if (sPcmFormatCompareTable[i] == format2) {
575            index2 = i;
576        }
577    }
578    // format1 not found => index1 < 0 => format2 > format1
579    // format2 not found => index2 < 0 => format2 < format1
580    return index1 - index2;
581}
582
583audio_format_t AudioPort::pickFormat() const
584{
585    // special case for uninitialized dynamic profile
586    if (mFormats.size() == 1 && mFormats[0] == 0) {
587        return AUDIO_FORMAT_DEFAULT;
588    }
589
590    audio_format_t format = AUDIO_FORMAT_DEFAULT;
591    audio_format_t bestFormat =
592            AudioPort::sPcmFormatCompareTable[
593                ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
594    // For mixed output and inputs, use best mixer output format. Do not
595    // limit format otherwise
596    if ((mType != AUDIO_PORT_TYPE_MIX) ||
597            ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
598             (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
599        bestFormat = AUDIO_FORMAT_INVALID;
600    }
601
602    for (size_t i = 0; i < mFormats.size(); i ++) {
603        if ((compareFormats(mFormats[i], format) > 0) &&
604                (compareFormats(mFormats[i], bestFormat) <= 0)) {
605            format = mFormats[i];
606        }
607    }
608    return format;
609}
610
611status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
612                                                  int index) const
613{
614    if (index < 0 || (size_t)index >= mGains.size()) {
615        return BAD_VALUE;
616    }
617    return mGains[index]->checkConfig(gainConfig);
618}
619
620void AudioPort::dump(int fd, int spaces) const
621{
622    const size_t SIZE = 256;
623    char buffer[SIZE];
624    String8 result;
625
626    if (mName.size() != 0) {
627        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
628        result.append(buffer);
629    }
630
631    if (mSamplingRates.size() != 0) {
632        snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
633        result.append(buffer);
634        for (size_t i = 0; i < mSamplingRates.size(); i++) {
635            if (i == 0 && mSamplingRates[i] == 0) {
636                snprintf(buffer, SIZE, "Dynamic");
637            } else {
638                snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
639            }
640            result.append(buffer);
641            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
642        }
643        result.append("\n");
644    }
645
646    if (mChannelMasks.size() != 0) {
647        snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
648        result.append(buffer);
649        for (size_t i = 0; i < mChannelMasks.size(); i++) {
650            ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
651
652            if (i == 0 && mChannelMasks[i] == 0) {
653                snprintf(buffer, SIZE, "Dynamic");
654            } else {
655                snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
656            }
657            result.append(buffer);
658            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
659        }
660        result.append("\n");
661    }
662
663    if (mFormats.size() != 0) {
664        snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
665        result.append(buffer);
666        for (size_t i = 0; i < mFormats.size(); i++) {
667            const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable,
668                                                 ARRAY_SIZE(sFormatNameToEnumTable),
669                                                 mFormats[i]);
670            if (i == 0 && strcmp(formatStr, "") == 0) {
671                snprintf(buffer, SIZE, "Dynamic");
672            } else {
673                snprintf(buffer, SIZE, "%s", formatStr);
674            }
675            result.append(buffer);
676            result.append(i == (mFormats.size() - 1) ? "" : ", ");
677        }
678        result.append("\n");
679    }
680    write(fd, result.string(), result.size());
681    if (mGains.size() != 0) {
682        snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
683        write(fd, buffer, strlen(buffer) + 1);
684        result.append(buffer);
685        for (size_t i = 0; i < mGains.size(); i++) {
686            mGains[i]->dump(fd, spaces + 2, i);
687        }
688    }
689}
690
691
692// --- AudioPortConfig class implementation
693
694AudioPortConfig::AudioPortConfig()
695{
696    mSamplingRate = 0;
697    mChannelMask = AUDIO_CHANNEL_NONE;
698    mFormat = AUDIO_FORMAT_INVALID;
699    mGain.index = -1;
700}
701
702status_t AudioPortConfig::applyAudioPortConfig(
703                                                        const struct audio_port_config *config,
704                                                        struct audio_port_config *backupConfig)
705{
706    struct audio_port_config localBackupConfig;
707    status_t status = NO_ERROR;
708
709    localBackupConfig.config_mask = config->config_mask;
710    toAudioPortConfig(&localBackupConfig);
711
712    sp<AudioPort> audioport = getAudioPort();
713    if (audioport == 0) {
714        status = NO_INIT;
715        goto exit;
716    }
717    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
718        status = audioport->checkExactSamplingRate(config->sample_rate);
719        if (status != NO_ERROR) {
720            goto exit;
721        }
722        mSamplingRate = config->sample_rate;
723    }
724    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
725        status = audioport->checkExactChannelMask(config->channel_mask);
726        if (status != NO_ERROR) {
727            goto exit;
728        }
729        mChannelMask = config->channel_mask;
730    }
731    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
732        status = audioport->checkFormat(config->format);
733        if (status != NO_ERROR) {
734            goto exit;
735        }
736        mFormat = config->format;
737    }
738    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
739        status = audioport->checkGain(&config->gain, config->gain.index);
740        if (status != NO_ERROR) {
741            goto exit;
742        }
743        mGain = config->gain;
744    }
745
746exit:
747    if (status != NO_ERROR) {
748        applyAudioPortConfig(&localBackupConfig);
749    }
750    if (backupConfig != NULL) {
751        *backupConfig = localBackupConfig;
752    }
753    return status;
754}
755
756void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
757                                        const struct audio_port_config *srcConfig) const
758{
759    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
760        dstConfig->sample_rate = mSamplingRate;
761        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
762            dstConfig->sample_rate = srcConfig->sample_rate;
763        }
764    } else {
765        dstConfig->sample_rate = 0;
766    }
767    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
768        dstConfig->channel_mask = mChannelMask;
769        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
770            dstConfig->channel_mask = srcConfig->channel_mask;
771        }
772    } else {
773        dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
774    }
775    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
776        dstConfig->format = mFormat;
777        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
778            dstConfig->format = srcConfig->format;
779        }
780    } else {
781        dstConfig->format = AUDIO_FORMAT_INVALID;
782    }
783    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
784        dstConfig->gain = mGain;
785        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
786            dstConfig->gain = srcConfig->gain;
787        }
788    } else {
789        dstConfig->gain.index = -1;
790    }
791    if (dstConfig->gain.index != -1) {
792        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
793    } else {
794        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
795    }
796}
797
798}; // namespace android
799