Blame src/pcm/pcm_share.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_share.c
Packit 4a16fb
 * \ingroup PCM_Plugins
Packit 4a16fb
 * \brief PCM Share Plugin Interface
Packit 4a16fb
 * \author Abramo Bagnara <abramo@alsa-project.org>
Packit 4a16fb
 * \date 2000-2001
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - Share
Packit 4a16fb
 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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 <stdio.h>
Packit 4a16fb
#include <stdlib.h>
Packit 4a16fb
#include <limits.h>
Packit 4a16fb
#include <unistd.h>
Packit 4a16fb
#include <string.h>
Packit 4a16fb
#include <signal.h>
Packit 4a16fb
#include <math.h>
Packit 4a16fb
#include <sys/socket.h>
Packit 4a16fb
#include <poll.h>
Packit 4a16fb
#include <pthread.h>
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_share = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
Packit 4a16fb
static LIST_HEAD(snd_pcm_share_slaves);
Packit 4a16fb
static pthread_mutex_t snd_pcm_share_slaves_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 4a16fb
Packit 4a16fb
#ifdef MUTEX_DEBUG
Packit 4a16fb
#define Pthread_mutex_lock(mutex) \
Packit 4a16fb
char *snd_pcm_share_slaves_mutex_holder;
Packit 4a16fb
do { \
Packit 4a16fb
	int err = pthread_mutex_trylock(mutex); \
Packit 4a16fb
	if (err < 0) { \
Packit 4a16fb
		fprintf(stderr, "lock " #mutex " is busy (%s): waiting in " __func__ "\n", *(mutex##_holder)); \
Packit 4a16fb
		pthread_mutex_lock(mutex); \
Packit 4a16fb
		fprintf(stderr, "... got\n"); \
Packit 4a16fb
	} \
Packit 4a16fb
	*(mutex##_holder) = __func__; \
Packit 4a16fb
} while (0)
Packit 4a16fb
Packit 4a16fb
#define Pthread_mutex_unlock(mutex) \
Packit 4a16fb
do { \
Packit 4a16fb
	*(mutex##_holder) = 0; \
Packit 4a16fb
	pthread_mutex_unlock(mutex); \
Packit 4a16fb
} while (0)
Packit 4a16fb
#else
Packit 4a16fb
#define Pthread_mutex_lock(mutex) pthread_mutex_lock(mutex)
Packit 4a16fb
#define Pthread_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	struct list_head clients;
Packit 4a16fb
	struct list_head list;
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_format_t format;
Packit 4a16fb
	int rate;
Packit 4a16fb
	unsigned int channels;
Packit 4a16fb
	snd_pcm_sframes_t period_time;
Packit 4a16fb
	snd_pcm_sframes_t buffer_time;
Packit 4a16fb
	unsigned int open_count;
Packit 4a16fb
	unsigned int setup_count;
Packit 4a16fb
	unsigned int prepared_count;
Packit 4a16fb
	unsigned int running_count;
Packit 4a16fb
	snd_pcm_uframes_t safety_threshold;
Packit 4a16fb
	snd_pcm_uframes_t silence_frames;
Packit 4a16fb
	snd_pcm_sw_params_t sw_params;
Packit 4a16fb
	snd_pcm_uframes_t hw_ptr;
Packit 4a16fb
	int poll[2];
Packit 4a16fb
	int polling;
Packit 4a16fb
	pthread_t thread;
Packit 4a16fb
	pthread_mutex_t mutex;
Packit 4a16fb
#ifdef MUTEX_DEBUG
Packit 4a16fb
	char *mutex_holder;
Packit 4a16fb
#endif
Packit 4a16fb
	pthread_cond_t poll_cond;
Packit 4a16fb
} snd_pcm_share_slave_t;
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	struct list_head list;
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_share_slave_t *slave;
Packit 4a16fb
	unsigned int channels;
Packit 4a16fb
	unsigned int *slave_channels;
Packit 4a16fb
	int drain_silenced;
Packit 4a16fb
	snd_htimestamp_t trigger_tstamp;
Packit 4a16fb
	snd_pcm_state_t state;
Packit 4a16fb
	snd_pcm_uframes_t hw_ptr;
Packit 4a16fb
	snd_pcm_uframes_t appl_ptr;
Packit 4a16fb
	int ready;
Packit 4a16fb
	int client_socket;
Packit 4a16fb
	int slave_socket;
Packit 4a16fb
} snd_pcm_share_t;
Packit 4a16fb
Packit 4a16fb
#endif /* DOC_HIDDEN */
Packit 4a16fb
Packit 4a16fb
static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state);
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_sframes_t avail;
Packit 4a16fb
	snd_pcm_t *pcm = slave->pcm;
Packit 4a16fb
  	avail = slave->hw_ptr - *pcm->appl.ptr;
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
		avail += pcm->buffer_size;
Packit 4a16fb
	if (avail < 0)
Packit 4a16fb
		avail += pcm->boundary;
Packit 4a16fb
	else if ((snd_pcm_uframes_t) avail >= pcm->boundary)
Packit 4a16fb
		avail -= pcm->boundary;
Packit 4a16fb
	return avail;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Warning: take the mutex before to call this */
Packit 4a16fb
/* Return number of frames to mmap_commit the slave */
Packit 4a16fb
static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *i;
Packit 4a16fb
	snd_pcm_uframes_t buffer_size;
Packit 4a16fb
	snd_pcm_sframes_t frames, safety_frames;
Packit 4a16fb
	snd_pcm_sframes_t min_frames, max_frames;
Packit 4a16fb
	snd_pcm_uframes_t avail, slave_avail;
Packit 4a16fb
	snd_pcm_uframes_t slave_hw_avail;
Packit 4a16fb
	slave_avail = snd_pcm_share_slave_avail(slave);
Packit 4a16fb
	buffer_size = slave->pcm->buffer_size;
Packit 4a16fb
	min_frames = slave_avail;
Packit 4a16fb
	max_frames = 0;
