1 /** 2 * \file mixer/mixer.c 3 * \brief Mixer Interface 4 * \author Jaroslav Kysela <perex (at) perex.cz> 5 * \author Abramo Bagnara <abramo (at) alsa-project.org> 6 * \date 2001 7 * 8 * Mixer interface is designed to access mixer elements. 9 * Callbacks may be used for event handling. 10 */ 11 /* 12 * Mixer Interface - main file 13 * Copyright (c) 1998/1999/2000 by Jaroslav Kysela <perex (at) perex.cz> 14 * Copyright (c) 2001 by Abramo Bagnara <abramo (at) alsa-project.org> 15 * 16 * 17 * This library is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU Lesser General Public License as 19 * published by the Free Software Foundation; either version 2.1 of 20 * the License, or (at your option) any later version. 21 * 22 * This program is distributed in the hope that it will be useful, 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * GNU Lesser General Public License for more details. 26 * 27 * You should have received a copy of the GNU Lesser General Public 28 * License along with this library; if not, write to the Free Software 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30 * 31 */ 32 33 /*! \page mixer Mixer interface 34 35 <P>Mixer interface is designed to access the abstracted mixer controls. 36 This is an abstraction layer over the hcontrol layer. 37 38 \section mixer_general_overview General overview 39 40 */ 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <string.h> 46 #include <fcntl.h> 47 #include <sys/ioctl.h> 48 #include "mixer_local.h" 49 50 #ifndef DOC_HIDDEN 51 typedef struct _snd_mixer_slave { 52 snd_hctl_t *hctl; 53 struct list_head list; 54 } snd_mixer_slave_t; 55 56 #endif 57 58 static int snd_mixer_compare_default(const snd_mixer_elem_t *c1, 59 const snd_mixer_elem_t *c2); 60 61 62 /** 63 * \brief Opens an empty mixer 64 * \param mixerp Returned mixer handle 65 * \param mode Open mode 66 * \return 0 on success otherwise a negative error code 67 */ 68 int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED) 69 { 70 snd_mixer_t *mixer; 71 assert(mixerp); 72 mixer = calloc(1, sizeof(*mixer)); 73 if (mixer == NULL) 74 return -ENOMEM; 75 INIT_LIST_HEAD(&mixer->slaves); 76 INIT_LIST_HEAD(&mixer->classes); 77 INIT_LIST_HEAD(&mixer->elems); 78 mixer->compare = snd_mixer_compare_default; 79 *mixerp = mixer; 80 return 0; 81 } 82 83 /** 84 * \brief Attach an HCTL element to a mixer element 85 * \param melem Mixer element 86 * \param helem HCTL element 87 * \return 0 on success otherwise a negative error code 88 * 89 * For use by mixer element class specific code. 90 */ 91 int snd_mixer_elem_attach(snd_mixer_elem_t *melem, 92 snd_hctl_elem_t *helem) 93 { 94 bag_t *bag = snd_hctl_elem_get_callback_private(helem); 95 int err; 96 err = bag_add(bag, melem); 97 if (err < 0) 98 return err; 99 return bag_add(&melem->helems, helem); 100 } 101 102 /** 103 * \brief Detach an HCTL element from a mixer element 104 * \param melem Mixer element 105 * \param helem HCTL element 106 * \return 0 on success otherwise a negative error code 107 * 108 * For use by mixer element class specific code. 109 */ 110 int snd_mixer_elem_detach(snd_mixer_elem_t *melem, 111 snd_hctl_elem_t *helem) 112 { 113 bag_t *bag = snd_hctl_elem_get_callback_private(helem); 114 int err; 115 err = bag_del(bag, melem); 116 assert(err >= 0); 117 err = bag_del(&melem->helems, helem); 118 assert(err >= 0); 119 return 0; 120 } 121 122 /** 123 * \brief Return true if a mixer element does not contain any HCTL elements 124 * \param melem Mixer element 125 * \return 0 if not empty, 1 if empty 126 * 127 * For use by mixer element class specific code. 128 */ 129 int snd_mixer_elem_empty(snd_mixer_elem_t *melem) 130 { 131 return bag_empty(&melem->helems); 132 } 133 134 static int hctl_elem_event_handler(snd_hctl_elem_t *helem, 135 unsigned int mask) 136 { 137 bag_t *bag = snd_hctl_elem_get_callback_private(helem); 138 if (mask == SND_CTL_EVENT_MASK_REMOVE) { 139 int res = 0; 140 int err; 141 bag_iterator_t i, n; 142 bag_for_each_safe(i, n, bag) { 143 snd_mixer_elem_t *melem = bag_iterator_entry(i); 144 snd_mixer_class_t *class = melem->class; 145 err = class->event(class, mask, helem, melem); 146 if (err < 0) 147 res = err; 148 } 149 assert(bag_empty(bag)); 150 bag_free(bag); 151 return res; 152 } 153 if (mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO)) { 154 int err = 0; 155 bag_iterator_t i, n; 156 bag_for_each_safe(i, n, bag) { 157 snd_mixer_elem_t *melem = bag_iterator_entry(i); 158 snd_mixer_class_t *class = melem->class; 159 err = class->event(class, mask, helem, melem); 160 if (err < 0) 161 return err; 162 } 163 } 164 return 0; 165 } 166 167 static int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask, 168 snd_hctl_elem_t *elem) 169 { 170 snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl); 171 int res = 0; 172 if (mask & SND_CTL_EVENT_MASK_ADD) { 173 struct list_head *pos; 174 bag_t *bag; 175 int err = bag_new(&bag); 176 if (err < 0) 177 return err; 178 snd_hctl_elem_set_callback(elem, hctl_elem_event_handler); 179 snd_hctl_elem_set_callback_private(elem, bag); 180 list_for_each(pos, &mixer->classes) { 181 snd_mixer_class_t *c; 182 c = list_entry(pos, snd_mixer_class_t, list); 183 err = c->event(c, mask, elem, NULL); 184 if (err < 0) 185 res = err; 186 } 187 } 188 return res; 189 } 190 191 192 /** 193 * \brief Attach an HCTL specified with the CTL device name to an opened mixer 194 * \param mixer Mixer handle 195 * \param name HCTL name (see #snd_hctl_open) 196 * \return 0 on success otherwise a negative error code 197 */ 198 int snd_mixer_attach(snd_mixer_t *mixer, const char *name) 199 { 200 snd_hctl_t *hctl; 201 int err; 202 203 err = snd_hctl_open(&hctl, name, 0); 204 if (err < 0) 205 return err; 206 err = snd_mixer_attach_hctl(mixer, hctl); 207 if (err < 0) { 208 snd_hctl_close(hctl); 209 return err; 210 } 211 return 0; 212 } 213 214 /** 215 * \brief Attach an HCTL to an opened mixer 216 * \param mixer Mixer handle 217 * \param hctl the HCTL to be attached 218 * \return 0 on success otherwise a negative error code 219 */ 220 int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) 221 { 222 snd_mixer_slave_t *slave; 223 int err; 224 225 assert(hctl); 226 slave = calloc(1, sizeof(*slave)); 227 if (slave == NULL) 228 return -ENOMEM; 229 err = snd_hctl_nonblock(hctl, 1); 230 if (err < 0) { 231 snd_hctl_close(hctl); 232 free(slave); 233 return err; 234 } 235 snd_hctl_set_callback(hctl, hctl_event_handler); 236 snd_hctl_set_callback_private(hctl, mixer); 237 slave->hctl = hctl; 238 list_add_tail(&slave->list, &mixer->slaves); 239 return 0; 240 } 241 242 /** 243 * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources 244 * \param mixer Mixer handle 245 * \param name HCTL previously attached 246 * \return 0 on success otherwise a negative error code 247 */ 248 int snd_mixer_detach(snd_mixer_t *mixer, const char *name) 249 { 250 struct list_head *pos; 251 list_for_each(pos, &mixer->slaves) { 252 snd_mixer_slave_t *s; 253 s = list_entry(pos, snd_mixer_slave_t, list); 254 if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { 255 snd_hctl_close(s->hctl); 256 list_del(pos); 257 free(s); 258 return 0; 259 } 260 } 261 return -ENOENT; 262 } 263 264 /** 265 * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources 266 * \param mixer Mixer handle 267 * \param hctl HCTL previously attached 268 * \return 0 on success otherwise a negative error code 269 * 270 * Note: The hctl handle is not closed! 271 */ 272 int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl) 273 { 274 struct list_head *pos; 275 list_for_each(pos, &mixer->slaves) { 276 snd_mixer_slave_t *s; 277 s = list_entry(pos, snd_mixer_slave_t, list); 278 if (hctl == s->hctl) { 279 list_del(pos); 280 free(s); 281 return 0; 282 } 283 } 284 return -ENOENT; 285 } 286 287 /** 288 * \brief Obtain a HCTL pointer associated to given name 289 * \param mixer Mixer handle 290 * \param name HCTL previously attached 291 * \param hctl HCTL pointer 292 * \return 0 on success otherwise a negative error code 293 */ 294 int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl) 295 { 296 struct list_head *pos; 297 list_for_each(pos, &mixer->slaves) { 298 snd_mixer_slave_t *s; 299 s = list_entry(pos, snd_mixer_slave_t, list); 300 if (strcmp(name, snd_hctl_name(s->hctl)) == 0) { 301 *hctl = s->hctl; 302 return 0; 303 } 304 } 305 return -ENOENT; 306 } 307 308 static int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask, 309 snd_mixer_elem_t *elem) 310 { 311 mixer->events++; 312 if (mixer->callback) 313 return mixer->callback(mixer, mask, elem); 314 return 0; 315 } 316 317 static int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask) 318 { 319 elem->class->mixer->events++; 320 if (elem->callback) 321 return elem->callback(elem, mask); 322 return 0; 323 } 324 325 static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir) 326 { 327 unsigned int l, u; 328 int c = 0; 329 int idx = -1; 330 assert(mixer && elem); 331 assert(mixer->compare); 332 l = 0; 333 u = mixer->count; 334 while (l < u) { 335 idx = (l + u) / 2; 336 c = mixer->compare(elem, mixer->pelems[idx]); 337 if (c < 0) 338 u = idx; 339 else if (c > 0) 340 l = idx + 1; 341 else 342 break; 343 } 344 *dir = c; 345 return idx; 346 } 347 348 /** 349 * \brief Get private data associated to give mixer element 350 * \param elem Mixer element 351 * \return private data 352 * 353 * For use by mixer element class specific code. 354 */ 355 void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem) 356 { 357 return elem->private_data; 358 } 359 360 /** 361 * \brief Allocate a new mixer element 362 * \param elem Returned mixer element 363 * \param type Mixer element type 364 * \param compare_weight Mixer element compare weight 365 * \param private_data Private data 366 * \param private_free Private data free callback 367 * \return 0 on success otherwise a negative error code 368 * 369 * For use by mixer element class specific code. 370 */ 371 int snd_mixer_elem_new(snd_mixer_elem_t **elem, 372 snd_mixer_elem_type_t type, 373 int compare_weight, 374 void *private_data, 375 void (*private_free)(snd_mixer_elem_t *elem)) 376 { 377 snd_mixer_elem_t *melem = calloc(1, sizeof(*melem)); 378 if (melem == NULL) 379 return -ENOMEM; 380 melem->type = type; 381 melem->compare_weight = compare_weight; 382 melem->private_data = private_data; 383 melem->private_free = private_free; 384 INIT_LIST_HEAD(&melem->helems); 385 *elem = melem; 386 return 0; 387 } 388 389 /** 390 * \brief Add an element for a registered mixer element class 391 * \param elem Mixer element 392 * \param class Mixer element class 393 * \return 0 on success otherwise a negative error code 394 * 395 * For use by mixer element class specific code. 396 */ 397 int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class) 398 { 399 int dir, idx; 400 snd_mixer_t *mixer = class->mixer; 401 elem->class = class; 402 403 if (mixer->count == mixer->alloc) { 404 snd_mixer_elem_t **m; 405 mixer->alloc += 32; 406 m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc); 407 if (!m) { 408 mixer->alloc -= 32; 409 return -ENOMEM; 410 } 411 mixer->pelems = m; 412 } 413 if (mixer->count == 0) { 414 list_add_tail(&elem->list, &mixer->elems); 415 mixer->pelems[0] = elem; 416 } else { 417 idx = _snd_mixer_find_elem(mixer, elem, &dir); 418 assert(dir != 0); 419 if (dir > 0) { 420 list_add(&elem->list, &mixer->pelems[idx]->list); 421 idx++; 422 } else { 423 list_add_tail(&elem->list, &mixer->pelems[idx]->list); 424 } 425 memmove(mixer->pelems + idx + 1, 426 mixer->pelems + idx, 427 (mixer->count - idx) * sizeof(snd_mixer_elem_t *)); 428 mixer->pelems[idx] = elem; 429 } 430 mixer->count++; 431 return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem); 432 } 433 434 /** 435 * \brief Remove a mixer element 436 * \param elem Mixer element 437 * \return 0 on success otherwise a negative error code 438 * 439 * For use by mixer element class specific code. 440 */ 441 int snd_mixer_elem_remove(snd_mixer_elem_t *elem) 442 { 443 snd_mixer_t *mixer = elem->class->mixer; 444 bag_iterator_t i, n; 445 int err, idx, dir; 446 unsigned int m; 447 assert(elem); 448 assert(mixer->count); 449 idx = _snd_mixer_find_elem(mixer, elem, &dir); 450 if (dir != 0) 451 return -EINVAL; 452 bag_for_each_safe(i, n, &elem->helems) { 453 snd_hctl_elem_t *helem = bag_iterator_entry(i); 454 snd_mixer_elem_detach(elem, helem); 455 } 456 err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE); 457 list_del(&elem->list); 458 snd_mixer_elem_free(elem); 459 mixer->count--; 460 m = mixer->count - idx; 461 if (m > 0) 462 memmove(mixer->pelems + idx, 463 mixer->pelems + idx + 1, 464 m * sizeof(snd_mixer_elem_t *)); 465 return err; 466 } 467 468 /** 469 * \brief Free a mixer element 470 * \param elem Mixer element 471 * \return 0 on success otherwise a negative error code 472 * 473 * For use by mixer element class specific code. 474 */ 475 void snd_mixer_elem_free(snd_mixer_elem_t *elem) 476 { 477 if (elem->private_free) 478 elem->private_free(elem); 479 free(elem); 480 } 481 482 /** 483 * \brief Mixer element informations are changed 484 * \param elem Mixer element 485 * \return 0 on success otherwise a negative error code 486 * 487 * For use by mixer element class specific code. 488 */ 489 int snd_mixer_elem_info(snd_mixer_elem_t *elem) 490 { 491 return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO); 492 } 493 494 /** 495 * \brief Mixer element values is changed 496 * \param elem Mixer element 497 * \return 0 on success otherwise a negative error code 498 * 499 * For use by mixer element class specific code. 500 */ 501 int snd_mixer_elem_value(snd_mixer_elem_t *elem) 502 { 503 return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE); 504 } 505 506 /** 507 * \brief Register mixer element class 508 * \param class Mixer element class 509 * \param mixer Mixer handle 510 * \return 0 on success otherwise a negative error code 511 * 512 * For use by mixer element class specific code. 513 */ 514 int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer) 515 { 516 struct list_head *pos; 517 class->mixer = mixer; 518 list_add_tail(&class->list, &mixer->classes); 519 if (!class->event) 520 return 0; 521 list_for_each(pos, &mixer->slaves) { 522 int err; 523 snd_mixer_slave_t *slave; 524 snd_hctl_elem_t *elem; 525 slave = list_entry(pos, snd_mixer_slave_t, list); 526 elem = snd_hctl_first_elem(slave->hctl); 527 while (elem) { 528 err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL); 529 if (err < 0) 530 return err; 531 elem = snd_hctl_elem_next(elem); 532 } 533 } 534 return 0; 535 } 536 537 /** 538 * \brief Unregister mixer element class and remove all its elements 539 * \param class Mixer element class 540 * \return 0 on success otherwise a negative error code 541 * 542 * Note that the class structure is also deallocated! 543 */ 544 int snd_mixer_class_unregister(snd_mixer_class_t *class) 545 { 546 unsigned int k; 547 snd_mixer_elem_t *e; 548 snd_mixer_t *mixer = class->mixer; 549 for (k = mixer->count; k > 0; k--) { 550 e = mixer->pelems[k-1]; 551 if (e->class == class) 552 snd_mixer_elem_remove(e); 553 } 554 if (class->private_free) 555 class->private_free(class); 556 list_del(&class->list); 557 free(class); 558 return 0; 559 } 560 561 /** 562 * \brief Load a mixer elements 563 * \param mixer Mixer handle 564 * \return 0 on success otherwise a negative error code 565 */ 566 int snd_mixer_load(snd_mixer_t *mixer) 567 { 568 struct list_head *pos; 569 list_for_each(pos, &mixer->slaves) { 570 int err; 571 snd_mixer_slave_t *s; 572 s = list_entry(pos, snd_mixer_slave_t, list); 573 err = snd_hctl_load(s->hctl); 574 if (err < 0) 575 return err; 576 } 577 return 0; 578 } 579 580 /** 581 * \brief Unload all mixer elements and free all related resources 582 * \param mixer Mixer handle 583 */ 584 void snd_mixer_free(snd_mixer_t *mixer) 585 { 586 struct list_head *pos; 587 list_for_each(pos, &mixer->slaves) { 588 snd_mixer_slave_t *s; 589 s = list_entry(pos, snd_mixer_slave_t, list); 590 snd_hctl_free(s->hctl); 591 } 592 } 593 594 /** 595 * \brief Close a mixer and free all related resources 596 * \param mixer Mixer handle 597 * \return 0 on success otherwise a negative error code 598 */ 599 int snd_mixer_close(snd_mixer_t *mixer) 600 { 601 int res = 0; 602 assert(mixer); 603 while (!list_empty(&mixer->classes)) { 604 snd_mixer_class_t *c; 605 c = list_entry(mixer->classes.next, snd_mixer_class_t, list); 606 snd_mixer_class_unregister(c); 607 } 608 assert(list_empty(&mixer->elems)); 609 assert(mixer->count == 0); 610 free(mixer->pelems); 611 mixer->pelems = NULL; 612 while (!list_empty(&mixer->slaves)) { 613 int err; 614 snd_mixer_slave_t *s; 615 s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list); 616 err = snd_hctl_close(s->hctl); 617 if (err < 0) 618 res = err; 619 list_del(&s->list); 620 free(s); 621 } 622 free(mixer); 623 return res; 624 } 625 626 static int snd_mixer_compare_default(const snd_mixer_elem_t *c1, 627 const snd_mixer_elem_t *c2) 628 { 629 int d = c1->compare_weight - c2->compare_weight; 630 if (d) 631 return d; 632 assert(c1->class && c1->class->compare); 633 assert(c2->class && c2->class->compare); 634 assert(c1->class == c2->class); 635 return c1->class->compare(c1, c2); 636 } 637 638 static int mixer_compare(const void *a, const void *b) 639 { 640 snd_mixer_t *mixer; 641 642 mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer; 643 return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b); 644 } 645 646 static int snd_mixer_sort(snd_mixer_t *mixer) 647 { 648 unsigned int k; 649 assert(mixer); 650 assert(mixer->compare); 651 INIT_LIST_HEAD(&mixer->elems); 652 qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare); 653 for (k = 0; k < mixer->count; k++) 654 list_add_tail(&mixer->pelems[k]->list, &mixer->elems); 655 return 0; 656 } 657 658 /** 659 * \brief Change mixer compare function and reorder elements 660 * \param mixer Mixer handle 661 * \param compare Element compare function 662 * \return 0 on success otherwise a negative error code 663 */ 664 int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare) 665 { 666 snd_mixer_compare_t compare_old; 667 int err; 668 669 assert(mixer); 670 compare_old = mixer->compare; 671 mixer->compare = compare == NULL ? snd_mixer_compare_default : compare; 672 if ((err = snd_mixer_sort(mixer)) < 0) { 673 mixer->compare = compare_old; 674 return err; 675 } 676 return 0; 677 } 678 679 /** 680 * \brief get count of poll descriptors for mixer handle 681 * \param mixer Mixer handle 682 * \return count of poll descriptors 683 */ 684 int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer) 685 { 686 struct list_head *pos; 687 unsigned int c = 0; 688 assert(mixer); 689 list_for_each(pos, &mixer->slaves) { 690 snd_mixer_slave_t *s; 691 int n; 692 s = list_entry(pos, snd_mixer_slave_t, list); 693 n = snd_hctl_poll_descriptors_count(s->hctl); 694 if (n < 0) 695 return n; 696 c += n; 697 } 698 return c; 699 } 700 701 /** 702 * \brief get poll descriptors 703 * \param mixer Mixer handle 704 * \param pfds array of poll descriptors 705 * \param space space in the poll descriptor array 706 * \return count of filled descriptors 707 */ 708 int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space) 709 { 710 struct list_head *pos; 711 unsigned int count = 0; 712 assert(mixer); 713 list_for_each(pos, &mixer->slaves) { 714 snd_mixer_slave_t *s; 715 int n; 716 s = list_entry(pos, snd_mixer_slave_t, list); 717 n = snd_hctl_poll_descriptors(s->hctl, pfds, space); 718 if (n < 0) 719 return n; 720 if (space >= (unsigned int) n) { 721 count += n; 722 space -= n; 723 pfds += n; 724 } else 725 space = 0; 726 } 727 return count; 728 } 729 730 /** 731 * \brief get returned events from poll descriptors 732 * \param mixer Mixer handle 733 * \param pfds array of poll descriptors 734 * \param nfds count of poll descriptors 735 * \param revents returned events 736 * \return zero if success, otherwise a negative error code 737 */ 738 int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 739 { 740 unsigned int idx; 741 unsigned short res; 742 assert(mixer && pfds && revents); 743 if (nfds == 0) 744 return -EINVAL; 745 res = 0; 746 for (idx = 0; idx < nfds; idx++) 747 res |= pfds->revents & (POLLIN|POLLERR|POLLNVAL); 748 *revents = res; 749 return 0; 750 } 751 752 /** 753 * \brief Wait for a mixer to become ready (i.e. at least one event pending) 754 * \param mixer Mixer handle 755 * \param timeout maximum time in milliseconds to wait 756 * \return 0 otherwise a negative error code on failure 757 */ 758 int snd_mixer_wait(snd_mixer_t *mixer, int timeout) 759 { 760 struct pollfd spfds[16]; 761 struct pollfd *pfds = spfds; 762 int err; 763 int count; 764 count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0])); 765 if (count < 0) 766 return count; 767 if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) { 768 pfds = malloc(count * sizeof(*pfds)); 769 if (!pfds) 770 return -ENOMEM; 771 err = snd_mixer_poll_descriptors(mixer, pfds, 772 (unsigned int) count); 773 assert(err == count); 774 } 775 err = poll(pfds, (unsigned int) count, timeout); 776 if (err < 0) 777 return -errno; 778 return 0; 779 } 780 781 /** 782 * \brief get first element for a mixer 783 * \param mixer Mixer handle 784 * \return pointer to first element 785 */ 786 snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer) 787 { 788 assert(mixer); 789 if (list_empty(&mixer->elems)) 790 return NULL; 791 return list_entry(mixer->elems.next, snd_mixer_elem_t, list); 792 } 793 794 /** 795 * \brief get last element for a mixer 796 * \param mixer Mixer handle 797 * \return pointer to last element 798 */ 799 snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer) 800 { 801 assert(mixer); 802 if (list_empty(&mixer->elems)) 803 return NULL; 804 return list_entry(mixer->elems.prev, snd_mixer_elem_t, list); 805 } 806 807 /** 808 * \brief get next mixer element 809 * \param elem mixer element 810 * \return pointer to next element 811 */ 812 snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem) 813 { 814 assert(elem); 815 if (elem->list.next == &elem->class->mixer->elems) 816 return NULL; 817 return list_entry(elem->list.next, snd_mixer_elem_t, list); 818 } 819 820 /** 821 * \brief get previous mixer element 822 * \param elem mixer element 823 * \return pointer to previous element 824 */ 825 snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem) 826 { 827 assert(elem); 828 if (elem->list.prev == &elem->class->mixer->elems) 829 return NULL; 830 return list_entry(elem->list.prev, snd_mixer_elem_t, list); 831 } 832 833 /** 834 * \brief Handle pending mixer events invoking callbacks 835 * \param mixer Mixer handle 836 * \return Number of events that occured on success, otherwise a negative error code on failure 837 */ 838 int snd_mixer_handle_events(snd_mixer_t *mixer) 839 { 840 struct list_head *pos; 841 assert(mixer); 842 mixer->events = 0; 843 list_for_each(pos, &mixer->slaves) { 844 int err; 845 snd_mixer_slave_t *s; 846 s = list_entry(pos, snd_mixer_slave_t, list); 847 err = snd_hctl_handle_events(s->hctl); 848 if (err < 0) 849 return err; 850 } 851 return mixer->events; 852 } 853 854 /** 855 * \brief Set callback function for a mixer 856 * \param obj mixer handle 857 * \param val callback function 858 */ 859 void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val) 860 { 861 assert(obj); 862 obj->callback = val; 863 } 864 865 /** 866 * \brief Set callback private value for a mixer 867 * \param mixer mixer handle 868 * \param val callback private value 869 */ 870 void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val) 871 { 872 assert(mixer); 873 mixer->callback_private = val; 874 } 875 876 /** 877 * \brief Get callback private value for a mixer 878 * \param mixer mixer handle 879 * \return callback private value 880 */ 881 void * snd_mixer_get_callback_private(const snd_mixer_t *mixer) 882 { 883 assert(mixer); 884 return mixer->callback_private; 885 } 886 887 /** 888 * \brief Get elements count for a mixer 889 * \param mixer mixer handle 890 * \return elements count 891 */ 892 unsigned int snd_mixer_get_count(const snd_mixer_t *mixer) 893 { 894 assert(mixer); 895 return mixer->count; 896 } 897 898 /** 899 * \brief Set callback function for a mixer element 900 * \param mixer mixer element 901 * \param val callback function 902 */ 903 void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val) 904 { 905 assert(mixer); 906 mixer->callback = val; 907 } 908 909 /** 910 * \brief Set callback private value for a mixer element 911 * \param mixer mixer element 912 * \param val callback private value 913 */ 914 void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val) 915 { 916 assert(mixer); 917 mixer->callback_private = val; 918 } 919 920 /** 921 * \brief Get callback private value for a mixer element 922 * \param mixer mixer element 923 * \return callback private value 924 */ 925 void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer) 926 { 927 assert(mixer); 928 return mixer->callback_private; 929 } 930 931 /** 932 * \brief Get type for a mixer element 933 * \param mixer mixer element 934 * \return mixer element type 935 */ 936 snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer) 937 { 938 assert(mixer); 939 return mixer->type; 940 } 941 942 943 /** 944 * \brief get size of #snd_mixer_class_t 945 * \return size in bytes 946 */ 947 size_t snd_mixer_class_sizeof() 948 { 949 return sizeof(snd_mixer_class_t); 950 } 951 952 /** 953 * \brief allocate an invalid #snd_mixer_class_t using standard malloc 954 * \param ptr returned pointer 955 * \return 0 on success otherwise negative error code 956 */ 957 int snd_mixer_class_malloc(snd_mixer_class_t **ptr) 958 { 959 assert(ptr); 960 *ptr = calloc(1, sizeof(snd_mixer_class_t)); 961 if (!*ptr) 962 return -ENOMEM; 963 return 0; 964 } 965 966 /** 967 * \brief frees a previously allocated #snd_mixer_class_t 968 * \param obj pointer to object to free 969 */ 970 void snd_mixer_class_free(snd_mixer_class_t *obj) 971 { 972 if (obj->private_free) 973 obj->private_free(obj); 974 free(obj); 975 } 976 977 /** 978 * \brief copy one #snd_mixer_class_t to another 979 * \param dst pointer to destination 980 * \param src pointer to source 981 */ 982 void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src) 983 { 984 assert(dst && src); 985 *dst = *src; 986 } 987 988 /** 989 * \brief Get a mixer associated to given mixer class 990 * \param obj Mixer simple class identifier 991 * \return mixer pointer 992 */ 993 snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj) 994 { 995 assert(obj); 996 return obj->mixer; 997 } 998 999 /** 1000 * \brief Get mixer event callback associated to given mixer class 1001 * \param obj Mixer simple class identifier 1002 * \return event callback pointer 1003 */ 1004 snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj) 1005 { 1006 assert(obj); 1007 return obj->event; 1008 } 1009 1010 /** 1011 * \brief Get mixer private data associated to given mixer class 1012 * \param obj Mixer simple class identifier 1013 * \return event callback pointer 1014 */ 1015 void *snd_mixer_class_get_private(const snd_mixer_class_t *obj) 1016 { 1017 assert(obj); 1018 return obj->private_data; 1019 } 1020 1021 1022 /** 1023 * \brief Get mixer compare callback associated to given mixer class 1024 * \param obj Mixer simple class identifier 1025 * \return event callback pointer 1026 */ 1027 snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj) 1028 { 1029 assert(obj); 1030 return obj->compare; 1031 } 1032 1033 /** 1034 * \brief Set mixer event callback to given mixer class 1035 * \param obj Mixer simple class identifier 1036 * \param event Event callback 1037 * \return zero if success, otherwise a negative error code 1038 */ 1039 int snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event) 1040 { 1041 assert(obj); 1042 obj->event = event; 1043 return 0; 1044 } 1045 1046 /** 1047 * \brief Set mixer private data to given mixer class 1048 * \param obj Mixer simple class identifier 1049 * \param private_data class private data 1050 * \return zero if success, otherwise a negative error code 1051 */ 1052 int snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data) 1053 { 1054 assert(obj); 1055 obj->private_data = private_data; 1056 return 0; 1057 } 1058 1059 /** 1060 * \brief Set mixer private data free callback to given mixer class 1061 * \param obj Mixer simple class identifier 1062 * \param private_free Mixer class private data free callback 1063 * \return zero if success, otherwise a negative error code 1064 */ 1065 int snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *class)) 1066 { 1067 assert(obj); 1068 obj->private_free = private_free; 1069 return 0; 1070 } 1071 1072 /** 1073 * \brief Set mixer compare callback to given mixer class 1074 * \param obj Mixer simple class identifier 1075 * \param compare the compare callback to be used 1076 * \return zero if success, otherwise a negative error code 1077 */ 1078 int snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare) 1079 { 1080 assert(obj); 1081 obj->compare = compare; 1082 return 0; 1083 } 1084