summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-02-14 13:33:08 +0000
committerTakashi Iwai <tiwai@suse.de>2005-02-14 13:33:08 +0000
commit5eb794fe0b77aa251d69b534a9bb4409f50c10cb (patch)
treebace73facdbe70941569068c0ddb7dc59cb2d6d0
parent4ea51d8201e29a93dd714967f1f14aa1b6f8a28e (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.am2
-rw-r--r--include/pcm.h4
-rw-r--r--include/pcm_external.h1
-rw-r--r--include/pcm_extplug.h96
-rw-r--r--src/Versions9
-rw-r--r--src/pcm/Makefile.am6
-rw-r--r--src/pcm/pcm_ext_parm.h27
-rw-r--r--src/pcm/pcm_extplug.c516
-rw-r--r--src/pcm/pcm_ioplug.c148
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 &params->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 &params->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 &params->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 &params->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)