parse.c revision 1.3 1 1.3 nia /* $NetBSD: parse.c,v 1.3 2021/05/08 13:03:40 nia Exp $ */
2 1.1 nia /*-
3 1.1 nia * Copyright (c) 2021 The NetBSD Foundation, Inc.
4 1.1 nia * All rights reserved.
5 1.1 nia *
6 1.1 nia * This code is derived from software contributed to The NetBSD Foundation
7 1.1 nia * by Nia Alarie.
8 1.1 nia *
9 1.1 nia * Redistribution and use in source and binary forms, with or without
10 1.1 nia * modification, are permitted provided that the following conditions
11 1.1 nia * are met:
12 1.1 nia * 1. Redistributions of source code must retain the above copyright
13 1.1 nia * notice, this list of conditions and the following disclaimer.
14 1.1 nia * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 nia * notice, this list of conditions and the following disclaimer in the
16 1.1 nia * documentation and/or other materials provided with the distribution.
17 1.1 nia *
18 1.1 nia * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.1 nia * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.1 nia * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.1 nia * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.1 nia * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.1 nia * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.1 nia * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.1 nia * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.1 nia * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.1 nia * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.1 nia * POSSIBILITY OF SUCH DAMAGE.
29 1.1 nia */
30 1.1 nia #include <sys/audioio.h>
31 1.1 nia #include <sys/ioctl.h>
32 1.1 nia #include <curses.h>
33 1.1 nia #include <stdlib.h>
34 1.1 nia #include "app.h"
35 1.1 nia #include "parse.h"
36 1.1 nia
37 1.1 nia static struct aiomixer_class *get_class(struct aiomixer *, int);
38 1.1 nia static int compare_control(const void *, const void *);
39 1.3 nia static int compare_class(const void *, const void *);
40 1.1 nia
41 1.1 nia static struct aiomixer_class *
42 1.1 nia get_class(struct aiomixer *aio, int class)
43 1.1 nia {
44 1.1 nia size_t i;
45 1.1 nia
46 1.1 nia for (i = 0; i < aio->numclasses; ++i) {
47 1.1 nia if (aio->classes[i].index == class) {
48 1.1 nia return &aio->classes[i];
49 1.1 nia }
50 1.1 nia }
51 1.1 nia return NULL;
52 1.1 nia }
53 1.1 nia
54 1.1 nia static int
55 1.1 nia compare_control(const void *pa, const void *pb)
56 1.1 nia {
57 1.1 nia const struct aiomixer_control *a = (const struct aiomixer_control *)pa;
58 1.1 nia const struct aiomixer_control *b = (const struct aiomixer_control *)pb;
59 1.1 nia
60 1.2 nia if (a->info.prev != AUDIO_MIXER_LAST ||
61 1.1 nia b->info.prev != AUDIO_MIXER_LAST) {
62 1.1 nia if (b->info.prev == a->info.index)
63 1.1 nia return -1;
64 1.1 nia if (a->info.prev == b->info.index)
65 1.1 nia return 1;
66 1.2 nia } else {
67 1.2 nia return strcmp(a->info.label.name, b->info.label.name);
68 1.1 nia }
69 1.2 nia return 0;
70 1.1 nia }
71 1.1 nia
72 1.3 nia static int
73 1.3 nia compare_class(const void *pa, const void *pb)
74 1.3 nia {
75 1.3 nia const struct aiomixer_class *a = (const struct aiomixer_class *)pa;
76 1.3 nia const struct aiomixer_class *b = (const struct aiomixer_class *)pb;
77 1.3 nia
78 1.3 nia if (strcmp(a->name, AudioCoutputs) == 0)
79 1.3 nia return -1;
80 1.3 nia if (strcmp(b->name, AudioCoutputs) == 0)
81 1.3 nia return 1;
82 1.3 nia
83 1.3 nia return strcmp(a->name, b->name);
84 1.3 nia }
85 1.3 nia
86 1.1 nia int
87 1.1 nia aiomixer_parse(struct aiomixer *aio)
88 1.1 nia {
89 1.1 nia size_t i;
90 1.1 nia struct mixer_devinfo info;
91 1.1 nia struct aiomixer_class *class;
92 1.1 nia struct aiomixer_control *control;
93 1.1 nia
94 1.1 nia for (info.index = 0;
95 1.1 nia ioctl(aio->fd, AUDIO_MIXER_DEVINFO, &info) != -1; ++info.index) {
96 1.1 nia if (info.type != AUDIO_MIXER_CLASS)
97 1.1 nia continue;
98 1.1 nia if (aio->numclasses >= __arraycount(aio->classes))
99 1.1 nia break;
100 1.1 nia class = &aio->classes[aio->numclasses++];
101 1.1 nia memcpy(class->name, info.label.name, MAX_AUDIO_DEV_LEN);
102 1.1 nia class->index = info.index;
103 1.1 nia class->numcontrols = 0;
104 1.1 nia }
105 1.1 nia for (info.index = 0;
106 1.1 nia ioctl(aio->fd, AUDIO_MIXER_DEVINFO, &info) != -1; ++info.index) {
107 1.1 nia if (info.type == AUDIO_MIXER_CLASS)
108 1.1 nia continue;
109 1.1 nia if (info.type == AUDIO_MIXER_VALUE) {
110 1.1 nia /* XXX workaround for hdaudio(4) bugs */
111 1.1 nia if (info.un.v.delta > AUDIO_MAX_GAIN)
112 1.1 nia continue;
113 1.1 nia if (info.un.v.num_channels == 0)
114 1.1 nia continue;
115 1.1 nia }
116 1.1 nia class = get_class(aio, info.mixer_class);
117 1.1 nia if (class == NULL)
118 1.1 nia break;
119 1.1 nia if (class->numcontrols >= __arraycount(class->controls))
120 1.1 nia break;
121 1.1 nia control = &class->controls[class->numcontrols++];
122 1.1 nia control->info = info;
123 1.1 nia }
124 1.3 nia qsort(aio->classes, aio->numclasses,
125 1.3 nia sizeof(struct aiomixer_class),
126 1.3 nia compare_class);
127 1.1 nia for (i = 0; i < aio->numclasses; ++i) {
128 1.1 nia class = &aio->classes[i];
129 1.1 nia qsort(class->controls, class->numcontrols,
130 1.1 nia sizeof(struct aiomixer_control),
131 1.1 nia compare_control);
132 1.1 nia }
133 1.1 nia return 0;
134 1.1 nia }
135 1.1 nia
136