Blame src/pcm/pcm_ioplug.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_ioplug.c
Packit 4a16fb
 * \ingroup Plugin_SDK
Packit 4a16fb
 * \brief I/O Plugin SDK
Packit 4a16fb
 * \author Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 * \date 2005
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - External I/O 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_ioplug.h"
Packit 4a16fb
#include "pcm_ext_parm.h"
Packit 4a16fb
#include "pcm_generic.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_ioplug = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
Packit 4a16fb
/* hw_params */
Packit 4a16fb
typedef struct snd_pcm_ioplug_priv {
Packit 4a16fb
	snd_pcm_ioplug_t *data;
Packit 4a16fb
	struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS];
Packit 4a16fb
	snd_pcm_uframes_t last_hw;
Packit 4a16fb
	snd_pcm_uframes_t avail_max;
Packit 4a16fb
	snd_htimestamp_t trigger_tstamp;
Packit 4a16fb
} ioplug_priv_t;
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_drop(snd_pcm_t *pcm);
Packit 4a16fb
static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm);
Packit 4a16fb
static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
Packit 4a16fb
static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
Packit 4a16fb
Packit 4a16fb
/* update the hw pointer */
Packit 4a16fb
/* called in lock */
Packit 4a16fb
static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t hw;
Packit 4a16fb
Packit 4a16fb
	hw = io->data->callback->pointer(io->data);
Packit 4a16fb
	if (hw >= 0) {
Packit 4a16fb
		snd_pcm_uframes_t delta;
Packit 4a16fb
		snd_pcm_uframes_t avail;
Packit 4a16fb
Packit 4a16fb
		if ((snd_pcm_uframes_t)hw >= io->last_hw)
Packit 4a16fb
			delta = hw - io->last_hw;
Packit 4a16fb
		else {
Packit 4a16fb
			const snd_pcm_uframes_t wrap_point =
Packit 4a16fb
				(io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ?
Packit 4a16fb
					pcm->boundary : pcm->buffer_size;
Packit 4a16fb
			delta = wrap_point + hw - io->last_hw;
Packit 4a16fb
		}
Packit 4a16fb
		snd_pcm_mmap_hw_forward(io->data->pcm, delta);
Packit 4a16fb
		/* stop the stream if all samples are drained */
Packit 4a16fb
		if (io->data->state == SND_PCM_STATE_DRAINING) {
Packit 4a16fb
			avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
			if (avail >= pcm->buffer_size)
Packit 4a16fb
				snd_pcm_ioplug_drop(pcm);
Packit 4a16fb
		}
Packit 4a16fb
		io->last_hw = (snd_pcm_uframes_t)hw;
Packit 4a16fb
	} else {
Packit 4a16fb
		if (io->data->state == SND_PCM_STATE_DRAINING)
Packit 4a16fb
			snd_pcm_ioplug_drop(pcm);
Packit 4a16fb
		else
Packit 4a16fb
			io->data->state = SNDRV_PCM_STATE_XRUN;
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	memset(info, 0, sizeof(*info));
Packit 4a16fb
	info->stream = pcm->stream;
Packit 4a16fb
	info->card = -1;
Packit 4a16fb
	if (pcm->name) {
Packit 4a16fb
		snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id));
Packit 4a16fb
		snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name));
Packit 4a16fb
		snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname));
Packit 4a16fb
	}
Packit 4a16fb
	info->subdevices_count = 1;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_channel_info_shm(pcm, info, -1);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	memset(status, 0, sizeof(*status));
Packit 4a16fb
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit 4a16fb
	status->state = io->data->state;
Packit 4a16fb
	status->trigger_tstamp = io->trigger_tstamp;
Packit 4a16fb
	status->avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
	status->avail_max = io->avail_max;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	return io->data->state;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->version >= 0x010001 &&
Packit 4a16fb
	    io->data->callback->delay)
Packit 4a16fb
		return io->data->callback->delay(io->data, delayp);
