From ecd6846c88d24f2a03895115b8ebf50679af69f3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 12 May 2009 08:05:50 +0200 Subject: Initial amixer implementation + ctl & hctl API merging This patch adds new mixer API which simplifies the previous mixer API (removed mixer class). The control and hcontrol APIs were merged into one. Signed-off-by: Jaroslav Kysela --- Makefile.am | 2 +- include/control.h | 134 ++--- include/mixer.h | 408 ++++++-------- include/mixer_abst.h | 77 ++- include/mixer_old.h | 331 +++++++++++ modules/mixer/Makefile.am | 2 +- modules/mixer/simple/sbase.c | 66 +-- modules/mixer/simple/sbase.h | 27 +- modules/mixer/simple/sbasedl.c | 2 +- src/Makefile.am | 4 +- src/conf/alsa.conf | 25 + src/control/Makefile.am | 3 +- src/control/control.c | 13 +- src/control/control_ext.c | 2 +- src/control/control_hw.c | 2 +- src/control/control_local.h | 34 +- src/control/control_shm.c | 9 +- src/control/hcontrol.c | 657 ++++++++-------------- src/control/hcontrol_old.c | 512 +++++++++++++++++ src/mixer/Makefile.am | 5 +- src/mixer/mixer.c | 1215 +++++++++++++++++++--------------------- src/mixer/mixer_local.h | 50 +- src/mixer/mixer_old.c | 375 +++++++++++++ src/mixer/mixer_old_local.h | 30 + src/mixer/mixer_simple.h | 31 - src/mixer/mixer_symbols.c | 36 ++ src/mixer/simple.c | 885 +++++++++-------------------- src/mixer/simple_abst.c | 420 -------------- src/mixer/simple_none.c | 539 ++++++++++-------- src/mixer/simple_old.c | 805 ++++++++++++++++++++++++++ 30 files changed, 3872 insertions(+), 2829 deletions(-) create mode 100644 include/mixer_old.h create mode 100644 src/control/hcontrol_old.c create mode 100644 src/mixer/mixer_old.c create mode 100644 src/mixer/mixer_old_local.h delete mode 100644 src/mixer/mixer_simple.h create mode 100644 src/mixer/mixer_symbols.c delete mode 100644 src/mixer/simple_abst.c create mode 100644 src/mixer/simple_old.c diff --git a/Makefile.am b/Makefile.am index f0c39c1d..924ae5e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ SUBDIRS += aserver endif if BUILD_MIXER if BUILD_ALISP -SUBDIRS += alsalisp +#SUBDIRS += alsalisp endif endif SUBDIRS += test utils diff --git a/include/control.h b/include/control.h index 2361dc3a..d2076f04 100644 --- a/include/control.h +++ b/include/control.h @@ -4,7 +4,7 @@ * \author Jaroslav Kysela * \author Abramo Bagnara * \author Takashi Iwai - * \date 1998-2001 + * \date 1998-2008 * * Application interface library for the ALSA driver */ @@ -199,14 +199,13 @@ typedef enum _snd_ctl_type { /** Read only (flag for open mode) \hideinitializer */ #define SND_CTL_READONLY 0x0004 +/** Cache (extended) mode (flag for open mode) \hideinitializer */ +#define SND_CTL_CACHE 0x0008 + /** CTL handle */ typedef struct _snd_ctl snd_ctl_t; - -/** Don't destroy the ctl handle when close */ -#define SND_SCTL_NOFREE 0x0001 - -/** SCTL type */ -typedef struct _snd_sctl snd_sctl_t; +/** CTL element handle */ +typedef struct _snd_ctl_elem snd_ctl_elem_t; int snd_card_load(int card); int snd_card_next(int *card); @@ -466,89 +465,72 @@ int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, /** * \defgroup HControl High level Control Interface * \ingroup Control - * The high level control interface. + * The high level control interface. The #SND_CTL_CACHE flag must be + * set to enable this interface. * See \ref hcontrol page for more details. * \{ */ -/** HCTL element handle */ -typedef struct _snd_hctl_elem snd_hctl_elem_t; - -/** HCTL handle */ -typedef struct _snd_hctl snd_hctl_t; - /** - * \brief Compare function for sorting HCTL elements + * \brief Compare function for sorting CTL elements * \param e1 First element * \param e2 Second element * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 */ -typedef int (*snd_hctl_compare_t)(const snd_hctl_elem_t *e1, - const snd_hctl_elem_t *e2); -int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, - const snd_hctl_elem_t *c2); +typedef int (*snd_ctl_compare_t)(const snd_ctl_elem_t *e1, + const snd_ctl_elem_t *e2); +int snd_ctl_compare_fast(const snd_ctl_elem_t *c1, + const snd_ctl_elem_t *c2); /** - * \brief HCTL callback function - * \param hctl HCTL handle + * \brief CTL callback function + * \param ctl CTL handle * \param mask event mask - * \param elem related HCTL element (if any) + * \param elem related CTL element (if any) * \return 0 on success otherwise a negative error code */ -typedef int (*snd_hctl_callback_t)(snd_hctl_t *hctl, - unsigned int mask, - snd_hctl_elem_t *elem); +typedef int (*snd_ctl_callback_t)(snd_ctl_t *ctl, + unsigned int mask, + snd_ctl_elem_t *elem); /** - * \brief HCTL element callback function - * \param elem HCTL element + * \brief CTL element callback function + * \param elem CTL element * \param mask event mask * \return 0 on success otherwise a negative error code */ -typedef int (*snd_hctl_elem_callback_t)(snd_hctl_elem_t *elem, - unsigned int mask); - -int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode); -int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl); -int snd_hctl_close(snd_hctl_t *hctl); -int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock); -int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl); -int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space); -int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -unsigned int snd_hctl_get_count(snd_hctl_t *hctl); -int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort); -snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl); -snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl); -snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id); -void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback); -void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data); -void *snd_hctl_get_callback_private(snd_hctl_t *hctl); -int snd_hctl_load(snd_hctl_t *hctl); -int snd_hctl_free(snd_hctl_t *hctl); -int snd_hctl_handle_events(snd_hctl_t *hctl); -const char *snd_hctl_name(snd_hctl_t *hctl); -int snd_hctl_wait(snd_hctl_t *hctl, int timeout); -snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl); - -snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem); -snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem); -int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info); -int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); -int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); -int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size); -int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv); -int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv); - -snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem); - -void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr); -unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj); -snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj); -const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj); -void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val); -void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj); -void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val); +typedef int (*snd_ctl_elem_callback_t)(snd_ctl_elem_t *elem, + unsigned int mask); + +unsigned int snd_ctl_get_count(snd_ctl_t *ctl); +int snd_ctl_set_compare(snd_ctl_t *ctl, snd_ctl_compare_t hsort); +snd_ctl_elem_t *snd_ctl_first_elem(snd_ctl_t *ctl); +snd_ctl_elem_t *snd_ctl_last_elem(snd_ctl_t *ctl); +snd_ctl_elem_t *snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); +void snd_ctl_set_callback(snd_ctl_t *ctl, snd_ctl_callback_t callback); +void snd_ctl_set_callback_private(snd_ctl_t *ctl, void *data); +void *snd_ctl_get_callback_private(snd_ctl_t *ctl); +int snd_ctl_handle_events(snd_ctl_t *ctl); + +snd_ctl_elem_t *snd_ctl_elem_next(snd_ctl_elem_t *elem); +snd_ctl_elem_t *snd_ctl_elem_prev(snd_ctl_elem_t *elem); +int snd_ctl_celem_info(snd_ctl_elem_t *elem, snd_ctl_elem_info_t * info); +int snd_ctl_celem_read(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_ctl_celem_write(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_ctl_celem_tlv_read(snd_ctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size); +int snd_ctl_celem_tlv_write(snd_ctl_elem_t *elem, const unsigned int *tlv); +int snd_ctl_celem_tlv_command(snd_ctl_elem_t *elem, const unsigned int *tlv); + +snd_ctl_t *snd_ctl_elem_get_ctl(snd_ctl_elem_t *elem); + +void snd_ctl_elem_get_id(const snd_ctl_elem_t *obj, snd_ctl_elem_id_t *ptr); +unsigned int snd_ctl_elem_get_numid(const snd_ctl_elem_t *obj); +snd_ctl_elem_iface_t snd_ctl_elem_get_interface(const snd_ctl_elem_t *obj); +unsigned int snd_ctl_elem_get_device(const snd_ctl_elem_t *obj); +unsigned int snd_ctl_elem_get_subdevice(const snd_ctl_elem_t *obj); +const char *snd_ctl_elem_get_name(const snd_ctl_elem_t *obj); +unsigned int snd_ctl_elem_get_index(const snd_ctl_elem_t *obj); +void snd_ctl_elem_set_callback(snd_ctl_elem_t *obj, snd_ctl_elem_callback_t val); +void * snd_ctl_elem_get_callback_private(const snd_ctl_elem_t *obj); +void snd_ctl_elem_set_callback_private(snd_ctl_elem_t *obj, void * val); /** \} */ @@ -561,6 +543,12 @@ void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val); * \{ */ +/** Don't destroy the ctl handle when close */ +#define SND_SCTL_NOFREE 0x0001 + +/** SCTL type */ +typedef struct _snd_sctl snd_sctl_t; + int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config, snd_config_t *private_data, int mode); int snd_sctl_free(snd_sctl_t *handle); diff --git a/include/mixer.h b/include/mixer.h index df921642..dd79fef8 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -1,10 +1,10 @@ -/** +/* * \file include/mixer.h * \brief Application interface library for the ALSA driver * \author Jaroslav Kysela * \author Abramo Bagnara * \author Takashi Iwai - * \date 1998-2001 + * \date 1998-2009 * * Application interface library for the ALSA driver */ @@ -34,142 +34,27 @@ extern "C" { /** * \defgroup Mixer Mixer Interface - * The mixer interface. + * The amixer interface. * \{ */ -/** Mixer handle */ -typedef struct _snd_mixer snd_mixer_t; -/** Mixer elements class handle */ -typedef struct _snd_mixer_class snd_mixer_class_t; -/** Mixer element handle */ -typedef struct _snd_mixer_elem snd_mixer_elem_t; - -/** - * \brief Mixer callback function - * \param mixer Mixer handle - * \param mask event mask - * \param elem related mixer element (if any) - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl, - unsigned int mask, - snd_mixer_elem_t *elem); - -/** - * \brief Mixer element callback function - * \param elem Mixer element - * \param mask event mask - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem, - unsigned int mask); - -/** - * \brief Compare function for sorting mixer elements - * \param e1 First element - * \param e2 Second element - * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 - */ -typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1, - const snd_mixer_elem_t *e2); - -/** - * \brief Event callback for the mixer class - * \param class_ Mixer class - * \param mask Event mask (SND_CTL_EVENT_*) - * \param helem HCTL element which invoked the event - * \param melem Mixer element associated to HCTL element - * \return zero if success, otherwise a negative error value - */ -typedef int (*snd_mixer_event_t)(snd_mixer_class_t *class_, unsigned int mask, - snd_hctl_elem_t *helem, snd_mixer_elem_t *melem); - - -/** Mixer element type */ -typedef enum _snd_mixer_elem_type { - /* Simple mixer elements */ - SND_MIXER_ELEM_SIMPLE, - SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE -} snd_mixer_elem_type_t; - -int snd_mixer_open(snd_mixer_t **mixer, int mode); -int snd_mixer_close(snd_mixer_t *mixer); -snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer); -snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer); -int snd_mixer_handle_events(snd_mixer_t *mixer); -int snd_mixer_attach(snd_mixer_t *mixer, const char *name); -int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); -int snd_mixer_detach(snd_mixer_t *mixer, const char *name); -int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); -int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl); -int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer); -int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space); -int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_mixer_load(snd_mixer_t *mixer); -void snd_mixer_free(snd_mixer_t *mixer); -int snd_mixer_wait(snd_mixer_t *mixer, int timeout); -int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort); -void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val); -void * snd_mixer_get_callback_private(const snd_mixer_t *obj); -void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val); -unsigned int snd_mixer_get_count(const snd_mixer_t *obj); -int snd_mixer_class_unregister(snd_mixer_class_t *clss); - -snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem); -snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem); -void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val); -void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj); -void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val); -snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj); - -int snd_mixer_class_register(snd_mixer_class_t *class_, snd_mixer_t *mixer); -int snd_mixer_add_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem); -int snd_mixer_remove_elem(snd_mixer_t *mixer, snd_mixer_elem_t *elem); -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_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class_); -int snd_mixer_elem_remove(snd_mixer_elem_t *elem); -void snd_mixer_elem_free(snd_mixer_elem_t *elem); -int snd_mixer_elem_info(snd_mixer_elem_t *elem); -int snd_mixer_elem_value(snd_mixer_elem_t *elem); -int snd_mixer_elem_attach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); -int snd_mixer_elem_detach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); -int snd_mixer_elem_empty(snd_mixer_elem_t *melem); -void *snd_mixer_elem_get_private(const snd_mixer_elem_t *melem); - -size_t snd_mixer_class_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_mixer_class_t using standard alloca - * \param ptr returned pointer - */ -#define snd_mixer_class_alloca(ptr) __snd_alloca(ptr, snd_mixer_class) -int snd_mixer_class_malloc(snd_mixer_class_t **ptr); -void snd_mixer_class_free(snd_mixer_class_t *obj); -void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src); -snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *class_); -snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *class_); -void *snd_mixer_class_get_private(const snd_mixer_class_t *class_); -snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *class_); -int snd_mixer_class_set_event(snd_mixer_class_t *class_, snd_mixer_event_t event); -int snd_mixer_class_set_private(snd_mixer_class_t *class_, void *private_data); -int snd_mixer_class_set_private_free(snd_mixer_class_t *class_, void (*private_free)(snd_mixer_class_t *class_)); -int snd_mixer_class_set_compare(snd_mixer_class_t *class_, snd_mixer_compare_t compare); +/* AMixer elements API */ -/** - * \defgroup SimpleMixer Simple Mixer Interface - * \ingroup Mixer - * The simple mixer interface. - * \{ - */ +/** dlsym version for interface entry callback */ +#define SND_AMIXER_DLSYM_VERSION _dlsym_amixer_001 -/* Simple mixer elements API */ +/** AMixer element operation identifier */ +typedef enum _snd_amixer_elem_type { + /** Playback */ + SND_MIXER_DIR_PLAYBACK = 0, + /** Capture */ + SND_MIXER_DIR_CAPTURE = 1, + /** Common - playback and capture directions are identical */ + SND_MIXER_DIR_COMMON = 2, +} snd_amixer_dir_t; -/** Mixer simple element channel identifier */ -typedef enum _snd_mixer_selem_channel_id { +/** AMixer element channel identifier */ +typedef enum _snd_amixer_elem_channel_id { /** Unknown */ SND_MIXER_SCHN_UNKNOWN = -1, /** Front left */ @@ -193,121 +78,168 @@ typedef enum _snd_mixer_selem_channel_id { SND_MIXER_SCHN_LAST = 31, /** Mono (Front left alias) */ SND_MIXER_SCHN_MONO = SND_MIXER_SCHN_FRONT_LEFT -} snd_mixer_selem_channel_id_t; - -/** Mixer simple element - register options - abstraction level */ -enum snd_mixer_selem_regopt_abstract { - /** no abstraction - try use all universal controls from driver */ - SND_MIXER_SABSTRACT_NONE = 0, - /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */ - SND_MIXER_SABSTRACT_BASIC, -}; - -/** Mixer simple element - register options */ -struct snd_mixer_selem_regopt { - /** structure version */ - int ver; - /** v1: abstract layer selection */ - enum snd_mixer_selem_regopt_abstract abstract; - /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */ - const char *device; - /** v1: playback PCM connected to mixer device (NULL == none) */ - snd_pcm_t *playback_pcm; - /** v1: capture PCM connected to mixer device (NULL == none) */ - snd_pcm_t *capture_pcm; -}; +} snd_amixer_elem_channel_id_t; +/** Mixer handle */ +typedef struct _snd_amixer snd_amixer_t; +/** Mixer element handle */ +typedef struct _snd_amixer_elem snd_amixer_elem_t; /** Mixer simple element identifier */ -typedef struct _snd_mixer_selem_id snd_mixer_selem_id_t; - -const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel); - -int snd_mixer_selem_register(snd_mixer_t *mixer, - struct snd_mixer_selem_regopt *options, - snd_mixer_class_t **classp); -void snd_mixer_selem_get_id(snd_mixer_elem_t *element, - snd_mixer_selem_id_t *id); -const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem); -unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem); -snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, - const snd_mixer_selem_id_t *id); +typedef struct _snd_amixer_elem_id { + char name[60]; + unsigned int index; +} snd_amixer_elem_id_t; -int snd_mixer_selem_is_active(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); -int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); -int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem); +/** + * \brief Mixer callback function + * \param amixer Mixer handle + * \param mask event mask + * \param elem related amixer element (if any) + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_amixer_callback_t)(snd_amixer_t *ctl, + unsigned int mask, + snd_amixer_elem_t *elem); -int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); -int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); -int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); -int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); -int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); -int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); -int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); -int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); -int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); -int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); -int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value); -int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value); -int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir); -int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir); -int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); -int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); -int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value); -int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value); -int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, - long min, long max); -int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, - long min, long max); +/** + * \brief Mixer element callback function + * \param elem Mixer element + * \param mask event mask + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_amixer_elem_callback_t)(snd_amixer_elem_t *elem, + unsigned int mask); -int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem); -int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem); -int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); -int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp); -int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx); +/** + * \brief Compare function for sorting amixer elements + * \param e1 First element + * \param e2 Second element + * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 + */ +typedef int (*snd_amixer_compare_t)(const snd_amixer_elem_t *e1, + const snd_amixer_elem_t *e2); -size_t snd_mixer_selem_id_sizeof(void); +/** + * \brief Event callback for the amixer class + * \param amixer mixer handle + * \param mask Event mask (SND_CTL_EVENT_*) + * \param celem CTL element which invoked the event + * \param melem Mixer element associated to CTL element + * \return zero if success, otherwise a negative error value + */ +typedef int (*snd_amixer_event_t)(snd_amixer_t *amixer, + unsigned int mask, + snd_ctl_elem_t *celem, + snd_amixer_elem_t *melem); + +/** Expose all mixer controls (flag for open mode) \hideinitializer */ +#define SND_AMIXER_ALL 0x00000002 +/** Compatibility mode for older selem API (flag for open mode) \hideinitializer */ +#define SND_AMIXER_COMPAT1 0x40000000 + +int snd_amixer_open(snd_amixer_t **amixer, const char *name, + snd_pcm_t *playback_pcm, snd_pcm_t *capture_pcm, + int mode); +int snd_amixer_close(snd_amixer_t *amixer); +int snd_amixer_handle_events(snd_amixer_t *amixer); +int snd_amixer_poll_descriptors_count(snd_amixer_t *amixer); +int snd_amixer_poll_descriptors(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int space); +int snd_amixer_poll_descriptors_revents(snd_amixer_t *amixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_amixer_wait(snd_amixer_t *amixer, int timeout); +int snd_amixer_set_compare(snd_amixer_t *amixer, snd_amixer_compare_t msort); +void snd_amixer_set_callback(snd_amixer_t *obj, snd_amixer_callback_t val); +void *snd_amixer_get_callback_private(const snd_amixer_t *obj); +void snd_amixer_set_callback_private(snd_amixer_t *obj, void *val); +void snd_amixer_set_event(snd_amixer_t *amixer, snd_amixer_event_t event); +snd_amixer_event_t snd_amixer_get_event(const snd_amixer_t *amixer); +unsigned int snd_amixer_get_count(const snd_amixer_t *obj); +void snd_amixer_set_private(const snd_amixer_t *amixer, void *private_data); +void snd_amixer_set_private_free(const snd_amixer_t *amixer, void (*private_free)(snd_amixer_t *amixer)); +void *snd_amixer_get_private(const snd_amixer_t *amixer); +int snd_amixer_conf_generic_id(const char *id); + +int snd_amixer_compare_default(const snd_amixer_elem_t *c1, const snd_amixer_elem_t *c2); + +snd_amixer_elem_t *snd_amixer_first_elem(snd_amixer_t *amixer); +snd_amixer_elem_t *snd_amixer_last_elem(snd_amixer_t *amixer); +snd_amixer_elem_t *snd_amixer_elem_next(snd_amixer_elem_t *elem); +snd_amixer_elem_t *snd_amixer_elem_prev(snd_amixer_elem_t *elem); +void snd_amixer_elem_set_callback(snd_amixer_elem_t *obj, snd_amixer_elem_callback_t val); +void * snd_amixer_elem_get_callback_private(const snd_amixer_elem_t *obj); +void snd_amixer_elem_set_callback_private(snd_amixer_elem_t *obj, void * val); + +int snd_amixer_add_elem(snd_amixer_t *amixer, snd_amixer_elem_t *elem); +int snd_amixer_remove_elem(snd_amixer_t *amixer, snd_amixer_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)); +int snd_amixer_elem_add(snd_amixer_t *amixer, snd_amixer_elem_t *elem); +int snd_amixer_elem_remove(snd_amixer_elem_t *elem); +void snd_amixer_elem_free(snd_amixer_elem_t *elem); +int snd_amixer_elem_info(snd_amixer_elem_t *elem); +int snd_amixer_elem_value(snd_amixer_elem_t *elem); +int snd_amixer_elem_attach(snd_amixer_elem_t *melem, snd_ctl_elem_t *helem); +int snd_amixer_elem_detach(snd_amixer_elem_t *melem, snd_ctl_elem_t *helem); +int snd_amixer_elem_is_empty(snd_amixer_elem_t *melem); +void *snd_amixer_elem_get_private(const snd_amixer_elem_t *melem); + +const char *snd_amixer_elem_channel_name(snd_amixer_elem_channel_id_t channel); + +void snd_amixer_elem_get_id(snd_amixer_elem_t *element, + snd_amixer_elem_id_t *id); +const char *snd_amixer_elem_get_name(snd_amixer_elem_t *elem); +unsigned int snd_amixer_elem_get_index(snd_amixer_elem_t *elem); +snd_amixer_elem_t *snd_amixer_find_elem(snd_amixer_t *amixer, + const snd_amixer_elem_id_t *id); + +int snd_amixer_elem_is_active(snd_amixer_elem_t *elem); +int snd_amixer_elem_has_channel(snd_amixer_elem_t *obj, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel); +int snd_amixer_elem_has_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_has_volume_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_has_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_has_switch_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); + +int snd_amixer_elem_get_group(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_has_switch_exclusive(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); + +int snd_amixer_elem_ask_vol_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, long *dBvalue); +int snd_amixer_elem_ask_dB_vol(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long dBvalue, int xdir, long *value); +int snd_amixer_elem_get_channels(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_get_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value); +int snd_amixer_elem_get_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value); +int snd_amixer_elem_get_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int *value); +int snd_amixer_elem_get_volume_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max); +int snd_amixer_elem_get_dB_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max); +int snd_amixer_elem_set_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value); +int snd_amixer_elem_set_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value, int xdir); +int snd_amixer_elem_set_volume_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value); +int snd_amixer_elem_set_dB_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, int xdir); +int snd_amixer_elem_set_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value); +int snd_amixer_elem_set_switch_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int value); +int snd_amixer_elem_set_volume_range(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long min, long max); + +int snd_amixer_elem_is_enum(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); +int snd_amixer_elem_get_enum_items(snd_amixer_elem_t *elem); +int snd_amixer_elem_get_enum_item_name(snd_amixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); +int snd_amixer_elem_get_enum_item(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int *idxp); +int snd_amixer_elem_set_enum_item(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int idx); + +size_t snd_amixer_elem_id_sizeof(void); /** \hideinitializer - * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca + * \brief allocate an invalid #snd_amixer_elem_id_t using standard alloca * \param ptr returned pointer */ -#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id) -int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr); -void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj); -void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src); -const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj); -unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj); -void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val); -void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val); - -/** \} */ +#define snd_amixer_elem_id_alloca(ptr) __snd_alloca(ptr, snd_amixer_elem_id) +int snd_amixer_elem_id_malloc(snd_amixer_elem_id_t **ptr); +void snd_amixer_elem_id_free(snd_amixer_elem_id_t *obj); +void snd_amixer_elem_id_copy(snd_amixer_elem_id_t *dst, const snd_amixer_elem_id_t *src); +const char *snd_amixer_elem_id_get_name(const snd_amixer_elem_id_t *obj); +unsigned int snd_amixer_elem_id_get_index(const snd_amixer_elem_id_t *obj); +void snd_amixer_elem_id_set_name(snd_amixer_elem_id_t *obj, const char *val); +void snd_amixer_elem_id_set_index(snd_amixer_elem_id_t *obj, unsigned int val); /** \} */ diff --git a/include/mixer_abst.h b/include/mixer_abst.h index 7844b191..781e9e30 100644 --- a/include/mixer_abst.h +++ b/include/mixer_abst.h @@ -2,7 +2,7 @@ * \file include/mixer_abst.h * \brief Mixer abstract implementation interface library for the ALSA library * \author Jaroslav Kysela - * \date 2005 + * \date 2005-2008 * * Mixer abstact implementation interface library for the ALSA library */ @@ -36,8 +36,11 @@ extern "C" { * \{ */ -#define SM_PLAY 0 -#define SM_CAPT 1 +#define SM_CTL_COUNT 8 + +#define SM_PLAY SND_MIXER_DIR_PLAYBACK +#define SM_CAPT SND_MIXER_DIR_CAPTURE +#define SM_COMM SND_MIXER_DIR_COMMON #define SM_CAP_GVOLUME (1<<1) #define SM_CAP_GSWITCH (1<<2) @@ -55,52 +58,45 @@ extern "C" { /* SM_CAP_* 24-31 => private for module use */ #define SM_OPS_IS_ACTIVE 0 -#define SM_OPS_IS_MONO 1 -#define SM_OPS_IS_CHANNEL 2 -#define SM_OPS_IS_ENUMERATED 3 -#define SM_OPS_IS_ENUMCNT 4 - -#define sm_selem(x) ((sm_selem_t *)((x)->private_data)) -#define sm_selem_ops(x) ((sm_selem_t *)((x)->private_data))->ops +#define SM_OPS_IS_CHANNEL 1 +#define SM_OPS_IS_ENUMERATED 2 +#define SM_OPS_IS_ENUMCNT 3 -typedef struct _sm_selem { - snd_mixer_selem_id_t *id; +typedef struct _sm_elem { + snd_amixer_elem_id_t id; struct sm_elem_ops *ops; unsigned int caps; unsigned int capture_group; -} sm_selem_t; - -typedef struct _sm_class_basic { - char *device; - snd_ctl_t *ctl; - snd_hctl_t *hctl; - snd_ctl_card_info_t *info; -} sm_class_basic_t; +} sm_elem_t; struct sm_elem_ops { - int (*is)(snd_mixer_elem_t *elem, int dir, int cmd, int val); - int (*get_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); - int (*set_range)(snd_mixer_elem_t *elem, int dir, long min, long max); - int (*get_dB_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); - int (*ask_vol_dB)(snd_mixer_elem_t *elem, int dir, long value, long *dbValue); - int (*ask_dB_vol)(snd_mixer_elem_t *elem, int dir, long dbValue, long *value, int xdir); - int (*get_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); - int (*get_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); - int (*set_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value); - int (*set_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value, int xdir); - int (*get_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int *value); - int (*set_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value); - int (*enum_item_name)(snd_mixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf); - int (*get_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *itemp); - int (*set_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int item); + int (*is)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int cmd, int val); + int (*get_channels)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir); + int (*get_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max); + int (*set_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long min, long max); + int (*get_dB_range)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max); + int (*ask_vol_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long value, long *dbValue); + int (*ask_dB_vol)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long dbValue, long *value, int xdir); + int (*get_volume)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value); + int (*get_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long *value); + int (*set_volume)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value); + int (*set_dB)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value, int xdir); + int (*get_switch)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int *value); + int (*set_switch)(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value); + int (*enum_item_name)(snd_amixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf); + int (*get_enum_item)(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int *itemp); + int (*set_enum_item)(snd_amixer_elem_t *elem, snd_amixer_elem_channel_id_t channel, unsigned int item); }; -int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2); +struct sm_open { + const char *name; + snd_pcm_t *pcm_playback; + snd_pcm_t *pcm_capture; + int mode; + snd_ctl_t *ctl[SM_CTL_COUNT]; +}; -int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info); -void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class); -void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data); -void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)); +sm_elem_t *snd_amixer_elem_get_sm(snd_amixer_elem_t *elem); /** \} */ @@ -109,4 +105,3 @@ void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*pr #endif #endif /* __ALSA_MIXER_ABST_H */ - diff --git a/include/mixer_old.h b/include/mixer_old.h new file mode 100644 index 00000000..fc38d346 --- /dev/null +++ b/include/mixer_old.h @@ -0,0 +1,331 @@ +/** + * \file include/mixer_old.h + * \brief Application interface library for the ALSA driver + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \author Takashi Iwai + * \date 1998-2009 + * + * Application interface library for the ALSA driver + */ +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_MIXER_OLD_H +#define __ALSA_MIXER_OLD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup HControl High level Control Interface + * \ingroup Control + * The high level control interface. + * See \ref hcontrol page for more details. + * \{ + */ + +/** HCTL element handle */ +#define snd_hctl_elem_t snd_ctl_elem_t + +/** HCTL handle */ +#define snd_hctl_t snd_ctl_t + +/** + * \brief Compare function for sorting HCTL elements + * \param e1 First element + * \param e2 Second element + * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 + */ +#define snd_hctl_compare_t snd_ctl_compare_t +#define snd_hctl_compare_fast snd_ctl_compare_fast + +/** + * \brief HCTL callback function + * \param hctl HCTL handle + * \param mask event mask + * \param elem related HCTL element (if any) + * \return 0 on success otherwise a negative error code + */ +#define snd_hctl_callback_t snd_ctl_callback_t + +/** + * \brief HCTL element callback function + * \param elem HCTL element + * \param mask event mask + * \return 0 on success otherwise a negative error code + */ +#define snd_hctl_elem_callback_t snd_ctl_elem_callback_t + +int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode); +int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl); +int snd_hctl_close(snd_hctl_t *hctl); +int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock); +int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl); +int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space); +int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +unsigned int snd_hctl_get_count(snd_hctl_t *hctl); +int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort); +snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl); +snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl); +snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id); +void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback); +void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data); +void *snd_hctl_get_callback_private(snd_hctl_t *hctl); +int snd_hctl_load(snd_hctl_t *hctl); +int snd_hctl_free(snd_hctl_t *hctl); +int snd_hctl_handle_events(snd_hctl_t *hctl); +const char *snd_hctl_name(snd_hctl_t *hctl); +int snd_hctl_wait(snd_hctl_t *hctl, int timeout); +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl); + +snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem); +snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem); +int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info); +int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); +int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size); +int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv); +int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv); + +snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem); + +void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr); +unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj); +snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj); +const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj); +unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj); +void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val); +void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj); +void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val); + +/** \} */ + +/** \} */ + +/** + * \defgroup MixerOld Mixer Interface + * The mixer interface. + * \{ + */ + +/** Mixer handle */ +typedef struct _snd_mixer snd_mixer_t; +/** Mixer element handle */ +#define snd_mixer_elem_t snd_amixer_elem_t + +/** + * \brief Mixer callback function + * \param mixer Mixer handle + * \param mask event mask + * \param elem related mixer element (if any) + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl, + unsigned int mask, + snd_mixer_elem_t *elem); + +/** + * \brief Mixer element callback function + * \param elem Mixer element + * \param mask event mask + * \return 0 on success otherwise a negative error code + */ +typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem, + unsigned int mask); + +/** + * \brief Compare function for sorting mixer elements + * \param e1 First element + * \param e2 Second element + * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 + */ +typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1, + const snd_mixer_elem_t *e2); + +/** Mixer element type */ +typedef enum _snd_mixer_elem_type { + /* Simple mixer elements */ + SND_MIXER_ELEM_SIMPLE, + SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE +} snd_mixer_elem_type_t; + +int snd_mixer_open(snd_mixer_t **mixer, int mode); +int snd_mixer_close(snd_mixer_t *mixer); +snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer); +snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer); +int snd_mixer_handle_events(snd_mixer_t *mixer); +int snd_mixer_attach(snd_mixer_t *mixer, const char *name); +int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); +int snd_mixer_detach(snd_mixer_t *mixer, const char *name); +int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); +int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl); +int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer); +int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space); +int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +int snd_mixer_load(snd_mixer_t *mixer); +void snd_mixer_free(snd_mixer_t *mixer); +int snd_mixer_wait(snd_mixer_t *mixer, int timeout); +int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort); +void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val); +void * snd_mixer_get_callback_private(const snd_mixer_t *obj); +void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val); +unsigned int snd_mixer_get_count(const snd_mixer_t *obj); + +snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem); +snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem); +void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val); +void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj); +void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val); +snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj); + +/** + * \defgroup SimpleMixer Simple Mixer Interface + * \ingroup Mixer + * The simple mixer interface. + * \{ + */ + +/* Simple mixer elements API */ + +/** Mixer simple element channel identifier */ +#define snd_mixer_selem_channel_id_t snd_amixer_elem_channel_id_t + +/** Mixer simple element - register options - abstraction level */ +enum snd_mixer_selem_regopt_abstract { + /** no abstraction - try use all universal controls from driver */ + SND_MIXER_SABSTRACT_NONE = 0, + /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */ + SND_MIXER_SABSTRACT_BASIC, +}; + +/** Mixer simple element - register options */ +struct snd_mixer_selem_regopt { + /** structure version */ + int ver; + /** v1: abstract layer selection */ + enum snd_mixer_selem_regopt_abstract abstract; + /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */ + const char *device; + /** v1: playback PCM connected to mixer device (NULL == none) */ + snd_pcm_t *playback_pcm; + /** v1: capture PCM connected to mixer device (NULL == none) */ + snd_pcm_t *capture_pcm; +}; + +/** Mixer simple element identifier */ +#define snd_mixer_selem_id_t snd_amixer_elem_id_t + +const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel); + +int snd_mixer_selem_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options, + void **nothing); +void snd_mixer_selem_get_id(snd_mixer_elem_t *element, + snd_mixer_selem_id_t *id); +const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem); +unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem); +snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, + const snd_mixer_selem_id_t *id); + +int snd_mixer_selem_is_active(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); +int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); +int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem); +int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem); + +int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); +int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); +int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); +int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); +int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); +int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); +int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); +int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); +int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); +int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); +int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); +int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value); +int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value); +int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir); +int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir); +int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); +int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); +int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value); +int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value); +int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, + long min, long max); +int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, + long *min, long *max); +int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, + long min, long max); + +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem); +int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem); +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp); +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx); + +size_t snd_mixer_selem_id_sizeof(void); +/** \hideinitializer + * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca + * \param ptr returned pointer + */ +#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id) +int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr); +void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj); +void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src); +const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj); +unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj); +void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val); +void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val); + +/** \} */ + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_MIXER_OLD_H */ diff --git a/modules/mixer/Makefile.am b/modules/mixer/Makefile.am index 9f5917fe..61272edf 100644 --- a/modules/mixer/Makefile.am +++ b/modules/mixer/Makefile.am @@ -1 +1 @@ -SUBDIRS=simple +#SUBDIRS=simple diff --git a/modules/mixer/simple/sbase.c b/modules/mixer/simple/sbase.c index 97feee89..1aab535a 100644 --- a/modules/mixer/simple/sbase.c +++ b/modules/mixer/simple/sbase.c @@ -34,7 +34,7 @@ * Prototypes */ -static int selem_read(snd_mixer_elem_t *elem); +static int selem_read(snd_amixer_elem_t *elem); /* * Helpers @@ -313,11 +313,11 @@ static void selem_free(snd_mixer_elem_t *elem) free(simple); } -static int simple_event_add1(snd_mixer_class_t *class, +static int simple_event_add1(snd_amixer_t *amixer, snd_hctl_elem_t *helem, struct helem_selector *sel) { - struct bclass_private *priv = snd_mixer_sbasic_get_private(class); + struct bmixer_private *priv = snd_amixer_sbasic_get_private(class); snd_mixer_elem_t *melem; snd_mixer_selem_id_t *id; snd_ctl_elem_info_t *info; @@ -328,12 +328,12 @@ static int simple_event_add1(snd_mixer_class_t *class, long min, max; int err, new = 0; struct list_head *pos; - struct bclass_sid *bsid; + struct bmixer_sid *bsid; struct melem_sids *sid; unsigned int ui; list_for_each(pos, &priv->sids) { - bsid = list_entry(pos, struct bclass_sid, list); + bsid = list_entry(pos, struct bmixer_sid, list); for (ui = 0; ui < bsid->count; ui++) { if (bsid->sids[ui].sid == sel->sid) { sid = &bsid->sids[ui]; @@ -391,7 +391,7 @@ static int simple_event_add1(snd_mixer_class_t *class, hsimple->max = max; snd_mixer_selem_id_set_name(id, sid->sname); snd_mixer_selem_id_set_index(id, sid->sindex); - melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id); + melem = snd_mixer_find_selem(amixer, id); if (!melem) { simple = calloc(1, sizeof(*simple)); if (!simple) { @@ -435,7 +435,7 @@ static int simple_event_add1(snd_mixer_class_t *class, } #endif if (new) - err = snd_mixer_elem_add(melem, class); + err = snd_mixer_elem_add(melem, amixer); else err = snd_mixer_elem_info(melem); if (err < 0) @@ -452,10 +452,10 @@ static int simple_event_add1(snd_mixer_class_t *class, return -EINVAL; } -static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) +static int simple_event_add(snd__amixer_t *amixer, snd_hctl_elem_t *helem) { - struct bclass_private *priv = snd_mixer_sbasic_get_private(class); - struct bclass_selector *sel; + struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer); + struct bmixer_selector *sel; struct helem_selector *hsel; struct list_head *pos; snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); @@ -465,11 +465,11 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) int err; list_for_each(pos, &priv->selectors) { - sel = list_entry(pos, struct bclass_selector, list); + sel = list_entry(pos, struct bmixer_selector, list); for (ui = 0; ui < sel->count; ui++) { hsel = &sel->selectors[ui]; if (hsel->iface == iface && !strcmp(hsel->name, name) && hsel->index == index) { - err = simple_event_add1(class, helem, hsel); + err = simple_event_add1(amixer, helem, hsel); if (err < 0) return err; /* early exit? */ } @@ -478,14 +478,14 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) return 0; } -int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask, +int alsa_mixer_sbasic_event(snd_amixer_t *amixer, unsigned int mask, snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) { int err; if (mask == SND_CTL_EVENT_MASK_REMOVE) return simple_event_remove(helem, melem); if (mask & SND_CTL_EVENT_MASK_ADD) { - err = simple_event_add(class, helem); + err = simple_event_add(amixer, helem); if (err < 0) return err; } @@ -493,7 +493,7 @@ int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask, err = simple_event_remove(helem, melem); if (err < 0) return err; - err = simple_event_add(class, helem); + err = simple_event_add(amixer, helem); if (err < 0) return err; return 0; @@ -511,39 +511,39 @@ int alsa_mixer_sbasic_event(snd_mixer_class_t *class, unsigned int mask, return 0; } -static void sbasic_cpriv_free(snd_mixer_class_t *class) +static void sbasic_cpriv_free(snd_amixer_t *amixer) { - struct bclass_private *priv = snd_mixer_sbasic_get_private(class); - struct bclass_selector *sel; - struct bclass_sid *sid; + struct bmixer_private *priv = snd_amixer_sbasic_get_private(amixer); + struct bmixer_selector *sel; + struct bmixer_sid *sid; struct list_head *pos, *pos1; list_for_each_safe(pos, pos1, &priv->selectors) { - sel = list_entry(pos, struct bclass_selector, list); + sel = list_entry(pos, struct bmixer_selector, list); free(sel); } list_for_each_safe(pos, pos1, &priv->sids) { - sid = list_entry(pos, struct bclass_sid, list); + sid = list_entry(pos, struct bmixer_sid, list); free(sid); } free(priv); } -void alsa_mixer_sbasic_initpriv(snd_mixer_class_t *class, - struct bclass_private *priv) +void alsa_mixer_sbasic_initpriv(snd_amixer_t *amixer, + struct bmixer_private *priv) { INIT_LIST_HEAD(&priv->selectors); INIT_LIST_HEAD(&priv->sids); - snd_mixer_sbasic_set_private(class, priv); - snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free); + snd_mixer_sbasic_set_private(amixer, priv); + snd_mixer_sbasic_set_private_free(amixer, sbasic_cpriv_free); } -int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class, +int alsa_mixer_sbasic_selreg(snd_amixer_t *amixer, struct helem_selector *selectors, unsigned int count) { - struct bclass_private *priv = snd_mixer_sbasic_get_private(class); - struct bclass_selector *sel = calloc(1, sizeof(*sel)); + struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer); + struct bmixer_selector *sel = calloc(1, sizeof(*sel)); if (sel == NULL) return -ENOMEM; @@ -560,12 +560,12 @@ int alsa_mixer_sbasic_selreg(snd_mixer_class_t *class, return 0; } -int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class, +int alsa_mixer_sbasic_sidreg(snd_amixer_t *amixer, struct melem_sids *sids, unsigned int count) { - struct bclass_private *priv = snd_mixer_sbasic_get_private(class); - struct bclass_sid *sid = calloc(1, sizeof(*sid)); + struct bmixer_private *priv = snd_mixer_sbasic_get_private(amixer); + struct bmixer_sid *sid = calloc(1, sizeof(*sid)); if (sid == NULL) return -ENOMEM; @@ -577,8 +577,8 @@ int alsa_mixer_sbasic_sidreg(snd_mixer_class_t *class, } INIT_LIST_HEAD(&priv->selectors); INIT_LIST_HEAD(&priv->sids); - snd_mixer_sbasic_set_private(class, priv); - snd_mixer_sbasic_set_private_free(class, sbasic_cpriv_free); + snd_mixer_sbasic_set_private(amixer, priv); + snd_mixer_sbasic_set_private_free(amixer, sbasic_cpriv_free); } sid->sids = sids; sid->count = count; diff --git a/modules/mixer/simple/sbase.h b/modules/mixer/simple/sbase.h index ee5fe03c..7feedc58 100644 --- a/modules/mixer/simple/sbase.h +++ b/modules/mixer/simple/sbase.h @@ -55,7 +55,7 @@ struct helem_selector { struct helem_base { struct list_head list; - snd_hctl_elem_t *helem; + snd_ctl_elem_t *helem; unsigned short purpose; unsigned int caps; unsigned int inactive: 1; @@ -64,7 +64,6 @@ struct helem_base { }; struct selem_base { - sm_selem_t selem; struct list_head helems; unsigned short sid; struct { @@ -75,37 +74,37 @@ struct selem_base { } dir[2]; }; -struct bclass_selector { +struct bmixer_selector { struct list_head list; struct helem_selector *selectors; unsigned int count; }; -struct bclass_sid { +struct bmixer_sid { struct list_head list; struct melem_sids *sids; unsigned int count; }; -typedef struct bclass_base_ops { - int (*event)(snd_mixer_class_t *class, unsigned int mask, - snd_hctl_elem_t *helem, snd_mixer_elem_t *melem); - int (*selreg)(snd_mixer_class_t *class, +typedef struct bmixer_base_ops { + int (*event)(snd_amixer_t *amixer, unsigned int mask, + snd_ctl_elem_t *helem, snd_amixer_elem_t *melem); + int (*selreg)(snd_amixer_t *amixer, struct helem_selector *selectors, unsigned int count); - int (*sidreg)(snd_mixer_class_t *class, + int (*sidreg)(snd_amixer_t *amixer, struct melem_sids *sids, unsigned int count); -} bclass_base_ops_t; +} bmixer_base_ops_t; -struct bclass_private { +struct bmixer_private { struct list_head selectors; struct list_head sids; void *dl_sbase; - bclass_base_ops_t ops; + bmixer_base_ops_t ops; }; -int mixer_simple_basic_dlopen(snd_mixer_class_t *class, - bclass_base_ops_t **ops); +int mixer_simple_basic_dlopen(snd_amixer_t *amixer, + bmixer_base_ops_t **ops); #endif /* __SMIXER_BASE_H */ diff --git a/modules/mixer/simple/sbasedl.c b/modules/mixer/simple/sbasedl.c index 0137586a..d03ca3ef 100644 --- a/modules/mixer/simple/sbasedl.c +++ b/modules/mixer/simple/sbasedl.c @@ -1,6 +1,6 @@ /* * Mixer Interface - simple abstact module - base library (dlopen function) - * Copyright (c) 2005 by Jaroslav Kysela + * Copyright (c) 2005-2008 by Jaroslav Kysela * * * This library is free software; you can redistribute it and/or modify diff --git a/src/Makefile.am b/src/Makefile.am index 3204fe46..d3e3a714 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,8 +39,8 @@ SUBDIRS += seq libasound_la_LIBADD += seq/libseq.la endif if BUILD_ALISP -SUBDIRS += alisp -libasound_la_LIBADD += alisp/libalisp.la +#SUBDIRS += alisp +#libasound_la_LIBADD += alisp/libalisp.la endif SUBDIRS += compat conf libasound_la_LIBADD += compat/libcompat.la @ALSA_DEPLIBS@ diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf index db642597..8d0d4a29 100644 --- a/src/conf/alsa.conf +++ b/src/conf/alsa.conf @@ -98,6 +98,7 @@ defaults.pcm.modem.device defaults.pcm.device # truncate files via file or tee PCM defaults.pcm.file_format "raw" defaults.pcm.file_truncate true +defaults.amixer.card 0 defaults.rawmidi.card 0 defaults.rawmidi.device 0 defaults.rawmidi.subdevice -1 @@ -367,6 +368,30 @@ ctl.shm { ctl $CTL } +# +# Mixer interface +# + +amixer.default { + type none + @args [ CARD ] + @args.CARD { + type string + default { + @func getenv + vars [ + ALSA_AMIXER_CARD + ALSA_CARD + ] + default { + @func refer + name defaults.amixer.card + } + } + } + card $CARD +} + # # RawMidi interface # diff --git a/src/control/Makefile.am b/src/control/Makefile.am index d4c50c01..eaf6f917 100644 --- a/src/control/Makefile.am +++ b/src/control/Makefile.am @@ -1,7 +1,8 @@ EXTRA_LTLIBRARIES = libcontrol.la libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c \ - control.c control_hw.c setup.c control_symbols.c + control.c control_hw.c hcontrol_old.c \ + setup.c control_symbols.c if BUILD_CTL_PLUGIN_SHM libcontrol_la_SOURCES += control_shm.c endif diff --git a/src/control/control.c b/src/control/control.c index c0907973..0537ad2a 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -88,6 +88,8 @@ snd_ctl_type_t snd_ctl_type(snd_ctl_t *ctl) int snd_ctl_close(snd_ctl_t *ctl) { int err; + + snd_ctl_cache_free(ctl); while (!list_empty(&ctl->async_handlers)) { snd_async_handler_t *h = list_entry(&ctl->async_handlers.next, snd_async_handler_t, hlist); snd_async_del_handler(h); @@ -118,16 +120,18 @@ int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock) } #ifndef DOC_HIDDEN -int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name) +int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name, int mode) { snd_ctl_t *ctl; ctl = calloc(1, sizeof(*ctl)); if (!ctl) return -ENOMEM; ctl->type = type; + ctl->mode = mode; if (name) ctl->name = strdup(name); INIT_LIST_HEAD(&ctl->async_handlers); + INIT_LIST_HEAD(&ctl->elems); *ctlp = ctl; return 0; } @@ -218,7 +222,14 @@ int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsign */ int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe) { + int err; + assert(ctl); + if (ctl->mode & SND_CTL_CACHE) { + err = snd_ctl_cache_load(ctl); + if (err < 0) + return err; + } return ctl->ops->subscribe_events(ctl, subscribe); } diff --git a/src/control/control_ext.c b/src/control/control_ext.c index d1fe8eaa..1f46f6ee 100644 --- a/src/control/control_ext.c +++ b/src/control/control_ext.c @@ -665,7 +665,7 @@ int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode) return -ENXIO; } - err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name); + err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name, mode); if (err < 0) return err; diff --git a/src/control/control_hw.c b/src/control/control_hw.c index e9a6be27..c33d8ca9 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -421,7 +421,7 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) hw->fd = fd; hw->protocol = ver; - err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name); + err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name, mode); if (err < 0) { close(fd); free(hw); diff --git a/src/control/control_local.h b/src/control/control_local.h index fd9f9418..b7518397 100644 --- a/src/control/control_local.h +++ b/src/control/control_local.h @@ -59,42 +59,44 @@ struct _snd_ctl { void *dl_handle; char *name; snd_ctl_type_t type; + int mode; const snd_ctl_ops_t *ops; void *private_data; int nonblock; int poll_fd; struct list_head async_handlers; + struct list_head elems; /* list of all controls */ + unsigned int alloc; + unsigned int count; + snd_ctl_elem_t **pelems; + snd_ctl_compare_t compare; + snd_ctl_callback_t callback; + void *callback_private; }; -struct _snd_hctl_elem { +struct _snd_ctl_elem { snd_ctl_elem_id_t id; /* must be always on top */ struct list_head list; /* links for list of all helems */ int compare_weight; /* compare weight (reversed) */ /* event callback */ - snd_hctl_elem_callback_t callback; + snd_ctl_elem_callback_t callback; void *callback_private; /* links */ - snd_hctl_t *hctl; /* associated handle */ -}; - -struct _snd_hctl { - snd_ctl_t *ctl; - struct list_head elems; /* list of all controls */ - unsigned int alloc; - unsigned int count; - snd_hctl_elem_t **pelems; - snd_hctl_compare_t compare; - snd_hctl_callback_t callback; - void *callback_private; + snd_ctl_t *ctl; /* associated handle */ }; /* make local functions really local */ -#define snd_ctl_new snd1_ctl_new +#define snd_ctl_new snd1_ctl_new +#define snd_ctl_cache_load snd1_ctl_cache_load +#define snd_ctl_cache_free snd1_ctl_cache_free -int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name); +int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name, int mode); int _snd_ctl_poll_descriptor(snd_ctl_t *ctl); #define _snd_ctl_async_descriptor _snd_ctl_poll_descriptor int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode); int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode); int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid); + +int snd_ctl_cache_load(snd_ctl_t *ctl); +int snd_ctl_cache_free(snd_ctl_t *ctl); diff --git a/src/control/control_shm.c b/src/control/control_shm.c index abab3983..721ee69e 100644 --- a/src/control/control_shm.c +++ b/src/control/control_shm.c @@ -535,7 +535,7 @@ int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname shm->socket = sock; shm->ctrl = ctrl; - err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name); + err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name, mode); if (err < 0) { result = err; goto _err; @@ -548,6 +548,13 @@ int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname return err; } ctl->poll_fd = err; + if (mode & SND_CTL_CACHE) { + err = snd_ctl_cache_load(ctl); + if (err < 0) { + snd_ctl_close(ctl); + return err; + } + } *handlep = ctl; return 0; diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c index 181e7672..7128616d 100644 --- a/src/control/hcontrol.c +++ b/src/control/hcontrol.c @@ -1,11 +1,11 @@ /** * \file control/hcontrol.c - * \brief HCTL Interface - High Level CTL + * \brief CTL Interface - High Level Cached Control Elements * \author Jaroslav Kysela * \author Abramo Bagnara * \date 2000 * - * HCTL interface is designed to access preloaded and sorted primitive controls. + * CTL interface is designed to access preloaded and sorted primitive controls. * Callbacks may be used for event handling. * See \ref hcontrol page for more details. */ @@ -31,7 +31,7 @@ * */ -/*! \page hcontrol High level control interface +/*! \page hcontrol High level cached control interface