Packit 4a16fb
	list_for_each(i, &slave->clients) {
Packit 4a16fb
		snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
Packit 4a16fb
		snd_pcm_t *pcm = share->pcm;
Packit 4a16fb
		switch (share->state) {
Packit 4a16fb
		case SND_PCM_STATE_RUNNING:
Packit 4a16fb
			break;
Packit 4a16fb
		case SND_PCM_STATE_DRAINING:
Packit 4a16fb
			if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
				continue;
Packit 4a16fb
			break;
Packit 4a16fb
		default:
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
		avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
		frames = slave_avail - avail;
Packit 4a16fb
		if (frames > max_frames)
Packit 4a16fb
			max_frames = frames;
Packit 4a16fb
		if (share->state != SND_PCM_STATE_RUNNING)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (frames < min_frames)
Packit 4a16fb
			min_frames = frames;
Packit 4a16fb
	}
Packit 4a16fb
	if (max_frames == 0)
Packit 4a16fb
		return 0;
Packit 4a16fb
	frames = min_frames;
Packit 4a16fb
	/* Slave xrun prevention */
Packit 4a16fb
	slave_hw_avail = buffer_size - slave_avail;
Packit 4a16fb
	safety_frames = slave->safety_threshold - slave_hw_avail;
Packit 4a16fb
	if (safety_frames > 0 &&
Packit 4a16fb
	    frames < safety_frames) {
Packit 4a16fb
		/* Avoid to pass over the last */
Packit 4a16fb
		if (max_frames < safety_frames)
Packit 4a16fb
			frames = max_frames;
Packit 4a16fb
		else
Packit 4a16fb
			frames = safety_frames;
Packit 4a16fb
	}
Packit 4a16fb
	if (frames < 0)
Packit 4a16fb
		return 0;
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/* 
Packit 4a16fb
   - stop PCM on xrun
Packit 4a16fb
   - update poll status
Packit 4a16fb
   - draining silencing
Packit 4a16fb
   - return distance in frames to next event
Packit 4a16fb
*/
Packit 4a16fb
static snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	snd_pcm_uframes_t buffer_size = spcm->buffer_size;
Packit 4a16fb
	int ready = 1, running = 0;
Packit 4a16fb
	snd_pcm_uframes_t avail = 0, slave_avail;
Packit 4a16fb
	snd_pcm_sframes_t hw_avail;
Packit 4a16fb
	snd_pcm_uframes_t missing = INT_MAX;
Packit 4a16fb
	snd_pcm_sframes_t ready_missing;
Packit 4a16fb
	// printf("state=%s hw_ptr=%ld appl_ptr=%ld slave appl_ptr=%ld safety=%ld silence=%ld\n", snd_pcm_state_name(share->state), slave->hw_ptr, share->appl_ptr, *slave->pcm->appl_ptr, slave->safety_threshold, slave->silence_frames);
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			break;
Packit 4a16fb
		/* Fall through */
Packit 4a16fb
	default:
Packit 4a16fb
		return INT_MAX;
Packit 4a16fb
	}
Packit 4a16fb
	share->hw_ptr = slave->hw_ptr;
Packit 4a16fb
	avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
	if (avail >= pcm->stop_threshold) {
Packit 4a16fb
		_snd_pcm_share_stop(pcm, share->state == SND_PCM_STATE_DRAINING ? SND_PCM_STATE_SETUP : SND_PCM_STATE_XRUN);
Packit 4a16fb
		goto update_poll;
Packit 4a16fb
	}
Packit 4a16fb
	hw_avail = buffer_size - avail;
Packit 4a16fb
	slave_avail = snd_pcm_share_slave_avail(slave);
Packit 4a16fb
	if (avail < slave_avail) {
Packit 4a16fb
		/* Some frames need still to be transferred */
Packit 4a16fb
		snd_pcm_sframes_t slave_hw_avail = buffer_size - slave_avail;
Packit 4a16fb
		snd_pcm_sframes_t safety_missing = slave_hw_avail - slave->safety_threshold;
Packit 4a16fb
		if (safety_missing < 0) {
Packit 4a16fb
			snd_pcm_sframes_t err;
Packit 4a16fb
			snd_pcm_sframes_t frames = slave_avail - avail;
Packit 4a16fb
			if (-safety_missing <= frames) {
Packit 4a16fb
				frames = -safety_missing;
Packit 4a16fb
				missing = 1;
Packit 4a16fb
			}
Packit 4a16fb
			err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				SYSMSG("snd_pcm_mmap_commit error");
Packit 4a16fb
				return INT_MAX;
Packit 4a16fb
			}
Packit 4a16fb
			if (err != frames)
Packit 4a16fb
				SYSMSG("commit returns %ld for size %ld", err, frames);
Packit 4a16fb
			slave_avail -= err;
Packit 4a16fb
		} else {
Packit 4a16fb
			if (safety_missing == 0)
Packit 4a16fb
				missing = 1;
Packit 4a16fb
			else
Packit 4a16fb
				missing = safety_missing;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
			if (hw_avail <= 0) {
Packit 4a16fb
				_snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
			if ((snd_pcm_uframes_t)hw_avail < missing)
Packit 4a16fb
				missing = hw_avail;
Packit 4a16fb
			running = 1;
Packit 4a16fb
			ready = 0;
Packit 4a16fb
		}
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		if (avail >= pcm->stop_threshold) {
Packit 4a16fb
			_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
Packit 4a16fb
			break;
Packit 4a16fb
		} else {
Packit 4a16fb
			snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail;
Packit 4a16fb
			if (missing > xrun_missing)
Packit 4a16fb
				missing = xrun_missing;
Packit 4a16fb
		}
Packit 4a16fb
		ready_missing = pcm->avail_min - avail;
Packit 4a16fb
		if (ready_missing > 0) {
Packit 4a16fb
			ready = 0;
Packit 4a16fb
			if (missing > (snd_pcm_uframes_t)ready_missing)
Packit 4a16fb
				missing = ready_missing;
Packit 4a16fb
		}
Packit 4a16fb
		running = 1;
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		SNDERR("invalid shared PCM state %d", share->state);
Packit 4a16fb
		return INT_MAX;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
 update_poll:
Packit 4a16fb
	if (ready != share->ready) {
Packit 4a16fb
		char buf[1];
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
			if (ready)
Packit 4a16fb
				read(share->slave_socket, buf, 1);
Packit 4a16fb
			else
Packit 4a16fb
				write(share->client_socket, buf, 1);
Packit 4a16fb
		} else {
Packit 4a16fb
			if (ready)
Packit 4a16fb
				write(share->slave_socket, buf, 1);
Packit 4a16fb
			else
Packit 4a16fb
				read(share->client_socket, buf, 1);
Packit 4a16fb
		}
Packit 4a16fb
		share->ready = ready;
Packit 4a16fb
	}
Packit 4a16fb
	if (!running)
Packit 4a16fb
		return INT_MAX;
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
Packit 4a16fb
	    share->state == SND_PCM_STATE_DRAINING &&
Packit 4a16fb
	    !share->drain_silenced) {
Packit 4a16fb
		/* drain silencing */
Packit 4a16fb
		if (avail >= slave->silence_frames) {
Packit 4a16fb
			snd_pcm_uframes_t offset = share->appl_ptr % buffer_size;
Packit 4a16fb
			snd_pcm_uframes_t xfer = 0;
Packit 4a16fb
			snd_pcm_uframes_t size = slave->silence_frames;
Packit 4a16fb
			while (xfer < size) {
Packit 4a16fb
				snd_pcm_uframes_t frames = size - xfer;
Packit 4a16fb
				snd_pcm_uframes_t cont = buffer_size - offset;
Packit 4a16fb
				if (cont < frames)
Packit 4a16fb
					frames = cont;
Packit 4a16fb
				snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
Packit 4a16fb
				offset += frames;
Packit 4a16fb
				if (offset >= buffer_size)
Packit 4a16fb
					offset = 0;
Packit 4a16fb
				xfer += frames;
Packit 4a16fb
			}
Packit 4a16fb
			share->drain_silenced = 1;
Packit 4a16fb
		} else {
Packit 4a16fb
			snd_pcm_uframes_t silence_missing;
Packit 4a16fb
			silence_missing = slave->silence_frames - avail;
Packit 4a16fb
			if (silence_missing < missing)
Packit 4a16fb
				missing = silence_missing;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	// printf("missing=%d\n", missing);
Packit 4a16fb
	return missing;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_uframes_t missing = INT_MAX;
Packit 4a16fb
	struct list_head *i;
Packit 4a16fb
	/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm);
Packit 4a16fb
	slave->hw_ptr = *slave->pcm->hw.ptr;
Packit 4a16fb
	list_for_each(i, &slave->clients) {
Packit 4a16fb
		snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
Packit 4a16fb
		snd_pcm_t *pcm = share->pcm;
Packit 4a16fb
		snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm);
Packit 4a16fb
		if (m < missing)
Packit 4a16fb
			missing = m;
Packit 4a16fb
	}
