Blame src/pcm/pcm_share.c

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