High level control interface is designed to access preloaded and sorted primitive controls. @@ -60,164 +60,26 @@ to reduce overhead accessing the real controls in kernel drivers. #define NOT_FOUND 1000000000 #endif -static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, - const snd_hctl_elem_t *c2); +static int snd_ctl_compare_default(const snd_ctl_elem_t *c1, + const snd_ctl_elem_t *c2); -/** - * \brief Opens an HCTL - * \param hctlp Returned HCTL handle - * \param name ASCII identifier of the underlying CTL handle - * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) - * \return 0 on success otherwise a negative error code - */ -int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode) -{ - snd_ctl_t *ctl; - int err; - - if ((err = snd_ctl_open(&ctl, name, mode)) < 0) - return err; - err = snd_hctl_open_ctl(hctlp, ctl); - if (err < 0) - snd_ctl_close(ctl); - return err; -} - -/** - * \brief Opens an HCTL - * \param hctlp Returned HCTL handle - * \param ctl underlying CTL handle - * \return 0 on success otherwise a negative error code - */ -int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) -{ - snd_hctl_t *hctl; - - assert(hctlp); - *hctlp = NULL; - if ((hctl = (snd_hctl_t *)calloc(1, sizeof(snd_hctl_t))) == NULL) - return -ENOMEM; - INIT_LIST_HEAD(&hctl->elems); - hctl->ctl = ctl; - *hctlp = hctl; - return 0; -} - -/** - * \brief close HCTL handle - * \param hctl HCTL handle - * \return 0 on success otherwise a negative error code - * - * Closes the specified HCTL handle and frees all associated - * resources. - */ -int snd_hctl_close(snd_hctl_t *hctl) -{ - int err; - - assert(hctl); - err = snd_ctl_close(hctl->ctl); - snd_hctl_free(hctl); - free(hctl); - return err; -} - -/** - * \brief get identifier of HCTL handle - * \param hctl HCTL handle - * \return ascii identifier of HCTL handle - * - * Returns the ASCII identifier of given HCTL handle. It's the same - * identifier specified in snd_hctl_open(). - */ -const char *snd_hctl_name(snd_hctl_t *hctl) -{ - assert(hctl); - return snd_ctl_name(hctl->ctl); -} - -/** - * \brief set nonblock mode - * \param hctl HCTL handle - * \param nonblock 0 = block, 1 = nonblock mode - * \return 0 on success otherwise a negative error code - */ -int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock) -{ - assert(hctl); - return snd_ctl_nonblock(hctl->ctl, nonblock); -} - -/** - * \brief set async mode - * \param hctl HCTL handle - * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) - * \param pid Process ID to signal: 0 current - * \return 0 on success otherwise a negative error code - * - * A signal is raised when a change happens. - */ -int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid) -{ - assert(hctl); - return snd_ctl_async(hctl->ctl, sig, pid); -} - -/** - * \brief get count of poll descriptors for HCTL handle - * \param hctl HCTL handle - * \return count of poll descriptors - */ -int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl) -{ - assert(hctl); - return snd_ctl_poll_descriptors_count(hctl->ctl); -} - -/** - * \brief get poll descriptors - * \param hctl HCTL handle - * \param pfds array of poll descriptors - * \param space space in the poll descriptor array - * \return count of filled descriptors - */ -int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space) -{ - assert(hctl); - return snd_ctl_poll_descriptors(hctl->ctl, pfds, space); -} - -/** - * \brief get returned events from poll descriptors - * \param hctl HCTL 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_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +static int snd_ctl_throw_event(snd_ctl_t *ctl, unsigned int mask, + snd_ctl_elem_t *elem) { - assert(hctl); - return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents); -} - -static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask, - snd_hctl_elem_t *elem) -{ - if (hctl->callback) - return hctl->callback(hctl, mask, elem); + if (ctl->callback) + return ctl->callback(ctl, mask, elem); return 0; } -static int snd_hctl_elem_throw_event(snd_hctl_elem_t *elem, - unsigned int mask) +static int snd_ctl_elem_throw_event(snd_ctl_elem_t *elem, + unsigned int mask) { if (elem->callback) return elem->callback(elem, mask); return 0; } -static int snd_hctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) +static int snd_ctl_compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) { int res; @@ -298,7 +160,7 @@ static int get_compare_weight(const snd_ctl_elem_id_t *id) const char *name = (char *)id->name, *name1; int res, res1; - if ((res = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND) + if ((res = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names, 1000000)) == NOT_FOUND) return NOT_FOUND; if (*name == '\0') return res; @@ -309,32 +171,32 @@ static int get_compare_weight(const snd_ctl_elem_id_t *id) if (name1 != name) { for (; name1 != name && *name1 != ' '; name1--); name = name1; - if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND) + if ((res1 = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names1, 1000)) == NOT_FOUND) return res; res += res1; } else { name = name1; } - if ((res1 = snd_hctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND) + if ((res1 = snd_ctl_compare_mixer_priority_lookup((const char **)&name, names2, 1)) == NOT_FOUND) return res; return res + res1; } -static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, int *dir) +static int _snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, int *dir) { unsigned int l, u; - snd_hctl_elem_t el; + snd_ctl_elem_t el; int c = 0; int idx = -1; - assert(hctl && id); - assert(hctl->compare); + assert(ctl && id); + assert(ctl->compare); el.id = *id; el.compare_weight = get_compare_weight(id); l = 0; - u = hctl->count; + u = ctl->count; while (l < u) { idx = (l + u) / 2; - c = hctl->compare(&el, hctl->pelems[idx]); + c = ctl->compare(&el, ctl->pelems[idx]); if (c < 0) u = idx; else if (c > 0) @@ -346,130 +208,133 @@ static int _snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id, in return idx; } -static int snd_hctl_elem_add(snd_hctl_t *hctl, snd_hctl_elem_t *elem) +static int snd_ctl_elem_add(snd_ctl_t *ctl, snd_ctl_elem_t *elem) { int dir; int idx; elem->compare_weight = get_compare_weight(&elem->id); - if (hctl->count == hctl->alloc) { - snd_hctl_elem_t **h; - hctl->alloc += 32; - h = realloc(hctl->pelems, sizeof(*h) * hctl->alloc); + if (ctl->count == ctl->alloc) { + snd_ctl_elem_t **h; + ctl->alloc += 32; + h = realloc(ctl->pelems, sizeof(*h) * ctl->alloc); if (!h) { - hctl->alloc -= 32; + ctl->alloc -= 32; return -ENOMEM; } - hctl->pelems = h; + ctl->pelems = h; } - if (hctl->count == 0) { - list_add_tail(&elem->list, &hctl->elems); - hctl->pelems[0] = elem; + if (ctl->count == 0) { + list_add_tail(&elem->list, &ctl->elems); + ctl->pelems[0] = elem; } else { - idx = _snd_hctl_find_elem(hctl, &elem->id, &dir); + idx = _snd_ctl_find_elem(ctl, &elem->id, &dir); assert(dir != 0); if (dir > 0) { - list_add(&elem->list, &hctl->pelems[idx]->list); + list_add(&elem->list, &ctl->pelems[idx]->list); idx++; } else { - list_add_tail(&elem->list, &hctl->pelems[idx]->list); + list_add_tail(&elem->list, &ctl->pelems[idx]->list); } - memmove(hctl->pelems + idx + 1, - hctl->pelems + idx, - (hctl->count - idx) * sizeof(snd_hctl_elem_t *)); - hctl->pelems[idx] = elem; + memmove(ctl->pelems + idx + 1, + ctl->pelems + idx, + (ctl->count - idx) * sizeof(snd_ctl_elem_t *)); + ctl->pelems[idx] = elem; } - hctl->count++; - return snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, elem); + ctl->count++; + return snd_ctl_throw_event(ctl, SNDRV_CTL_EVENT_MASK_ADD, elem); } -static void snd_hctl_elem_remove(snd_hctl_t *hctl, unsigned int idx) +static void snd_ctl_celem_remove(snd_ctl_t *ctl, unsigned int idx) { - snd_hctl_elem_t *elem = hctl->pelems[idx]; + snd_ctl_elem_t *elem = ctl->pelems[idx]; unsigned int m; - snd_hctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE); + snd_ctl_elem_throw_event(elem, SNDRV_CTL_EVENT_MASK_REMOVE); list_del(&elem->list); free(elem); - hctl->count--; - m = hctl->count - idx; + ctl->count--; + m = ctl->count - idx; if (m > 0) - memmove(hctl->pelems + idx, - hctl->pelems + idx + 1, - m * sizeof(snd_hctl_elem_t *)); + memmove(ctl->pelems + idx, + ctl->pelems + idx + 1, + m * sizeof(snd_ctl_elem_t *)); } +#ifndef DOC_HIDDEN /** - * \brief free HCTL loaded elements - * \param hctl HCTL handle + * \brief free cached elements + * \param ctl CTL handle * \return 0 on success otherwise a negative error code */ -int snd_hctl_free(snd_hctl_t *hctl) +int snd_ctl_cache_free(snd_ctl_t *ctl) { - while (hctl->count > 0) - snd_hctl_elem_remove(hctl, hctl->count - 1); - free(hctl->pelems); - hctl->pelems = 0; - hctl->alloc = 0; - INIT_LIST_HEAD(&hctl->elems); + while (ctl->count > 0) + snd_ctl_celem_remove(ctl, ctl->count - 1); + if (ctl->pelems) + free(ctl->pelems); + ctl->pelems = 0; + ctl->alloc = 0; + INIT_LIST_HEAD(&ctl->elems); return 0; } +#endif -static snd_hctl_t *compare_hctl; -static int hctl_compare(const void *a, const void *b) { - return compare_hctl->compare(*(const snd_hctl_elem_t * const *) a, - *(const snd_hctl_elem_t * const *) b); +static snd_ctl_t *compare_ctl; +static int ctl_compare(const void *a, const void *b) { + return compare_ctl->compare(*(const snd_ctl_elem_t * const *) a, + *(const snd_ctl_elem_t * const *) b); } -static void snd_hctl_sort(snd_hctl_t *hctl) +static void snd_ctl_sort(snd_ctl_t *ctl) { unsigned int k; #ifdef HAVE_LIBPTHREAD static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER; #endif - assert(hctl); - assert(hctl->compare); - INIT_LIST_HEAD(&hctl->elems); + assert(ctl); + assert(ctl->compare); + INIT_LIST_HEAD(&ctl->elems); #ifdef HAVE_LIBPTHREAD pthread_mutex_lock(&sync_lock); #endif - compare_hctl = hctl; - qsort(hctl->pelems, hctl->count, sizeof(*hctl->pelems), hctl_compare); + compare_ctl = ctl; + qsort(ctl->pelems, ctl->count, sizeof(*ctl->pelems), ctl_compare); #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&sync_lock); #endif - for (k = 0; k < hctl->count; k++) - list_add_tail(&hctl->pelems[k]->list, &hctl->elems); + for (k = 0; k < ctl->count; k++) + list_add_tail(&ctl->pelems[k]->list, &ctl->elems); } /** - * \brief Change HCTL compare function and reorder elements - * \param hctl HCTL handle + * \brief Change CTL compare function and reorder elements + * \param ctl CTL handle * \param compare Element compare function * \return 0 on success otherwise a negative error code */ -int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare) +int snd_ctl_set_compare(snd_ctl_t *ctl, snd_ctl_compare_t compare) { - assert(hctl); - hctl->compare = compare == NULL ? snd_hctl_compare_default : compare; - snd_hctl_sort(hctl); + assert(ctl); + ctl->compare = compare == NULL ? snd_ctl_compare_default : compare; + snd_ctl_sort(ctl); return 0; } /** - * \brief A "don't care" fast compare functions that may be used with #snd_hctl_set_compare - * \param c1 First HCTL element - * \param c2 Second HCTL element + * \brief A "don't care" fast compare functions that may be used with #snd_ctl_set_compare + * \param c1 First CTL element + * \param c2 Second CTL element * \return -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2 */ -int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, - const snd_hctl_elem_t *c2) +int snd_ctl_compare_fast(const snd_ctl_elem_t *c1, + const snd_ctl_elem_t *c2) { return c1->id.numid - c2->id.numid; } -static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, - const snd_hctl_elem_t *c2) +static int snd_ctl_compare_default(const snd_ctl_elem_t *c1, + const snd_ctl_elem_t *c2) { int res; int d = c1->id.iface - c2->id.iface; @@ -488,248 +353,187 @@ static int snd_hctl_compare_default(const snd_hctl_elem_t *c1, } /** - * \brief get first element for an HCTL - * \param hctl HCTL handle + * \brief get first element for an CTL + * \param ctl CTL handle * \return pointer to first element */ -snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl) +snd_ctl_elem_t *snd_ctl_first_elem(snd_ctl_t *ctl) { - assert(hctl); - if (list_empty(&hctl->elems)) + assert(ctl); + if (list_empty(&ctl->elems)) return NULL; - return list_entry(hctl->elems.next, snd_hctl_elem_t, list); + return list_entry(ctl->elems.next, snd_ctl_elem_t, list); } /** - * \brief get last element for an HCTL - * \param hctl HCTL handle + * \brief get last element for an CTL + * \param ctl CTL handle * \return pointer to last element */ -snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl) +snd_ctl_elem_t *snd_ctl_last_elem(snd_ctl_t *ctl) { - assert(hctl); - if (list_empty(&hctl->elems)) + assert(ctl); + if (list_empty(&ctl->elems)) return NULL; - return list_entry(hctl->elems.prev, snd_hctl_elem_t, list); + return list_entry(ctl->elems.prev, snd_ctl_elem_t, list); } /** - * \brief get next HCTL element - * \param elem HCTL element + * \brief get next CTL element + * \param elem CTL element * \return pointer to next element */ -snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem) +snd_ctl_elem_t *snd_ctl_elem_next(snd_ctl_elem_t *elem) { assert(elem); - if (elem->list.next == &elem->hctl->elems) + if (elem->list.next == &elem->ctl->elems) return NULL; - return list_entry(elem->list.next, snd_hctl_elem_t, list); + return list_entry(elem->list.next, snd_ctl_elem_t, list); } /** - * \brief get previous HCTL element - * \param elem HCTL element + * \brief get previous CTL element + * \param elem CTL element * \return pointer to previous element */ -snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem) +snd_ctl_elem_t *snd_ctl_elem_prev(snd_ctl_elem_t *elem) { assert(elem); - if (elem->list.prev == &elem->hctl->elems) + if (elem->list.prev == &elem->ctl->elems) return NULL; - return list_entry(elem->list.prev, snd_hctl_elem_t, list); + return list_entry(elem->list.prev, snd_ctl_elem_t, list); } /** - * \brief Search an HCTL element - * \param hctl HCTL handle + * \brief Search an CTL element + * \param ctl CTL handle * \param id Element identifier - * \return pointer to found HCTL element or NULL if it does not exists + * \return pointer to found CTL element or NULL if it does not exists */ -snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id) +snd_ctl_elem_t *snd_ctl_find_elem(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id) { int dir; - int res = _snd_hctl_find_elem(hctl, id, &dir); + int res = _snd_ctl_find_elem(ctl, id, &dir); if (res < 0 || dir != 0) return NULL; - return hctl->pelems[res]; + return ctl->pelems[res]; } +#ifndef DOC_HIDDEN /** - * \brief Load an HCTL with all elements and sort them - * \param hctl HCTL handle + * \brief Load an CTL with all elements and sort them + * \param ctl CTL handle * \return 0 on success otherwise a negative error code */ -int snd_hctl_load(snd_hctl_t *hctl) +int snd_ctl_cache_load(snd_ctl_t *ctl) { snd_ctl_elem_list_t list; int err = 0; unsigned int idx; - assert(hctl); - assert(hctl->ctl); - assert(hctl->count == 0); - assert(list_empty(&hctl->elems)); + assert(ctl); + assert(ctl->count == 0); + assert(list_empty(&ctl->elems)); memset(&list, 0, sizeof(list)); - if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) + if ((err = snd_ctl_elem_list(ctl, &list)) < 0) goto _end; while (list.count != list.used) { + if (list.space) + snd_ctl_elem_list_free_space(&list); err = snd_ctl_elem_list_alloc_space(&list, list.count); if (err < 0) goto _end; - if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) + if ((err = snd_ctl_elem_list(ctl, &list)) < 0) goto _end; } - if (hctl->alloc < list.count) { - hctl->alloc = list.count; - free(hctl->pelems); - hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems)); - if (!hctl->pelems) { + if (ctl->alloc < list.count) { + ctl->alloc = list.count; + free(ctl->pelems); + ctl->pelems = malloc(ctl->alloc * sizeof(*ctl->pelems)); + if (!ctl->pelems) { err = -ENOMEM; goto _end; } } for (idx = 0; idx < list.count; idx++) { - snd_hctl_elem_t *elem; - elem = calloc(1, sizeof(snd_hctl_elem_t)); + snd_ctl_elem_t *elem; + elem = calloc(1, sizeof(snd_ctl_elem_t)); if (elem == NULL) { - snd_hctl_free(hctl); + snd_ctl_cache_free(ctl); err = -ENOMEM; goto _end; } elem->id = list.pids[idx]; - elem->hctl = hctl; + elem->ctl = ctl; elem->compare_weight = get_compare_weight(&elem->id); - hctl->pelems[idx] = elem; - list_add_tail(&elem->list, &hctl->elems); - hctl->count++; + ctl->pelems[idx] = elem; + list_add_tail(&elem->list, &ctl->elems); + ctl->count++; } - if (!hctl->compare) - hctl->compare = snd_hctl_compare_default; - snd_hctl_sort(hctl); - for (idx = 0; idx < hctl->count; idx++) { - int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, - hctl->pelems[idx]); + if (!ctl->compare) + ctl->compare = snd_ctl_compare_default; + snd_ctl_sort(ctl); + for (idx = 0; idx < ctl->count; idx++) { + int res = snd_ctl_throw_event(ctl, SNDRV_CTL_EVENT_MASK_ADD, + ctl->pelems[idx]); if (res < 0) return res; } - err = snd_ctl_subscribe_events(hctl->ctl, 1); _end: - free(list.pids); + snd_ctl_elem_list_free_space(&list); return err; } +#endif /** - * \brief Set callback function for an HCTL - * \param hctl HCTL handle + * \brief Set callback function for an CTL + * \param ctl CTL handle * \param callback callback function */ -void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback) +void snd_ctl_set_callback(snd_ctl_t *ctl, snd_ctl_callback_t callback) { - assert(hctl); - hctl->callback = callback; + assert(ctl); + ctl->callback = callback; } /** - * \brief Set callback private value for an HCTL - * \param hctl HCTL handle + * \brief Set callback private value for an CTL + * \param ctl CTL handle * \param callback_private callback private value */ -void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private) +void snd_ctl_set_callback_private(snd_ctl_t *ctl, void *callback_private) { - assert(hctl); - hctl->callback_private = callback_private; + assert(ctl); + ctl->callback_private = callback_private; } /** - * \brief Get callback private value for an HCTL - * \param hctl HCTL handle + * \brief Get callback private value for an CTL + * \param ctl CTL handle * \return callback private value */ -void *snd_hctl_get_callback_private(snd_hctl_t *hctl) +void *snd_ctl_get_callback_private(snd_ctl_t *ctl) { - assert(hctl); - return hctl->callback_private; + assert(ctl); + return ctl->callback_private; } /** - * \brief Get number of loaded elements for an HCTL - * \param hctl HCTL handle + * \brief Get number of loaded elements for an CTL + * \param ctl CTL handle * \return elements count */ -unsigned int snd_hctl_get_count(snd_hctl_t *hctl) -{ - return hctl->count; -} - -/** - * \brief Wait for a HCTL to become ready (i.e. at least one event pending) - * \param hctl HCTL handle - * \param timeout maximum time in milliseconds to wait - * \return a positive value on success otherwise a negative error code - * \retval 0 timeout occurred - * \retval 1 an event is pending - */ -int snd_hctl_wait(snd_hctl_t *hctl, int timeout) -{ - struct pollfd *pfd; - unsigned short *revents; - int i, npfds, pollio, err, err_poll; - - npfds = snd_hctl_poll_descriptors_count(hctl); - if (npfds <= 0 || npfds >= 16) { - SNDERR("Invalid poll_fds %d\n", npfds); - return -EIO; - } - pfd = alloca(sizeof(*pfd) * npfds); - revents = alloca(sizeof(*revents) * npfds); - err = snd_hctl_poll_descriptors(hctl, pfd, npfds); - if (err < 0) - return err; - if (err != npfds) { - SNDMSG("invalid poll descriptors %d\n", err); - return -EIO; - } - do { - pollio = 0; - err_poll = poll(pfd, npfds, timeout); - if (err_poll < 0) { - if (errno == EINTR) - continue; - return -errno; - } - if (! err_poll) - break; - err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents); - if (err < 0) - return err; - for (i = 0; i < npfds; i++) { - if (revents[i] & (POLLERR | POLLNVAL)) - return -EIO; - if ((revents[i] & (POLLIN | POLLOUT)) == 0) - continue; - pollio++; - } - } while (! pollio); - return err_poll > 0 ? 1 : 0; -} - -/** - * \brief Get a ctl handle associated to the given hctl handle - * \param hctl HCTL handle - * \return a ctl handle otherwise NULL - */ -snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) +unsigned int snd_ctl_get_count(snd_ctl_t *ctl) { - return hctl->ctl; + return ctl->count; } -static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) +static int snd_ctl_handle_event(snd_ctl_t *ctl, snd_ctl_event_t *event) { - snd_hctl_elem_t *elem; + snd_ctl_elem_t *elem; int res; - assert(hctl); - assert(hctl->ctl); + assert(ctl); switch (event->type) { case SND_CTL_EVENT_ELEM: break; @@ -738,30 +542,30 @@ static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) } if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) { int dir; - res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir); + res = _snd_ctl_find_elem(ctl, &event->data.elem.id, &dir); assert(res >= 0 && dir == 0); if (res < 0 || dir != 0) return -ENOENT; - snd_hctl_elem_remove(hctl, (unsigned int) res); + snd_ctl_celem_remove(ctl, (unsigned int) res); return 0; } if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) { - elem = calloc(1, sizeof(snd_hctl_elem_t)); + elem = calloc(1, sizeof(snd_ctl_elem_t)); if (elem == NULL) return -ENOMEM; elem->id = event->data.elem.id; - elem->hctl = hctl; - res = snd_hctl_elem_add(hctl, elem); + elem->ctl = ctl; + res = snd_ctl_elem_add(ctl, elem); if (res < 0) return res; } if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO)) { - elem = snd_hctl_find_elem(hctl, &event->data.elem.id); + elem = snd_ctl_find_elem(ctl, &event->data.elem.id); assert(elem); if (!elem) return -ENOENT; - res = snd_hctl_elem_throw_event(elem, event->data.elem.mask & + res = snd_ctl_elem_throw_event(elem, event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO)); if (res < 0) @@ -771,23 +575,22 @@ static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) } /** - * \brief Handle pending HCTL events invoking callbacks - * \param hctl HCTL handle + * \brief Handle pending CTL events invoking callbacks + * \param ctl CTL handle * \return 0 otherwise a negative error code on failure */ -int snd_hctl_handle_events(snd_hctl_t *hctl) +int snd_ctl_handle_events(snd_ctl_t *ctl) { snd_ctl_event_t event; int res; unsigned int count = 0; - assert(hctl); - assert(hctl->ctl); - while ((res = snd_ctl_read(hctl->ctl, &event)) != 0 && + assert(ctl); + while ((res = snd_ctl_read(ctl, &event)) != 0 && res != -EAGAIN) { if (res < 0) return res; - res = snd_hctl_handle_event(hctl, &event); + res = snd_ctl_handle_event(ctl, &event); if (res < 0) return res; count++; @@ -796,108 +599,108 @@ int snd_hctl_handle_events(snd_hctl_t *hctl) } /** - * \brief Get information for an HCTL element - * \param elem HCTL element - * \param info HCTL element information + * \brief Get information for an CTL element + * \param elem CTL element + * \param info CTL element information * \return 0 otherwise a negative error code on failure */ -int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info) +int snd_ctl_celem_info(snd_ctl_elem_t *elem, snd_ctl_elem_info_t *info) { assert(elem); - assert(elem->hctl); + assert(elem->ctl); assert(info); info->id = elem->id; - return snd_ctl_elem_info(elem->hctl->ctl, info); + return snd_ctl_elem_info(elem->ctl, info); } /** - * \brief Get value for an HCTL element - * \param elem HCTL element - * \param value HCTL element value + * \brief Get value for an CTL element + * \param elem CTL element + * \param value CTL element value * \return 0 otherwise a negative error code on failure */ -int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +int snd_ctl_celem_read(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value) { assert(elem); - assert(elem->hctl); + assert(elem->ctl); assert(value); value->id = elem->id; - return snd_ctl_elem_read(elem->hctl->ctl, value); + return snd_ctl_elem_read(elem->ctl, value); } /** - * \brief Set value for an HCTL element - * \param elem HCTL element - * \param value HCTL element value + * \brief Set value for an CTL element + * \param elem CTL element + * \param value CTL element value * \retval 0 on success * \retval >1 on success when value was changed * \retval <0 a negative error code on failure */ -int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +int snd_ctl_celem_write(snd_ctl_elem_t *elem, snd_ctl_elem_value_t * value) { assert(elem); - assert(elem->hctl); + assert(elem->ctl); assert(value); value->id = elem->id; - return snd_ctl_elem_write(elem->hctl->ctl, value); + return snd_ctl_elem_write(elem->ctl, value); } /** - * \brief Get TLV value for an HCTL element - * \param elem HCTL element + * \brief Get TLV value for an CTL element + * \param elem CTL element * \param tlv TLV array for value * \param tlv_size size of TLV array in bytes * \return 0 otherwise a negative error code on failure */ -int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) +int snd_ctl_celem_tlv_read(snd_ctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) { assert(elem); assert(tlv); assert(tlv_size >= 12); - return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size); + return snd_ctl_elem_tlv_read(elem->ctl, &elem->id, tlv, tlv_size); } /** - * \brief Set TLV value for an HCTL element - * \param elem HCTL element + * \brief Set TLV value for an CTL element + * \param elem CTL element * \param tlv TLV array for value * \retval 0 on success * \retval >1 on success when value was changed * \retval <0 a negative error code on failure */ -int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv) +int snd_ctl_celem_tlv_write(snd_ctl_elem_t *elem, const unsigned int *tlv) { assert(elem); assert(tlv); assert(tlv[1] >= 4); - return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv); + return snd_ctl_elem_tlv_write(elem->ctl, &elem->id, tlv); } /** - * \brief Set TLV value for an HCTL element - * \param elem HCTL element + * \brief Set TLV value for an CTL element + * \param elem CTL element * \param tlv TLV array for value * \retval 0 on success * \retval >1 on success when value was changed * \retval <0 a negative error code on failure */ -int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv) +int snd_ctl_celem_tlv_command(snd_ctl_elem_t *elem, const unsigned int *tlv) { assert(elem); assert(tlv); assert(tlv[1] >= 4); - return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv); + return snd_ctl_elem_tlv_command(elem->ctl, &elem->id, tlv); } /** - * \brief Get HCTL handle for an HCTL element - * \param elem HCTL element - * \return HCTL handle + * \brief Get CTL handle for an CTL element + * \param elem CTL element + * \return CTL handle */ -snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) +snd_ctl_t *snd_ctl_elem_get_ctl(snd_ctl_elem_t *elem) { assert(elem); - return elem->hctl; + return elem->ctl; } /** @@ -905,7 +708,7 @@ snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) * \param obj CTL element id/value * \param ptr Pointer to returned CTL element identifier */ -void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) +void snd_ctl_elem_get_id(const snd_ctl_elem_t *obj, snd_ctl_elem_id_t *ptr) { assert(obj && ptr); *ptr = obj->id; @@ -916,7 +719,7 @@ void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) * \param obj CTL element id/value * \return element numeric identifier */ -unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) +unsigned int snd_ctl_elem_get_numid(const snd_ctl_elem_t *obj) { assert(obj); return obj->id.numid; @@ -927,7 +730,7 @@ unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) * \param obj CTL element id/value * \return interface part of element identifier */ -snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) +snd_ctl_elem_iface_t snd_ctl_elem_get_interface(const snd_ctl_elem_t *obj) { assert(obj); return obj->id.iface; @@ -938,7 +741,7 @@ snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) * \param obj CTL element id/value * \return device part of element identifier */ -unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) +unsigned int snd_ctl_elem_get_device(const snd_ctl_elem_t *obj) { assert(obj); return obj->id.device; @@ -949,7 +752,7 @@ unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) * \param obj CTL element id/value * \return subdevice part of element identifier */ -unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) +unsigned int snd_ctl_elem_get_subdevice(const snd_ctl_elem_t *obj) { assert(obj); return obj->id.subdevice; @@ -960,7 +763,7 @@ unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) * \param obj CTL element id/value * \return name part of element identifier */ -const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) +const char *snd_ctl_elem_get_name(const snd_ctl_elem_t *obj) { assert(obj); return (const char *)obj->id.name; @@ -971,40 +774,40 @@ const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) * \param obj CTL element id/value * \return index part of element identifier */ -unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj) +unsigned int snd_ctl_elem_get_index(const snd_ctl_elem_t *obj) { assert(obj); return obj->id.index; } /** - * \brief Set callback function for an HCTL element - * \param obj HCTL element + * \brief Set callback function for an CTL element + * \param obj CTL element * \param val callback function */ -void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val) +void snd_ctl_elem_set_callback(snd_ctl_elem_t *obj, snd_ctl_elem_callback_t val) { assert(obj); obj->callback = val; } /** - * \brief Set callback private value for an HCTL element - * \param obj HCTL element + * \brief Set callback private value for an CTL element + * \param obj CTL element * \param val callback private value */ -void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val) +void snd_ctl_elem_set_callback_private(snd_ctl_elem_t *obj, void * val) { assert(obj); obj->callback_private = val; } /** - * \brief Get callback private value for an HCTL element - * \param obj HCTL element + * \brief Get callback private value for an CTL element + * \param obj CTL element * \return callback private value */ -void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj) +void * snd_ctl_elem_get_callback_private(const snd_ctl_elem_t *obj) { assert(obj); return obj->callback_private; diff --git a/src/control/hcontrol_old.c b/src/control/hcontrol_old.c new file mode 100644 index 00000000..a084f1a2 --- /dev/null +++ b/src/control/hcontrol_old.c @@ -0,0 +1,512 @@ +/** + * \file control/hcontrol_old.c + * \brief HCTL Interface - High Level CTL + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2000 + * + * HCTL interface is designed to access preloaded and sorted primitive controls. + * Callbacks may be used for event handling. + * See \ref hcontrol page for more details. + */ +/* + * Control Interface - high level API + * Copyright (c) 2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page hcontrol High level control interface + +