Packit 4a16fb
	return missing;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void *snd_pcm_share_thread(void *data)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_slave_t *slave = data;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	struct pollfd pfd[2];
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	pfd[0].fd = slave->poll[0];
Packit 4a16fb
	pfd[0].events = POLLIN;
Packit 4a16fb
	err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1);
Packit 4a16fb
	if (err != 1) {
Packit 4a16fb
		SNDERR("invalid poll descriptors %d", err);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	err = pipe(slave->poll);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		SYSERR("can't create a pipe");
Packit 4a16fb
		Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
	while (slave->open_count > 0) {
Packit 4a16fb
		snd_pcm_uframes_t missing;
Packit 4a16fb
		// printf("begin min_missing\n");
Packit 4a16fb
		missing = _snd_pcm_share_slave_missing(slave);
Packit 4a16fb
		// printf("min_missing=%ld\n", missing);
Packit 4a16fb
		if (missing < INT_MAX) {
Packit 4a16fb
			snd_pcm_uframes_t hw_ptr;
Packit 4a16fb
			snd_pcm_sframes_t avail_min;
Packit 4a16fb
			hw_ptr = slave->hw_ptr + missing;
Packit 4a16fb
			hw_ptr += spcm->period_size - 1;
Packit 4a16fb
			if (hw_ptr >= spcm->boundary)
Packit 4a16fb
				hw_ptr -= spcm->boundary;
Packit 4a16fb
			hw_ptr -= hw_ptr % spcm->period_size;
Packit 4a16fb
			avail_min = hw_ptr - *spcm->appl.ptr;
Packit 4a16fb
			if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
				avail_min += spcm->buffer_size;
Packit 4a16fb
			if (avail_min < 0)
Packit 4a16fb
				avail_min += spcm->boundary;
Packit 4a16fb
			// printf("avail_min=%d\n", avail_min);
Packit 4a16fb
			if ((snd_pcm_uframes_t)avail_min != spcm->avail_min) {
Packit 4a16fb
				snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min);
Packit 4a16fb
				err = snd_pcm_sw_params(spcm, &slave->sw_params);
Packit 4a16fb
				if (err < 0) {
Packit 4a16fb
					SYSERR("snd_pcm_sw_params error");
Packit 4a16fb
					Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
					return NULL;
Packit 4a16fb
				}
Packit 4a16fb
			}
Packit 4a16fb
			slave->polling = 1;
Packit 4a16fb
			Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
			err = poll(pfd, 2, -1);
Packit 4a16fb
			Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
			if (pfd[0].revents & POLLIN) {
Packit 4a16fb
				char buf[1];
Packit 4a16fb
				read(pfd[0].fd, buf, 1);
Packit 4a16fb
			}
Packit 4a16fb
		} else {
Packit 4a16fb
			slave->polling = 0;
Packit 4a16fb
			pthread_cond_wait(&slave->poll_cond, &slave->mutex);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void _snd_pcm_share_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	snd_pcm_uframes_t missing;
Packit 4a16fb
	/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm);
Packit 4a16fb
	slave->hw_ptr = *slave->pcm->hw.ptr;
Packit 4a16fb
	missing = _snd_pcm_share_missing(pcm);
Packit 4a16fb
	// printf("missing %ld\n", missing);
Packit 4a16fb
	if (!slave->polling) {
Packit 4a16fb
		pthread_cond_signal(&slave->poll_cond);
Packit 4a16fb
		return;
Packit 4a16fb
	}
Packit 4a16fb
	if (missing < INT_MAX) {
Packit 4a16fb
		snd_pcm_uframes_t hw_ptr;
Packit 4a16fb
		snd_pcm_sframes_t avail_min;
Packit 4a16fb
		hw_ptr = slave->hw_ptr + missing;
Packit 4a16fb
		hw_ptr += spcm->period_size - 1;
Packit 4a16fb
		if (hw_ptr >= spcm->boundary)
Packit 4a16fb
			hw_ptr -= spcm->boundary;
Packit 4a16fb
		hw_ptr -= hw_ptr % spcm->period_size;
Packit 4a16fb
		avail_min = hw_ptr - *spcm->appl.ptr;
Packit 4a16fb
		if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			avail_min += spcm->buffer_size;
Packit 4a16fb
		if (avail_min < 0)
Packit 4a16fb
			avail_min += spcm->boundary;
Packit 4a16fb
		if ((snd_pcm_uframes_t)avail_min < spcm->avail_min) {
Packit 4a16fb
			int err;
Packit 4a16fb
			snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min);
Packit 4a16fb
			err = snd_pcm_sw_params(spcm, &slave->sw_params);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				SYSERR("snd_pcm_sw_params error");
Packit 4a16fb
				return;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENOSYS;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	return snd_pcm_info(share->slave->pcm, info);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_access_mask_t access_mask;
Packit 4a16fb
	int err;
Packit 4a16fb
	snd_pcm_access_mask_any(&access_mask);
Packit 4a16fb
	snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
Packit 4a16fb
	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
					 &access_mask);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
Packit 4a16fb
				    share->channels, 0);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	if (slave->format != SND_PCM_FORMAT_UNKNOWN) {
Packit 4a16fb
		err = _snd_pcm_hw_params_set_format(params, slave->format);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (slave->rate >= 0) {
Packit 4a16fb
		err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE,
Packit 4a16fb
					    slave->rate, 0);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	if (slave->period_time >= 0) {
Packit 4a16fb
		err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit 4a16fb
					    slave->period_time, 0);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	if (slave->buffer_time >= 0) {
Packit 4a16fb
		err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME,
Packit 4a16fb
					    slave->buffer_time, 0);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	params->info |= SND_PCM_INFO_DOUBLE;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
Packit 4a16fb
	_snd_pcm_hw_params_any(sparams);
Packit 4a16fb
	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
				   &saccess_mask);
Packit 4a16fb
	_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
Packit 4a16fb
			      slave->channels, 0);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
Packit 4a16fb
					  snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_SUBFORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_RATE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIODS);
Packit 4a16fb
	const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
	if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
Packit 4a16fb
	    !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
Packit 4a16fb
	    !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
Packit 4a16fb
		snd_pcm_access_mask_t saccess_mask;
Packit 4a16fb
		snd_pcm_access_mask_any(&saccess_mask);
Packit 4a16fb
		snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
Packit 4a16fb
		err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
						 &saccess_mask);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	err = _snd_pcm_hw_params_refine(sparams, links, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
	
Packit 4a16fb
static int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
Packit 4a16fb
					   snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_SUBFORMAT |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_RATE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIOD_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_PERIODS);
Packit 4a16fb
	snd_pcm_access_mask_t access_mask;
Packit 4a16fb
	const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
	snd_pcm_access_mask_any(&access_mask);
