Blame pulse/pcm_pulse.c

Packit 675970
/*-*- linux-c -*-*/
Packit 675970
Packit 675970
/*
Packit 675970
 * ALSA <-> PulseAudio PCM I/O plugin
Packit 675970
 *
Packit 675970
 * Copyright (c) 2006 by Pierre Ossman <ossman@cendio.se>
Packit 675970
 *
Packit 675970
 * This library is free software; you can redistribute it and/or modify
Packit 675970
 * it under the terms of the GNU Lesser General Public License as
Packit 675970
 * published by the Free Software Foundation; either version 2.1 of
Packit 675970
 * the License, or (at your option) any later version.
Packit 675970
 *
Packit 675970
 * This program is distributed in the hope that it will be useful,
Packit 675970
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 675970
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 675970
 * GNU Lesser General Public License for more details.
Packit 675970
 *
Packit 675970
 * You should have received a copy of the GNU Lesser General Public
Packit 675970
 * License along with this library; if not, write to the Free Software
Packit 675970
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 675970
 */
Packit 675970
Packit 675970
#include <stdio.h>
Packit 675970
#include <sys/poll.h>
Packit 675970
Packit 675970
#include <alsa/asoundlib.h>
Packit 675970
#include <alsa/pcm_external.h>
Packit 675970
Packit 675970
#include "pulse.h"
Packit 675970
Packit 675970
typedef struct snd_pcm_pulse {
Packit 675970
	snd_pcm_ioplug_t io;
Packit 675970
Packit 675970
	snd_pulse_t *p;
Packit 675970
Packit 675970
	char *device;
Packit 675970
Packit 675970
	/* Since ALSA expects a ring buffer we must do some voodoo. */
Packit 675970
	size_t last_size;
Packit 675970
	size_t ptr;
Packit 675970
	int underrun;
Packit 675970
	int handle_underrun;
Packit 675970
Packit 675970
	size_t offset;
Packit 675970
	int64_t written;
Packit 675970
Packit 675970
	pa_stream *stream;
Packit 675970
Packit 675970
	pa_sample_spec ss;
Packit 675970
	size_t frame_size;
Packit 675970
	pa_buffer_attr buffer_attr;
Packit 675970
} snd_pcm_pulse_t;
Packit 675970
Packit 675970
static int check_stream(snd_pcm_pulse_t *pcm)
Packit 675970
{
Packit 675970
	int err;
Packit 675970
	pa_stream_state_t state;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	err = pulse_check_connection(pcm->p);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	if (!pcm->stream)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	state = pa_stream_get_state(pcm->stream);
Packit 675970
	if (!PA_STREAM_IS_GOOD(state))
Packit 675970
		return -EIO;
Packit 675970
Packit 675970
	err = 0;
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int update_ptr(snd_pcm_pulse_t *pcm)
Packit 675970
{
Packit 675970
	size_t size;
Packit 675970
Packit 675970
	if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK)
Packit 675970
		size = pa_stream_writable_size(pcm->stream);
Packit 675970
	else
Packit 675970
		size = pa_stream_readable_size(pcm->stream);
Packit 675970
Packit 675970
	if (size == (size_t) -1)
Packit 675970
		return -EIO;
Packit 675970
Packit 675970
	if (pcm->io.stream == SND_PCM_STREAM_CAPTURE)
Packit 675970
		size -= pcm->offset;
Packit 675970
Packit 675970
	/* Prevent accidental overrun of the fake ringbuffer */
Packit 675970
	if (size > pcm->buffer_attr.tlength - pcm->frame_size)
Packit 675970
		size = pcm->buffer_attr.tlength - pcm->frame_size;
Packit 675970
Packit 675970
	if (size > pcm->last_size) {
Packit 675970
		pcm->ptr += size - pcm->last_size;
Packit 675970
		pcm->ptr %= pcm->buffer_attr.tlength;
Packit 675970
	}
Packit 675970
Packit 675970
	pcm->last_size = size;
Packit 675970
	return 0;
Packit 675970
  }
Packit 675970
Packit 675970
static int check_active(snd_pcm_pulse_t *pcm) {
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	/*
Packit 675970
	 * ALSA thinks in periods, not bytes, samples or frames.
Packit 675970
	 */
Packit 675970
Packit 675970
	if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK) {
Packit 675970
		size_t wsize;
Packit 675970
Packit 675970
		wsize = pa_stream_writable_size(pcm->stream);
Packit 675970
Packit 675970
		if (wsize == (size_t) -1)
Packit 675970
			return -EIO;
Packit 675970
Packit 675970
		return wsize >= pcm->buffer_attr.minreq;
Packit 675970
	} else {
Packit 675970
		size_t rsize;
Packit 675970
Packit 675970
		rsize = pa_stream_readable_size(pcm->stream);
Packit 675970
Packit 675970
		if (rsize == (size_t) -1)
Packit 675970
			return -EIO;
Packit 675970
Packit 675970
		return rsize >= pcm->buffer_attr.fragsize;
Packit 675970
	}