High level control interface is designed to access preloaded and sorted primitive controls. + +\section hcontrol_general_overview General overview + +

High level control interface caches the accesses to primitive controls +to reduce overhead accessing the real controls in kernel drivers. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "control_local.h" +#include "mixer_old.h" + +/** + * \brief Opens an HCTL + * \param hctlp Returned HCTL handle + * \param name ASCII identifier of the underlying CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_open(snd_hctl_t **hctlp, const char *name, int mode ATTRIBUTE_UNUSED) +{ + return snd_ctl_open(hctlp, name, SND_CTL_CACHE); +} + +/** + * \brief Opens an HCTL + * \param hctlp Returned HCTL handle + * \param ctl underlying CTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl) +{ + assert(hctlp); + assert(ctl); + *hctlp = ctl; + ctl->mode = SND_CTL_CACHE; + return 0; +} + +/** + * \brief close HCTL handle + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified HCTL handle and frees all associated + * resources. + */ +int snd_hctl_close(snd_hctl_t *hctl) +{ + return snd_ctl_close(hctl); +} + +/** + * \brief get identifier of HCTL handle + * \param hctl HCTL handle + * \return ascii identifier of HCTL handle + * + * Returns the ASCII identifier of given HCTL handle. It's the same + * identifier specified in snd_hctl_open(). + */ +const char *snd_hctl_name(snd_hctl_t *hctl) +{ + assert(hctl); + return snd_ctl_name(hctl); +} + +/** + * \brief set nonblock mode + * \param hctl HCTL handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock) +{ + assert(hctl); + return snd_ctl_nonblock(hctl, nonblock); +} + +/** + * \brief set async mode + * \param hctl HCTL handle + * \param sig Signal to raise: < 0 disable, 0 default (SIGIO) + * \param pid Process ID to signal: 0 current + * \return 0 on success otherwise a negative error code + * + * A signal is raised when a change happens. + */ +int snd_hctl_async(snd_hctl_t *hctl, int sig, pid_t pid) +{ + assert(hctl); + return snd_ctl_async(hctl, sig, pid); +} + +/** + * \brief get count of poll descriptors for HCTL handle + * \param hctl HCTL handle + * \return count of poll descriptors + */ +int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl) +{ + assert(hctl); + return snd_ctl_poll_descriptors_count(hctl); +} + +/** + * \brief get poll descriptors + * \param hctl HCTL handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space) +{ + assert(hctl); + return snd_ctl_poll_descriptors(hctl, pfds, space); +} + +/** + * \brief get returned events from poll descriptors + * \param hctl HCTL 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_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + assert(hctl); + return snd_ctl_poll_descriptors_revents(hctl, pfds, nfds, revents); +} + +/** + * \brief free HCTL loaded elements + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_free(snd_hctl_t *hctl) +{ + return snd_ctl_cache_free(hctl); +} + +/** + * \brief Change HCTL compare function and reorder elements + * \param hctl HCTL handle + * \param compare Element compare function + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t compare) +{ + return snd_ctl_set_compare(hctl, compare); +} + +/** + * \brief get first element for an HCTL + * \param hctl HCTL handle + * \return pointer to first element + */ +snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl) +{ + return snd_ctl_first_elem(hctl); +} + +/** + * \brief get last element for an HCTL + * \param hctl HCTL handle + * \return pointer to last element + */ +snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl) +{ + return snd_ctl_last_elem(hctl); +} + +/** + * \brief get next HCTL element + * \param elem HCTL element + * \return pointer to next element + */ +snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem) +{ + return snd_ctl_elem_next(elem); +} + +/** + * \brief get previous HCTL element + * \param elem HCTL element + * \return pointer to previous element + */ +snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem) +{ + return snd_ctl_elem_prev(elem); +} + +/** + * \brief Search an HCTL element + * \param hctl HCTL handle + * \param id Element identifier + * \return pointer to found HCTL element or NULL if it does not exists + */ +snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id) +{ + return snd_ctl_find_elem(hctl, id); +} + +/** + * \brief Load an HCTL with all elements and sort them + * \param hctl HCTL handle + * \return 0 on success otherwise a negative error code + */ +int snd_hctl_load(snd_hctl_t *hctl) +{ + return snd_ctl_subscribe_events(hctl, 1); +} + +/** + * \brief Set callback function for an HCTL + * \param hctl HCTL handle + * \param callback callback function + */ +void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback) +{ + snd_ctl_set_callback(hctl, callback); +} + +/** + * \brief Set callback private value for an HCTL + * \param hctl HCTL handle + * \param callback_private callback private value + */ +void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *callback_private) +{ + snd_ctl_set_callback_private(hctl, callback_private); +} + +/** + * \brief Get callback private value for an HCTL + * \param hctl HCTL handle + * \return callback private value + */ +void *snd_hctl_get_callback_private(snd_hctl_t *hctl) +{ + return snd_ctl_get_callback_private(hctl); +} + +/** + * \brief Get number of loaded elements for an HCTL + * \param hctl HCTL handle + * \return elements count + */ +unsigned int snd_hctl_get_count(snd_hctl_t *hctl) +{ + return snd_ctl_get_count(hctl); +} + +/** + * \brief Wait for a HCTL to become ready (i.e. at least one event pending) + * \param hctl HCTL handle + * \param timeout maximum time in milliseconds to wait + * \return a positive value on success otherwise a negative error code + * \retval 0 timeout occurred + * \retval 1 an event is pending + */ +int snd_hctl_wait(snd_hctl_t *hctl, int timeout) +{ + return snd_ctl_wait(hctl, timeout); +} + +/** + * \brief Get a ctl handle associated to the given hctl handle + * \param hctl HCTL handle + * \return a ctl handle otherwise NULL + */ +snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl) +{ + return hctl; +} + +/** + * \brief Handle pending HCTL events invoking callbacks + * \param hctl HCTL handle + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_handle_events(snd_hctl_t *hctl) +{ + return snd_ctl_handle_events(hctl); +} + +/** + * \brief Get information for an HCTL element + * \param elem HCTL element + * \param info HCTL element information + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t *info) +{ + return snd_ctl_celem_info(elem, info); +} + +/** + * \brief Get value for an HCTL element + * \param elem HCTL element + * \param value HCTL element value + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +{ + return snd_ctl_celem_read(elem, value); +} + +/** + * \brief Set value for an HCTL element + * \param elem HCTL element + * \param value HCTL element value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value) +{ + return snd_ctl_celem_write(elem, value); +} + +/** + * \brief Get TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \param tlv_size size of TLV array in bytes + * \return 0 otherwise a negative error code on failure + */ +int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size) +{ + return snd_ctl_celem_tlv_read(elem, tlv, tlv_size); +} + +/** + * \brief Set TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv) +{ + return snd_ctl_celem_tlv_write(elem, tlv); +} + +/** + * \brief Set TLV value for an HCTL element + * \param elem HCTL element + * \param tlv TLV array for value + * \retval 0 on success + * \retval >1 on success when value was changed + * \retval <0 a negative error code on failure + */ +int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv) +{ + return snd_ctl_celem_tlv_command(elem, tlv); +} + +/** + * \brief Get HCTL handle for an HCTL element + * \param elem HCTL element + * \return HCTL handle + */ +snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem) +{ + return snd_ctl_elem_get_ctl(elem); +} + +/** + * \brief Get CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \param ptr Pointer to returned CTL element identifier + */ +void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr) +{ + snd_ctl_elem_get_id(obj, ptr); +} + +/** + * \brief Get element numeric identifier of a CTL element id/value + * \param obj CTL element id/value + * \return element numeric identifier + */ +unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_numid(obj); +} + +/** + * \brief Get interface part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return interface part of element identifier + */ +snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj) +{ +return snd_ctl_elem_get_interface(obj); +} + +/** + * \brief Get device part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return device part of element identifier + */ +unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_device(obj); +} + +/** + * \brief Get subdevice part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return subdevice part of element identifier + */ +unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_subdevice(obj); +} + +/** + * \brief Get name part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return name part of element identifier + */ +const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_name(obj); +} + +/** + * \brief Get index part of CTL element identifier of a CTL element id/value + * \param obj CTL element id/value + * \return index part of element identifier + */ +unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_index(obj); +} + +/** + * \brief Set callback function for an HCTL element + * \param obj HCTL element + * \param val callback function + */ +void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val) +{ + return snd_ctl_elem_set_callback(obj, val); +} + +/** + * \brief Set callback private value for an HCTL element + * \param obj HCTL element + * \param val callback private value + */ +void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val) +{ + return snd_ctl_elem_set_callback_private(obj, val); +} + +/** + * \brief Get callback private value for an HCTL element + * \param obj HCTL element + * \return callback private value + */ +void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj) +{ + return snd_ctl_elem_get_callback_private(obj); +} + diff --git a/src/mixer/Makefile.am b/src/mixer/Makefile.am index bb466ed7..84272ada 100644 --- a/src/mixer/Makefile.am +++ b/src/mixer/Makefile.am @@ -1,8 +1,9 @@ EXTRA_LTLIBRARIES=libmixer.la -libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c simple_abst.c +libmixer_la_SOURCES = bag.c mixer.c simple.c simple_none.c mixer_symbols.c \ + mixer_old.c simple_old.c -noinst_HEADERS = mixer_local.h mixer_simple.h +noinst_HEADERS = mixer_local.h mixer_old_local.h all: libmixer.la 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 * \author Abramo Bagnara - * \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 -

