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