1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <alsa/asoundlib.h>
7 #include <limits.h>
8 #include <stdio.h>
9 #include <syslog.h>
10
11 #include "cras_alsa_mixer.h"
12 #include "cras_alsa_mixer_name.h"
13 #include "cras_alsa_ucm.h"
14 #include "cras_util.h"
15 #include "utlist.h"
16
17 #define MIXER_CONTROL_VOLUME_DB_INVALID LONG_MAX
18
19 /* Represents an ALSA control element. Each device can have several of these,
20 * each potentially having independent volume and mute controls.
21 * elem - ALSA mixer element.
22 * has_volume - non-zero indicates there is a volume control.
23 * has_mute - non-zero indicates there is a mute switch.
24 * max_volume_dB - the maximum volume for this control, or
25 * MIXER_CONTROL_VOLUME_DB_INVALID.
26 * min_volume_dB - the minimum volume for this control, or
27 * MIXER_CONTROL_VOLUME_DB_INVALID.
28 */
29 struct mixer_control_element {
30 snd_mixer_elem_t *elem;
31 int has_volume;
32 int has_mute;
33 long max_volume_dB;
34 long min_volume_dB;
35 struct mixer_control_element *prev, *next;
36 };
37
38 /* Represents an ALSA control element related to a specific input/output
39 * node such as speakers or headphones. A device can have several of these,
40 * each potentially having independent volume and mute controls.
41 *
42 * Each will have at least one mixer_control_element. For cases where there
43 * are separate control elements for left/right channels (for example),
44 * additional mixer_control_elements are added.
45 *
46 * For controls with volume it is assumed that all elements have the same
47 * range.
48 *
49 * name - Name of the control (typicially this is the same as the name of the
50 * mixer_control_element when there is one, or the name of the UCM
51 * parent when there are multiple).
52 * dir - Control direction, OUTPUT or INPUT only.
53 * elements - The mixer_control_elements that are driven by this control.
54 * has_volume - non-zero indicates there is a volume control.
55 * has_mute - non-zero indicates there is a mute switch.
56 * max_volume_dB - Maximum volume available in the volume control.
57 * min_volume_dB - Minimum volume available in the volume control.
58 */
59 struct mixer_control {
60 const char *name;
61 enum CRAS_STREAM_DIRECTION dir;
62 struct mixer_control_element *elements;
63 int has_volume;
64 int has_mute;
65 long max_volume_dB;
66 long min_volume_dB;
67 struct mixer_control *prev, *next;
68 };
69
70 /* Holds a reference to the opened mixer and the volume controls.
71 * mixer - Pointer to the opened alsa mixer.
72 * main_volume_controls - List of volume controls (normally 'Master' and 'PCM').
73 * playback_switch - Switch used to mute the device.
74 * main_capture_controls - List of capture gain controls (normally 'Capture').
75 * capture_switch - Switch used to mute the capture stream.
76 * max_volume_dB - Maximum volume available in main volume controls. The dBFS
77 * value setting will be applied relative to this.
78 * min_volume_dB - Minimum volume available in main volume controls.
79 */
80 struct cras_alsa_mixer {
81 snd_mixer_t *mixer;
82 struct mixer_control *main_volume_controls;
83 struct mixer_control *output_controls;
84 snd_mixer_elem_t *playback_switch;
85 struct mixer_control *main_capture_controls;
86 struct mixer_control *input_controls;
87 snd_mixer_elem_t *capture_switch;
88 long max_volume_dB;
89 long min_volume_dB;
90 };
91
92 /* Wrapper for snd_mixer_open and helpers.
93 * Args:
94 * mixdev - Name of the device to open the mixer for.
95 * mixer - Pointer filled with the opened mixer on success, NULL on failure.
96 */
alsa_mixer_open(const char * mixdev,snd_mixer_t ** mixer)97 static void alsa_mixer_open(const char *mixdev,
98 snd_mixer_t **mixer)
99 {
100 int rc;
101
102 *mixer = NULL;
103 rc = snd_mixer_open(mixer, 0);
104 if (rc < 0) {
105 syslog(LOG_ERR, "snd_mixer_open: %d: %s", rc, strerror(-rc));
106 return;
107 }
108 rc = snd_mixer_attach(*mixer, mixdev);
109 if (rc < 0) {
110 syslog(LOG_ERR, "snd_mixer_attach: %d: %s", rc, strerror(-rc));
111 goto fail_after_open;
112 }
113 rc = snd_mixer_selem_register(*mixer, NULL, NULL);
114 if (rc < 0) {
115 syslog(LOG_ERR, "snd_mixer_selem_register: %d: %s", rc, strerror(-rc));
116 goto fail_after_open;
117 }
118 rc = snd_mixer_load(*mixer);
119 if (rc < 0) {
120 syslog(LOG_ERR, "snd_mixer_load: %d: %s", rc, strerror(-rc));
121 goto fail_after_open;
122 }
123 return;
124
125 fail_after_open:
126 snd_mixer_close(*mixer);
127 *mixer = NULL;
128 }
129
mixer_control_element_create(snd_mixer_elem_t * elem,enum CRAS_STREAM_DIRECTION dir)130 static struct mixer_control_element *mixer_control_element_create(
131 snd_mixer_elem_t *elem,
132 enum CRAS_STREAM_DIRECTION dir)
133 {
134 struct mixer_control_element *c;
135 long min, max;
136
137 if (!elem)
138 return NULL;
139
140 c = (struct mixer_control_element *)calloc(1, sizeof(*c));
141 if (!c) {
142 syslog(LOG_ERR, "No memory for mixer_control_elem.");
143 return NULL;
144 }
145
146 c->elem = elem;
147 c->max_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID;
148 c->min_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID;
149
150 if (dir == CRAS_STREAM_OUTPUT) {
151 c->has_mute = snd_mixer_selem_has_playback_switch(elem);
152
153 if (snd_mixer_selem_has_playback_volume(elem) &&
154 snd_mixer_selem_get_playback_dB_range(
155 elem, &min, &max) == 0) {
156 c->max_volume_dB = max;
157 c->min_volume_dB = min;
158 c->has_volume = 1;
159 }
160 }
161 else if (dir == CRAS_STREAM_INPUT) {
162 c->has_mute = snd_mixer_selem_has_capture_switch(elem);
163
164 if (snd_mixer_selem_has_capture_volume(elem) &&
165 snd_mixer_selem_get_capture_dB_range(
166 elem, &min, &max) == 0) {
167 c->max_volume_dB = max;
168 c->min_volume_dB = min;
169 c->has_volume = 1;
170 }
171 }
172
173 return c;
174 }
175
mixer_control_destroy(struct mixer_control * control)176 static void mixer_control_destroy(struct mixer_control *control) {
177 struct mixer_control_element *elem;
178
179 if (!control)
180 return;
181
182 DL_FOREACH(control->elements, elem) {
183 DL_DELETE(control->elements, elem);
184 free(elem);
185 }
186 if (control->name)
187 free((void *)control->name);
188 free(control);
189 }
190
mixer_control_destroy_list(struct mixer_control * control_list)191 static void mixer_control_destroy_list(struct mixer_control *control_list)
192 {
193 struct mixer_control *control;
194 if (!control_list)
195 return;
196 DL_FOREACH(control_list, control) {
197 DL_DELETE(control_list, control);
198 mixer_control_destroy(control);
199 }
200 }
201
mixer_control_add_element(struct mixer_control * control,snd_mixer_elem_t * snd_elem)202 static int mixer_control_add_element(struct mixer_control *control,
203 snd_mixer_elem_t *snd_elem)
204 {
205 struct mixer_control_element *elem;
206
207 if (!control)
208 return -EINVAL;
209
210 elem = mixer_control_element_create(snd_elem, control->dir);
211 if (!elem)
212 return -ENOMEM;
213
214 DL_APPEND(control->elements, elem);
215
216 if (elem->has_volume) {
217 if (!control->has_volume)
218 control->has_volume = 1;
219
220 /* Assume that all elements have a common volume range, and
221 * that both min and max values are valid if one of the two
222 * is valid. */
223 if (control->min_volume_dB ==
224 MIXER_CONTROL_VOLUME_DB_INVALID) {
225 control->min_volume_dB = elem->min_volume_dB;
226 control->max_volume_dB = elem->max_volume_dB;
227 } else if (control->min_volume_dB != elem->min_volume_dB ||
228 control->max_volume_dB != elem->max_volume_dB) {
229 syslog(LOG_WARNING,
230 "Element '%s' of control '%s' has different"
231 "volume range: [%ld:%ld] ctrl: [%ld:%ld]",
232 snd_mixer_selem_get_name(elem->elem),
233 control->name,
234 elem->min_volume_dB, elem->max_volume_dB,
235 control->min_volume_dB, control->max_volume_dB);
236 }
237 }
238
239 if (elem->has_mute && !control->has_mute)
240 control->has_mute = 1;
241 return 0;
242 }
243
mixer_control_create(struct mixer_control ** control,const char * name,snd_mixer_elem_t * elem,enum CRAS_STREAM_DIRECTION dir)244 static int mixer_control_create(struct mixer_control **control,
245 const char *name,
246 snd_mixer_elem_t *elem,
247 enum CRAS_STREAM_DIRECTION dir)
248 {
249 struct mixer_control *c;
250 int rc = 0;
251
252 if (!control)
253 return -EINVAL;
254
255 c = (struct mixer_control *)calloc(1, sizeof(*c));
256 if (!c) {
257 syslog(LOG_ERR, "No memory for mixer_control: %s", name);
258 rc = -ENOMEM;
259 goto error;
260 }
261
262 c->dir = dir;
263 c->min_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID;
264 c->max_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID;
265
266 if (!name && elem)
267 name = snd_mixer_selem_get_name(elem);
268 if (!name) {
269 syslog(LOG_ERR, "Control does not have a name.");
270 rc = -EINVAL;
271 goto error;
272 }
273
274 c->name = strdup(name);
275 if (!c->name) {
276 syslog(LOG_ERR, "No memory for control's name: %s", name);
277 rc = -ENOMEM;
278 goto error;
279 }
280
281 if (elem && (rc = mixer_control_add_element(c, elem)))
282 goto error;
283
284 *control = c;
285 return 0;
286
287 error:
288 mixer_control_destroy(c);
289 *control = NULL;
290 return rc;
291 }
292
293 /* Creates a mixer_control by finding mixer element names in simple mixer
294 * interface.
295 * Args:
296 * control[out] - Storage for resulting pointer to mixer_control.
297 * cmix[in] - Parent alsa mixer.
298 * name[in] - Optional name of the control. Input NULL to take the name of
299 * the first element from mixer_names.
300 * mixer_names[in] - Names of the ASLA mixer control elements. Must not
301 * be empty.
302 * dir[in] - Control direction: CRAS_STREAM_OUTPUT or CRAS_STREAM_INPUT.
303 * Returns:
304 * Returns 0 for success, negative error code otherwise. *control is
305 * initialized to NULL on error, or has a valid pointer for success.
306 */
mixer_control_create_by_name(struct mixer_control ** control,struct cras_alsa_mixer * cmix,const char * name,struct mixer_name * mixer_names,enum CRAS_STREAM_DIRECTION dir)307 static int mixer_control_create_by_name(
308 struct mixer_control **control,
309 struct cras_alsa_mixer *cmix,
310 const char *name,
311 struct mixer_name *mixer_names,
312 enum CRAS_STREAM_DIRECTION dir)
313 {
314 snd_mixer_selem_id_t *sid;
315 snd_mixer_elem_t *elem;
316 struct mixer_control *c;
317 struct mixer_name *m_name;
318 int rc;
319
320 if (!control)
321 return -EINVAL;
322 *control = NULL;
323 if (!mixer_names)
324 return -EINVAL;
325 if (!name) {
326 /* Assume that we're using the first name in the list of mixer
327 * names. */
328 name = mixer_names->name;
329 }
330
331 rc = mixer_control_create(&c, name, NULL, dir);
332 if (rc)
333 return rc;
334
335 snd_mixer_selem_id_malloc(&sid);
336
337 DL_FOREACH(mixer_names, m_name) {
338 snd_mixer_selem_id_set_index(sid, 0);
339 snd_mixer_selem_id_set_name(sid, m_name->name);
340 elem = snd_mixer_find_selem(cmix->mixer, sid);
341 if (!elem) {
342 mixer_control_destroy(c);
343 snd_mixer_selem_id_free(sid);
344 syslog(LOG_ERR, "Unable to find simple control %s, 0",
345 m_name->name);
346 return -ENOENT;
347 }
348 rc = mixer_control_add_element(c, elem);
349 if (rc) {
350 mixer_control_destroy(c);
351 snd_mixer_selem_id_free(sid);
352 return rc;
353 }
354 }
355
356 snd_mixer_selem_id_free(sid);
357 *control = c;
358 return 0;
359 }
360
mixer_control_set_dBFS(const struct mixer_control * control,long to_set)361 static int mixer_control_set_dBFS(
362 const struct mixer_control *control, long to_set)
363 {
364 const struct mixer_control_element *elem = NULL;
365 int rc = -EINVAL;
366 if (!control)
367 return rc;
368 DL_FOREACH(control->elements, elem) {
369 if(elem->has_volume) {
370 if (control->dir == CRAS_STREAM_OUTPUT)
371 rc = snd_mixer_selem_set_playback_dB_all(
372 elem->elem, to_set, 1);
373 else if (control->dir == CRAS_STREAM_INPUT)
374 rc = snd_mixer_selem_set_capture_dB_all(
375 elem->elem, to_set, 1);
376 if (rc)
377 break;
378 syslog(LOG_DEBUG, "%s:%s volume set to %ld",
379 control->name,
380 snd_mixer_selem_get_name(elem->elem),
381 to_set);
382 }
383 }
384 if (rc && elem) {
385 syslog(LOG_ERR, "Failed to set volume of '%s:%s': %d",
386 control->name,
387 snd_mixer_selem_get_name(elem->elem), rc);
388 }
389 return rc;
390 }
391
mixer_control_get_dBFS(const struct mixer_control * control,long * to_get)392 static int mixer_control_get_dBFS(
393 const struct mixer_control *control, long *to_get)
394 {
395 const struct mixer_control_element *elem = NULL;
396 int rc = -EINVAL;
397 if (!control || !to_get)
398 return -EINVAL;
399 DL_FOREACH(control->elements, elem) {
400 if (elem->has_volume) {
401 if (control->dir == CRAS_STREAM_OUTPUT)
402 rc = snd_mixer_selem_get_playback_dB(
403 elem->elem,
404 SND_MIXER_SCHN_FRONT_LEFT,
405 to_get);
406 else if (control->dir == CRAS_STREAM_INPUT)
407 rc = snd_mixer_selem_get_capture_dB(
408 elem->elem,
409 SND_MIXER_SCHN_FRONT_LEFT,
410 to_get);
411 /* Assume all of the elements of this control have
412 * the same value. */
413 break;
414 }
415 }
416 if (rc && elem) {
417 syslog(LOG_ERR, "Failed to get volume of '%s:%s': %d",
418 control->name,
419 snd_mixer_selem_get_name(elem->elem), rc);
420 }
421 return rc;
422 }
423
mixer_control_set_mute(const struct mixer_control * control,int muted)424 static int mixer_control_set_mute(
425 const struct mixer_control *control, int muted)
426 {
427 const struct mixer_control_element *elem = NULL;
428 int rc;
429 if (!control)
430 return -EINVAL;
431 DL_FOREACH(control->elements, elem) {
432 if(elem->has_mute) {
433 if (control->dir == CRAS_STREAM_OUTPUT)
434 rc = snd_mixer_selem_set_playback_switch_all(
435 elem->elem, !muted);
436 else if (control->dir == CRAS_STREAM_INPUT)
437 rc = snd_mixer_selem_set_capture_switch_all(
438 elem->elem, !muted);
439 if (rc)
440 break;
441 }
442 }
443 if (rc && elem) {
444 syslog(LOG_ERR, "Failed to mute '%s:%s': %d",
445 control->name,
446 snd_mixer_selem_get_name(elem->elem), rc);
447 }
448 return rc;
449 }
450
451 /* Adds the main volume control to the list and grabs the first seen playback
452 * switch to use for mute. */
add_main_volume_control(struct cras_alsa_mixer * cmix,snd_mixer_elem_t * elem)453 static int add_main_volume_control(struct cras_alsa_mixer *cmix,
454 snd_mixer_elem_t *elem)
455 {
456 if (snd_mixer_selem_has_playback_volume(elem)) {
457 long range;
458 struct mixer_control *c, *next;
459 int rc = mixer_control_create(&c, NULL, elem, CRAS_STREAM_OUTPUT);
460 if (rc)
461 return rc;
462
463 if (c->has_volume) {
464 cmix->max_volume_dB += c->max_volume_dB;
465 cmix->min_volume_dB += c->min_volume_dB;
466 }
467
468 range = c->max_volume_dB - c->min_volume_dB;
469 DL_FOREACH(cmix->main_volume_controls, next) {
470 if (range > next->max_volume_dB - next->min_volume_dB)
471 break;
472 }
473
474 syslog(LOG_DEBUG, "Add main volume control %s\n", c->name);
475 DL_INSERT(cmix->main_volume_controls, next, c);
476 }
477
478 /* If cmix doesn't yet have a playback switch and this is a playback
479 * switch, use it. */
480 if (cmix->playback_switch == NULL &&
481 snd_mixer_selem_has_playback_switch(elem)) {
482 syslog(LOG_DEBUG, "Using '%s' as playback switch.",
483 snd_mixer_selem_get_name(elem));
484 cmix->playback_switch = elem;
485 }
486
487 return 0;
488 }
489
490 /* Adds the main capture control to the list and grabs the first seen capture
491 * switch to mute input. */
add_main_capture_control(struct cras_alsa_mixer * cmix,snd_mixer_elem_t * elem)492 static int add_main_capture_control(struct cras_alsa_mixer *cmix,
493 snd_mixer_elem_t *elem)
494 {
495 /* TODO(dgreid) handle index != 0, map to correct input. */
496 if (snd_mixer_selem_get_index(elem) > 0)
497 return 0;
498
499 if (snd_mixer_selem_has_capture_volume(elem)) {
500 struct mixer_control *c;
501 int rc = mixer_control_create(&c, NULL, elem, CRAS_STREAM_INPUT);
502 if (rc)
503 return rc;
504
505 syslog(LOG_DEBUG, "Add main capture control %s\n", c->name);
506 DL_APPEND(cmix->main_capture_controls, c);
507 }
508
509 /* If cmix doesn't yet have a capture switch and this is a capture
510 * switch, use it. */
511 if (cmix->capture_switch == NULL &&
512 snd_mixer_selem_has_capture_switch(elem)) {
513 syslog(LOG_DEBUG, "Using '%s' as capture switch.",
514 snd_mixer_selem_get_name(elem));
515 cmix->capture_switch = elem;
516 }
517
518 return 0;
519 }
520
521 /* Adds a control to the list. */
add_control_with_name(struct cras_alsa_mixer * cmix,enum CRAS_STREAM_DIRECTION dir,snd_mixer_elem_t * elem,const char * name)522 static int add_control_with_name(struct cras_alsa_mixer *cmix,
523 enum CRAS_STREAM_DIRECTION dir,
524 snd_mixer_elem_t *elem,
525 const char *name)
526 {
527 int index; /* Index part of mixer simple element */
528 struct mixer_control *c;
529 int rc;
530
531 index = snd_mixer_selem_get_index(elem);
532 syslog(LOG_DEBUG, "Add %s control: %s,%d\n",
533 dir == CRAS_STREAM_OUTPUT ? "output" : "input",
534 name, index);
535
536 rc = mixer_control_create(&c, name, elem, dir);
537 if (rc)
538 return rc;
539
540 if (c->has_volume)
541 syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
542 c->name, c->min_volume_dB, c->max_volume_dB);
543
544 if (dir == CRAS_STREAM_OUTPUT)
545 DL_APPEND(cmix->output_controls, c);
546 else if (dir == CRAS_STREAM_INPUT)
547 DL_APPEND(cmix->input_controls, c);
548 return 0;
549 }
550
add_control(struct cras_alsa_mixer * cmix,enum CRAS_STREAM_DIRECTION dir,snd_mixer_elem_t * elem)551 static int add_control(struct cras_alsa_mixer *cmix,
552 enum CRAS_STREAM_DIRECTION dir,
553 snd_mixer_elem_t *elem)
554 {
555 return add_control_with_name(cmix, dir, elem,
556 snd_mixer_selem_get_name(elem));
557 }
558
list_controls(struct mixer_control * control_list,cras_alsa_mixer_control_callback cb,void * cb_arg)559 static void list_controls(struct mixer_control *control_list,
560 cras_alsa_mixer_control_callback cb,
561 void *cb_arg)
562 {
563 struct mixer_control *control;
564
565 DL_FOREACH(control_list, control)
566 cb(control, cb_arg);
567 }
568
get_control_matching_name(struct mixer_control * control_list,const char * name)569 static struct mixer_control *get_control_matching_name(
570 struct mixer_control *control_list,
571 const char *name)
572 {
573 struct mixer_control *c;
574
575 DL_FOREACH(control_list, c) {
576 if (strstr(name, c->name))
577 return c;
578 }
579 return NULL;
580 }
581
582 /* Creates a mixer_control with multiple control elements. */
add_control_with_coupled_mixers(struct cras_alsa_mixer * cmix,enum CRAS_STREAM_DIRECTION dir,const char * name,struct mixer_name * coupled_controls)583 static int add_control_with_coupled_mixers(
584 struct cras_alsa_mixer *cmix,
585 enum CRAS_STREAM_DIRECTION dir,
586 const char *name,
587 struct mixer_name *coupled_controls)
588 {
589 struct mixer_control *c;
590 int rc;
591
592 rc = mixer_control_create_by_name(
593 &c, cmix, name, coupled_controls, dir);
594 if (rc)
595 return rc;
596 syslog(LOG_DEBUG, "Add %s control: %s\n",
597 dir == CRAS_STREAM_OUTPUT ? "output" : "input",
598 c->name);
599 mixer_name_dump(coupled_controls, " elements");
600
601 if (c->has_volume)
602 syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
603 c->name, c->min_volume_dB, c->max_volume_dB);
604
605 if (dir == CRAS_STREAM_OUTPUT)
606 DL_APPEND(cmix->output_controls, c);
607 else if (dir == CRAS_STREAM_INPUT)
608 DL_APPEND(cmix->input_controls, c);
609 return 0;
610 }
611
add_control_by_name(struct cras_alsa_mixer * cmix,enum CRAS_STREAM_DIRECTION dir,const char * name)612 static int add_control_by_name(struct cras_alsa_mixer *cmix,
613 enum CRAS_STREAM_DIRECTION dir,
614 const char *name)
615 {
616 struct mixer_control *c;
617 struct mixer_name *m_name;
618 int rc;
619
620 m_name = mixer_name_add(NULL, name, dir, MIXER_NAME_VOLUME);
621 if (!m_name)
622 return -ENOMEM;
623
624 rc = mixer_control_create_by_name(&c, cmix, name, m_name, dir);
625 mixer_name_free(m_name);
626 if (rc)
627 return rc;
628 syslog(LOG_DEBUG, "Add %s control: %s\n",
629 dir == CRAS_STREAM_OUTPUT ? "output" : "input",
630 c->name);
631
632 if (c->has_volume)
633 syslog(LOG_DEBUG, "Control '%s' volume range: [%ld:%ld]",
634 c->name, c->min_volume_dB, c->max_volume_dB);
635
636 if (dir == CRAS_STREAM_OUTPUT)
637 DL_APPEND(cmix->output_controls, c);
638 else if (dir == CRAS_STREAM_INPUT)
639 DL_APPEND(cmix->input_controls, c);
640 return 0;
641 }
642
643 /*
644 * Exported interface.
645 */
646
cras_alsa_mixer_create(const char * card_name)647 struct cras_alsa_mixer *cras_alsa_mixer_create(const char *card_name)
648 {
649 struct cras_alsa_mixer *cmix;
650
651 cmix = (struct cras_alsa_mixer *)calloc(1, sizeof(*cmix));
652 if (cmix == NULL)
653 return NULL;
654
655 syslog(LOG_DEBUG, "Add mixer for device %s", card_name);
656
657 alsa_mixer_open(card_name, &cmix->mixer);
658
659 return cmix;
660 }
661
cras_alsa_mixer_add_controls_by_name_matching(struct cras_alsa_mixer * cmix,struct mixer_name * extra_controls,struct mixer_name * coupled_controls)662 int cras_alsa_mixer_add_controls_by_name_matching(
663 struct cras_alsa_mixer *cmix,
664 struct mixer_name *extra_controls,
665 struct mixer_name *coupled_controls)
666 {
667 /* Names of controls for main system volume. */
668 static const char * const main_volume_names[] = {
669 "Master",
670 "Digital",
671 "PCM",
672 };
673 /* Names of controls for individual outputs. */
674 static const char * const output_names[] = {
675 "Headphone",
676 "Headset",
677 "HDMI",
678 "Speaker",
679 };
680 /* Names of controls for capture gain/attenuation and mute. */
681 static const char * const main_capture_names[] = {
682 "Capture",
683 "Digital Capture",
684 };
685 /* Names of controls for individual inputs. */
686 static const char * const input_names[] = {
687 "Mic",
688 "Microphone",
689 };
690
691 struct mixer_name *default_controls = NULL;
692 snd_mixer_elem_t *elem;
693 int extra_main_volume = 0;
694 snd_mixer_elem_t *other_elem = NULL;
695 long other_dB_range = 0;
696 int rc = 0;
697
698 /* Note that there is no mixer on some cards. This is acceptable. */
699 if (cmix->mixer == NULL) {
700 syslog(LOG_DEBUG, "Couldn't open mixer.");
701 return 0;
702 }
703
704 default_controls = mixer_name_add_array(default_controls,
705 output_names, ARRAY_SIZE(output_names),
706 CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME);
707 default_controls = mixer_name_add_array(default_controls,
708 input_names, ARRAY_SIZE(input_names),
709 CRAS_STREAM_INPUT, MIXER_NAME_VOLUME);
710 default_controls =
711 mixer_name_add_array(default_controls,
712 main_volume_names, ARRAY_SIZE(main_volume_names),
713 CRAS_STREAM_OUTPUT, MIXER_NAME_MAIN_VOLUME);
714 default_controls =
715 mixer_name_add_array(default_controls,
716 main_capture_names, ARRAY_SIZE(main_capture_names),
717 CRAS_STREAM_INPUT, MIXER_NAME_MAIN_VOLUME);
718 extra_main_volume =
719 mixer_name_find(extra_controls, NULL,
720 CRAS_STREAM_OUTPUT,
721 MIXER_NAME_MAIN_VOLUME) != NULL;
722
723 /* Find volume and mute controls. */
724 for(elem = snd_mixer_first_elem(cmix->mixer);
725 elem != NULL; elem = snd_mixer_elem_next(elem)) {
726 const char *name;
727 struct mixer_name *control;
728 int found = 0;
729
730 name = snd_mixer_selem_get_name(elem);
731 if (name == NULL)
732 continue;
733
734 /* Find a matching control. */
735 control = mixer_name_find(default_controls, name,
736 CRAS_STREAM_OUTPUT,
737 MIXER_NAME_UNDEFINED);
738
739 /* If our extra controls contain a main volume
740 * entry, and we found a main volume entry, then
741 * skip it. */
742 if (extra_main_volume &&
743 control && control->type == MIXER_NAME_MAIN_VOLUME)
744 control = NULL;
745
746 /* If we didn't match any of the defaults, match
747 * the extras list. */
748 if (!control)
749 control = mixer_name_find(extra_controls, name,
750 CRAS_STREAM_OUTPUT,
751 MIXER_NAME_UNDEFINED);
752
753 if (control) {
754 int rc = -1;
755 switch(control->type) {
756 case MIXER_NAME_MAIN_VOLUME:
757 rc = add_main_volume_control(cmix, elem);
758 break;
759 case MIXER_NAME_VOLUME:
760 /* TODO(dgreid) - determine device index. */
761 rc = add_control(
762 cmix, CRAS_STREAM_OUTPUT, elem);
763 break;
764 case MIXER_NAME_UNDEFINED:
765 rc = -EINVAL;
766 break;
767 }
768 if (rc) {
769 syslog(LOG_ERR,
770 "Failed to add mixer control '%s'"
771 " with type '%d'",
772 control->name, control->type);
773 goto out;
774 }
775 found = 1;
776 }
777
778 /* Find a matching input control. */
779 control = mixer_name_find(default_controls, name,
780 CRAS_STREAM_INPUT,
781 MIXER_NAME_UNDEFINED);
782
783 /* If we didn't match any of the defaults, match
784 the extras list */
785 if (!control)
786 control = mixer_name_find(extra_controls, name,
787 CRAS_STREAM_INPUT,
788 MIXER_NAME_UNDEFINED);
789
790 if (control) {
791 int rc = -1;
792 switch(control->type) {
793 case MIXER_NAME_MAIN_VOLUME:
794 rc = add_main_capture_control(cmix, elem);
795 break;
796 case MIXER_NAME_VOLUME:
797 rc = add_control(
798 cmix, CRAS_STREAM_INPUT, elem);
799 break;
800 case MIXER_NAME_UNDEFINED:
801 rc = -EINVAL;
802 break;
803 }
804 if (rc) {
805 syslog(LOG_ERR,
806 "Failed to add mixer control '%s'"
807 " with type '%d'",
808 control->name, control->type);
809 goto out;
810 }
811 found = 1;
812 }
813
814 if (!found && snd_mixer_selem_has_playback_volume(elem)) {
815 /* Temporarily cache one elem whose name is not
816 * in the list above, but has a playback volume
817 * control and the largest volume range. */
818 long min, max, range;
819 if (snd_mixer_selem_get_playback_dB_range(elem,
820 &min,
821 &max) != 0)
822 continue;
823
824 range = max - min;
825 if (other_dB_range < range) {
826 other_dB_range = range;
827 other_elem = elem;
828 }
829 }
830 }
831
832 /* Handle coupled output names for speaker */
833 if (coupled_controls) {
834 rc = add_control_with_coupled_mixers(
835 cmix, CRAS_STREAM_OUTPUT,
836 "Speaker", coupled_controls);
837 if (rc) {
838 syslog(LOG_ERR, "Could not add coupled output");
839 goto out;
840 }
841 }
842
843 /* If there is no volume control and output control found,
844 * use the volume control which has the largest volume range
845 * in the mixer as a main volume control. */
846 if (!cmix->main_volume_controls && !cmix->output_controls &&
847 other_elem) {
848 rc = add_main_volume_control(cmix, other_elem);
849 if (rc) {
850 syslog(LOG_ERR, "Could not add other volume control");
851 goto out;
852 }
853 }
854
855 out:
856 mixer_name_free(default_controls);
857 return rc;
858 }
859
cras_alsa_mixer_add_controls_in_section(struct cras_alsa_mixer * cmix,struct ucm_section * section)860 int cras_alsa_mixer_add_controls_in_section(
861 struct cras_alsa_mixer *cmix,
862 struct ucm_section *section)
863 {
864 int rc;
865
866 /* Note that there is no mixer on some cards. This is acceptable. */
867 if (cmix->mixer == NULL) {
868 syslog(LOG_DEBUG, "Couldn't open mixer.");
869 return 0;
870 }
871
872 if (!section) {
873 syslog(LOG_ERR, "No UCM SectionDevice specified.");
874 return -EINVAL;
875 }
876
877 /* TODO(muirj) - Extra main volume controls when fully-specified. */
878
879 if (section->mixer_name) {
880 rc = add_control_by_name(
881 cmix, section->dir, section->mixer_name);
882 if (rc) {
883 syslog(LOG_ERR, "Could not add mixer control '%s': %s",
884 section->mixer_name, strerror(-rc));
885 return rc;
886 }
887 }
888
889 if (section->coupled) {
890 rc = add_control_with_coupled_mixers(
891 cmix, section->dir,
892 section->name, section->coupled);
893 if (rc) {
894 syslog(LOG_ERR, "Could not add coupled control: %s",
895 strerror(-rc));
896 return rc;
897 }
898 }
899 return 0;
900 }
901
cras_alsa_mixer_destroy(struct cras_alsa_mixer * cras_mixer)902 void cras_alsa_mixer_destroy(struct cras_alsa_mixer *cras_mixer)
903 {
904 assert(cras_mixer);
905
906 mixer_control_destroy_list(cras_mixer->main_volume_controls);
907 mixer_control_destroy_list(cras_mixer->main_capture_controls);
908 mixer_control_destroy_list(cras_mixer->output_controls);
909 mixer_control_destroy_list(cras_mixer->input_controls);
910 if (cras_mixer->mixer)
911 snd_mixer_close(cras_mixer->mixer);
912 free(cras_mixer);
913 }
914
cras_alsa_mixer_has_main_volume(const struct cras_alsa_mixer * cras_mixer)915 int cras_alsa_mixer_has_main_volume(
916 const struct cras_alsa_mixer *cras_mixer)
917 {
918 return !!cras_mixer->main_volume_controls;
919 }
920
cras_alsa_mixer_has_volume(const struct mixer_control * mixer_control)921 int cras_alsa_mixer_has_volume(const struct mixer_control *mixer_control)
922 {
923 return mixer_control && mixer_control->has_volume;
924 }
925
cras_alsa_mixer_set_dBFS(struct cras_alsa_mixer * cras_mixer,long dBFS,struct mixer_control * mixer_output)926 void cras_alsa_mixer_set_dBFS(struct cras_alsa_mixer *cras_mixer,
927 long dBFS,
928 struct mixer_control *mixer_output)
929 {
930 struct mixer_control *c;
931 long to_set;
932
933 assert(cras_mixer);
934
935 /* dBFS is normally < 0 to specify the attenuation from max. max is the
936 * combined max of the master controls and the current output.
937 */
938 to_set = dBFS + cras_mixer->max_volume_dB;
939 if (cras_alsa_mixer_has_volume(mixer_output))
940 to_set += mixer_output->max_volume_dB;
941 /* Go through all the controls, set the volume level for each,
942 * taking the value closest but greater than the desired volume. If the
943 * entire volume can't be set on the current control, move on to the
944 * next one until we have the exact volume, or gotten as close as we
945 * can. Once all of the volume is set the rest of the controls should be
946 * set to 0dB. */
947 DL_FOREACH(cras_mixer->main_volume_controls, c) {
948 long actual_dB;
949
950 if (!c->has_volume)
951 continue;
952 mixer_control_set_dBFS(c, to_set);
953 mixer_control_get_dBFS(c, &actual_dB);
954 to_set -= actual_dB;
955 }
956 /* Apply the rest to the output-specific control. */
957 if (cras_alsa_mixer_has_volume(mixer_output))
958 mixer_control_set_dBFS(mixer_output, to_set);
959 }
960
cras_alsa_mixer_get_dB_range(struct cras_alsa_mixer * cras_mixer)961 long cras_alsa_mixer_get_dB_range(struct cras_alsa_mixer *cras_mixer)
962 {
963 if (!cras_mixer)
964 return 0;
965 return cras_mixer->max_volume_dB - cras_mixer->min_volume_dB;
966 }
967
cras_alsa_mixer_get_output_dB_range(struct mixer_control * mixer_output)968 long cras_alsa_mixer_get_output_dB_range(
969 struct mixer_control *mixer_output)
970 {
971 if (!cras_alsa_mixer_has_volume(mixer_output))
972 return 0;
973
974 return mixer_output->max_volume_dB - mixer_output->min_volume_dB;
975 }
976
cras_alsa_mixer_set_capture_dBFS(struct cras_alsa_mixer * cras_mixer,long dBFS,struct mixer_control * mixer_input)977 void cras_alsa_mixer_set_capture_dBFS(struct cras_alsa_mixer *cras_mixer,
978 long dBFS,
979 struct mixer_control *mixer_input)
980 {
981 struct mixer_control *c;
982 long to_set;
983
984 assert(cras_mixer);
985 to_set = dBFS;
986 /* Go through all the controls, set the gain for each, taking the value
987 * closest but greater than the desired gain. If the entire gain can't
988 * be set on the current control, move on to the next one until we have
989 * the exact gain, or gotten as close as we can. Once all of the gain is
990 * set the rest of the controls should be set to 0dB. */
991 DL_FOREACH(cras_mixer->main_capture_controls, c) {
992 long actual_dB;
993
994 if (!c->has_volume)
995 continue;
996 mixer_control_set_dBFS(c, to_set);
997 mixer_control_get_dBFS(c, &actual_dB);
998 to_set -= actual_dB;
999 }
1000
1001 /* Apply the reset to input specific control */
1002 if (cras_alsa_mixer_has_volume(mixer_input))
1003 mixer_control_set_dBFS(mixer_input, to_set);
1004 }
1005
cras_alsa_mixer_get_minimum_capture_gain(struct cras_alsa_mixer * cmix,struct mixer_control * mixer_input)1006 long cras_alsa_mixer_get_minimum_capture_gain(
1007 struct cras_alsa_mixer *cmix,
1008 struct mixer_control *mixer_input)
1009 {
1010 struct mixer_control *c;
1011 long total_min = 0;
1012
1013 assert(cmix);
1014 DL_FOREACH(cmix->main_capture_controls, c)
1015 if (c->has_volume)
1016 total_min += c->min_volume_dB;
1017 if (mixer_input &&
1018 mixer_input->has_volume)
1019 total_min += mixer_input->min_volume_dB;
1020
1021 return total_min;
1022 }
1023
cras_alsa_mixer_get_maximum_capture_gain(struct cras_alsa_mixer * cmix,struct mixer_control * mixer_input)1024 long cras_alsa_mixer_get_maximum_capture_gain(
1025 struct cras_alsa_mixer *cmix,
1026 struct mixer_control *mixer_input)
1027 {
1028 struct mixer_control *c;
1029 long total_max = 0;
1030
1031 assert(cmix);
1032 DL_FOREACH(cmix->main_capture_controls, c)
1033 if (c->has_volume)
1034 total_max += c->max_volume_dB;
1035
1036 if (mixer_input &&
1037 mixer_input->has_volume)
1038 total_max += mixer_input->max_volume_dB;
1039
1040 return total_max;
1041 }
1042
cras_alsa_mixer_set_mute(struct cras_alsa_mixer * cras_mixer,int muted,struct mixer_control * mixer_output)1043 void cras_alsa_mixer_set_mute(struct cras_alsa_mixer *cras_mixer,
1044 int muted,
1045 struct mixer_control *mixer_output)
1046 {
1047 assert(cras_mixer);
1048
1049 if (cras_mixer->playback_switch) {
1050 snd_mixer_selem_set_playback_switch_all(
1051 cras_mixer->playback_switch, !muted);
1052 }
1053 if (mixer_output && mixer_output->has_mute) {
1054 mixer_control_set_mute(mixer_output, muted);
1055 }
1056 }
1057
cras_alsa_mixer_set_capture_mute(struct cras_alsa_mixer * cras_mixer,int muted,struct mixer_control * mixer_input)1058 void cras_alsa_mixer_set_capture_mute(struct cras_alsa_mixer *cras_mixer,
1059 int muted,
1060 struct mixer_control *mixer_input)
1061 {
1062 assert(cras_mixer);
1063 if (cras_mixer->capture_switch) {
1064 snd_mixer_selem_set_capture_switch_all(
1065 cras_mixer->capture_switch, !muted);
1066 return;
1067 }
1068 if (mixer_input && mixer_input->has_mute)
1069 mixer_control_set_mute(mixer_input, muted);
1070 }
1071
cras_alsa_mixer_list_outputs(struct cras_alsa_mixer * cras_mixer,cras_alsa_mixer_control_callback cb,void * cb_arg)1072 void cras_alsa_mixer_list_outputs(struct cras_alsa_mixer *cras_mixer,
1073 cras_alsa_mixer_control_callback cb,
1074 void *cb_arg)
1075 {
1076 assert(cras_mixer);
1077 list_controls(cras_mixer->output_controls, cb, cb_arg);
1078 }
1079
cras_alsa_mixer_list_inputs(struct cras_alsa_mixer * cras_mixer,cras_alsa_mixer_control_callback cb,void * cb_arg)1080 void cras_alsa_mixer_list_inputs(struct cras_alsa_mixer *cras_mixer,
1081 cras_alsa_mixer_control_callback cb,
1082 void *cb_arg)
1083 {
1084 assert(cras_mixer);
1085 list_controls(cras_mixer->input_controls, cb, cb_arg);
1086 }
1087
cras_alsa_mixer_get_control_name(const struct mixer_control * control)1088 const char *cras_alsa_mixer_get_control_name(
1089 const struct mixer_control *control)
1090 {
1091 if (!control)
1092 return NULL;
1093 return control->name;
1094 }
1095
cras_alsa_mixer_get_control_matching_name(struct cras_alsa_mixer * cras_mixer,enum CRAS_STREAM_DIRECTION dir,const char * name,int create_missing)1096 struct mixer_control *cras_alsa_mixer_get_control_matching_name(
1097 struct cras_alsa_mixer *cras_mixer,
1098 enum CRAS_STREAM_DIRECTION dir, const char *name,
1099 int create_missing)
1100 {
1101 struct mixer_control *c;
1102
1103 assert(cras_mixer);
1104 if (!name)
1105 return NULL;
1106
1107 if (dir == CRAS_STREAM_OUTPUT) {
1108 c = get_control_matching_name(
1109 cras_mixer->output_controls, name);
1110 } else if (dir == CRAS_STREAM_INPUT) {
1111 c = get_control_matching_name(
1112 cras_mixer->input_controls, name);
1113 } else {
1114 return NULL;
1115 }
1116
1117 /* TODO: Allowing creation of a new control is a workaround: we
1118 * should pass the input names in ucm config to
1119 * cras_alsa_mixer_create. */
1120 if (!c && cras_mixer->mixer && create_missing) {
1121 int rc = add_control_by_name(cras_mixer, dir, name);
1122 if (rc)
1123 return NULL;
1124 c = cras_alsa_mixer_get_control_matching_name(
1125 cras_mixer, dir, name, 0);
1126 }
1127 return c;
1128 }
1129
cras_alsa_mixer_get_control_for_section(struct cras_alsa_mixer * cras_mixer,const struct ucm_section * section)1130 struct mixer_control *cras_alsa_mixer_get_control_for_section(
1131 struct cras_alsa_mixer *cras_mixer,
1132 const struct ucm_section *section)
1133 {
1134 assert(cras_mixer && section);
1135 if (section->mixer_name) {
1136 return cras_alsa_mixer_get_control_matching_name(
1137 cras_mixer, section->dir, section->mixer_name, 0);
1138 } else if (section->coupled) {
1139 return cras_alsa_mixer_get_control_matching_name(
1140 cras_mixer, section->dir, section->name, 0);
1141 }
1142 return NULL;
1143 }
1144
cras_alsa_mixer_get_output_matching_name(struct cras_alsa_mixer * cras_mixer,const char * const name)1145 struct mixer_control *cras_alsa_mixer_get_output_matching_name(
1146 struct cras_alsa_mixer *cras_mixer,
1147 const char * const name)
1148 {
1149 return cras_alsa_mixer_get_control_matching_name(
1150 cras_mixer, CRAS_STREAM_OUTPUT, name, 0);
1151 }
1152
cras_alsa_mixer_get_input_matching_name(struct cras_alsa_mixer * cras_mixer,const char * name)1153 struct mixer_control *cras_alsa_mixer_get_input_matching_name(
1154 struct cras_alsa_mixer *cras_mixer,
1155 const char *name)
1156 {
1157 /* TODO: Allowing creation of a new control is a workaround: we
1158 * should pass the input names in ucm config to
1159 * cras_alsa_mixer_create. */
1160 return cras_alsa_mixer_get_control_matching_name(
1161 cras_mixer, CRAS_STREAM_INPUT, name, 1);
1162 }
1163
cras_alsa_mixer_set_output_active_state(struct mixer_control * output,int active)1164 int cras_alsa_mixer_set_output_active_state(
1165 struct mixer_control *output,
1166 int active)
1167 {
1168 assert(output);
1169 if (!output->has_mute)
1170 return -1;
1171 return mixer_control_set_mute(output, !active);
1172 }
1173