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