1 /* tinymix.c
2 **
3 ** Copyright 2011, The Android Open Source Project
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions are met:
7 ** * Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 ** * Redistributions in binary form must reproduce the above copyright
10 ** notice, this list of conditions and the following disclaimer in the
11 ** documentation and/or other materials provided with the distribution.
12 ** * Neither the name of The Android Open Source Project nor the names of
13 ** its contributors may be used to endorse or promote products derived
14 ** from this software without specific prior written permission.
15 **
16 ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 ** DAMAGE.
27 */
28
29 #include <tinyalsa/asoundlib.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <string.h>
35
36 static void tinymix_list_controls(struct mixer *mixer);
37 static void tinymix_detail_control(struct mixer *mixer, const char *control,
38 int print_all);
39 static void tinymix_set_value(struct mixer *mixer, const char *control,
40 char **values, unsigned int num_values);
41 static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all);
42
main(int argc,char ** argv)43 int main(int argc, char **argv)
44 {
45 struct mixer *mixer;
46 int card = 0;
47
48 if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) {
49 argv++;
50 if (argv[1]) {
51 card = atoi(argv[1]);
52 argv++;
53 argc -= 2;
54 } else {
55 argc -= 1;
56 }
57 }
58
59 mixer = mixer_open(card);
60 if (!mixer) {
61 fprintf(stderr, "Failed to open mixer\n");
62 return EXIT_FAILURE;
63 }
64
65
66 if (argc == 1) {
67 printf("Mixer name: '%s'\n", mixer_get_name(mixer));
68 tinymix_list_controls(mixer);
69 } else if (argc == 2) {
70 tinymix_detail_control(mixer, argv[1], 1);
71 } else if (argc >= 3) {
72 tinymix_set_value(mixer, argv[1], &argv[2], argc - 2);
73 } else {
74 printf("Usage: tinymix [-D card] [control id] [value to set]\n");
75 }
76
77 mixer_close(mixer);
78
79 return 0;
80 }
81
tinymix_list_controls(struct mixer * mixer)82 static void tinymix_list_controls(struct mixer *mixer)
83 {
84 struct mixer_ctl *ctl;
85 const char *name, *type;
86 unsigned int num_ctls, num_values;
87 unsigned int i;
88
89 num_ctls = mixer_get_num_ctls(mixer);
90
91 printf("Number of controls: %d\n", num_ctls);
92
93 printf("ctl\ttype\tnum\t%-40s value\n", "name");
94 for (i = 0; i < num_ctls; i++) {
95 ctl = mixer_get_ctl(mixer, i);
96
97 name = mixer_ctl_get_name(ctl);
98 type = mixer_ctl_get_type_string(ctl);
99 num_values = mixer_ctl_get_num_values(ctl);
100 printf("%d\t%s\t%d\t%-40s", i, type, num_values, name);
101 tinymix_detail_control(mixer, name, 0);
102 }
103 }
104
tinymix_print_enum(struct mixer_ctl * ctl,int print_all)105 static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all)
106 {
107 unsigned int num_enums;
108 unsigned int i;
109 const char *string;
110
111 num_enums = mixer_ctl_get_num_enums(ctl);
112
113 for (i = 0; i < num_enums; i++) {
114 string = mixer_ctl_get_enum_string(ctl, i);
115 if (print_all)
116 printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "",
117 string);
118 else if (mixer_ctl_get_value(ctl, 0) == (int)i)
119 printf(" %-s", string);
120 }
121 }
122
tinymix_detail_control(struct mixer * mixer,const char * control,int print_all)123 static void tinymix_detail_control(struct mixer *mixer, const char *control,
124 int print_all)
125 {
126 struct mixer_ctl *ctl;
127 enum mixer_ctl_type type;
128 unsigned int num_values;
129 unsigned int i;
130 int min, max;
131 int ret;
132 char *buf = NULL;
133 size_t len;
134
135 if (isdigit(control[0]))
136 ctl = mixer_get_ctl(mixer, atoi(control));
137 else
138 ctl = mixer_get_ctl_by_name(mixer, control);
139
140 if (!ctl) {
141 fprintf(stderr, "Invalid mixer control\n");
142 return;
143 }
144
145 type = mixer_ctl_get_type(ctl);
146 num_values = mixer_ctl_get_num_values(ctl);
147
148 if (type == MIXER_CTL_TYPE_BYTE) {
149
150 buf = calloc(1, num_values);
151 if (buf == NULL) {
152 fprintf(stderr, "Failed to alloc mem for bytes %d\n", num_values);
153 return;
154 }
155
156 len = num_values;
157 ret = mixer_ctl_get_array(ctl, buf, len);
158 if (ret < 0) {
159 fprintf(stderr, "Failed to mixer_ctl_get_array\n");
160 free(buf);
161 return;
162 }
163 }
164
165 if (print_all)
166 printf("%s:", mixer_ctl_get_name(ctl));
167
168 for (i = 0; i < num_values; i++) {
169 switch (type)
170 {
171 case MIXER_CTL_TYPE_INT:
172 printf(" %d", mixer_ctl_get_value(ctl, i));
173 break;
174 case MIXER_CTL_TYPE_BOOL:
175 printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
176 break;
177 case MIXER_CTL_TYPE_ENUM:
178 tinymix_print_enum(ctl, print_all);
179 break;
180 case MIXER_CTL_TYPE_BYTE:
181 printf("%02x", buf[i]);
182 break;
183 default:
184 printf(" unknown");
185 break;
186 };
187 }
188
189 if (print_all) {
190 if (type == MIXER_CTL_TYPE_INT) {
191 min = mixer_ctl_get_range_min(ctl);
192 max = mixer_ctl_get_range_max(ctl);
193 printf(" (range %d->%d)", min, max);
194 }
195 }
196
197 free(buf);
198
199 printf("\n");
200 }
201
tinymix_set_byte_ctl(struct mixer_ctl * ctl,char ** values,unsigned int num_values)202 static void tinymix_set_byte_ctl(struct mixer_ctl *ctl,
203 char **values, unsigned int num_values)
204 {
205 int ret;
206 char *buf;
207 char *end;
208 unsigned int i;
209 long n;
210
211 buf = calloc(1, num_values);
212 if (buf == NULL) {
213 fprintf(stderr, "set_byte_ctl: Failed to alloc mem for bytes %d\n", num_values);
214 exit(EXIT_FAILURE);
215 }
216
217 for (i = 0; i < num_values; i++) {
218 errno = 0;
219 n = strtol(values[i], &end, 0);
220 if (*end) {
221 fprintf(stderr, "%s not an integer\n", values[i]);
222 goto fail;
223 }
224 if (errno) {
225 fprintf(stderr, "strtol: %s: %s\n", values[i],
226 strerror(errno));
227 goto fail;
228 }
229 if (n < 0 || n > 0xff) {
230 fprintf(stderr, "%s should be between [0, 0xff]\n",
231 values[i]);
232 goto fail;
233 }
234 buf[i] = n;
235 }
236
237 ret = mixer_ctl_set_array(ctl, buf, num_values);
238 if (ret < 0) {
239 fprintf(stderr, "Failed to set binary control\n");
240 goto fail;
241 }
242
243 free(buf);
244 return;
245
246 fail:
247 free(buf);
248 exit(EXIT_FAILURE);
249 }
250
tinymix_set_value(struct mixer * mixer,const char * control,char ** values,unsigned int num_values)251 static void tinymix_set_value(struct mixer *mixer, const char *control,
252 char **values, unsigned int num_values)
253 {
254 struct mixer_ctl *ctl;
255 enum mixer_ctl_type type;
256 unsigned int num_ctl_values;
257 unsigned int i;
258
259 if (isdigit(control[0]))
260 ctl = mixer_get_ctl(mixer, atoi(control));
261 else
262 ctl = mixer_get_ctl_by_name(mixer, control);
263
264 if (!ctl) {
265 fprintf(stderr, "Invalid mixer control\n");
266 return;
267 }
268
269 type = mixer_ctl_get_type(ctl);
270 num_ctl_values = mixer_ctl_get_num_values(ctl);
271
272 if (type == MIXER_CTL_TYPE_BYTE) {
273 tinymix_set_byte_ctl(ctl, values, num_values);
274 return;
275 }
276
277 if (isdigit(values[0][0])) {
278 if (num_values == 1) {
279 /* Set all values the same */
280 int value = atoi(values[0]);
281
282 for (i = 0; i < num_ctl_values; i++) {
283 if (mixer_ctl_set_value(ctl, i, value)) {
284 fprintf(stderr, "Error: invalid value\n");
285 return;
286 }
287 }
288 } else {
289 /* Set multiple values */
290 if (num_values > num_ctl_values) {
291 fprintf(stderr,
292 "Error: %d values given, but control only takes %d\n",
293 num_values, num_ctl_values);
294 return;
295 }
296 for (i = 0; i < num_values; i++) {
297 if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
298 fprintf(stderr, "Error: invalid value for index %d\n", i);
299 return;
300 }
301 }
302 }
303 } else {
304 if (type == MIXER_CTL_TYPE_ENUM) {
305 if (num_values != 1) {
306 fprintf(stderr, "Enclose strings in quotes and try again\n");
307 return;
308 }
309 if (mixer_ctl_set_enum_by_string(ctl, values[0]))
310 fprintf(stderr, "Error: invalid enum value\n");
311 } else {
312 fprintf(stderr, "Error: only enum types can be set with strings\n");
313 }
314 }
315 }
316
317