diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-02-14 13:33:08 +0000 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2005-02-14 13:33:08 +0000 |
commit | 5eb794fe0b77aa251d69b534a9bb4409f50c10cb (patch) | |
tree | bace73facdbe70941569068c0ddb7dc59cb2d6d0 | |
parent | 4ea51d8201e29a93dd714967f1f14aa1b6f8a28e (diff) |
Add filter-type external plugin SDK
Added the SDK for filter-type PCM plugins.
Share some codes with ioplug.
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/pcm.h | 4 | ||||
-rw-r--r-- | include/pcm_external.h | 1 | ||||
-rw-r--r-- | include/pcm_extplug.h | 96 | ||||
-rw-r--r-- | src/Versions | 9 | ||||
-rw-r--r-- | src/pcm/Makefile.am | 6 | ||||
-rw-r--r-- | src/pcm/pcm_ext_parm.h | 27 | ||||
-rw-r--r-- | src/pcm/pcm_extplug.c | 516 | ||||
-rw-r--r-- | src/pcm/pcm_ioplug.c | 148 |
9 files changed, 672 insertions, 137 deletions
diff --git a/include/Makefile.am b/include/Makefile.am index eeb21fee..201256fc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -10,7 +10,7 @@ alsainclude_HEADERS = asoundlib.h asoundef.h \ seq_event.h seq.h seqmid.h seq_midi_event.h \ conv.h instr.h iatomic.h \ pcm_ordinary.h mixer_ordinary.h \ - alisp.h pcm_external.h pcm_ioplug.h + alisp.h pcm_external.h pcm_ioplug.h pcm_extplug.h noinst_HEADERS = sys.h search.h list.h aserver.h local.h alsa-symbols.h diff --git a/include/pcm.h b/include/pcm.h index 1357359a..5224bb3c 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -360,7 +360,9 @@ enum _snd_pcm_type { SND_PCM_TYPE_SOFTVOL, /** External I/O plugin */ SND_PCM_TYPE_IOPLUG, - SND_PCM_TYPE_LAST = SND_PCM_TYPE_IOPLUG + /** External filter plugin */ + SND_PCM_TYPE_EXTPLUG, + SND_PCM_TYPE_LAST = SND_PCM_TYPE_EXTPLUG }; /** PCM type */ diff --git a/include/pcm_external.h b/include/pcm_external.h index 92d7c520..be169674 100644 --- a/include/pcm_external.h +++ b/include/pcm_external.h @@ -12,5 +12,6 @@ int SND_PCM_PLUGIN_ENTRY(plugin) (snd_pcm_t **pcmp, const char *name,\ snd_pcm_stream_t stream, int mode) #include "pcm_ioplug.h" +#include "pcm_extplug.h" #endif /* __ALSA_PCM_EXTERNAL_H */ diff --git a/include/pcm_extplug.h b/include/pcm_extplug.h new file mode 100644 index 00000000..9ea667f9 --- /dev/null +++ b/include/pcm_extplug.h @@ -0,0 +1,96 @@ +/* + * ALSA external PCM plugin SDK (draft version) + * + * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> + * + * 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_PCM_EXTPLUG_H +#define __ALSA_PCM_EXTPLUG_H + +/* hw constraints */ +enum { + SND_PCM_EXTPLUG_HW_FORMAT, + SND_PCM_EXTPLUG_HW_CHANNELS, + SND_PCM_EXTPLUG_HW_PARAMS +}; + +typedef struct snd_pcm_extplug snd_pcm_extplug_t; +typedef struct snd_pcm_extplug_callback snd_pcm_extplug_callback_t; + +/* exported pcm data */ +struct snd_pcm_extplug { + /* must be filled before calling snd_pcm_extplug_create() */ + const char *name; + const snd_pcm_extplug_callback_t *callback; + void *private_data; + /* filled by snd_pcm_extplug_open() */ + snd_pcm_t *pcm; + /* read-only status */ + snd_pcm_stream_t stream; + /* filled in hw_params */ + snd_pcm_format_t format; + snd_pcm_subformat_t subformat; + unsigned int channels; + unsigned int rate; + snd_pcm_format_t slave_format; + snd_pcm_subformat_t slave_subformat; + unsigned int slave_channels; +}; + +/* callback table */ +struct snd_pcm_extplug_callback { + /* required */ + snd_pcm_sframes_t (*transfer)(snd_pcm_extplug_t *ext, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + snd_pcm_uframes_t size); + int (*close)(snd_pcm_extplug_t *ext); + int (*hw_params)(snd_pcm_extplug_t *ext, snd_pcm_hw_params_t *params); + int (*hw_free)(snd_pcm_extplug_t *ext); + void (*dump)(snd_pcm_extplug_t *ext, snd_output_t *out); +}; + + +int snd_pcm_extplug_create(snd_pcm_extplug_t *ext, const char *name, + snd_config_t *root, snd_config_t *slave_conf, + snd_pcm_stream_t stream, int mode); +int snd_pcm_extplug_delete(snd_pcm_extplug_t *ext); + +/* clear hw_parameter setting */ +void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *ext); + +/* hw_parameter setting */ +int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); +int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); +int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); +int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); + +static inline int snd_pcm_extplug_set_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) +{ + return snd_pcm_extplug_set_param_list(extplug, type, 1, &val); +} + +static inline int snd_pcm_extplug_set_slave_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) +{ + return snd_pcm_extplug_set_slave_param_list(extplug, type, 1, &val); +} + + +#endif /* __ALSA_PCM_EXTPLUG_H */ diff --git a/src/Versions b/src/Versions index 5ac29f29..e093deda 100644 --- a/src/Versions +++ b/src/Versions @@ -180,4 +180,13 @@ ALSA_1.0.9 { snd_pcm_ioplug_params_reset; snd_pcm_ioplug_set_param_minmax; snd_pcm_ioplug_set_param_list; + + snd_pcm_extplug_create; + snd_pcm_extplug_delete; + snd_pcm_extplug_params_reset; + snd_pcm_extplug_set_param_list; + snd_pcm_extplug_set_param_minmax; + snd_pcm_extplug_set_slave_param_list; + snd_pcm_extplug_set_slave_param_minmax; + } ALSA_1.0.5; diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am index 2ace7912..27ce61cd 100644 --- a/src/pcm/Makefile.am +++ b/src/pcm/Makefile.am @@ -12,14 +12,14 @@ libpcm_la_SOURCES = atomic.c mask.c interval.c \ pcm_meter.c pcm_hooks.c pcm_lfloat.c pcm_ladspa.c \ pcm_direct.c pcm_dmix.c pcm_dsnoop.c pcm_dshare.c \ pcm_asym.c pcm_iec958.c pcm_softvol.c pcm_symbols.c \ - pcm_ioplug.c + pcm_ioplug.c pcm_extplug.c -EXTRA_SOURCES = pcm_dmix_i386.c pcm_dmix_x86_64.c pcm_dmix_generic.c +EXTRA_DIST = pcm_dmix_i386.c pcm_dmix_x86_64.c pcm_dmix_generic.c noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \ interval.h interval_inline.h plugin_ops.h ladspa.h \ pcm_direct.h pcm_dmix_i386.h pcm_dmix_x86_64.h \ - pcm_generic.h + pcm_generic.h pcm_ext_parm.h alsadir = $(datadir)/alsa diff --git a/src/pcm/pcm_ext_parm.h b/src/pcm/pcm_ext_parm.h new file mode 100644 index 00000000..b70749f2 --- /dev/null +++ b/src/pcm/pcm_ext_parm.h @@ -0,0 +1,27 @@ +/* hw_params */ +struct snd_ext_parm { + unsigned int min, max; + unsigned int num_list; + unsigned int *list; + unsigned int active: 1; + unsigned int integer: 1; +}; + +static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; +} + +static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var) +{ + return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; +} + +int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max); +int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list); +void snd_ext_parm_clear(struct snd_ext_parm *parm); +int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list); +int snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type); +int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type); diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c new file mode 100644 index 00000000..24137e6e --- /dev/null +++ b/src/pcm/pcm_extplug.c @@ -0,0 +1,516 @@ +/** + * \file pcm/pcm_extplug.c + * \ingroup Plugin_SDK + * \brief External Plugin SDK + * \author Takashi Iwai <tiwai@suse.de> + * \date 2005 + */ +/* + * PCM - External Filter Plugin SDK + * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de> + * + * + * 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 "pcm_local.h" +#include "pcm_plugin.h" +#include "pcm_extplug.h" +#include "pcm_ext_parm.h" + +typedef struct snd_pcm_extplug_priv { + snd_pcm_plugin_t plug; + snd_pcm_extplug_t *data; + struct snd_ext_parm params[SND_PCM_EXTPLUG_HW_PARAMS]; + struct snd_ext_parm sparams[SND_PCM_EXTPLUG_HW_PARAMS]; +} extplug_priv_t; + +static int hw_params_type[SND_PCM_EXTPLUG_HW_PARAMS] = { + [SND_PCM_EXTPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, + [SND_PCM_EXTPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS +}; + +#define is_mask_type(i) (hw_params_type[i] < SND_PCM_HW_PARAM_FIRST_INTERVAL) + +static unsigned int excl_parbits[SND_PCM_EXTPLUG_HW_PARAMS] = { + [SND_PCM_EXTPLUG_HW_FORMAT] = (SND_PCM_HW_PARBIT_FORMAT| + SND_PCM_HW_PARBIT_SUBFORMAT | + SND_PCM_HW_PARBIT_SAMPLE_BITS), + [SND_PCM_EXTPLUG_HW_CHANNELS] = (SND_PCM_HW_PARBIT_CHANNELS| + SND_PCM_HW_PARBIT_FRAME_BITS), +}; + +/* + */ + +int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max) +{ + parm->num_list = 0; + free(parm->list); + parm->list = NULL; + parm->min = min; + parm->max = max; + parm->active = 1; + return 0; +} + +static int val_compar(const void *ap, const void *bp) +{ + return *(const unsigned int *)ap - *(const unsigned int *)bp; +} + +int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list) +{ + unsigned int *new_list; + + new_list = malloc(sizeof(*new_list) * num_list); + if (new_list == NULL) + return -ENOMEM; + memcpy(new_list, list, sizeof(*new_list) * num_list); + qsort(new_list, num_list, sizeof(*new_list), val_compar); + + free(parm->list); + parm->num_list = num_list; + parm->list = new_list; + parm->active = 1; + return 0; +} + +void snd_ext_parm_clear(struct snd_ext_parm *parm) +{ + free(parm->list); + memset(parm, 0, sizeof(*parm)); +} + +int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list) +{ + int imin, imax; + int changed = 0; + + if (snd_interval_empty(ival)) + return -ENOENT; + for (imin = 0; imin < num_list; imin++) { + if (ival->min == list[imin] && ! ival->openmin) + break; + if (ival->min <= list[imin]) { + ival->min = list[imin]; + ival->openmin = 0; + changed = 1; + break; + } + } + if (imin >= num_list) + return -EINVAL; + for (imax = num_list - 1; imax >= imin; imax--) { + if (ival->max == list[imax] && ! ival->openmax) + break; + if (ival->max >= list[imax]) { + ival->max = list[imax]; + ival->openmax = 0; + changed = 1; + break; + } + } + if (imax < imin) + return -EINVAL; + return changed; +} + +int snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type) +{ + parm += type; + if (! parm->active) + return 0; + ival->integer |= parm->integer; + if (parm->num_list) { + return snd_interval_list(ival, parm->num_list, parm->list); + } else if (parm->min || parm->max) { + snd_interval_t t; + memset(&t, 0, sizeof(t)); + snd_interval_set_minmax(&t, parm->min, parm->max); + t.integer = ival->integer; + return snd_interval_refine(ival, &t); + } + return 0; +} + +int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type) +{ + snd_mask_t bits; + unsigned int i; + + parm += type; + memset(&bits, 0, sizeof(bits)); + for (i = 0; i < parm->num_list; i++) + bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); + return snd_mask_refine(mask, &bits); +} + + +/* + */ + +static int extplug_hw_refine(snd_pcm_hw_params_t *hw_params, + struct snd_ext_parm *parm) +{ + int i, err, change = 0; + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + int type = hw_params_type[i]; + if (is_mask_type(i)) + err = snd_ext_parm_mask_refine(hw_param_mask(hw_params, type), + parm, i); + else + err = snd_ext_parm_interval_refine(hw_param_interval(hw_params, type), + parm, i); + if (err < 0) + return err; + change |= err; + } + return change; +} + +static int snd_pcm_extplug_hw_refine_cprepare(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params) +{ + extplug_priv_t *ext = pcm->private_data; + int err; + snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; + err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, + &access_mask); + if (err < 0) + return err; + err = extplug_hw_refine(params, ext->params); + if (err < 0) + return err; + params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); + return 0; +} + +static int snd_pcm_extplug_hw_refine_sprepare(snd_pcm_t *pcm, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; + _snd_pcm_hw_params_any(sparams); + _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, + &saccess_mask); + extplug_hw_refine(sparams, ext->sparams); + return 0; +} + +static unsigned int get_links(struct snd_ext_parm *params) +{ + int i; + unsigned int links = -1; + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + if (params[i].active) + links &= ~excl_parbits[i]; + } + return links; +} + +static int snd_pcm_extplug_hw_refine_schange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + unsigned int links = get_links(ext->sparams); + int err, change; + err = extplug_hw_refine(sparams, ext->sparams); + if (err < 0) + return err; + change = err; + err = _snd_pcm_hw_params_refine(sparams, links, params); + if (err < 0) + return err; + change |= err; + return change; +} + +static int snd_pcm_extplug_hw_refine_cchange(snd_pcm_t *pcm, + snd_pcm_hw_params_t *params, + snd_pcm_hw_params_t *sparams) +{ + extplug_priv_t *ext = pcm->private_data; + unsigned int links = get_links(ext->params); + int err, change; + err = extplug_hw_refine(params, ext->params); + if (err < 0) + return err; + change = err; + err = _snd_pcm_hw_params_refine(params, links, sparams); + if (err < 0) + return err; + change |= err; + return change; +} + +static int snd_pcm_extplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + return snd_pcm_hw_refine_slave(pcm, params, + snd_pcm_extplug_hw_refine_cprepare, + snd_pcm_extplug_hw_refine_cchange, + snd_pcm_extplug_hw_refine_sprepare, + snd_pcm_extplug_hw_refine_schange, + snd_pcm_generic_hw_refine); +} + +static int snd_pcm_extplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +{ + + extplug_priv_t *ext = pcm->private_data; + snd_pcm_t *slave = ext->plug.gen.slave; + int err = snd_pcm_hw_params_slave(pcm, params, + snd_pcm_extplug_hw_refine_cchange, + snd_pcm_extplug_hw_refine_sprepare, + snd_pcm_extplug_hw_refine_schange, + snd_pcm_generic_hw_params); + if (err < 0) + return err; + ext->data->slave_format = slave->format; + ext->data->slave_subformat = slave->subformat; + ext->data->slave_channels = slave->channels; + ext->data->rate = slave->rate; + INTERNAL(snd_pcm_hw_params_get_format)(params, &ext->data->format); + INTERNAL(snd_pcm_hw_params_get_subformat)(params, &ext->data->subformat); + if (ext->data->callback->hw_params) { + err = ext->data->callback->hw_params(ext->data, params); + if (err < 0) + return err; + } + return 0; +} + +static int snd_pcm_extplug_hw_free(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + snd_pcm_hw_free(ext->plug.gen.slave); + if (ext->data->callback->hw_free) + return ext->data->callback->hw_free(ext->data); + return 0; +} + +static snd_pcm_uframes_t +snd_pcm_extplug_write_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + extplug_priv_t *ext = pcm->private_data; + + if (size > *slave_sizep) + size = *slave_sizep; + ext->data->callback->transfer(ext->data, slave_areas, slave_offset, + areas, offset, size); + *slave_sizep = size; + return size; +} + +static snd_pcm_uframes_t +snd_pcm_extplug_read_areas(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas, + snd_pcm_uframes_t offset, + snd_pcm_uframes_t size, + const snd_pcm_channel_area_t *slave_areas, + snd_pcm_uframes_t slave_offset, + snd_pcm_uframes_t *slave_sizep) +{ + extplug_priv_t *ext = pcm->private_data; + + if (size > *slave_sizep) + size = *slave_sizep; + ext->data->callback->transfer(ext->data, areas, offset, + slave_areas, slave_offset, size); + *slave_sizep = size; + return size; +} + +static void snd_pcm_extplug_dump(snd_pcm_t *pcm, snd_output_t *out) +{ + extplug_priv_t *ext = pcm->private_data; + + if (ext->data->callback->dump) + ext->data->callback->dump(ext->data, out); + else { + if (ext->data->name) + snd_output_printf(out, "%s\n", ext->data->name); + else + snd_output_printf(out, "External PCM Plugin\n"); + if (pcm->setup) { + snd_output_printf(out, "Its setup is:\n"); + snd_pcm_dump_setup(pcm, out); + } + } + snd_output_printf(out, "Slave: "); + snd_pcm_dump(ext->plug.gen.slave, out); +} + +static void clear_ext_params(extplug_priv_t *ext) +{ + int i; + for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { + snd_ext_parm_clear(&ext->params[i]); + snd_ext_parm_clear(&ext->sparams[i]); + } +} + +static int snd_pcm_extplug_close(snd_pcm_t *pcm) +{ + extplug_priv_t *ext = pcm->private_data; + + snd_pcm_close(ext->plug.gen.slave); + clear_ext_params(ext); + if (ext->data->callback->close) + ext->data->callback->close(ext->data); + free(ext); + return 0; +} + +static snd_pcm_ops_t snd_pcm_extplug_ops = { + .close = snd_pcm_extplug_close, + .info = snd_pcm_generic_info, + .hw_refine = snd_pcm_extplug_hw_refine, + .hw_params = snd_pcm_extplug_hw_params, + .hw_free = snd_pcm_extplug_hw_free, + .sw_params = snd_pcm_generic_sw_params, + .channel_info = snd_pcm_generic_channel_info, + .dump = snd_pcm_extplug_dump, + .nonblock = snd_pcm_generic_nonblock, + .async = snd_pcm_generic_async, + .poll_revents = snd_pcm_generic_poll_revents, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, +}; + +/* + */ +void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *extplug) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + clear_ext_params(ext); +} + +int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_list(&ext->sparams[type], num_list, list); +} + +int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (is_mask_type(type)) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_minmax(&ext->sparams[type], min, max); +} + +int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_list(&ext->params[type], num_list, list); +} + +int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) +{ + extplug_priv_t *ext = extplug->pcm->private_data; + if (type < 0 && type >= SND_PCM_EXTPLUG_HW_PARAMS) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + if (is_mask_type(type)) { + SNDERR("EXTPLUG: invalid parameter type %d", type); + return -EINVAL; + } + return snd_ext_parm_set_minmax(&ext->params[type], min, max); +} + +/* + */ +int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, + snd_config_t *root, snd_config_t *slave_conf, + snd_pcm_stream_t stream, int mode) +{ + extplug_priv_t *ext; + int err; + snd_pcm_t *spcm, *pcm; + snd_config_t *sconf; + + assert(extplug && extplug->callback); + assert(extplug->callback->transfer); + + err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0); + if (err < 0) + return err; + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); + snd_config_delete(sconf); + if (err < 0) + return err; + + ext = calloc(1, sizeof(*ext)); + if (! ext) + return -ENOMEM; + + ext->data = extplug; + extplug->stream = stream; + + snd_pcm_plugin_init(&ext->plug); + ext->plug.read = snd_pcm_extplug_read_areas; + ext->plug.write = snd_pcm_extplug_write_areas; + ext->plug.undo_read = snd_pcm_plugin_undo_read_generic; + ext->plug.undo_write = snd_pcm_plugin_undo_write_generic; + ext->plug.gen.slave = spcm; + ext->plug.gen.close_slave = 1; + + err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode); + if (err < 0) { + free(ext); + return err; + } + + extplug->pcm = pcm; + pcm->ops = &snd_pcm_extplug_ops; + pcm->fast_ops = &snd_pcm_plugin_fast_ops; + pcm->private_data = ext; + pcm->poll_fd = spcm->poll_fd; + pcm->poll_events = spcm->poll_events; + snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0); + + return 0; +} + +int snd_pcm_extplug_delete(snd_pcm_extplug_t *extplug) +{ + return snd_pcm_close(extplug->pcm); +} diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c index 9ed12555..bf8c9882 100644 --- a/src/pcm/pcm_ioplug.c +++ b/src/pcm/pcm_ioplug.c @@ -28,19 +28,12 @@ #include "pcm_local.h" #include "pcm_ioplug.h" +#include "pcm_ext_parm.h" /* hw_params */ -struct ioplug_parm { - unsigned int min, max; - unsigned int num_list; - unsigned int *list; - unsigned int active: 1; - unsigned int integer: 1; -}; - typedef struct snd_pcm_ioplug_priv { snd_pcm_ioplug_t *data; - struct ioplug_parm params[SND_PCM_IOPLUG_HW_PARAMS]; + struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS]; unsigned int last_hw; snd_pcm_uframes_t avail_max; snd_htimestamp_t trigger_tstamp; @@ -138,18 +131,6 @@ static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm) return 0; } -static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; -} - -static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, - snd_pcm_hw_param_t var) -{ - return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; -} - static int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = { [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS, [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, @@ -160,72 +141,6 @@ static int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = { [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS, }; -static int ioplug_mask_refine(snd_mask_t *mask, struct ioplug_parm *parm) -{ - snd_mask_t bits; - unsigned int i; - - memset(&bits, 0, sizeof(bits)); - for (i = 0; i < parm->num_list; i++) - bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); - return snd_mask_refine(mask, &bits); -} - -static int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list) -{ - int imin, imax; - int changed = 0; - - if (snd_interval_empty(ival)) - return -ENOENT; - for (imin = 0; imin < num_list; imin++) { - if (ival->min == list[imin] && ! ival->openmin) - break; - if (ival->min <= list[imin]) { - ival->min = list[imin]; - ival->openmin = 0; - changed = 1; - break; - } - } - if (imin >= num_list) - return -EINVAL; - for (imax = num_list - 1; imax >= imin; imax--) { - if (ival->max == list[imax] && ! ival->openmax) - break; - if (ival->max >= list[imax]) { - ival->max = list[imax]; - ival->openmax = 0; - changed = 1; - break; - } - } - if (imax < imin) - return -EINVAL; - return changed; -} - -static int ioplug_interval_refine(ioplug_priv_t *io, snd_pcm_hw_params_t *params, int type) -{ - struct ioplug_parm *parm = &io->params[type]; - snd_interval_t *ival; - - if (! parm->active) - return 0; - ival = hw_param_interval(params, hw_params_type[type]); - ival->integer |= parm->integer; - if (parm->num_list) { - return snd_interval_list(ival, parm->num_list, parm->list); - } else if (parm->min || parm->max) { - snd_interval_t t; - memset(&t, 0, sizeof(t)); - snd_interval_set_minmax(&t, parm->min, parm->max); - t.integer = ival->integer; - return snd_interval_refine(ival, &t); - } - return 0; -} - /* x = a * b */ static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b) { @@ -324,15 +239,16 @@ static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) /* access, format */ for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) { - err = ioplug_mask_refine(hw_param_mask(params, hw_params_type[i]), - &io->params[i]); + err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]), + io->params, i); if (err < 0) return err; change |= err; } /* channels, rate */ for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) { - err = ioplug_interval_refine(io, params, i); + err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]), + io->params, i); if (err < 0) return err; change |= err; @@ -354,7 +270,8 @@ static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) SND_PCM_HW_PARAM_PERIOD_BYTES); if (change1 < 0) return change1; - err = ioplug_interval_refine(io, params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), + io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); if (err < 0) return err; change1 |= err; @@ -376,7 +293,8 @@ static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) do { change2 = 0; - err = ioplug_interval_refine(io, params, SND_PCM_IOPLUG_HW_BUFFER_BYTES); + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES), + io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES); if (err < 0) return err; change2 |= err; @@ -387,7 +305,8 @@ static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) if (err < 0) return err; change2 |= err; - err = ioplug_interval_refine(io, params, SND_PCM_IOPLUG_HW_PERIODS); + err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS), + io->params, SND_PCM_IOPLUG_HW_PERIODS); if (err < 0) return err; change2 |= err; @@ -723,10 +642,8 @@ static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out) static void clear_io_params(ioplug_priv_t *io) { int i; - for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++) { - free(io->params[i].list); - memset(&io->params[i], 0, sizeof(io->params[i])); - } + for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++) + snd_ext_parm_clear(&io->params[i]); } static int snd_pcm_ioplug_close(snd_pcm_t *pcm) @@ -783,39 +700,6 @@ static snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = { .mmap_commit = snd_pcm_ioplug_mmap_commit, }; -static int ioplug_set_parm_minmax(struct ioplug_parm *parm, unsigned int min, unsigned int max) -{ - parm->num_list = 0; - free(parm->list); - parm->list = NULL; - parm->min = min; - parm->max = max; - parm->active = 1; - return 0; -} - -static int val_compar(const void *ap, const void *bp) -{ - return *(const unsigned int *)ap - *(const unsigned int *)bp; -} - -static int ioplug_set_parm_list(struct ioplug_parm *parm, unsigned int num_list, const unsigned int *list) -{ - unsigned int *new_list; - - new_list = malloc(sizeof(*new_list) * num_list); - if (new_list == NULL) - return -ENOMEM; - memcpy(new_list, list, sizeof(*new_list) * num_list); - qsort(new_list, num_list, sizeof(*new_list), val_compar); - - free(parm->list); - parm->num_list = num_list; - parm->list = new_list; - parm->active = 1; - return 0; -} - void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug) { ioplug_priv_t *io = ioplug->pcm->private_data; @@ -831,7 +715,7 @@ int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned i } if (type == SND_PCM_IOPLUG_HW_PERIODS) io->params[type].integer = 1; - return ioplug_set_parm_list(&io->params[type], num_list, list); + return snd_ext_parm_set_list(&io->params[type], num_list, list); } int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max) @@ -847,7 +731,7 @@ int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned } if (type == SND_PCM_IOPLUG_HW_PERIODS) io->params[type].integer = 1; - return ioplug_set_parm_minmax(&io->params[type], min, max); + return snd_ext_parm_set_minmax(&io->params[type], min, max); } int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug) |