Packit 4a16fb
	snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
Packit 4a16fb
	if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
Packit 4a16fb
		snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
Packit 4a16fb
	if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
Packit 4a16fb
	    !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
Packit 4a16fb
		snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
Packit 4a16fb
	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
Packit 4a16fb
					 &access_mask);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = _snd_pcm_hw_params_refine(params, links, sparams);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	return snd_pcm_hw_refine(share->slave->pcm, params);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	return _snd_pcm_hw_params_internal(share->slave->pcm, params);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	return snd_pcm_hw_refine_slave(pcm, params,
Packit 4a16fb
				       snd_pcm_share_hw_refine_cprepare,
Packit 4a16fb
				       snd_pcm_share_hw_refine_cchange,
Packit 4a16fb
				       snd_pcm_share_hw_refine_sprepare,
Packit 4a16fb
				       snd_pcm_share_hw_refine_schange,
Packit 4a16fb
				       snd_pcm_share_hw_refine_slave);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	if (slave->setup_count) {
Packit 4a16fb
		err = _snd_pcm_hw_params_set_format(params, spcm->format);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _err;
Packit 4a16fb
		err = _snd_pcm_hw_params_set_subformat(params, spcm->subformat);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _err;
Packit 4a16fb
		err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE,
Packit 4a16fb
						   spcm->rate, 0, 
Packit 4a16fb
						   spcm->rate, 1);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _err;
Packit 4a16fb
		err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit 4a16fb
						   spcm->period_time, 0,
Packit 4a16fb
						   spcm->period_time, 1);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _err;
Packit 4a16fb
		err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
Packit 4a16fb
					    spcm->buffer_size, 0);
Packit 4a16fb
	_err:
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			SNDERR("slave is already running with incompatible setup");
Packit 4a16fb
			err = -EBUSY;
Packit 4a16fb
			goto _end;
Packit 4a16fb
		}
Packit 4a16fb
	} else {
Packit 4a16fb
		err = snd_pcm_hw_params_slave(pcm, params,
Packit 4a16fb
					      snd_pcm_share_hw_refine_cchange,
Packit 4a16fb
					      snd_pcm_share_hw_refine_sprepare,
Packit 4a16fb
					      snd_pcm_share_hw_refine_schange,
Packit 4a16fb
					      snd_pcm_share_hw_params_slave);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _end;
Packit 4a16fb
		snd_pcm_sw_params_current(slave->pcm, &slave->sw_params);
Packit 4a16fb
		/* >= 30 ms */
Packit 4a16fb
		slave->safety_threshold = slave->pcm->rate * 30 / 1000;
Packit 4a16fb
		slave->safety_threshold += slave->pcm->period_size - 1;
Packit 4a16fb
		slave->safety_threshold -= slave->safety_threshold % slave->pcm->period_size;
Packit 4a16fb
		slave->silence_frames = slave->safety_threshold;
Packit 4a16fb
		if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
Packit 4a16fb
	}
Packit 4a16fb
	share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
	slave->setup_count++;
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hw_free(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	slave->setup_count--;
Packit 4a16fb
	if (slave->setup_count == 0)
Packit 4a16fb
		err = snd_pcm_hw_free(slave->pcm);
Packit 4a16fb
	share->state = SND_PCM_STATE_OPEN;
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	snd_pcm_sframes_t sd = 0, d = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		status->avail = snd_pcm_mmap_playback_avail(pcm);
Packit 4a16fb
		if (share->state != SND_PCM_STATE_RUNNING &&
Packit 4a16fb
		    share->state != SND_PCM_STATE_DRAINING)
Packit 4a16fb
			goto _notrunning;
Packit 4a16fb
		d = pcm->buffer_size - status->avail;
Packit 4a16fb
	} else {
Packit 4a16fb
		status->avail = snd_pcm_mmap_capture_avail(pcm);
Packit 4a16fb
		if (share->state != SND_PCM_STATE_RUNNING)
Packit 4a16fb
			goto _notrunning;
Packit 4a16fb
		d = status->avail;
Packit 4a16fb
	}
Packit 4a16fb
	err = snd_pcm_delay(slave->pcm, &sd);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		goto _end;
Packit 4a16fb
 _notrunning:
Packit 4a16fb
	status->delay = sd + d;
Packit 4a16fb
	status->state = share->state;
