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