From 3bcf2f805d4a7825c87bc2e0c1b2c783400fe6bc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 6 Jun 2005 14:01:13 +0000 Subject: [PATCH] Implemented the top-level redirector code for simple mixer - mixer_abst.c is almost finished (an example module should be created now) - also fixed some error paths for name function --- src/mixer/mixer.c | 4 + src/mixer/simple_abst.c | 175 ++++++++++++++++++++++++++++++++++++++-- src/names.c | 6 +- 3 files changed, 176 insertions(+), 9 deletions(-) diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 2a06c757..88c39475 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -497,6 +497,8 @@ int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer) * \brief Unregister mixer element class and remove all its elements * \param class Mixer element class * \return 0 on success otherwise a negative error code + * + * Note that the class structure is also deallocated! */ int snd_mixer_class_unregister(snd_mixer_class_t *class) { @@ -929,6 +931,8 @@ int snd_mixer_class_malloc(snd_mixer_class_t **ptr) */ void snd_mixer_class_free(snd_mixer_class_t *obj) { + if (obj->private_free) + obj->private_free(obj); free(obj); } diff --git a/src/mixer/simple_abst.c b/src/mixer/simple_abst.c index ab43c4ff..29f421f2 100644 --- a/src/mixer/simple_abst.c +++ b/src/mixer/simple_abst.c @@ -34,9 +34,123 @@ #include #include #include -#include "mixer_local.h" +#include +#include "config.h" +#include "asoundlib.h" #include "mixer_simple.h" +#define SO_PATH PKGLIBDIR "/smixer/" + +typedef struct _class_priv { + char *device; + snd_ctl_t *ctl; + snd_hctl_t *hctl; + snd_ctl_card_info_t *info; +} class_priv_t; + +static int try_open(snd_mixer_class_t *class, const char *lib) +{ + snd_mixer_event_t event_func; + char *xlib; + void *h; + + xlib = malloc(strlen(lib) + strlen(SO_PATH) + 1); + if (xlib == NULL) + return -ENOMEM; + strcpy(xlib, SO_PATH); + strcat(xlib, lib); + h = snd_dlopen(lib, RTLD_NOW); + if (h == NULL) { + SNDERR("Unable to open library '%s'", xlib); + free(xlib); + return -ENXIO; + } + event_func = dlsym(h, "alsa_mixer_simple_event"); + if (event_func == NULL) { + SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); + snd_dlclose(h); + free(xlib); + return -ENXIO; + } + free(xlib); + snd_mixer_class_set_event(class, event_func); + return 0; +} + +static int match(snd_mixer_class_t *class, const char *lib, const char *searchl) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + const char *components; + + if (searchl == NULL) + return try_open(class, lib); + components = snd_ctl_card_info_get_components(priv->info); + while (*components != '\0') { + if (!strncmp(components, searchl, strlen(searchl))) + return try_open(class, lib); + while (*components != ' ' && *components != '\0') + components++; + while (*components == ' ' && *components != '\0') + components++; + } + return 0; +} + +static int find_module(snd_mixer_class_t *class, snd_config_t *top) +{ + snd_config_iterator_t i, next; + snd_config_iterator_t j, jnext; + char *lib, *searchl; + const char *id; + int err; + + snd_config_for_each(i, next, top) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + searchl = NULL; + lib = NULL; + snd_config_for_each(j, jnext, n) { + snd_config_t *m = snd_config_iterator_entry(j); + if (snd_config_get_id(m, &id) < 0) + continue; + if (!strcmp(id, "searchl")) { + err = snd_config_get_string(m, (const char **)&searchl); + if (err < 0) + return err; + continue; + } + if (!strcmp(id, "lib")) { + err = snd_config_get_string(m, (const char **)&lib); + if (err < 0) + return err; + continue; + } + } + err = match(class, lib, searchl); + if (err == 1) + return 0; + if (err < 0) + return err; + } + return -ENOENT; +} + +static void private_free(snd_mixer_class_t *class) +{ + class_priv_t *priv = snd_mixer_class_get_private(class); + + if (priv->info) + snd_ctl_card_info_free(priv->info); + if (priv->hctl) + snd_hctl_close(priv->hctl); + else if (priv->ctl) + snd_ctl_close(priv->ctl); + if (priv->device) + free(priv->device); + free(priv); +} + /** * \brief Register mixer simple element class - basic abstraction * \param mixer Mixer handle @@ -48,29 +162,74 @@ int snd_mixer_simple_basic_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp) { - snd_mixer_class_t *class = calloc(1, sizeof(*class)); + snd_mixer_class_t *class; + class_priv_t *priv = calloc(1, sizeof(*priv)); const char *file; snd_input_t *input; + snd_config_t *top = NULL; int err; - if (snd_mixer_class_malloc(&class)) + if (options->device == NULL) + return -EIO; + if (priv == NULL) + return -ENOMEM; + if (snd_mixer_class_malloc(&class)) { + free(priv); + return -ENOMEM; + } + priv->device = strdup(options->device); + if (priv->device == NULL) { + free(priv); + snd_mixer_class_free(class); return -ENOMEM; - //snd_mixer_class_set_event(class, simple_event); + } snd_mixer_class_set_compare(class, snd_mixer_selem_compare); + snd_mixer_class_set_private(class, priv); + snd_mixer_class_set_private_free(class, private_free); + err = snd_ctl_open(&priv->ctl, priv->device, 0); + if (err < 0) { + SNDERR("unable to open control device '%s': %s", priv->device, snd_strerror(err)); + goto __error; + } + err = snd_hctl_open_ctl(&priv->hctl, priv->ctl); + if (err < 0) + goto __error; + err = snd_ctl_card_info_malloc(&priv->info); + if (err < 0) + goto __error; + err = snd_ctl_card_info(priv->ctl, priv->info); + if (err < 0) + goto __error; file = getenv("ALSA_MIXER_SIMPLE"); if (!file) file = DATADIR "/alsa/smixer.conf"; - if ((err = snd_input_stdio_open(&input, file, "r")) < 0) { - SNDERR("unable to open simple mixer configuration file '%s'", file); - goto __error; + err = snd_config_top(&top); + if (err >= 0) { + err = snd_input_stdio_open(&input, file, "r"); + if (err < 0) { + SNDERR("unable to open simple mixer configuration file '%s'", file); + goto __error; + } + err = snd_config_load(top, input); + snd_input_close(input); + if (err < 0) { + SNDERR("%s may be old or corrupted: consider to remove or fix it", file); + goto __error; + } + err = find_module(class, top); } - err = snd_mixer_class_register(class, mixer); + if (err >= 0) + err = snd_mixer_class_register(class, mixer); if (err < 0) { __error: + if (top) + snd_config_delete(top); if (class) snd_mixer_class_free(class); return err; } + if (top) + snd_config_delete(top); if (classp) *classp = class; return 0; diff --git a/src/names.c b/src/names.c index 638201af..dbbdaa90 100644 --- a/src/names.c +++ b/src/names.c @@ -75,6 +75,7 @@ static int names_parse(snd_config_t *top, const char *iface, snd_devname_t **lis err = -ENOMEM; goto _err; } + continue; } if (strcmp(id, "comment") == 0) { err = snd_config_get_string(m, (const char **)&comment); @@ -85,6 +86,7 @@ static int names_parse(snd_config_t *top, const char *iface, snd_devname_t **lis err = -ENOMEM; goto _err; } + continue; } } if (name != NULL) { @@ -151,6 +153,7 @@ int snd_names_list(const char *iface, snd_devname_t **list) return -ENOMEM; } } + top = NULL; err = snd_config_top(&top); if (err >= 0) err = snd_input_stdio_open(&in, file, "r"); @@ -169,7 +172,8 @@ int snd_names_list(const char *iface, snd_devname_t **list) } else { SNDERR("cannot access file %s", file); } - snd_config_delete(top); + if (top) + snd_config_delete(top); return err >= 0 ? 0 : err; } -- 2.47.1