Home | History | Annotate | Download | only in mixer
      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