1 /* mixer.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 <stdio.h> 30 #include <stdlib.h> 31 #include <stdint.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <ctype.h> 37 #include <poll.h> 38 39 #include <sys/ioctl.h> 40 41 #include <linux/ioctl.h> 42 #define __force 43 #define __bitwise 44 #define __user 45 #include <sound/asound.h> 46 47 #include <tinyalsa/asoundlib.h> 48 49 struct mixer_ctl { 50 struct mixer *mixer; 51 struct snd_ctl_elem_info *info; 52 char **ename; 53 }; 54 55 struct mixer { 56 int fd; 57 struct snd_ctl_card_info card_info; 58 struct snd_ctl_elem_info *elem_info; 59 struct mixer_ctl *ctl; 60 unsigned int count; 61 }; 62 63 void mixer_close(struct mixer *mixer) 64 { 65 unsigned int n,m; 66 67 if (!mixer) 68 return; 69 70 if (mixer->fd >= 0) 71 close(mixer->fd); 72 73 if (mixer->ctl) { 74 for (n = 0; n < mixer->count; n++) { 75 if (mixer->ctl[n].ename) { 76 unsigned int max = mixer->ctl[n].info->value.enumerated.items; 77 for (m = 0; m < max; m++) 78 free(mixer->ctl[n].ename[m]); 79 free(mixer->ctl[n].ename); 80 } 81 } 82 free(mixer->ctl); 83 } 84 85 if (mixer->elem_info) 86 free(mixer->elem_info); 87 88 free(mixer); 89 90 /* TODO: verify frees */ 91 } 92 93 struct mixer *mixer_open(unsigned int card) 94 { 95 struct snd_ctl_elem_list elist; 96 struct snd_ctl_elem_info tmp; 97 struct snd_ctl_elem_id *eid = NULL; 98 struct mixer *mixer = NULL; 99 unsigned int n, m; 100 int fd; 101 char fn[256]; 102 103 snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); 104 fd = open(fn, O_RDWR); 105 if (fd < 0) 106 return 0; 107 108 memset(&elist, 0, sizeof(elist)); 109 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) 110 goto fail; 111 112 mixer = calloc(1, sizeof(*mixer)); 113 if (!mixer) 114 goto fail; 115 116 mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); 117 mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); 118 if (!mixer->ctl || !mixer->elem_info) 119 goto fail; 120 121 if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) 122 goto fail; 123 124 eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); 125 if (!eid) 126 goto fail; 127 128 mixer->count = elist.count; 129 mixer->fd = fd; 130 elist.space = mixer->count; 131 elist.pids = eid; 132 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) 133 goto fail; 134 135 for (n = 0; n < mixer->count; n++) { 136 struct snd_ctl_elem_info *ei = mixer->elem_info + n; 137 ei->id.numid = eid[n].numid; 138 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) 139 goto fail; 140 mixer->ctl[n].info = ei; 141 mixer->ctl[n].mixer = mixer; 142 if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { 143 char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); 144 if (!enames) 145 goto fail; 146 mixer->ctl[n].ename = enames; 147 for (m = 0; m < ei->value.enumerated.items; m++) { 148 memset(&tmp, 0, sizeof(tmp)); 149 tmp.id.numid = ei->id.numid; 150 tmp.value.enumerated.item = m; 151 if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) 152 goto fail; 153 enames[m] = strdup(tmp.value.enumerated.name); 154 if (!enames[m]) 155 goto fail; 156 } 157 } 158 } 159 160 free(eid); 161 return mixer; 162 163 fail: 164 /* TODO: verify frees in failure case */ 165 if (eid) 166 free(eid); 167 if (mixer) 168 mixer_close(mixer); 169 else if (fd >= 0) 170 close(fd); 171 return 0; 172 } 173 174 const char *mixer_get_name(struct mixer *mixer) 175 { 176 return (const char *)mixer->card_info.name; 177 } 178 179 unsigned int mixer_get_num_ctls(struct mixer *mixer) 180 { 181 if (!mixer) 182 return 0; 183 184 return mixer->count; 185 } 186 187 struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id) 188 { 189 if (mixer && (id < mixer->count)) 190 return mixer->ctl + id; 191 192 return NULL; 193 } 194 195 struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name) 196 { 197 unsigned int n; 198 199 if (!mixer) 200 return NULL; 201 202 for (n = 0; n < mixer->count; n++) 203 if (!strcmp(name, (char*) mixer->elem_info[n].id.name)) 204 return mixer->ctl + n; 205 206 return NULL; 207 } 208 209 void mixer_ctl_update(struct mixer_ctl *ctl) 210 { 211 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); 212 } 213 214 const char *mixer_ctl_get_name(struct mixer_ctl *ctl) 215 { 216 if (!ctl) 217 return NULL; 218 219 return (const char *)ctl->info->id.name; 220 } 221 222 enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl) 223 { 224 if (!ctl) 225 return MIXER_CTL_TYPE_UNKNOWN; 226 227 switch (ctl->info->type) { 228 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL; 229 case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT; 230 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM; 231 case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE; 232 case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958; 233 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64; 234 default: return MIXER_CTL_TYPE_UNKNOWN; 235 }; 236 } 237 238 const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl) 239 { 240 if (!ctl) 241 return ""; 242 243 switch (ctl->info->type) { 244 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL"; 245 case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT"; 246 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM"; 247 case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE"; 248 case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958"; 249 case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64"; 250 default: return "Unknown"; 251 }; 252 } 253 254 unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl) 255 { 256 if (!ctl) 257 return 0; 258 259 return ctl->info->count; 260 } 261 262 static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) 263 { 264 int range; 265 266 if (percent > 100) 267 percent = 100; 268 else if (percent < 0) 269 percent = 0; 270 271 range = (ei->value.integer.max - ei->value.integer.min); 272 273 return ei->value.integer.min + (range * percent) / 100; 274 } 275 276 static int int_to_percent(struct snd_ctl_elem_info *ei, int value) 277 { 278 int range = (ei->value.integer.max - ei->value.integer.min); 279 280 if (range == 0) 281 return 0; 282 283 return ((value - ei->value.integer.min) / range) * 100; 284 } 285 286 int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id) 287 { 288 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) 289 return -EINVAL; 290 291 return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id)); 292 } 293 294 int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent) 295 { 296 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) 297 return -EINVAL; 298 299 return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent)); 300 } 301 302 int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id) 303 { 304 struct snd_ctl_elem_value ev; 305 int ret; 306 307 if (!ctl || (id >= ctl->info->count)) 308 return -EINVAL; 309 310 memset(&ev, 0, sizeof(ev)); 311 ev.id.numid = ctl->info->id.numid; 312 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); 313 if (ret < 0) 314 return ret; 315 316 switch (ctl->info->type) { 317 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 318 return !!ev.value.integer.value[id]; 319 320 case SNDRV_CTL_ELEM_TYPE_INTEGER: 321 return ev.value.integer.value[id]; 322 323 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 324 return ev.value.enumerated.item[id]; 325 326 case SNDRV_CTL_ELEM_TYPE_BYTES: 327 return ev.value.bytes.data[id]; 328 329 default: 330 return -EINVAL; 331 } 332 333 return 0; 334 } 335 336 int mixer_ctl_is_access_tlv_rw(struct mixer_ctl *ctl) 337 { 338 return (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE); 339 } 340 341 int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) 342 { 343 struct snd_ctl_elem_value ev; 344 int ret = 0; 345 size_t size; 346 void *source; 347 size_t total_count; 348 349 if ((!ctl) || !count || !array) 350 return -EINVAL; 351 352 total_count = ctl->info->count; 353 354 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) && 355 mixer_ctl_is_access_tlv_rw(ctl)) { 356 /* Additional two words is for the TLV header */ 357 total_count += TLV_HEADER_SIZE; 358 } 359 360 if (count > total_count) 361 return -EINVAL; 362 363 memset(&ev, 0, sizeof(ev)); 364 ev.id.numid = ctl->info->id.numid; 365 366 switch (ctl->info->type) { 367 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 368 case SNDRV_CTL_ELEM_TYPE_INTEGER: 369 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); 370 if (ret < 0) 371 return ret; 372 size = sizeof(ev.value.integer.value[0]); 373 source = ev.value.integer.value; 374 break; 375 376 case SNDRV_CTL_ELEM_TYPE_BYTES: 377 /* check if this is new bytes TLV */ 378 if (mixer_ctl_is_access_tlv_rw(ctl)) { 379 struct snd_ctl_tlv *tlv; 380 int ret; 381 382 if (count > SIZE_MAX - sizeof(*tlv)) 383 return -EINVAL; 384 tlv = calloc(1, sizeof(*tlv) + count); 385 if (!tlv) 386 return -ENOMEM; 387 tlv->numid = ctl->info->id.numid; 388 tlv->length = count; 389 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv); 390 391 source = tlv->tlv; 392 memcpy(array, source, count); 393 394 free(tlv); 395 396 return ret; 397 } else { 398 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); 399 if (ret < 0) 400 return ret; 401 size = sizeof(ev.value.bytes.data[0]); 402 source = ev.value.bytes.data; 403 break; 404 } 405 406 case SNDRV_CTL_ELEM_TYPE_IEC958: 407 size = sizeof(ev.value.iec958); 408 source = &ev.value.iec958; 409 break; 410 411 default: 412 return -EINVAL; 413 } 414 415 memcpy(array, source, size * count); 416 417 return 0; 418 } 419 420 int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) 421 { 422 struct snd_ctl_elem_value ev; 423 int ret; 424 425 if (!ctl || (id >= ctl->info->count)) 426 return -EINVAL; 427 428 memset(&ev, 0, sizeof(ev)); 429 ev.id.numid = ctl->info->id.numid; 430 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); 431 if (ret < 0) 432 return ret; 433 434 switch (ctl->info->type) { 435 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 436 ev.value.integer.value[id] = !!value; 437 break; 438 439 case SNDRV_CTL_ELEM_TYPE_INTEGER: 440 ev.value.integer.value[id] = value; 441 break; 442 443 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 444 ev.value.enumerated.item[id] = value; 445 break; 446 447 case SNDRV_CTL_ELEM_TYPE_BYTES: 448 ev.value.bytes.data[id] = value; 449 break; 450 451 default: 452 return -EINVAL; 453 } 454 455 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); 456 } 457 458 int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) 459 { 460 struct snd_ctl_elem_value ev; 461 size_t size; 462 void *dest; 463 size_t total_count; 464 465 if ((!ctl) || !count || !array) 466 return -EINVAL; 467 468 total_count = ctl->info->count; 469 470 if ((ctl->info->type == SNDRV_CTL_ELEM_TYPE_BYTES) && 471 mixer_ctl_is_access_tlv_rw(ctl)) { 472 /* Additional two words is for the TLV header */ 473 total_count += TLV_HEADER_SIZE; 474 } 475 476 if (count > total_count) 477 return -EINVAL; 478 479 memset(&ev, 0, sizeof(ev)); 480 ev.id.numid = ctl->info->id.numid; 481 482 switch (ctl->info->type) { 483 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 484 case SNDRV_CTL_ELEM_TYPE_INTEGER: 485 size = sizeof(ev.value.integer.value[0]); 486 dest = ev.value.integer.value; 487 break; 488 489 case SNDRV_CTL_ELEM_TYPE_BYTES: 490 /* check if this is new bytes TLV */ 491 if (mixer_ctl_is_access_tlv_rw(ctl)) { 492 struct snd_ctl_tlv *tlv; 493 int ret = 0; 494 if (count > SIZE_MAX - sizeof(*tlv)) 495 return -EINVAL; 496 tlv = calloc(1, sizeof(*tlv) + count); 497 if (!tlv) 498 return -ENOMEM; 499 tlv->numid = ctl->info->id.numid; 500 tlv->length = count; 501 memcpy(tlv->tlv, array, count); 502 503 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv); 504 free(tlv); 505 506 return ret; 507 } else { 508 size = sizeof(ev.value.bytes.data[0]); 509 dest = ev.value.bytes.data; 510 } 511 break; 512 513 case SNDRV_CTL_ELEM_TYPE_IEC958: 514 size = sizeof(ev.value.iec958); 515 dest = &ev.value.iec958; 516 break; 517 518 default: 519 return -EINVAL; 520 } 521 522 memcpy(dest, array, size * count); 523 524 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); 525 } 526 527 int mixer_ctl_get_range_min(struct mixer_ctl *ctl) 528 { 529 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) 530 return -EINVAL; 531 532 return ctl->info->value.integer.min; 533 } 534 535 int mixer_ctl_get_range_max(struct mixer_ctl *ctl) 536 { 537 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) 538 return -EINVAL; 539 540 return ctl->info->value.integer.max; 541 } 542 543 unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl) 544 { 545 if (!ctl) 546 return 0; 547 548 return ctl->info->value.enumerated.items; 549 } 550 551 const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, 552 unsigned int enum_id) 553 { 554 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) || 555 (enum_id >= ctl->info->value.enumerated.items)) 556 return NULL; 557 558 return (const char *)ctl->ename[enum_id]; 559 } 560 561 int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string) 562 { 563 unsigned int i, num_enums; 564 struct snd_ctl_elem_value ev; 565 int ret; 566 567 if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)) 568 return -EINVAL; 569 570 num_enums = ctl->info->value.enumerated.items; 571 for (i = 0; i < num_enums; i++) { 572 if (!strcmp(string, ctl->ename[i])) { 573 memset(&ev, 0, sizeof(ev)); 574 ev.value.enumerated.item[0] = i; 575 ev.id.numid = ctl->info->id.numid; 576 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); 577 if (ret < 0) 578 return ret; 579 return 0; 580 } 581 } 582 583 return -EINVAL; 584 } 585 586 /** Subscribes for the mixer events. 587 * @param mixer A mixer handle. 588 * @param subscribe value indicating subscribe or unsubscribe for events 589 * @returns On success, zero. 590 * On failure, non-zero. 591 * @ingroup libtinyalsa-mixer 592 */ 593 int mixer_subscribe_events(struct mixer *mixer, int subscribe) 594 { 595 if (ioctl(mixer->fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) { 596 return -1; 597 } 598 return 0; 599 } 600 601 /** Wait for mixer events. 602 * @param mixer A mixer handle. 603 * @param timeout timout value 604 * @returns On success, 1. 605 * On failure, -errno. 606 * On timeout, 0 607 * @ingroup libtinyalsa-mixer 608 */ 609 int mixer_wait_event(struct mixer *mixer, int timeout) 610 { 611 struct pollfd pfd; 612 613 pfd.fd = mixer->fd; 614 pfd.events = POLLIN | POLLOUT | POLLERR | POLLNVAL; 615 616 for (;;) { 617 int err; 618 err = poll(&pfd, 1, timeout); 619 if (err < 0) 620 return -errno; 621 if (!err) 622 return 0; 623 if (pfd.revents & (POLLERR | POLLNVAL)) 624 return -EIO; 625 if (pfd.revents & (POLLIN | POLLOUT)) 626 return 1; 627 } 628 } 629