Packit 4a16fb
	else {
Packit 4a16fb
		snd_pcm_ioplug_hw_ptr_update(pcm);
Packit 4a16fb
		*delayp = snd_pcm_mmap_hw_avail(pcm);
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	io->data->appl_ptr = 0;
Packit 4a16fb
	io->data->hw_ptr = 0;
Packit 4a16fb
	io->last_hw = 0;
Packit 4a16fb
	io->avail_max = 0;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_ioplug_reset(pcm);
Packit 4a16fb
	if (io->data->callback->prepare) {
Packit 4a16fb
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit 4a16fb
		err = io->data->callback->prepare(io->data);
Packit 4a16fb
		snd_pcm_lock(pcm);
Packit 4a16fb
	}
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
Packit 4a16fb
	io->data->state = SND_PCM_STATE_PREPARED;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit 4a16fb
	[SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/* x = a * b */
Packit 4a16fb
static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
Packit 4a16fb
{
Packit 4a16fb
	snd_interval_t t;
Packit 4a16fb
Packit 4a16fb
	snd_interval_mul(hw_param_interval(params, a),
Packit 4a16fb
			 hw_param_interval(params, b), &t);
Packit 4a16fb
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* x = a / b */
Packit 4a16fb
static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
Packit 4a16fb
{
Packit 4a16fb
	snd_interval_t t;
Packit 4a16fb
Packit 4a16fb
	snd_interval_div(hw_param_interval(params, a),
Packit 4a16fb
			 hw_param_interval(params, b), &t);
Packit 4a16fb
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* x = a * b / k */
Packit 4a16fb
static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
Packit 4a16fb
{
Packit 4a16fb
	snd_interval_t t;
Packit 4a16fb
Packit 4a16fb
	snd_interval_muldivk(hw_param_interval(params, a),
Packit 4a16fb
			     hw_param_interval(params, b), k, &t);
Packit 4a16fb
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* x = a * k / b */
Packit 4a16fb
static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
Packit 4a16fb
{
Packit 4a16fb
	snd_interval_t t;
Packit 4a16fb
Packit 4a16fb
	snd_interval_mulkdiv(hw_param_interval(params, a), k,
Packit 4a16fb
			     hw_param_interval(params, b), &t);
Packit 4a16fb
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
#if 0
Packit 4a16fb
static void dump_parm(snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_output_t *log;
Packit 4a16fb
	snd_output_stdio_attach(&log, stderr, 0);
Packit 4a16fb
	snd_pcm_hw_params_dump(params, log);
Packit 4a16fb
	snd_output_close(log);
Packit 4a16fb
}
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
/* refine *_TIME and *_SIZE, then update *_BYTES */
Packit 4a16fb
static int refine_time_and_size(snd_pcm_hw_params_t *params,
Packit 4a16fb
				int time, int size, int bytes)
Packit 4a16fb
{
Packit 4a16fb
	int err, change1 = 0;
Packit 4a16fb
Packit 4a16fb
	/* size = time * rate / 1000000 */
Packit 4a16fb
	err = rule_muldivk(params, size, time,
Packit 4a16fb
			   SND_PCM_HW_PARAM_RATE, 1000000);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	change1 |= err;
Packit 4a16fb
Packit 4a16fb
	/* bytes = size * framebits / 8 */
Packit 4a16fb
	err = rule_muldivk(params, bytes, size,
Packit 4a16fb
			   SND_PCM_HW_PARAM_FRAME_BITS, 8);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	change1 |= err;
Packit 4a16fb
	return change1;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* refine *_TIME and *_SIZE from *_BYTES */
Packit 4a16fb
static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
Packit 4a16fb
				     int time, int size, int bytes)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	/* size = bytes * 8 / framebits */
Packit 4a16fb
	err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	/* time = size * 1000000 / rate */
Packit 4a16fb
	err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	int change = 0, change1, change2, err;
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	struct snd_ext_parm *p;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	/* access, format */
Packit 4a16fb
	for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
Packit 4a16fb
		err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
Packit 4a16fb
					       io->params, i);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change |= err;
Packit 4a16fb
	}
Packit 4a16fb
	/* channels, rate */
Packit 4a16fb
	for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
Packit 4a16fb
		err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
Packit 4a16fb
						   io->params, i);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change |= err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
Packit 4a16fb
			     (1 << SND_PCM_HW_PARAM_FORMAT) |
Packit 4a16fb
			     (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
Packit 4a16fb
			     (1 << SND_PCM_HW_PARAM_CHANNELS) |
Packit 4a16fb
			     (1 << SND_PCM_HW_PARAM_RATE))) {
Packit 4a16fb
		err = snd_pcm_hw_refine_soft(pcm, params);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change |= err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit 4a16fb
				       SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit 4a16fb
				       SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit 4a16fb
	if (change1 < 0)
Packit 4a16fb
		return change1;
Packit 4a16fb
	err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
Packit 4a16fb
					   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	change1 |= err;
Packit 4a16fb
	if (change1) {
Packit 4a16fb
		change |= change1;
Packit 4a16fb
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit 4a16fb
						SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit 4a16fb
						SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
Packit 4a16fb
				       SND_PCM_HW_PARAM_BUFFER_SIZE,
Packit 4a16fb
				       SND_PCM_HW_PARAM_BUFFER_BYTES);
Packit 4a16fb
	if (change1 < 0)
Packit 4a16fb
		return change1;
Packit 4a16fb
	change |= change1;
Packit 4a16fb
Packit 4a16fb
	do {
Packit 4a16fb
		change2 = 0;
Packit 4a16fb
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
Packit 4a16fb
						   io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change2 |= err;
Packit 4a16fb
		/* periods = buffer_bytes / period_bytes */
Packit 4a16fb
		err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
Packit 4a16fb
			       SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit 4a16fb
			       SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change2 |= err;
Packit 4a16fb
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
Packit 4a16fb
						   io->params, SND_PCM_IOPLUG_HW_PERIODS);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change2 |= err;
Packit 4a16fb
		/* buffer_bytes = periods * period_bytes */
Packit 4a16fb
		err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit 4a16fb
			       SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit 4a16fb
			       SND_PCM_HW_PARAM_PERIODS);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		change2 |= err;
Packit 4a16fb
		change1 |= change2;
Packit 4a16fb
	} while (change2);
Packit 4a16fb
	change |= change1;
Packit 4a16fb
Packit 4a16fb
	if (change1) {
Packit 4a16fb
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
Packit 4a16fb
						SND_PCM_HW_PARAM_BUFFER_SIZE,
Packit 4a16fb
						SND_PCM_HW_PARAM_BUFFER_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* period_bytes = buffer_bytes / periods */
Packit 4a16fb
	err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit 4a16fb
		       SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit 4a16fb
		       SND_PCM_HW_PARAM_PERIODS);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	if (err) {
Packit 4a16fb
		/* update period_size and period_time */
Packit 4a16fb
		change |= err;
Packit 4a16fb
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
Packit 4a16fb
						   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit 4a16fb
						SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit 4a16fb
						SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	params->info = SND_PCM_INFO_BLOCK_TRANSFER;
Packit 4a16fb
	p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
Packit 4a16fb
	if (p->active) {
Packit 4a16fb
		for (i = 0; i < p->num_list; i++)
Packit 4a16fb
			switch (p->list[i]) {
Packit 4a16fb
			case SND_PCM_ACCESS_MMAP_INTERLEAVED:
Packit 4a16fb
			case SND_PCM_ACCESS_RW_INTERLEAVED:
Packit 4a16fb
				params->info |= SND_PCM_INFO_INTERLEAVED;
Packit 4a16fb
				break;
Packit 4a16fb
			case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
Packit 4a16fb
			case SND_PCM_ACCESS_RW_NONINTERLEAVED:
Packit 4a16fb
				params->info |= SND_PCM_INFO_NONINTERLEAVED;
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
	}
Packit 4a16fb
	if (io->data->callback->pause)
Packit 4a16fb
		params->info |= SND_PCM_INFO_PAUSE;
Packit 4a16fb
	if (io->data->callback->resume)
Packit 4a16fb
		params->info |= SND_PCM_INFO_RESUME;
Packit 4a16fb
Packit 4a16fb
#if 0
Packit 4a16fb
	fprintf(stderr, "XXX\n");
Packit 4a16fb
	dump_parm(params);
Packit 4a16fb
#endif
Packit 4a16fb
	return change;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
Packit 4a16fb
	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
Packit 4a16fb
	if (io->data->callback->hw_params) {
Packit 4a16fb
		err = io->data->callback->hw_params(io->data, params);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
Packit 4a16fb
		INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->hw_free)
Packit 4a16fb
		return io->data->callback->hw_free(io->data);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (!io->data->callback->sw_params)
Packit 4a16fb
		return 0;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit 4a16fb
	err = io->data->callback->sw_params(io->data, params);
Packit 4a16fb
	snd_pcm_lock(pcm);
Packit 4a16fb
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
	
Packit 4a16fb
	if (io->data->state != SND_PCM_STATE_PREPARED)
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
Packit 4a16fb
	err = io->data->callback->start(io->data);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
Packit 4a16fb
	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
Packit 4a16fb
	io->data->state = SND_PCM_STATE_RUNNING;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->state == SND_PCM_STATE_OPEN)
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
Packit 4a16fb
	io->data->callback->stop(io->data);
Packit 4a16fb
Packit 4a16fb
	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
Packit 4a16fb
	io->data->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int ioplug_drain_via_poll(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	while (io->data->state == SND_PCM_STATE_DRAINING) {
Packit 4a16fb
		snd_pcm_ioplug_hw_ptr_update(pcm);
Packit 4a16fb
		if (io->data->state != SND_PCM_STATE_DRAINING)
Packit 4a16fb
			break;
Packit 4a16fb
		/* in non-blocking mode, let application to poll() by itself */
Packit 4a16fb
		if (io->data->nonblock)
Packit 4a16fb
			return -EAGAIN;
Packit 4a16fb
		if (snd_pcm_wait_nocheck(pcm, -1) < 0)
Packit 4a16fb
			break;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0; /* force to drop at error */
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* need own locking */
Packit 4a16fb
static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_lock(pcm);
Packit 4a16fb
	switch (io->data->state) {
Packit 4a16fb
	case SND_PCM_STATE_OPEN:
Packit 4a16fb
	case SND_PCM_STATE_DISCONNECTED:
Packit 4a16fb
	case SND_PCM_STATE_SUSPENDED:
Packit 4a16fb
		snd_pcm_unlock(pcm);
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
			if (!io->data->callback->drain) {
Packit 4a16fb
				err = snd_pcm_ioplug_start(pcm);
Packit 4a16fb
				if (err < 0)
Packit 4a16fb
					goto unlock;
Packit 4a16fb
			}
Packit 4a16fb
			io->data->state = SND_PCM_STATE_DRAINING;
Packit 4a16fb
		}
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		io->data->state = SND_PCM_STATE_DRAINING;
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (io->data->state == SND_PCM_STATE_DRAINING) {
Packit 4a16fb
		if (io->data->callback->drain) {
Packit 4a16fb
			snd_pcm_unlock(pcm); /* let plugin own locking */
Packit 4a16fb
			err = io->data->callback->drain(io->data);
Packit 4a16fb
			snd_pcm_lock(pcm);
Packit 4a16fb
		} else {
Packit 4a16fb
			err = ioplug_drain_via_poll(pcm);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
 unlock:
Packit 4a16fb
	if (!err && io->data->state != SND_PCM_STATE_SETUP)
Packit 4a16fb
		snd_pcm_ioplug_drop(pcm);
Packit 4a16fb
	snd_pcm_unlock(pcm);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	static const snd_pcm_state_t states[2] = {
Packit 4a16fb
		SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
Packit 4a16fb
	};
Packit 4a16fb
	int prev, err;
Packit 4a16fb
Packit 4a16fb
	prev = !enable;
Packit 4a16fb
	enable = !prev;
Packit 4a16fb
	if (io->data->state != states[prev])
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	if (io->data->callback->pause) {
Packit 4a16fb
		err = io->data->callback->pause(io->data, enable);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	io->data->state = states[enable];
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_mmap_hw_rewindable(pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_mmap_appl_backward(pcm, frames);
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_mmap_avail(pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_mmap_appl_forward(pcm, frames);
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* need own locking */
Packit 4a16fb
static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->resume)
Packit 4a16fb
		io->data->callback->resume(io->data);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* called in lock */
Packit 4a16fb
static snd_pcm_sframes_t ioplug_priv_transfer_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
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t result;
Packit 4a16fb
		
Packit 4a16fb
	if (! size)
Packit 4a16fb
		return 0;
Packit 4a16fb
	if (io->data->callback->transfer)
Packit 4a16fb
		result = io->data->callback->transfer(io->data, areas, offset, size);
Packit 4a16fb
	else
Packit 4a16fb
		result = size;
Packit 4a16fb
	if (result > 0)
Packit 4a16fb
		snd_pcm_mmap_appl_forward(pcm, result);
Packit 4a16fb
	return result;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	if (pcm->mmap_rw)
Packit 4a16fb
		return snd_pcm_mmap_writei(pcm, buffer, size);
Packit 4a16fb
	else {
Packit 4a16fb
		snd_pcm_channel_area_t areas[pcm->channels];
Packit 4a16fb
		snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
Packit 4a16fb
		return snd_pcm_write_areas(pcm, areas, 0, size, 
Packit 4a16fb
					   ioplug_priv_transfer_areas);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	if (pcm->mmap_rw)
Packit 4a16fb
		return snd_pcm_mmap_writen(pcm, bufs, size);
Packit 4a16fb
	else {
Packit 4a16fb
		snd_pcm_channel_area_t areas[pcm->channels];
Packit 4a16fb
		snd_pcm_areas_from_bufs(pcm, areas, bufs);
Packit 4a16fb
		return snd_pcm_write_areas(pcm, areas, 0, size,
Packit 4a16fb
					   ioplug_priv_transfer_areas);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	if (pcm->mmap_rw)
Packit 4a16fb
		return snd_pcm_mmap_readi(pcm, buffer, size);
Packit 4a16fb
	else {
Packit 4a16fb
		snd_pcm_channel_area_t areas[pcm->channels];
Packit 4a16fb
		snd_pcm_areas_from_buf(pcm, areas, buffer);
Packit 4a16fb
		return snd_pcm_read_areas(pcm, areas, 0, size,
Packit 4a16fb
					  ioplug_priv_transfer_areas);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	if (pcm->mmap_rw)
Packit 4a16fb
		return snd_pcm_mmap_readn(pcm, bufs, size);
Packit 4a16fb
	else {
Packit 4a16fb
		snd_pcm_channel_area_t areas[pcm->channels];
Packit 4a16fb
		snd_pcm_areas_from_bufs(pcm, areas, bufs);
Packit 4a16fb
		return snd_pcm_read_areas(pcm, areas, 0, size,
Packit 4a16fb
					  ioplug_priv_transfer_areas);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
Packit 4a16fb
						    snd_pcm_uframes_t offset,
Packit 4a16fb
						    snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
Packit 4a16fb
	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
Packit 4a16fb
	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
Packit 4a16fb
		const snd_pcm_channel_area_t *areas;
Packit 4a16fb
		snd_pcm_uframes_t ofs, frames = size;
Packit 4a16fb
Packit 4a16fb
		__snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames);
Packit 4a16fb
		if (ofs != offset)
Packit 4a16fb
			return -EIO;
Packit 4a16fb
		return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	snd_pcm_mmap_appl_forward(pcm, size);
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	snd_pcm_uframes_t avail;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit 4a16fb
	if (io->data->state == SND_PCM_STATE_XRUN)
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
Packit 4a16fb
	avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
Packit 4a16fb
	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
Packit 4a16fb
	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
Packit 4a16fb
		if (io->data->callback->transfer) {
Packit 4a16fb
			const snd_pcm_channel_area_t *areas;
Packit 4a16fb
			snd_pcm_uframes_t offset, size = UINT_MAX;
Packit 4a16fb
			snd_pcm_sframes_t result;
Packit 4a16fb
Packit 4a16fb
			__snd_pcm_mmap_begin(pcm, &areas, &offset, &size);
Packit 4a16fb
			result = io->data->callback->transfer(io->data, areas, offset, size);
Packit 4a16fb
			if (result < 0)
Packit 4a16fb
				return result;
Packit 4a16fb
Packit 4a16fb
			/* If the available data doesn't fit in the
Packit 4a16fb
			   contiguous area at the end of the mmap we
Packit 4a16fb
			   must transfer the remaining data to the
Packit 4a16fb
			   beginning of the mmap. */
Packit 4a16fb
			if (size < avail) {
Packit 4a16fb
				result = io->data->callback->transfer(io->data, areas,
Packit 4a16fb
								      0, avail - size);
Packit 4a16fb
				if (result < 0)
Packit 4a16fb
					return result;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (avail > io->avail_max)
Packit 4a16fb
		io->avail_max = avail;
Packit 4a16fb
	return (snd_pcm_sframes_t)avail;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	io->data->nonblock = nonblock;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err = 1;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->poll_descriptors_count) {
Packit 4a16fb
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit 4a16fb
		err = io->data->callback->poll_descriptors_count(io->data);
Packit 4a16fb
		snd_pcm_lock(pcm);
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->poll_descriptors) {
Packit 4a16fb
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit 4a16fb
		err = io->data->callback->poll_descriptors(io->data, pfds, space);
Packit 4a16fb
		snd_pcm_lock(pcm);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	if (pcm->poll_fd < 0)
Packit 4a16fb
		return -EIO;
Packit 4a16fb
	if (space >= 1 && pfds) {
Packit 4a16fb
		pfds->fd = pcm->poll_fd;
Packit 4a16fb
		pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
Packit 4a16fb
	} else {
Packit 4a16fb
		return 0;
Packit 4a16fb
	}
Packit 4a16fb
	return 1;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->poll_revents) {
Packit 4a16fb
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit 4a16fb
		err = io->data->callback->poll_revents(io->data, pfds, nfds, revents);
Packit 4a16fb
		snd_pcm_lock(pcm);
Packit 4a16fb
	} else {
Packit 4a16fb
		*revents = pfds->revents;
Packit 4a16fb
		err = 0;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
Packit 4a16fb
				int sig ATTRIBUTE_UNUSED,
Packit 4a16fb
				pid_t pid ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENOSYS;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->version >= 0x010002 &&
Packit 4a16fb
	    io->data->callback->query_chmaps)
Packit 4a16fb
		return io->data->callback->query_chmaps(io->data);
Packit 4a16fb
	return NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->version >= 0x010002 &&
Packit 4a16fb
	    io->data->callback->get_chmap)
Packit 4a16fb
		return io->data->callback->get_chmap(io->data);
Packit 4a16fb
	return NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->version >= 0x010002 &&
Packit 4a16fb
	    io->data->callback->set_chmap)
Packit 4a16fb
		return io->data->callback->set_chmap(io->data, map);
Packit 4a16fb
	return -ENXIO;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	if (io->data->callback->dump)
Packit 4a16fb
		io->data->callback->dump(io->data, out);
Packit 4a16fb
	else {
Packit 4a16fb
		if (io->data->name)
Packit 4a16fb
			snd_output_printf(out, "%s\n", io->data->name);
Packit 4a16fb
		else
Packit 4a16fb
			snd_output_printf(out, "IO-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
}
Packit 4a16fb
Packit 4a16fb
static void clear_io_params(ioplug_priv_t *io)
Packit 4a16fb
{
Packit 4a16fb
	int i;
Packit 4a16fb
	for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
Packit 4a16fb
		snd_ext_parm_clear(&io->params[i]);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	clear_io_params(io);
Packit 4a16fb
	if (io->data->callback->close)
Packit 4a16fb
		io->data->callback->close(io->data);
Packit 4a16fb
	free(io);
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
Packit 4a16fb
	.close = snd_pcm_ioplug_close,
Packit 4a16fb
	.nonblock = snd_pcm_ioplug_nonblock,
Packit 4a16fb
	.async = snd_pcm_ioplug_async,
Packit 4a16fb
	.info = snd_pcm_ioplug_info,
Packit 4a16fb
	.hw_refine = snd_pcm_ioplug_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_ioplug_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_ioplug_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_ioplug_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_ioplug_channel_info,
Packit 4a16fb
	.dump = snd_pcm_ioplug_dump,
Packit 4a16fb
	.mmap = snd_pcm_ioplug_mmap,
Packit 4a16fb
	.munmap = snd_pcm_ioplug_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_ioplug_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_ioplug_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_ioplug_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
Packit 4a16fb
	.status = snd_pcm_ioplug_status,
Packit 4a16fb
	.prepare = snd_pcm_ioplug_prepare,
Packit 4a16fb
	.reset = snd_pcm_ioplug_reset,
Packit 4a16fb
	.start = snd_pcm_ioplug_start,
Packit 4a16fb
	.drop = snd_pcm_ioplug_drop,
Packit 4a16fb
	.drain = snd_pcm_ioplug_drain,
Packit 4a16fb
	.pause = snd_pcm_ioplug_pause,
Packit 4a16fb
	.state = snd_pcm_ioplug_state,
Packit 4a16fb
	.hwsync = snd_pcm_ioplug_hwsync,
Packit 4a16fb
	.delay = snd_pcm_ioplug_delay,
Packit 4a16fb
	.resume = snd_pcm_ioplug_resume,
Packit 4a16fb
	.link = NULL,
Packit 4a16fb
	.link_slaves = NULL,
Packit 4a16fb
	.unlink = NULL,
Packit 4a16fb
	.rewindable = snd_pcm_ioplug_rewindable,
Packit 4a16fb
	.rewind = snd_pcm_ioplug_rewind,
Packit 4a16fb
	.forwardable = snd_pcm_ioplug_forwardable,
Packit 4a16fb
	.forward = snd_pcm_ioplug_forward,
Packit 4a16fb
	.writei = snd_pcm_ioplug_writei,
Packit 4a16fb
	.writen = snd_pcm_ioplug_writen,
Packit 4a16fb
	.readi = snd_pcm_ioplug_readi,
Packit 4a16fb
	.readn = snd_pcm_ioplug_readn,
Packit 4a16fb
	.avail_update = snd_pcm_ioplug_avail_update,
Packit 4a16fb
	.mmap_commit = snd_pcm_ioplug_mmap_commit,
Packit 4a16fb
	.htimestamp = snd_pcm_generic_real_htimestamp,
Packit 4a16fb
	.poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
Packit 4a16fb
	.poll_descriptors = snd_pcm_ioplug_poll_descriptors,
Packit 4a16fb
	.poll_revents = snd_pcm_ioplug_poll_revents,
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_ioplug External Plugin: I/O Plugin
Packit 4a16fb
Packit 4a16fb
The I/O-type plugin is a PCM plugin to work as the input or output terminal point,
Packit 4a16fb
i.e. as a user-space PCM driver.
Packit 4a16fb
Packit 4a16fb
The new plugin is created via #snd_pcm_ioplug_create() function.
Packit 4a16fb
The first argument is a pointer of the pluging information.  Some of
Packit 4a16fb
this struct must be initialized in prior to call
Packit 4a16fb
#snd_pcm_ioplug_create().  Then the function fills other fields in
Packit 4a16fb
return.  The rest arguments, name, stream and mode, are usually
Packit 4a16fb
identical with the values passed from the ALSA plugin constructor.
Packit 4a16fb
Packit 4a16fb
The following fields are mandatory: version, name, callback.
Packit 4a16fb
Otherfields are optional and should be initialized with zero.
Packit 4a16fb
Packit 4a16fb
The constant #SND_PCM_IOPLUG_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_ioplug_callback_t).
Packit 4a16fb
Packit 4a16fb
flags field specifies the optional bit-flags.  poll_fd and poll_events
Packit 4a16fb
specify the poll file descriptor and the corresponding poll events
Packit 4a16fb
(POLLIN, POLLOUT) for the plugin.  If the plugin requires multiple
Packit 4a16fb
poll descriptors or poll descriptor(s) dynamically varying, set
Packit 4a16fb
poll_descriptors and poll_descriptors_count callbacks to the callback
Packit 4a16fb
table.  Then the poll_fd and poll_events field are ignored.
Packit 4a16fb
Packit 4a16fb
mmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
Packit 4a16fb
When this value is set to 1, the plugin creates always a local buffer
Packit 4a16fb
and performs read/write calls using this buffer as if it's mmapped.
Packit 4a16fb
The address of local buffer can be obtained via
Packit 4a16fb
#snd_pcm_ioplug_mmap_areas() function.
Packit 4a16fb
When poll_fd, poll_events and mmap_rw fields are changed after
Packit 4a16fb
#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
Packit 4a16fb
reflect the changes.
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_ioplug_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_ioplug_callback_t define the real
Packit 4a16fb
behavior of the driver.
Packit 4a16fb
At least, start, stop and pointer callbacks must be given.  Other
Packit 4a16fb
callbacks are optional.  The start and stop callbacks are called when
Packit 4a16fb
the PCM stream is started and stopped, repsectively.  The pointer
Packit 4a16fb
callback returns the current DMA position, which may be called at any
Packit 4a16fb
time.
Packit 4a16fb
Packit 4a16fb
The transfer callback is called when any data transfer happens.  It
Packit 4a16fb
receives the area array, offset and the size to transfer.  The area
Packit 4a16fb
array contains the array of snd_pcm_channel_area_t with the elements
Packit 4a16fb
of number of channels.
Packit 4a16fb
Packit 4a16fb
When the PCM is closed, close callback is called.  If the driver
Packit 4a16fb
allocates any internal buffers, they should be released in this
Packit 4a16fb
callback.  The hw_params and hw_free callbacks are called when
Packit 4a16fb
hw_params are set and reset, respectively.  Note that they may be
Packit 4a16fb
called multiple times according to the application.  Similarly,
Packit 4a16fb
sw_params callback is called when sw_params is set or changed.
Packit 4a16fb
Packit 4a16fb
The prepare, drain, pause and resume callbacks are called when
Packit 4a16fb
#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
Packit 4a16fb
#snd_pcm_resume() are called.  The poll_descriptors_count and
Packit 4a16fb
poll_descriptors callbacks are used to return the multiple or dynamic
Packit 4a16fb
poll descriptors as mentioned above.  The poll_revents callback is
Packit 4a16fb
used to modify poll events.  If the driver needs to mangle the native
Packit 4a16fb
poll events to proper poll events for PCM, you can do it in this
Packit 4a16fb
callback.
Packit 4a16fb
Packit 4a16fb
Finally, the dump callback is used to print the status of the plugin.
Packit 4a16fb
Packit 4a16fb
Note that some callbacks (start, stop, pointer, transfer and pause)
Packit 4a16fb
may be called inside the internal pthread mutex, and they shouldn't
Packit 4a16fb
call the PCM functions again unnecessarily from the callback itself;
Packit 4a16fb
otherwise it may lead to a deadlock.
Packit 4a16fb
Packit 4a16fb
The hw_params constraints can be defined via either
Packit 4a16fb
#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
Packit 4a16fb
functions after calling #snd_pcm_ioplug_create().
Packit 4a16fb
The former defines the minimal and maximal acceptable values for the
Packit 4a16fb
given hw_params parameter (SND_PCM_IOPLUG_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
Packit 4a16fb
To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
Packit 4a16fb
Packit 4a16fb
*/
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Create an ioplug instance
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \param name name of PCM
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 ioplug instance.
Packit 4a16fb
 *
Packit 4a16fb
 * The callback is the mandatory field of ioplug handle.  At least, start, stop and
Packit 4a16fb
 * pointer callbacks must be set before calling this function.
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
Packit 4a16fb
			  snd_pcm_stream_t stream, int mode)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io;
Packit 4a16fb
	int err;
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
Packit 4a16fb
	assert(ioplug && ioplug->callback);
Packit 4a16fb
	assert(ioplug->callback->start &&
Packit 4a16fb
	       ioplug->callback->stop &&
Packit 4a16fb
	       ioplug->callback->pointer);
Packit 4a16fb
Packit 4a16fb
	/* We support 1.0.0 to current */
Packit 4a16fb
	if (ioplug->version < 0x010000 ||
Packit 4a16fb
	    ioplug->version > SND_PCM_IOPLUG_VERSION) {
Packit 4a16fb
		SNDERR("ioplug: Plugin version mismatch: 0x%x\n",
Packit 4a16fb
		       ioplug->version);
Packit 4a16fb
		return -ENXIO;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	io = calloc(1, sizeof(*io));
Packit 4a16fb
	if (! io)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	io->data = ioplug;
Packit 4a16fb
	ioplug->state = SND_PCM_STATE_OPEN;
Packit 4a16fb
	ioplug->stream = stream;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(io);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	ioplug->pcm = pcm;
Packit 4a16fb
	pcm->ops = &snd_pcm_ioplug_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
Packit 4a16fb
	pcm->private_data = io;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
Packit 4a16fb
Packit 4a16fb
	snd_pcm_ioplug_reinit_status(ioplug);
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Delete the ioplug instance
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_close(ioplug->pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Reset ioplug parameters
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 *
Packit 4a16fb
 * Resets the all parameters for the given ioplug handle.
Packit 4a16fb
 */
Packit 4a16fb
void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit 4a16fb
	clear_io_params(io);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set parameter as the list
Packit 4a16fb
 * \param ioplug the ioplug 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 parameter as the list.
Packit 4a16fb
 * The available values of the given parameter type is restricted to the ones of the given list.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	if (type == SND_PCM_IOPLUG_HW_PERIODS)
Packit 4a16fb
		io->params[type].integer = 1;
Packit 4a16fb
	return snd_ext_parm_set_list(&io->params[type], num_list, list);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Set parameter as the min/max values
Packit 4a16fb
 * \param ioplug the ioplug 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 parameter as the min/max values.
Packit 4a16fb
 * The available values of the given parameter type is restricted between the given
Packit 4a16fb
 * minimum and maximum values.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
Packit 4a16fb
{
Packit 4a16fb
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit 4a16fb
	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
Packit 4a16fb
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
Packit 4a16fb
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
	if (type == SND_PCM_IOPLUG_HW_PERIODS)
Packit 4a16fb
		io->params[type].integer = 1;
Packit 4a16fb
	return snd_ext_parm_set_minmax(&io->params[type], min, max);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Reinitialize the poll and mmap status
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \return 0 if successful, or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Reinitializes the poll and the mmap status of the PCM.
Packit 4a16fb
 * Call this function to propagate the status change in the ioplug instance to
Packit 4a16fb
 * its PCM internals.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
Packit 4a16fb
{
Packit 4a16fb
	ioplug->pcm->poll_fd = ioplug->poll_fd;
Packit 4a16fb
	ioplug->pcm->poll_events = ioplug->poll_events;
Packit 4a16fb
	if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
Packit 4a16fb
		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
Packit 4a16fb
	else
Packit 4a16fb
		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
Packit 4a16fb
	ioplug->pcm->mmap_rw = ioplug->mmap_rw;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Get mmap area of ioplug
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \return the mmap channel areas if available, or NULL
Packit 4a16fb
 *
Packit 4a16fb
 * Returns the mmap channel areas if available.  When mmap_rw field is not set,
Packit 4a16fb
 * this function always returns NULL.
Packit 4a16fb
 */
Packit 4a16fb
const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
Packit 4a16fb
{
Packit 4a16fb
	if (ioplug->mmap_rw)
Packit 4a16fb
		return snd_pcm_mmap_areas(ioplug->pcm);
Packit 4a16fb
	return NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Change the ioplug PCM status
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \param state the PCM status
Packit 4a16fb
 * \return zero if successful or a negative error code
Packit 4a16fb
 *
Packit 4a16fb
 * Changes the PCM status of the ioplug to the given value.
Packit 4a16fb
 * This function can be used for external plugins to notify the status
Packit 4a16fb
 * change, e.g. XRUN.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
Packit 4a16fb
{
Packit 4a16fb
	ioplug->state = state;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Get the available frames. This function can be used to calculate the
Packit 4a16fb
 * the available frames before calling #snd_pcm_avail_update()
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \param hw_ptr hardware pointer in frames
Packit 4a16fb
 * \param appl_ptr application pointer in frames
Packit 4a16fb
 * \return available frames for the application
Packit 4a16fb
 */
Packit 4a16fb
snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,
Packit 4a16fb
				       const snd_pcm_uframes_t hw_ptr,
Packit 4a16fb
				       const snd_pcm_uframes_t appl_ptr)
Packit 4a16fb
{
Packit 4a16fb
	return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Get the available frames. This function can be used to calculate the
Packit 4a16fb
 * the available frames before calling #snd_pcm_avail_update()
Packit 4a16fb
 * \param ioplug the ioplug handle
Packit 4a16fb
 * \param hw_ptr hardware pointer in frames
Packit 4a16fb
 * \param appl_ptr application pointer in frames
Packit 4a16fb
 * \return available frames for the hardware
Packit 4a16fb
 */
Packit 4a16fb
snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,
Packit 4a16fb
					  const snd_pcm_uframes_t hw_ptr,
Packit 4a16fb
					  const snd_pcm_uframes_t appl_ptr)
Packit 4a16fb
{
Packit 4a16fb
	/* available data/space which can be transferred by the user
Packit 4a16fb
	 * application
Packit 4a16fb
	 */
Packit 4a16fb
	const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug,
Packit 4a16fb
								  hw_ptr,
Packit 4a16fb
								  appl_ptr);
Packit 4a16fb
Packit 4a16fb
	if (user_avail > ioplug->pcm->buffer_size) {
Packit 4a16fb
		/* there was an Xrun */
Packit 4a16fb
		return 0;
Packit 4a16fb
	}
Packit 4a16fb
	/* available data/space which can be transferred by the DMA */
Packit 4a16fb
	return ioplug->pcm->buffer_size - user_avail;
Packit 4a16fb
}