Mixer interface is designed to access the abstracted mixer controls. -This is an abstraction layer over the hcontrol layer. +

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 #include #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; } diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h index 27b4a3b1..cf68ffe3 100644 --- a/src/mixer/mixer_local.h +++ b/src/mixer/mixer_local.h @@ -21,6 +21,7 @@ */ #include "local.h" +#include "mixer_abst.h" typedef struct _bag1 { void *ptr; @@ -42,41 +43,40 @@ typedef struct list_head *bag_iterator_t; #define bag_for_each(pos, bag) list_for_each(pos, bag) #define bag_for_each_safe(pos, next, bag) list_for_each_safe(pos, next, bag) -struct _snd_mixer_class { - struct list_head list; - snd_mixer_t *mixer; - snd_mixer_event_t event; - void *private_data; - void (*private_free)(snd_mixer_class_t *class); - snd_mixer_compare_t compare; -}; - -struct _snd_mixer_elem { - snd_mixer_elem_type_t type; +struct _snd_amixer_elem { struct list_head list; /* links for list of all elems */ - snd_mixer_class_t *class; + snd_amixer_t *amixer; + snd_ctl_t *ctl; void *private_data; - void (*private_free)(snd_mixer_elem_t *elem); - snd_mixer_elem_callback_t callback; + void (*private_free)(snd_amixer_elem_t *elem); + snd_amixer_elem_callback_t callback; void *callback_private; bag_t helems; int compare_weight; /* compare weight (reversed) */ + sm_elem_t sm; }; -struct _snd_mixer { - struct list_head slaves; /* list of all slaves */ - struct list_head classes; /* list of all elem classes */ - struct list_head elems; /* list of all elems */ - snd_mixer_elem_t **pelems; /* array of all elems */ +struct _snd_amixer { + struct sm_open sm_open; + struct list_head elems; /* list of all elems */ + snd_amixer_elem_t **pelems; /* array of all elems */ unsigned int count; unsigned int alloc; unsigned int events; - snd_mixer_callback_t callback; + snd_amixer_callback_t callback; void *callback_private; - snd_mixer_compare_t compare; + snd_amixer_compare_t compare; + snd_amixer_event_t event; + void *dl_handle; }; -struct _snd_mixer_selem_id { - char name[60]; - unsigned int index; -}; +/* make local functions really local */ +#define snd_amixer_simple_none_open \ + snd1_amixer_simple_none_open +#define snd_amixer_simple_basic_open \ + snd1_amixer_simple_basic_open + +int snd_amixer_simple_none_open(snd_amixer_t *amixer, + struct sm_open *sm_open); +int snd_amixer_simple_basic_open(snd_amixer_t *amixer, + struct sm_open *sm_open); diff --git a/src/mixer/mixer_old.c b/src/mixer/mixer_old.c new file mode 100644 index 00000000..37da864e --- /dev/null +++ b/src/mixer/mixer_old.c @@ -0,0 +1,375 @@ +/** + * \file mixer/mixer.c + * \brief Mixer Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2001 + * + * Old (v1) mixer interface is designed to access mixer elements. + * Callbacks may be used for event handling. + */ +/* + * Mixer Interface - main file + * Copyright (c) 1998/1999/2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/*! \page mixer Mixer interface + +

