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