Blame src/pcm/pcm_extplug.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_extplug.c
Packit 4a16fb
 * \ingroup Plugin_SDK
Packit 4a16fb
 * \brief External Filter Plugin SDK
Packit 4a16fb
 * \author Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 * \date 2005
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - External Filter Plugin SDK
Packit 4a16fb
 *  Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 *
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
  
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_plugin.h"
Packit 4a16fb
#include "pcm_extplug.h"
Packit 4a16fb
#include "pcm_ext_parm.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_extplug = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
Packit 4a16fb
typedef struct snd_pcm_extplug_priv {
Packit 4a16fb
	snd_pcm_plugin_t plug;
Packit 4a16fb
	snd_pcm_extplug_t *data;
Packit 4a16fb
	struct snd_ext_parm params[SND_PCM_EXTPLUG_HW_PARAMS];
Packit 4a16fb
	struct snd_ext_parm sparams[SND_PCM_EXTPLUG_HW_PARAMS];
Packit 4a16fb
} extplug_priv_t;
Packit 4a16fb
Packit 4a16fb
static const int hw_params_type[SND_PCM_EXTPLUG_HW_PARAMS] = {
Packit 4a16fb
	[SND_PCM_EXTPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
Packit 4a16fb
	[SND_PCM_EXTPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
#define is_mask_type(i) (hw_params_type[i] < SND_PCM_HW_PARAM_FIRST_INTERVAL)
Packit 4a16fb
Packit 4a16fb
static const unsigned int excl_parbits[SND_PCM_EXTPLUG_HW_PARAMS] = {
Packit 4a16fb
	[SND_PCM_EXTPLUG_HW_FORMAT] = (SND_PCM_HW_PARBIT_FORMAT|
Packit 4a16fb
				       SND_PCM_HW_PARBIT_SUBFORMAT |
Packit 4a16fb
				       SND_PCM_HW_PARBIT_SAMPLE_BITS),
Packit 4a16fb
	[SND_PCM_EXTPLUG_HW_CHANNELS] = (SND_PCM_HW_PARBIT_CHANNELS|
Packit 4a16fb
					 SND_PCM_HW_PARBIT_FRAME_BITS),
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * set min/max values for the given parameter
Packit 4a16fb
 */
Packit 4a16fb
int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max)
Packit 4a16fb
{
Packit 4a16fb
	parm->num_list = 0;
Packit 4a16fb
	free(parm->list);
Packit 4a16fb
	parm->list = NULL;
Packit 4a16fb
	parm->min = min;
Packit 4a16fb
	parm->max = max;
Packit 4a16fb
	parm->active = 1;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * set the list of available values for the given parameter
Packit 4a16fb
 */
Packit 4a16fb
static int val_compar(const void *ap, const void *bp)
Packit 4a16fb
{
Packit 4a16fb
	return *(const unsigned int *)ap - *(const unsigned int *)bp;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int *new_list;
Packit 4a16fb
Packit 4a16fb
	new_list = malloc(sizeof(*new_list) * num_list);
Packit 4a16fb
	if (new_list == NULL)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	memcpy(new_list, list, sizeof(*new_list) * num_list);
Packit 4a16fb
	qsort(new_list, num_list, sizeof(*new_list), val_compar);
Packit 4a16fb
Packit 4a16fb
	free(parm->list);
Packit 4a16fb
	parm->num_list = num_list;
Packit 4a16fb
	parm->list = new_list;
Packit 4a16fb
	parm->active = 1;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
void snd_ext_parm_clear(struct snd_ext_parm *parm)
Packit 4a16fb
{
Packit 4a16fb
	free(parm->list);
Packit 4a16fb
	memset(parm, 0, sizeof(*parm));
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * limit the interval to the given list
Packit 4a16fb
 */
Packit 4a16fb
int snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list)
Packit 4a16fb
{
Packit 4a16fb
	int imin, imax;
Packit 4a16fb
	int changed = 0;
Packit 4a16fb
Packit 4a16fb
	if (snd_interval_empty(ival))
Packit 4a16fb
		return -ENOENT;
Packit 4a16fb
	for (imin = 0; imin < num_list; imin++) {
Packit 4a16fb
		if (ival->min == list[imin] && ! ival->openmin)
Packit 4a16fb
			break;
Packit 4a16fb
		if (ival->min <= list[imin]) {
Packit 4a16fb
			ival->min = list[imin];
Packit 4a16fb
			ival->openmin = 0;
Packit 4a16fb
			changed = 1;
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (imin >= num_list)
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	for (imax = num_list - 1; imax >= imin; imax--) {
Packit 4a16fb
		if (ival->max == list[imax] && ! ival->openmax)
Packit 4a16fb
			break;
Packit 4a16fb
		if (ival->max >= list[imax]) {
Packit 4a16fb
			ival->max = list[imax];
Packit 4a16fb
			ival->openmax = 0;
Packit 4a16fb
			changed = 1;
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (imax < imin)
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	return changed;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * refine the interval parameter
Packit 4a16fb
 */
Packit 4a16fb
int snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type)
Packit 4a16fb
{
Packit 4a16fb
	parm += type;
Packit 4a16fb
	if (! parm->active)
Packit 4a16fb
		return 0;
Packit 4a16fb
	ival->integer |= parm->integer;
Packit 4a16fb
	if (parm->num_list) {
Packit 4a16fb
		return snd_interval_list(ival, parm->num_list, parm->list);
Packit 4a16fb
	} else if (parm->min || parm->max) {
Packit 4a16fb
		snd_interval_t t;
Packit 4a16fb
		memset(&t, 0, sizeof(t));
Packit 4a16fb
		snd_interval_set_minmax(&t, parm->min, parm->max);
Packit 4a16fb
		t.integer = ival->integer;
Packit 4a16fb
		return snd_interval_refine(ival, &t);
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * refine the mask parameter
Packit 4a16fb
 */
Packit 4a16fb
int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type)
Packit 4a16fb
{
Packit 4a16fb
	snd_mask_t bits;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	parm += type;
Packit 4a16fb
	if (!parm->active)
Packit 4a16fb
		return 0;
Packit 4a16fb
	memset(&bits, 0, sizeof(bits));
Packit 4a16fb
	for (i = 0; i < parm->num_list; i++)
Packit 4a16fb
		bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32);
Packit 4a16fb
	return snd_mask_refine(mask, &bits);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * hw_refine callback
Packit 4a16fb
 */
Packit 4a16fb
static int extplug_hw_refine(snd_pcm_hw_params_t *hw_params,
Packit 4a16fb
			     struct snd_ext_parm *parm)
Packit 4a16fb
{
Packit 4a16fb
	int i, err, change = 0;
Packit 4a16fb
	for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) {
Packit 4a16fb
		int type = hw_params_type[i];
Packit 4a16fb
		if (is_mask_type(i))
Packit 4a16fb
			err = snd_ext_parm_mask_refine(hw_param_mask(hw_params, type),
Packit 4a16fb
						       parm, i);
Packit 4a16fb
		else
Packit 4a16fb
			err = snd_ext_parm_interval_refine(hw_param_interval(hw_params, type),
Packit 4a16fb
							   parm, i);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change |= err;
Packit 4a16fb
	}
Packit 4a16fb
	return change;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_hw_refine_cprepare(snd_pcm_t *pcm,
Packit 4a16fb
					      snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
Packit 4a16fb
	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
					 &access_mask);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = extplug_hw_refine(params, ext->params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_hw_refine_sprepare(snd_pcm_t *pcm,
Packit 4a16fb
					      snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
Packit 4a16fb
	_snd_pcm_hw_params_any(sparams);
Packit 4a16fb
	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
				   &saccess_mask);
Packit 4a16fb
	extplug_hw_refine(sparams, ext->sparams);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static unsigned int get_links(struct snd_ext_parm *params)
Packit 4a16fb
{
Packit 4a16fb
	int i;
Packit 4a16fb
	unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_SUBFORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_SAMPLE_BITS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_CHANNELS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_FRAME_BITS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_RATE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIODS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_TICK_TIME);
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) {
Packit 4a16fb
		if (params[i].active && !params[i].keep_link)
Packit 4a16fb
			links &= ~excl_parbits[i];
Packit 4a16fb
	}
Packit 4a16fb
	return links;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_hw_refine_schange(snd_pcm_t *pcm,
Packit 4a16fb
					     snd_pcm_hw_params_t *params,
Packit 4a16fb
					     snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	unsigned int links = get_links(ext->sparams);
Packit 4a16fb
Packit 4a16fb
	return _snd_pcm_hw_params_refine(sparams, links, params);
Packit 4a16fb
}
Packit 4a16fb
	
Packit 4a16fb
static int snd_pcm_extplug_hw_refine_cchange(snd_pcm_t *pcm,
Packit 4a16fb
					     snd_pcm_hw_params_t *params,
Packit 4a16fb
					     snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	unsigned int links = get_links(ext->params);
Packit 4a16fb
Packit 4a16fb
	return _snd_pcm_hw_params_refine(params, links, sparams);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	int err = snd_pcm_hw_refine_slave(pcm, params,
Packit 4a16fb
				       snd_pcm_extplug_hw_refine_cprepare,
Packit 4a16fb
				       snd_pcm_extplug_hw_refine_cchange,
Packit 4a16fb
				       snd_pcm_extplug_hw_refine_sprepare,
Packit 4a16fb
				       snd_pcm_extplug_hw_refine_schange,
Packit 4a16fb
				       snd_pcm_generic_hw_refine);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * hw_params callback
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_extplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = ext->plug.gen.slave;
Packit 4a16fb
	int err = snd_pcm_hw_params_slave(pcm, params,
Packit 4a16fb
					  snd_pcm_extplug_hw_refine_cchange,
Packit 4a16fb
					  snd_pcm_extplug_hw_refine_sprepare,
Packit 4a16fb
					  snd_pcm_extplug_hw_refine_schange,
Packit 4a16fb
					  snd_pcm_generic_hw_params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	ext->data->slave_format = slave->format;
Packit 4a16fb
	ext->data->slave_subformat = slave->subformat;
Packit 4a16fb
	ext->data->slave_channels = slave->channels;
Packit 4a16fb
	ext->data->rate = slave->rate;
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_format)(params, &ext->data->format);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_subformat)(params, &ext->data->subformat);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_channels)(params, &ext->data->channels);
Packit 4a16fb
Packit 4a16fb
	if (ext->data->callback->hw_params) {
Packit 4a16fb
		err = ext->data->callback->hw_params(ext->data, params);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * hw_free callback
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_extplug_hw_free(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_hw_free(ext->plug.gen.slave);
Packit 4a16fb
	if (ext->data->callback->hw_free)
Packit 4a16fb
		return ext->data->callback->hw_free(ext->data);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * write_areas skeleton - call transfer callback
Packit 4a16fb
 */
Packit 4a16fb
static snd_pcm_uframes_t
Packit 4a16fb
snd_pcm_extplug_write_areas(snd_pcm_t *pcm,
Packit 4a16fb
			    const snd_pcm_channel_area_t *areas,
Packit 4a16fb
			    snd_pcm_uframes_t offset,
Packit 4a16fb
			    snd_pcm_uframes_t size,
Packit 4a16fb
			    const snd_pcm_channel_area_t *slave_areas,
Packit 4a16fb
			    snd_pcm_uframes_t slave_offset,
Packit 4a16fb
			    snd_pcm_uframes_t *slave_sizep)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (size > *slave_sizep)
Packit 4a16fb
		size = *slave_sizep;
Packit 4a16fb
	size = ext->data->callback->transfer(ext->data, slave_areas, slave_offset,
Packit 4a16fb
					     areas, offset, size);
Packit 4a16fb
	*slave_sizep = size;
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * read_areas skeleton - call transfer callback
Packit 4a16fb
 */
Packit 4a16fb
static snd_pcm_uframes_t
Packit 4a16fb
snd_pcm_extplug_read_areas(snd_pcm_t *pcm,
Packit 4a16fb
			   const snd_pcm_channel_area_t *areas,
Packit 4a16fb
			   snd_pcm_uframes_t offset,
Packit 4a16fb
			   snd_pcm_uframes_t size,
Packit 4a16fb
			   const snd_pcm_channel_area_t *slave_areas,
Packit 4a16fb
			   snd_pcm_uframes_t slave_offset,
Packit 4a16fb
			   snd_pcm_uframes_t *slave_sizep)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (size > *slave_sizep)
Packit 4a16fb
		size = *slave_sizep;
Packit 4a16fb
	size = ext->data->callback->transfer(ext->data, areas, offset,
Packit 4a16fb
					     slave_areas, slave_offset, size);
Packit 4a16fb
	*slave_sizep = size;
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * call init callback
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_extplug_init(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
	return ext->data->callback->init(ext->data);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * dump setup
Packit 4a16fb
 */
Packit 4a16fb
static void snd_pcm_extplug_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (ext->data->callback->dump)
Packit 4a16fb
		ext->data->callback->dump(ext->data, out);
Packit 4a16fb
	else {
Packit 4a16fb
		if (ext->data->name)
Packit 4a16fb
			snd_output_printf(out, "%s\n", ext->data->name);
Packit 4a16fb
		else
Packit 4a16fb
			snd_output_printf(out, "External PCM Plugin\n");
Packit 4a16fb
		if (pcm->setup) {
Packit 4a16fb
			snd_output_printf(out, "Its setup is:\n");
Packit 4a16fb
			snd_pcm_dump_setup(pcm, out);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	snd_output_printf(out, "Slave: ");
Packit 4a16fb
	snd_pcm_dump(ext->plug.gen.slave, out);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void clear_ext_params(extplug_priv_t *ext)
Packit 4a16fb
{
Packit 4a16fb
	int i;
Packit 4a16fb
	for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) {
Packit 4a16fb
		snd_ext_parm_clear(&ext->params[i]);
Packit 4a16fb
		snd_ext_parm_clear(&ext->sparams[i]);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_close(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_close(ext->plug.gen.slave);
Packit 4a16fb
	clear_ext_params(ext);
Packit 4a16fb
	if (ext->data->callback->close)
Packit 4a16fb
		ext->data->callback->close(ext->data);
Packit 4a16fb
	free(ext);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_query_t **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (ext->data->version >= 0x010002 &&
Packit 4a16fb
	    ext->data->callback->query_chmaps)
Packit 4a16fb
		return ext->data->callback->query_chmaps(ext->data);
Packit 4a16fb
	return snd_pcm_generic_query_chmaps(pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_t *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (ext->data->version >= 0x010002 &&
Packit 4a16fb
	    ext->data->callback->get_chmap)
Packit 4a16fb
		return ext->data->callback->get_chmap(ext->data);
Packit 4a16fb
	return snd_pcm_generic_get_chmap(pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (ext->data->version >= 0x010002 &&
Packit 4a16fb
	    ext->data->callback->set_chmap)
Packit 4a16fb
		return ext->data->callback->set_chmap(ext->data, map);
Packit 4a16fb
	return snd_pcm_generic_set_chmap(pcm, map);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_extplug_ops = {
Packit 4a16fb
	.close = snd_pcm_extplug_close,
Packit 4a16fb
	.info = snd_pcm_generic_info,
Packit 4a16fb
	.hw_refine = snd_pcm_extplug_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_extplug_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_extplug_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_generic_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_generic_channel_info,
Packit 4a16fb
	.dump = snd_pcm_extplug_dump,
Packit 4a16fb
	.nonblock = snd_pcm_generic_nonblock,
Packit 4a16fb
	.async = snd_pcm_generic_async,
Packit 4a16fb
	.mmap = snd_pcm_generic_mmap,
Packit 4a16fb
	.munmap = snd_pcm_generic_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_extplug_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_extplug_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_extplug_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
#endif /* !DOC_HIDDEN */
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Exported functions
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_external_plugins PCM External Plugin SDK
Packit 4a16fb
Packit 4a16fb
\section pcm_externals External Plugins
Packit 4a16fb
Packit 4a16fb
The external plugins are implemented in a shared object file located
Packit 4a16fb
at /usr/lib/alsa-lib (the exact location depends on the build option
Packit 4a16fb
and asoundrc configuration).  It has to be the file like
Packit 4a16fb
libasound_module_pcm_MYPLUGIN.so, where MYPLUGIN corresponds to your
Packit 4a16fb
own plugin name.
Packit 4a16fb
Packit 4a16fb
The entry point of the plugin is defined via
Packit 4a16fb
#SND_PCM_PLUGIN_DEFINE_FUNC() macro.  This macro defines the function
Packit 4a16fb
with a proper name to be referred from alsa-lib.  The function takes
Packit 4a16fb
the following 6 arguments:
Packit 4a16fb
\code
Packit 4a16fb
int (snd_pcm_t **pcmp, const char *name, snd_config_t *root,
Packit 4a16fb
	snd_config_t *conf, snd_pcm_stream_t stream, int mode)
Packit 4a16fb
\endcode
Packit 4a16fb
The first argument, pcmp, is the pointer to store the resultant PCM
Packit 4a16fb
handle.  The arguments name, root, stream and mode are the parameters
Packit 4a16fb
to be passed to the plugin constructor.  The conf is the configuration
Packit 4a16fb
tree for the plugin.  The arguments above are defined in the macro
Packit 4a16fb
itself, so don't use variables with the same names to shadow
Packit 4a16fb
parameters.
Packit 4a16fb
Packit 4a16fb
After parsing the configuration parameters in the given conf tree,
Packit 4a16fb
usually you will call the external plugin API function,
Packit 4a16fb
#snd_pcm_extplug_create() or #snd_pcm_ioplug_create(), depending
Packit 4a16fb
on the plugin type.  The PCM handle must be filled *pcmp in return.
Packit 4a16fb
Then this function must return either a value 0 when succeeded, or a
Packit 4a16fb
negative value as the error code. 
Packit 4a16fb
Packit 4a16fb
Finally, add #SND_PCM_PLUGIN_SYMBOL() with the name of your
Packit 4a16fb
plugin as the argument at the end.  This defines the proper versioned
Packit 4a16fb
symbol as the reference.
Packit 4a16fb
Packit 4a16fb
The typical code would look like below:
Packit 4a16fb
\code
Packit 4a16fb
struct myplug_info {
Packit 4a16fb
	snd_pcm_extplug_t ext;
Packit 4a16fb
	int my_own_data;
Packit 4a16fb
	...
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
SND_PCM_PLUGIN_DEFINE_FUNC(myplug)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *slave = NULL;
Packit 4a16fb
	struct myplug_info *myplug;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, conf) {
Packit 4a16fb
		snd_config_t *n = snd_config_iterator_entry(i);
Packit 4a16fb
		const char *id;
Packit 4a16fb
		if (snd_config_get_id(n, &id) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (strcmp(id, "slave") == 0) {
Packit 4a16fb
			slave = n;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
		if (strcmp(id, "my_own_parameter") == 0) {
Packit 4a16fb
			....
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
		SNDERR("Unknown field %s", id);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (! slave) {
Packit 4a16fb
		SNDERR("No slave defined for myplug");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	myplug = calloc(1, sizeof(*myplug));
Packit 4a16fb
	if (myplug == NULL)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	myplug->ext.version = SND_PCM_EXTPLUG_VERSION;
Packit 4a16fb
	myplug->ext.name = "My Own Plugin";
Packit 4a16fb
	myplug->ext.callback = &my_own_callback;
Packit 4a16fb
	myplug->ext.private_data = myplug;
Packit 4a16fb
	....
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_extplug_create(&myplug->ext, name, root, conf, stream, mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		myplug_free(myplug);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	*pcmp = myplug->ext.pcm;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
SND_PCM_PLUGIN_SYMBOL(myplug);
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
Read the codes in alsa-plugins package for the real examples.
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
\section pcm_extplug External Plugin: Filter-Type Plugin
Packit 4a16fb
Packit 4a16fb
The filter-type plugin is a plugin to convert the PCM signals from the input
Packit 4a16fb
and feeds to the output.  Thus, this plugin always needs a slave PCM as its output.
Packit 4a16fb
Packit 4a16fb
The plugin can modify the format and the channels of the input/output PCM.
Packit 4a16fb
It can not modify the sample rate (because of simplicity reason).
Packit 4a16fb
Packit 4a16fb
The following fields have to be filled in extplug record before calling
Packit 4a16fb
#snd_pcm_extplug_create() : version, name, callback.
Packit 4a16fb
Otherfields are optional and should be initialized with zero.
Packit 4a16fb
Packit 4a16fb
The constant #SND_PCM_EXTPLUG_VERSION must be passed to the version
Packit 4a16fb
field for the version check in alsa-lib.  A non-NULL ASCII string
Packit 4a16fb
has to be passed to the name field.  The callback field contains the 
Packit 4a16fb
table of callback functions for this plugin (defined as
Packit 4a16fb
#snd_pcm_extplug_callback_t).
Packit 4a16fb
Packit 4a16fb
The driver can set an arbitrary value (pointer) to private_data
Packit 4a16fb
field to refer its own data in the callbacks.
Packit 4a16fb
Packit 4a16fb
The rest fields are filled by #snd_pcm_extplug_create().  The pcm field
Packit 4a16fb
is the resultant PCM handle.  The others are the current status of the
Packit 4a16fb
PCM.
Packit 4a16fb
Packit 4a16fb
The callback functions in #snd_pcm_extplug_callback_t define the real
Packit 4a16fb
behavior of the driver.
Packit 4a16fb
At least, transfer callback must be given.  This callback is called
Packit 4a16fb
at each time certain size of data block is transfered to the slave
Packit 4a16fb
PCM.  Other callbacks are optional.  
Packit 4a16fb
Packit 4a16fb
The close callback is called when the PCM is closed.  If the plugin
Packit 4a16fb
allocates private resources, this is the place to release them
Packit 4a16fb
again.  The hw_params and hw_free callbacks are called at
Packit 4a16fb
#snd_pcm_hw_params() and #snd_pcm_hw_free() API calls,
Packit 4a16fb
respectively.  The last, dump callback, is called for printing the
Packit 4a16fb
information of the given plugin.
Packit 4a16fb
Packit 4a16fb
The init callback is called when the PCM is at prepare state or any
Packit 4a16fb
initialization is issued.  Use this callback to reset the PCM instance
Packit 4a16fb
to a sane initial state.
Packit 4a16fb
Packit 4a16fb
The hw_params constraints can be defined via either
Packit 4a16fb
#snd_pcm_extplug_set_param_minmax() and #snd_pcm_extplug_set_param_list()
Packit 4a16fb
functions after calling #snd_pcm_extplug_create().
Packit 4a16fb
The former defines the minimal and maximal acceptable values for the
Packit 4a16fb
given hw_params parameter (SND_PCM_EXTPLUG_HW_XXX).
Packit 4a16fb
This function can't be used for the format parameter.  The latter
Packit 4a16fb
function specifies the available parameter values as the list.
Packit 4a16fb
As mentioned above, the rate can't be changed.  Only changeable
Packit 4a16fb
parameters are sample format and channels.
Packit 4a16fb
Packit 4a16fb
To define the constraints of the slave PCM configuration, use
Packit 4a16fb
either #snd_pcm_extplug_set_slave_param_minmax() and
Packit 4a16fb
#snd_pcm_extplug_set_slave_param_list().  The arguments are as same
Packit 4a16fb
as former functions.
Packit 4a16fb
Packit 4a16fb
To clear the parameter constraints, call #snd_pcm_extplug_params_reset()
Packit 4a16fb
function. 
Packit 4a16fb
Packit 4a16fb
When using snd_pcm_extplug_set_param_*() or snd_pcm_extplug_set_slave_param_*()
Packit 4a16fb
for any parameter. This parameter is no longer linked between the client and
Packit 4a16fb
slave PCM. Therefore it could differ and the extplug has to support conversion
Packit 4a16fb
between all valid parameter configurations. To keep the client and slave
Packit 4a16fb
parameter linked #snd_pcm_extplug_set_param_link() can be used for the
Packit 4a16fb
corresponding parameter. For example if the extplug does not support channel nor
Packit 4a16fb
format conversion the supported client parameters can be limited with
Packit 4a16fb
snd_pcm_extplug_set_param_*() and afterwards
Packit 4a16fb
#snd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_FORMAT, 1) and
Packit 4a16fb
#snd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_CHANNELS, 1) should be
Packit 4a16fb
called to keep the client and slave parameters the same.
Packit 4a16fb
*/
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Create an extplug instance
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 * \param name name of the PCM
Packit 4a16fb
 * \param root configuration tree root
Packit 4a16fb
 * \param slave_conf slave configuration root
Packit 4a16fb
 * \param stream stream direction
Packit 4a16fb
 * \param mode PCM open mode
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Creates the extplug instance based on the given handle.
Packit 4a16fb
 * The slave_conf argument is mandatory, and usually taken from the config tree of the
Packit 4a16fb
 * PCM plugin as "slave" config value.
Packit 4a16fb
 * name, root, stream and mode arguments are the values used for opening the PCM.
Packit 4a16fb
 *
Packit 4a16fb
 * The callback is the mandatory field of extplug handle.  At least, start, stop and
Packit 4a16fb
 * pointer callbacks must be set before calling this function.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name,
Packit 4a16fb
			   snd_config_t *root, snd_config_t *slave_conf,
Packit 4a16fb
			   snd_pcm_stream_t stream, int mode)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext;
Packit 4a16fb
	int err;
Packit 4a16fb
	snd_pcm_t *spcm, *pcm;
Packit 4a16fb
	snd_config_t *sconf;
Packit 4a16fb
Packit 4a16fb
	assert(root);
Packit 4a16fb
	assert(extplug && extplug->callback);
Packit 4a16fb
	assert(extplug->callback->transfer);
Packit 4a16fb
	assert(slave_conf);
Packit 4a16fb
Packit 4a16fb
	/* We support 1.0.0 to current */
Packit 4a16fb
	if (extplug->version < 0x010000 ||
Packit 4a16fb
	    extplug->version > SND_PCM_EXTPLUG_VERSION) {
Packit 4a16fb
		SNDERR("extplug: Plugin version mismatch: 0x%x\n",
Packit 4a16fb
		       extplug->version);
Packit 4a16fb
		return -ENXIO;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL);
Packit 4a16fb
	snd_config_delete(sconf);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
Packit 4a16fb
	ext = calloc(1, sizeof(*ext));
Packit 4a16fb
	if (! ext)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	ext->data = extplug;
Packit 4a16fb
	extplug->stream = stream;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_plugin_init(&ext->plug);
Packit 4a16fb
	ext->plug.read = snd_pcm_extplug_read_areas;
Packit 4a16fb
	ext->plug.write = snd_pcm_extplug_write_areas;
Packit 4a16fb
	ext->plug.undo_read = snd_pcm_plugin_undo_read_generic;
Packit 4a16fb
	ext->plug.undo_write = snd_pcm_plugin_undo_write_generic;
Packit 4a16fb
	ext->plug.gen.slave = spcm;
Packit 4a16fb
	ext->plug.gen.close_slave = 1;
Packit 4a16fb
	if (extplug->version >= 0x010001 && extplug->callback->init)
Packit 4a16fb
		ext->plug.init = snd_pcm_extplug_init;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_EXTPLUG, name, stream, mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(ext);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	extplug->pcm = pcm;
Packit 4a16fb
	pcm->ops = &snd_pcm_extplug_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_plugin_fast_ops;
Packit 4a16fb
	pcm->private_data = ext;
Packit 4a16fb
	pcm->poll_fd = spcm->poll_fd;
Packit 4a16fb
	pcm->poll_events = spcm->poll_events;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0);
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Delete the extplug instance
Packit 4a16fb
 * \param extplug the extplug handle to delete
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * The destructor of extplug instance.
Packit 4a16fb
 * Closes the PCM and deletes the associated resources.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_delete(snd_pcm_extplug_t *extplug)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_close(extplug->pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Reset extplug parameters
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 *
Packit 4a16fb
 * Resets the all parameters for the given extplug handle.
Packit 4a16fb
 */
Packit 4a16fb
void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *extplug)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
	clear_ext_params(ext);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set slave parameter as the list
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 * \param type parameter type
Packit 4a16fb
 * \param num_list number of available values
Packit 4a16fb
 * \param list the list of available values
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Sets the slave parameter as the list.
Packit 4a16fb
 * The available values of the given parameter type of the slave PCM is restricted
Packit 4a16fb
 * to the ones of the given list.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_ext_parm_set_list(&ext->sparams[type], num_list, list);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set slave parameter as the min/max values
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 * \param type parameter type
Packit 4a16fb
 * \param min the minimum value
Packit 4a16fb
 * \param max the maximum value
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Sets the slave parameter as the min/max values.
Packit 4a16fb
 * The available values of the given parameter type of the slave PCM is restricted
Packit 4a16fb
 * between the given minimum and maximum values.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	if (is_mask_type(type)) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_ext_parm_set_minmax(&ext->sparams[type], min, max);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set master parameter as the list
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 * \param type parameter type
Packit 4a16fb
 * \param num_list number of available values
Packit 4a16fb
 * \param list the list of available values
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Sets the master parameter as the list.
Packit 4a16fb
 * The available values of the given parameter type of this PCM (as input) is restricted
Packit 4a16fb
 * to the ones of the given list.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_ext_parm_set_list(&ext->params[type], num_list, list);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set master parameter as the min/max values
Packit 4a16fb
 * \param extplug the extplug handle
Packit 4a16fb
 * \param type parameter type
Packit 4a16fb
 * \param min the minimum value
Packit 4a16fb
 * \param max the maximum value
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Sets the master parameter as the min/max values.
Packit 4a16fb
 * The available values of the given parameter type of this PCM (as input) is restricted
Packit 4a16fb
 * between the given minimum and maximum values.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	if (is_mask_type(type)) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_ext_parm_set_minmax(&ext->params[type], min, max);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * @brief Keep the client and slave format/channels the same if requested. This
Packit 4a16fb
 * is for example useful if this extplug does not support any channel
Packit 4a16fb
 * conversion.
Packit 4a16fb
 * @param extplug the extplug handle
Packit 4a16fb
 * @param type parameter type
Packit 4a16fb
 * @param keep_link if 1 the parameter identified by type will be kept the same
Packit 4a16fb
 * for the client and slave PCM of this extplug
Packit 4a16fb
 * @return 0 if successful, or a negative error code
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_extplug_set_param_link(snd_pcm_extplug_t *extplug, int type,
Packit 4a16fb
				   int keep_link)
Packit 4a16fb
{
Packit 4a16fb
	extplug_priv_t *ext = extplug->pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("EXTPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	ext->params[type].keep_link = keep_link ? 1 : 0;
Packit 4a16fb
	ext->sparams[type].keep_link = keep_link ? 1 : 0;
Packit 4a16fb
	return 0;
Packit 4a16fb
}