diff options
-rw-r--r-- | include/control.h | 37 | ||||
-rw-r--r-- | src/control/Makefile.am | 2 | ||||
-rw-r--r-- | src/control/control.c | 6 | ||||
-rw-r--r-- | src/control/control_local.h | 34 | ||||
-rw-r--r-- | src/control/controls.c | 339 | ||||
-rw-r--r-- | src/mixer/mixer.c | 14 | ||||
-rw-r--r-- | src/mixer/mixer_local.h | 25 | ||||
-rw-r--r-- | src/mixer/simple.c | 605 |
8 files changed, 791 insertions, 271 deletions
diff --git a/include/control.h b/include/control.h index b1718211..c30a3ce5 100644 --- a/include/control.h +++ b/include/control.h @@ -50,6 +50,43 @@ int snd_ctl_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info); int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks); +/* + * Highlevel API for controls + */ + +typedef struct snd_hcontrol_stru snd_hcontrol_t; + +struct snd_hcontrol_stru { + snd_control_id_t id; + int change: 1, /* structure change */ + value: 1; /* value change */ + /* event callbacks */ + void (*event_change)(snd_ctl_t *handle, snd_hcontrol_t *hcontrol); + void (*event_value)(snd_ctl_t *handle, snd_hcontrol_t *hcontrol); + void (*event_remove)(snd_ctl_t *handle, snd_hcontrol_t *hcontrol); + /* private data */ + void *private_data; + void (*private_free)(void *private_data); + /* links */ + snd_hcontrol_t *prev; + snd_hcontrol_t *next; +}; + +typedef int (snd_ctl_csort_t)(const snd_hcontrol_t **c1, const snd_hcontrol_t **c2); +typedef int (snd_ctl_ccallback_rebuild_t)(snd_ctl_t *handle, void *private_data); +typedef int (snd_ctl_ccallback_add_t)(snd_ctl_t *handle, void *private_data, snd_hcontrol_t *hcontrol); + +int snd_ctl_cbuild(snd_ctl_t *handle, snd_ctl_csort_t *csort); +int snd_ctl_cfree(snd_ctl_t *handle); +snd_hcontrol_t *snd_ctl_cfirst(snd_ctl_t *handle); +snd_hcontrol_t *snd_ctl_clast(snd_ctl_t *handle); +snd_hcontrol_t *snd_ctl_cfind(snd_ctl_t *handle, snd_control_id_t *id); +int snd_ctl_csort(const snd_hcontrol_t **c1, const snd_hcontrol_t **c2); +int snd_ctl_cresort(snd_ctl_t *handle, snd_ctl_csort_t *csort); +int snd_ctl_ccallback_rebuild(snd_ctl_t *handle, snd_ctl_ccallback_rebuild_t *callback, void *private_data); +int snd_ctl_ccallback_add(snd_ctl_t *handle, snd_ctl_ccallback_add_t *callback, void *private_data); +int snd_ctl_cevent(snd_ctl_t *handle); + #ifdef __cplusplus } #endif diff --git a/src/control/Makefile.am b/src/control/Makefile.am index 34712264..22002c4a 100644 --- a/src/control/Makefile.am +++ b/src/control/Makefile.am @@ -1,6 +1,6 @@ EXTRA_LTLIBRARIES = libcontrol.la -libcontrol_la_SOURCES = cards.c control.c defaults.c +libcontrol_la_SOURCES = cards.c control.c controls.c defaults.c all: libcontrol.la diff --git a/src/control/control.c b/src/control/control.c index 70409de3..9a14c3d9 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -28,15 +28,11 @@ #include <sys/ioctl.h> #include <assert.h> #include "asoundlib.h" +#include "control_local.h" #define SND_FILE_CONTROL "/dev/snd/controlC%i" #define SND_CTL_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0) -struct snd_ctl { - int card; - int fd; -}; - int snd_ctl_open(snd_ctl_t **handle, int card) { int fd, ver; diff --git a/src/control/control_local.h b/src/control/control_local.h new file mode 100644 index 00000000..45d0ad6c --- /dev/null +++ b/src/control/control_local.h @@ -0,0 +1,34 @@ +/* + * Control Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz> + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +struct snd_ctl { + int card; + int fd; + int ccount; + int cerr; + snd_hcontrol_t *cfirst; + snd_hcontrol_t *clast; + snd_ctl_csort_t *csort; + snd_ctl_ccallback_rebuild_t *callback_rebuild; + void *callback_rebuild_private_data; + snd_ctl_ccallback_add_t *callback_add; + void *callback_add_private_data; +}; diff --git a/src/control/controls.c b/src/control/controls.c new file mode 100644 index 00000000..1871fffb --- /dev/null +++ b/src/control/controls.c @@ -0,0 +1,339 @@ +/* + * Control Interface - highlevel API + * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz> + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <assert.h> +#include "asoundlib.h" +#include "control_local.h" + +static void snd_ctl_link_after(snd_ctl_t *handle, snd_hcontrol_t *point, snd_hcontrol_t *hcontrol); + +int snd_ctl_cbuild(snd_ctl_t *handle, snd_ctl_csort_t *csort) +{ + snd_control_list_t list; + snd_hcontrol_t *hcontrol, *prev; + int err, idx; + + assert(handle != NULL); + if ((err = snd_ctl_cfree(handle)) < 0) + return err; + __rebuild: + memset(&list, 0, sizeof(list)); + do { + if (list.pids != NULL) + free(list.pids); + list.controls_offset = 0; + list.controls_request = 0; + list.controls_count = 0; + if ((err = snd_ctl_clist(handle, &list)) < 0) + return err; + if (list.controls == 0) + break; + list.pids = (snd_control_id_t *)calloc(list.controls, sizeof(snd_control_id_t)); + if (list.pids == NULL) + return -ENOMEM; + list.controls_request = list.controls; + if ((err = snd_ctl_clist(handle, &list)) < 0) + return err; + } while (list.controls != list.controls_count); + for (idx = 0, prev = NULL; idx < list.controls_count; idx++) { + hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t)); + if (hcontrol == NULL) { + snd_ctl_cfree(handle); + free(list.pids); + return -ENOMEM; + } + hcontrol->id = list.pids[idx]; + if (prev == NULL) { + handle->cfirst = handle->clast = hcontrol; + handle->ccount = 1; + } else { + snd_ctl_link_after(handle, prev, hcontrol); + } + prev = hcontrol; + } + if (list.pids != NULL) + free(list.pids); + if (csort != NULL && (err = snd_ctl_cresort(handle, csort)) < 0) + return err; + return 0; +} + +snd_hcontrol_t *snd_ctl_cfirst(snd_ctl_t *handle) +{ + assert(handle != NULL); + return handle->cfirst; +} + +snd_hcontrol_t *snd_ctl_clast(snd_ctl_t *handle) +{ + assert(handle != NULL); + return handle->clast; +} + +static void snd_ctl_unlink(snd_ctl_t *handle, snd_hcontrol_t *hcontrol) +{ + if (handle->cfirst == hcontrol) + handle->cfirst = hcontrol->next; + if (handle->clast == hcontrol) + handle->clast = hcontrol->prev; + if (hcontrol->prev != NULL) + hcontrol->prev->next = hcontrol->next; + if (hcontrol->next != NULL) + hcontrol->next->prev = hcontrol->prev; + hcontrol->prev = hcontrol->next = NULL; + handle->ccount--; +} + +static void snd_ctl_link_before(snd_ctl_t *handle, snd_hcontrol_t *point, snd_hcontrol_t *hcontrol) +{ + if (point == handle->cfirst) + handle->cfirst = hcontrol; + hcontrol->next = point; + hcontrol->prev = point->prev; + if (point->prev != NULL) + point->prev->next = hcontrol; + point->prev = hcontrol; + handle->ccount++; +} + +static void snd_ctl_link_after(snd_ctl_t *handle, snd_hcontrol_t *point, snd_hcontrol_t *hcontrol) +{ + if (point == handle->clast) + handle->clast = hcontrol; + hcontrol->prev = point; + hcontrol->next = point->next; + if (point->next != NULL) + point->next->prev = hcontrol; + point->next = hcontrol; + handle->ccount++; +} + +static void snd_ctl_cfree1(snd_ctl_t *handle, snd_hcontrol_t *hcontrol) +{ + snd_ctl_unlink(handle, hcontrol); + if (hcontrol->event_remove) + hcontrol->event_remove(handle, hcontrol); + if (hcontrol->private_free) + hcontrol->private_free(hcontrol->private_data); + free(hcontrol); +} + +int snd_ctl_cfree(snd_ctl_t *handle) +{ + handle->csort = NULL; + while (handle->cfirst) + snd_ctl_cfree1(handle, handle->cfirst); + assert(handle->ccount == 0); +} + +int snd_ctl_csort(const snd_hcontrol_t **_c1, const snd_hcontrol_t **_c2) +{ + const snd_hcontrol_t *c1 = *_c1; + const snd_hcontrol_t *c2 = *_c2; + int res; + + res = strcmp(c1->id.name, c2->id.name); + if (res == 0) { + if (c1->id.index < c2->id.index) + return -1; + if (c1->id.index > c2->id.index) + return 1; + return 0; + } +} + +int snd_ctl_cresort(snd_ctl_t *handle, snd_ctl_csort_t *csort) +{ + int idx, count; + snd_hcontrol_t **pmap, *hcontrol; + + assert(handle != NULL && csort != NULL); + if (handle->ccount == 0) + return 0; + pmap = (snd_hcontrol_t **)calloc(handle->ccount, sizeof(snd_hcontrol_t *)); + if (pmap == NULL) + return -ENOMEM; + for (hcontrol = handle->cfirst, idx = 0; hcontrol != NULL; hcontrol = hcontrol->next, idx++) { + printf("idx = %i, hcontrol = 0x%x (0x%x), '%s'\n", idx, (int)hcontrol, (int)&pmap[idx], hcontrol->id.name); + pmap[idx] = hcontrol; + } + assert(idx == handle->ccount); + handle->csort = csort; + qsort(pmap, count = handle->ccount, sizeof(snd_hcontrol_t *), (int (*)(const void *, const void *))csort); + while (handle->cfirst) + snd_ctl_unlink(handle, handle->cfirst); + handle->cfirst = handle->clast = pmap[0]; handle->ccount = 1; + for (idx = 1; idx < count; idx++) + snd_ctl_link_after(handle, pmap[idx-1], pmap[idx]); + free(pmap); + return 0; +} + +snd_hcontrol_t *snd_ctl_cfind(snd_ctl_t *handle, snd_control_id_t *id) +{ + snd_hcontrol_t *hcontrol; + + assert(handle != NULL); + for (hcontrol = handle->cfirst; hcontrol != NULL; hcontrol = hcontrol->next) { + if (hcontrol->id.iface != id->iface) + continue; + if (hcontrol->id.device != id->device) + continue; + if (hcontrol->id.subdevice != id->subdevice) + continue; + if (strncmp(hcontrol->id.name, id->name, sizeof(hcontrol->id.name))) + continue; + if (hcontrol->id.index != id->index) + continue; + return hcontrol; + } + return NULL; +} + +int snd_ctl_ccallback_rebuild(snd_ctl_t *handle, snd_ctl_ccallback_rebuild_t *callback, void *private_data) +{ + assert(handle != NULL); + handle->callback_rebuild = callback; + handle->callback_rebuild_private_data = private_data; +} + +int snd_ctl_ccallback_add(snd_ctl_t *handle, snd_ctl_ccallback_add_t *callback, void *private_data) +{ + assert(handle != NULL); + handle->callback_add = callback; + handle->callback_add_private_data = private_data; +} + +static void callback_rebuild(snd_ctl_t *handle, void *private_data) +{ + handle->cerr = snd_ctl_cbuild(handle, handle->csort); + if (handle->cerr >= 0 && handle->callback_rebuild) + handle->callback_rebuild(handle, handle->callback_rebuild_private_data); +} + +static void callback_change(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) +{ + snd_hcontrol_t *hcontrol; + + if (handle->cerr < 0) + return; + hcontrol = snd_ctl_cfind(handle, id); + if (hcontrol == NULL) { + handle->cerr = -ENOENT; + return; + } + hcontrol->change = 1; +} + +static void callback_value(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) +{ + snd_hcontrol_t *hcontrol; + + if (handle->cerr < 0) + return; + hcontrol = snd_ctl_cfind(handle, id); + if (hcontrol == NULL) { + handle->cerr = -ENOENT; + return; + } + hcontrol->value = 1; +} + +static void callback_add(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) +{ + snd_hcontrol_t *hcontrol, *icontrol; + + if (handle->cerr < 0) + return; + hcontrol = (snd_hcontrol_t *)calloc(1, sizeof(snd_hcontrol_t)); + if (hcontrol == NULL) { + handle->cerr = -ENOMEM; + return; + } + hcontrol->id = *id; + if (handle->csort != NULL) { + for (icontrol = handle->cfirst; icontrol != NULL; icontrol = icontrol->next) { + if (handle->csort((const snd_hcontrol_t **)&icontrol, (const snd_hcontrol_t **)&hcontrol) > 0) { + snd_ctl_link_before(handle, icontrol, hcontrol); + break; + } + } + if (icontrol == NULL) + snd_ctl_link_after(handle, handle->clast, hcontrol); + } else { + snd_ctl_link_after(handle, handle->clast, hcontrol); + } + if (handle->callback_add) + handle->callback_add(handle, handle->callback_add_private_data, hcontrol); +} + +static void callback_remove(snd_ctl_t *handle, void *private_data, snd_control_id_t *id) +{ + snd_hcontrol_t *hcontrol; + + if (handle->cerr < 0) + return; + hcontrol = snd_ctl_cfind(handle, id); + if (hcontrol == NULL) { + handle->cerr = -ENOENT; + return; + } + snd_ctl_cfree1(handle, hcontrol); +} + +int snd_ctl_cevent(snd_ctl_t *handle) +{ + snd_ctl_callbacks_t callbacks = { + rebuild: callback_rebuild, + value: callback_value, + change: callback_change, + add: callback_add, + remove: callback_remove + }; + snd_hcontrol_t *hcontrol; + int res; + + assert(handle != NULL); + handle->cerr = 0; + res = snd_ctl_read(handle, &callbacks); + if (res < 0) + return res; + if (handle->cerr < 0) + return handle->cerr; + for (hcontrol = handle->cfirst; hcontrol != NULL; hcontrol = hcontrol->next) { + if (hcontrol->change && hcontrol->event_change) { + hcontrol->event_change(handle, hcontrol); + hcontrol->change = 0; + } + if (hcontrol->value && hcontrol->event_value) { + hcontrol->event_value(handle, hcontrol); + hcontrol->value = 0; + } + } + return res; +} diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 83b048e8..d28f9cf4 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -103,11 +103,10 @@ int snd_mixer_simple_control_list(snd_mixer_t *handle, snd_mixer_simple_control_ for (s = handle->simple_first; s != NULL && tmp > 0; s = s->next); tmp = list->controls_request; p = list->pids; - printf("request = %i\n", tmp); if (tmp > 0 && p == NULL) return -EINVAL; for (; s != NULL && tmp > 0; s = s->next, tmp--, p++, list->controls_count++) - memcpy(p, &s->id, sizeof(*p)); + memcpy(p, &s->sid, sizeof(*p)); list->controls = handle->simple_count; return 0; } @@ -117,7 +116,7 @@ static mixer_simple_t *look_for_simple(snd_mixer_t *handle, snd_mixer_sid_t *sid mixer_simple_t *s; for (s = handle->simple_first; s != NULL; s = s->next) - if (!strcmp(s->id.name, sid->name) && s->id.index == sid->index) + if (!strcmp(s->sid.name, sid->name) && s->sid.index == sid->index) return s; return NULL; } @@ -214,16 +213,9 @@ int snd_mixer_simple_read(snd_mixer_t *handle, snd_mixer_simple_callbacks_t *cal return -EINVAL; if (!handle->simple_valid) snd_mixer_simple_build(handle); - memset(&xcallbacks, 0, sizeof(xcallbacks)); - xcallbacks.private_data = handle; - xcallbacks.rebuild = snd_mixer_simple_read_rebuild; - xcallbacks.value = snd_mixer_simple_read_value; - xcallbacks.change = snd_mixer_simple_read_change; - xcallbacks.add = snd_mixer_simple_read_add; - xcallbacks.remove = snd_mixer_simple_read_remove; handle->callbacks = callbacks; handle->simple_changes = 0; - if ((err = snd_ctl_read(handle->ctl_handle, &xcallbacks)) <= 0) { + if ((err = snd_ctl_cevent(handle->ctl_handle)) <= 0) { handle->callbacks = NULL; return err; } diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h index dfb67b30..e37ba575 100644 --- a/src/mixer/mixer_local.h +++ b/src/mixer/mixer_local.h @@ -28,10 +28,33 @@ typedef int (mixer_simple_get_t) (snd_mixer_t *handle, mixer_simple_t *simple, s typedef int (mixer_simple_put_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control); typedef int (mixer_simple_event_t) (snd_mixer_t *handle, snd_ctl_event_type_t etype, snd_control_id_t *id); +#define MIXER_PRESENT_GLOBAL_SWITCH (1<<0) +#define MIXER_PRESENT_GLOBAL_VOLUME (1<<1) +#define MIXER_PRESENT_PLAYBACK_SWITCH (1<<2) +#define MIXER_PRESENT_PLAYBACK_VOLUME (1<<3) +#define MIXER_PRESENT_CAPTURE_SWITCH (1<<4) +#define MIXER_PRESENT_CAPTURE_VOLUME (1<<5) +#define MIXER_PRESENT_CAPTURE_SOURCE (1<<6) + struct mixer_simple { + /* this may be moved to a private area */ + unsigned int present; /* present controls */ + unsigned int gswitch_values; + unsigned int pswitch_values; + unsigned int cswitch_values; + unsigned int gvolume_values; + unsigned int pvolume_values; + unsigned int cvolume_values; + unsigned int ccapture_values; + unsigned int capture_item; + unsigned int caps; + long min; + long max; + int voices; + /* -- */ int refs; /* number of references */ int change; /* simple control was changed */ - snd_mixer_sid_t id; + snd_mixer_sid_t sid; mixer_simple_get_t *get; mixer_simple_put_t *put; mixer_simple_event_t *event; diff --git a/src/mixer/simple.c b/src/mixer/simple.c index 5fa2c5ae..c0e554eb 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -31,22 +31,16 @@ static int test_mixer_id(snd_mixer_t *handle, const char *name, int index) { - snd_control_t c; - int err; + snd_control_id_t id; + snd_hcontrol_t *hcontrol; - memset(&c, 0, sizeof(c)); - c.id.iface = SND_CONTROL_IFACE_MIXER; - strcpy(c.id.name, name); - c.id.index = index; - err = snd_ctl_cread(handle->ctl_handle, &c); - fprintf(stderr, "Looking for control: '%s', %i (%i)\n", name, index, err); - switch (err) { - case 0: - case -EBUSY: - return 1; - default: - return 0; - } + memset(&id, 0, sizeof(id)); + id.iface = SND_CONTROL_IFACE_MIXER; + strcpy(id.name, name); + id.index = index; + hcontrol = snd_ctl_cfind(handle->ctl_handle, &id); + // fprintf(stderr, "Looking for control: '%s', %i (0x%lx)\n", name, index, (long)hcontrol); + return hcontrol != NULL; } static int get_mixer_info(snd_mixer_t *handle, const char *name, int index, snd_control_info_t *info) @@ -58,6 +52,27 @@ static int get_mixer_info(snd_mixer_t *handle, const char *name, int index, snd_ return snd_ctl_cinfo(handle->ctl_handle, info); } +static int get_mixer_read(snd_mixer_t *handle, const char *name, int index, snd_control_t *control) +{ + memset(control, 0, sizeof(*control)); + control->id.iface = SND_CONTROL_IFACE_MIXER; + strcpy(control->id.name, name); + control->id.index = index; + return snd_ctl_cread(handle->ctl_handle, control); +} + +static int put_mixer_write(snd_mixer_t *handle, const char *name, int index, snd_control_t *control) +{ + control->id.numid = 0; + control->id.iface = SND_CONTROL_IFACE_MIXER; + strcpy(control->id.name, name); + control->id.device = control->id.subdevice = 0; + control->id.index = index; + control->indirect = 0; + memset(&control->reserved, 0, sizeof(control->reserved)); + return snd_ctl_cwrite(handle->ctl_handle, control); +} + static mixer_simple_t *simple_new(mixer_simple_t *scontrol) { mixer_simple_t *s; @@ -104,297 +119,378 @@ static int simple_remove(snd_mixer_t *handle, mixer_simple_t *scontrol) return 0; } -static int input_get(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control) +static int input_get_volume(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) { char str[128]; - int mute_is_valid = 0; - snd_control_info_t mute_info; - int volume_is_valid = 0; - snd_control_info_t volume_info; - int capture_is_valid = 0, capture1_is_valid = 0; - unsigned int capture1_item = 0; - snd_control_info_t capture_info; - unsigned int voices = 0, idx; snd_control_t ctl; - int err; + int idx, err; + + sprintf(str, "%s %sVolume", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < simple->voices && idx < 32; idx++) + control->volume.values[idx] = ctl.value.integer.value[voices == 1 ? 0 : idx]; +} + +static int input_get_mute_switch(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) +{ + char str[128]; + snd_control_t ctl; + int idx, err; + + sprintf(str, "%s %sSwitch", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < simple->voices && idx < 32; idx++) + if (ctl.value.integer.value[voices == 1 ? 0 : idx] == 0) + control->mute |= 1 << idx; +} + +static int input_get_capture_switch(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) +{ + char str[128]; + snd_control_t ctl; + int idx, err; + + sprintf(str, "%s %sSwitch", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < simple->voices && idx < 32; idx++) + if (ctl.value.integer.value[voices == 1 ? 0 : idx]) + control->capture |= 1 << idx; +} + +static int input_get(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control) +{ + int idx, err; if (simple == NULL) return -EINVAL; - control->caps = 0; + control->caps = simple->caps; control->channels = 0; control->mute = 0; control->capture = 0; control->capture_group = 0; - control->min = 0; - control->max = 0; + control->min = simple->min; + control->max = simple->max; for (idx = 0; idx < 32; idx++) control->volume.values[idx] = 0; - sprintf(str, "%s Mute", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &mute_info)) < 0) - return err; - if (mute_info.type == SND_CONTROL_TYPE_BOOLEAN) { - if (voices < mute_info.values_count) - voices = mute_info.values_count; - mute_is_valid++; - control->caps |= SND_MIXER_SCTCAP_MUTE; + for (idx = 0; idx < simple->voices && idx < 32; idx++) + control->channels |= 1 << idx; + if (simple->caps & SND_MIXER_SCTCAP_VOLUME) { + if (simple->present & MIXER_PRESENT_PLAYBACK_VOLUME) { + input_get_volume(handle, simple, control, "Playback ", simple->pvolume_values); + } else if (simple->present & MIXER_PRESENT_GLOBAL_VOLUME) { + input_get_volume(handle, simple, control, "", simple->gvolume_values); } } - sprintf(str, "%s Volume", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &volume_info)) < 0) - return err; - if (volume_info.type == SND_CONTROL_TYPE_INTEGER) { - if (voices < volume_info.values_count) - voices = volume_info.values_count; - volume_is_valid++; - control->caps |= SND_MIXER_SCTCAP_VOLUME; - control->min = volume_info.value.integer.min; - control->max = volume_info.value.integer.max; + if (simple->caps & SND_MIXER_SCTCAP_MUTE) { + if (simple->present & MIXER_PRESENT_PLAYBACK_SWITCH) { + input_get_mute_switch(handle, simple, control, "Playback ", simple->pswitch_values); + } else if (simple->present & MIXER_PRESENT_GLOBAL_VOLUME) { + input_get_mute_switch(handle, simple, control, "", simple->pvolume_values); } } - sprintf(str, "%s Capture", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &capture_info)) < 0) - return err; - if (capture_info.type == SND_CONTROL_TYPE_BOOLEAN) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture_is_valid++; - control->caps |= SND_MIXER_SCTCAP_CAPTURE; - } - } else if (test_mixer_id(handle, "Capture Source", 0)) { - if ((err = get_mixer_info(handle, "Capture Source", 0, &capture_info)) < 0) - return err; - strcpy(str, control->sid.name); - if (!strcmp(str, "Master")) /* special case */ - strcpy(str, "Mix"); - else if (!strcmp(str, "Master Mono")) /* special case */ - strcpy(str, "Mono Mix"); - if (capture_info.type == SND_CONTROL_TYPE_ENUMERATED) { - if (!strcmp(capture_info.value.enumerated.name, str)) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture1_is_valid++; - control->caps |= SND_MIXER_SCTCAP_CAPTURE | SND_MIXER_SCTCAP_EXCL_CAPTURE; - control->capture_group = 1; - } - for (capture1_item = 1; capture1_item < capture_info.value.enumerated.items; capture1_item++) { - capture_info.value.enumerated.item = capture1_item; - if ((err = snd_ctl_cinfo(handle->ctl_handle, &capture_info)) < 0) - return err; - if (!strcmp(capture_info.value.enumerated.name, str)) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture1_is_valid++; - control->caps |= SND_MIXER_SCTCAP_CAPTURE | SND_MIXER_SCTCAP_EXCL_CAPTURE; - control->capture_group = 1; - break; - } - } + if (simple->caps & SND_MIXER_SCTCAP_CAPTURE) { + if (simple->present & MIXER_PRESENT_CAPTURE_SWITCH) { + input_get_capture_switch(handle, simple, control, "Capture ", simple->cswitch_values); + } else if (simple->present & MIXER_PRESENT_CAPTURE_SOURCE) { + char str[128]; + snd_control_t ctl; + if ((err = get_mixer_read(handle, "Capture Source", 0, &ctl)) < 0) + return err; + for (idx = 0; idx < simple->voices && idx < 32; idx++) + if (ctl.value.enumerated.item[simple->ccapture_values == 1 ? 0 : idx] == simple->capture_item) + control->capture |= 1 << idx; } } + return 0; +} - for (idx = 0; idx < voices && idx < 32; idx++) - control->channels |= 1 << idx; - if (voices > 1) { - if (volume_is_valid && volume_info.values_count == 1) - control->caps |= SND_MIXER_SCTCAP_JOINTLY_VOLUME; - if (mute_is_valid && mute_info.values_count == 1) - control->caps |= SND_MIXER_SCTCAP_JOINTLY_MUTE; - if ((capture_is_valid || capture1_is_valid) && capture_info.values_count == 1) - control->caps |= SND_MIXER_SCTCAP_JOINTLY_CAPTURE; - } - if (volume_is_valid) { - memset(&ctl, 0, sizeof(ctl)); - ctl.id = volume_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) - return err; - for (idx = 0; idx < voices && idx < 32; idx++) - control->volume.values[idx] = ctl.value.integer.value[volume_info.values_count == 1 ? 0 : idx]; - } - if (mute_is_valid) { - memset(&ctl, 0, sizeof(ctl)); - ctl.id = mute_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) - return err; - for (idx = 0; idx < voices && idx < 32; idx++) - if (ctl.value.integer.value[mute_info.values_count == 1 ? 0 : idx]) - control->mute |= 1 << idx; +static int input_put_volume(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) +{ + char str[128]; + snd_control_t ctl; + int idx, err; + + sprintf(str, "%s %sVolume", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) { + ctl.value.integer.value[idx] = control->volume.values[idx]; + // fprintf(stderr, "ctl.id.name = '%s', volume = %i\n", ctl.id.name, ctl.value.integer.value[idx]); } - if (capture_is_valid) { - memset(&ctl, 0, sizeof(ctl)); - ctl.id = capture_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) - return err; - for (idx = 0; idx < voices && idx < 32; idx++) - if (ctl.value.integer.value[capture_info.values_count == 1 ? 0 : idx]) - control->capture |= 1 << idx; - } else if (capture1_is_valid) { - memset(&ctl, 0, sizeof(ctl)); - ctl.id = capture_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) - return err; - for (idx = 0; idx < voices && idx < 32; idx++) - if (ctl.value.enumerated.item[capture_info.values_count == 1 ? 0 : idx] == capture1_item) - control->capture |= 1 << idx; + if ((err = put_mixer_write(handle, str, simple->sid.index, &ctl)) < 0) + return err; +} + +static int input_put_mute_switch(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) +{ + char str[128]; + snd_control_t ctl; + int idx, err; + + sprintf(str, "%s %sSwitch", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) { + ctl.value.integer.value[idx] = (control->mute & (1 << idx)) ? 0 : 1; + // fprintf(stderr, "ctl.id.name = '%s', switch = %i\n", ctl.id.name, ctl.value.integer.value[idx]); } + err = put_mixer_write(handle, str, simple->sid.index, &ctl); + if ((err = put_mixer_write(handle, str, simple->sid.index, &ctl)) < 0) + return err; +} - return 0; +static int input_put_capture_switch(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control, const char *direction, int voices) +{ + char str[128]; + snd_control_t ctl; + int idx, err; + + sprintf(str, "%s %sSwitch", simple->sid.name, direction); + if ((err = get_mixer_read(handle, str, simple->sid.index, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) + ctl.value.integer.value[idx] = (control->capture & (1 << idx)) ? 1 : 0; + if ((err = put_mixer_write(handle, str, simple->sid.index, &ctl)) < 0) + return err; } static int input_put(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control) { - char str[128]; - int mute_is_valid = 0; - snd_control_info_t mute_info; - int volume_is_valid = 0; - snd_control_info_t volume_info; - int capture_is_valid = 0, capture1_is_valid = 0; - unsigned int capture1_item = 0; - snd_control_info_t capture_info; - unsigned int voices = 0, idx; - snd_control_t ctl_mute, ctl_volume, ctl_capture; - int err; + int err, idx; if (simple == NULL) return -EINVAL; - sprintf(str, "%s Mute", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &mute_info)) < 0) - return err; - if (mute_info.type == SND_CONTROL_TYPE_BOOLEAN) { - if (voices < mute_info.values_count) - voices = mute_info.values_count; - mute_is_valid++; - } - } - sprintf(str, "%s Volume", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &volume_info)) < 0) - return err; - if (volume_info.type == SND_CONTROL_TYPE_INTEGER) { - if (voices < volume_info.values_count) - voices = volume_info.values_count; - volume_is_valid++; + if (simple->caps & SND_MIXER_SCTCAP_VOLUME) { + if (simple->present & MIXER_PRESENT_PLAYBACK_VOLUME) { + input_put_volume(handle, simple, control, "Playback ", simple->pvolume_values); + } else if (simple->present & MIXER_PRESENT_GLOBAL_VOLUME) { + input_put_volume(handle, simple, control, "", simple->gvolume_values); } } - sprintf(str, "%s Capture", control->sid.name); - if (test_mixer_id(handle, str, control->sid.index)) { - if ((err = get_mixer_info(handle, str, control->sid.index, &capture_info)) < 0) - return err; - if (capture_info.type == SND_CONTROL_TYPE_BOOLEAN) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture_is_valid++; - } - } else if (test_mixer_id(handle, "Capture Source", 0)) { - if ((err = get_mixer_info(handle, "Capture Source", 0, &capture_info)) < 0) - return err; - strcpy(str, control->sid.name); - if (!strcmp(str, "Master")) /* special case */ - strcpy(str, "Mix"); - else if (!strcmp(str, "Master Mono")) /* special case */ - strcpy(str, "Mono Mix"); - if (capture_info.type == SND_CONTROL_TYPE_ENUMERATED) { - if (!strcmp(capture_info.value.enumerated.name, str)) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture1_is_valid++; - } - for (capture1_item = 1; capture1_item < capture_info.value.enumerated.items; capture1_item++) { - capture_info.value.enumerated.item = capture1_item; - if ((err = snd_ctl_cinfo(handle->ctl_handle, &capture_info)) < 0) - return err; - if (!strcmp(capture_info.value.enumerated.name, str)) { - if (voices < capture_info.values_count) - voices = capture_info.values_count; - capture1_is_valid++; - break; - } - } + if (simple->caps & SND_MIXER_SCTCAP_MUTE) { + if (simple->present & MIXER_PRESENT_PLAYBACK_SWITCH) { + input_put_mute_switch(handle, simple, control, "Playback ", simple->pswitch_values); + } else if (simple->present & MIXER_PRESENT_GLOBAL_VOLUME) { + input_put_mute_switch(handle, simple, control, "", simple->pvolume_values); } } - - memset(&ctl_mute, 0, sizeof(ctl_mute)); - memset(&ctl_volume, 0, sizeof(ctl_volume)); - memset(&ctl_capture, 0, sizeof(ctl_capture)); - if (mute_is_valid) { - ctl_mute.id = mute_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_mute)) < 0) - return err; - } - if (volume_is_valid) { - ctl_volume.id = volume_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_volume)) < 0) - return err; - } - if (capture_is_valid || capture1_is_valid) { - ctl_capture.id = capture_info.id; - if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_capture)) < 0) - return err; - } - for (idx = 0; idx < voices && idx < 32; idx++) { - if (control->channels & (1 << idx)) { - if (volume_is_valid) { - if (control->volume.values[idx] < volume_info.value.integer.min || - control->volume.values[idx] > volume_info.value.integer.max) - return -EINVAL; - ctl_volume.value.integer.value[idx] = control->volume.values[idx]; - } - if (mute_is_valid) { - ctl_mute.value.integer.value[idx] = (control->mute & (1 << idx)) ? 1 : 0; - } - if (capture_is_valid) { - ctl_capture.value.integer.value[idx] = (control->capture & (1 << idx)) ? 1 : 0; - } else if (capture1_is_valid && (control->capture & (1 << idx))) { - ctl_capture.value.enumerated.item[idx] = capture1_item; + if (simple->caps & SND_MIXER_SCTCAP_CAPTURE) { + // fprintf(stderr, "capture: present = 0x%x\n", simple->present); + if (simple->present & MIXER_PRESENT_CAPTURE_SWITCH) { + input_put_capture_switch(handle, simple, control, "Capture ", simple->cswitch_values); + } else if (simple->present & MIXER_PRESENT_CAPTURE_SOURCE) { + char str[128]; + snd_control_t ctl; + if ((err = get_mixer_read(handle, "Capture Source", 0, &ctl)) < 0) + return err; + // fprintf(stderr, "put capture source : %i [0x%x]\n", simple->capture_item, control->capture); + for (idx = 0; idx < simple->voices && idx < 32; idx++) { + if (control->capture & (1 << idx)) + ctl.value.enumerated.item[idx] = simple->capture_item; } + if ((err = put_mixer_write(handle, "Capture Source", 0, &ctl)) < 0) + return err; } } - if (volume_is_valid) { - if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_volume)) < 0) - return err; - } - if (mute_is_valid) { - if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_mute)) < 0) - return err; - } - if (capture_is_valid || capture1_is_valid) { - if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_capture)) < 0) - return err; - } return 0; } -static int build_input_scontrol(snd_mixer_t *handle, const char *sname, int index) +static mixer_simple_t *build_input_scontrol(snd_mixer_t *handle, const char *sname, int index) { - mixer_simple_t s; + mixer_simple_t s, *p; memset(&s, 0, sizeof(s)); - strcpy(s.id.name, sname); - s.id.index = index; + strcpy(s.sid.name, sname); + s.sid.index = index; s.get = input_get; s.put = input_put; - return simple_add(handle, simple_new(&s)); + if (simple_add(handle, p = simple_new(&s)) < 0) { + free(p); + return NULL; + } + return p; } static int build_input(snd_mixer_t *handle, const char *sname) { char str[128]; + unsigned int present, caps, capture_item; + int index = -1, voices, err; + snd_control_info_t gswitch_info, pswitch_info, cswitch_info; + snd_control_info_t gvolume_info, pvolume_info, cvolume_info; + snd_control_info_t csource_info; + long min, max; + mixer_simple_t *simple; - fprintf(stderr, "build_input: '%s'\n", sname); - sprintf(str, "%s Mute", sname); - if (test_mixer_id(handle, str, 0)) { - fprintf(stderr, "id ok (mute): %s\n", str); - return build_input_scontrol(handle, sname, 0); - } - sprintf(str, "%s Volume", sname); - if (test_mixer_id(handle, str, 0)) - return build_input_scontrol(handle, sname, 0); + memset(&gswitch_info, 0, sizeof(gswitch_info)); + memset(&pswitch_info, 0, sizeof(pswitch_info)); + memset(&cswitch_info, 0, sizeof(cswitch_info)); + memset(&gvolume_info, 0, sizeof(gvolume_info)); + memset(&pvolume_info, 0, sizeof(pvolume_info)); + memset(&cvolume_info, 0, sizeof(cvolume_info)); + do { + index++; + voices = 0; + present = caps = capture_item = 0; + min = max = 0; + sprintf(str, "%s Switch", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &gswitch_info)) < 0) + return err; + if (gswitch_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < gswitch_info.values_count) + voices = gswitch_info.values_count; + caps |= SND_MIXER_SCTCAP_MUTE; + present |= MIXER_PRESENT_GLOBAL_SWITCH; + } + } + sprintf(str, "%s Volume", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &gvolume_info)) < 0) + return err; + if (gvolume_info.type == SND_CONTROL_TYPE_INTEGER) { + if (voices < gvolume_info.values_count) + voices = gvolume_info.values_count; + if (min > gvolume_info.value.integer.min) + min = gvolume_info.value.integer.min; + if (max < gvolume_info.value.integer.max) + max = gvolume_info.value.integer.max; + caps |= SND_MIXER_SCTCAP_VOLUME; + present |= MIXER_PRESENT_GLOBAL_VOLUME; + } + } + sprintf(str, "%s Playback Switch", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &pswitch_info)) < 0) + return err; + if (pswitch_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < pswitch_info.values_count) + voices = pswitch_info.values_count; + caps |= SND_MIXER_SCTCAP_MUTE; + present |= MIXER_PRESENT_PLAYBACK_SWITCH; + } + } + sprintf(str, "%s Capture Switch", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &cswitch_info)) < 0) + return err; + if (cswitch_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < cswitch_info.values_count) + voices = cswitch_info.values_count; + caps |= SND_MIXER_SCTCAP_CAPTURE; + present |= MIXER_PRESENT_CAPTURE_SWITCH; + } + } + sprintf(str, "%s Playback Volume", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &pvolume_info)) < 0) + return err; + if (pvolume_info.type == SND_CONTROL_TYPE_INTEGER) { + if (voices < pvolume_info.values_count) + voices = pvolume_info.values_count; + if (min > pvolume_info.value.integer.min) + min = pvolume_info.value.integer.min; + if (max < pvolume_info.value.integer.max) + max = pvolume_info.value.integer.max; + caps |= SND_MIXER_SCTCAP_VOLUME; + present |= MIXER_PRESENT_PLAYBACK_VOLUME; + } + } + sprintf(str, "%s Capture Volume", sname); + if (test_mixer_id(handle, str, index)) { + if ((err = get_mixer_info(handle, str, index, &cvolume_info)) < 0) + return err; + if (cvolume_info.type == SND_CONTROL_TYPE_INTEGER) { + if (voices < cvolume_info.values_count) + voices = cvolume_info.values_count; + if (min > pvolume_info.value.integer.min) + min = pvolume_info.value.integer.min; + if (max < pvolume_info.value.integer.max) + max = pvolume_info.value.integer.max; + caps |= SND_MIXER_SCTCAP_VOLUME; + present |= MIXER_PRESENT_CAPTURE_VOLUME; + } + } + if (index == 0 && test_mixer_id(handle, "Capture Source", 0)) { + if ((err = get_mixer_info(handle, "Capture Source", 0, &csource_info)) < 0) + return err; + strcpy(str, sname); + if (!strcmp(str, "Master")) /* special case */ + strcpy(str, "Mix"); + else if (!strcmp(str, "Master Mono")) /* special case */ + strcpy(str, "Mono Mix"); + if (csource_info.type == SND_CONTROL_TYPE_ENUMERATED) { + capture_item = 0; + if (!strcmp(csource_info.value.enumerated.name, str)) { + if (voices < csource_info.values_count) + voices = csource_info.values_count; + caps |= SND_MIXER_SCTCAP_CAPTURE; + present |= MIXER_PRESENT_CAPTURE_SOURCE; + } else for (capture_item = 1; capture_item < csource_info.value.enumerated.items; capture_item++) { + csource_info.value.enumerated.item = capture_item; + if ((err = snd_ctl_cinfo(handle->ctl_handle, &csource_info)) < 0) + return err; + if (!strcmp(csource_info.value.enumerated.name, str)) { + if (voices < csource_info.values_count) + voices = csource_info.values_count; + caps |= SND_MIXER_SCTCAP_CAPTURE; + present |= MIXER_PRESENT_CAPTURE_SOURCE; + break; + } + } + } + } + if (voices > 1) { + caps |= SND_MIXER_SCTCAP_JOINTLY_MUTE | SND_MIXER_SCTCAP_JOINTLY_CAPTURE | SND_MIXER_SCTCAP_JOINTLY_VOLUME; + if (present & MIXER_PRESENT_GLOBAL_SWITCH) { + if (gswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_MUTE; + } + if (present & MIXER_PRESENT_PLAYBACK_SWITCH) { + if (pswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_MUTE; + } + if (present & MIXER_PRESENT_CAPTURE_SWITCH) { + if (cswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_CAPTURE; + } + if (present & MIXER_PRESENT_GLOBAL_VOLUME) { + if (gswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_VOLUME; + } + if (present & MIXER_PRESENT_PLAYBACK_VOLUME) { + if (pswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_VOLUME; + } + if (present & MIXER_PRESENT_CAPTURE_VOLUME) { + if (cswitch_info.values_count > 1) + caps &= ~SND_MIXER_SCTCAP_JOINTLY_VOLUME; + } + } + simple = build_input_scontrol(handle, sname, index); + if (simple == NULL) + return -ENOMEM; + simple->present = present; + simple->gswitch_values = gswitch_info.values_count; + simple->pswitch_values = pswitch_info.values_count; + simple->cswitch_values = cswitch_info.values_count; + simple->gvolume_values = gvolume_info.values_count; + simple->pvolume_values = pvolume_info.values_count; + simple->cvolume_values = cvolume_info.values_count; + simple->ccapture_values = csource_info.values_count; + simple->capture_item = capture_item; + simple->caps = caps; + simple->voices = voices; + simple->min = min; + simple->max = max; + // fprintf(stderr, "sname = '%s', index = %i, present = 0x%x, voices = %i\n", sname, index, present, voices); + } while (present != 0); return 0; } @@ -420,6 +516,8 @@ int snd_mixer_simple_build(snd_mixer_t *handle) char **input = inputs; int err; + if ((err = snd_ctl_cbuild(handle->ctl_handle, snd_ctl_csort)) < 0) + return err; while (*input) { if ((err = build_input(handle, *input)) < 0) { snd_mixer_simple_destroy(handle); @@ -436,5 +534,6 @@ int snd_mixer_simple_destroy(snd_mixer_t *handle) while (handle->simple_first) simple_remove(handle, handle->simple_first); handle->simple_valid = 0; + snd_ctl_cfree(handle->ctl_handle); return 0; } |