From 273d115de05574251bdd661747ecb68449a5cf1d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 15 Jul 2000 10:20:32 +0000 Subject: [PATCH] Removed old mixer API functions. Added simple control layer (experimental). --- include/control.h | 27 +- include/mixer.h | 140 ++++++---- include/pcm.h | 5 + src/control/control.c | 68 ++--- src/control/defaults.c | 5 - src/mixer/Makefile.am | 2 +- src/mixer/elements.c | 331 ----------------------- src/mixer/mixer.c | 568 ++++++++++------------------------------ src/mixer/mixer_local.h | 54 ++++ src/mixer/simple.c | 440 +++++++++++++++++++++++++++++++ src/pcm/pcm_common.c | 14 +- 11 files changed, 789 insertions(+), 865 deletions(-) delete mode 100644 src/mixer/elements.c create mode 100644 src/mixer/mixer_local.h create mode 100644 src/mixer/simple.c diff --git a/include/control.h b/include/control.h index d0864fdd..b1718211 100644 --- a/include/control.h +++ b/include/control.h @@ -5,21 +5,22 @@ * * ****************************************************************************/ +typedef struct snd_ctl snd_ctl_t; + typedef struct snd_ctl_callbacks { - void *private_data; /* should be used by an application */ - void (*rebuild) (void *private_data); - void (*xswitch) (void *private_data, int cmd, - int iface, int device, int channel, - snd_switch_list_item_t *item); - void *reserved[29]; /* reserved for the future use - must be NULL!!! */ + void *private_data; /* may be used by an application */ + void (*rebuild) (snd_ctl_t *handle, void *private_data); + void (*value) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id); + void (*change) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id); + void (*add) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id); + void (*remove) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id); + void *reserved[58]; /* reserved for the future use - must be NULL!!! */ } snd_ctl_callbacks_t; #ifdef __cplusplus extern "C" { #endif -typedef struct snd_ctl snd_ctl_t; - int snd_card_load(int card); int snd_cards(void); unsigned int snd_cards_mask(void); @@ -29,7 +30,6 @@ int snd_card_get_longname(int card, char **name); int snd_defaults_card(void); int snd_defaults_mixer_card(void); -int snd_defaults_mixer_device(void); int snd_defaults_pcm_card(void); int snd_defaults_pcm_device(void); int snd_defaults_rawmidi_card(void); @@ -39,14 +39,15 @@ int snd_ctl_open(snd_ctl_t **handle, int card); int snd_ctl_close(snd_ctl_t *handle); int snd_ctl_file_descriptor(snd_ctl_t *handle); int snd_ctl_hw_info(snd_ctl_t *handle, struct snd_ctl_hw_info *info); -int snd_ctl_switch_list(snd_ctl_t *handle, snd_switch_list_t * list); -int snd_ctl_switch_read(snd_ctl_t *handle, snd_switch_t * sw); -int snd_ctl_switch_write(snd_ctl_t *handle, snd_switch_t * sw); +int snd_ctl_clist(snd_ctl_t *handle, snd_control_list_t * list); +int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t * sw); +int snd_ctl_cread(snd_ctl_t *handle, snd_control_t * control); +int snd_ctl_cwrite(snd_ctl_t *handle, snd_control_t * control); int snd_ctl_hwdep_info(snd_ctl_t *handle, snd_hwdep_info_t * info); int snd_ctl_pcm_info(snd_ctl_t *handle, snd_pcm_info_t * info); int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *handle, int subdev); -int snd_ctl_mixer_info(snd_ctl_t *handle, snd_mixer_info_t * info); int snd_ctl_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info); + int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks); #ifdef __cplusplus diff --git a/include/mixer.h b/include/mixer.h index dcb7c4d2..e224ecdb 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -5,58 +5,108 @@ * * ****************************************************************************/ -typedef struct snd_mixer_callbacks { - void *private_data; /* should be used with an application */ - void (*rebuild) (void *private_data); - void (*element) (void *private_data, int cmd, snd_mixer_eid_t *eid); - void (*group) (void *private_data, int cmd, snd_mixer_gid_t *gid); - void *reserved[28]; /* reserved for the future use - must be NULL!!! */ -} snd_mixer_callbacks_t; - -typedef struct { - char *name; - int weight; -} snd_mixer_weight_entry_t; +typedef struct snd_mixer snd_mixer_t; #ifdef __cplusplus extern "C" { #endif -typedef struct snd_mixer snd_mixer_t; - -int snd_mixer_open(snd_mixer_t **handle, int card, int device); +int snd_mixer_open(snd_mixer_t **handle, int card); int snd_mixer_close(snd_mixer_t *handle); int snd_mixer_file_descriptor(snd_mixer_t *handle); -int snd_mixer_info(snd_mixer_t *handle, snd_mixer_info_t * info); -int snd_mixer_elements(snd_mixer_t *handle, snd_mixer_elements_t * elements); -int snd_mixer_routes(snd_mixer_t *handle, snd_mixer_routes_t * routes); -int snd_mixer_groups(snd_mixer_t *handle, snd_mixer_groups_t * groups); -int snd_mixer_group_read(snd_mixer_t *handle, snd_mixer_group_t * group); -int snd_mixer_group_write(snd_mixer_t *handle, snd_mixer_group_t * group); -int snd_mixer_element_info(snd_mixer_t *handle, snd_mixer_element_info_t * info); -int snd_mixer_element_read(snd_mixer_t *handle, snd_mixer_element_t * element); -int snd_mixer_element_write(snd_mixer_t *handle, snd_mixer_element_t * element); -int snd_mixer_get_filter(snd_mixer_t *handle, snd_mixer_filter_t * filter); -int snd_mixer_put_filter(snd_mixer_t *handle, snd_mixer_filter_t * filter); -int snd_mixer_read(snd_mixer_t *handle, snd_mixer_callbacks_t * callbacks); - -void snd_mixer_set_bit(unsigned int *bitmap, int bit, int val); -int snd_mixer_get_bit(unsigned int *bitmap, int bit); - -const char *snd_mixer_channel_name(int channel); - -int snd_mixer_element_has_info(snd_mixer_eid_t *eid); -int snd_mixer_element_info_build(snd_mixer_t *handle, snd_mixer_element_info_t * info); -int snd_mixer_element_info_free(snd_mixer_element_info_t * info); -int snd_mixer_element_has_control(snd_mixer_eid_t *eid); -int snd_mixer_element_build(snd_mixer_t *handle, snd_mixer_element_t * element); -int snd_mixer_element_free(snd_mixer_element_t * element); - -void snd_mixer_sort_eid_name_index(snd_mixer_eid_t *list, int count); -void snd_mixer_sort_eid_table(snd_mixer_eid_t *list, int count, snd_mixer_weight_entry_t *table); -void snd_mixer_sort_gid_name_index(snd_mixer_gid_t *list, int count); -void snd_mixer_sort_gid_table(snd_mixer_gid_t *list, int count, snd_mixer_weight_entry_t *table); -extern snd_mixer_weight_entry_t *snd_mixer_default_weights; + +#ifdef __cplusplus +} +#endif + +/* + * Simple (legacy) mixer API + */ + +typedef enum { + SND_MIXER_CHN_FRONT_LEFT = 0, + SND_MIXER_CHN_FRONT_RIGHT, + SND_MIXER_CHN_FRONT_CENTER, + SND_MIXER_CHN_REAR_LEFT, + SND_MIXER_CHN_REAR_RIGHT, + SND_MIXER_CHN_WOOFER, + SND_MIXER_CHN_LAST = 31, + SND_MIXER_CHN_MONO = SND_MIXER_CHN_FRONT_LEFT +} snd_mixer_channel_id_t; + +#define SND_MIXER_CHN_MASK_MONO (1<fd, SND_CTL_IOCTL_SWITCH_LIST, list) < 0) + if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_LIST, list) < 0) return -errno; return 0; } -int snd_ctl_switch_read(snd_ctl_t *handle, snd_switch_t *sw) +int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t *info) { - assert(handle && sw && sw->name[0]); - if (ioctl(handle->fd, SND_CTL_IOCTL_SWITCH_READ, sw) < 0) + assert(handle && info && info->id.name[0]); + if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_INFO, info) < 0) return -errno; return 0; } -int snd_ctl_switch_write(snd_ctl_t *handle, snd_switch_t *sw) +int snd_ctl_cread(snd_ctl_t *handle, snd_control_t *control) { - assert(handle && sw && sw->name[0]); - if (ioctl(handle->fd, SND_CTL_IOCTL_SWITCH_WRITE, sw) < 0) + assert(handle && control && control->id.name[0]); + if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_READ, control) < 0) + return -errno; + return 0; +} + +int snd_ctl_cwrite(snd_ctl_t *handle, snd_control_t *control) +{ + assert(handle && control && control->id.name[0]); + if (ioctl(handle->fd, SND_CTL_IOCTL_CONTROL_WRITE, control) < 0) return -errno; return 0; } @@ -143,14 +151,6 @@ int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *handle, int subdev) return 0; } -int snd_ctl_mixer_info(snd_ctl_t *handle, snd_mixer_info_t * info) -{ - assert(handle && info); - if (ioctl(handle->fd, SND_CTL_IOCTL_MIXER_INFO, info) < 0) - return -errno; - return 0; -} - int snd_ctl_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info) { assert(handle && info); @@ -162,7 +162,8 @@ int snd_ctl_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info) int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks) { int result, count; - snd_ctl_read_t r; + snd_ctl_event_t r; + assert(handle); count = 0; while ((result = read(handle->fd, &r, sizeof(r))) > 0) { @@ -170,21 +171,26 @@ int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks) return -EIO; if (!callbacks) continue; - switch (r.cmd) { - case SND_CTL_READ_REBUILD: + switch (r.type) { + case SND_CTL_EVENT_REBUILD: if (callbacks->rebuild) - callbacks->rebuild(callbacks->private_data); + callbacks->rebuild(handle, callbacks->private_data); + break; + case SND_CTL_EVENT_VALUE: + if (callbacks->value) + callbacks->value(handle, callbacks->private_data, &r.data.id); + break; + case SND_CTL_EVENT_CHANGE: + if (callbacks->change) + callbacks->change(handle, callbacks->private_data, &r.data.id); + break; + case SND_CTL_EVENT_ADD: + if (callbacks->add) + callbacks->add(handle, callbacks->private_data, &r.data.id); break; - case SND_CTL_READ_SWITCH_VALUE: - case SND_CTL_READ_SWITCH_CHANGE: - case SND_CTL_READ_SWITCH_ADD: - case SND_CTL_READ_SWITCH_REMOVE: - if (callbacks->xswitch) - callbacks->xswitch(callbacks->private_data, - r.cmd, r.data.sw.iface, - r.data.sw.device, - r.data.sw.stream, - &r.data.sw.switem); + case SND_CTL_EVENT_REMOVE: + if (callbacks->remove) + callbacks->remove(handle, callbacks->private_data, &r.data.id); break; } count++; diff --git a/src/control/defaults.c b/src/control/defaults.c index f2835b56..5e6a27eb 100644 --- a/src/control/defaults.c +++ b/src/control/defaults.c @@ -72,11 +72,6 @@ int snd_defaults_mixer_card(void) return snd_defaults_card(); } -int snd_defaults_mixer_device(void) -{ - return defaults_device("ALSA_MIXER_DEVICE"); -} - int snd_defaults_pcm_card(void) { int result; diff --git a/src/mixer/Makefile.am b/src/mixer/Makefile.am index cc126ba4..037fcc1e 100644 --- a/src/mixer/Makefile.am +++ b/src/mixer/Makefile.am @@ -1,6 +1,6 @@ EXTRA_LTLIBRARIES=libmixer.la -libmixer_la_SOURCES = mixer.c elements.c +libmixer_la_SOURCES = mixer.c simple.c all: libmixer.la diff --git a/src/mixer/elements.c b/src/mixer/elements.c deleted file mode 100644 index 7644e9a9..00000000 --- a/src/mixer/elements.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Mixer Interface - elements - * Copyright (c) 1999 by Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include "asoundlib.h" - -static inline void safe_free(void **ptr) -{ - if (*ptr) - free(*ptr); - *ptr = NULL; -} - -int snd_mixer_element_has_info(snd_mixer_eid_t *eid) -{ - if (!eid) - return -EINVAL; - switch (eid->type) { - case SND_MIXER_ETYPE_INPUT: - case SND_MIXER_ETYPE_OUTPUT: - case SND_MIXER_ETYPE_CAPTURE1: - case SND_MIXER_ETYPE_CAPTURE2: - case SND_MIXER_ETYPE_CAPTURE3: - case SND_MIXER_ETYPE_PLAYBACK1: - case SND_MIXER_ETYPE_PLAYBACK2: - case SND_MIXER_ETYPE_PLAYBACK3: - case SND_MIXER_ETYPE_ADC: - case SND_MIXER_ETYPE_DAC: - case SND_MIXER_ETYPE_SWITCH3: - case SND_MIXER_ETYPE_VOLUME1: - case SND_MIXER_ETYPE_VOLUME2: - case SND_MIXER_ETYPE_ACCU1: - case SND_MIXER_ETYPE_ACCU2: - case SND_MIXER_ETYPE_ACCU3: - case SND_MIXER_ETYPE_MUX1: - case SND_MIXER_ETYPE_MUX2: - case SND_MIXER_ETYPE_TONE_CONTROL1: - case SND_MIXER_ETYPE_PAN_CONTROL1: - case SND_MIXER_ETYPE_3D_EFFECT1: - case SND_MIXER_ETYPE_PRE_EFFECT1: - return 1; - } - return 0; -} - -int snd_mixer_element_info_build(snd_mixer_t *handle, snd_mixer_element_info_t *element) -{ - int err; - - if (!handle || !element) - return -EINVAL; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - switch (element->eid.type) { - case SND_MIXER_ETYPE_INPUT: - case SND_MIXER_ETYPE_OUTPUT: - element->data.io.channels_size = element->data.io.channels_over; - element->data.io.channels = element->data.io.channels_over = 0; - element->data.io.pchannels = (snd_mixer_channel_t *)malloc(element->data.io.channels_size * sizeof(snd_mixer_channel_t)); - if (!element->data.io.pchannels) - return -ENOMEM; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_CAPTURE1: - case SND_MIXER_ETYPE_PLAYBACK1: - element->data.pcm1.devices_size = element->data.pcm1.devices_over; - element->data.pcm1.devices = element->data.pcm1.devices_over = 0; - element->data.pcm1.pdevices = (int *)malloc(element->data.pcm1.devices_size * sizeof(int)); - if (!element->data.pcm1.pdevices) - return -ENOMEM; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_VOLUME1: - element->data.volume1.range_size = element->data.volume1.range_over; - element->data.volume1.range = element->data.volume1.range_over = 0; - element->data.volume1.prange = (struct snd_mixer_element_volume1_range *)malloc(element->data.volume1.range_size * sizeof(struct snd_mixer_element_volume1_range)); - if (!element->data.volume1.prange) - return -ENOMEM; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_VOLUME2: - element->data.volume2.schannels_size = element->data.volume2.schannels_over; - element->data.volume2.schannels = element->data.volume2.schannels_over = 0; - element->data.volume2.pschannels = (snd_mixer_channel_t *)malloc(element->data.volume2.schannels_size * sizeof(snd_mixer_channel_t)); - if (!element->data.volume2.pschannels) - return -ENOMEM; - element->data.volume2.range_size = element->data.volume2.range_over; - element->data.volume2.range = element->data.volume2.range_over = 0; - element->data.volume2.prange = (struct snd_mixer_element_volume2_range *)malloc(element->data.volume2.range_size * sizeof(struct snd_mixer_element_volume2_range)); - if (!element->data.volume1.prange) { - safe_free((void **)&element->data.volume2.pschannels); - return -ENOMEM; - } - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_ACCU3: - element->data.accu3.range_size = element->data.accu3.range_over; - element->data.accu3.range = element->data.accu3.range_over = 0; - element->data.accu3.prange = (struct snd_mixer_element_accu3_range *)malloc(element->data.accu3.range_size * sizeof(struct snd_mixer_element_accu3_range)); - if (!element->data.accu3.prange) - return -ENOMEM; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_PRE_EFFECT1: - element->data.peffect1.items_size = element->data.peffect1.items_over; - element->data.peffect1.items = element->data.peffect1.items_over = 0; - element->data.peffect1.pitems = (struct snd_mixer_element_pre_effect1_info_item *)malloc(element->data.peffect1.items_size * sizeof(struct snd_mixer_element_pre_effect1_info_item)); - if (!element->data.peffect1.pitems) - return -ENOMEM; - element->data.peffect1.parameters_size = element->data.peffect1.parameters_over; - element->data.peffect1.parameters = element->data.peffect1.parameters_over = 0; - element->data.peffect1.pparameters = (struct snd_mixer_element_pre_effect1_info_parameter *)malloc(element->data.peffect1.parameters_size * sizeof(struct snd_mixer_element_pre_effect1_info_parameter)); - if (!element->data.peffect1.pparameters) { - safe_free((void **)&element->data.peffect1.pitems); - return -ENOMEM; - } - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_PAN_CONTROL1: - element->data.pc1.range_size = element->data.pc1.range_over; - element->data.pc1.range = element->data.pc1.range_over = 0; - element->data.pc1.prange = (struct snd_mixer_element_pan_control1_range *)malloc(element->data.pc1.range_size * sizeof(struct snd_mixer_element_pan_control1_range)); - if (!element->data.pc1.prange) - return -ENOMEM; - if ((err = snd_mixer_element_info(handle, element)) < 0) - return err; - break; - } - return 0; -} - -int snd_mixer_element_info_free(snd_mixer_element_info_t *element) -{ - if (!element) - return -EINVAL; - switch (element->eid.type) { - case SND_MIXER_ETYPE_INPUT: - case SND_MIXER_ETYPE_OUTPUT: - safe_free((void **)&element->data.io.pchannels); - break; - case SND_MIXER_ETYPE_CAPTURE1: - case SND_MIXER_ETYPE_PLAYBACK1: - safe_free((void **)&element->data.pcm1.pdevices); - break; - case SND_MIXER_ETYPE_VOLUME1: - safe_free((void **)&element->data.volume1.prange); - break; - case SND_MIXER_ETYPE_VOLUME2: - safe_free((void **)&element->data.volume2.pschannels); - safe_free((void **)&element->data.volume1.prange); - break; - case SND_MIXER_ETYPE_ACCU3: - safe_free((void **)&element->data.accu3.prange); - break; - case SND_MIXER_ETYPE_PRE_EFFECT1: - safe_free((void **)&element->data.peffect1.pitems); - safe_free((void **)&element->data.peffect1.pparameters); - break; - case SND_MIXER_ETYPE_PAN_CONTROL1: - safe_free((void **)&element->data.pc1.prange); - break; - } - return 0; -} - -int snd_mixer_element_has_control(snd_mixer_eid_t *eid) -{ - if (!eid) - return -EINVAL; - switch (eid->type) { - case SND_MIXER_ETYPE_SWITCH1: - case SND_MIXER_ETYPE_SWITCH2: - case SND_MIXER_ETYPE_SWITCH3: - case SND_MIXER_ETYPE_VOLUME1: - case SND_MIXER_ETYPE_VOLUME2: - case SND_MIXER_ETYPE_ACCU3: - case SND_MIXER_ETYPE_MUX1: - case SND_MIXER_ETYPE_MUX2: - case SND_MIXER_ETYPE_TONE_CONTROL1: - case SND_MIXER_ETYPE_PAN_CONTROL1: - case SND_MIXER_ETYPE_3D_EFFECT1: - case SND_MIXER_ETYPE_PRE_EFFECT1: - return 1; - } - return 0; -} - -int snd_mixer_element_build(snd_mixer_t *handle, snd_mixer_element_t *element) -{ - int err; - - if (!handle || !element) - return -EINVAL; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - switch (element->eid.type) { - case SND_MIXER_ETYPE_SWITCH1: - element->data.switch1.sw_size = element->data.switch1.sw_over; - element->data.switch1.sw = element->data.switch1.sw_over = 0; - element->data.switch1.psw = (unsigned int *)malloc(((element->data.switch1.sw_size + 31) / 32) * sizeof(unsigned int)); - if (!element->data.switch1.psw) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_SWITCH3: - element->data.switch3.rsw_size = element->data.switch3.rsw_over; - element->data.switch3.rsw = element->data.switch3.rsw_over = 0; - element->data.switch3.prsw = (unsigned int *)malloc(((element->data.switch3.rsw_size + 31) / 32) * sizeof(unsigned int)); - if (!element->data.switch3.prsw) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_VOLUME1: - element->data.volume1.channels_size = element->data.volume1.channels_over; - element->data.volume1.channels = element->data.volume1.channels_over = 0; - element->data.volume1.pchannels = (int *)malloc(element->data.volume1.channels_size * sizeof(int)); - if (!element->data.volume1.pchannels) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_VOLUME2: - element->data.volume2.achannels_size = element->data.volume2.achannels_over; - element->data.volume2.achannels = element->data.volume2.achannels_over = 0; - element->data.volume2.pachannels = (int *)malloc(element->data.volume2.achannels_size * sizeof(int)); - if (!element->data.volume2.pachannels) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_ACCU3: - element->data.accu3.channels_size = element->data.accu3.channels_over; - element->data.accu3.channels = element->data.accu3.channels_over = 0; - element->data.accu3.pchannels = (int *)malloc(element->data.accu3.channels_size * sizeof(int)); - if (!element->data.accu3.pchannels) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_MUX1: - element->data.mux1.sel_size = element->data.mux1.sel_over; - element->data.mux1.sel = element->data.mux1.sel_over = 0; - element->data.mux1.psel = (snd_mixer_eid_t *)malloc(element->data.mux1.sel_size * sizeof(snd_mixer_eid_t)); - if (!element->data.mux1.psel) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - case SND_MIXER_ETYPE_PRE_EFFECT1: - if (element->data.peffect1.item < 0) { - element->data.peffect1.parameters_size = element->data.peffect1.parameters_over; - element->data.peffect1.parameters = element->data.peffect1.parameters_over = 0; - element->data.peffect1.pparameters = (int *)malloc(element->data.peffect1.parameters_size * sizeof(int)); - if (!element->data.peffect1.pparameters) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - } - break; - case SND_MIXER_ETYPE_PAN_CONTROL1: - element->data.pc1.pan_size = element->data.pc1.pan_over; - element->data.pc1.pan = element->data.pc1.pan_over = 0; - element->data.pc1.ppan = (int *)malloc(element->data.pc1.pan_size * sizeof(int)); - if (!element->data.pc1.ppan) - return -ENOMEM; - if ((err = snd_mixer_element_read(handle, element)) < 0) - return err; - break; - } - return 0; -} - -int snd_mixer_element_free(snd_mixer_element_t *element) -{ - if (!element) - return -EINVAL; - switch (element->eid.type) { - case SND_MIXER_ETYPE_SWITCH1: - safe_free((void **)&element->data.switch1.psw); - break; - case SND_MIXER_ETYPE_SWITCH3: - safe_free((void **)&element->data.switch3.prsw); - break; - case SND_MIXER_ETYPE_VOLUME1: - safe_free((void **)&element->data.volume1.pchannels); - break; - case SND_MIXER_ETYPE_VOLUME2: - safe_free((void **)&element->data.volume2.pachannels); - break; - case SND_MIXER_ETYPE_ACCU3: - safe_free((void **)&element->data.accu3.pchannels); - break; - case SND_MIXER_ETYPE_MUX1: - safe_free((void **)&element->data.mux1.psel); - break; - case SND_MIXER_ETYPE_PRE_EFFECT1: - if (element->data.peffect1.item < 0) - safe_free((void **)&element->data.peffect1.pparameters); - break; - case SND_MIXER_ETYPE_PAN_CONTROL1: - safe_free((void **)&element->data.pc1.ppan); - } - return 0; -} diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c index 4a636a3d..83b048e8 100644 --- a/src/mixer/mixer.c +++ b/src/mixer/mixer.c @@ -1,6 +1,6 @@ /* * Mixer Interface - main file - * Copyright (c) 1998 by Jaroslav Kysela + * Copyright (c) 1998/1999/2000 by Jaroslav Kysela * * * This library is free software; you can redistribute it and/or modify @@ -27,265 +27,50 @@ #include #include #include "asoundlib.h" +#include "mixer_local.h" -#define __USE_GNU -#include - -#define SND_FILE_MIXER "/dev/snd/mixerC%iD%i" -#define SND_MIXER_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0) - -struct snd_mixer { - int card; - int device; - int fd; -} ; - -int snd_mixer_open(snd_mixer_t **handle, int card, int device) +int snd_mixer_open(snd_mixer_t **r_handle, int card) { - int fd, ver; - char filename[32]; - snd_mixer_t *mixer; - - *handle = NULL; + snd_mixer_t *handle; + snd_ctl_t *ctl_handle; + int err; - if (card < 0 || card >= SND_CARDS) + if (r_handle == NULL) return -EINVAL; - sprintf(filename, SND_FILE_MIXER, card, device); - if ((fd = open(filename, O_RDWR)) < 0) { - snd_card_load(card); - if ((fd = open(filename, O_RDWR)) < 0) - return -errno; - } - if (ioctl(fd, SND_MIXER_IOCTL_PVERSION, &ver) < 0) { - close(fd); - return -errno; - } - if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_MIXER_VERSION_MAX)) { - close(fd); - return -SND_ERROR_INCOMPATIBLE_VERSION; - } - mixer = (snd_mixer_t *) calloc(1, sizeof(snd_mixer_t)); - if (mixer == NULL) { - close(fd); + *r_handle = NULL; + if ((err = snd_ctl_open(&ctl_handle, card)) < 0) + return err; + handle = (snd_mixer_t *) calloc(1, sizeof(snd_mixer_t)); + if (handle == NULL) { + snd_ctl_close(ctl_handle); return -ENOMEM; } - mixer->card = card; - mixer->device = device; - mixer->fd = fd; - *handle = mixer; + handle->ctl_handle = ctl_handle; + *r_handle = handle; return 0; } int snd_mixer_close(snd_mixer_t *handle) { - snd_mixer_t *mixer; - int res; + int err = 0; - mixer = handle; - if (!mixer) + if (handle == NULL) return -EINVAL; - res = close(mixer->fd) < 0 ? -errno : 0; - free(mixer); - return res; + if (handle->simple_valid) + snd_mixer_simple_destroy(handle); + if (handle->ctl_handle) + err = snd_ctl_close(handle->ctl_handle); + return err; } int snd_mixer_file_descriptor(snd_mixer_t *handle) { - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer) - return -EINVAL; - return mixer->fd; -} - -int snd_mixer_info(snd_mixer_t *handle, snd_mixer_info_t * info) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !info) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_INFO, info) < 0) - return -errno; - return 0; -} - -int snd_mixer_elements(snd_mixer_t *handle, snd_mixer_elements_t * elements) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !elements) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_ELEMENTS, elements) < 0) - return -errno; - return 0; -} - -int snd_mixer_routes(snd_mixer_t *handle, snd_mixer_routes_t * routes) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !routes) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_ROUTES, routes) < 0) - return -errno; - return 0; -} - -int snd_mixer_groups(snd_mixer_t *handle, snd_mixer_groups_t * groups) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !groups) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_GROUPS, groups) < 0) - return -errno; - return 0; -} - -int snd_mixer_group_read(snd_mixer_t *handle, snd_mixer_group_t * group) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !group) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_GROUP_READ, group) < 0) - return -errno; - return 0; -} - -int snd_mixer_group_write(snd_mixer_t *handle, snd_mixer_group_t * group) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !group) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_GROUP_WRITE, group) < 0) - return -errno; - return 0; -} - -int snd_mixer_element_info(snd_mixer_t *handle, snd_mixer_element_info_t * info) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !info) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_ELEMENT_INFO, info) < 0) - return -errno; - return 0; -} - -int snd_mixer_element_read(snd_mixer_t *handle, snd_mixer_element_t * element) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !element) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_ELEMENT_READ, element) < 0) - return -errno; - return 0; -} - -int snd_mixer_element_write(snd_mixer_t *handle, snd_mixer_element_t * element) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !element) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_ELEMENT_WRITE, element) < 0) - return -errno; - return 0; -} - -int snd_mixer_get_filter(snd_mixer_t *handle, snd_mixer_filter_t * filter) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !filter) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_GET_FILTER, filter) < 0) - return -errno; - return 0; -} - -int snd_mixer_put_filter(snd_mixer_t *handle, snd_mixer_filter_t * filter) -{ - snd_mixer_t *mixer; - - mixer = handle; - if (!mixer || !filter) - return -EINVAL; - if (ioctl(mixer->fd, SND_MIXER_IOCTL_PUT_FILTER, filter) < 0) - return -errno; - return 0; -} - -int snd_mixer_read(snd_mixer_t *handle, snd_mixer_callbacks_t * callbacks) -{ - snd_mixer_t *mixer; - int result, count; - snd_mixer_read_t r; - - mixer = handle; - if (!mixer) - return -EINVAL; - count = 0; - while ((result = read(mixer->fd, &r, sizeof(r))) > 0) { - if (result != sizeof(r)) - return -EIO; - if (!callbacks) - continue; - switch (r.cmd) { - case SND_MIXER_READ_REBUILD: - if (callbacks->rebuild) - callbacks->rebuild(callbacks->private_data); - break; - case SND_MIXER_READ_ELEMENT_VALUE: - case SND_MIXER_READ_ELEMENT_CHANGE: - case SND_MIXER_READ_ELEMENT_ROUTE: - case SND_MIXER_READ_ELEMENT_ADD: - case SND_MIXER_READ_ELEMENT_REMOVE: - if (callbacks->element) - callbacks->element(callbacks->private_data, r.cmd, &r.data.eid); - break; - case SND_MIXER_READ_GROUP_CHANGE: - case SND_MIXER_READ_GROUP_ADD: - case SND_MIXER_READ_GROUP_REMOVE: - if (callbacks->group) - callbacks->group(callbacks->private_data, r.cmd, &r.data.gid); - break; - } - count++; - } - return result >= 0 ? count : -errno; + if (handle == NULL || handle->ctl_handle == NULL) + return -EIO; + return snd_ctl_file_descriptor(handle->ctl_handle); } -void snd_mixer_set_bit(unsigned int *bitmap, int bit, int val) -{ - if (val) { - bitmap[bit >> 5] |= 1 << (bit & 31); - } else { - bitmap[bit >> 5] &= ~(1 << (bit & 31)); - } -} - -int snd_mixer_get_bit(unsigned int *bitmap, int bit) -{ - return (bitmap[bit >> 5] & (1 << (bit & 31))) ? 1 : 0; -} - -const char *snd_mixer_channel_name(int channel) +const char *snd_mixer_simple_channel_name(int channel) { static char *array[6] = { "Front-Left", @@ -301,228 +86,147 @@ const char *snd_mixer_channel_name(int channel) return array[channel]; } -typedef int (*snd_mixer_compare_gid_func_t)(const snd_mixer_gid_t *a, const snd_mixer_gid_t *b, void* private_data); - -void snd_mixer_sort_gid_ptr(snd_mixer_gid_t **list, int count, - void* private_data, - snd_mixer_compare_gid_func_t compare) +int snd_mixer_simple_control_list(snd_mixer_t *handle, snd_mixer_simple_control_list_t *list) { - int _compare(const void* a, const void* b) { - snd_mixer_gid_t * const *_a = a; - snd_mixer_gid_t * const *_b = b; - return compare(*_a, *_b, private_data); - } - qsort(list, count, sizeof(snd_mixer_gid_t *), _compare); -} + mixer_simple_t *s; + snd_mixer_sid_t *p; + int err; + unsigned int tmp; -void snd_mixer_sort_gid(snd_mixer_gid_t *list, int count, - void* private_data, - snd_mixer_compare_gid_func_t compare) -{ - snd_mixer_gid_t *list1 = malloc(sizeof(snd_mixer_gid_t) * count); - snd_mixer_gid_t **ptrs = malloc(sizeof(snd_mixer_gid_t *) * count); - int k; - memcpy(list1, list, count * sizeof(snd_mixer_gid_t)); - for (k = 0; k < count; ++k) - ptrs[k] = list1 + k; - snd_mixer_sort_gid_ptr(ptrs, count, private_data, compare); - for (k = 0; k < count; ++k) - memcpy(list + k, ptrs[k], sizeof(snd_mixer_gid_t)); - free(list1); - free(ptrs); + if (handle == NULL || list == NULL) + return -EINVAL; + if (!handle->simple_valid) + if ((err = snd_mixer_simple_build(handle)) < 0) + return err; + list->controls_count = 0; + tmp = list->controls_offset; + for (s = handle->simple_first; s != NULL && tmp > 0; s = s->next); + tmp = list->controls_request; + p = list->pids; + printf("request = %i\n", tmp); + if (tmp > 0 && p == NULL) + return -EINVAL; + for (; s != NULL && tmp > 0; s = s->next, tmp--, p++, list->controls_count++) + memcpy(p, &s->id, sizeof(*p)); + list->controls = handle->simple_count; + return 0; } -/* Compare using name and index */ -int snd_mixer_compare_gid_name_index(const snd_mixer_gid_t *a, - const snd_mixer_gid_t *b, - void *ignored UNUSED) +static mixer_simple_t *look_for_simple(snd_mixer_t *handle, snd_mixer_sid_t *sid) { - int r = strcmp(a->name, b->name); - if (r != 0) - return r; - return a->index - b->index; + mixer_simple_t *s; + + for (s = handle->simple_first; s != NULL; s = s->next) + if (!strcmp(s->id.name, sid->name) && s->id.index == sid->index) + return s; + return NULL; } -/* Compare using a table mapping name to weight */ -int snd_mixer_compare_gid_table(const snd_mixer_gid_t *a, - const snd_mixer_gid_t *b, - void* private_data) +int snd_mixer_simple_control_read(snd_mixer_t *handle, snd_mixer_simple_control_t *control) { - struct hsearch_data *htab = private_data; - ENTRY ea, eb; - ENTRY *ra, *rb; - int aw = 0, bw = 0; - int r; - ea.key = (char *) a->name; - if (hsearch_r(ea, FIND, &ra, htab)) - aw = *(int *)ra->data; - eb.key = (char *) b->name; - if (hsearch_r(eb, FIND, &rb, htab)) - bw = *(int *)rb->data; - r = aw - bw; - if (r != 0) - return r; - r = strcmp(a->name, b->name); - if (r != 0) - return r; - return a->index - b->index; -} + mixer_simple_t *s; + if (handle == NULL || control == NULL) + return -EINVAL; + if (!handle->simple_valid) + snd_mixer_simple_build(handle); + s = look_for_simple(handle, &control->sid); + if (s == NULL) + return -ENOENT; + if (s->get == NULL) + return -EIO; + return s->get(handle, s, control); +} -void snd_mixer_sort_gid_name_index(snd_mixer_gid_t *list, int count) +int snd_mixer_simple_control_write(snd_mixer_t *handle, snd_mixer_simple_control_t *control) { - snd_mixer_sort_gid(list, count, NULL, snd_mixer_compare_gid_name_index); + mixer_simple_t *s; + + if (handle == NULL || control == NULL) + return -EINVAL; + if (!handle->simple_valid) + snd_mixer_simple_build(handle); + s = look_for_simple(handle, &control->sid); + if (s == NULL) + return -ENOENT; + if (s->put == NULL) + return -EIO; + return s->put(handle, s, control); } -void snd_mixer_sort_gid_table(snd_mixer_gid_t *list, int count, snd_mixer_weight_entry_t *table) +static void snd_mixer_simple_read_rebuild(snd_ctl_t *ctl_handle, void *private_data) { - struct hsearch_data htab; - int k; - htab.table = NULL; - for (k = 0; table[k].name; ++k); - hcreate_r(k*2, &htab); - for (k = 0; table[k].name; ++k) { - ENTRY e; - ENTRY *r; - e.key = table[k].name; - e.data = (char *) &table[k].weight; - hsearch_r(e, ENTER, &r, &htab); - } - snd_mixer_sort_gid(list, count, &htab, snd_mixer_compare_gid_table); - hdestroy_r(&htab); + snd_mixer_t *handle = (snd_mixer_t *)private_data; + if (handle->ctl_handle != ctl_handle) + return; + handle->callbacks->rebuild(handle, handle->callbacks->private_data); + handle->simple_changes++; } -typedef int (*snd_mixer_compare_eid_func_t)(const snd_mixer_eid_t *a, const snd_mixer_eid_t *b, void* private_data); - -void snd_mixer_sort_eid_ptr(snd_mixer_eid_t **list, int count, - void* private_data, - snd_mixer_compare_eid_func_t compare) +static void event_for_all_simple_controls(snd_mixer_t *handle, snd_ctl_event_type_t etype, snd_control_id_t *id) { - int _compare(const void* a, const void* b) { - snd_mixer_eid_t * const *_a = a; - snd_mixer_eid_t * const *_b = b; - return compare(*_a, *_b, private_data); + mixer_simple_t *s; + + for (s = handle->simple_first; s != NULL; s = s->next) { + if (s->event) + s->event(handle, etype, id); } - qsort(list, count, sizeof(snd_mixer_eid_t *), _compare); -} +} -void snd_mixer_sort_eid(snd_mixer_eid_t *list, int count, - void* private_data, - snd_mixer_compare_eid_func_t compare) +static void snd_mixer_simple_read_value(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) { - snd_mixer_eid_t *list1 = malloc(sizeof(snd_mixer_eid_t) * count); - snd_mixer_eid_t **ptrs = malloc(sizeof(snd_mixer_eid_t *) * count); - int k; - memcpy(list1, list, count * sizeof(snd_mixer_eid_t)); - for (k = 0; k < count; ++k) - ptrs[k] = list1 + k; - snd_mixer_sort_eid_ptr(ptrs, count, private_data, compare); - for (k = 0; k < count; ++k) - memcpy(list + k, ptrs[k], sizeof(snd_mixer_eid_t)); - free(list1); - free(ptrs); + snd_mixer_t *handle = (snd_mixer_t *)private_data; + if (handle->ctl_handle != ctl_handle) + return; + event_for_all_simple_controls(handle, SND_CTL_EVENT_VALUE, id); } -/* Compare using name and index */ -int snd_mixer_compare_eid_name_index(const snd_mixer_eid_t *a, - const snd_mixer_eid_t *b, - void *ignored UNUSED) +static void snd_mixer_simple_read_change(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) { - int r = strcmp(a->name, b->name); - if (r != 0) - return r; - return a->index - b->index; + snd_mixer_t *handle = (snd_mixer_t *)private_data; + if (handle->ctl_handle != ctl_handle) + return; + event_for_all_simple_controls(handle, SND_CTL_EVENT_CHANGE, id); } -/* Compare using a table mapping name to weight */ -int snd_mixer_compare_eid_table(const snd_mixer_eid_t *a, - const snd_mixer_eid_t *b, - void* private_data) +static void snd_mixer_simple_read_add(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) { - struct hsearch_data *htab = private_data; - ENTRY ea, eb; - ENTRY *ra, *rb; - int aw = 0, bw = 0; - int r; - ea.key = (char *) a->name; - if (hsearch_r(ea, FIND, &ra, htab)) - aw = *(int *)ra->data; - eb.key = (char *) b->name; - if (hsearch_r(eb, FIND, &rb, htab)) - bw = *(int *)rb->data; - r = aw - bw; - if (r != 0) - return r; - r = strcmp(a->name, b->name); - if (r != 0) - return r; - return a->index - b->index; + snd_mixer_t *handle = (snd_mixer_t *)private_data; + if (handle->ctl_handle != ctl_handle) + return; + event_for_all_simple_controls(handle, SND_CTL_EVENT_ADD, id); } - -void snd_mixer_sort_eid_name_index(snd_mixer_eid_t *list, int count) +static void snd_mixer_simple_read_remove(snd_ctl_t *ctl_handle, void *private_data, snd_control_id_t *id) { - snd_mixer_sort_eid(list, count, NULL, snd_mixer_compare_eid_name_index); + snd_mixer_t *handle = (snd_mixer_t *)private_data; + if (handle->ctl_handle != ctl_handle) + return; + event_for_all_simple_controls(handle, SND_CTL_EVENT_REMOVE, id); } -void snd_mixer_sort_eid_table(snd_mixer_eid_t *list, int count, snd_mixer_weight_entry_t *table ) +int snd_mixer_simple_read(snd_mixer_t *handle, snd_mixer_simple_callbacks_t *callbacks) { - struct hsearch_data htab; - int k; - htab.table = NULL; - for (k = 0; table[k].name; ++k); - hcreate_r(k*2, &htab); - for (k = 0; table[k].name; ++k) { - ENTRY e; - ENTRY *r; - e.key = table[k].name; - e.data = (char *) &table[k].weight; - hsearch_r(e, ENTER, &r, &htab); + snd_ctl_callbacks_t xcallbacks; + int err; + + if (handle == NULL) + return -EINVAL; + if (!handle->simple_valid) + snd_mixer_simple_build(handle); + memset(&xcallbacks, 0, sizeof(xcallbacks)); + xcallbacks.private_data = handle; + xcallbacks.rebuild = snd_mixer_simple_read_rebuild; + xcallbacks.value = snd_mixer_simple_read_value; + xcallbacks.change = snd_mixer_simple_read_change; + xcallbacks.add = snd_mixer_simple_read_add; + xcallbacks.remove = snd_mixer_simple_read_remove; + handle->callbacks = callbacks; + handle->simple_changes = 0; + if ((err = snd_ctl_read(handle->ctl_handle, &xcallbacks)) <= 0) { + handle->callbacks = NULL; + return err; } - snd_mixer_sort_eid(list, count, &htab, snd_mixer_compare_eid_table); - hdestroy_r(&htab); + handle->callbacks = NULL; + return handle->simple_changes; } - - -static snd_mixer_weight_entry_t _snd_mixer_default_weights[] = { - { SND_MIXER_OUT_MASTER, -1360 }, - { SND_MIXER_OUT_MASTER_DIGITAL, -1350 }, - { SND_MIXER_OUT_MASTER_MONO, -1340 }, - { SND_MIXER_OUT_HEADPHONE, -1330 }, - { SND_MIXER_OUT_PHONE, -1320 }, - { SND_MIXER_GRP_EFFECT_3D, -1310 }, - { SND_MIXER_GRP_BASS, -1300 }, - { SND_MIXER_GRP_TREBLE, -1290 }, - { SND_MIXER_GRP_EQUALIZER, -1280 }, - { SND_MIXER_GRP_FADER, -1270 }, - { SND_MIXER_OUT_CENTER, -1260 }, - { SND_MIXER_IN_CENTER, -1250 }, - { SND_MIXER_OUT_WOOFER, -1240 }, - { SND_MIXER_IN_WOOFER, -1230 }, - { SND_MIXER_OUT_SURROUND, -1220 }, - { SND_MIXER_IN_SURROUND, -1210 }, - { SND_MIXER_IN_SYNTHESIZER, -1200 }, - { SND_MIXER_IN_FM, -1190 }, - { SND_MIXER_GRP_EFFECT, -1180 }, - { SND_MIXER_OUT_DSP, -1170 }, - { SND_MIXER_IN_DSP, -1160 }, - { SND_MIXER_IN_PCM, -1150 }, - { SND_MIXER_IN_DAC, -1140 }, - { SND_MIXER_IN_LINE, -1130 }, - { SND_MIXER_IN_MIC, -1120 }, - { SND_MIXER_IN_CD, -1110 }, - { SND_MIXER_IN_VIDEO, -1100 }, - { SND_MIXER_IN_RADIO, -1090 }, - { SND_MIXER_IN_PHONE, -1080 }, - { SND_MIXER_GRP_MIC_GAIN, -1070 }, - { SND_MIXER_GRP_OGAIN, -1060 }, - { SND_MIXER_GRP_IGAIN, -1050 }, - { SND_MIXER_GRP_ANALOG_LOOPBACK,-1040 }, - { SND_MIXER_GRP_DIGITAL_LOOPBACK,-1030 }, - { SND_MIXER_IN_SPEAKER, -1020 }, - { SND_MIXER_IN_MONO, -1010 }, - { SND_MIXER_IN_AUX, -1000 }, - { NULL, 0 } -}; - -snd_mixer_weight_entry_t *snd_mixer_default_weights = _snd_mixer_default_weights; diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h new file mode 100644 index 00000000..dfb67b30 --- /dev/null +++ b/src/mixer/mixer_local.h @@ -0,0 +1,54 @@ +/* + * Mixer Interface - local header file + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include "asoundlib.h" + +typedef struct mixer_simple mixer_simple_t; + +typedef int (mixer_simple_get_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control); +typedef int (mixer_simple_put_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control); +typedef int (mixer_simple_event_t) (snd_mixer_t *handle, snd_ctl_event_type_t etype, snd_control_id_t *id); + +struct mixer_simple { + int refs; /* number of references */ + int change; /* simple control was changed */ + snd_mixer_sid_t id; + mixer_simple_get_t *get; + mixer_simple_put_t *put; + mixer_simple_event_t *event; + mixer_simple_t *prev; + mixer_simple_t *next; + unsigned long private_value; +}; + +struct snd_mixer { + snd_ctl_t *ctl_handle; + int simple_valid; + int simple_count; + int simple_changes; /* total number of changes */ + mixer_simple_t *simple_first; + mixer_simple_t *simple_last; + snd_mixer_simple_callbacks_t *callbacks; +}; + +int snd_mixer_simple_build(snd_mixer_t *handle); +int snd_mixer_simple_destroy(snd_mixer_t *handle); diff --git a/src/mixer/simple.c b/src/mixer/simple.c new file mode 100644 index 00000000..5fa2c5ae --- /dev/null +++ b/src/mixer/simple.c @@ -0,0 +1,440 @@ +/* + * Mixer Interface - simple controls + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "asoundlib.h" +#include "mixer_local.h" + +static int test_mixer_id(snd_mixer_t *handle, const char *name, int index) +{ + snd_control_t c; + int err; + + memset(&c, 0, sizeof(c)); + c.id.iface = SND_CONTROL_IFACE_MIXER; + strcpy(c.id.name, name); + c.id.index = index; + err = snd_ctl_cread(handle->ctl_handle, &c); + fprintf(stderr, "Looking for control: '%s', %i (%i)\n", name, index, err); + switch (err) { + case 0: + case -EBUSY: + return 1; + default: + return 0; + } +} + +static int get_mixer_info(snd_mixer_t *handle, const char *name, int index, snd_control_info_t *info) +{ + memset(info, 0, sizeof(*info)); + info->id.iface = SND_CONTROL_IFACE_MIXER; + strcpy(info->id.name, name); + info->id.index = index; + return snd_ctl_cinfo(handle->ctl_handle, info); +} + +static mixer_simple_t *simple_new(mixer_simple_t *scontrol) +{ + mixer_simple_t *s; + + if (scontrol == NULL) + return NULL; + s = (mixer_simple_t *) calloc(1, sizeof(*s)); + if (s == NULL) + return NULL; + *s = *scontrol; + return s; +} + +static int simple_add(snd_mixer_t *handle, mixer_simple_t *scontrol) +{ + if (handle == NULL || scontrol == NULL) + return -EINVAL; + if (handle->simple_last != NULL) { + handle->simple_last->next = scontrol; + scontrol->prev = handle->simple_last; + scontrol->next = NULL; + handle->simple_last = scontrol; + } else { + handle->simple_first = handle->simple_last = scontrol; + scontrol->prev = scontrol->next = NULL; + } + handle->simple_count++; + return 0; +} + +static int simple_remove(snd_mixer_t *handle, mixer_simple_t *scontrol) +{ + if (handle == NULL || scontrol == NULL) + return -EINVAL; + if (handle->simple_first == scontrol) + handle->simple_first = scontrol->next; + if (handle->simple_last == scontrol) + handle->simple_last = scontrol->prev; + if (scontrol->prev) + scontrol->prev->next = scontrol->next; + if (scontrol->next) + scontrol->next->prev = scontrol->prev; + handle->simple_count--; + return 0; +} + +static int input_get(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control) +{ + char str[128]; + int mute_is_valid = 0; + snd_control_info_t mute_info; + int volume_is_valid = 0; + snd_control_info_t volume_info; + int capture_is_valid = 0, capture1_is_valid = 0; + unsigned int capture1_item = 0; + snd_control_info_t capture_info; + unsigned int voices = 0, idx; + snd_control_t ctl; + int err; + + if (simple == NULL) + return -EINVAL; + + control->caps = 0; + control->channels = 0; + control->mute = 0; + control->capture = 0; + control->capture_group = 0; + control->min = 0; + control->max = 0; + for (idx = 0; idx < 32; idx++) + control->volume.values[idx] = 0; + + sprintf(str, "%s Mute", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &mute_info)) < 0) + return err; + if (mute_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < mute_info.values_count) + voices = mute_info.values_count; + mute_is_valid++; + control->caps |= SND_MIXER_SCTCAP_MUTE; + } + } + sprintf(str, "%s Volume", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &volume_info)) < 0) + return err; + if (volume_info.type == SND_CONTROL_TYPE_INTEGER) { + if (voices < volume_info.values_count) + voices = volume_info.values_count; + volume_is_valid++; + control->caps |= SND_MIXER_SCTCAP_VOLUME; + control->min = volume_info.value.integer.min; + control->max = volume_info.value.integer.max; + } + } + sprintf(str, "%s Capture", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &capture_info)) < 0) + return err; + if (capture_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture_is_valid++; + control->caps |= SND_MIXER_SCTCAP_CAPTURE; + } + } else if (test_mixer_id(handle, "Capture Source", 0)) { + if ((err = get_mixer_info(handle, "Capture Source", 0, &capture_info)) < 0) + return err; + strcpy(str, control->sid.name); + if (!strcmp(str, "Master")) /* special case */ + strcpy(str, "Mix"); + else if (!strcmp(str, "Master Mono")) /* special case */ + strcpy(str, "Mono Mix"); + if (capture_info.type == SND_CONTROL_TYPE_ENUMERATED) { + if (!strcmp(capture_info.value.enumerated.name, str)) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture1_is_valid++; + control->caps |= SND_MIXER_SCTCAP_CAPTURE | SND_MIXER_SCTCAP_EXCL_CAPTURE; + control->capture_group = 1; + } + for (capture1_item = 1; capture1_item < capture_info.value.enumerated.items; capture1_item++) { + capture_info.value.enumerated.item = capture1_item; + if ((err = snd_ctl_cinfo(handle->ctl_handle, &capture_info)) < 0) + return err; + if (!strcmp(capture_info.value.enumerated.name, str)) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture1_is_valid++; + control->caps |= SND_MIXER_SCTCAP_CAPTURE | SND_MIXER_SCTCAP_EXCL_CAPTURE; + control->capture_group = 1; + break; + } + } + } + } + + for (idx = 0; idx < voices && idx < 32; idx++) + control->channels |= 1 << idx; + if (voices > 1) { + if (volume_is_valid && volume_info.values_count == 1) + control->caps |= SND_MIXER_SCTCAP_JOINTLY_VOLUME; + if (mute_is_valid && mute_info.values_count == 1) + control->caps |= SND_MIXER_SCTCAP_JOINTLY_MUTE; + if ((capture_is_valid || capture1_is_valid) && capture_info.values_count == 1) + control->caps |= SND_MIXER_SCTCAP_JOINTLY_CAPTURE; + } + if (volume_is_valid) { + memset(&ctl, 0, sizeof(ctl)); + ctl.id = volume_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) + control->volume.values[idx] = ctl.value.integer.value[volume_info.values_count == 1 ? 0 : idx]; + } + if (mute_is_valid) { + memset(&ctl, 0, sizeof(ctl)); + ctl.id = mute_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) + if (ctl.value.integer.value[mute_info.values_count == 1 ? 0 : idx]) + control->mute |= 1 << idx; + } + if (capture_is_valid) { + memset(&ctl, 0, sizeof(ctl)); + ctl.id = capture_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) + if (ctl.value.integer.value[capture_info.values_count == 1 ? 0 : idx]) + control->capture |= 1 << idx; + } else if (capture1_is_valid) { + memset(&ctl, 0, sizeof(ctl)); + ctl.id = capture_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl)) < 0) + return err; + for (idx = 0; idx < voices && idx < 32; idx++) + if (ctl.value.enumerated.item[capture_info.values_count == 1 ? 0 : idx] == capture1_item) + control->capture |= 1 << idx; + } + + return 0; +} + +static int input_put(snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control) +{ + char str[128]; + int mute_is_valid = 0; + snd_control_info_t mute_info; + int volume_is_valid = 0; + snd_control_info_t volume_info; + int capture_is_valid = 0, capture1_is_valid = 0; + unsigned int capture1_item = 0; + snd_control_info_t capture_info; + unsigned int voices = 0, idx; + snd_control_t ctl_mute, ctl_volume, ctl_capture; + int err; + + if (simple == NULL) + return -EINVAL; + + sprintf(str, "%s Mute", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &mute_info)) < 0) + return err; + if (mute_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < mute_info.values_count) + voices = mute_info.values_count; + mute_is_valid++; + } + } + sprintf(str, "%s Volume", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &volume_info)) < 0) + return err; + if (volume_info.type == SND_CONTROL_TYPE_INTEGER) { + if (voices < volume_info.values_count) + voices = volume_info.values_count; + volume_is_valid++; + } + } + sprintf(str, "%s Capture", control->sid.name); + if (test_mixer_id(handle, str, control->sid.index)) { + if ((err = get_mixer_info(handle, str, control->sid.index, &capture_info)) < 0) + return err; + if (capture_info.type == SND_CONTROL_TYPE_BOOLEAN) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture_is_valid++; + } + } else if (test_mixer_id(handle, "Capture Source", 0)) { + if ((err = get_mixer_info(handle, "Capture Source", 0, &capture_info)) < 0) + return err; + strcpy(str, control->sid.name); + if (!strcmp(str, "Master")) /* special case */ + strcpy(str, "Mix"); + else if (!strcmp(str, "Master Mono")) /* special case */ + strcpy(str, "Mono Mix"); + if (capture_info.type == SND_CONTROL_TYPE_ENUMERATED) { + if (!strcmp(capture_info.value.enumerated.name, str)) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture1_is_valid++; + } + for (capture1_item = 1; capture1_item < capture_info.value.enumerated.items; capture1_item++) { + capture_info.value.enumerated.item = capture1_item; + if ((err = snd_ctl_cinfo(handle->ctl_handle, &capture_info)) < 0) + return err; + if (!strcmp(capture_info.value.enumerated.name, str)) { + if (voices < capture_info.values_count) + voices = capture_info.values_count; + capture1_is_valid++; + break; + } + } + } + } + + memset(&ctl_mute, 0, sizeof(ctl_mute)); + memset(&ctl_volume, 0, sizeof(ctl_volume)); + memset(&ctl_capture, 0, sizeof(ctl_capture)); + if (mute_is_valid) { + ctl_mute.id = mute_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_mute)) < 0) + return err; + } + if (volume_is_valid) { + ctl_volume.id = volume_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_volume)) < 0) + return err; + } + if (capture_is_valid || capture1_is_valid) { + ctl_capture.id = capture_info.id; + if ((err = snd_ctl_cread(handle->ctl_handle, &ctl_capture)) < 0) + return err; + } + for (idx = 0; idx < voices && idx < 32; idx++) { + if (control->channels & (1 << idx)) { + if (volume_is_valid) { + if (control->volume.values[idx] < volume_info.value.integer.min || + control->volume.values[idx] > volume_info.value.integer.max) + return -EINVAL; + ctl_volume.value.integer.value[idx] = control->volume.values[idx]; + } + if (mute_is_valid) { + ctl_mute.value.integer.value[idx] = (control->mute & (1 << idx)) ? 1 : 0; + } + if (capture_is_valid) { + ctl_capture.value.integer.value[idx] = (control->capture & (1 << idx)) ? 1 : 0; + } else if (capture1_is_valid && (control->capture & (1 << idx))) { + ctl_capture.value.enumerated.item[idx] = capture1_item; + } + } + } + if (volume_is_valid) { + if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_volume)) < 0) + return err; + } + if (mute_is_valid) { + if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_mute)) < 0) + return err; + } + if (capture_is_valid || capture1_is_valid) { + if ((err = snd_ctl_cwrite(handle->ctl_handle, &ctl_capture)) < 0) + return err; + } + return 0; +} + +static int build_input_scontrol(snd_mixer_t *handle, const char *sname, int index) +{ + mixer_simple_t s; + + memset(&s, 0, sizeof(s)); + strcpy(s.id.name, sname); + s.id.index = index; + s.get = input_get; + s.put = input_put; + return simple_add(handle, simple_new(&s)); +} + +static int build_input(snd_mixer_t *handle, const char *sname) +{ + char str[128]; + + fprintf(stderr, "build_input: '%s'\n", sname); + sprintf(str, "%s Mute", sname); + if (test_mixer_id(handle, str, 0)) { + fprintf(stderr, "id ok (mute): %s\n", str); + return build_input_scontrol(handle, sname, 0); + } + sprintf(str, "%s Volume", sname); + if (test_mixer_id(handle, str, 0)) + return build_input_scontrol(handle, sname, 0); + return 0; +} + +int snd_mixer_simple_build(snd_mixer_t *handle) +{ + static char *inputs[] = { + "Master", + "Master Mono", + "Master Digital", + "PCM", + "Synth", + "Wave", + "Music", + "Line", + "CD", + "Mic", + "Video", + "Phone", + "PC Speaker", + "Aux", + NULL + }; + char **input = inputs; + int err; + + while (*input) { + if ((err = build_input(handle, *input)) < 0) { + snd_mixer_simple_destroy(handle); + return err; + } + input++; + } + handle->simple_valid = 1; + return 0; +} + +int snd_mixer_simple_destroy(snd_mixer_t *handle) +{ + while (handle->simple_first) + simple_remove(handle, handle->simple_first); + handle->simple_valid = 0; + return 0; +} diff --git a/src/pcm/pcm_common.c b/src/pcm/pcm_common.c index d33ab8cd..3601704e 100644 --- a/src/pcm/pcm_common.c +++ b/src/pcm/pcm_common.c @@ -28,8 +28,8 @@ #include "../../include/pcm.h" #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) -#define vmalloc snd_vmalloc -#define vfree snd_vfree +#define __vmalloc snd_vmalloc +#define __vfree snd_vfree #else #include #include @@ -39,8 +39,8 @@ #include "pcm_local.h" #define snd_pcm_plug_first(plug) ((plug)->first) #define snd_pcm_plug_last(plug) ((plug)->last) -#define vmalloc malloc -#define vfree free +#define __vmalloc malloc +#define __vfree free #endif static int snd_pcm_plugin_src_channels_mask(snd_pcm_plugin_t *plugin, @@ -81,8 +81,8 @@ static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, size_t frames) size /= 8; if (plugin->buf_frames < frames) { if (plugin->buf) - vfree(plugin->buf); - plugin->buf = vmalloc(size); + __vfree(plugin->buf); + plugin->buf = __vmalloc(size); plugin->buf_frames = frames; } if (!plugin->buf) @@ -215,7 +215,7 @@ int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin) free(plugin->name); free(plugin->buf_channels); if (plugin->buf) - vfree(plugin->buf); + __vfree(plugin->buf); free(plugin->src_vmask); free(plugin->dst_vmask); free(plugin); -- 2.47.1