Mixer interface is designed to access the abstracted mixer controls. +This is an abstraction layer over the hcontrol layer. + +\section mixer_general_overview General overview + +*/ + +#include +#include +#include +#include +#include +#include +#include "mixer_old_local.h" + +/** + * \brief Opens an empty mixer + * \param mixerp Returned mixer handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_open(snd_mixer_t **mixerp, int mode ATTRIBUTE_UNUSED) +{ + snd_mixer_t *mixer; + assert(mixerp); + mixer = calloc(1, sizeof(*mixer)); + if (mixer == NULL) + return -ENOMEM; + *mixerp = mixer; + return 0; +} + +/** + * \brief Attach a HCTL to midxer + * \param mixer Mixer handle + * \param name the HCTL device name + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_attach(snd_mixer_t *mixer, const char *name) +{ + assert(mixer); + assert(name); + if (mixer->amixer) + return -EBUSY; + return snd_amixer_open(&mixer->amixer, name, NULL, NULL, SND_AMIXER_COMPAT1); +} + +/** + * \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) +{ + return -ENXIO; +} + +/** + * \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) +{ + return -ENXIO; +} + +/** + * \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) +{ + return -ENXIO; +} + +/** + * \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) +{ + return -ENXIO; +} + +/** + * \brief Get private data associated to give mixer 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) +{ + return snd_amixer_elem_get_private(elem); +} + +/** + * \brief Load a mixer elements + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_load(snd_mixer_t *mixer) +{ + return 0; +} + +/** + * \brief Unload all mixer elements and free all related resources + * \param mixer Mixer handle + */ +void snd_mixer_free(snd_mixer_t *mixer) +{ +} + +/** + * \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; + + if (mixer->amixer) + res = snd_amixer_close(mixer->amixer); + free(mixer); + return 0; +} + +/** + * \brief Change mixer compare function and reorder elements + * \param mixer 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) +{ + return snd_amixer_set_compare(mixer->amixer, compare); +} + +/** + * \brief get count of poll descriptors for mixer handle + * \param mixer Mixer handle + * \return count of poll descriptors + */ +int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer) +{ + return snd_amixer_poll_descriptors_count(mixer->amixer); +} + +/** + * \brief get poll descriptors + * \param mixer 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) +{ + return snd_amixer_poll_descriptors(mixer->amixer, pfds, space); +} + +/** + * \brief get returned events from poll descriptors + * \param mixer 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) +{ + return snd_amixer_poll_descriptors_revents(mixer->amixer, pfds, nfds, revents); +} + +/** + * \brief Wait for a mixer to become ready (i.e. at least one event pending) + * \param mixer 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) +{ + return snd_amixer_wait(mixer->amixer, timeout); +} + +/** + * \brief get first element for a mixer + * \param mixer Mixer handle + * \return pointer to first element + */ +snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer) +{ + return snd_amixer_first_elem(mixer->amixer); +} + +/** + * \brief get last element for a mixer + * \param mixer Mixer handle + * \return pointer to last element + */ +snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer) +{ + return snd_amixer_last_elem(mixer->amixer); +} + +/** + * \brief get next mixer element + * \param elem mixer element + * \return pointer to next element + */ +snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_next(elem); +} + +/** + * \brief get previous mixer element + * \param elem mixer element + * \return pointer to previous element + */ +snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_prev(elem); +} + +/** + * \brief Handle pending mixer events invoking callbacks + * \param mixer 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) +{ + return snd_amixer_handle_events(mixer->amixer); +} + +static int snd_mixer_default_callback(snd_amixer_t *mixer, + unsigned int mask, + snd_mixer_elem_t *elem) +{ + snd_mixer_t *old = snd_amixer_get_callback_private(mixer); + return old->callback(old, mask, elem); +} + +/** + * \brief Set callback function for a mixer + * \param obj mixer handle + * \param val callback function + */ +void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val) +{ + assert(obj); + obj->callback = val; + snd_amixer_set_callback(obj->amixer, snd_mixer_default_callback); + snd_amixer_set_callback_private(obj->amixer, obj); +} + +/** + * \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) +{ + return snd_amixer_get_count(mixer->amixer); +} + +/** + * \brief Set callback function for a mixer element + * \param mixer mixer element + * \param val callback function + */ +void snd_mixer_elem_set_callback(snd_mixer_elem_t *mixer, snd_mixer_elem_callback_t val) +{ + return snd_amixer_elem_set_callback(mixer, val); +} + +/** + * \brief Set callback private value for a mixer element + * \param elem mixer element + * \param val callback private value + */ +void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *elem, void * val) +{ + return snd_amixer_elem_set_callback_private(elem, val); +} + +/** + * \brief Get callback private value for a mixer element + * \param elem mixer element + * \return callback private value + */ +void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_callback_private(elem); +} + +/** + * \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 SND_MIXER_ELEM_SIMPLE; +} + + diff --git a/src/mixer/mixer_old_local.h b/src/mixer/mixer_old_local.h new file mode 100644 index 00000000..16d10c05 --- /dev/null +++ b/src/mixer/mixer_old_local.h @@ -0,0 +1,30 @@ +/* + * Mixer Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "local.h" +#include "mixer_old.h" + +struct _snd_mixer { + snd_amixer_t *amixer; + snd_mixer_callback_t callback; + void *callback_private; +}; diff --git a/src/mixer/mixer_simple.h b/src/mixer/mixer_simple.h deleted file mode 100644 index e88b0071..00000000 --- a/src/mixer/mixer_simple.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Mixer Simple Interface - local header file - * Copyright (c) 2005 by Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "mixer_abst.h" - -/* make local functions really local */ -#define snd_mixer_simple_none_register \ - snd1_mixer_simple_none_register -#define snd_mixer_simple_basic_register \ - snd1_mixer_simple_basic_register - -int snd_mixer_simple_none_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); -int snd_mixer_simple_basic_register(snd_mixer_t *mixer, struct snd_mixer_selem_regopt *options, snd_mixer_class_t **classp); diff --git a/src/mixer/mixer_symbols.c b/src/mixer/mixer_symbols.c new file mode 100644 index 00000000..29af4c0e --- /dev/null +++ b/src/mixer/mixer_symbols.c @@ -0,0 +1,36 @@ +/* + * Mixer Symbols + * Copyright (c) 2009 by Jaroslav Kysela + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef PIC + +#include "config.h" + +extern const char *_snd_module_mixer_none; + +static const char **snd_pcm_open_objects[] = { + &_snd_module_mixer_none, +}; + +void *snd_mixer_open_symbols(void) +{ + return snd_mixer_open_objects; +} + +#endif /* !PIC */ diff --git a/src/mixer/simple.c b/src/mixer/simple.c index 39790b2e..8cbe484d 100644 --- a/src/mixer/simple.c +++ b/src/mixer/simple.c @@ -3,7 +3,7 @@ * \brief Mixer Simple Element Class Interface * \author Jaroslav Kysela * \author Abramo Bagnara - * \date 2001-2004 + * \date 2001-2008 * * Mixer simple element class interface. */ @@ -37,89 +37,33 @@ #include #include #include "mixer_local.h" -#include "mixer_simple.h" - -/** - * \brief Register mixer simple element class - * \param mixer Mixer handle - * \param options Options container - * \param classp Pointer to returned mixer simple element class handle (or NULL) - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_register(snd_mixer_t *mixer, - struct snd_mixer_selem_regopt *options, - snd_mixer_class_t **classp) -{ - if (options && options->ver == 1) { - if (options->device != NULL && - (options->playback_pcm != NULL || - options->capture_pcm != NULL)) - return -EINVAL; - if (options->device == NULL && - options->playback_pcm == NULL && - options->capture_pcm == NULL) - return -EINVAL; - } - if (options == NULL || - (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) { - int err = snd_mixer_simple_none_register(mixer, options, classp); - if (err < 0) - return err; - if (options != NULL) { - err = snd_mixer_attach(mixer, options->device); - if (err < 0) - return err; - } - return 0; - } else if (options->ver == 1) { - if (options->abstract == SND_MIXER_SABSTRACT_BASIC) - return snd_mixer_simple_basic_register(mixer, options, classp); - } - return -ENXIO; -} #ifndef DOC_HIDDEN -#define CHECK_BASIC(xelem) \ -{ \ - assert(xelem); \ - assert((xelem)->type == SND_MIXER_ELEM_SIMPLE); \ -} - -#define CHECK_DIR(xelem, xwhat) \ -{ \ - unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ - if (! (xcaps & (xwhat))) \ - return -EINVAL; \ -} - -#define CHECK_DIR_CHN(xelem, xwhat, xjoin, xchannel) \ -{ \ - unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ - if (! (xcaps & (xwhat))) \ - return -EINVAL; \ - if (xcaps & (xjoin)) \ - xchannel = 0; \ -} - #define CHECK_ENUM(xelem) \ - if (!((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM)) \ + if (!(elem->sm.caps & (SM_CAP_PENUM|SM_CAP_CENUM))) \ return -EINVAL; #define COND_CAPS(xelem, what) \ - !!(((sm_selem_t *)(elem)->private_data)->caps & (what)) + !!(elem->sm.caps & (what)) + +#define sm_elem(x) (&(x)->sm) +#define sm_elem_ops(x) ((x)->sm.ops) #endif /* !DOC_HIDDEN */ #ifndef DOC_HIDDEN -int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2) +int snd_amixer_compare_default(const snd_amixer_elem_t *c1, const snd_amixer_elem_t *c2) { - sm_selem_t *s1 = c1->private_data; - sm_selem_t *s2 = c2->private_data; - int res = strcmp(s1->id->name, s2->id->name); - if (res) - return res; - return s1->id->index - s2->id->index; + int d; + + d = c1->compare_weight - c2->compare_weight; + if (d) + return d; + d = strcmp(c1->sm.id.name, c2->sm.id.name); + if (d) + return d; + return c1->sm.id.index - c2->sm.id.index; } #endif @@ -129,19 +73,15 @@ int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t * * \param id Mixer simple element identifier * \return mixer simple element handle or NULL if not found */ -snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, - const snd_mixer_selem_id_t *id) +snd_amixer_elem_t *snd_amixer_find_elem(snd_amixer_t *mixer, + const snd_amixer_elem_id_t *id) { struct list_head *list; - snd_mixer_elem_t *e; - sm_selem_t *s; + snd_amixer_elem_t *e; list_for_each(list, &mixer->elems) { - e = list_entry(list, snd_mixer_elem_t, list); - if (e->type != SND_MIXER_ELEM_SIMPLE) - continue; - s = e->private_data; - if (!strcmp(s->id->name, id->name) && s->id->index == id->index) + e = list_entry(list, snd_amixer_elem_t, list); + if (!strcmp(e->sm.id.name, id->name) && e->sm.id.index == id->index) return e; } return NULL; @@ -152,14 +92,11 @@ snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, * \param elem Mixer simple element handle * \param id returned mixer simple element identifier */ -void snd_mixer_selem_get_id(snd_mixer_elem_t *elem, - snd_mixer_selem_id_t *id) +void snd_amixer_elem_get_id(snd_amixer_elem_t *elem, + snd_amixer_elem_id_t *id) { - sm_selem_t *s; assert(id); - CHECK_BASIC(elem); - s = elem->private_data; - *id = *s->id; + *id = elem->sm.id; } /** @@ -167,12 +104,9 @@ void snd_mixer_selem_get_id(snd_mixer_elem_t *elem, * \param elem Mixer simple element handle * \return name part of simple element identifier */ -const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem) +const char *snd_amixer_elem_get_name(snd_amixer_elem_t *elem) { - sm_selem_t *s; - CHECK_BASIC(elem); - s = elem->private_data; - return s->id->name; + return elem->sm.id.name; } /** @@ -180,34 +114,73 @@ const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem) * \param elem Mixer simple element handle * \return index part of simple element identifier */ -unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem) +unsigned int snd_amixer_elem_get_index(snd_amixer_elem_t *elem) { - sm_selem_t *s; - CHECK_BASIC(elem); - s = elem->private_data; - return s->id->index; + return elem->sm.id.index; } /** - * \brief Return true if mixer simple element has only one volume control for both playback and capture + * \brief Return true if mixer simple element has control for specified direction * \param elem Mixer simple element handle - * \return 0 separated control, 1 common control + * \param dir Mixer direction + * \return 0 false, 1 true */ -int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem) +int snd_amixer_elem_has_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_GVOLUME); + if (dir == SM_COMM) + return COND_CAPS(elem, SM_CAP_GVOLUME); + if (dir == SM_PLAY) + return COND_CAPS(elem, SM_CAP_PVOLUME); + if (dir == SM_CAPT) + return COND_CAPS(elem, SM_CAP_CVOLUME); + return 0; } /** - * \brief Return true if mixer simple element has only one switch control for both playback and capture + * \brief Return info about volume control of a mixer simple element * \param elem Mixer simple element handle - * \return 0 separated control, 1 common control + * \param dir Mixer direction + * \return 0 if control is separated per channel, 1 if control acts on all channels together */ -int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem) +int snd_amixer_elem_has_volume_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_GSWITCH); + if (dir == SM_PLAY) + return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN); + if (dir == SM_CAPT) + return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN); + return 0; +} + +/** + * \brief Return true if mixer simple element has control for specified direction + * \param elem Mixer simple element handle + * \param dir Mixer direction + * \return 0 false, 1 true + */ +int snd_amixer_elem_has_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) +{ + if (dir == SM_COMM) + return COND_CAPS(elem, SM_CAP_GSWITCH); + if (dir == SM_PLAY) + return COND_CAPS(elem, SM_CAP_PSWITCH); + if (dir == SM_CAPT) + return COND_CAPS(elem, SM_CAP_CSWITCH); + return 0; +} + +/** + * \brief Return info about switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param dir Mixer direction + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_amixer_elem_has_switch_joined(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) +{ + if (dir == SM_PLAY) + return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN); + if (dir == SM_CAPT) + return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN); + return 0; } /** @@ -215,7 +188,7 @@ int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem) * \param channel mixer simple element channel identifier * \return channel name */ -const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel) +const char *snd_amixer_elem_channel_name(snd_amixer_elem_channel_id_t channel) { static const char *const array[SND_MIXER_SCHN_LAST + 1] = { [SND_MIXER_SCHN_FRONT_LEFT] = "Front Left", @@ -241,270 +214,262 @@ const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel) * \param elem Mixer simple element handle * \return 0 if not active, 1 if active */ -int snd_mixer_selem_is_active(snd_mixer_elem_t *elem) +int snd_amixer_elem_is_active(snd_amixer_elem_t *elem) { - CHECK_BASIC(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0); + return sm_elem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0); } /** - * \brief Get info about channels of playback stream of a mixer simple element + * \brief Get info about channels of a mixer simple element * \param elem Mixer simple element handle - * \return 0 if not mono, 1 if mono + * \param dir Mixer direction + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present */ -int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem) +int snd_amixer_elem_has_channel(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel) { - CHECK_BASIC(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_MONO, 0); + return sm_elem_ops(elem)->is(elem, dir, SM_OPS_IS_CHANNEL, (int)channel); } /** - * \brief Get info about channels of playback stream of a mixer simple element + * \brief Get count of valid channels * \param elem Mixer simple element handle - * \param channel Mixer simple element channel identifier - * \return 0 if channel is not present, 1 if present + * \param dir Mixer direction + * \return 1 or more */ -int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) +int snd_amixer_elem_get_channels(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - CHECK_BASIC(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel); + return sm_elem_ops(elem)->get_channels(elem, dir); } /** - * \brief Get range for playback volume of a mixer simple element + * \brief Get range for volume of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param min Pointer to returned minimum * \param max Pointer to returned maximum */ -int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, - long *min, long *max) +int snd_amixer_elem_get_volume_range(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + long *min, long *max) { - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_PVOLUME); - return sm_selem_ops(elem)->get_range(elem, SM_PLAY, min, max); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + return sm_elem_ops(elem)->get_range(elem, dir, min, max); } /** - * \brief Get range in dB for playback volume of a mixer simple element + * \brief Get range in dB for volume of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param min Pointer to returned minimum (dB * 100) * \param max Pointer to returned maximum (dB * 100) */ -int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, - long *min, long *max) +int snd_amixer_elem_get_dB_range(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + long *min, long *max) { - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_PVOLUME); - return sm_selem_ops(elem)->get_dB_range(elem, SM_PLAY, min, max); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + return sm_elem_ops(elem)->get_dB_range(elem, dir, min, max); } /** - * \brief Set range for playback volume of a mixer simple element + * \brief Set range for volume of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param min minimum volume value * \param max maximum volume value */ -int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, - long min, long max) +int snd_amixer_elem_set_volume_range(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + long min, long max) { - CHECK_BASIC(elem); assert(min < max); - CHECK_DIR(elem, SM_CAP_PVOLUME); - return sm_selem_ops(elem)->set_range(elem, SM_PLAY, min, max); -} - -/** - * \brief Return info about playback volume control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if no control is present, 1 if it's present - */ -int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_PVOLUME); -} - -/** - * \brief Return info about playback volume control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if control is separated per channel, 1 if control acts on all channels together - */ -int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN); -} - -/** - * \brief Return info about playback switch control existence of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if no control is present, 1 if it's present - */ -int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_PSWITCH); -} - -/** - * \brief Return info about playback switch control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if control is separated per channel, 1 if control acts on all channels together - */ -int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + return sm_elem_ops(elem)->set_range(elem, dir, min, max); } /** - * \brief Return corresponding dB value to an integer playback volume for a mixer simple element + * \brief Return corresponding dB value to an integer volume for a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param value value to be converted to dB range * \param dBvalue pointer to returned dB value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) +int snd_amixer_elem_ask_vol_dB(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + long value, long *dBvalue) { - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_PVOLUME); - return sm_selem_ops(elem)->ask_vol_dB(elem, SM_PLAY, value, dBvalue); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + return sm_elem_ops(elem)->ask_vol_dB(elem, dir, value, dBvalue); } /** - * \brief Return corresponding integer playback volume for given dB value for a mixer simple element + * \brief Return corresponding integer volume for given dB value for a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param value value to be converted to dB range - * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \param xdir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) * \param dBvalue pointer to returned dB value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +int snd_amixer_elem_ask_dB_vol(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + long dBvalue, int xdir, long *value) { - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_PVOLUME); - return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + return sm_elem_ops(elem)->ask_dB_vol(elem, dir, dBvalue, value, xdir); } /** * \brief Return value of playback volume control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value pointer to returned value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +int snd_amixer_elem_get_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, + long *value) { - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); - return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + if (snd_amixer_elem_has_volume_joined(elem, dir)) + channel = 0; + return sm_elem_ops(elem)->get_volume(elem, dir, channel, value); } /** - * \brief Return value of playback volume in dB control of a mixer simple element + * \brief Return value of volume in dB control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value pointer to returned value (dB * 100) * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +int snd_amixer_elem_get_dB(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, long *value) { - unsigned int caps; - - CHECK_BASIC(elem); - caps = ((sm_selem_t *)elem->private_data)->caps; - if (!(caps & SM_CAP_PVOLUME)) + if (!snd_amixer_elem_has_volume(elem, dir)) return -EINVAL; - if (caps & SM_CAP_PVOLUME_JOIN) + if (snd_amixer_elem_has_volume_joined(elem, dir)) channel = 0; - return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value); + return sm_elem_ops(elem)->get_dB(elem, dir, channel, value); } /** * \brief Return value of playback switch control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value pointer to returned value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) +int snd_amixer_elem_get_switch(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, + int *value) { - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); - return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + if (snd_amixer_elem_has_volume_joined(elem, dir)) + channel = 0; + return sm_elem_ops(elem)->get_switch(elem, dir, channel, value); } /** - * \brief Set value of playback volume control of a mixer simple element + * \brief Set value of volume control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value control value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) +int snd_amixer_elem_set_volume(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, + long value) { - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); - return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + if (snd_amixer_elem_has_volume_joined(elem, dir)) + channel = 0; + return sm_elem_ops(elem)->set_volume(elem, dir, channel, value); } /** * \brief Set value in dB of playback volume control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value control value in dB * 100 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +int snd_amixer_elem_set_dB(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, + long value, int xdir) { - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); - return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir); + if (!snd_amixer_elem_has_volume(elem, dir)) + return -EINVAL; + if (snd_amixer_elem_has_volume_joined(elem, dir)) + channel = 0; + return sm_elem_ops(elem)->set_dB(elem, dir, channel, value, xdir); } /** - * \brief Set value of playback volume control for all channels of a mixer simple element + * \brief Set value of volume control for all channels of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param value control value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) +int snd_amixer_elem_set_volume_all(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, long value) { - snd_mixer_selem_channel_id_t chn; + snd_amixer_elem_channel_id_t chn; int err; - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_playback_channel(elem, chn)) + for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) { + if (!snd_amixer_elem_has_channel(elem, dir, chn)) continue; - err = snd_mixer_selem_set_playback_volume(elem, chn, value); + err = snd_amixer_elem_set_volume(elem, dir, chn, value); if (err < 0) return err; - if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) + if (chn == 0 && snd_amixer_elem_has_volume_joined(elem, dir)) return 0; } return 0; } /** - * \brief Set value in dB of playback volume control for all channels of a mixer simple element + * \brief Set value in dB of volume control for all channels of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param value control value in dB * 100 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir) +int snd_amixer_elem_set_dB_all(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + long value, int xdir) { - snd_mixer_selem_channel_id_t chn; + snd_amixer_elem_channel_id_t chn; int err; - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_playback_channel(elem, chn)) + for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) { + if (!snd_amixer_elem_has_channel(elem, dir, chn)) continue; - err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir); + err = snd_amixer_elem_set_dB(elem, dir, chn, value, xdir); if (err < 0) return err; - if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) + if (chn == 0 && snd_amixer_elem_has_volume_joined(elem, dir)) return 0; } return 0; @@ -513,397 +478,91 @@ int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int /** * \brief Set value of playback switch control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param channel mixer simple element channel identifier * \param value control value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) +int snd_amixer_elem_set_switch(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, + int value) { - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); - return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value); + if (!snd_amixer_elem_has_switch(elem, dir)) + return -EINVAL; + if (snd_amixer_elem_has_switch_joined(elem, dir)) + channel = 0; + return sm_elem_ops(elem)->set_switch(elem, dir, channel, value); } /** - * \brief Set value of playback switch control for all channels of a mixer simple element + * \brief Set value of switch control for all channels of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction * \param value control value * \return 0 on success otherwise a negative error code */ -int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value) +int snd_amixer_elem_set_switch_all(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, int value) { - snd_mixer_selem_channel_id_t chn; + snd_amixer_elem_channel_id_t chn; int err; - CHECK_BASIC(elem); - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_playback_channel(elem, chn)) + for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) { + if (!snd_amixer_elem_has_channel(elem, dir, chn)) continue; - err = snd_mixer_selem_set_playback_switch(elem, chn, value); + err = snd_amixer_elem_set_switch(elem, dir, chn, value); if (err < 0) return err; - if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem)) + if (chn == 0 && snd_amixer_elem_has_switch_joined(elem, dir)) return 0; } return 0; } /** - * \brief Get info about channels of capture stream of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if not mono, 1 if mono - */ -int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); - return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0); -} - -/** - * \brief Get info about channels of capture stream of a mixer simple element - * \param elem Mixer simple element handle - * \param channel Mixer simple element channel identifier - * \return 0 if channel is not present, 1 if present - */ -int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); - return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel); -} - -/** - * \brief Get range for capture volume of a mixer simple element - * \param elem Mixer simple element handle - * \param min Pointer to returned minimum - * \param max Pointer to returned maximum - */ -int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, - long *min, long *max) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME); - return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max); -} - -/** - * \brief Get range in dB for capture volume of a mixer simple element - * \param elem Mixer simple element handle - * \param min Pointer to returned minimum (dB * 100) - * \param max Pointer to returned maximum (dB * 100) - */ -int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, - long *min, long *max) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME); - return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max); -} - -/** - * \brief Set range for capture volume of a mixer simple element - * \param elem Mixer simple element handle - * \param min minimum volume value - * \param max maximum volume value - */ -int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, - long min, long max) -{ - CHECK_BASIC(elem); - assert(min < max); - CHECK_DIR(elem, SM_CAP_CVOLUME); - return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max); -} - -/** - * \brief Return info about capture volume control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if no control is present, 1 if it's present - */ -int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_CVOLUME); -} - -/** - * \brief Return info about capture volume control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if control is separated per channel, 1 if control acts on all channels together - */ -int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN); -} - -/** - * \brief Return info about capture switch control existence of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if no control is present, 1 if it's present - */ -int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_CSWITCH); -} - -/** - * \brief Return info about capture switch control of a mixer simple element - * \param elem Mixer simple element handle - * \return 0 if control is separated per channel, 1 if control acts on all channels together - */ -int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN); -} - -/** - * \brief Return info about capture switch control of a mixer simple element + * \brief Return info about switch control of a mixer simple element * \param elem Mixer simple element handle + * \param dir Mixer direction (should be capture for now) * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group) */ -int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem) +int snd_amixer_elem_has_switch_exclusive(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - CHECK_BASIC(elem); - return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL); + if (dir == SM_CAPT) + return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL); + return 0; } /** - * \brief Return info about capture switch control of a mixer simple element + * \brief Return info about switch control of a mixer simple element * \param elem Mixer simple element handle - * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive) + * \param dir Mixer direction + * \return group for switch exclusivity (see #snd_amixer_elem_has_switch_exclusive) */ -int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem) +int snd_amixer_elem_get_group(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - sm_selem_t *s; - CHECK_BASIC(elem); - s = elem->private_data; + sm_elem_t *s; + if (dir != SM_CAPT) + return -EINVAL; + s = sm_elem(elem); if (! (s->caps & SM_CAP_CSWITCH_EXCL)) return -EINVAL; return s->capture_group; } /** - * \brief Return corresponding dB value to an integer capture volume for a mixer simple element - * \param elem Mixer simple element handle - * \param value value to be converted to dB range - * \param dBvalue pointer to returned dB value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME); - return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue); -} - -/** - * \brief Return corresponding integer capture volume for given dB value for a mixer simple element - * \param elem Mixer simple element handle - * \param dBvalue dB value to be converted to integer range - * \param value pointer to returned integer value - * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) -{ - CHECK_BASIC(elem); - CHECK_DIR(elem, SM_CAP_CVOLUME); - return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir); -} - -/** - * \brief Return value of capture volume control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value pointer to returned value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); - return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value); -} - -/** - * \brief Return value of capture volume in dB control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value pointer to returned value (dB * 100) - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); - return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value); -} - -/** - * \brief Return value of capture switch control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value pointer to returned value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); - return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value); -} - -/** - * \brief Set value of capture volume control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value control value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); - return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value); -} - -/** - * \brief Set value in dB of capture volume control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value control value in dB * 100 - * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); - return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir); -} - -/** - * \brief Set value of capture volume control for all channels of a mixer simple element - * \param elem Mixer simple element handle - * \param value control value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value) -{ - snd_mixer_selem_channel_id_t chn; - int err; - - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_capture_channel(elem, chn)) - continue; - err = snd_mixer_selem_set_capture_volume(elem, chn, value); - if (err < 0) - return err; - if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) - return 0; - } - return 0; -} - -/** - * \brief Set value in dB of capture volume control for all channels of a mixer simple element - * \param elem Mixer simple element handle - * \param value control value in dB * 100 - * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir) -{ - snd_mixer_selem_channel_id_t chn; - int err; - - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_capture_channel(elem, chn)) - continue; - err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir); - if (err < 0) - return err; - if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) - return 0; - } - return 0; -} - -/** - * \brief Set value of capture switch control of a mixer simple element - * \param elem Mixer simple element handle - * \param channel mixer simple element channel identifier - * \param value control value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) -{ - CHECK_BASIC(elem); - CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); - return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value); -} - -/** - * \brief Set value of capture switch control for all channels of a mixer simple element - * \param elem Mixer simple element handle - * \param value control value - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) -{ - snd_mixer_selem_channel_id_t chn; - int err; - - for (chn = 0; chn < 32; chn++) { - if (!snd_mixer_selem_has_capture_channel(elem, chn)) - continue; - err = snd_mixer_selem_set_capture_switch(elem, chn, value); - if (err < 0) - return err; - if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem)) - return 0; - } - return 0; -} - -/** - * \brief Return true if mixer simple element is an enumerated control - * \param elem Mixer simple element handle - * \return 0 normal volume/switch control, 1 enumerated control - */ -int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - CHECK_ENUM(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0); -} - -/** - * \brief Return true if mixer simple enumerated element belongs to the playback direction + * \brief Return true if mixer simple enumerated element belongs to the direction * \param elem Mixer simple element handle + * \param dir Mixer direction * \return 0 no playback direction, 1 playback direction */ -int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem) +int snd_amixer_elem_is_enum(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) { - CHECK_BASIC(elem); - CHECK_ENUM(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1); -} + int res; -/** - * \brief Return true if mixer simple enumerated element belongs to the capture direction - * \param elem Mixer simple element handle - * \return 0 no capture direction, 1 capture direction - */ -int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) -{ - CHECK_BASIC(elem); - CHECK_ENUM(elem); - return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1); + if (!(elem->sm.caps & (SM_CAP_PENUM|SM_CAP_CENUM))) + return 0; + return sm_elem_ops(elem)->is(elem, dir, SM_OPS_IS_ENUMERATED, 0); } /** @@ -911,11 +570,10 @@ int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) * \param elem Mixer simple element handle * \return the number of enumerated items, otherwise a negative error code */ -int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) +int snd_amixer_elem_get_enum_items(snd_amixer_elem_t *elem) { - CHECK_BASIC(elem); CHECK_ENUM(elem); - return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0); + return sm_elem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0); } /** @@ -926,13 +584,12 @@ int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) * \param buf the buffer to store the name string * \return 0 if successful, otherwise a negative error code */ -int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, +int snd_amixer_elem_get_enum_item_name(snd_amixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf) { - CHECK_BASIC(elem); CHECK_ENUM(elem); - return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf); + return sm_elem_ops(elem)->enum_item_name(elem, item, maxlen, buf); } /** @@ -942,13 +599,12 @@ int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, * \param itemp the pointer to store the index of the enumerated item * \return 0 if successful, otherwise a negative error code */ -int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, - snd_mixer_selem_channel_id_t channel, +int snd_amixer_elem_get_enum_item(snd_amixer_elem_t *elem, + snd_amixer_elem_channel_id_t channel, unsigned int *itemp) { - CHECK_BASIC(elem); CHECK_ENUM(elem); - return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp); + return sm_elem_ops(elem)->get_enum_item(elem, channel, itemp); } /** @@ -958,53 +614,52 @@ int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, * \param item the enumerated item index * \return 0 if successful, otherwise a negative error code */ -int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, - snd_mixer_selem_channel_id_t channel, +int snd_amixer_elem_set_enum_item(snd_amixer_elem_t *elem, + snd_amixer_elem_channel_id_t channel, unsigned int item) { - CHECK_BASIC(elem); CHECK_ENUM(elem); - return sm_selem_ops(elem)->set_enum_item(elem, channel, item); + return sm_elem_ops(elem)->set_enum_item(elem, channel, item); } /** - * \brief get size of #snd_mixer_selem_id_t + * \brief get size of #snd_amixer_elem_id_t * \return size in bytes */ -size_t snd_mixer_selem_id_sizeof() +size_t snd_amixer_elem_id_sizeof() { - return sizeof(snd_mixer_selem_id_t); + return sizeof(snd_amixer_elem_id_t); } /** - * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc + * \brief allocate an invalid #snd_amixer_elem_id_t using standard malloc * \param ptr returned pointer * \return 0 on success otherwise negative error code */ -int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr) +int snd_amixer_elem_id_malloc(snd_amixer_elem_id_t **ptr) { assert(ptr); - *ptr = calloc(1, sizeof(snd_mixer_selem_id_t)); + *ptr = calloc(1, sizeof(snd_amixer_elem_id_t)); if (!*ptr) return -ENOMEM; return 0; } /** - * \brief frees a previously allocated #snd_mixer_selem_id_t + * \brief frees a previously allocated #snd_amixer_elem_id_t * \param obj pointer to object to free */ -void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj) +void snd_amixer_elem_id_free(snd_amixer_elem_id_t *obj) { free(obj); } /** - * \brief copy one #snd_mixer_selem_id_t to another + * \brief copy one #snd_amixer_elem_id_t to another * \param dst pointer to destination * \param src pointer to source */ -void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src) +void snd_amixer_elem_id_copy(snd_amixer_elem_id_t *dst, const snd_amixer_elem_id_t *src) { assert(dst && src); *dst = *src; @@ -1015,7 +670,7 @@ void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id * \param obj Mixer simple element identifier * \return name part */ -const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) +const char *snd_amixer_elem_id_get_name(const snd_amixer_elem_id_t *obj) { assert(obj); return obj->name; @@ -1026,7 +681,7 @@ const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) * \param obj Mixer simple element identifier * \return index part */ -unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) +unsigned int snd_amixer_elem_id_get_index(const snd_amixer_elem_id_t *obj) { assert(obj); return obj->index; @@ -1037,7 +692,7 @@ unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) * \param obj Mixer simple element identifier * \param val name part */ -void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) +void snd_amixer_elem_id_set_name(snd_amixer_elem_id_t *obj, const char *val) { assert(obj); strncpy(obj->name, val, sizeof(obj->name)); @@ -1049,8 +704,20 @@ void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) * \param obj Mixer simple element identifier * \param val index part */ -void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val) +void snd_amixer_elem_id_set_index(snd_amixer_elem_id_t *obj, unsigned int val) { assert(obj); obj->index = val; } + +/** + * \brief Get simple mixer element abstraction structure + * \param obj Mixer simple element identifier + * \return sm_elem_t pointer + */ +sm_elem_t *snd_amixer_elem_get_sm(snd_amixer_elem_t *obj) +{ + assert(obj); + return &obj->sm; +} + diff --git a/src/mixer/simple_abst.c b/src/mixer/simple_abst.c deleted file mode 100644 index 9e9aaf55..00000000 --- a/src/mixer/simple_abst.c +++ /dev/null @@ -1,420 +0,0 @@ -/** - * \file mixer/simple_abst.c - * \brief Mixer Simple Element Class Interface - Module Abstraction - * \author Jaroslav Kysela - * \date 2005 - * - * Mixer simple element class interface. - */ -/* - * Mixer Interface - simple controls - abstraction module - * Copyright (c) 2005 by Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "asoundlib.h" -#include "mixer_simple.h" - -#ifndef DOC_HIDDEN - -#define SO_PATH ALSA_PLUGIN_DIR "/smixer" - -typedef struct _class_priv { - char *device; - snd_ctl_t *ctl; - snd_hctl_t *hctl; - int attach_flag; - snd_ctl_card_info_t *info; - void *dlhandle; - void *private_data; - void (*private_free)(snd_mixer_class_t *class); -} class_priv_t; - -typedef int (*snd_mixer_sbasic_init_t)(snd_mixer_class_t *class); -typedef int (*snd_mixer_sfbasic_init_t)(snd_mixer_class_t *class, - snd_mixer_t *mixer, - const char *device); - -#endif /* !DOC_HIDDEN */ - -static int try_open(snd_mixer_class_t *class, const char *lib) -{ - class_priv_t *priv = snd_mixer_class_get_private(class); - snd_mixer_event_t event_func; - snd_mixer_sbasic_init_t init_func = NULL; - char *xlib, *path; - void *h; - int err = 0; - - path = getenv("ALSA_MIXER_SIMPLE_MODULES"); - if (!path) - path = SO_PATH; - xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); - if (xlib == NULL) - return -ENOMEM; - strcpy(xlib, path); - strcat(xlib, "/"); - strcat(xlib, lib); - h = snd_dlopen(xlib, RTLD_NOW); - if (h == NULL) { - SNDERR("Unable to open library '%s'", xlib); - free(xlib); - return -ENXIO; - } - priv->dlhandle = h; - event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); - if (event_func == NULL) { - SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); - err = -ENXIO; - } - if (err == 0) { - init_func = snd_dlsym(h, "alsa_mixer_simple_init", NULL); - if (init_func == NULL) { - SNDERR("Symbol 'alsa_mixer_simple_init' was not found in '%s'", xlib); - err = -ENXIO; - } - } - free(xlib); - err = err == 0 ? init_func(class) : err; - if (err < 0) - return err; - snd_mixer_class_set_event(class, event_func); - return 1; -} - -static int try_open_full(snd_mixer_class_t *class, snd_mixer_t *mixer, - const char *lib, const char *device) -{ - class_priv_t *priv = snd_mixer_class_get_private(class); - snd_mixer_event_t event_func; - snd_mixer_sfbasic_init_t init_func = NULL; - char *xlib, *path; - void *h; - int err = 0; - - path = getenv("ALSA_MIXER_SIMPLE_MODULES"); - if (!path) - path = SO_PATH; - xlib = malloc(strlen(lib) + strlen(path) + 1 + 1); - if (xlib == NULL) - return -ENOMEM; - strcpy(xlib, path); - strcat(xlib, "/"); - strcat(xlib, lib); - /* note python modules requires RTLD_GLOBAL */ - h = snd_dlopen(xlib, RTLD_NOW|RTLD_GLOBAL); - if (h == NULL) { - SNDERR("Unable to open library '%s'", xlib); - free(xlib); - return -ENXIO; - } - priv->dlhandle = h; - event_func = snd_dlsym(h, "alsa_mixer_simple_event", NULL); - if (event_func == NULL) { - SNDERR("Symbol 'alsa_mixer_simple_event' was not found in '%s'", xlib); - err = -ENXIO; - } - if (err == 0) { - init_func = snd_dlsym(h, "alsa_mixer_simple_finit", NULL); - if (init_func == NULL) { - SNDERR("Symbol 'alsa_mixer_simple_finit' was not found in '%s'", xlib); - err = -ENXIO; - } - } - free(xlib); - err = err == 0 ? init_func(class, mixer, device) : err; - if (err < 0) - return err; - snd_mixer_class_set_event(class, event_func); - return 1; -} - -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_full(snd_mixer_class_t *class, snd_mixer_t *mixer, - snd_config_t *top, const char *device) -{ - snd_config_iterator_t i, next; - char *lib; - 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; - if (strcmp(id, "_full")) - continue; - err = snd_config_get_string(n, (const char **)&lib); - if (err < 0) - return err; - err = try_open_full(class, mixer, lib, device); - if (err < 0) - return err; - return 0; - } - return -ENOENT; -} - -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; - if (*id == '_') - 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->private_free) - priv->private_free(class); - if (priv->dlhandle) - snd_dlclose(priv->dlhandle); - if (priv->info) - snd_ctl_card_info_free(priv->info); - if (priv->hctl) { - if (priv->attach_flag) - snd_mixer_detach_hctl(snd_mixer_class_get_mixer(class), priv->hctl); - snd_hctl_close(priv->hctl); - } else if (priv->ctl) - snd_ctl_close(priv->ctl); - free(priv->device); - free(priv); -} - -/** - * \brief Register mixer simple element class - basic abstraction - * \param mixer Mixer handle - * \param options Options container - * \param classp Pointer to returned mixer simple element class handle (or NULL - * \return 0 on success otherwise a negative error code - */ -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; - class_priv_t *priv = calloc(1, sizeof(*priv)); - const char *file; - snd_input_t *input; - snd_config_t *top = NULL; - int err; - - if (priv == NULL) - return -ENOMEM; - if (options->device == NULL) { - free(priv); - return -EINVAL; - } - 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_compare(class, snd_mixer_selem_compare); - snd_mixer_class_set_private(class, priv); - snd_mixer_class_set_private_free(class, private_free); - file = getenv("ALSA_MIXER_SIMPLE"); - if (!file) - file = ALSA_CONFIG_DIR "/smixer.conf"; - 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_full(class, mixer, top, priv->device); - if (err >= 0) - goto __full; - } - if (err >= 0) { - 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; - } - if (err >= 0) - err = find_module(class, top); - if (err >= 0) - err = snd_mixer_attach_hctl(mixer, priv->hctl); - if (err >= 0) { - priv->attach_flag = 1; - err = snd_mixer_class_register(class, mixer); - } - __full: - 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; -} - -/** - * \brief Basic Mixer Abstraction - Get information about device - * \param class Mixer class - * \param info Info structure - * \return 0 on success otherwise a negative error code - */ -int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info) -{ - class_priv_t *priv = snd_mixer_class_get_private(class); - - if (class == NULL || info == NULL) - return -EINVAL; - info->device = priv->device; - info->ctl = priv->ctl; - info->hctl = priv->hctl; - info->info = priv->info; - return 0; -} - -/** - * \brief Get private data for basic abstraction - * \param class Mixer class - * \return private data - */ -void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class) -{ - class_priv_t *priv = snd_mixer_class_get_private(class); - - if (class == NULL) - return NULL; - return priv->private_data; -} - -/** - * \brief Set private data for basic abstraction - * \param class Mixer class - * \param private_data Private data - */ -void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data) -{ - class_priv_t *priv; - - if (class == NULL) - return; - priv = snd_mixer_class_get_private(class); - priv->private_data = private_data; -} - -/** - * \brief Set private data free callback for basic abstraction - * \param class Mixer class - * \param private_free free callback for private data - */ -void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)) -{ - class_priv_t *priv; - - if (class == NULL) - return; - priv = snd_mixer_class_get_private(class); - priv->private_free = private_free; -} diff --git a/src/mixer/simple_none.c b/src/mixer/simple_none.c index 48022004..63442111 100644 --- a/src/mixer/simple_none.c +++ b/src/mixer/simple_none.c @@ -5,7 +5,7 @@ * \author Abramo Bagnara * \date 2001-2004 * - * Mixer simple element class interface. + * Mixer simple element interface. */ /* * Mixer Interface - simple controls @@ -39,7 +39,12 @@ #include #include #include -#include "mixer_simple.h" +#include "mixer_abst.h" + +#ifndef PIC +/* entry for static linking */ +const char *_snd_module_mixer_none = ""; +#endif #ifndef DOC_HIDDEN @@ -66,7 +71,7 @@ typedef enum _selem_ctl_type { } selem_ctl_type_t; typedef struct _selem_ctl { - snd_hctl_elem_t *elem; + snd_ctl_elem_t *elem; snd_ctl_elem_type_t type; unsigned int inactive: 1; unsigned int values; @@ -74,7 +79,6 @@ typedef struct _selem_ctl { } selem_ctl_t; typedef struct _selem_none { - sm_selem_t selem; selem_ctl_t ctls[CTL_LAST + 1]; unsigned int capture_item; struct selem_str { @@ -211,7 +215,7 @@ static int get_compare_weight(const char *name, unsigned int idx) return MIXER_COMPARE_WEIGHT_SIMPLE_BASE + res + idx; } -static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) +static long to_user(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_t *c, long value) { int64_t n; if (c->max == c->min) @@ -220,7 +224,7 @@ static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) return s->str[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min); } -static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) +static long from_user(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_t *c, long value) { int64_t n; if (s->str[dir].max == s->str[dir].min) @@ -229,14 +233,15 @@ static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) return c->min + (n + (s->str[dir].max - s->str[dir].min) / 2) / (s->str[dir].max - s->str[dir].min); } -static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_read_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type) { + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < s->str[dir].channels; idx++) { unsigned int idx1 = idx; @@ -247,14 +252,15 @@ static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type) return 0; } -static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_read_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type) { + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < s->str[dir].channels; idx++) { unsigned int idx1 = idx; @@ -266,14 +272,15 @@ static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type) return 0; } -static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_read_route(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, selem_ctl_type_t type) { + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < s->str[dir].channels; idx++) { unsigned int idx1 = idx; @@ -285,23 +292,25 @@ static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type) return 0; } -static int elem_read_enum(selem_none_t *s) +static int elem_read_enum(snd_amixer_elem_t *elem) { + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); snd_ctl_elem_value_t *ctl; unsigned int idx; int err; int type; selem_ctl_t *c; type = CTL_GLOBAL_ENUM; - if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) + if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) type = CTL_GLOBAL_ENUM; - else if (s->selem.caps & SM_CAP_PENUM) + else if (sm->caps & SM_CAP_PENUM) type = CTL_PLAYBACK_ENUM; - else if (s->selem.caps & SM_CAP_CENUM) + else if (sm->caps & SM_CAP_CENUM) type = CTL_CAPTURE_ENUM; c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < s->str[0].channels; idx++) { unsigned int idx1 = idx; @@ -312,17 +321,15 @@ static int elem_read_enum(selem_none_t *s) return 0; } -static int selem_read(snd_mixer_elem_t *elem) +static int selem_read(snd_amixer_elem_t *elem) { - selem_none_t *s; + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); unsigned int idx; int err = 0; long pvol[32], cvol[32]; unsigned int psw, csw; - assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); - s = snd_mixer_elem_get_private(elem); - memcpy(pvol, s->str[SM_PLAY].vol, sizeof(pvol)); memset(&s->str[SM_PLAY].vol, 0, sizeof(s->str[SM_PLAY].vol)); psw = s->str[SM_PLAY].sw; @@ -333,21 +340,21 @@ static int selem_read(snd_mixer_elem_t *elem) s->str[SM_CAPT].sw = ~0U; if (s->ctls[CTL_GLOBAL_ENUM].elem) { - err = elem_read_enum(s); + err = elem_read_enum(elem); if (err < 0) return err; goto __skip_cswitch; } if (s->ctls[CTL_CAPTURE_ENUM].elem) { - err = elem_read_enum(s); + err = elem_read_enum(elem); if (err < 0) return err; goto __skip_cswitch; } if (s->ctls[CTL_PLAYBACK_ENUM].elem) { - err = elem_read_enum(s); + err = elem_read_enum(elem); if (err < 0) return err; goto __skip_cswitch; @@ -355,84 +362,84 @@ static int selem_read(snd_mixer_elem_t *elem) if (s->ctls[CTL_PLAYBACK_VOLUME].elem) - err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME); + err = elem_read_volume(elem, SM_PLAY, CTL_PLAYBACK_VOLUME); else if (s->ctls[CTL_GLOBAL_VOLUME].elem) - err = elem_read_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME); + err = elem_read_volume(elem, SM_PLAY, CTL_GLOBAL_VOLUME); else if (s->ctls[CTL_SINGLE].elem && s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) - err = elem_read_volume(s, SM_PLAY, CTL_SINGLE); + err = elem_read_volume(elem, SM_PLAY, CTL_SINGLE); if (err < 0) return err; - if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) { + if ((sm->caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) { s->str[SM_PLAY].sw = 0; goto __skip_pswitch; } if (s->ctls[CTL_PLAYBACK_SWITCH].elem) { - err = elem_read_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH); + err = elem_read_switch(elem, SM_PLAY, CTL_PLAYBACK_SWITCH); if (err < 0) return err; } if (s->ctls[CTL_GLOBAL_SWITCH].elem) { - err = elem_read_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH); + err = elem_read_switch(elem, SM_PLAY, CTL_GLOBAL_SWITCH); if (err < 0) return err; } if (s->ctls[CTL_SINGLE].elem && s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { - err = elem_read_switch(s, SM_PLAY, CTL_SINGLE); + err = elem_read_switch(elem, SM_PLAY, CTL_SINGLE); if (err < 0) return err; } if (s->ctls[CTL_PLAYBACK_ROUTE].elem) { - err = elem_read_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE); + err = elem_read_route(elem, SM_PLAY, CTL_PLAYBACK_ROUTE); if (err < 0) return err; } if (s->ctls[CTL_GLOBAL_ROUTE].elem) { - err = elem_read_route(s, SM_PLAY, CTL_GLOBAL_ROUTE); + err = elem_read_route(elem, SM_PLAY, CTL_GLOBAL_ROUTE); if (err < 0) return err; } __skip_pswitch: if (s->ctls[CTL_CAPTURE_VOLUME].elem) - err = elem_read_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME); + err = elem_read_volume(elem, SM_CAPT, CTL_CAPTURE_VOLUME); else if (s->ctls[CTL_GLOBAL_VOLUME].elem) - err = elem_read_volume(s, SM_CAPT, CTL_GLOBAL_VOLUME); + err = elem_read_volume(elem, SM_CAPT, CTL_GLOBAL_VOLUME); else if (s->ctls[CTL_SINGLE].elem && s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) - err = elem_read_volume(s, SM_CAPT, CTL_SINGLE); + err = elem_read_volume(elem, SM_CAPT, CTL_SINGLE); if (err < 0) return err; - if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) { + if ((sm->caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) { s->str[SM_CAPT].sw = 0; goto __skip_cswitch; } if (s->ctls[CTL_CAPTURE_SWITCH].elem) { - err = elem_read_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH); + err = elem_read_switch(elem, SM_CAPT, CTL_CAPTURE_SWITCH); if (err < 0) return err; } if (s->ctls[CTL_GLOBAL_SWITCH].elem) { - err = elem_read_switch(s, SM_CAPT, CTL_GLOBAL_SWITCH); + err = elem_read_switch(elem, SM_CAPT, CTL_GLOBAL_SWITCH); if (err < 0) return err; } if (s->ctls[CTL_SINGLE].elem && s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { - err = elem_read_switch(s, SM_CAPT, CTL_SINGLE); + err = elem_read_switch(elem, SM_CAPT, CTL_SINGLE); if (err < 0) return err; } if (s->ctls[CTL_CAPTURE_ROUTE].elem) { - err = elem_read_route(s, SM_CAPT, CTL_CAPTURE_ROUTE); + err = elem_read_route(elem, SM_CAPT, CTL_CAPTURE_ROUTE); if (err < 0) return err; } if (s->ctls[CTL_GLOBAL_ROUTE].elem) { - err = elem_read_route(s, SM_CAPT, CTL_GLOBAL_ROUTE); + err = elem_read_route(elem, SM_CAPT, CTL_GLOBAL_ROUTE); if (err < 0) return err; } @@ -440,7 +447,7 @@ static int selem_read(snd_mixer_elem_t *elem) snd_ctl_elem_value_t *ctl; selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; snd_ctl_elem_value_alloca(&ctl); - err = snd_hctl_elem_read(c->elem, ctl); + err = snd_ctl_celem_read(c->elem, ctl); if (err < 0) return err; for (idx = 0; idx < s->str[SM_CAPT].channels; idx++) { @@ -461,34 +468,34 @@ static int selem_read(snd_mixer_elem_t *elem) return 0; } -static int elem_write_volume(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_write_volume(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type) { snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values; idx++) snd_ctl_elem_value_set_integer(ctl, idx, from_user(s, dir, c, s->str[dir].vol[idx])); - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; return 0; } -static int elem_write_switch(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_write_switch(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type) { snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values; idx++) snd_ctl_elem_value_set_integer(ctl, idx, !!(s->str[dir].sw & (1 << idx))); - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; return 0; } @@ -500,75 +507,75 @@ static int elem_write_switch_constant(selem_none_t *s, selem_ctl_type_t type, in int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values; idx++) snd_ctl_elem_value_set_integer(ctl, idx, !!val); - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; return 0; } -static int elem_write_route(selem_none_t *s, int dir, selem_ctl_type_t type) +static int elem_write_route(selem_none_t *s, snd_amixer_dir_t dir, selem_ctl_type_t type) { snd_ctl_elem_value_t *ctl; unsigned int idx; int err; selem_ctl_t *c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values * c->values; idx++) snd_ctl_elem_value_set_integer(ctl, idx, 0); for (idx = 0; idx < c->values; idx++) snd_ctl_elem_value_set_integer(ctl, idx * c->values + idx, !!(s->str[dir].sw & (1 << idx))); - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; return 0; } -static int elem_write_enum(selem_none_t *s) +static int elem_write_enum(snd_amixer_elem_t *elem) { + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); snd_ctl_elem_value_t *ctl; + unsigned int idx; int err; int type; selem_ctl_t *c; type = CTL_GLOBAL_ENUM; - if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) ) + if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) ) type = CTL_GLOBAL_ENUM; - else if (s->selem.caps & SM_CAP_PENUM) + else if (sm->caps & SM_CAP_PENUM) type = CTL_PLAYBACK_ENUM; - else if (s->selem.caps & SM_CAP_CENUM) + else if (sm->caps & SM_CAP_CENUM) type = CTL_CAPTURE_ENUM; c = &s->ctls[type]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values; idx++) snd_ctl_elem_value_set_enumerated(ctl, idx, (unsigned int)s->str[0].vol[idx]); - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; return 0; } -static int selem_write_main(snd_mixer_elem_t *elem) +static int selem_write_main(snd_amixer_elem_t *elem) { - selem_none_t *s; + selem_none_t *s = snd_amixer_elem_get_private(elem); unsigned int idx; int err; - assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); - s = snd_mixer_elem_get_private(elem); - if (s->ctls[CTL_GLOBAL_ENUM].elem) - return elem_write_enum(s); + return elem_write_enum(elem); if (s->ctls[CTL_PLAYBACK_ENUM].elem) - return elem_write_enum(s); + return elem_write_enum(elem); if (s->ctls[CTL_CAPTURE_ENUM].elem) - return elem_write_enum(s); + return elem_write_enum(elem); if (s->ctls[CTL_SINGLE].elem) { if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) @@ -625,13 +632,13 @@ static int selem_write_main(snd_mixer_elem_t *elem) snd_ctl_elem_value_t *ctl; selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; snd_ctl_elem_value_alloca(&ctl); - if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_read(c->elem, ctl)) < 0) return err; for (idx = 0; idx < c->values; idx++) { if (s->str[SM_CAPT].sw & (1 << idx)) snd_ctl_elem_value_set_enumerated(ctl, idx, s->capture_item); } - if ((err = snd_hctl_elem_write(c->elem, ctl)) < 0) + if ((err = snd_ctl_celem_write(c->elem, ctl)) < 0) return err; /* update the element, don't remove */ err = selem_read(elem); @@ -641,7 +648,7 @@ static int selem_write_main(snd_mixer_elem_t *elem) return 0; } -static int selem_write(snd_mixer_elem_t *elem) +static int selem_write(snd_amixer_elem_t *elem) { int err; @@ -651,21 +658,19 @@ static int selem_write(snd_mixer_elem_t *elem) return err; } -static void selem_free(snd_mixer_elem_t *elem) +static void selem_free(snd_amixer_elem_t *elem) { - selem_none_t *simple = snd_mixer_elem_get_private(elem); - assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); - if (simple->selem.id) - snd_mixer_selem_id_free(simple->selem.id); + selem_none_t *simple = snd_amixer_elem_get_private(elem); /* free db range information */ free(simple->str[0].db_info); free(simple->str[1].db_info); free(simple); } -static int simple_update(snd_mixer_elem_t *melem) +static int simple_update(snd_amixer_elem_t *melem) { selem_none_t *simple; + sm_elem_t *sm; unsigned int caps, pchannels, cchannels; long pmin, pmax, cmin, cmax; selem_ctl_t *ctl; @@ -678,9 +683,9 @@ static int simple_update(snd_mixer_elem_t *melem) cchannels = 0; cmin = LONG_MAX; cmax = LONG_MIN; - assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE); - simple = snd_mixer_elem_get_private(melem); - name = snd_mixer_selem_get_name(melem); + simple = snd_amixer_elem_get_private(melem); + sm = snd_amixer_elem_get_sm(melem); + name = snd_amixer_elem_get_name(melem); ctl = &simple->ctls[CTL_SINGLE]; if (ctl->elem) { pchannels = cchannels = ctl->values; @@ -868,7 +873,7 @@ static int simple_update(snd_mixer_elem_t *melem) (caps & (SM_CAP_PVOLUME|SM_CAP_CVOLUME)) == 0) caps |= SM_CAP_PVOLUME|SM_CAP_CVOLUME; - simple->selem.caps = caps; + sm->caps = caps; simple->str[SM_PLAY].channels = pchannels; if (!simple->str[SM_PLAY].range) { simple->str[SM_PLAY].min = pmin != LONG_MAX ? pmin : 0; @@ -943,16 +948,17 @@ static int base_len(const char *name, selem_ctl_type_t *type) * Simple Mixer Operations */ -static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value) +static int _snd_amixer_selem_set_volume(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, long value) { - selem_none_t *s = snd_mixer_elem_get_private(elem); - if (s->selem.caps & SM_CAP_GVOLUME) + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; if ((unsigned int) channel >= s->str[dir].channels) return 0; if (value < s->str[dir].min || value > s->str[dir].max) return 0; - if (s->selem.caps & + if (sm->caps & (dir == SM_PLAY ? SM_CAP_PVOLUME_JOIN : SM_CAP_CVOLUME_JOIN)) channel = 0; if (value != s->str[dir].vol[channel]) { @@ -962,12 +968,14 @@ static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixe return 0; } -static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value) +static int _snd_amixer_selem_set_switch(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, snd_amixer_elem_channel_id_t channel, int value) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); + if ((unsigned int) channel >= s->str[dir].channels) return 0; - if (s->selem.caps & + if (sm->caps & (dir == SM_PLAY ? SM_CAP_PSWITCH_JOIN : SM_CAP_CSWITCH_JOIN)) channel = 0; if (value) { @@ -984,9 +992,10 @@ static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixe return 0; } -static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) +static int is_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, int cmd, int val) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); switch (cmd) { @@ -998,37 +1007,31 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) return 1; } - case SM_OPS_IS_MONO: - return s->str[dir].channels == 1; - case SM_OPS_IS_CHANNEL: return (unsigned int) val < s->str[dir].channels; case SM_OPS_IS_ENUMERATED: - if (val == 1) { - if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) ) - return 1; - if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) ) - return 1; - return 0; - } - if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) + if (dir == SM_PLAY && (sm->caps & SM_CAP_PENUM) && !(sm->caps & SM_CAP_CENUM)) + return 1; + if (dir == SM_CAPT && (sm->caps & SM_CAP_CENUM) && !(sm->caps & SM_CAP_PENUM)) + return 1; + if (dir == SM_COMM && (sm->caps & (SM_CAP_CENUM|SM_CAP_PENUM)) == (SM_CAP_CENUM|SM_CAP_PENUM)) return 1; return 0; case SM_OPS_IS_ENUMCNT: /* Both */ - if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) { + if ( (sm->caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) { if (! s->ctls[CTL_GLOBAL_ENUM].elem) return -EINVAL; return s->ctls[CTL_GLOBAL_ENUM].max; /* Only Playback */ - } else if (s->selem.caps & SM_CAP_PENUM ) { + } else if (sm->caps & SM_CAP_PENUM ) { if (! s->ctls[CTL_PLAYBACK_ENUM].elem) return -EINVAL; return s->ctls[CTL_PLAYBACK_ENUM].max; /* Only Capture */ - } else if (s->selem.caps & SM_CAP_CENUM ) { + } else if (sm->caps & SM_CAP_CENUM ) { if (! s->ctls[CTL_CAPTURE_ENUM].elem) return -EINVAL; return s->ctls[CTL_CAPTURE_ENUM].max; @@ -1039,19 +1042,25 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) return 1; } -static int get_range_ops(snd_mixer_elem_t *elem, int dir, +static int get_channels_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir) +{ + selem_none_t *s = snd_amixer_elem_get_private(elem); + return s->str[dir].channels; +} + +static int get_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); *min = s->str[dir].min; *max = s->str[dir].max; return 0; } -static int set_range_ops(snd_mixer_elem_t *elem, int dir, +static int set_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long min, long max) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); int err; s->str[dir].range = 1; @@ -1062,11 +1071,12 @@ static int set_range_ops(snd_mixer_elem_t *elem, int dir, return 0; } -static int get_volume_ops(snd_mixer_elem_t *elem, int dir, - snd_mixer_selem_channel_id_t channel, long *value) +static int get_volume_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, long *value) { - selem_none_t *s = snd_mixer_elem_get_private(elem); - if (s->selem.caps & SM_CAP_GVOLUME) + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; if ((unsigned int) channel >= s->str[dir].channels) return -EINVAL; @@ -1074,9 +1084,9 @@ static int get_volume_ops(snd_mixer_elem_t *elem, int dir, return 0; } -static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec); +static int init_db_range(snd_ctl_elem_t *ctl, struct selem_str *rec); -static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, +static int convert_to_dB(snd_ctl_elem_t *ctl, struct selem_str *rec, long volume, long *db_gain) { if (init_db_range(ctl, rec) < 0) @@ -1087,7 +1097,7 @@ static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, /* initialize dB range information, reading TLV via hcontrol */ -static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec) +static int init_db_range(snd_ctl_elem_t *ctl, struct selem_str *rec) { snd_ctl_elem_info_t *info; unsigned int *tlv = NULL; @@ -1101,14 +1111,14 @@ static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec) return 0; snd_ctl_elem_info_alloca(&info); - if (snd_hctl_elem_info(ctl, info) < 0) + if (snd_ctl_celem_info(ctl, info) < 0) goto error; if (! snd_ctl_elem_info_is_tlv_readable(info)) goto error; tlv = malloc(tlv_size); if (! tlv) return -ENOMEM; - if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0) + if (snd_ctl_celem_tlv_read(ctl, tlv, tlv_size) < 0) goto error; db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec); if (db_size < 0) @@ -1128,7 +1138,7 @@ static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec) } /* get selem_ctl for TLV access */ -static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir) +static selem_ctl_t *get_selem_ctl(selem_none_t *s, snd_amixer_dir_t dir) { selem_ctl_t *c; if (dir == SM_PLAY) @@ -1147,7 +1157,7 @@ static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir) return c; } -static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec, +static int get_dB_range(snd_ctl_elem_t *ctl, struct selem_str *rec, long *min, long *max) { if (init_db_range(ctl, rec) < 0) @@ -1156,13 +1166,14 @@ static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec, return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max); } -static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, +static int get_dB_range_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long *min, long *max) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); selem_ctl_t *c; - if (s->selem.caps & SM_CAP_GVOLUME) + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; c = get_selem_ctl(s, dir); if (! c) @@ -1170,7 +1181,7 @@ static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, return get_dB_range(c->elem, &s->str[dir], min, max); } -static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, +static int convert_from_dB(snd_ctl_elem_t *ctl, struct selem_str *rec, long db_gain, long *value, int xdir) { if (init_db_range(ctl, rec) < 0) @@ -1180,12 +1191,12 @@ static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, db_gain, value, xdir); } -static int ask_vol_dB_ops(snd_mixer_elem_t *elem, - int dir, +static int ask_vol_dB_ops(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, long value, long *dBvalue) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); selem_ctl_t *c; c = get_selem_ctl(s, dir); @@ -1195,17 +1206,18 @@ static int ask_vol_dB_ops(snd_mixer_elem_t *elem, return res; } -static int get_dB_ops(snd_mixer_elem_t *elem, - int dir, - snd_mixer_selem_channel_id_t channel, +static int get_dB_ops(snd_amixer_elem_t *elem, + snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, long *value) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); selem_ctl_t *c; int err; long volume, db_gain; - if (s->selem.caps & SM_CAP_GVOLUME) + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; c = get_selem_ctl(s, dir); if (! c) @@ -1220,11 +1232,12 @@ static int get_dB_ops(snd_mixer_elem_t *elem, return err; } -static int get_switch_ops(snd_mixer_elem_t *elem, int dir, - snd_mixer_selem_channel_id_t channel, int *value) +static int get_switch_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, int *value) { - selem_none_t *s = snd_mixer_elem_get_private(elem); - if (s->selem.caps & SM_CAP_GSWITCH) + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); + if (sm->caps & SM_CAP_GSWITCH) dir = SM_PLAY; if ((unsigned int) channel >= s->str[dir].channels) return -EINVAL; @@ -1232,11 +1245,11 @@ static int get_switch_ops(snd_mixer_elem_t *elem, int dir, return 0; } -static int set_volume_ops(snd_mixer_elem_t *elem, int dir, - snd_mixer_selem_channel_id_t channel, long value) +static int set_volume_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, long value) { int changed; - changed = _snd_mixer_selem_set_volume(elem, dir, channel, value); + changed = _snd_amixer_selem_set_volume(elem, dir, channel, value); if (changed < 0) return changed; if (changed) @@ -1244,13 +1257,14 @@ static int set_volume_ops(snd_mixer_elem_t *elem, int dir, return 0; } -static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir, +static int ask_dB_vol_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, long dbValue, long *value, int xdir) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); selem_ctl_t *c; - if (s->selem.caps & SM_CAP_GVOLUME) + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; c = get_selem_ctl(s, dir); if (! c) @@ -1258,16 +1272,17 @@ static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir, return convert_from_dB(c->elem, &s->str[dir], dbValue, value, xdir); } -static int set_dB_ops(snd_mixer_elem_t *elem, int dir, - snd_mixer_selem_channel_id_t channel, +static int set_dB_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, long db_gain, int xdir) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); selem_ctl_t *c; long value; int err; - if (s->selem.caps & SM_CAP_GVOLUME) + if (sm->caps & SM_CAP_GVOLUME) dir = SM_PLAY; c = get_selem_ctl(s, dir); if (! c) @@ -1278,21 +1293,21 @@ static int set_dB_ops(snd_mixer_elem_t *elem, int dir, return set_volume_ops(elem, dir, channel, value); } -static int set_switch_ops(snd_mixer_elem_t *elem, int dir, - snd_mixer_selem_channel_id_t channel, int value) +static int set_switch_ops(snd_amixer_elem_t *elem, snd_amixer_dir_t dir, + snd_amixer_elem_channel_id_t channel, int value) { int changed; - selem_none_t *s = snd_mixer_elem_get_private(elem); - if (s->selem.caps & SM_CAP_GSWITCH) + sm_elem_t *sm = snd_amixer_elem_get_sm(elem); + if (sm->caps & SM_CAP_GSWITCH) dir = SM_PLAY; if (dir == SM_PLAY) { - if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH))) + if (! (sm->caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH))) return -EINVAL; } else { - if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH))) + if (! (sm->caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH))) return -EINVAL; } - changed = _snd_mixer_selem_set_switch(elem, dir, channel, value); + changed = _snd_amixer_selem_set_switch(elem, dir, channel, value); if (changed < 0) return changed; if (changed) @@ -1300,13 +1315,13 @@ static int set_switch_ops(snd_mixer_elem_t *elem, int dir, return 0; } -static int enum_item_name_ops(snd_mixer_elem_t *elem, +static int enum_item_name_ops(snd_amixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_info_t *info; - snd_hctl_elem_t *helem; + snd_ctl_elem_t *helem; int type; type = CTL_GLOBAL_ENUM; @@ -1323,20 +1338,20 @@ static int enum_item_name_ops(snd_mixer_elem_t *elem, if (item >= (unsigned int)s->ctls[type].max) return -EINVAL; snd_ctl_elem_info_alloca(&info); - snd_hctl_elem_info(helem, info); + snd_ctl_celem_info(helem, info); snd_ctl_elem_info_set_item(info, item); - snd_hctl_elem_info(helem, info); + snd_ctl_celem_info(helem, info); strncpy(buf, snd_ctl_elem_info_get_item_name(info), maxlen); return 0; } -static int get_enum_item_ops(snd_mixer_elem_t *elem, - snd_mixer_selem_channel_id_t channel, +static int get_enum_item_ops(snd_amixer_elem_t *elem, + snd_amixer_elem_channel_id_t channel, unsigned int *itemp) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_value_t *ctl; - snd_hctl_elem_t *helem; + snd_ctl_elem_t *helem; int err; if ((unsigned int) channel >= s->str[0].channels) @@ -1346,19 +1361,19 @@ static int get_enum_item_ops(snd_mixer_elem_t *elem, if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem; assert(helem); snd_ctl_elem_value_alloca(&ctl); - err = snd_hctl_elem_read(helem, ctl); + err = snd_ctl_celem_read(helem, ctl); if (! err) *itemp = snd_ctl_elem_value_get_enumerated(ctl, channel); return err; } -static int set_enum_item_ops(snd_mixer_elem_t *elem, - snd_mixer_selem_channel_id_t channel, +static int set_enum_item_ops(snd_amixer_elem_t *elem, + snd_amixer_elem_channel_id_t channel, unsigned int item) { - selem_none_t *s = snd_mixer_elem_get_private(elem); + selem_none_t *s = snd_amixer_elem_get_private(elem); snd_ctl_elem_value_t *ctl; - snd_hctl_elem_t *helem; + snd_ctl_elem_t *helem; int err; int type; @@ -1380,16 +1395,17 @@ static int set_enum_item_ops(snd_mixer_elem_t *elem, return -EINVAL; } snd_ctl_elem_value_alloca(&ctl); - err = snd_hctl_elem_read(helem, ctl); + err = snd_ctl_celem_read(helem, ctl); if (err < 0) { return err; } snd_ctl_elem_value_set_enumerated(ctl, channel, item); - return snd_hctl_elem_write(helem, ctl); + return snd_ctl_celem_write(helem, ctl); } static struct sm_elem_ops simple_none_ops = { .is = is_ops, + .get_channels = get_channels_ops, .get_range = get_range_ops, .get_dB_range = get_dB_range_ops, .set_range = set_range_ops, @@ -1406,12 +1422,13 @@ static struct sm_elem_ops simple_none_ops = { .set_enum_item = set_enum_item_ops }; -static int simple_add1(snd_mixer_class_t *class, const char *name, - snd_hctl_elem_t *helem, selem_ctl_type_t type, +static int simple_add1(snd_amixer_t *amixer, const char *name, + snd_ctl_elem_t *helem, selem_ctl_type_t type, unsigned int value) { - snd_mixer_elem_t *melem; - snd_mixer_selem_id_t *id; + snd_amixer_elem_t *melem; + sm_elem_t *sm; + snd_amixer_elem_id_t *id; int new = 0; int err; snd_ctl_elem_info_t *info; @@ -1421,7 +1438,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, unsigned long values; snd_ctl_elem_info_alloca(&info); - err = snd_hctl_elem_info(helem, info); + err = snd_ctl_celem_info(helem, info); if (err < 0) return err; ctype = snd_ctl_elem_info_get_type(info); @@ -1508,39 +1525,42 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, break; } name1 = get_short_name(name); - if (snd_mixer_selem_id_malloc(&id)) + if (snd_amixer_elem_id_malloc(&id)) return -ENOMEM; - snd_mixer_selem_id_set_name(id, name1); - snd_mixer_selem_id_set_index(id, snd_hctl_elem_get_index(helem)); - melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id); + snd_amixer_elem_id_set_name(id, name1); + snd_amixer_elem_id_set_index(id, snd_ctl_elem_get_index(helem)); + melem = snd_amixer_find_elem(amixer, id); if (!melem) { simple = calloc(1, sizeof(*simple)); if (!simple) { - snd_mixer_selem_id_free(id); + snd_amixer_elem_id_free(id); return -ENOMEM; } - simple->selem.id = id; - simple->selem.ops = &simple_none_ops; - err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE, - get_compare_weight(snd_mixer_selem_id_get_name(simple->selem.id), snd_mixer_selem_id_get_index(simple->selem.id)), - simple, selem_free); + err = snd_amixer_elem_new(amixer, + &melem, + id, + get_compare_weight(snd_amixer_elem_id_get_name(id), snd_amixer_elem_id_get_index(id)), + simple, selem_free); + snd_amixer_elem_id_free(id); if (err < 0) { - snd_mixer_selem_id_free(id); + snd_amixer_elem_id_free(id); free(simple); return err; } + sm = snd_amixer_elem_get_sm(melem); + sm->ops = &simple_none_ops; new = 1; } else { - simple = snd_mixer_elem_get_private(melem); - snd_mixer_selem_id_free(id); + simple = snd_amixer_elem_get_private(melem); + snd_amixer_elem_id_free(id); } if (simple->ctls[type].elem) { SNDERR("helem (%s,'%s',%u,%u,%u) appears twice or more", - snd_ctl_elem_iface_name(snd_hctl_elem_get_interface(helem)), - snd_hctl_elem_get_name(helem), - snd_hctl_elem_get_index(helem), - snd_hctl_elem_get_device(helem), - snd_hctl_elem_get_subdevice(helem)); + snd_ctl_elem_iface_name(snd_ctl_elem_get_interface(helem)), + snd_ctl_elem_get_name(helem), + snd_ctl_elem_get_index(helem), + snd_ctl_elem_get_device(helem), + snd_ctl_elem_get_subdevice(helem)); err = -EINVAL; goto __error; } @@ -1566,7 +1586,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, default: break; } - err = snd_mixer_elem_attach(melem, helem); + err = snd_amixer_elem_attach(melem, helem); if (err < 0) goto __error; err = simple_update(melem); @@ -1576,36 +1596,36 @@ static int simple_add1(snd_mixer_class_t *class, const char *name, return err; } if (new) - err = snd_mixer_elem_add(melem, class); + err = snd_amixer_elem_add(amixer, melem); else - err = snd_mixer_elem_info(melem); + err = snd_amixer_elem_info(melem); if (err < 0) return err; err = selem_read(melem); if (err < 0) return err; if (err) - err = snd_mixer_elem_value(melem); + err = snd_amixer_elem_value(melem); return err; __error: if (new) - snd_mixer_elem_free(melem); + snd_amixer_elem_free(melem); return -EINVAL; } -static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) +static int simple_event_add(snd_amixer_t *amixer, snd_ctl_elem_t *helem) { - const char *name = snd_hctl_elem_get_name(helem); + const char *name = snd_ctl_elem_get_name(helem); size_t len; selem_ctl_type_t type = CTL_SINGLE; /* to shut up warning */ - if (snd_hctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER) + if (snd_ctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER) return 0; if (strcmp(name, "Capture Source") == 0) { snd_ctl_elem_info_t *info; unsigned int k, items; int err; snd_ctl_elem_info_alloca(&info); - err = snd_hctl_elem_info(helem, info); + err = snd_ctl_celem_info(helem, info); assert(err >= 0); if (snd_ctl_elem_info_get_type(info) != SND_CTL_ELEM_TYPE_ENUMERATED) return 0; @@ -1613,11 +1633,11 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) for (k = 0; k < items; ++k) { const char *n; snd_ctl_elem_info_set_item(info, k); - err = snd_hctl_elem_info(helem, info); + err = snd_ctl_celem_info(helem, info); if (err < 0) return err; n = snd_ctl_elem_info_get_item_name(info); - err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE, k); + err = simple_add1(amixer, n, helem, CTL_CAPTURE_SOURCE, k); if (err < 0) return err; } @@ -1625,7 +1645,7 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) } len = base_len(name, &type); if (len == 0) { - return simple_add1(class, name, helem, CTL_SINGLE, 0); + return simple_add1(amixer, name, helem, CTL_SINGLE, 0); } else { char ename[128]; if (len >= sizeof(ename)) @@ -1637,14 +1657,14 @@ static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) type = CTL_CAPTURE_VOLUME; else if (type == CTL_GLOBAL_SWITCH && !strcmp(ename, "Capture")) type = CTL_CAPTURE_SWITCH; - return simple_add1(class, ename, helem, type, 0); + return simple_add1(amixer, ename, helem, type, 0); } } -static int simple_event_remove(snd_hctl_elem_t *helem, - snd_mixer_elem_t *melem) +static int simple_event_remove(snd_ctl_elem_t *helem, + snd_amixer_elem_t *melem) { - selem_none_t *simple = snd_mixer_elem_get_private(melem); + selem_none_t *simple = snd_amixer_elem_get_private(melem); int err; int k; for (k = 0; k <= CTL_LAST; k++) { @@ -1653,23 +1673,23 @@ static int simple_event_remove(snd_hctl_elem_t *helem, } assert(k <= CTL_LAST); simple->ctls[k].elem = NULL; - err = snd_mixer_elem_detach(melem, helem); + err = snd_amixer_elem_detach(melem, helem); if (err < 0) return err; - if (snd_mixer_elem_empty(melem)) - return snd_mixer_elem_remove(melem); + if (snd_amixer_elem_is_empty(melem)) + return snd_amixer_elem_remove(melem); err = simple_update(melem); - return snd_mixer_elem_info(melem); + return snd_amixer_elem_info(melem); } -static int simple_event(snd_mixer_class_t *class, unsigned int mask, - snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) +static int simple_event(snd_amixer_t *amixer, unsigned int mask, + snd_ctl_elem_t *helem, snd_amixer_elem_t *melem) { int err; if (mask == SND_CTL_EVENT_MASK_REMOVE) return simple_event_remove(helem, melem); if (mask & SND_CTL_EVENT_MASK_ADD) { - err = simple_event_add(class, helem); + err = simple_event_add(amixer, helem); if (err < 0) return err; } @@ -1677,7 +1697,7 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask, err = simple_event_remove(helem, melem); if (err < 0) return err; - err = simple_event_add(class, helem); + err = simple_event_add(amixer, helem); if (err < 0) return err; return 0; @@ -1687,7 +1707,7 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask, if (err < 0) return err; if (err) { - err = snd_mixer_elem_value(melem); + err = snd_amixer_elem_value(melem); if (err < 0) return err; } @@ -1695,30 +1715,75 @@ static int simple_event(snd_mixer_class_t *class, unsigned int mask, return 0; } +#ifndef DOC_HIDDEN /** - * \brief Register mixer simple element class - none abstraction - * \param mixer Mixer handle - * \param options Options container - * \param classp Pointer to returned mixer simple element class handle (or NULL) + * \brief Open mixer - none abstraction + * \param amixer Mixer handle + * \param name Device name + * \param pcm_playback PCM handle for playback + * \param pcm_capture PCM handle for capture + * \param mode Open mode * \return 0 on success otherwise a negative error code */ -int snd_mixer_simple_none_register(snd_mixer_t *mixer, - struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED, - snd_mixer_class_t **classp) +int _snd_amixer_none_open(snd_amixer_t *amixer, + snd_config_t *root ATTRIBUTE_UNUSED, + snd_config_t *conf, + struct sm_open *sm_open) { - snd_mixer_class_t *class; + snd_config_iterator_t i, next; + const char *str; int err; - - if (snd_mixer_class_malloc(&class)) - return -ENOMEM; - snd_mixer_class_set_event(class, simple_event); - snd_mixer_class_set_compare(class, snd_mixer_selem_compare); - err = snd_mixer_class_register(class, mixer); - if (err < 0) { - free(class); - return err; + snd_config_t *n; + char ctlname[64]; + + ctlname[0] = '\0'; + if (sm_open->pcm_playback || sm_open->pcm_capture) + return -ENXIO; + snd_config_for_each(i, next, conf) { + const char *id; + n = snd_config_iterator_entry(i); + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_amixer_conf_generic_id(id)) + continue; + if (strcmp(id, "card") == 0) { + long card = -1; + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + return card; + } + } + sprintf(ctlname, "hw:%li", card); + continue; + } + if (strcmp(id, "ctlname") == 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("ctlname must be a string"); + return -EINVAL; + } + strncpy(ctlname, str, sizeof(ctlname)-1); + ctlname[sizeof(ctlname)-1] = '\0'; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; } - if (classp) - *classp = class; - return 0; + if (ctlname[0] == '\0') { + SNDERR("card or ctlname is not defined"); + return -EINVAL; + } + snd_amixer_set_event(amixer, simple_event); + return snd_ctl_open(&sm_open->ctl[0], ctlname, SND_CTL_CACHE); } + +SND_DLSYM_BUILD_VERSION(_snd_amixer_none_open, SND_AMIXER_DLSYM_VERSION); +#endif diff --git a/src/mixer/simple_old.c b/src/mixer/simple_old.c new file mode 100644 index 00000000..339b9940 --- /dev/null +++ b/src/mixer/simple_old.c @@ -0,0 +1,805 @@ +/** + * \file mixer/simple.c + * \brief Mixer Simple Element Class Interface + * \author Jaroslav Kysela + * \author Abramo Bagnara + * \date 2001-2004 + * + * Mixer simple element class interface. + */ +/* + * Mixer Interface - simple controls + * Copyright (c) 2000,2004 by Jaroslav Kysela + * Copyright (c) 2001 by Abramo Bagnara + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mixer_old_local.h" + +#define SM_PLAY SND_MIXER_DIR_PLAYBACK +#define SM_CAPT SND_MIXER_DIR_CAPTURE +#define SM_COMM SND_MIXER_DIR_COMMON + +/** + * \brief Register mixer simple element class + * \param mixer Mixer handle + * \param options Options container + * \param nothing Pass NULL + * \return zero on success, otherwise a negative error code + */ +int snd_mixer_selem_register(snd_mixer_t *mixer, + struct snd_mixer_selem_regopt *options, + void **nothing ATTRIBUTE_UNUSED) +{ + int err; + + if (options && options->ver == 1) { + if (options->device != NULL && + (options->playback_pcm != NULL || + options->capture_pcm != NULL)) + return -EINVAL; + if (options->device == NULL && + options->playback_pcm == NULL && + options->capture_pcm == NULL) + return -EINVAL; + } + if (options == NULL || + (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) { + if (options != NULL) { + err = snd_mixer_attach(mixer, options->device); + if (err < 0) + return err; + } + return 0; + } else if (options->ver == 1) { + if (options->abstract == SND_MIXER_SABSTRACT_BASIC) + return snd_mixer_attach(mixer, options->device); + } + return -ENXIO; +} + +/** + * \brief Find a mixer simple element + * \param mixer Mixer handle + * \param id Mixer simple element identifier + * \return mixer simple element handle or NULL if not found + */ +snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, + const snd_mixer_selem_id_t *id) +{ + return snd_amixer_find_elem(mixer->amixer, id); +} + +/** + * \brief Get mixer simple element identifier + * \param elem Mixer simple element handle + * \param id returned mixer simple element identifier + */ +void snd_mixer_selem_get_id(snd_mixer_elem_t *elem, + snd_mixer_selem_id_t *id) +{ + return snd_amixer_elem_get_id(elem, id); +} + +/** + * \brief Get name part of mixer simple element identifier + * \param elem Mixer simple element handle + * \return name part of simple element identifier + */ +const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_name(elem); +} + +/** + * \brief Get index part of mixer simple element identifier + * \param elem Mixer simple element handle + * \return index part of simple element identifier + */ +unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_index(elem); +} + +/** + * \brief Return true if mixer simple element has only one volume control for both playback and capture + * \param elem Mixer simple element handle + * \return 0 separated control, 1 common control + */ +int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_volume(elem, SM_COMM); +} + +/** + * \brief Return true if mixer simple element has only one switch control for both playback and capture + * \param elem Mixer simple element handle + * \return 0 separated control, 1 common control + */ +int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch(elem, SM_COMM); +} + +/** + * \brief Return name of mixer simple element channel + * \param channel mixer simple element channel identifier + * \return channel name + */ +const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel) +{ + return snd_amixer_elem_channel_name(channel); +} + +/** + * \brief Get info about the active state of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not active, 1 if active + */ +int snd_mixer_selem_is_active(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_is_active(elem); +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_channels(elem, SM_PLAY) == 1; +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) +{ + return snd_amixer_elem_has_channel(elem, SM_PLAY, channel); +} + +/** + * \brief Get range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + return snd_amixer_elem_get_volume_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Get range in dB for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum (dB * 100) + * \param max Pointer to returned maximum (dB * 100) + */ +int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + return snd_amixer_elem_get_dB_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Set range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, + long min, long max) +{ + return snd_amixer_elem_set_volume_range(elem, SM_PLAY, min, max); +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_volume(elem, SM_PLAY); +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_volume_joined(elem, SM_PLAY); +} + +/** + * \brief Return info about playback switch control existence of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch(elem, SM_PLAY); +} + +/** + * \brief Return info about playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch_joined(elem, SM_PLAY); +} + +/** + * \brief Return corresponding dB value to an integer playback volume for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) +{ + return snd_amixer_elem_ask_vol_dB(elem, SM_PLAY, value, dBvalue); +} + +/** + * \brief Return corresponding integer playback volume for given dB value for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +{ + return snd_amixer_elem_ask_dB_vol(elem, SM_PLAY, dBvalue, dir, value); +} + +/** + * \brief Return value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + return snd_amixer_elem_get_volume(elem, SM_PLAY, channel, value); +} + +/** + * \brief Return value of playback volume in dB control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value (dB * 100) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + return snd_amixer_elem_get_dB(elem, SM_PLAY, channel, value); +} + +/** + * \brief Return value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) +{ + return snd_amixer_elem_get_switch(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) +{ + return snd_amixer_elem_set_volume(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value in dB of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +{ + return snd_amixer_elem_set_dB(elem, SM_PLAY, channel, value, dir); +} + +/** + * \brief Set value of playback volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) +{ + return snd_amixer_elem_set_volume_all(elem, SM_PLAY, value); +} + +/** + * \brief Set value in dB of playback volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir) +{ + return snd_amixer_elem_set_dB_all(elem, SM_PLAY, value, dir); +} + +/** + * \brief Set value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) +{ + return snd_amixer_elem_set_switch(elem, SM_PLAY, channel, value); +} + +/** + * \brief Set value of playback switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value) +{ + return snd_amixer_elem_set_switch_all(elem, SM_PLAY, value); +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_channels(elem, SM_CAPT) == 1; +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) +{ + return snd_amixer_elem_has_channel(elem, SM_CAPT, channel); +} + +/** + * \brief Get range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + return snd_amixer_elem_get_volume_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Get range in dB for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum (dB * 100) + * \param max Pointer to returned maximum (dB * 100) + */ +int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, + long *min, long *max) +{ + return snd_amixer_elem_get_dB_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Set range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, + long min, long max) +{ + return snd_amixer_elem_set_volume_range(elem, SM_CAPT, min, max); +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_volume(elem, SM_CAPT); +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_volume_joined(elem, SM_CAPT); +} + +/** + * \brief Return info about capture switch control existence of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch(elem, SM_CAPT); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch_joined(elem, SM_CAPT); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group) + */ +int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_has_switch_exclusive(elem, SM_CAPT); +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive) + */ +int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_group(elem, SM_CAPT); +} + +/** + * \brief Return corresponding dB value to an integer capture volume for a mixer simple element + * \param elem Mixer simple element handle + * \param value value to be converted to dB range + * \param dBvalue pointer to returned dB value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) +{ + return snd_amixer_elem_ask_vol_dB(elem, SM_CAPT, value, dBvalue); +} + +/** + * \brief Return corresponding integer capture volume for given dB value for a mixer simple element + * \param elem Mixer simple element handle + * \param dBvalue dB value to be converted to integer range + * \param value pointer to returned integer value + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) +{ + return snd_amixer_elem_ask_dB_vol(elem, SM_CAPT, dBvalue, dir, value); +} + +/** + * \brief Return value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + return snd_amixer_elem_get_volume(elem, SM_CAPT, channel, value); +} + +/** + * \brief Return value of capture volume in dB control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value (dB * 100) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) +{ + return snd_amixer_elem_get_dB(elem, SM_CAPT, channel, value); +} + +/** + * \brief Return value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) +{ + return snd_amixer_elem_get_switch(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) +{ + return snd_amixer_elem_set_volume(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value in dB of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) +{ + return snd_amixer_elem_set_dB(elem, SM_CAPT, channel, value, dir); +} + +/** + * \brief Set value of capture volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value) +{ + return snd_amixer_elem_set_volume_all(elem, SM_CAPT, value); +} + +/** + * \brief Set value in dB of capture volume control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value in dB * 100 + * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir) +{ + return snd_amixer_elem_set_dB_all(elem, SM_CAPT, value, dir); +} + +/** + * \brief Set value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) +{ + return snd_amixer_elem_set_switch(elem, SM_CAPT, channel, value); +} + +/** + * \brief Set value of capture switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) +{ + return snd_amixer_elem_set_switch_all(elem, SM_CAPT, value); +} + +/** + * \brief Return true if mixer simple element is an enumerated control + * \param elem Mixer simple element handle + * \return 0 normal volume/switch control, 1 enumerated control + */ +int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_is_enum(elem, SM_COMM) || + snd_amixer_elem_is_enum(elem, SM_PLAY) || + snd_amixer_elem_is_enum(elem, SM_CAPT); +} + +/** + * \brief Return true if mixer simple enumerated element belongs to the playback direction + * \param elem Mixer simple element handle + * \return 0 no playback direction, 1 playback direction + */ +int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_is_enum(elem, SM_PLAY); +} + +/** + * \brief Return true if mixer simple enumerated element belongs to the capture direction + * \param elem Mixer simple element handle + * \return 0 no capture direction, 1 capture direction + */ +int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_is_enum(elem, SM_CAPT); +} + +/** + * \brief Return the number of enumerated items of the given mixer simple element + * \param elem Mixer simple element handle + * \return the number of enumerated items, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) +{ + return snd_amixer_elem_get_enum_items(elem); +} + +/** + * \brief get the enumerated item string for the given mixer simple element + * \param elem Mixer simple element handle + * \param item the index of the enumerated item to query + * \param maxlen the maximal length to be stored + * \param buf the buffer to store the name string + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, + unsigned int item, + size_t maxlen, char *buf) +{ + return snd_amixer_elem_get_enum_item_name(elem, item, maxlen, buf); +} + +/** + * \brief get the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param itemp the pointer to store the index of the enumerated item + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + return snd_amixer_elem_get_enum_item(elem, channel, itemp); +} + +/** + * \brief set the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param item the enumerated item index + * \return 0 if successful, otherwise a negative error code + */ +int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + return snd_amixer_elem_set_enum_item(elem, channel, item); +} + +/** + * \brief get size of #snd_mixer_selem_id_t + * \return size in bytes + */ +size_t snd_mixer_selem_id_sizeof(void) +{ + return snd_amixer_elem_id_sizeof(); +} + +/** + * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr) +{ + return snd_amixer_elem_id_malloc(ptr); +} + +/** + * \brief frees a previously allocated #snd_mixer_selem_id_t + * \param obj pointer to object to free + */ +void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj) +{ + return snd_amixer_elem_id_free(obj); +} + +/** + * \brief copy one #snd_mixer_selem_id_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src) +{ + return snd_amixer_elem_id_copy(dst, src); +} + +/** + * \brief Get name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return name part + */ +const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) +{ + return snd_amixer_elem_id_get_name(obj); +} + +/** + * \brief Get index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return index part + */ +unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) +{ + return snd_amixer_elem_id_get_index(obj); +} + +/** + * \brief Set name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val name part + */ +void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) +{ + return snd_amixer_elem_id_set_name(obj, val); +} + +/** + * \brief Set index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val index part + */ +void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val) +{ + return snd_amixer_elem_id_set_index(obj, val); +} -- cgit v1.2.1