Packit 4a16fb
	status->trigger_tstamp = share->trigger_tstamp;
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	return share->state;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int _snd_pcm_share_hwsync(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_XRUN:
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
	default:
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_pcm_hwsync(slave->pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_hwsync(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	err = _snd_pcm_share_hwsync(pcm);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_XRUN:
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			break;
Packit 4a16fb
		/* Fall through */
Packit 4a16fb
	default:
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	}
Packit 4a16fb
	return snd_pcm_delay(slave->pcm, delayp);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	err = _snd_pcm_share_delay(pcm, delayp);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t avail;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	if (share->state == SND_PCM_STATE_RUNNING) {
Packit 4a16fb
		avail = snd_pcm_avail_update(slave->pcm);
Packit 4a16fb
		if (avail < 0) {
Packit 4a16fb
			Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
			return avail;
Packit 4a16fb
		}
Packit 4a16fb
		share->hw_ptr = *slave->pcm->hw.ptr;
Packit 4a16fb
	}
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	avail = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
	if ((snd_pcm_uframes_t)avail > pcm->buffer_size)
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
	return avail;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
Packit 4a16fb
				    snd_htimestamp_t *tstamp)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	err = snd_pcm_htimestamp(slave->pcm, avail, tstamp);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Call it with mutex held */
Packit 4a16fb
static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
Packit 4a16fb
						    snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
Packit 4a16fb
						    snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	snd_pcm_sframes_t frames;
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
Packit 4a16fb
	    share->state == SND_PCM_STATE_RUNNING) {
Packit 4a16fb
		frames = *spcm->appl.ptr - share->appl_ptr;
Packit 4a16fb
		if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
Packit 4a16fb
			frames -= pcm->boundary;
Packit 4a16fb
		else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
Packit 4a16fb
			frames += pcm->boundary;
Packit 4a16fb
		if (frames > 0) {
Packit 4a16fb
			/* Latecomer PCM */
Packit 4a16fb
			ret = snd_pcm_rewind(spcm, frames);
Packit 4a16fb
			if (ret < 0)
Packit 4a16fb
				return ret;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_mmap_appl_forward(pcm, size);
Packit 4a16fb
	if (share->state == SND_PCM_STATE_RUNNING) {
Packit 4a16fb
		frames = _snd_pcm_share_slave_forward(slave);
Packit 4a16fb
		if (frames > 0) {
Packit 4a16fb
			snd_pcm_sframes_t err;
Packit 4a16fb
			err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				SYSMSG("snd_pcm_mmap_commit error");
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			if (err != frames) {
Packit 4a16fb
				SYSMSG("commit returns %ld for size %ld", err, frames);
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
		_snd_pcm_share_update(pcm);
Packit 4a16fb
	}
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
Packit 4a16fb
						   snd_pcm_uframes_t offset,
Packit 4a16fb
						   snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	ret = _snd_pcm_share_mmap_commit(pcm, offset, size);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_prepare(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_OPEN:
Packit 4a16fb
		err = -EBADFD;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		err = -EBUSY;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
		err = 0;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	default:	/* nothing todo */
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	if (slave->prepared_count == 0) {
Packit 4a16fb
		err = snd_pcm_prepare(slave->pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _end;
Packit 4a16fb
	}
Packit 4a16fb
	slave->prepared_count++;
Packit 4a16fb
	share->hw_ptr = 0;
Packit 4a16fb
	share->appl_ptr = 0;
Packit 4a16fb
	share->state = SND_PCM_STATE_PREPARED;
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_reset(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	/* FIXME? */
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format);
Packit 4a16fb
	share->hw_ptr = *slave->pcm->hw.ptr;
Packit 4a16fb
	share->appl_ptr = share->hw_ptr;
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_start(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_t *spcm = slave->pcm;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	if (share->state != SND_PCM_STATE_PREPARED)
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	share->state = SND_PCM_STATE_RUNNING;
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		snd_pcm_uframes_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
Packit 4a16fb
		snd_pcm_uframes_t xfer = 0;
Packit 4a16fb
		if (hw_avail == 0) {
Packit 4a16fb
			err = -EPIPE;
Packit 4a16fb
			goto _end;
Packit 4a16fb
		}
Packit 4a16fb
		if (slave->running_count) {
Packit 4a16fb
			snd_pcm_sframes_t sd;
Packit 4a16fb
			err = snd_pcm_delay(spcm, &sd);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				goto _end;
Packit 4a16fb
			err = snd_pcm_rewind(spcm, sd);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				goto _end;
Packit 4a16fb
		}
Packit 4a16fb
		assert(share->hw_ptr == 0);
Packit 4a16fb
		share->hw_ptr = *spcm->hw.ptr;
Packit 4a16fb
		share->appl_ptr = *spcm->appl.ptr;
Packit 4a16fb
		while (xfer < hw_avail) {
Packit 4a16fb
			snd_pcm_uframes_t frames = hw_avail - xfer;
Packit 4a16fb
			snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
Packit 4a16fb
			snd_pcm_uframes_t cont = pcm->buffer_size - offset;
Packit 4a16fb
			if (cont < frames)
Packit 4a16fb
				frames = cont;
Packit 4a16fb
			if (pcm->stopped_areas != NULL)
Packit 4a16fb
				snd_pcm_areas_copy(pcm->running_areas, offset,
Packit 4a16fb
						   pcm->stopped_areas, xfer,
Packit 4a16fb
						   pcm->channels, frames,
Packit 4a16fb
						   pcm->format);
Packit 4a16fb
			xfer += frames;
Packit 4a16fb
		}
Packit 4a16fb
		snd_pcm_mmap_appl_forward(pcm, hw_avail);
Packit 4a16fb
		if (slave->running_count == 0) {
Packit 4a16fb
			snd_pcm_sframes_t res;
Packit 4a16fb
			res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
Packit 4a16fb
			if (res < 0) {
Packit 4a16fb
				err = res;
Packit 4a16fb
				goto _end;
Packit 4a16fb
			}
Packit 4a16fb
			assert((snd_pcm_uframes_t)res == hw_avail);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (slave->running_count == 0) {
Packit 4a16fb
		err = snd_pcm_start(spcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto _end;
Packit 4a16fb
	}
Packit 4a16fb
	slave->running_count++;
Packit 4a16fb
	_snd_pcm_share_update(pcm);
Packit 4a16fb
	gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENOSYS;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return -ENXIO;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	unsigned int channel = info->channel;
Packit 4a16fb
	int c = share->slave_channels[channel];
Packit 4a16fb
	int err;
Packit 4a16fb
	info->channel = c;
Packit 4a16fb
	err = snd_pcm_channel_info(slave->pcm, info);
Packit 4a16fb
	info->channel = channel;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t n;
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
		if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			return -EBADFD;
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream != SND_PCM_STREAM_CAPTURE)
Packit 4a16fb
			return -EBADFD;
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_XRUN:
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
	default:
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	}
Packit 4a16fb
	n = snd_pcm_mmap_hw_avail(pcm);
Packit 4a16fb
	assert(n >= 0);
Packit 4a16fb
	if ((snd_pcm_uframes_t)n > frames)
Packit 4a16fb
		frames = n;
Packit 4a16fb
	if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
Packit 4a16fb
		snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames);
Packit 4a16fb
		if (ret < 0)
Packit 4a16fb
			return ret;
Packit 4a16fb
		frames = ret;
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_mmap_appl_backward(pcm, frames);
Packit 4a16fb
	_snd_pcm_share_update(pcm);
Packit 4a16fb
	return n;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	ret = snd_pcm_rewindable(slave->pcm);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	ret = _snd_pcm_share_rewind(pcm, frames);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t n;
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
		if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
			return -EBADFD;
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream != SND_PCM_STREAM_CAPTURE)
Packit 4a16fb
			return -EBADFD;
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_XRUN:
Packit 4a16fb
		return -EPIPE;
Packit 4a16fb
	default:
Packit 4a16fb
		return -EBADFD;
Packit 4a16fb
	}
Packit 4a16fb
	n = snd_pcm_mmap_avail(pcm);
Packit 4a16fb
	if ((snd_pcm_uframes_t)n > frames)
Packit 4a16fb
		frames = n;
Packit 4a16fb
	if (share->state == SND_PCM_STATE_RUNNING && frames > 0) {
Packit 4a16fb
		snd_pcm_sframes_t ret = INTERNAL(snd_pcm_forward)(slave->pcm, frames);
Packit 4a16fb
		if (ret < 0)
Packit 4a16fb
			return ret;
Packit 4a16fb
		frames = ret;
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_mmap_appl_forward(pcm, frames);
Packit 4a16fb
	_snd_pcm_share_update(pcm);
Packit 4a16fb
	return n;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	ret = snd_pcm_forwardable(slave->pcm);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	snd_pcm_sframes_t ret;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	ret = _snd_pcm_share_forward(pcm, frames);
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Warning: take the mutex before to call this */
Packit 4a16fb
static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
#if 0
Packit 4a16fb
	if (!pcm->mmap_channels) {
Packit 4a16fb
		/* PCM closing already begun in the main thread */
Packit 4a16fb
		return;
Packit 4a16fb
	}
Packit 4a16fb
#endif
Packit 4a16fb
	gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
Packit 4a16fb
		snd_pcm_areas_copy(pcm->stopped_areas, 0,
Packit 4a16fb
				   pcm->running_areas, 0,
Packit 4a16fb
				   pcm->channels, pcm->buffer_size,
Packit 4a16fb
				   pcm->format);
Packit 4a16fb
	} else if (slave->running_count > 1) {
Packit 4a16fb
		int err;
Packit 4a16fb
		snd_pcm_sframes_t delay;
Packit 4a16fb
		snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
Packit 4a16fb
				      pcm->buffer_size, pcm->format);
Packit 4a16fb
		err = snd_pcm_delay(slave->pcm, &delay);
Packit 4a16fb
		if (err >= 0 && delay > 0)
Packit 4a16fb
			snd_pcm_rewind(slave->pcm, delay);
Packit 4a16fb
		share->drain_silenced = 0;
Packit 4a16fb
	}
Packit 4a16fb
	share->state = state;
Packit 4a16fb
	slave->prepared_count--;
Packit 4a16fb
	slave->running_count--;
Packit 4a16fb
	if (slave->running_count == 0) {
Packit 4a16fb
		int err = snd_pcm_drop(slave->pcm);
Packit 4a16fb
		assert(err >= 0);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_drain(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_OPEN:
Packit 4a16fb
		err = -EBADFD;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
		share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	case SND_PCM_STATE_SETUP:
Packit 4a16fb
		goto _end;
Packit 4a16fb
	default:
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		switch (share->state) {
Packit 4a16fb
		case SND_PCM_STATE_XRUN:
Packit 4a16fb
			share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
			goto _end;
Packit 4a16fb
		case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		case SND_PCM_STATE_RUNNING:
Packit 4a16fb
			share->state = SND_PCM_STATE_DRAINING;
Packit 4a16fb
			_snd_pcm_share_update(pcm);
Packit 4a16fb
			Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
			if (!(pcm->mode & SND_PCM_NONBLOCK))
Packit 4a16fb
				snd_pcm_wait(pcm, -1);
Packit 4a16fb
			return 0;
Packit 4a16fb
		default:
Packit 4a16fb
			assert(0);
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	} else {
Packit 4a16fb
		switch (share->state) {
Packit 4a16fb
		case SND_PCM_STATE_RUNNING:
Packit 4a16fb
			_snd_pcm_share_stop(pcm, SND_PCM_STATE_DRAINING);
Packit 4a16fb
			_snd_pcm_share_update(pcm);
Packit 4a16fb
			/* Fall through */
Packit 4a16fb
		case SND_PCM_STATE_XRUN:
Packit 4a16fb
		case SND_PCM_STATE_DRAINING:
Packit 4a16fb
			if (snd_pcm_mmap_capture_avail(pcm) <= 0)
Packit 4a16fb
				share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
			else
Packit 4a16fb
				share->state = SND_PCM_STATE_DRAINING;
Packit 4a16fb
			break;
Packit 4a16fb
		default:
Packit 4a16fb
			assert(0);
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_drop(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	switch (share->state) {
Packit 4a16fb
	case SND_PCM_STATE_OPEN:
Packit 4a16fb
		err = -EBADFD;
Packit 4a16fb
		goto _end;
Packit 4a16fb
	case SND_PCM_STATE_SETUP:
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_DRAINING:
Packit 4a16fb
		if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
Packit 4a16fb
			share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
		/* Fall through */
Packit 4a16fb
	case SND_PCM_STATE_RUNNING:
Packit 4a16fb
		_snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
Packit 4a16fb
		_snd_pcm_share_update(pcm);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_STATE_PREPARED:
Packit 4a16fb
	case SND_PCM_STATE_XRUN:
Packit 4a16fb
		share->state = SND_PCM_STATE_SETUP;
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		assert(0);
Packit 4a16fb
		break;
Packit 4a16fb
	}
Packit 4a16fb
	
Packit 4a16fb
	share->appl_ptr = share->hw_ptr = 0;
Packit 4a16fb
 _end:
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_close(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
	Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
	slave->open_count--;
Packit 4a16fb
	if (slave->open_count == 0) {
Packit 4a16fb
		pthread_cond_signal(&slave->poll_cond);
Packit 4a16fb
		Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
		err = pthread_join(slave->thread, 0);
Packit 4a16fb
		assert(err == 0);
Packit 4a16fb
		err = snd_pcm_close(slave->pcm);
Packit 4a16fb
		pthread_mutex_destroy(&slave->mutex);
Packit 4a16fb
		pthread_cond_destroy(&slave->poll_cond);
Packit 4a16fb
		list_del(&slave->list);
Packit 4a16fb
		free(slave);
Packit 4a16fb
		list_del(&share->list);
Packit 4a16fb
	} else {
Packit 4a16fb
		list_del(&share->list);
Packit 4a16fb
		Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
	}
Packit 4a16fb
	Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
	close(share->client_socket);
Packit 4a16fb
	close(share->slave_socket);
Packit 4a16fb
	free(share->slave_channels);
Packit 4a16fb
	free(share);
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_share_t *share = pcm->private_data;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = share->slave;
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	snd_output_printf(out, "Share PCM\n");
Packit 4a16fb
	snd_output_printf(out, "  Channel bindings:\n");
Packit 4a16fb
	for (k = 0; k < share->channels; ++k)
Packit 4a16fb
		snd_output_printf(out, "    %d: %d\n", k, share->slave_channels[k]);
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
	snd_output_printf(out, "Slave: ");
Packit 4a16fb
	snd_pcm_dump(slave->pcm, out);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_share_ops = {
Packit 4a16fb
	.close = snd_pcm_share_close,
Packit 4a16fb
	.info = snd_pcm_share_info,
Packit 4a16fb
	.hw_refine = snd_pcm_share_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_share_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_share_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_share_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_share_channel_info,
Packit 4a16fb
	.dump = snd_pcm_share_dump,
Packit 4a16fb
	.nonblock = snd_pcm_share_nonblock,
Packit 4a16fb
	.async = snd_pcm_share_async,
Packit 4a16fb
	.mmap = snd_pcm_share_mmap,
Packit 4a16fb
	.munmap = snd_pcm_share_munmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
Packit 4a16fb
	.status = snd_pcm_share_status,
Packit 4a16fb
	.state = snd_pcm_share_state,
Packit 4a16fb
	.hwsync = snd_pcm_share_hwsync,
Packit 4a16fb
	.delay = snd_pcm_share_delay,
Packit 4a16fb
	.prepare = snd_pcm_share_prepare,
Packit 4a16fb
	.reset = snd_pcm_share_reset,
Packit 4a16fb
	.start = snd_pcm_share_start,
Packit 4a16fb
	.drop = snd_pcm_share_drop,
Packit 4a16fb
	.drain = snd_pcm_share_drain,
Packit 4a16fb
	.pause = snd_pcm_share_pause,
Packit 4a16fb
	.writei = snd_pcm_mmap_writei,
Packit 4a16fb
	.writen = snd_pcm_mmap_writen,
Packit 4a16fb
	.readi = snd_pcm_mmap_readi,
Packit 4a16fb
	.readn = snd_pcm_mmap_readn,
Packit 4a16fb
	.rewindable = snd_pcm_share_rewindable,
Packit 4a16fb
	.rewind = snd_pcm_share_rewind,
Packit 4a16fb
	.forwardable = snd_pcm_share_forwardable,
Packit 4a16fb
	.forward = snd_pcm_share_forward,
Packit 4a16fb
	.resume = snd_pcm_share_resume,
Packit 4a16fb
	.avail_update = snd_pcm_share_avail_update,
Packit 4a16fb
	.htimestamp = snd_pcm_share_htimestamp,
Packit 4a16fb
	.mmap_commit = snd_pcm_share_mmap_commit,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Creates a new Share PCM
Packit 4a16fb
 * \param pcmp Returns created PCM handle
Packit 4a16fb
 * \param name Name of PCM
Packit 4a16fb
 * \param sname Slave name
Packit 4a16fb
 * \param sformat Slave format
Packit 4a16fb
 * \param srate Slave rate
Packit 4a16fb
 * \param schannels Slave channels
Packit 4a16fb
 * \param speriod_time Slave period time
Packit 4a16fb
 * \param sbuffer_time Slave buffer time
Packit 4a16fb
 * \param channels Count of channels
Packit 4a16fb
 * \param channels_map Map of channels
Packit 4a16fb
 * \param stream Direction
Packit 4a16fb
 * \param mode PCM mode
Packit 4a16fb
 * \retval zero on success otherwise a negative error code
Packit 4a16fb
 * \warning Using of this function might be dangerous in the sense
Packit 4a16fb
 *          of compatibility reasons. The prototype might be freely
Packit 4a16fb
 *          changed in future.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
Packit 4a16fb
		       snd_pcm_format_t sformat, int srate,
Packit 4a16fb
		       unsigned int schannels,
Packit 4a16fb
		       int speriod_time, int sbuffer_time,
Packit 4a16fb
		       unsigned int channels, unsigned int *channels_map,
Packit 4a16fb
		       snd_pcm_stream_t stream, int mode)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_share_t *share;
Packit 4a16fb
	int err;
Packit 4a16fb
	struct list_head *i;
Packit 4a16fb
	char slave_map[32] = { 0 };
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	snd_pcm_share_slave_t *slave = NULL;
Packit 4a16fb
	int sd[2];
Packit 4a16fb
Packit 4a16fb
	assert(pcmp);
Packit 4a16fb
	assert(channels > 0 && sname && channels_map);
Packit 4a16fb
Packit 4a16fb
	for (k = 0; k < channels; ++k) {
Packit 4a16fb
		if (channels_map[k] >= sizeof(slave_map) / sizeof(slave_map[0])) {
Packit 4a16fb
			SNDERR("Invalid slave channel (%d) in binding", channels_map[k]);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		if (slave_map[channels_map[k]]) {
Packit 4a16fb
			SNDERR("Repeated slave channel (%d) in binding", channels_map[k]);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		slave_map[channels_map[k]] = 1;
Packit 4a16fb
		assert((unsigned)channels_map[k] < schannels);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	share = calloc(1, sizeof(snd_pcm_share_t));
Packit 4a16fb
	if (!share)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	share->channels = channels;
Packit 4a16fb
	share->slave_channels = calloc(channels, sizeof(*share->slave_channels));
Packit 4a16fb
	if (!share->slave_channels) {
Packit 4a16fb
		free(share);
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
	memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels));
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(share->slave_channels);
Packit 4a16fb
		free(share);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		snd_pcm_free(pcm);
Packit 4a16fb
		free(share->slave_channels);
Packit 4a16fb
		free(share);
Packit 4a16fb
		return -errno;
Packit 4a16fb
	}
Packit 4a16fb
		
Packit 4a16fb
	if (stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		int bufsize = 1;
Packit 4a16fb
		err = setsockopt(sd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
Packit 4a16fb
		if (err >= 0) {
Packit 4a16fb
			struct pollfd pfd;
Packit 4a16fb
			pfd.fd = sd[0];
Packit 4a16fb
			pfd.events = POLLOUT;
Packit 4a16fb
			while ((err = poll(&pfd, 1, 0)) == 1) {
Packit 4a16fb
				char buf[1];
Packit 4a16fb
				err = write(sd[0], buf, 1);
Packit 4a16fb
				assert(err != 0);
Packit 4a16fb
				if (err != 1)
Packit 4a16fb
					break;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		err = -errno;
Packit 4a16fb
		close(sd[0]);
Packit 4a16fb
		close(sd[1]);
Packit 4a16fb
		snd_pcm_free(pcm);
Packit 4a16fb
		free(share->slave_channels);
Packit 4a16fb
		free(share);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
	list_for_each(i, &snd_pcm_share_slaves) {
Packit 4a16fb
		snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list);
Packit 4a16fb
		if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) {
Packit 4a16fb
			slave = s;
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (!slave) {
Packit 4a16fb
		snd_pcm_t *spcm;
Packit 4a16fb
		err = snd_pcm_open(&spcm, sname, stream, mode);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
			close(sd[0]);
Packit 4a16fb
			close(sd[1]);
Packit 4a16fb
			snd_pcm_free(pcm);
Packit 4a16fb
			free(share->slave_channels);
Packit 4a16fb
			free(share);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		/* FIXME: bellow is a real ugly hack to get things working */
Packit 4a16fb
		/* there is a memory leak somewhere, but I'm unable to trace it --jk */
Packit 4a16fb
		slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8);
Packit 4a16fb
		if (!slave) {
Packit 4a16fb
			Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
			snd_pcm_close(spcm);
Packit 4a16fb
			close(sd[0]);
Packit 4a16fb
			close(sd[1]);
Packit 4a16fb
			snd_pcm_free(pcm);
Packit 4a16fb
			free(share->slave_channels);
Packit 4a16fb
			free(share);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		INIT_LIST_HEAD(&slave->clients);
Packit 4a16fb
		slave->pcm = spcm;
Packit 4a16fb
		slave->channels = schannels;
Packit 4a16fb
		slave->format = sformat;
Packit 4a16fb
		slave->rate = srate;
Packit 4a16fb
		slave->period_time = speriod_time;
Packit 4a16fb
		slave->buffer_time = sbuffer_time;
Packit 4a16fb
		pthread_mutex_init(&slave->mutex, NULL);
Packit 4a16fb
		pthread_cond_init(&slave->poll_cond, NULL);
Packit 4a16fb
		list_add_tail(&slave->list, &snd_pcm_share_slaves);
Packit 4a16fb
		Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
		err = pthread_create(&slave->thread, NULL, snd_pcm_share_thread, slave);
Packit 4a16fb
		assert(err == 0);
Packit 4a16fb
		Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
	} else {
Packit 4a16fb
		Pthread_mutex_lock(&slave->mutex);
Packit 4a16fb
		Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
Packit 4a16fb
		list_for_each(i, &slave->clients) {
Packit 4a16fb
			snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list);
Packit 4a16fb
			for (k = 0; k < sh->channels; ++k) {
Packit 4a16fb
				if (slave_map[sh->slave_channels[k]]) {
Packit 4a16fb
					SNDERR("Slave channel %d is already in use", sh->slave_channels[k]);
Packit 4a16fb
					Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
					close(sd[0]);
Packit 4a16fb
					close(sd[1]);
Packit 4a16fb
					snd_pcm_free(pcm);
Packit 4a16fb
					free(share->slave_channels);
Packit 4a16fb
					free(share);
Packit 4a16fb
					return -EBUSY;
Packit 4a16fb
				}
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	share->slave = slave;
Packit 4a16fb
	share->pcm = pcm;
Packit 4a16fb
	share->client_socket = sd[0];
Packit 4a16fb
	share->slave_socket = sd[1];
Packit 4a16fb
	
Packit 4a16fb
	pcm->mmap_rw = 1;
Packit 4a16fb
	pcm->ops = &snd_pcm_share_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_share_fast_ops;
Packit 4a16fb
	pcm->private_data = share;
Packit 4a16fb
	pcm->poll_fd = share->client_socket;
Packit 4a16fb
	pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
Packit 4a16fb
	pcm->tstamp_type = slave->pcm->tstamp_type;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
Packit 4a16fb
Packit 4a16fb
	slave->open_count++;
Packit 4a16fb
	list_add_tail(&share->list, &slave->clients);
Packit 4a16fb
Packit 4a16fb
	Pthread_mutex_unlock(&slave->mutex);
Packit 4a16fb
Packit 4a16fb
	*pcmp = pcm;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_plugins
Packit 4a16fb
Packit 4a16fb
\section pcm_plugins_share Plugin: Share
Packit 4a16fb
Packit 4a16fb
This plugin allows sharing of multiple channels with more clients. The access
Packit 4a16fb
to each channel is exlusive (samples are not mixed together). It means, if
Packit 4a16fb
the channel zero is used with first client, the channel cannot be used with
Packit 4a16fb
second one. If you are looking for a mixing plugin, use the
Packit 4a16fb
\ref pcm_plugins_dmix "dmix plugin".
Packit 4a16fb
Packit 4a16fb
The difference from \ref pcm_plugins_dshare "dshare plugin" is that
Packit 4a16fb
share plugin requires the server program "aserver", while dshare plugin
Packit 4a16fb
doesn't need the explicit server but access to the shared buffer.
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
pcm.name {
Packit 4a16fb
        type share              # Share PCM
Packit 4a16fb
        slave STR               # Slave name
Packit 4a16fb
        # or
Packit 4a16fb
        slave {                 # Slave definition
Packit 4a16fb
                pcm STR         # Slave PCM name
Packit 4a16fb
                [format STR]    # Slave format
Packit 4a16fb
                [channels INT]  # Slave channels
Packit 4a16fb
                [rate INT]      # Slave rate
Packit 4a16fb
                [period_time INT] # Slave period time in us
Packit 4a16fb
                [buffer_time INT] # Slave buffer time in us
Packit 4a16fb
        }
Packit 4a16fb
	bindings {
Packit 4a16fb
		N INT		# Slave channel INT for client channel N
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
\subsection pcm_plugins_share_funcref Function reference
Packit 4a16fb
Packit 4a16fb
    Packit 4a16fb
      
  • snd_pcm_share_open()
  • Packit 4a16fb
      
  • _snd_pcm_share_open()
  • Packit 4a16fb
    Packit 4a16fb
    Packit 4a16fb
    */
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Creates a new Share PCM
    Packit 4a16fb
     * \param pcmp Returns created PCM handle
    Packit 4a16fb
     * \param name Name of PCM
    Packit 4a16fb
     * \param root Root configuration node
    Packit 4a16fb
     * \param conf Configuration node with Share PCM description
    Packit 4a16fb
     * \param stream Stream type
    Packit 4a16fb
     * \param mode Stream mode
    Packit 4a16fb
     * \retval zero on success otherwise a negative error code
    Packit 4a16fb
     * \warning Using of this function might be dangerous in the sense
    Packit 4a16fb
     *          of compatibility reasons. The prototype might be freely
    Packit 4a16fb
     *          changed in future.
    Packit 4a16fb
     */
    Packit 4a16fb
    int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name,
    Packit 4a16fb
    			snd_config_t *root, snd_config_t *conf,
    Packit 4a16fb
    			snd_pcm_stream_t stream, int mode)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_config_iterator_t i, next;
    Packit 4a16fb
    	const char *sname = NULL;
    Packit 4a16fb
    	snd_config_t *bindings = NULL;
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	snd_config_t *slave = NULL, *sconf;
    Packit 4a16fb
    	unsigned int *channels_map = NULL;
    Packit 4a16fb
    	unsigned int channels = 0;
    Packit 4a16fb
    	snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
    Packit 4a16fb
    	int schannels = -1;
    Packit 4a16fb
    	int srate = -1;
    Packit 4a16fb
    	int speriod_time= -1, sbuffer_time = -1;
    Packit 4a16fb
    	unsigned int schannel_max = 0;
    Packit 4a16fb
    	
    Packit 4a16fb
    	snd_config_for_each(i, next, conf) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (snd_pcm_conf_generic_id(id))
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "slave") == 0) {
    Packit 4a16fb
    			slave = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (strcmp(id, "bindings") == 0) {
    Packit 4a16fb
    			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    				SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			bindings = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!slave) {
    Packit 4a16fb
    		SNDERR("slave is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_slave_conf(root, slave, &sconf, 5,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_CHANNELS, 0, &schannels,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_RATE, 0, &srate,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time,
    Packit 4a16fb
    				 SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    Packit 4a16fb
    	/* FIXME: nothing strictly forces to have named definition */
    Packit 4a16fb
    	err = snd_config_get_string(sconf, &sname);
    Packit 4a16fb
    	sname = err >= 0 && sname ? strdup(sname) : NULL;
    Packit 4a16fb
    	snd_config_delete(sconf);
    Packit 4a16fb
    	if (sname == NULL) {
    Packit 4a16fb
    		SNDERR("slave.pcm is not a string");
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    Packit 4a16fb
    	if (!bindings) {
    Packit 4a16fb
    		SNDERR("bindings is not defined");
    Packit 4a16fb
    		err = -EINVAL;
    Packit 4a16fb
    		goto _free;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	snd_config_for_each(i, next, bindings) {
    Packit 4a16fb
    		long cchannel = -1;
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		err = safe_strtol(id, &cchannel);
    Packit 4a16fb
    		if (err < 0 || cchannel < 0) {
    Packit 4a16fb
    			SNDERR("Invalid client channel in binding: %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if ((unsigned)cchannel >= channels)
    Packit 4a16fb
    			channels = cchannel + 1;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (channels == 0) {
    Packit 4a16fb
    		SNDERR("No bindings defined");
    Packit 4a16fb
    		err = -EINVAL;
    Packit 4a16fb
    		goto _free;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	channels_map = calloc(channels, sizeof(*channels_map));
    Packit 4a16fb
    	if (! channels_map) {
    Packit 4a16fb
    		err = -ENOMEM;
    Packit 4a16fb
    		goto _free;
    Packit 4a16fb
    	}
    Packit 4a16fb
    Packit 4a16fb
    	snd_config_for_each(i, next, bindings) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		long cchannel;
    Packit 4a16fb
    		long schannel = -1;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		cchannel = atoi(id);
    Packit 4a16fb
    		err = snd_config_get_integer(n, &schannel);
    Packit 4a16fb
    		if (err < 0) {
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		assert(schannel >= 0);
    Packit 4a16fb
    		assert(schannels <= 0 || schannel < schannels);
    Packit 4a16fb
    		channels_map[cchannel] = schannel;
    Packit 4a16fb
    		if ((unsigned)schannel > schannel_max)
    Packit 4a16fb
    			schannel_max = schannel;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (schannels <= 0)
    Packit 4a16fb
    		schannels = schannel_max + 1;
    Packit 4a16fb
    	err = snd_pcm_share_open(pcmp, name, sname, sformat, srate, 
    Packit 4a16fb
    				 (unsigned int) schannels,
    Packit 4a16fb
    				 speriod_time, sbuffer_time,
    Packit 4a16fb
    				 channels, channels_map, stream, mode);
    Packit 4a16fb
    _free:
    Packit 4a16fb
    	free(channels_map);
    Packit 4a16fb
    	free((char *)sname);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif