From 7376ad380ed3df90f36b71715213e3875e1668b7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 16 Aug 2000 13:35:36 +0000 Subject: [PATCH] Added bag operations for the high-level control interface. Added event layer for simple mixer controls (not fully finished). --- include/control.h | 6 +++ src/control/Makefile.am | 2 +- src/control/bag.c | 87 ++++++++++++++++++++++++++++++++++++++ src/control/controls.c | 91 ++++++++++++++++++++++++++++++++++++++- src/mixer/mixer.c | 94 +++++++++++++++++++++-------------------- src/mixer/mixer_local.h | 19 ++++++--- src/mixer/simple.c | 90 ++++++++++++++++++++++++++------------- 7 files changed, 304 insertions(+), 85 deletions(-) create mode 100644 src/control/bag.c diff --git a/include/control.h b/include/control.h index ad88add7..ad154c99 100644 --- a/include/control.h +++ b/include/control.h @@ -113,6 +113,12 @@ int snd_ctl_hcallback_rebuild(snd_ctl_t *handle, snd_ctl_hcallback_rebuild_t *ca int snd_ctl_hcallback_add(snd_ctl_t *handle, snd_ctl_hcallback_add_t *callback, void *private_data); int snd_ctl_hevent(snd_ctl_t *handle); +int snd_ctl_hbag_create(void **bag); +int snd_ctl_hbag_destroy(void **bag, void (*hcontrol_free)(snd_hcontrol_t *hcontrol)); +int snd_ctl_hbag_add(void **bag, snd_hcontrol_t *hcontrol); +int snd_ctl_hbag_del(void **bag, snd_hcontrol_t *hcontrol); +snd_hcontrol_t *snd_ctl_hbag_find(void **bag, snd_control_id_t *id); + #ifdef __cplusplus } #endif diff --git a/src/control/Makefile.am b/src/control/Makefile.am index 22002c4a..61b2679d 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 controls.c defaults.c +libcontrol_la_SOURCES = cards.c control.c controls.c bag.c defaults.c all: libcontrol.la diff --git a/src/control/bag.c b/src/control/bag.c new file mode 100644 index 00000000..ad6f55af --- /dev/null +++ b/src/control/bag.c @@ -0,0 +1,87 @@ +/* + * Control Interface - highlevel API - hcontrol bag operations + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#define __USE_GNU +#include +#include "asoundlib.h" +#include "control_local.h" + +int snd_ctl_hbag_create(void **bag) +{ + assert(bag != NULL); + *bag = NULL; + return 0; +} + +static void snd_ctl_hbag_free_private(snd_hcontrol_t *hcontrol ATTRIBUTE_UNUSED) +{ + /* nothing */ +} + +int snd_ctl_hbag_destroy(void **bag, void (*hcontrol_free)(snd_hcontrol_t *hcontrol)) +{ + assert(bag != NULL); + if (hcontrol_free == NULL) + hcontrol_free = snd_ctl_hbag_free_private; + tdestroy(*bag, (__free_fn_t)hcontrol_free); + *bag = NULL; + return 0; +} + +int snd_ctl_hbag_add(void **bag, snd_hcontrol_t *hcontrol) +{ + void *res; + + assert(bag != NULL && hcontrol != NULL); + res = tsearch(hcontrol, bag, (__compar_fn_t)snd_ctl_hsort); + if (res == NULL) + return -ENOMEM; + if ((snd_hcontrol_t *)res == hcontrol) + return -EALREADY; + return 0; +} + +int snd_ctl_hbag_del(void **bag, snd_hcontrol_t *hcontrol) +{ + assert(bag != NULL && hcontrol != NULL); + if (tdelete(hcontrol, bag, (__compar_fn_t)snd_ctl_hsort) == NULL) + return -ENOENT; + return 0; +} + +snd_hcontrol_t *snd_ctl_hbag_find(void **bag, snd_control_id_t *id) +{ + void *res; + + assert(bag != NULL && id != NULL); + if (*bag == NULL) + return NULL; + res = tfind(id, bag, (__compar_fn_t)snd_ctl_hsort); + return res == NULL ? NULL : *(snd_hcontrol_t **)res; +} diff --git a/src/control/controls.c b/src/control/controls.c index 6d31968b..4ab9837e 100644 --- a/src/control/controls.c +++ b/src/control/controls.c @@ -124,16 +124,103 @@ int snd_ctl_hfree(snd_ctl_t *handle) return 0; } -int snd_ctl_hsort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2) +#define NOT_FOUND 1000000000 + +static int snd_ctl_hsort_mixer_priority_lookup(char **name, char * const *names, int coef) { int res; + for (res = 0; *names; names++, res += coef) { + if (!strncmp(*name, *names, strlen(*names))) { + *name += strlen(*names); + if (**name == ' ') + *name++; + return res; + } + } + return NOT_FOUND; +} + +static int snd_ctl_hsort_mixer_priority(const char *name) +{ + static char *names[] = { + "Master", + "Master Digital", + "Master Mono", + "Hardware Master", + "Headphone", + "Tone Control", + "3D Control", + "PCM", + "PCM Front", + "PCM Rear", + "PCM Pan", + "Wave", + "Music", + "Line", + "CD", + "Mic", + "Phone", + "Video", + "PC Speaker", + "Aux", + "ADC", + "Capture Source", + "Capture", + "Playback", + "Loopback", + "Analog Loopback", + "Digital Loopback", + "S/PDIF Input", + "S/PDIF Output", + NULL + }; + static char *names1[] = { + "Switch", + "Volume", + "Playback", + "Capture", + "Bypass", + NULL + }; + static char *names2[] = { + "Switch", + "Volume", + "Bypass", + NULL + }; + char **ptr, *s; + int res, res1; + + if ((res = snd_ctl_hsort_mixer_priority_lookup((char **)&name, names, 1000000)) == NOT_FOUND) + return NOT_FOUND; + if ((res1 = snd_ctl_hsort_mixer_priority_lookup((char **)&name, names1, 1000)) == NOT_FOUND) + return res; + res += res1; + if ((res1 = snd_ctl_hsort_mixer_priority_lookup((char **)&name, names2, 1)) == NOT_FOUND) + return res; + return res + res1; +} + +int snd_ctl_hsort(const snd_hcontrol_t *c1, const snd_hcontrol_t *c2) +{ + int res, p1, p2; + if (c1->id.iface < c2->id.iface) return -1; if (c1->id.iface > c2->id.iface) return 1; - if ((res = strcmp(c1->id.name, c2->id.name)) != 0) + if ((res = strcmp(c1->id.name, c2->id.name)) != 0) { + if (c1->id.iface != SND_CONTROL_IFACE_MIXER) + return res; + p1 = snd_ctl_hsort_mixer_priority(c1->id.name); + p2 = snd_ctl_hsort_mixer_priority(c2->id.name); + if (p1 < p2) + return -1; + if (p1 > p2) + return 1; return res; + } if (c1->id.index < c2->id.index) return -1; if (c1->id.index > c2->id.index) diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 4e5b4e8c..d66671cc 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -29,6 +29,9 @@ #include "asoundlib.h" #include "mixer_local.h" +static void snd_mixer_simple_read_rebuild(snd_ctl_t *ctl_handle, void *private_data); +static void snd_mixer_simple_read_add(snd_ctl_t *ctl_handle, void *private_data, snd_hcontrol_t *hcontrol); + int snd_mixer_open(snd_mixer_t **r_handle, int card) { snd_mixer_t *handle; @@ -40,12 +43,21 @@ int snd_mixer_open(snd_mixer_t **r_handle, int card) *r_handle = NULL; if ((err = snd_ctl_open(&ctl_handle, card)) < 0) return err; + if ((err = snd_ctl_hcallback_rebuild(ctl_handle, snd_mixer_simple_read_rebuild, handle)) < 0) { + snd_ctl_close(ctl_handle); + return err; + } + if ((err = snd_ctl_hcallback_add(ctl_handle, snd_mixer_simple_read_add, handle)) < 0) { + snd_ctl_close(ctl_handle); + return err; + } handle = (snd_mixer_t *) calloc(1, sizeof(snd_mixer_t)); if (handle == NULL) { snd_ctl_close(ctl_handle); return -ENOMEM; } handle->ctl_handle = ctl_handle; + INIT_LIST_HEAD(&handle->simples); *r_handle = handle; return 0; } @@ -88,10 +100,10 @@ const char *snd_mixer_simple_channel_name(int channel) int snd_mixer_simple_control_list(snd_mixer_t *handle, snd_mixer_simple_control_list_t *list) { + struct list_head *lh; mixer_simple_t *s; snd_mixer_sid_t *p; - int err; - unsigned int tmp; + int err, idx; if (handle == NULL || list == NULL) return -EINVAL; @@ -99,25 +111,34 @@ int snd_mixer_simple_control_list(snd_mixer_t *handle, snd_mixer_simple_control_ if ((err = snd_mixer_simple_build(handle)) < 0) return err; list->controls_count = 0; - tmp = list->controls_offset; - for (s = handle->simple_first; s != NULL && tmp > 0; s = s->next); - tmp = list->controls_request; p = list->pids; - if (tmp > 0 && p == NULL) + if (list->controls_request > 0 && p == NULL) return -EINVAL; - for (; s != NULL && tmp > 0; s = s->next, tmp--, p++, list->controls_count++) - memcpy(p, &s->sid, sizeof(*p)); + idx = 0; + list_for_each(lh, &handle->simples) { + if (idx >= list->controls_offset + list->controls_request) + break; + if (idx >= list->controls_offset) { + s = list_entry(lh, mixer_simple_t, list); + memcpy(p, &s->sid, sizeof(*p)); p++; + list->controls_count++; + } + idx++; + } list->controls = handle->simple_count; return 0; } static mixer_simple_t *look_for_simple(snd_mixer_t *handle, snd_mixer_sid_t *sid) { + struct list_head *list; mixer_simple_t *s; - for (s = handle->simple_first; s != NULL; s = s->next) + list_for_each(list, &handle->simples) { + s = list_entry(list, mixer_simple_t, list); if (!strcmp(s->sid.name, sid->name) && s->sid.index == sid->index) return s; + } return NULL; } @@ -162,53 +183,26 @@ static void snd_mixer_simple_read_rebuild(snd_ctl_t *ctl_handle, void *private_d handle->simple_changes++; } -static void event_for_all_simple_controls(snd_mixer_t *handle, snd_ctl_event_type_t etype, snd_control_id_t *id) +static void snd_mixer_simple_read_add(snd_ctl_t *ctl_handle, void *private_data, snd_hcontrol_t *hcontrol) { + snd_mixer_t *handle = (snd_mixer_t *)private_data; mixer_simple_t *s; + struct list_head *list; - for (s = handle->simple_first; s != NULL; s = s->next) { - if (s->event) - s->event(handle, etype, id); + list_for_each(list, &handle->simples) { + s = list_entry(list, mixer_simple_t, list); + if (s->event_add) + s->event_add(handle, hcontrol); } } -static void snd_mixer_simple_read_value(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) -{ - snd_mixer_t *handle = (snd_mixer_t *)private_data; - if (handle->ctl_handle != ctl_handle) - return; - event_for_all_simple_controls(handle, SND_CTL_EVENT_VALUE, id); -} - -static void snd_mixer_simple_read_change(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) -{ - snd_mixer_t *handle = (snd_mixer_t *)private_data; - if (handle->ctl_handle != ctl_handle) - return; - event_for_all_simple_controls(handle, SND_CTL_EVENT_CHANGE, id); -} - -static void snd_mixer_simple_read_add(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) -{ - snd_mixer_t *handle = (snd_mixer_t *)private_data; - if (handle->ctl_handle != ctl_handle) - return; - event_for_all_simple_controls(handle, SND_CTL_EVENT_ADD, id); -} - -static void snd_mixer_simple_read_remove(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) -{ - snd_mixer_t *handle = (snd_mixer_t *)private_data; - if (handle->ctl_handle != ctl_handle) - return; - event_for_all_simple_controls(handle, SND_CTL_EVENT_REMOVE, id); -} - int snd_mixer_simple_read(snd_mixer_t *handle, snd_mixer_simple_callbacks_t *callbacks) { + mixer_simple_t *s; + struct list_head *list; int err; - if (handle == NULL) + if (handle == NULL || callbacks == NULL) return -EINVAL; if (!handle->simple_valid) snd_mixer_simple_build(handle); @@ -219,5 +213,13 @@ int snd_mixer_simple_read(snd_mixer_t *handle, snd_mixer_simple_callbacks_t *cal return err; } handle->callbacks = NULL; + list_for_each(list, &handle->simples) { + s = list_entry(list, mixer_simple_t, list); + if (s->change > 0) { + s->change = 0; + if (callbacks->value) + callbacks->value(handle, callbacks->private_data, &s->sid); + } + } return handle->simple_changes; } diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h index e37ba575..1d69cd52 100644 --- a/src/mixer/mixer_local.h +++ b/src/mixer/mixer_local.h @@ -21,12 +21,14 @@ #include #include "asoundlib.h" +#include "list.h" typedef struct mixer_simple mixer_simple_t; +typedef struct mixer_simple_hcontrol_private mixer_simple_hcontrol_private_t; typedef int (mixer_simple_get_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control); 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); +typedef int (mixer_simple_event_add_t) (snd_mixer_t *handle, snd_hcontrol_t *hcontrol); #define MIXER_PRESENT_GLOBAL_SWITCH (1<<0) #define MIXER_PRESENT_GLOBAL_VOLUME (1<<1) @@ -57,19 +59,22 @@ struct mixer_simple { snd_mixer_sid_t sid; mixer_simple_get_t *get; mixer_simple_put_t *put; - mixer_simple_event_t *event; - mixer_simple_t *prev; - mixer_simple_t *next; + mixer_simple_event_add_t *event_add; + struct list_head list; + void *hcontrols; /* bag of associated hcontrols */ unsigned long private_value; }; + +struct mixer_simple_hcontrol_private { + void *simples; /* list of associated hcontrols */ +}; struct snd_mixer { snd_ctl_t *ctl_handle; int simple_valid; - int simple_count; int simple_changes; /* total number of changes */ - mixer_simple_t *simple_first; - mixer_simple_t *simple_last; + int simple_count; + struct list_head simples; /* list of all simple controls */ snd_mixer_simple_callbacks_t *callbacks; }; diff --git a/src/mixer/simple.c b/src/mixer/simple.c index 4a7c15f8..69d8c21b 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -29,7 +29,7 @@ #include "asoundlib.h" #include "mixer_local.h" -static int test_mixer_id(snd_mixer_t *handle, const char *name, int index) +static snd_hcontrol_t *test_mixer_id(snd_mixer_t *handle, const char *name, int index) { snd_control_id_t id; snd_hcontrol_t *hcontrol; @@ -40,7 +40,7 @@ static int test_mixer_id(snd_mixer_t *handle, const char *name, int index) id.index = index; hcontrol = snd_ctl_hfind(handle->ctl_handle, &id); // fprintf(stderr, "Looking for control: '%s', %i (0x%lx)\n", name, index, (long)hcontrol); - return hcontrol != NULL; + return hcontrol; } static int get_mixer_info(snd_mixer_t *handle, const char *name, int index, snd_control_info_t *info) @@ -86,19 +86,42 @@ static mixer_simple_t *simple_new(mixer_simple_t *scontrol) return s; } +static void hcontrol_event_change(snd_ctl_t *ctl_handle, snd_hcontrol_t *hcontrol) +{ + /* ignore at this moment */ +} + +static void hcontrol_event_value(snd_ctl_t *ctl_handle, snd_hcontrol_t *hcontrol) +{ + snd_mixer_t *handle = (snd_mixer_t *)hcontrol->private_data; + mixer_simple_t *s; + struct list_head *list; + list_for_each(list, &handle->simples) { + s = list_entry(list, mixer_simple_t, list); + if (snd_ctl_hbag_find(&s->hcontrols, &hcontrol->id)) + s->change++; + } +} + +static void hcontrol_event_remove(snd_ctl_t *ctl_handle, snd_hcontrol_t *hcontrol) +{ + /* ignore at this moment */ +} + +static void hcontrol_add(snd_mixer_t *handle, void **bag, snd_hcontrol_t *hcontrol) +{ + snd_ctl_hbag_add(bag, hcontrol); + hcontrol->event_change = hcontrol_event_change; + hcontrol->event_value = hcontrol_event_value; + hcontrol->event_remove = hcontrol_event_remove; + hcontrol->private_data = handle; +} + static int simple_add(snd_mixer_t *handle, mixer_simple_t *scontrol) { if (handle == NULL || scontrol == NULL) return -EINVAL; - if (handle->simple_last != NULL) { - handle->simple_last->next = scontrol; - scontrol->prev = handle->simple_last; - scontrol->next = NULL; - handle->simple_last = scontrol; - } else { - handle->simple_first = handle->simple_last = scontrol; - scontrol->prev = scontrol->next = NULL; - } + list_add_tail(&scontrol->list, &handle->simples); handle->simple_count++; return 0; } @@ -107,15 +130,10 @@ static int simple_remove(snd_mixer_t *handle, mixer_simple_t *scontrol) { if (handle == NULL || scontrol == NULL) return -EINVAL; - if (handle->simple_first == scontrol) - handle->simple_first = scontrol->next; - if (handle->simple_last == scontrol) - handle->simple_last = scontrol->prev; - if (scontrol->prev) - scontrol->prev->next = scontrol->next; - if (scontrol->next) - scontrol->next->prev = scontrol->prev; + list_del(&scontrol->list); handle->simple_count--; + snd_ctl_hbag_destroy(&scontrol->hcontrols, NULL); + free(scontrol); return 0; } @@ -330,7 +348,9 @@ static int build_input(snd_mixer_t *handle, const char *sname) snd_control_info_t gvolume_info, pvolume_info, cvolume_info; snd_control_info_t csource_info; long min, max; + void *bag; mixer_simple_t *simple; + snd_hcontrol_t *hcontrol; memset(&gswitch_info, 0, sizeof(gswitch_info)); memset(&pswitch_info, 0, sizeof(pswitch_info)); @@ -343,8 +363,9 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = 0; present = caps = capture_item = 0; min = max = 0; + bag = NULL; sprintf(str, "%s Switch", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -352,10 +373,11 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = gswitch_info.values_count; caps |= SND_MIXER_SCTCAP_MUTE; present |= MIXER_PRESENT_GLOBAL_SWITCH; + hcontrol_add(handle, &bag, hcontrol); } } sprintf(str, "%s Volume", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -367,10 +389,11 @@ static int build_input(snd_mixer_t *handle, const char *sname) max = gvolume_info.value.integer.max; caps |= SND_MIXER_SCTCAP_VOLUME; present |= MIXER_PRESENT_GLOBAL_VOLUME; + hcontrol_add(handle, &bag, hcontrol); } } sprintf(str, "%s Playback Switch", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -378,10 +401,11 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = pswitch_info.values_count; caps |= SND_MIXER_SCTCAP_MUTE; present |= MIXER_PRESENT_PLAYBACK_SWITCH; + hcontrol_add(handle, &bag, hcontrol); } } sprintf(str, "%s Capture Switch", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -389,10 +413,11 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = cswitch_info.values_count; caps |= SND_MIXER_SCTCAP_CAPTURE; present |= MIXER_PRESENT_CAPTURE_SWITCH; + hcontrol_add(handle, &bag, hcontrol); } } sprintf(str, "%s Playback Volume", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -404,10 +429,11 @@ static int build_input(snd_mixer_t *handle, const char *sname) max = pvolume_info.value.integer.max; caps |= SND_MIXER_SCTCAP_VOLUME; present |= MIXER_PRESENT_PLAYBACK_VOLUME; + hcontrol_add(handle, &bag, hcontrol); } } sprintf(str, "%s Capture Volume", sname); - if (test_mixer_id(handle, str, index)) { + if (hcontrol = 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) { @@ -419,9 +445,10 @@ static int build_input(snd_mixer_t *handle, const char *sname) max = pvolume_info.value.integer.max; caps |= SND_MIXER_SCTCAP_VOLUME; present |= MIXER_PRESENT_CAPTURE_VOLUME; + hcontrol_add(handle, &bag, hcontrol); } } - if (index == 0 && test_mixer_id(handle, "Capture Source", 0)) { + if (index == 0 && (hcontrol = test_mixer_id(handle, "Capture Source", 0)) != NULL) { if ((err = get_mixer_info(handle, "Capture Source", 0, &csource_info)) < 0) return err; strcpy(str, sname); @@ -436,6 +463,7 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = csource_info.values_count; caps |= SND_MIXER_SCTCAP_CAPTURE; present |= MIXER_PRESENT_CAPTURE_SOURCE; + hcontrol_add(handle, &bag, hcontrol); } 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) @@ -445,6 +473,7 @@ static int build_input(snd_mixer_t *handle, const char *sname) voices = csource_info.values_count; caps |= SND_MIXER_SCTCAP_CAPTURE; present |= MIXER_PRESENT_CAPTURE_SOURCE; + hcontrol_add(handle, &bag, hcontrol); break; } } @@ -480,8 +509,10 @@ static int build_input(snd_mixer_t *handle, const char *sname) if (present == 0) break; simple = build_input_scontrol(handle, sname, index); - if (simple == NULL) + if (simple == NULL) { + snd_ctl_hbag_destroy(&bag, NULL); return -ENOMEM; + } simple->present = present; simple->gswitch_values = gswitch_info.values_count; simple->pswitch_values = pswitch_info.values_count; @@ -495,6 +526,7 @@ static int build_input(snd_mixer_t *handle, const char *sname) simple->voices = voices; simple->min = min; simple->max = max; + simple->hcontrols = bag; // fprintf(stderr, "sname = '%s', index = %i, present = 0x%x, voices = %i\n", sname, index, present, voices); }; return 0; @@ -537,8 +569,8 @@ int snd_mixer_simple_build(snd_mixer_t *handle) int snd_mixer_simple_destroy(snd_mixer_t *handle) { - while (handle->simple_first) - simple_remove(handle, handle->simple_first); + while (!list_empty(&handle->simples)) + simple_remove(handle, list_entry(handle->simples.next, mixer_simple_t, list)); handle->simple_valid = 0; snd_ctl_hfree(handle->ctl_handle); return 0; -- 2.47.1