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 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 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 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 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 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 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