summaryrefslogtreecommitdiff
path: root/src/mixer/mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mixer/mixer.c')
-rw-r--r--src/mixer/mixer.c1215
1 files changed, 562 insertions, 653 deletions
diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c
index 85d843fc..cece6541 100644
--- a/src/mixer/mixer.c
+++ b/src/mixer/mixer.c
@@ -3,7 +3,7 @@
* \brief Mixer Interface
* \author Jaroslav Kysela <perex@perex.cz>
* \author Abramo Bagnara <abramo@alsa-project.org>
- * \date 2001
+ * \date 2001-2009
*
* Mixer interface is designed to access mixer elements.
* Callbacks may be used for event handling.
@@ -30,12 +30,49 @@
*
*/
-/*! \page mixer Mixer interface
+/*! \page amixer Mixer interface
-<P>Mixer interface is designed to access the abstracted mixer controls.
-This is an abstraction layer over the hcontrol layer.
+<P>Mixer interface is designed to access the abstracted amixer controls.
-\section mixer_general_overview General overview
+\section amixer_general_overview General overview
+
+\section amixer_global Global mixer
+
+The global mixer exposes basic or all (#SND_AMIXER_ALL) mixer related
+controls to application.
+
+\par Master
+This control element defines playback master volume control for
+whole card.
+
+\section amixer_pcm PCM related mixer
+
+This mixer works with PCM related controls with predefined abstractions.
+
+\subsection amixer_pcm_playback Playback direction
+
+Bellow mixer controls are available for playback PCM.
+
+\par Master
+Playback master volume control.
+
+\par PCM
+Playback PCM stream related volume control.
+
+\subsection amixer_pcm_capture Capture direction
+
+Note that none or any combination of controls might be present, but
+at least Capture control should be implemented in alsa-lib.
+
+\par Capture
+Capture PCM stream related volume control.
+
+\par Source
+Capture Source (enum like Mic,CD,Line etc.).
+
+\par [other] - like CD, Aux, Front Line etc.
+These sources are mixed to PCM input. Both volume and switch might be
+available.
*/
@@ -46,103 +83,342 @@ This is an abstraction layer over the hcontrol layer.
#include <fcntl.h>
#include <sys/ioctl.h>
#include "mixer_local.h"
-
-#ifndef DOC_HIDDEN
-typedef struct _snd_mixer_slave {
- snd_hctl_t *hctl;
- struct list_head list;
-} snd_mixer_slave_t;
-
+#include "mixer_abst.h"
+
+static int ctl_event_handler(snd_ctl_t *ctl,
+ unsigned int mask,
+ snd_ctl_elem_t *elem);
+
+static const char *const build_in_mixers[] = {
+ "none", NULL
+};
+
+static int snd_amixer_open_conf(snd_amixer_t **amixerp,
+ const char *name,
+ snd_config_t *mixer_root,
+ snd_config_t *mixer_conf,
+ snd_pcm_t *pcm_playback,
+ snd_pcm_t *pcm_capture,
+ int mode)
+{
+ const char *str;
+ char *buf = NULL, *buf1 = NULL;
+ int err, idx;
+ snd_config_t *conf, *type_conf = NULL;
+ snd_config_iterator_t i, next;
+ const char *id;
+ const char *lib = NULL, *open_name = NULL;
+ int (*open_func)(snd_amixer_t *amixer,
+ snd_config_t *root,
+ snd_config_t *conf,
+ struct sm_open *sm_open) = NULL;
+#ifndef PIC
+ extern void *snd_amixer_open_symbols(void);
+#endif
+ void *h = NULL;
+ snd_amixer_t *amixer;
+ if (snd_config_get_type(mixer_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ char *val;
+ id = NULL;
+ snd_config_get_id(mixer_conf, &id);
+ val = NULL;
+ snd_config_get_ascii(mixer_conf, &val);
+ SNDERR("Invalid type for mixer %s%sdefinition (id: %s, value: %s)", name ? name : "", name ? " " : "", id, val);
+ free(val);
+ return -EINVAL;
+ }
+ err = snd_config_search(mixer_conf, "type", &conf);
+ if (err < 0) {
+ SNDERR("type is not defined");
+ return err;
+ }
+ err = snd_config_get_id(conf, &id);
+ if (err < 0) {
+ SNDERR("unable to get id");
+ return err;
+ }
+ err = snd_config_get_string(conf, &str);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ return err;
+ }
+ err = snd_config_search_definition(mixer_root, "amixer_type", str, &type_conf);
+ if (err >= 0) {
+ if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ SNDERR("Invalid type for amixer type %s definition", str);
+ goto _err;
+ }
+ snd_config_for_each(i, next, type_conf) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+ if (strcmp(id, "comment") == 0)
+ continue;
+ if (strcmp(id, "lib") == 0) {
+ err = snd_config_get_string(n, &lib);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ goto _err;
+ }
+ continue;
+ }
+ if (strcmp(id, "open") == 0) {
+ err = snd_config_get_string(n, &open_name);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ goto _err;
+ }
+ continue;
+ }
+ SNDERR("Unknown field %s", id);
+ err = -EINVAL;
+ goto _err;
+ }
+ }
+ if (!open_name) {
+ buf = malloc(strlen(str) + 32);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto _err;
+ }
+ open_name = buf;
+ sprintf(buf, "_snd_amixer_%s_open", str);
+ }
+ if (!lib) {
+ const char *const *build_in = build_in_mixers;
+ while (*build_in) {
+ if (!strcmp(*build_in, str))
+ break;
+ build_in++;
+ }
+ if (*build_in == NULL) {
+ buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
+ if (buf1 == NULL) {
+ err = -ENOMEM;
+ goto _err;
+ }
+ lib = buf1;
+ sprintf(buf1, "%s/libasound_module_mixer_%s.so", ALSA_PLUGIN_DIR, str);
+ }
+ }
+#ifndef PIC
+ snd_mixer_open_symbols(); /* this call is for static linking only */
#endif
+ open_func = snd_dlobj_cache_lookup(open_name);
+ if (open_func) {
+ err = 0;
+ goto _err;
+ }
+ h = snd_dlopen(lib, RTLD_NOW);
+ if (h)
+ open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_AMIXER_DLSYM_VERSION));
+ err = 0;
+ if (!h) {
+ SNDERR("Cannot open shared library %s",
+ lib ? lib : "[builtin]");
+ err = -ENOENT;
+ } else if (!open_func) {
+ SNDERR("symbol %s is not defined inside %s", open_name,
+ lib ? lib : "[builtin]");
+ snd_dlclose(h);
+ err = -ENXIO;
+ }
+ _err:
+ if (err >= 0) {
+ amixer = calloc(1, sizeof(*amixer));
+ if (amixer == NULL) {
+ err = -ENOMEM;
+ goto _err1;
+ }
+ INIT_LIST_HEAD(&amixer->elems);
+ amixer->compare = snd_amixer_compare_default;
+ amixer->sm_open.name = name;
+ amixer->sm_open.pcm_playback = pcm_playback;
+ amixer->sm_open.pcm_capture = pcm_capture;
+ amixer->sm_open.mode = mode;
+ err = open_func(amixer, mixer_root, mixer_conf, &amixer->sm_open);
+ if (err < 0) {
+ snd_amixer_close(amixer);
+ goto _err1;
+ }
+ for (idx = 0; idx < SM_CTL_COUNT; idx++) {
+ snd_ctl_t *ctl = amixer->sm_open.ctl[idx];
+ if (ctl == NULL)
+ continue;
+ snd_ctl_set_callback(ctl, ctl_event_handler);
+ snd_ctl_set_callback_private(ctl, amixer);
+ err = snd_hctl_nonblock(ctl, 1);
+ if (err >= 0)
+ err = snd_ctl_subscribe_events(ctl, 1);
+ if (err < 0) {
+ snd_amixer_close(amixer);
+ goto _err1;
+ }
+ }
+ *amixerp = amixer;
+ _err1:
+ if (err >= 0) {
+ if (h /*&& (mode & SND_PCM_KEEP_ALIVE)*/) {
+ snd_dlobj_cache_add(open_name, h, open_func);
+ h = NULL;
+ }
+ amixer->dl_handle = h;
+ err = 0;
+ } else {
+ if (h)
+ snd_dlclose(h);
+ }
+ }
+ if (type_conf)
+ snd_config_delete(type_conf);
+ free(buf);
+ free(buf1);
+ return err;
+}
+
+static int snd_amixer_open_noupdate(snd_amixer_t **amixerp,
+ snd_config_t *root,
+ const char *name,
+ snd_pcm_t *pcm_playback,
+ snd_pcm_t *pcm_capture,
+ int mode,
+ int hop)
+{
+ int err, pcm = pcm_playback || pcm_capture;
+ snd_config_t *mixer_conf;
+ const char *str;
-static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
- const snd_mixer_elem_t *c2);
+ err = snd_config_search_definition(root, pcm ? "amixer_pcm" : "amixer", name, &mixer_conf);
+ if (err < 0) {
+ SNDERR("Uknown amixer %s", name);
+ return err;
+ }
+ if (snd_config_get_string(mixer_conf, &str) >= 0) {
+ err = snd_amixer_open_noupdate(amixerp, root, name, pcm_playback, pcm_capture, mode, hop);
+ } else {
+ snd_config_set_hop(mixer_conf, hop);
+ err = snd_amixer_open_conf(amixerp, name, root, mixer_conf, pcm_playback, pcm_capture, mode);
+ }
+ snd_config_delete(mixer_conf);
+ return err;
+}
+/**
+ * \brief Opens the global or PCM related mixer
+ * \param amixerp Returned amixer handle
+ * \param name ASCII identifier of the mixer handle
+ * \param pcm_playback Playback PCM
+ * \param pcm_capture Capture PCM
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ *
+ * If both pcm_playback and pcm_capture parameters are NULL, the global
+ * mixer is opened.
+ */
+int snd_amixer_open(snd_amixer_t **amixerp,
+ const char *name,
+ snd_pcm_t *pcm_playback,
+ snd_pcm_t *pcm_capture,
+ int mode)
+{
+ int err;
+ assert(amixerp);
+ assert(name);
+ err = snd_config_update();
+ if (err < 0)
+ return err;
+ return snd_amixer_open_noupdate(amixerp, snd_config, name, pcm_playback, pcm_capture, mode, 0);
+}
/**
- * \brief Opens an empty mixer
- * \param mixerp Returned mixer handle
+ * \brief Opens the global or PCM related mixer using local configuration
+ * \param amixerp Returned amixer handle
+ * \param name ASCII identifier of the mixer handle
+ * \param pcm_playback Playback PCM
+ * \param pcm_capture Capture PCM
* \param mode Open mode
+ * \param lconf Local configuration
* \return 0 on success otherwise a negative error code
+ *
+ * If both pcm_playback and pcm_capture parameters are NULL, the global
+ * mixer is opened.
*/
-int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED)
+int snd_amixer_open_lconf(snd_amixer_t **amixerp,
+ const char *name,
+ snd_pcm_t *pcm_playback,
+ snd_pcm_t *pcm_capture,
+ int mode,
+ snd_config_t *lconf)
{
- snd_mixer_t *mixer;
- assert(mixerp);
- mixer = calloc(1, sizeof(*mixer));
- if (mixer == NULL)
- return -ENOMEM;
- INIT_LIST_HEAD(&mixer->slaves);
- INIT_LIST_HEAD(&mixer->classes);
- INIT_LIST_HEAD(&mixer->elems);
- mixer->compare = snd_mixer_compare_default;
- *mixerp = mixer;
- return 0;
+ assert(amixerp);
+ assert(name);
+ assert(lconf);
+ return snd_amixer_open_noupdate(amixerp, lconf, name, pcm_playback, pcm_capture, mode, 0);
}
/**
- * \brief Attach an HCTL element to a mixer element
+ * \brief Attach an CTL element to a amixer element
* \param melem Mixer element
- * \param helem HCTL element
+ * \param elem CTL element
* \return 0 on success otherwise a negative error code
*
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
*/
-int snd_mixer_elem_attach(snd_mixer_elem_t *melem,
- snd_hctl_elem_t *helem)
+int snd_amixer_elem_attach(snd_amixer_elem_t *melem,
+ snd_ctl_elem_t *elem)
{
- bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+ bag_t *bag = snd_ctl_elem_get_callback_private(elem);
int err;
err = bag_add(bag, melem);
if (err < 0)
return err;
- return bag_add(&melem->helems, helem);
+ return bag_add(&melem->helems, elem);
}
/**
- * \brief Detach an HCTL element from a mixer element
+ * \brief Detach an CTL element from a amixer element
* \param melem Mixer element
- * \param helem HCTL element
+ * \param elem CTL element
* \return 0 on success otherwise a negative error code
*
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
*/
-int snd_mixer_elem_detach(snd_mixer_elem_t *melem,
- snd_hctl_elem_t *helem)
+int snd_amixer_elem_detach(snd_amixer_elem_t *melem,
+ snd_ctl_elem_t *elem)
{
- bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+ bag_t *bag = snd_ctl_elem_get_callback_private(elem);
int err;
err = bag_del(bag, melem);
assert(err >= 0);
- err = bag_del(&melem->helems, helem);
+ err = bag_del(&melem->helems, elem);
assert(err >= 0);
return 0;
}
/**
- * \brief Return true if a mixer element does not contain any HCTL elements
+ * \brief Return true if a amixer element does not contain any CTL elements
* \param melem Mixer element
* \return 0 if not empty, 1 if empty
*
- * For use by mixer element class specific code.
+ * For use by amixer element class specific code.
*/
-int snd_mixer_elem_empty(snd_mixer_elem_t *melem)
+int snd_amixer_elem_is_empty(snd_amixer_elem_t *melem)
{
return bag_empty(&melem->helems);
}
-static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
- unsigned int mask)
+static int ctl_elem_event_handler(snd_ctl_elem_t *elem,
+ unsigned int mask)
{
- bag_t *bag = snd_hctl_elem_get_callback_private(helem);
+ bag_t *bag = snd_ctl_elem_get_callback_private(elem);
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
int res = 0;
int err;
bag_iterator_t i, n;
bag_for_each_safe(i, n, bag) {
- snd_mixer_elem_t *melem = bag_iterator_entry(i);
- snd_mixer_class_t *class = melem->class;
- err = class->event(class, mask, helem, melem);
+ snd_amixer_elem_t *melem = bag_iterator_entry(i);
+ err = melem->amixer->event(melem->amixer, mask, elem, melem);
if (err < 0)
res = err;
}
@@ -154,9 +430,8 @@ static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
int err = 0;
bag_iterator_t i, n;
bag_for_each_safe(i, n, bag) {
- snd_mixer_elem_t *melem = bag_iterator_entry(i);
- snd_mixer_class_t *class = melem->class;
- err = class->event(class, mask, helem, melem);
+ snd_amixer_elem_t *melem = bag_iterator_entry(i);
+ err = melem->amixer->event(melem->amixer, mask, elem, melem);
if (err < 0)
return err;
}
@@ -164,176 +439,57 @@ static int hctl_elem_event_handler(snd_hctl_elem_t *helem,
return 0;
}
-static int hctl_event_handler(snd_hctl_t *hctl, unsigned int mask,
- snd_hctl_elem_t *elem)
+static int ctl_event_handler(snd_ctl_t *ctl,
+ unsigned int mask,
+ snd_ctl_elem_t *elem)
{
- snd_mixer_t *mixer = snd_hctl_get_callback_private(hctl);
+ snd_amixer_t *amixer = snd_ctl_get_callback_private(ctl);
int res = 0;
if (mask & SND_CTL_EVENT_MASK_ADD) {
- struct list_head *pos;
bag_t *bag;
int err = bag_new(&bag);
if (err < 0)
return err;
- snd_hctl_elem_set_callback(elem, hctl_elem_event_handler);
- snd_hctl_elem_set_callback_private(elem, bag);
- list_for_each(pos, &mixer->classes) {
- snd_mixer_class_t *c;
- c = list_entry(pos, snd_mixer_class_t, list);
- err = c->event(c, mask, elem, NULL);
- if (err < 0)
- res = err;
- }
+ snd_ctl_elem_set_callback(elem, ctl_elem_event_handler);
+ snd_ctl_elem_set_callback_private(elem, bag);
+ err = amixer->event(amixer, mask, elem, NULL);
+ if (err < 0)
+ return err;
}
return res;
}
-
-/**
- * \brief Attach an HCTL specified with the CTL device name to an opened mixer
- * \param mixer Mixer handle
- * \param name HCTL name (see #snd_hctl_open)
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_attach(snd_mixer_t *mixer, const char *name)
-{
- snd_hctl_t *hctl;
- int err;
-
- err = snd_hctl_open(&hctl, name, 0);
- if (err < 0)
- return err;
- err = snd_mixer_attach_hctl(mixer, hctl);
- if (err < 0) {
- snd_hctl_close(hctl);
- return err;
- }
- return 0;
-}
-
-/**
- * \brief Attach an HCTL to an opened mixer
- * \param mixer Mixer handle
- * \param hctl the HCTL to be attached
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
-{
- snd_mixer_slave_t *slave;
- int err;
-
- assert(hctl);
- slave = calloc(1, sizeof(*slave));
- if (slave == NULL)
- return -ENOMEM;
- err = snd_hctl_nonblock(hctl, 1);
- if (err < 0) {
- snd_hctl_close(hctl);
- free(slave);
- return err;
- }
- snd_hctl_set_callback(hctl, hctl_event_handler);
- snd_hctl_set_callback_private(hctl, mixer);
- slave->hctl = hctl;
- list_add_tail(&slave->list, &mixer->slaves);
- return 0;
-}
-
-/**
- * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
- * \param mixer Mixer handle
- * \param name HCTL previously attached
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_detach(snd_mixer_t *mixer, const char *name)
-{
- struct list_head *pos;
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
- snd_hctl_close(s->hctl);
- list_del(pos);
- free(s);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/**
- * \brief Detach a previously attached HCTL to an opened mixer freeing all related resources
- * \param mixer Mixer handle
- * \param hctl HCTL previously attached
- * \return 0 on success otherwise a negative error code
- *
- * Note: The hctl handle is not closed!
- */
-int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl)
-{
- struct list_head *pos;
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- if (hctl == s->hctl) {
- list_del(pos);
- free(s);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/**
- * \brief Obtain a HCTL pointer associated to given name
- * \param mixer Mixer handle
- * \param name HCTL previously attached
- * \param hctl HCTL pointer
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl)
-{
- struct list_head *pos;
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- if (strcmp(name, snd_hctl_name(s->hctl)) == 0) {
- *hctl = s->hctl;
- return 0;
- }
- }
- return -ENOENT;
-}
-
-static int snd_mixer_throw_event(snd_mixer_t *mixer, unsigned int mask,
- snd_mixer_elem_t *elem)
+static int snd_amixer_throw_event(snd_amixer_t *amixer,
+ unsigned int mask,
+ snd_amixer_elem_t *elem)
{
- mixer->events++;
- if (mixer->callback)
- return mixer->callback(mixer, mask, elem);
+ amixer->events++;
+ if (amixer->callback)
+ return amixer->callback(amixer, mask, elem);
return 0;
}
-static int snd_mixer_elem_throw_event(snd_mixer_elem_t *elem, unsigned int mask)
+static int snd_amixer_elem_throw_event(snd_amixer_elem_t *elem,
+ unsigned int mask)
{
- elem->class->mixer->events++;
+ elem->amixer->events++;
if (elem->callback)
return elem->callback(elem, mask);
return 0;
}
-static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int *dir)
+static int _snd_amixer_find_elem(snd_amixer_t *amixer, snd_amixer_elem_t *elem, int *dir)
{
unsigned int l, u;
int c = 0;
int idx = -1;
- assert(mixer && elem);
- assert(mixer->compare);
+ assert(amixer && elem);
+ assert(amixer->compare);
l = 0;
- u = mixer->count;
+ u = amixer->count;
while (l < u) {
idx = (l + u) / 2;
- c = mixer->compare(elem, mixer->pelems[idx]);
+ c = amixer->compare(elem, amixer->pelems[idx]);
if (c < 0)
u = idx;
else if (c > 0)
@@ -346,38 +502,37 @@ static int _snd_mixer_find_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem, int
}
/**
- * \brief Get private data associated to give mixer element
+ * \brief Get private data associated to give amixer element
* \param elem Mixer element
* \return private data
- *
- * For use by mixer element class specific code.
*/
-void *snd_mixer_elem_get_private(const snd_mixer_elem_t *elem)
+void *snd_amixer_elem_get_private(const snd_amixer_elem_t *elem)
{
return elem->private_data;
}
/**
- * \brief Allocate a new mixer element
- * \param elem Returned mixer element
- * \param type Mixer element type
+ * \brief Allocate a new amixer element
+ * \param amixer Mixer handle
+ * \param elem Returned amixer element
+ * \param id Element identificator
* \param compare_weight Mixer element compare weight
* \param private_data Private data
* \param private_free Private data free callback
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
*/
-int snd_mixer_elem_new(snd_mixer_elem_t **elem,
- snd_mixer_elem_type_t type,
- int compare_weight,
- void *private_data,
- void (*private_free)(snd_mixer_elem_t *elem))
+int snd_amixer_elem_new(snd_amixer_t *amixer,
+ snd_amixer_elem_t **elem,
+ snd_amixer_elem_id_t *id,
+ int compare_weight,
+ void *private_data,
+ void (*private_free)(snd_amixer_elem_t *elem))
{
- snd_mixer_elem_t *melem = calloc(1, sizeof(*melem));
+ snd_amixer_elem_t *melem = calloc(1, sizeof(*melem));
if (melem == NULL)
return -ENOMEM;
- melem->type = type;
+ melem->amixer = amixer;
+ melem->sm.id = *id;
melem->compare_weight = compare_weight;
melem->private_data = private_data;
melem->private_free = private_free;
@@ -387,92 +542,84 @@ int snd_mixer_elem_new(snd_mixer_elem_t **elem,
}
/**
- * \brief Add an element for a registered mixer element class
+ * \brief Add an element for an amixer handle
+ * \param amixer Mixer handle
* \param elem Mixer element
- * \param class Mixer element class
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
*/
-int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class)
+int snd_amixer_elem_add(snd_amixer_t *amixer, snd_amixer_elem_t *elem)
{
int dir, idx;
- snd_mixer_t *mixer = class->mixer;
- elem->class = class;
- if (mixer->count == mixer->alloc) {
- snd_mixer_elem_t **m;
- mixer->alloc += 32;
- m = realloc(mixer->pelems, sizeof(*m) * mixer->alloc);
+ if (amixer->count == amixer->alloc) {
+ snd_amixer_elem_t **m;
+ amixer->alloc += 32;
+ m = realloc(amixer->pelems, sizeof(*m) * amixer->alloc);
if (!m) {
- mixer->alloc -= 32;
+ amixer->alloc -= 32;
return -ENOMEM;
}
- mixer->pelems = m;
+ amixer->pelems = m;
}
- if (mixer->count == 0) {
- list_add_tail(&elem->list, &mixer->elems);
- mixer->pelems[0] = elem;
+ if (amixer->count == 0) {
+ list_add_tail(&elem->list, &amixer->elems);
+ amixer->pelems[0] = elem;
} else {
- idx = _snd_mixer_find_elem(mixer, elem, &dir);
+ idx = _snd_amixer_find_elem(amixer, elem, &dir);
assert(dir != 0);
if (dir > 0) {
- list_add(&elem->list, &mixer->pelems[idx]->list);
+ list_add(&elem->list, &amixer->pelems[idx]->list);
idx++;
} else {
- list_add_tail(&elem->list, &mixer->pelems[idx]->list);
+ list_add_tail(&elem->list, &amixer->pelems[idx]->list);
}
- memmove(mixer->pelems + idx + 1,
- mixer->pelems + idx,
- (mixer->count - idx) * sizeof(snd_mixer_elem_t *));
- mixer->pelems[idx] = elem;
+ memmove(amixer->pelems + idx + 1,
+ amixer->pelems + idx,
+ (amixer->count - idx) * sizeof(snd_amixer_elem_t *));
+ amixer->pelems[idx] = elem;
}
- mixer->count++;
- return snd_mixer_throw_event(mixer, SND_CTL_EVENT_MASK_ADD, elem);
+ amixer->count++;
+ return snd_amixer_throw_event(amixer, SND_CTL_EVENT_MASK_ADD, elem);
}
/**
- * \brief Remove a mixer element
+ * \brief Remove a amixer element
* \param elem Mixer element
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
*/
-int snd_mixer_elem_remove(snd_mixer_elem_t *elem)
+int snd_amixer_elem_remove(snd_amixer_elem_t *elem)
{
- snd_mixer_t *mixer = elem->class->mixer;
+ snd_amixer_t *amixer = elem->amixer;
bag_iterator_t i, n;
int err, idx, dir;
unsigned int m;
assert(elem);
- assert(mixer->count);
- idx = _snd_mixer_find_elem(mixer, elem, &dir);
+ assert(amixer->count);
+ idx = _snd_amixer_find_elem(amixer, elem, &dir);
if (dir != 0)
return -EINVAL;
bag_for_each_safe(i, n, &elem->helems) {
- snd_hctl_elem_t *helem = bag_iterator_entry(i);
- snd_mixer_elem_detach(elem, helem);
+ snd_ctl_elem_t *helem = bag_iterator_entry(i);
+ snd_amixer_elem_detach(elem, helem);
}
- err = snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
+ err = snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_REMOVE);
list_del(&elem->list);
- snd_mixer_elem_free(elem);
- mixer->count--;
- m = mixer->count - idx;
+ snd_amixer_elem_free(elem);
+ amixer->count--;
+ m = amixer->count - idx;
if (m > 0)
- memmove(mixer->pelems + idx,
- mixer->pelems + idx + 1,
- m * sizeof(snd_mixer_elem_t *));
+ memmove(amixer->pelems + idx,
+ amixer->pelems + idx + 1,
+ m * sizeof(snd_amixer_elem_t *));
return err;
}
/**
- * \brief Free a mixer element
+ * \brief Free a amixer element
* \param elem Mixer element
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
*/
-void snd_mixer_elem_free(snd_mixer_elem_t *elem)
+void snd_amixer_elem_free(snd_amixer_elem_t *elem)
{
if (elem->private_free)
elem->private_free(elem);
@@ -483,214 +630,100 @@ void snd_mixer_elem_free(snd_mixer_elem_t *elem)
* \brief Mixer element informations are changed
* \param elem Mixer element
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
*/
-int snd_mixer_elem_info(snd_mixer_elem_t *elem)
+int snd_amixer_elem_info(snd_amixer_elem_t *elem)
{
- return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
+ return snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_INFO);
}
/**
* \brief Mixer element values is changed
* \param elem Mixer element
* \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
- */
-int snd_mixer_elem_value(snd_mixer_elem_t *elem)
-{
- return snd_mixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
-}
-
-/**
- * \brief Register mixer element class
- * \param class Mixer element class
- * \param mixer Mixer handle
- * \return 0 on success otherwise a negative error code
- *
- * For use by mixer element class specific code.
- */
-int snd_mixer_class_register(snd_mixer_class_t *class, snd_mixer_t *mixer)
-{
- struct list_head *pos;
- class->mixer = mixer;
- list_add_tail(&class->list, &mixer->classes);
- if (!class->event)
- return 0;
- list_for_each(pos, &mixer->slaves) {
- int err;
- snd_mixer_slave_t *slave;
- snd_hctl_elem_t *elem;
- slave = list_entry(pos, snd_mixer_slave_t, list);
- elem = snd_hctl_first_elem(slave->hctl);
- while (elem) {
- err = class->event(class, SND_CTL_EVENT_MASK_ADD, elem, NULL);
- if (err < 0)
- return err;
- elem = snd_hctl_elem_next(elem);
- }
- }
- return 0;
-}
-
-/**
- * \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)
+int snd_amixer_elem_value(snd_amixer_elem_t *elem)
{
- unsigned int k;
- snd_mixer_elem_t *e;
- snd_mixer_t *mixer = class->mixer;
- for (k = mixer->count; k > 0; k--) {
- e = mixer->pelems[k-1];
- if (e->class == class)
- snd_mixer_elem_remove(e);
- }
- if (class->private_free)
- class->private_free(class);
- list_del(&class->list);
- free(class);
- return 0;
+ return snd_amixer_elem_throw_event(elem, SND_CTL_EVENT_MASK_VALUE);
}
/**
- * \brief Load a mixer elements
- * \param mixer Mixer handle
+ * \brief Close a amixer and free all related resources
+ * \param amixer Mixer handle
* \return 0 on success otherwise a negative error code
*/
-int snd_mixer_load(snd_mixer_t *mixer)
+int snd_amixer_close(snd_amixer_t *amixer)
{
- struct list_head *pos;
- list_for_each(pos, &mixer->slaves) {
- int err;
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- err = snd_hctl_load(s->hctl);
- if (err < 0)
- return err;
- }
- return 0;
-}
+ int res = 0, i;
-/**
- * \brief Unload all mixer elements and free all related resources
- * \param mixer Mixer handle
- */
-void snd_mixer_free(snd_mixer_t *mixer)
-{
- struct list_head *pos;
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- snd_hctl_free(s->hctl);
- }
-}
-
-/**
- * \brief Close a mixer and free all related resources
- * \param mixer Mixer handle
- * \return 0 on success otherwise a negative error code
- */
-int snd_mixer_close(snd_mixer_t *mixer)
-{
- int res = 0;
- assert(mixer);
- while (!list_empty(&mixer->classes)) {
- snd_mixer_class_t *c;
- c = list_entry(mixer->classes.next, snd_mixer_class_t, list);
- snd_mixer_class_unregister(c);
+ assert(amixer);
+ for (i = 0; i < SM_CTL_COUNT; i++) {
+ if (amixer->sm_open.ctl[i])
+ res = snd_ctl_close(amixer->sm_open.ctl[i]);
+ amixer->sm_open.ctl[i] = NULL;
}
- assert(list_empty(&mixer->elems));
- assert(mixer->count == 0);
- free(mixer->pelems);
- mixer->pelems = NULL;
- while (!list_empty(&mixer->slaves)) {
- int err;
- snd_mixer_slave_t *s;
- s = list_entry(mixer->slaves.next, snd_mixer_slave_t, list);
- err = snd_hctl_close(s->hctl);
- if (err < 0)
- res = err;
- list_del(&s->list);
- free(s);
- }
- free(mixer);
+ assert(list_empty(&amixer->elems));
+ if (amixer->pelems)
+ free(amixer->pelems);
+ if (amixer->dl_handle)
+ snd_dlclose(amixer->dl_handle);
+ free(amixer);
return res;
}
-static int snd_mixer_compare_default(const snd_mixer_elem_t *c1,
- const snd_mixer_elem_t *c2)
-{
- int d = c1->compare_weight - c2->compare_weight;
- if (d)
- return d;
- assert(c1->class && c1->class->compare);
- assert(c2->class && c2->class->compare);
- assert(c1->class == c2->class);
- return c1->class->compare(c1, c2);
-}
-
-static int mixer_compare(const void *a, const void *b)
+static int amixer_compare(const void *a, const void *b)
{
- snd_mixer_t *mixer;
+ snd_amixer_t *amixer;
- mixer = (*((const snd_mixer_elem_t * const *)a))->class->mixer;
- return mixer->compare(*(const snd_mixer_elem_t * const *)a, *(const snd_mixer_elem_t * const *)b);
+ amixer = (*((const snd_amixer_elem_t * const *)a))->amixer;
+ return amixer->compare(*(const snd_amixer_elem_t * const *)a, *(const snd_amixer_elem_t * const *)b);
}
-static int snd_mixer_sort(snd_mixer_t *mixer)
+static int snd_amixer_sort(snd_amixer_t *amixer)
{
unsigned int k;
- assert(mixer);
- assert(mixer->compare);
- INIT_LIST_HEAD(&mixer->elems);
- qsort(mixer->pelems, mixer->count, sizeof(snd_mixer_elem_t *), mixer_compare);
- for (k = 0; k < mixer->count; k++)
- list_add_tail(&mixer->pelems[k]->list, &mixer->elems);
+ assert(amixer);
+ assert(amixer->compare);
+ INIT_LIST_HEAD(&amixer->elems);
+ qsort(amixer->pelems, amixer->count, sizeof(snd_amixer_elem_t *), amixer_compare);
+ for (k = 0; k < amixer->count; k++)
+ list_add_tail(&amixer->pelems[k]->list, &amixer->elems);
return 0;
}
/**
- * \brief Change mixer compare function and reorder elements
- * \param mixer Mixer handle
+ * \brief Change amixer compare function and reorder elements
+ * \param amixer Mixer handle
* \param compare Element compare function
* \return 0 on success otherwise a negative error code
*/
-int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t compare)
+int snd_amixer_set_compare(snd_amixer_t *amixer, snd_amixer_compare_t compare)
{
- snd_mixer_compare_t compare_old;
+ snd_amixer_compare_t compare_old;
int err;
- assert(mixer);
- compare_old = mixer->compare;
- mixer->compare = compare == NULL ? snd_mixer_compare_default : compare;
- if ((err = snd_mixer_sort(mixer)) < 0) {
- mixer->compare = compare_old;
+ assert(amixer);
+ compare_old = amixer->compare;
+ amixer->compare = compare == NULL ? snd_amixer_compare_default : compare;
+ if ((err = snd_amixer_sort(amixer)) < 0) {
+ amixer->compare = compare_old;
return err;
}
return 0;
}
/**
- * \brief get count of poll descriptors for mixer handle
- * \param mixer Mixer handle
+ * \brief get count of poll descriptors for amixer handle
+ * \param amixer Mixer handle
* \return count of poll descriptors
*/
-int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
+int snd_amixer_poll_descriptors_count(snd_amixer_t *amixer)
{
- struct list_head *pos;
- unsigned int c = 0;
- assert(mixer);
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- int n;
- s = list_entry(pos, snd_mixer_slave_t, list);
- n = snd_hctl_poll_descriptors_count(s->hctl);
+ assert(amixer);
+ int i, c = 0, n;
+ for (i = 0; i < SM_CTL_COUNT; i++) {
+ if (amixer->sm_open.ctl[i] == NULL)
+ continue;
+ n = snd_ctl_poll_descriptors_count(amixer->sm_open.ctl[i]);
if (n < 0)
return n;
c += n;
@@ -700,46 +733,46 @@ int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer)
/**
* \brief get poll descriptors
- * \param mixer Mixer handle
+ * \param amixer Mixer handle
* \param pfds array of poll descriptors
* \param space space in the poll descriptor array
* \return count of filled descriptors
*/
-int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
+int snd_amixer_poll_descriptors(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int space)
{
- struct list_head *pos;
- unsigned int count = 0;
- assert(mixer);
- list_for_each(pos, &mixer->slaves) {
- snd_mixer_slave_t *s;
- int n;
- s = list_entry(pos, snd_mixer_slave_t, list);
- n = snd_hctl_poll_descriptors(s->hctl, pfds, space);
+ int i, count = 0, n;
+
+ assert(amixer);
+ for (i = 0; i < SM_CTL_COUNT; i++) {
+ if (amixer->sm_open.ctl[i] == NULL)
+ continue;
+ n = snd_ctl_poll_descriptors(amixer->sm_open.ctl[i], pfds, space);
if (n < 0)
return n;
- if (space >= (unsigned int) n) {
+ if (space >= (unsigned int)n) {
count += n;
space -= n;
pfds += n;
- } else
+ } else {
space = 0;
+ }
}
return count;
}
/**
* \brief get returned events from poll descriptors
- * \param mixer Mixer handle
+ * \param amixer Mixer handle
* \param pfds array of poll descriptors
* \param nfds count of poll descriptors
* \param revents returned events
* \return zero if success, otherwise a negative error code
*/
-int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+int snd_amixer_poll_descriptors_revents(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{
unsigned int idx;
unsigned short res;
- assert(mixer && pfds && revents);
+ assert(amixer && pfds && revents);
if (nfds == 0)
return -EINVAL;
res = 0;
@@ -750,25 +783,25 @@ int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds,
}
/**
- * \brief Wait for a mixer to become ready (i.e. at least one event pending)
- * \param mixer Mixer handle
+ * \brief Wait for a amixer to become ready (i.e. at least one event pending)
+ * \param amixer Mixer handle
* \param timeout maximum time in milliseconds to wait
* \return 0 otherwise a negative error code on failure
*/
-int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
+int snd_amixer_wait(snd_amixer_t *amixer, int timeout)
{
struct pollfd spfds[16];
struct pollfd *pfds = spfds;
int err;
int count;
- count = snd_mixer_poll_descriptors(mixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
+ count = snd_amixer_poll_descriptors(amixer, pfds, sizeof(spfds) / sizeof(spfds[0]));
if (count < 0)
return count;
if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) {
pfds = malloc(count * sizeof(*pfds));
if (!pfds)
return -ENOMEM;
- err = snd_mixer_poll_descriptors(mixer, pfds,
+ err = snd_amixer_poll_descriptors(amixer, pfds,
(unsigned int) count);
assert(err == count);
}
@@ -779,305 +812,181 @@ int snd_mixer_wait(snd_mixer_t *mixer, int timeout)
}
/**
- * \brief get first element for a mixer
- * \param mixer Mixer handle
+ * \brief get first element for a amixer
+ * \param amixer Mixer handle
* \return pointer to first element
*/
-snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer)
+snd_amixer_elem_t *snd_amixer_first_elem(snd_amixer_t *amixer)
{
- assert(mixer);
- if (list_empty(&mixer->elems))
+ assert(amixer);
+ if (list_empty(&amixer->elems))
return NULL;
- return list_entry(mixer->elems.next, snd_mixer_elem_t, list);
+ return list_entry(amixer->elems.next, snd_amixer_elem_t, list);
}
/**
- * \brief get last element for a mixer
- * \param mixer Mixer handle
+ * \brief get last element for a amixer
+ * \param amixer Mixer handle
* \return pointer to last element
*/
-snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer)
+snd_amixer_elem_t *snd_amixer_last_elem(snd_amixer_t *amixer)
{
- assert(mixer);
- if (list_empty(&mixer->elems))
+ assert(amixer);
+ if (list_empty(&amixer->elems))
return NULL;
- return list_entry(mixer->elems.prev, snd_mixer_elem_t, list);
+ return list_entry(amixer->elems.prev, snd_amixer_elem_t, list);
}
/**
- * \brief get next mixer element
- * \param elem mixer element
+ * \brief get next amixer element
+ * \param elem amixer element
* \return pointer to next element
*/
-snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem)
+snd_amixer_elem_t *snd_amixer_elem_next(snd_amixer_elem_t *elem)
{
assert(elem);
- if (elem->list.next == &elem->class->mixer->elems)
+ if (elem->list.next == &elem->amixer->elems)
return NULL;
- return list_entry(elem->list.next, snd_mixer_elem_t, list);
+ return list_entry(elem->list.next, snd_amixer_elem_t, list);
}
/**
- * \brief get previous mixer element
- * \param elem mixer element
+ * \brief get previous amixer element
+ * \param elem amixer element
* \return pointer to previous element
*/
-snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem)
+snd_amixer_elem_t *snd_amixer_elem_prev(snd_amixer_elem_t *elem)
{
assert(elem);
- if (elem->list.prev == &elem->class->mixer->elems)
+ if (elem->list.prev == &elem->amixer->elems)
return NULL;
- return list_entry(elem->list.prev, snd_mixer_elem_t, list);
+ return list_entry(elem->list.prev, snd_amixer_elem_t, list);
}
/**
- * \brief Handle pending mixer events invoking callbacks
- * \param mixer Mixer handle
+ * \brief Handle pending amixer events invoking callbacks
+ * \param amixer Mixer handle
* \return Number of events that occured on success, otherwise a negative error code on failure
*/
-int snd_mixer_handle_events(snd_mixer_t *mixer)
+int snd_amixer_handle_events(snd_amixer_t *amixer)
{
- struct list_head *pos;
- assert(mixer);
- mixer->events = 0;
- list_for_each(pos, &mixer->slaves) {
- int err;
- snd_mixer_slave_t *s;
- s = list_entry(pos, snd_mixer_slave_t, list);
- err = snd_hctl_handle_events(s->hctl);
+ int err, i;
+
+ assert(amixer);
+ amixer->events = 0;
+ for (i = 0; i < SM_CTL_COUNT; i++) {
+ if (amixer->sm_open.ctl[i] == NULL)
+ continue;
+ err = snd_ctl_handle_events(amixer->sm_open.ctl[i]);
if (err < 0)
return err;
}
- return mixer->events;
+ return amixer->events;
}
/**
- * \brief Set callback function for a mixer
- * \param obj mixer handle
+ * \brief Set event callback function for a amixer
+ * \param obj amixer handle
* \param val callback function
+ *
+ * This function is used in the mixer implementation. Use callback
+ * functions to watch events.
*/
-void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val)
+void snd_amixer_set_event(snd_amixer_t *obj, snd_amixer_event_t val)
{
assert(obj);
- obj->callback = val;
-}
-
-/**
- * \brief Set callback private value for a mixer
- * \param mixer mixer handle
- * \param val callback private value
- */
-void snd_mixer_set_callback_private(snd_mixer_t *mixer, void * val)
-{
- assert(mixer);
- mixer->callback_private = val;
-}
-
-/**
- * \brief Get callback private value for a mixer
- * \param mixer mixer handle
- * \return callback private value
- */
-void * snd_mixer_get_callback_private(const snd_mixer_t *mixer)
-{
- assert(mixer);
- return mixer->callback_private;
-}
-
-/**
- * \brief Get elements count for a mixer
- * \param mixer mixer handle
- * \return elements count
- */
-unsigned int snd_mixer_get_count(const snd_mixer_t *mixer)
-{
- assert(mixer);
- return mixer->count;
+ obj->event = val;
}
/**
- * \brief Set callback function for a mixer element
- * \param mixer mixer element
+ * \brief Set callback function for a amixer
+ * \param obj amixer handle
* \param val callback function
*/
-void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val)
-{
- assert(mixer);
- mixer->callback = val;
-}
-
-/**
- * \brief Set callback private value for a mixer element
- * \param mixer mixer element
- * \param val callback private value
- */
-void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *mixer, void * val)
-{
- assert(mixer);
- mixer->callback_private = val;
-}
-
-/**
- * \brief Get callback private value for a mixer element
- * \param mixer mixer element
- * \return callback private value
- */
-void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *mixer)
-{
- assert(mixer);
- return mixer->callback_private;
-}
-
-/**
- * \brief Get type for a mixer element
- * \param mixer mixer element
- * \return mixer element type
- */
-snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *mixer)
-{
- assert(mixer);
- return mixer->type;
-}
-
-
-/**
- * \brief get size of #snd_mixer_class_t
- * \return size in bytes
- */
-size_t snd_mixer_class_sizeof()
-{
- return sizeof(snd_mixer_class_t);
-}
-
-/**
- * \brief allocate an invalid #snd_mixer_class_t using standard malloc
- * \param ptr returned pointer
- * \return 0 on success otherwise negative error code
- */
-int snd_mixer_class_malloc(snd_mixer_class_t **ptr)
-{
- assert(ptr);
- *ptr = calloc(1, sizeof(snd_mixer_class_t));
- if (!*ptr)
- return -ENOMEM;
- return 0;
-}
-
-/**
- * \brief frees a previously allocated #snd_mixer_class_t
- * \param obj pointer to object to free
- */
-void snd_mixer_class_free(snd_mixer_class_t *obj)
-{
- if (obj->private_free)
- obj->private_free(obj);
- free(obj);
-}
-
-/**
- * \brief copy one #snd_mixer_class_t to another
- * \param dst pointer to destination
- * \param src pointer to source
- */
-void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src)
-{
- assert(dst && src);
- *dst = *src;
-}
-
-/**
- * \brief Get a mixer associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return mixer pointer
- */
-snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *obj)
+void snd_amixer_set_callback(snd_amixer_t *obj, snd_amixer_callback_t val)
{
assert(obj);
- return obj->mixer;
+ obj->callback = val;
}
/**
- * \brief Get mixer event callback associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Set callback private value for a amixer
+ * \param obj amixer handle
+ * \param val callback private value
*/
-snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *obj)
+void snd_amixer_set_callback_private(snd_amixer_t *obj, void * val)
{
assert(obj);
- return obj->event;
+ obj->callback_private = val;
}
/**
- * \brief Get mixer private data associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Get callback private value for a amixer
+ * \param amixer amixer handle
+ * \return callback private value
*/
-void *snd_mixer_class_get_private(const snd_mixer_class_t *obj)
+void * snd_amixer_get_callback_private(const snd_amixer_t *amixer)
{
- assert(obj);
- return obj->private_data;
+ assert(amixer);
+ return amixer->callback_private;
}
-
/**
- * \brief Get mixer compare callback associated to given mixer class
- * \param obj Mixer simple class identifier
- * \return event callback pointer
+ * \brief Get elements count for a amixer
+ * \param amixer amixer handle
+ * \return elements count
*/
-snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *obj)
+unsigned int snd_amixer_get_count(const snd_amixer_t *amixer)
{
- assert(obj);
- return obj->compare;
+ assert(amixer);
+ return amixer->count;
}
/**
- * \brief Set mixer event callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param event Event callback
- * \return zero if success, otherwise a negative error code
+ * \brief Set callback function for a amixer element
+ * \param amixer amixer element
+ * \param val callback function
*/
-int snd_mixer_class_set_event(snd_mixer_class_t *obj, snd_mixer_event_t event)
+void snd_amixer_elem_set_callback(snd_amixer_elem_t *amixer, snd_amixer_elem_callback_t val)
{
- assert(obj);
- obj->event = event;
- return 0;
+ assert(amixer);
+ amixer->callback = val;
}
/**
- * \brief Set mixer private data to given mixer class
- * \param obj Mixer simple class identifier
- * \param private_data class private data
- * \return zero if success, otherwise a negative error code
+ * \brief Set callback private value for a amixer element
+ * \param amixer amixer element
+ * \param val callback private value
*/
-int snd_mixer_class_set_private(snd_mixer_class_t *obj, void *private_data)
+void snd_amixer_elem_set_callback_private(snd_amixer_elem_t *amixer, void * val)
{
- assert(obj);
- obj->private_data = private_data;
- return 0;
+ assert(amixer);
+ amixer->callback_private = val;
}
/**
- * \brief Set mixer private data free callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param private_free Mixer class private data free callback
- * \return zero if success, otherwise a negative error code
+ * \brief Get callback private value for a amixer element
+ * \param amixer amixer element
+ * \return callback private value
*/
-int snd_mixer_class_set_private_free(snd_mixer_class_t *obj, void (*private_free)(snd_mixer_class_t *class))
+void * snd_amixer_elem_get_callback_private(const snd_amixer_elem_t *amixer)
{
- assert(obj);
- obj->private_free = private_free;
- return 0;
+ assert(amixer);
+ return amixer->callback_private;
}
/**
- * \brief Set mixer compare callback to given mixer class
- * \param obj Mixer simple class identifier
- * \param compare the compare callback to be used
- * \return zero if success, otherwise a negative error code
+ * \brief Check if ID is generic
+ * \param id string
+ * \return 1 if success, otherwise 0
*/
-int snd_mixer_class_set_compare(snd_mixer_class_t *obj, snd_mixer_compare_t compare)
+int snd_amixer_conf_generic_id(const char *id)
{
- assert(obj);
- obj->compare = compare;
+ static const char ids[3][8] = { "comment", "type", "hint" };
+ unsigned int k;
+ for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) {
+ if (strcmp(id, ids[k]) == 0)
+ return 1;
+ }
return 0;
}