Packit 675970
}
Packit 675970
Packit 675970
static int update_active(snd_pcm_pulse_t *pcm) {
Packit 675970
	int ret;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	ret = check_stream(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	ret = check_active(pcm);
Packit 675970
Packit 675970
finish:
Packit 675970
Packit 675970
	if (ret != 0) /* On error signal the caller, too */
Packit 675970
		pulse_poll_activate(pcm->p);
Packit 675970
	else
Packit 675970
		pulse_poll_deactivate(pcm->p);
Packit 675970
Packit 675970
	return ret;
Packit 675970
}
Packit 675970
Packit 675970
static int wait_stream_state(snd_pcm_pulse_t *pcm, pa_stream_state_t target)
Packit 675970
{
Packit 675970
	pa_stream_state_t state;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	for (;;) {
Packit 675970
		int err;
Packit 675970
Packit 675970
		err = pulse_check_connection(pcm->p);
Packit 675970
		if (err < 0)
Packit 675970
			return err;
Packit 675970
Packit 675970
		if (!pcm->stream)
Packit 675970
			return -EBADFD;
Packit 675970
Packit 675970
		state = pa_stream_get_state(pcm->stream);
Packit 675970
		if (state == target)
Packit 675970
			break;
Packit 675970
Packit 675970
		if (!PA_STREAM_IS_GOOD(state))
Packit 675970
			return -EIO;
Packit 675970
Packit 675970
		pa_threaded_mainloop_wait(pcm->p->mainloop);
Packit 675970
	}
Packit 675970
Packit 675970
	return 0;
Packit 675970
}
Packit 675970
Packit 675970
static void stream_success_cb(pa_stream * p, int success, void *userdata)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = userdata;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return;
Packit 675970
Packit 675970
	pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_start(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	pa_operation *o, *u;
Packit 675970
	int err = 0, err_o = 0, err_u = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	err = check_stream(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	o = pa_stream_cork(pcm->stream, 0, stream_success_cb, pcm);
Packit 675970
	if (!o) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	u = pa_stream_trigger(pcm->stream, stream_success_cb, pcm);
Packit 675970
Packit 675970
	pcm->underrun = 0;
Packit 675970
	err_o = pulse_wait_operation(pcm->p, o);
Packit 675970
	if (u)
Packit 675970
		err_u = pulse_wait_operation(pcm->p, u);
Packit 675970
Packit 675970
	pa_operation_unref(o);
Packit 675970
	if (u)
Packit 675970
		pa_operation_unref(u);
Packit 675970
Packit 675970
	if (err_o < 0 || err_u < 0) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_stop(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	pa_operation *o, *u;
Packit 675970
	int err = 0, err_o = 0, err_u = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	err = check_stream(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	o = pa_stream_cork(pcm->stream, 1, stream_success_cb, pcm);
Packit 675970
	if (!o) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	u = pa_stream_flush(pcm->stream, stream_success_cb, pcm);
Packit 675970
	if (!u) {
Packit 675970
		pa_operation_unref(o);
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	err_o = pulse_wait_operation(pcm->p, o);
Packit 675970
	err_u = pulse_wait_operation(pcm->p, u);
Packit 675970
Packit 675970
	pa_operation_unref(o);
Packit 675970
	pa_operation_unref(u);
Packit 675970
Packit 675970
	if (err_o < 0 || err_u < 0) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_drain(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	pa_operation *o;
Packit 675970
	int err = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	err = check_stream(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	o = pa_stream_drain(pcm->stream, stream_success_cb, pcm);
Packit 675970
	if (!o) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	err = pulse_wait_operation(pcm->p, o);
Packit 675970
Packit 675970
	pa_operation_unref(o);
Packit 675970
Packit 675970
	if (err < 0) {
Packit 675970
		err = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static snd_pcm_sframes_t pulse_pointer(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	snd_pcm_sframes_t ret = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	if (io->state == SND_PCM_STATE_XRUN)
Packit 675970
		return -EPIPE;
Packit 675970
Packit 675970
	if (io->state != SND_PCM_STATE_RUNNING)
Packit 675970
		return 0;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	ret = check_stream(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	if (pcm->underrun) {
Packit 675970
		ret = -EPIPE;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	ret = update_ptr(pcm);
Packit 675970
	if (ret < 0) {
Packit 675970
		ret = -EPIPE;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	if (pcm->underrun)
Packit 675970
		ret = -EPIPE;
Packit 675970
	else
Packit 675970
		ret = snd_pcm_bytes_to_frames(io->pcm, pcm->ptr);
Packit 675970
Packit 675970
finish:
Packit 675970
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return ret;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	int err = 0;
Packit 675970
	pa_usec_t lat = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	for (;;) {
Packit 675970
		err = check_stream(pcm);
Packit 675970
		if (err < 0)
Packit 675970
			goto finish;
Packit 675970
Packit 675970
		err = pa_stream_get_latency(pcm->stream, &lat, NULL);
Packit 675970
		if (err) {
Packit 675970
			if (err != PA_ERR_NODATA) {
Packit 675970
				err = -EIO;
Packit 675970
				goto finish;
Packit 675970
			}
Packit 675970
		} else
Packit 675970
			break;
Packit 675970
Packit 675970
		pa_threaded_mainloop_wait(pcm->p->mainloop);
Packit 675970
	}
Packit 675970
Packit 675970
	*delayp =
Packit 675970
	    snd_pcm_bytes_to_frames(io->pcm,
Packit 675970
				    pa_usec_to_bytes(lat, &pcm->ss));
Packit 675970
Packit 675970
	err = 0;
Packit 675970
Packit 675970
finish:
Packit 675970
Packit 675970
	if (pcm->underrun && pcm->io.state == SND_PCM_STATE_RUNNING)
Packit 675970
		snd_pcm_ioplug_set_state(io, SND_PCM_STATE_XRUN);
Packit 675970
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io,
Packit 675970
				     const snd_pcm_channel_area_t * areas,
Packit 675970
				     snd_pcm_uframes_t offset,
Packit 675970
				     snd_pcm_uframes_t size)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	const char *buf;
Packit 675970
	snd_pcm_sframes_t ret = 0;
Packit 675970
	size_t writebytes;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	ret = check_stream(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	/* Make sure the buffer pointer is in sync */
Packit 675970
	ret = update_ptr(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	buf =
Packit 675970
	    (char *) areas->addr + (areas->first +
Packit 675970
				    areas->step * offset) / 8;
Packit 675970
Packit 675970
	writebytes = size * pcm->frame_size;
Packit 675970
	ret = pa_stream_write(pcm->stream, buf, writebytes, NULL, 0, 0);
Packit 675970
	if (ret < 0) {
Packit 675970
		ret = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	/* Make sure the buffer pointer is in sync */
Packit 675970
	pcm->last_size -= writebytes;
Packit 675970
	pcm->written += writebytes;
Packit 675970
	ret = update_ptr(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
Packit 675970
	ret = update_active(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	ret = size;
Packit 675970
	pcm->underrun = 0;
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return ret;
Packit 675970
}
Packit 675970
Packit 675970
static snd_pcm_sframes_t pulse_read(snd_pcm_ioplug_t * io,
Packit 675970
				    const snd_pcm_channel_area_t * areas,
Packit 675970
				    snd_pcm_uframes_t offset,
Packit 675970
				    snd_pcm_uframes_t size)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	void *dst_buf;
Packit 675970
	size_t remain_size, frag_length;
Packit 675970
	snd_pcm_sframes_t ret = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	ret = check_stream(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	/* Make sure the buffer pointer is in sync */
Packit 675970
	ret = update_ptr(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	remain_size = size * pcm->frame_size;
Packit 675970
Packit 675970
	dst_buf =
Packit 675970
	    (char *) areas->addr + (areas->first +
Packit 675970
				    areas->step * offset) / 8;
Packit 675970
	while (remain_size > 0) {
Packit 675970
		const void *src_buf;
Packit 675970
Packit 675970
		if (pa_stream_peek(pcm->stream, &src_buf, &frag_length) < 0) {
Packit 675970
			ret = -EIO;
Packit 675970
			goto finish;
Packit 675970
		}
Packit 675970
Packit 675970
		if (frag_length == 0)
Packit 675970
			break;
Packit 675970
Packit 675970
		src_buf = (char *) src_buf + pcm->offset;
Packit 675970
		frag_length -= pcm->offset;
Packit 675970
Packit 675970
		if (frag_length > remain_size) {
Packit 675970
			pcm->offset += remain_size;
Packit 675970
			frag_length = remain_size;
Packit 675970
		} else
Packit 675970
			pcm->offset = 0;
Packit 675970
Packit 675970
		memcpy(dst_buf, src_buf, frag_length);
Packit 675970
Packit 675970
		if (pcm->offset == 0)
Packit 675970
			pa_stream_drop(pcm->stream);
Packit 675970
Packit 675970
		dst_buf = (char *) dst_buf + frag_length;
Packit 675970
		remain_size -= frag_length;
Packit 675970
		pcm->last_size -= frag_length;
Packit 675970
	}
Packit 675970
Packit 675970
	/* Make sure the buffer pointer is in sync */
Packit 675970
	ret = update_ptr(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	ret = update_active(pcm);
Packit 675970
	if (ret < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	ret = size - (remain_size / pcm->frame_size);
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return ret;
Packit 675970
}
Packit 675970
Packit 675970
static void stream_state_cb(pa_stream * p, void *userdata)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = userdata;
Packit 675970
	pa_stream_state_t state;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return;
Packit 675970
Packit 675970
	state = pa_stream_get_state(p);
Packit 675970
	if (!PA_STREAM_IS_GOOD(state))
Packit 675970
		pulse_poll_activate(pcm->p);
Packit 675970
Packit 675970
	pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
Packit 675970
}
Packit 675970
Packit 675970
static void stream_request_cb(pa_stream * p, size_t length, void *userdata)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = userdata;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return;
Packit 675970
Packit 675970
	update_active(pcm);
Packit 675970
}
Packit 675970
Packit 675970
#ifndef PA_CHECK_VERSION
Packit 675970
#define PA_CHECK_VERSION(x, y, z)	0
Packit 675970
#endif
Packit 675970
Packit 675970
#if PA_CHECK_VERSION(0,99,0)
Packit 675970
#define DEFAULT_HANDLE_UNDERRUN		1
Packit 675970
#define do_underrun_detect(pcm, p) \
Packit 675970
	((pcm)->written <= pa_stream_get_underflow_index(p))
Packit 675970
#else
Packit 675970
#define DEFAULT_HANDLE_UNDERRUN		0
Packit 675970
#define do_underrun_detect(pcm, p)	1	/* always true */
Packit 675970
#endif
Packit 675970
Packit 675970
static void stream_underrun_cb(pa_stream * p, void *userdata)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = userdata;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return;
Packit 675970
Packit 675970
	if (do_underrun_detect(pcm, p))
Packit 675970
		pcm->underrun = 1;
Packit 675970
}
Packit 675970
Packit 675970
static void stream_latency_cb(pa_stream *p, void *userdata) {
Packit 675970
	snd_pcm_pulse_t *pcm = userdata;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p)
Packit 675970
		return;
Packit 675970
Packit 675970
	pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_pcm_poll_revents(snd_pcm_ioplug_t * io,
Packit 675970
				  struct pollfd *pfd, unsigned int nfds,
Packit 675970
				  unsigned short *revents)
Packit 675970
{
Packit 675970
	int err = 0;
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	err = check_stream(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	err = check_active(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	if (err > 0)
Packit 675970
		*revents = io->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
Packit 675970
	else
Packit 675970
		*revents = 0;
Packit 675970
Packit 675970
	err = 0;
Packit 675970
Packit 675970
finish:
Packit 675970
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_prepare(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	pa_channel_map map;
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	int err = 0, r;
Packit 675970
	unsigned c, d;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	if (pcm->stream) {
Packit 675970
		pa_stream_disconnect(pcm->stream);
Packit 675970
		wait_stream_state(pcm, PA_STREAM_TERMINATED);
Packit 675970
		pa_stream_unref(pcm->stream);
Packit 675970
		pcm->stream = NULL;
Packit 675970
	}
Packit 675970
Packit 675970
	err = pulse_check_connection(pcm->p);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	assert(pcm->stream == NULL);
Packit 675970
Packit 675970
	for (c = pcm->ss.channels; c > 0; c--)
Packit 675970
		if (pa_channel_map_init_auto(&map, c, PA_CHANNEL_MAP_ALSA))
Packit 675970
			break;
Packit 675970
Packit 675970
	/* Extend if nessary */
Packit 675970
	for (d = c; d < pcm->ss.channels; d++)
Packit 675970
		map.map[d] = PA_CHANNEL_POSITION_AUX0+(d-c);
Packit 675970
Packit 675970
	map.channels = pcm->ss.channels;
Packit 675970
Packit 675970
	if (io->stream == SND_PCM_STREAM_PLAYBACK)
Packit 675970
		pcm->stream =
Packit 675970
		    pa_stream_new(pcm->p->context, "ALSA Playback", &pcm->ss, &map);
Packit 675970
	else
Packit 675970
		pcm->stream =
Packit 675970
		    pa_stream_new(pcm->p->context, "ALSA Capture", &pcm->ss, &map);
Packit 675970
Packit 675970
	if (!pcm->stream) {
Packit 675970
		err = -ENOMEM;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	pa_stream_set_state_callback(pcm->stream, stream_state_cb, pcm);
Packit 675970
	pa_stream_set_latency_update_callback(pcm->stream, stream_latency_cb, pcm);
Packit 675970
Packit 675970
	if (io->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 675970
		pa_stream_set_write_callback(pcm->stream,
Packit 675970
					     stream_request_cb, pcm);
Packit 675970
		if (pcm->handle_underrun)
Packit 675970
			pa_stream_set_underflow_callback(pcm->stream,
Packit 675970
							 stream_underrun_cb, pcm);
Packit 675970
		r = pa_stream_connect_playback(pcm->stream, pcm->device,
Packit 675970
					       &pcm->buffer_attr,
Packit 675970
					       PA_STREAM_AUTO_TIMING_UPDATE |
Packit 675970
					       PA_STREAM_INTERPOLATE_TIMING
Packit 675970
#ifdef PA_STREAM_EARLY_REQUESTS
Packit 675970
					     | PA_STREAM_EARLY_REQUESTS
Packit 675970
#endif
Packit 675970
					       , NULL, NULL);
Packit 675970
	} else {
Packit 675970
		pa_stream_set_read_callback(pcm->stream, stream_request_cb,
Packit 675970
					    pcm);
Packit 675970
		r = pa_stream_connect_record(pcm->stream, pcm->device,
Packit 675970
					     &pcm->buffer_attr,
Packit 675970
					     PA_STREAM_AUTO_TIMING_UPDATE |
Packit 675970
					     PA_STREAM_INTERPOLATE_TIMING
Packit 675970
#ifdef PA_STREAM_EARLY_REQUESTS
Packit 675970
					     | PA_STREAM_EARLY_REQUESTS
Packit 675970
#endif
Packit 675970
			);
Packit 675970
	}
Packit 675970
Packit 675970
	if (r < 0) {
Packit 675970
		SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
Packit 675970
		pa_stream_unref(pcm->stream);
Packit 675970
		pcm->stream = NULL;
Packit 675970
		r = -EIO;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	err = wait_stream_state(pcm, PA_STREAM_READY);
Packit 675970
	if (err < 0) {
Packit 675970
		SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
Packit 675970
		pa_stream_unref(pcm->stream);
Packit 675970
		pcm->stream = NULL;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	pcm->offset = 0;
Packit 675970
	pcm->underrun = 0;
Packit 675970
	pcm->written = 0;
Packit 675970
Packit 675970
	/* Reset fake ringbuffer */
Packit 675970
	pcm->last_size = 0;
Packit 675970
	pcm->ptr = 0;
Packit 675970
	update_ptr(pcm);
Packit 675970
Packit 675970
      finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_hw_params(snd_pcm_ioplug_t * io,
Packit 675970
			   snd_pcm_hw_params_t * params)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	int err = 0;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	pcm->frame_size =
Packit 675970
	    (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
Packit 675970
Packit 675970
	switch (io->format) {
Packit 675970
	case SND_PCM_FORMAT_U8:
Packit 675970
		pcm->ss.format = PA_SAMPLE_U8;
Packit 675970
		break;
Packit 675970
	case SND_PCM_FORMAT_A_LAW:
Packit 675970
		pcm->ss.format = PA_SAMPLE_ALAW;
Packit 675970
		break;
Packit 675970
	case SND_PCM_FORMAT_MU_LAW:
Packit 675970
		pcm->ss.format = PA_SAMPLE_ULAW;
Packit 675970
		break;
Packit 675970
	case SND_PCM_FORMAT_S16_LE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S16LE;
Packit 675970
		break;
Packit 675970
	case SND_PCM_FORMAT_S16_BE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S16BE;
Packit 675970
		break;
Packit 675970
#ifdef PA_SAMPLE_FLOAT32LE
Packit 675970
	case SND_PCM_FORMAT_FLOAT_LE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_FLOAT32LE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_FLOAT32BE
Packit 675970
	case SND_PCM_FORMAT_FLOAT_BE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_FLOAT32BE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S32LE
Packit 675970
	case SND_PCM_FORMAT_S32_LE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S32LE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S32BE
Packit 675970
	case SND_PCM_FORMAT_S32_BE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S32BE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S24LE
Packit 675970
	case SND_PCM_FORMAT_S24_3LE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S24LE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S24BE
Packit 675970
	case SND_PCM_FORMAT_S24_3BE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S24BE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S24_32LE
Packit 675970
	case SND_PCM_FORMAT_S24_LE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S24_32LE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
#ifdef PA_SAMPLE_S24_32BE
Packit 675970
	case SND_PCM_FORMAT_S24_BE:
Packit 675970
		pcm->ss.format = PA_SAMPLE_S24_32BE;
Packit 675970
		break;
Packit 675970
#endif
Packit 675970
	default:
Packit 675970
		SNDERR("PulseAudio: Unsupported format %s\n",
Packit 675970
			snd_pcm_format_name(io->format));
Packit 675970
		err = -EINVAL;
Packit 675970
		goto finish;
Packit 675970
	}
Packit 675970
Packit 675970
	pcm->ss.rate = io->rate;
Packit 675970
	pcm->ss.channels = io->channels;
Packit 675970
Packit 675970
	pcm->buffer_attr.maxlength =
Packit 675970
		4 * 1024 * 1024;
Packit 675970
	pcm->buffer_attr.tlength =
Packit 675970
		io->buffer_size * pcm->frame_size;
Packit 675970
	if (pcm->buffer_attr.prebuf == (uint32_t)-1)
Packit 675970
		pcm->buffer_attr.prebuf =
Packit 675970
			(io->buffer_size - io->period_size) * pcm->frame_size;
Packit 675970
	pcm->buffer_attr.minreq = io->period_size * pcm->frame_size;
Packit 675970
	pcm->buffer_attr.fragsize = io->period_size * pcm->frame_size;
Packit 675970
Packit 675970
      finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	snd_pcm_uframes_t start_threshold;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
Packit 675970
Packit 675970
	/* At least one period to keep PulseAudio happy */
Packit 675970
	if (start_threshold < io->period_size)
Packit 675970
		start_threshold = io->period_size;
Packit 675970
Packit 675970
	pcm->buffer_attr.prebuf = start_threshold * pcm->frame_size;
Packit 675970
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return 0;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_close(snd_pcm_ioplug_t * io)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
Packit 675970
	assert(pcm);
Packit 675970
Packit 675970
	if (pcm->p && pcm->p->mainloop) {
Packit 675970
Packit 675970
		pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
		if (pcm->stream) {
Packit 675970
			pa_stream_disconnect(pcm->stream);
Packit 675970
			pa_stream_unref(pcm->stream);
Packit 675970
		}
Packit 675970
Packit 675970
		pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
	}
Packit 675970
Packit 675970
	if (pcm->p)
Packit 675970
		pulse_free(pcm->p);
Packit 675970
Packit 675970
	free(pcm->device);
Packit 675970
	free(pcm);
Packit 675970
Packit 675970
	return 0;
Packit 675970
}
Packit 675970
Packit 675970
static int pulse_pause(snd_pcm_ioplug_t * io, int enable)
Packit 675970
{
Packit 675970
	snd_pcm_pulse_t *pcm = io->private_data;
Packit 675970
	int err = 0;
Packit 675970
	pa_operation *o;
Packit 675970
Packit 675970
	assert (pcm);
Packit 675970
Packit 675970
	if (!pcm->p || !pcm->p->mainloop)
Packit 675970
		return -EBADFD;
Packit 675970
Packit 675970
	pa_threaded_mainloop_lock(pcm->p->mainloop);
Packit 675970
Packit 675970
	err = check_stream(pcm);
Packit 675970
	if (err < 0)
Packit 675970
		goto finish;
Packit 675970
Packit 675970
	o = pa_stream_cork(pcm->stream, enable, NULL, NULL);
Packit 675970
	if (o)
Packit 675970
		pa_operation_unref(o);
Packit 675970
	else
Packit 675970
		err = -EIO;
Packit 675970
Packit 675970
finish:
Packit 675970
	pa_threaded_mainloop_unlock(pcm->p->mainloop);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
Packit 675970
	.start = pulse_start,
Packit 675970
	.stop = pulse_stop,
Packit 675970
	.drain = pulse_drain,
Packit 675970
	.pointer = pulse_pointer,
Packit 675970
	.transfer = pulse_write,
Packit 675970
	.delay = pulse_delay,
Packit 675970
	.poll_revents = pulse_pcm_poll_revents,
Packit 675970
	.prepare = pulse_prepare,
Packit 675970
	.hw_params = pulse_hw_params,
Packit 675970
	.sw_params = pulse_sw_params,
Packit 675970
	.close = pulse_close,
Packit 675970
	.pause = pulse_pause
Packit 675970
};
Packit 675970
Packit 675970
Packit 675970
static const snd_pcm_ioplug_callback_t pulse_capture_callback = {
Packit 675970
	.start = pulse_start,
Packit 675970
	.stop = pulse_stop,
Packit 675970
	.pointer = pulse_pointer,
Packit 675970
	.transfer = pulse_read,
Packit 675970
	.delay = pulse_delay,
Packit 675970
	.poll_revents = pulse_pcm_poll_revents,
Packit 675970
	.prepare = pulse_prepare,
Packit 675970
	.hw_params = pulse_hw_params,
Packit 675970
	.close = pulse_close,
Packit 675970
};
Packit 675970
Packit 675970
Packit 675970
static int pulse_hw_constraint(snd_pcm_pulse_t * pcm)
Packit 675970
{
Packit 675970
	snd_pcm_ioplug_t *io = &pcm->io;
Packit 675970
Packit 675970
	static const snd_pcm_access_t access_list[] = {
Packit 675970
		SND_PCM_ACCESS_RW_INTERLEAVED
Packit 675970
	};
Packit 675970
	static const unsigned int formats[] = {
Packit 675970
		SND_PCM_FORMAT_U8,
Packit 675970
		SND_PCM_FORMAT_A_LAW,
Packit 675970
		SND_PCM_FORMAT_MU_LAW,
Packit 675970
		SND_PCM_FORMAT_S16_LE,
Packit 675970
		SND_PCM_FORMAT_S16_BE,
Packit 675970
		SND_PCM_FORMAT_FLOAT_LE,
Packit 675970
		SND_PCM_FORMAT_FLOAT_BE,
Packit 675970
		SND_PCM_FORMAT_S32_LE,
Packit 675970
		SND_PCM_FORMAT_S32_BE,
Packit 675970
		SND_PCM_FORMAT_S24_3LE,
Packit 675970
		SND_PCM_FORMAT_S24_3BE,
Packit 675970
		SND_PCM_FORMAT_S24_LE,
Packit 675970
		SND_PCM_FORMAT_S24_BE
Packit 675970
	};
Packit 675970
Packit 675970
	int err;
Packit 675970
Packit 675970
	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
Packit 675970
					    ARRAY_SIZE(access_list),
Packit 675970
					    access_list);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
Packit 675970
					    ARRAY_SIZE(formats), formats);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err =
Packit 675970
	    snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
Packit 675970
					    1, PA_CHANNELS_MAX);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
Packit 675970
					      1, PA_RATE_MAX);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err =
Packit 675970
	    snd_pcm_ioplug_set_param_minmax(io,
Packit 675970
					    SND_PCM_IOPLUG_HW_BUFFER_BYTES,
Packit 675970
					    1, 4 * 1024 * 1024);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err =
Packit 675970
	    snd_pcm_ioplug_set_param_minmax(io,
Packit 675970
					    SND_PCM_IOPLUG_HW_PERIOD_BYTES,
Packit 675970
					    128, 2 * 1024 * 1024);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
Packit 675970
	err =
Packit 675970
	    snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
Packit 675970
					    3, 1024);
Packit 675970
	if (err < 0)
Packit 675970
		return err;
Packit 675970
	return 0;
Packit 675970
}
Packit 675970
Packit 675970
SND_PCM_PLUGIN_DEFINE_FUNC(pulse)
Packit 675970
{
Packit 675970
	snd_config_iterator_t i, next;
Packit 675970
	const char *server = NULL;
Packit 675970
	const char *device = NULL;
Packit 675970
	const char *fallback_name = NULL;
Packit 675970
	int handle_underrun = DEFAULT_HANDLE_UNDERRUN;
Packit 675970
	int err;
Packit 675970
	snd_pcm_pulse_t *pcm;
Packit 675970
Packit 675970
	snd_config_for_each(i, next, conf) {
Packit 675970
		snd_config_t *n = snd_config_iterator_entry(i);
Packit 675970
		const char *id;
Packit 675970
		if (snd_config_get_id(n, &id) < 0)
Packit 675970
			continue;
Packit 675970
		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0
Packit 675970
		    || strcmp(id, "hint") == 0)
Packit 675970
			continue;
Packit 675970
		if (strcmp(id, "server") == 0) {
Packit 675970
			if (snd_config_get_string(n, &server) < 0) {
Packit 675970
				SNDERR("Invalid type for %s", id);
Packit 675970
				return -EINVAL;
Packit 675970
			}
Packit 675970
			continue;
Packit 675970
		}
Packit 675970
		if (strcmp(id, "device") == 0) {
Packit 675970
			if (snd_config_get_string(n, &device) < 0) {
Packit 675970
				SNDERR("Invalid type for %s", id);
Packit 675970
				return -EINVAL;
Packit 675970
			}
Packit 675970
			continue;
Packit 675970
		}
Packit 675970
		if (strcmp(id, "handle_underrun") == 0) {
Packit 675970
			if ((err = snd_config_get_bool(n)) < 0) {
Packit 675970
				SNDERR("Invalid value for %s", id);
Packit 675970
				return -EINVAL;
Packit 675970
			}
Packit 675970
			handle_underrun = err;
Packit 675970
			continue;
Packit 675970
		}
Packit 675970
		if (strcmp(id, "fallback") == 0) {
Packit 675970
			if (snd_config_get_string(n, &fallback_name) < 0) {
Packit 675970
				SNDERR("Invalid value for %s", id);
Packit 675970
				return -EINVAL;
Packit 675970
			}
Packit 675970
			continue;
Packit 675970
		}
Packit 675970
		SNDERR("Unknown field %s", id);
Packit 675970
		return -EINVAL;
Packit 675970
	}
Packit 675970
Packit 675970
	if (fallback_name && name && !strcmp(name, fallback_name))
Packit 675970
		fallback_name = NULL; /* no fallback for the same name */
Packit 675970
Packit 675970
	pcm = calloc(1, sizeof(*pcm));
Packit 675970
	if (!pcm)
Packit 675970
		return -ENOMEM;
Packit 675970
Packit 675970
	if (device) {
Packit 675970
		pcm->device = strdup(device);
Packit 675970
Packit 675970
		if (!pcm->device) {
Packit 675970
			err = -ENOMEM;
Packit 675970
			goto error;
Packit 675970
		}
Packit 675970
	}
Packit 675970
Packit 675970
	pcm->p = pulse_new();
Packit 675970
	if (!pcm->p) {
Packit 675970
		err = -EIO;
Packit 675970
		goto error;
Packit 675970
	}
Packit 675970
Packit 675970
	pcm->handle_underrun = handle_underrun;
Packit 675970
	pcm->buffer_attr.prebuf = -1;
Packit 675970
Packit 675970
	err = pulse_connect(pcm->p, server, fallback_name != NULL);
Packit 675970
	if (err < 0)
Packit 675970
		goto error;
Packit 675970
Packit 675970
	pcm->io.version = SND_PCM_IOPLUG_VERSION;
Packit 675970
	pcm->io.name = "ALSA <-> PulseAudio PCM I/O Plugin";
Packit 675970
	pcm->io.poll_fd = pcm->p->main_fd;
Packit 675970
	pcm->io.poll_events = POLLIN;
Packit 675970
	pcm->io.mmap_rw = 0;
Packit 675970
	pcm->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
Packit 675970
	    &pulse_playback_callback : &pulse_capture_callback;
Packit 675970
	pcm->io.private_data = pcm;
Packit 675970
Packit 675970
	err = snd_pcm_ioplug_create(&pcm->io, name, stream, mode);
Packit 675970
	if (err < 0)
Packit 675970
		goto error;
Packit 675970
Packit 675970
	err = pulse_hw_constraint(pcm);
Packit 675970
	if (err < 0) {
Packit 675970
		snd_pcm_ioplug_delete(&pcm->io);
Packit 675970
		goto error2;
Packit 675970
	}
Packit 675970
Packit 675970
	*pcmp = pcm->io.pcm;
Packit 675970
	return 0;
Packit 675970
Packit 675970
error:
Packit 675970
	if (pcm->p)
Packit 675970
		pulse_free(pcm->p);
Packit 675970
Packit 675970
	free(pcm->device);
Packit 675970
	free(pcm);
Packit 675970
Packit 675970
error2:
Packit 675970
	if (fallback_name)
Packit 675970
		return snd_pcm_open_fallback(pcmp, root, fallback_name, name,
Packit 675970
					     stream, mode);
Packit 675970
Packit 675970
	return err;
Packit 675970
}
Packit 675970
Packit 675970
SND_PCM_PLUGIN_SYMBOL(pulse);