Blame src/pcm/pcm_multi.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_multi.c
Packit 4a16fb
 * \ingroup PCM_Plugins
Packit 4a16fb
 * \brief PCM Multi Streams to One Conversion Plugin Interface
Packit 4a16fb
 * \author Abramo Bagnara <abramo@alsa-project.org>
Packit 4a16fb
 * \date 2000-2001
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - Multi
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 <unistd.h>
Packit 4a16fb
#include <string.h>
Packit 4a16fb
#include <math.h>
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_generic.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_multi = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	unsigned int channels_count;
Packit 4a16fb
	int close_slave;
Packit 4a16fb
	snd_pcm_t *linked;
Packit 4a16fb
} snd_pcm_multi_slave_t;
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	int slave_idx;
Packit 4a16fb
	unsigned int slave_channel;
Packit 4a16fb
} snd_pcm_multi_channel_t;
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	snd_pcm_uframes_t appl_ptr, hw_ptr;
Packit 4a16fb
	unsigned int slaves_count;
Packit 4a16fb
	unsigned int master_slave;
Packit 4a16fb
	snd_pcm_multi_slave_t *slaves;
Packit 4a16fb
	unsigned int channels_count;
Packit 4a16fb
	snd_pcm_multi_channel_t *channels;
Packit 4a16fb
} snd_pcm_multi_t;
Packit 4a16fb
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_close(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int ret = 0;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_multi_slave_t *slave = &multi->slaves[i];
Packit 4a16fb
		if (slave->close_slave) {
Packit 4a16fb
			int err = snd_pcm_close(slave->pcm);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				ret = err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	free(multi->slaves);
Packit 4a16fb
	free(multi->channels);
Packit 4a16fb
	free(multi);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_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_multi_async(snd_pcm_t *pcm, int sig, pid_t pid)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_async(slave_0, sig, pid);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_poll_descriptors_count(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_poll_descriptors_count(slave_0);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave;
Packit 4a16fb
	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		slave = multi->slaves[i].pcm;
Packit 4a16fb
		if (slave == slave_0)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_poll_descriptors(slave, pfds, space);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	/* finally overwrite with master's pfds */
Packit 4a16fb
	return snd_pcm_poll_descriptors(slave_0, pfds, space);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_poll_descriptors_revents(slave_0, pfds, nfds, revents);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err, n;
Packit 4a16fb
	assert(info->subdevice < multi->slaves_count);
Packit 4a16fb
	n = info->subdevice;
Packit 4a16fb
	info->subdevice = 0;
Packit 4a16fb
	err = snd_pcm_info(multi->slaves[n].pcm, info);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	info->subdevices_count = multi->slaves_count;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
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
				    multi->channels_count, 0);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	params->info = ~0U;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, unsigned int slave_idx,
Packit 4a16fb
					    snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx];
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_count, 0);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
Packit 4a16fb
					   unsigned int slave_idx ATTRIBUTE_UNUSED,
Packit 4a16fb
					   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_PERIODS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_TICK_TIME);
Packit 4a16fb
	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_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
Packit 4a16fb
					   unsigned int slave_idx ATTRIBUTE_UNUSED,
Packit 4a16fb
					   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_PERIODS |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_BUFFER_TIME |
Packit 4a16fb
			      SND_PCM_HW_PARBIT_TICK_TIME);
Packit 4a16fb
	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
	params->info &= sparams->info;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm,
Packit 4a16fb
					 unsigned int slave_idx,
Packit 4a16fb
					 snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
Packit 4a16fb
	return snd_pcm_hw_refine(slave, sparams);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	snd_pcm_hw_params_t sparams[multi->slaves_count];
Packit 4a16fb
	int err;
Packit 4a16fb
	unsigned int cmask, changed;
Packit 4a16fb
	err = snd_pcm_multi_hw_refine_cprepare(pcm, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	for (k = 0; k < multi->slaves_count; ++k) {
Packit 4a16fb
		err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			SNDERR("Slave PCM #%d not usable", k);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	do {
Packit 4a16fb
		cmask = params->cmask;
Packit 4a16fb
		params->cmask = 0;
Packit 4a16fb
		for (k = 0; k < multi->slaves_count; ++k) {
Packit 4a16fb
			err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
Packit 4a16fb
			if (err >= 0)
Packit 4a16fb
				err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
		err = snd_pcm_hw_refine_soft(pcm, params);
Packit 4a16fb
		changed = params->cmask;
Packit 4a16fb
		params->cmask |= cmask;
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	} while (changed);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm,
Packit 4a16fb
					 unsigned int slave_idx,
Packit 4a16fb
					 snd_pcm_hw_params_t *sparams)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
Packit 4a16fb
	int err = snd_pcm_hw_params(slave, sparams);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	if (slave->stopped_areas) {
Packit 4a16fb
		err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* reset links to the normal state
Packit 4a16fb
 * slave #0 = trigger master
Packit 4a16fb
 * slave #1-(N-1) = trigger slaves, linked is set to #0
Packit 4a16fb
 */
Packit 4a16fb
static void reset_links(snd_pcm_multi_t *multi)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			snd_pcm_unlink(multi->slaves[i].linked);
Packit 4a16fb
		multi->slaves[0].linked = NULL;
Packit 4a16fb
		if (! i)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0)
Packit 4a16fb
			multi->slaves[i].linked = multi->slaves[0].pcm;
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_hw_params_t sparams[multi->slaves_count];
Packit 4a16fb
	int err;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]);
Packit 4a16fb
		assert(err >= 0);
Packit 4a16fb
		err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]);
Packit 4a16fb
		assert(err >= 0);
Packit 4a16fb
		err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	reset_links(multi);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hw_free(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave = multi->slaves[i].pcm;
Packit 4a16fb
		int e = snd_pcm_hw_free(slave);
Packit 4a16fb
		if (e < 0)
Packit 4a16fb
			err = e;
Packit 4a16fb
		if (!multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		e = snd_pcm_unlink(slave);
Packit 4a16fb
		if (e < 0)
Packit 4a16fb
			err = e;
Packit 4a16fb
		multi->slaves[i].linked = NULL;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave = multi->slaves[i].pcm;
Packit 4a16fb
		err = snd_pcm_sw_params(slave, params);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_status(slave, status);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_state(slave);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_multi_hwptr_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_uframes_t hw_ptr = 0, slave_hw_ptr, avail, last_avail;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	/* the logic is really simple, choose the lowest hw_ptr from slaves */
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit 4a16fb
		last_avail = 0;
Packit 4a16fb
		for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
			slave_hw_ptr = *multi->slaves[i].pcm->hw.ptr;
Packit 4a16fb
			avail = __snd_pcm_playback_avail(pcm, multi->hw_ptr, slave_hw_ptr);
Packit 4a16fb
			if (avail > last_avail) {
Packit 4a16fb
				hw_ptr = slave_hw_ptr;
Packit 4a16fb
				last_avail = avail;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	} else {
Packit 4a16fb
		last_avail = LONG_MAX;
Packit 4a16fb
		for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
			slave_hw_ptr = *multi->slaves[i].pcm->hw.ptr;
Packit 4a16fb
			avail = __snd_pcm_capture_avail(pcm, multi->hw_ptr, slave_hw_ptr);
Packit 4a16fb
			if (avail < last_avail) {
Packit 4a16fb
				hw_ptr = slave_hw_ptr;
Packit 4a16fb
				last_avail = avail;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	multi->hw_ptr = hw_ptr;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_hwsync(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		err = snd_pcm_hwsync(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_multi_hwptr_update(pcm);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t d, dr = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		err = snd_pcm_delay(multi->slaves[i].pcm, &d);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (dr < d)
Packit 4a16fb
			dr = d;
Packit 4a16fb
	}
Packit 4a16fb
	*delayp = dr;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_sframes_t ret = LONG_MAX;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_sframes_t avail;
Packit 4a16fb
		avail = snd_pcm_avail_update(multi->slaves[i].pcm);
Packit 4a16fb
		if (avail < 0)
Packit 4a16fb
			return avail;
Packit 4a16fb
		if (ret > avail)
Packit 4a16fb
			ret = avail;
Packit 4a16fb
	}
Packit 4a16fb
	snd_pcm_multi_hwptr_update(pcm);
Packit 4a16fb
	return ret;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
Packit 4a16fb
				    snd_htimestamp_t *tstamp)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
Packit 4a16fb
	return snd_pcm_htimestamp(slave, avail, tstamp);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int result = 0, err;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		/* We call prepare to each slave even if it's linked.
Packit 4a16fb
		 * This is to make sure to sync non-mmaped control/status.
Packit 4a16fb
		 */
Packit 4a16fb
		err = snd_pcm_prepare(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			result = err;
Packit 4a16fb
	}
Packit 4a16fb
	multi->hw_ptr = multi->appl_ptr = 0;
Packit 4a16fb
	return result;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_reset(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int result = 0, err;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		/* Reset each slave, as well as in prepare */
Packit 4a16fb
		err = snd_pcm_reset(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0) 
Packit 4a16fb
			result = err;
Packit 4a16fb
	}
Packit 4a16fb
	multi->hw_ptr = multi->appl_ptr = 0;
Packit 4a16fb
	return result;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* when the first slave PCM is linked, it means that the whole multi
Packit 4a16fb
 * plugin instance is linked manually to another PCM.  in this case,
Packit 4a16fb
 * we need to trigger the master.
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_multi_start(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	if (multi->slaves[0].linked)
Packit 4a16fb
		return snd_pcm_start(multi->slaves[0].linked);
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_start(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_drop(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	if (multi->slaves[0].linked)
Packit 4a16fb
		return snd_pcm_drop(multi->slaves[0].linked);
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_drop(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_drain(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	if (multi->slaves[0].linked)
Packit 4a16fb
		return snd_pcm_drain(multi->slaves[0].linked);
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_drain(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	if (multi->slaves[0].linked)
Packit 4a16fb
		return snd_pcm_pause(multi->slaves[0].linked, enable);
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_pause(multi->slaves[i].pcm, enable);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int channel = info->channel;
Packit 4a16fb
	snd_pcm_multi_channel_t *c = &multi->channels[channel];
Packit 4a16fb
	int err;
Packit 4a16fb
	if (c->slave_idx < 0)
Packit 4a16fb
		return -ENXIO;
Packit 4a16fb
	info->channel = c->slave_channel;
Packit 4a16fb
	err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info);
Packit 4a16fb
	info->channel = channel;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_rewindable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_sframes_t frames = LONG_MAX;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_sframes_t f = snd_pcm_rewindable(multi->slaves[i].pcm);
Packit 4a16fb
		if (f <= 0)
Packit 4a16fb
			return f;
Packit 4a16fb
		if (f < frames)
Packit 4a16fb
			frames = f;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return frames;
Packit 4a16fb
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_forwardable(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_sframes_t frames = LONG_MAX;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_sframes_t f = snd_pcm_forwardable(multi->slaves[i].pcm);
Packit 4a16fb
		if (f <= 0)
Packit 4a16fb
			return f;
Packit 4a16fb
		if (f < frames)
Packit 4a16fb
			frames = f;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return frames;
Packit 4a16fb
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_uframes_t pos[multi->slaves_count];
Packit 4a16fb
	memset(pos, 0, sizeof(pos));
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave_i = multi->slaves[i].pcm;
Packit 4a16fb
		snd_pcm_sframes_t f = snd_pcm_rewind(slave_i, frames);
Packit 4a16fb
		if (f < 0)
Packit 4a16fb
			return f;
Packit 4a16fb
		pos[i] = f;
Packit 4a16fb
		frames = f;
Packit 4a16fb
	}
Packit 4a16fb
	/* Realign the pointers */
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave_i = multi->slaves[i].pcm;
Packit 4a16fb
		snd_pcm_uframes_t f = pos[i] - frames;
Packit 4a16fb
		snd_pcm_sframes_t result;
Packit 4a16fb
		if (f > 0) {
Packit 4a16fb
			result = INTERNAL(snd_pcm_forward)(slave_i, f);
Packit 4a16fb
			if (result < 0)
Packit 4a16fb
				return result;
Packit 4a16fb
			if ((snd_pcm_uframes_t)result != f)
Packit 4a16fb
				return -EIO;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_uframes_t pos[multi->slaves_count];
Packit 4a16fb
	memset(pos, 0, sizeof(pos));
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave_i = multi->slaves[i].pcm;
Packit 4a16fb
		snd_pcm_sframes_t f = INTERNAL(snd_pcm_forward)(slave_i, frames);
Packit 4a16fb
		if (f < 0)
Packit 4a16fb
			return f;
Packit 4a16fb
		pos[i] = f;
Packit 4a16fb
		frames = f;
Packit 4a16fb
	}
Packit 4a16fb
	/* Realign the pointers */
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_t *slave_i = multi->slaves[i].pcm;
Packit 4a16fb
		snd_pcm_uframes_t f = pos[i] - frames;
Packit 4a16fb
		snd_pcm_sframes_t result;
Packit 4a16fb
		if (f > 0) {
Packit 4a16fb
			result = snd_pcm_rewind(slave_i, f);
Packit 4a16fb
			if (result < 0)
Packit 4a16fb
				return result;
Packit 4a16fb
			if ((snd_pcm_uframes_t)result != f)
Packit 4a16fb
				return -EIO;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_resume(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	if (multi->slaves[0].linked)
Packit 4a16fb
		return snd_pcm_resume(multi->slaves[0].linked);
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_pcm_resume(multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* if a multi plugin instance is linked as slaves, every slave PCMs
Packit 4a16fb
 * including the first one has to be relinked to the given master.
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
Packit 4a16fb
{ 
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_unlink(multi->slaves[i].pcm);
Packit 4a16fb
		multi->slaves[i].linked = NULL;
Packit 4a16fb
		err = snd_pcm_link(master, multi->slaves[i].pcm);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			reset_links(multi);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		multi->slaves[i].linked = master;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* linking to a multi as a master is easy - simply link to the first
Packit 4a16fb
 * slave element as its own slaves are already linked.
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm1->private_data;
Packit 4a16fb
	if (multi->slaves[0].pcm->fast_ops->link)
Packit 4a16fb
		return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2);
Packit 4a16fb
	return -ENOSYS;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (multi->slaves[i].linked)
Packit 4a16fb
			snd_pcm_unlink(multi->slaves[i].linked);
Packit 4a16fb
		multi->slaves[0].linked = NULL;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_multi_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_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_sframes_t result;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		slave = multi->slaves[i].pcm;
Packit 4a16fb
		result = snd_pcm_mmap_commit(slave, offset, size);
Packit 4a16fb
		if (result < 0)
Packit 4a16fb
			return result;
Packit 4a16fb
		if ((snd_pcm_uframes_t)result != size)
Packit 4a16fb
			return -EIO;
Packit 4a16fb
	}
Packit 4a16fb
	multi->appl_ptr += size;
Packit 4a16fb
	multi->appl_ptr %= pcm->boundary;
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	free(pcm->mmap_channels);
Packit 4a16fb
	free(pcm->running_areas);
Packit 4a16fb
	pcm->mmap_channels = NULL;
Packit 4a16fb
	pcm->running_areas = NULL;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int c;
Packit 4a16fb
Packit 4a16fb
	pcm->mmap_channels = calloc(pcm->channels,
Packit 4a16fb
				    sizeof(pcm->mmap_channels[0]));
Packit 4a16fb
	pcm->running_areas = calloc(pcm->channels,
Packit 4a16fb
				    sizeof(pcm->running_areas[0]));
Packit 4a16fb
	if (!pcm->mmap_channels || !pcm->running_areas) {
Packit 4a16fb
		snd_pcm_multi_munmap(pcm);
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* Copy the slave mmapped buffer data */
Packit 4a16fb
	for (c = 0; c < pcm->channels; c++) {
Packit 4a16fb
		snd_pcm_multi_channel_t *chan = &multi->channels[c];
Packit 4a16fb
		snd_pcm_t *slave;
Packit 4a16fb
		if (chan->slave_idx < 0) {
Packit 4a16fb
			snd_pcm_multi_munmap(pcm);
Packit 4a16fb
			return -ENXIO;
Packit 4a16fb
		}
Packit 4a16fb
		slave = multi->slaves[chan->slave_idx].pcm;
Packit 4a16fb
		pcm->mmap_channels[c] =
Packit 4a16fb
			slave->mmap_channels[chan->slave_channel];
Packit 4a16fb
		pcm->mmap_channels[c].channel = c;
Packit 4a16fb
		pcm->running_areas[c] =
Packit 4a16fb
			slave->running_areas[chan->slave_channel];
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; ++i) {
Packit 4a16fb
		if (snd_pcm_may_wait_for_avail_min(multi->slaves[i].pcm, avail))
Packit 4a16fb
			return 1;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_chmap_query_t **slave_maps[multi->slaves_count];
Packit 4a16fb
	snd_pcm_chmap_query_t **maps;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err = -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	memset(slave_maps, 0, sizeof(slave_maps));
Packit 4a16fb
	maps = calloc(2, sizeof(*maps));
Packit 4a16fb
	if (!maps)
Packit 4a16fb
		return NULL;
Packit 4a16fb
	maps[0] = calloc(multi->channels_count + 2, sizeof(int *));
Packit 4a16fb
	if (!maps[0])
Packit 4a16fb
		goto error;
Packit 4a16fb
	maps[0]->type = SND_CHMAP_TYPE_FIXED;
Packit 4a16fb
	maps[0]->map.channels = multi->channels_count;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++) {
Packit 4a16fb
		slave_maps[i] = snd_pcm_query_chmaps(multi->slaves[i].pcm);
Packit 4a16fb
		if (!slave_maps[i])
Packit 4a16fb
			goto error;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->channels_count; i++) {
Packit 4a16fb
		snd_pcm_multi_channel_t *bind = &multi->channels[i];
Packit 4a16fb
		unsigned int slave_channels =
Packit 4a16fb
			multi->slaves[bind->slave_idx].channels_count;
Packit 4a16fb
		snd_pcm_chmap_query_t **p;
Packit 4a16fb
Packit 4a16fb
		for (p = slave_maps[bind->slave_idx]; *p; p++) {
Packit 4a16fb
			if ((*p)->map.channels == slave_channels) {
Packit 4a16fb
				maps[0]->map.pos[i] =
Packit 4a16fb
					(*p)->map.pos[bind->slave_channel];
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	err = 0;
Packit 4a16fb
Packit 4a16fb
 error:
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++) {
Packit 4a16fb
		if (slave_maps[i])
Packit 4a16fb
			snd_pcm_free_chmaps(slave_maps[i]);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (err) {
Packit 4a16fb
		snd_pcm_free_chmaps(maps);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return maps;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_chmap_t *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_chmap_t *map;
Packit 4a16fb
	snd_pcm_chmap_t *slave_maps[multi->slaves_count];
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err = -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	memset(slave_maps, 0, sizeof(slave_maps));
Packit 4a16fb
	map = calloc(multi->channels_count + 1, sizeof(int));
Packit 4a16fb
	if (!map)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++) {
Packit 4a16fb
		slave_maps[i] = snd_pcm_get_chmap(multi->slaves[i].pcm);
Packit 4a16fb
		if (!slave_maps[i])
Packit 4a16fb
			goto error;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	map->channels = multi->channels_count;
Packit 4a16fb
	for (i = 0; i < multi->channels_count; i++) {
Packit 4a16fb
		snd_pcm_multi_channel_t *bind = &multi->channels[i];
Packit 4a16fb
		map->pos[i] = slave_maps[bind->slave_idx]->pos[bind->slave_channel];
Packit 4a16fb
	}
Packit 4a16fb
	err = 0;
Packit 4a16fb
Packit 4a16fb
 error:
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++)
Packit 4a16fb
		free(slave_maps[i]);
Packit 4a16fb
Packit 4a16fb
	if (err) {
Packit 4a16fb
		free(map);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return map;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	snd_pcm_chmap_t *slave_maps[multi->slaves_count];
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	if (map->channels != multi->channels_count)
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++) {
Packit 4a16fb
		slave_maps[i] = calloc(multi->slaves[i].channels_count + 1,
Packit 4a16fb
				       sizeof(int));
Packit 4a16fb
		if (!slave_maps[i]) {
Packit 4a16fb
			for (i++; i < multi->slaves_count; i++)
Packit 4a16fb
				slave_maps[i] = NULL;
Packit 4a16fb
			err = -ENOMEM;
Packit 4a16fb
			goto error;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->channels_count; i++) {
Packit 4a16fb
		snd_pcm_multi_channel_t *bind = &multi->channels[i];
Packit 4a16fb
		slave_maps[bind->slave_idx]->pos[bind->slave_channel] =
Packit 4a16fb
			map->pos[i];
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++) {
Packit 4a16fb
		err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_maps[i]);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			goto error;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
 error:
Packit 4a16fb
	for (i = 0; i < multi->slaves_count; i++)
Packit 4a16fb
		free(slave_maps[i]);
Packit 4a16fb
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_multi_t *multi = pcm->private_data;
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	snd_output_printf(out, "Multi PCM\n");
Packit 4a16fb
	snd_output_printf(out, "  Channel bindings:\n");
Packit 4a16fb
	for (k = 0; k < multi->channels_count; ++k) {
Packit 4a16fb
		snd_pcm_multi_channel_t *c = &multi->channels[k];
Packit 4a16fb
		if (c->slave_idx < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
		snd_output_printf(out, "    %d: slave %d, channel %d\n", 
Packit 4a16fb
			k, c->slave_idx, c->slave_channel);
Packit 4a16fb
	}
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
	for (k = 0; k < multi->slaves_count; ++k) {
Packit 4a16fb
		snd_output_printf(out, "Slave #%d: ", k);
Packit 4a16fb
		snd_pcm_dump(multi->slaves[k].pcm, out);
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_multi_ops = {
Packit 4a16fb
	.close = snd_pcm_multi_close,
Packit 4a16fb
	.info = snd_pcm_multi_info,
Packit 4a16fb
	.hw_refine = snd_pcm_multi_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_multi_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_multi_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_multi_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_multi_channel_info,
Packit 4a16fb
	.dump = snd_pcm_multi_dump,
Packit 4a16fb
	.nonblock = snd_pcm_multi_nonblock,
Packit 4a16fb
	.async = snd_pcm_multi_async,
Packit 4a16fb
	.mmap = snd_pcm_multi_mmap,
Packit 4a16fb
	.munmap = snd_pcm_multi_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_multi_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_multi_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_multi_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
Packit 4a16fb
	.status = snd_pcm_multi_status,
Packit 4a16fb
	.state = snd_pcm_multi_state,
Packit 4a16fb
	.hwsync = snd_pcm_multi_hwsync,
Packit 4a16fb
	.delay = snd_pcm_multi_delay,
Packit 4a16fb
	.prepare = snd_pcm_multi_prepare,
Packit 4a16fb
	.reset = snd_pcm_multi_reset,
Packit 4a16fb
	.start = snd_pcm_multi_start,
Packit 4a16fb
	.drop = snd_pcm_multi_drop,
Packit 4a16fb
	.drain = snd_pcm_multi_drain,
Packit 4a16fb
	.pause = snd_pcm_multi_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_multi_rewindable,
Packit 4a16fb
	.rewind = snd_pcm_multi_rewind,
Packit 4a16fb
	.forwardable = snd_pcm_multi_forwardable,
Packit 4a16fb
	.forward = snd_pcm_multi_forward,
Packit 4a16fb
	.resume = snd_pcm_multi_resume,
Packit 4a16fb
	.link = snd_pcm_multi_link,
Packit 4a16fb
	.link_slaves = snd_pcm_multi_link_slaves,
Packit 4a16fb
	.unlink = snd_pcm_multi_unlink,
Packit 4a16fb
	.avail_update = snd_pcm_multi_avail_update,
Packit 4a16fb
	.mmap_commit = snd_pcm_multi_mmap_commit,
Packit 4a16fb
	.htimestamp = snd_pcm_multi_htimestamp,
Packit 4a16fb
	.poll_descriptors_count = snd_pcm_multi_poll_descriptors_count,
Packit 4a16fb
	.poll_descriptors = snd_pcm_multi_poll_descriptors,
Packit 4a16fb
	.poll_revents = snd_pcm_multi_poll_revents,
Packit 4a16fb
	.may_wait_for_avail_min = snd_pcm_multi_may_wait_for_avail_min,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Creates a new Multi PCM
Packit 4a16fb
 * \param pcmp Returns created PCM handle
Packit 4a16fb
 * \param name Name of PCM
Packit 4a16fb
 * \param slaves_count Count of slaves
Packit 4a16fb
 * \param master_slave Master slave number
Packit 4a16fb
 * \param slaves_pcm Array with slave PCMs
Packit 4a16fb
 * \param schannels_count Array with slave channel counts
Packit 4a16fb
 * \param channels_count Count of channels
Packit 4a16fb
 * \param sidxs Array with channels indexes to slaves
Packit 4a16fb
 * \param schannels Array with slave channels
Packit 4a16fb
 * \param close_slaves When set, the slave PCM handle is closed
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_multi_open(snd_pcm_t **pcmp, const char *name,
Packit 4a16fb
		       unsigned int slaves_count, unsigned int master_slave,
Packit 4a16fb
		       snd_pcm_t **slaves_pcm, unsigned int *schannels_count,
Packit 4a16fb
		       unsigned int channels_count,
Packit 4a16fb
		       int *sidxs, unsigned int *schannels,
Packit 4a16fb
		       int close_slaves)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_multi_t *multi;
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
	snd_pcm_stream_t stream;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	assert(pcmp);
Packit 4a16fb
	assert(slaves_count > 0 && slaves_pcm && schannels_count);
Packit 4a16fb
	assert(channels_count > 0 && sidxs && schannels);
Packit 4a16fb
	assert(master_slave < slaves_count);
Packit 4a16fb
Packit 4a16fb
	multi = calloc(1, sizeof(snd_pcm_multi_t));
Packit 4a16fb
	if (!multi) {
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	stream = slaves_pcm[0]->stream;
Packit 4a16fb
	
Packit 4a16fb
	multi->slaves_count = slaves_count;
Packit 4a16fb
	multi->master_slave = master_slave;
Packit 4a16fb
	multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
Packit 4a16fb
	if (!multi->slaves) {
Packit 4a16fb
		free(multi);
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
	multi->channels_count = channels_count;
Packit 4a16fb
	multi->channels = calloc(channels_count, sizeof(*multi->channels));
Packit 4a16fb
	if (!multi->channels) {
Packit 4a16fb
		free(multi->slaves);
Packit 4a16fb
		free(multi);
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	}
Packit 4a16fb
	for (i = 0; i < slaves_count; ++i) {
Packit 4a16fb
		snd_pcm_multi_slave_t *slave = &multi->slaves[i];
Packit 4a16fb
		assert(slaves_pcm[i]->stream == stream);
Packit 4a16fb
		slave->pcm = slaves_pcm[i];
Packit 4a16fb
		slave->channels_count = schannels_count[i];
Packit 4a16fb
		slave->close_slave = close_slaves;
Packit 4a16fb
	}
Packit 4a16fb
	for (i = 0; i < channels_count; ++i) {
Packit 4a16fb
		snd_pcm_multi_channel_t *bind = &multi->channels[i];
Packit 4a16fb
		assert(sidxs[i] < (int)slaves_count);
Packit 4a16fb
		assert(schannels[i] < schannels_count[sidxs[i]]);
Packit 4a16fb
		bind->slave_idx = sidxs[i];
Packit 4a16fb
		bind->slave_channel = schannels[i];
Packit 4a16fb
		if (sidxs[i] < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
	}
Packit 4a16fb
	multi->channels_count = channels_count;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream,
Packit 4a16fb
			  multi->slaves[0].pcm->mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(multi->slaves);
Packit 4a16fb
		free(multi->channels);
Packit 4a16fb
		free(multi);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	pcm->mmap_rw = 1;
Packit 4a16fb
	pcm->mmap_shadow = 1; /* has own mmap method */
Packit 4a16fb
	pcm->ops = &snd_pcm_multi_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_multi_fast_ops;
Packit 4a16fb
	pcm->private_data = multi;
Packit 4a16fb
	pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
Packit 4a16fb
	pcm->poll_events = multi->slaves[master_slave].pcm->poll_events;
Packit 4a16fb
	pcm->tstamp_type = multi->slaves[master_slave].pcm->tstamp_type;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &multi->hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &multi->appl_ptr, -1, 0);
Packit 4a16fb
	*pcmp = pcm;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_plugins
Packit 4a16fb
Packit 4a16fb
\section pcm_plugins_multi Plugin: Multiple streams to One
Packit 4a16fb
Packit 4a16fb
This plugin converts multiple streams to one.
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
pcm.name {
Packit 4a16fb
        type multi              # Multiple streams conversion PCM
Packit 4a16fb
        slaves {		# Slaves definition
Packit 4a16fb
		ID STR		# Slave PCM name
Packit 4a16fb
		# or
Packit 4a16fb
		ID {
Packit 4a16fb
			pcm STR		# Slave PCM name
Packit 4a16fb
			# or
Packit 4a16fb
			pcm { } 	# Slave PCM definition
Packit 4a16fb
			channels INT	# Slave channels
Packit 4a16fb
		}
Packit 4a16fb
        }
Packit 4a16fb
	bindings {		# Bindings table
Packit 4a16fb
		N {
Packit 4a16fb
			slave STR	# Slave key
Packit 4a16fb
			channel INT	# Slave channel
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	[master INT]		# Define the master slave
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
For example, to bind two PCM streams with two-channel stereo (hw:0,0 and
Packit 4a16fb
hw:0,1) as one 4-channel stereo PCM stream, define like this:
Packit 4a16fb
\code
Packit 4a16fb
pcm.quad {
Packit 4a16fb
	type multi
Packit 4a16fb
Packit 4a16fb
	slaves.a.pcm "hw:0,0"
Packit 4a16fb
	slaves.a.channels 2
Packit 4a16fb
	slaves.b.pcm "hw:0,1"
Packit 4a16fb
	slaves.b.channels 2
Packit 4a16fb
Packit 4a16fb
	bindings.0.slave a
Packit 4a16fb
	bindings.0.channel 0
Packit 4a16fb
	bindings.1.slave a
Packit 4a16fb
	bindings.1.channel 1
Packit 4a16fb
	bindings.2.slave b
Packit 4a16fb
	bindings.2.channel 0
Packit 4a16fb
	bindings.3.slave b
Packit 4a16fb
	bindings.3.channel 1
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Note that the resultant pcm "quad" is not in the interleaved format
Packit 4a16fb
but in the "complex" format.  Hence, it's not accessible by applications
Packit 4a16fb
which can handle only the interleaved (or the non-interleaved) format.
Packit 4a16fb
In such a case, wrap this PCM with \ref pcm_plugins_route "route" or
Packit 4a16fb
\ref pcm_plugins_plug "plug" plugin.
Packit 4a16fb
\code
Packit 4a16fb
pcm.quad2 {
Packit 4a16fb
	type route
Packit 4a16fb
	slave.pcm "quad"
Packit 4a16fb
	ttable.0.0 1
Packit 4a16fb
	ttable.1.1 1
Packit 4a16fb
	ttable.2.2 1
Packit 4a16fb
	ttable.3.3 1
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
\subsection pcm_plugins_multi_funcref Function reference
Packit 4a16fb
Packit 4a16fb
    Packit 4a16fb
      
  • snd_pcm_multi_open()
  • Packit 4a16fb
      
  • _snd_pcm_multi_open()
  • Packit 4a16fb
    Packit 4a16fb
    Packit 4a16fb
    */
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Creates a new Multi 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 Multi 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_multi_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, inext, j, jnext;
    Packit 4a16fb
    	snd_config_t *slaves = NULL;
    Packit 4a16fb
    	snd_config_t *bindings = NULL;
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	unsigned int idx;
    Packit 4a16fb
    	const char **slaves_id = NULL;
    Packit 4a16fb
    	snd_config_t **slaves_conf = NULL;
    Packit 4a16fb
    	snd_pcm_t **slaves_pcm = NULL;
    Packit 4a16fb
    	unsigned int *slaves_channels = NULL;
    Packit 4a16fb
    	int *channels_sidx = NULL;
    Packit 4a16fb
    	unsigned int *channels_schannel = NULL;
    Packit 4a16fb
    	unsigned int slaves_count = 0;
    Packit 4a16fb
    	long master_slave = 0;
    Packit 4a16fb
    	unsigned int channels_count = 0;
    Packit 4a16fb
    	snd_config_for_each(i, inext, 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, "slaves") == 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
    			slaves = 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
    		if (strcmp(id, "master") == 0) {
    Packit 4a16fb
    			if (snd_config_get_integer(n, &master_slave) < 0) {
    Packit 4a16fb
    				SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!slaves) {
    Packit 4a16fb
    		SNDERR("slaves is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!bindings) {
    Packit 4a16fb
    		SNDERR("bindings is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	snd_config_for_each(i, inext, slaves) {
    Packit 4a16fb
    		++slaves_count;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (master_slave < 0 || master_slave >= (long)slaves_count) {
    Packit 4a16fb
    		SNDERR("Master slave is out of range (0-%u)\n", slaves_count-1);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	snd_config_for_each(i, inext, bindings) {
    Packit 4a16fb
    		long cchannel;
    Packit 4a16fb
    		snd_config_t *m = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(m, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		err = safe_strtol(id, &cchannel);
    Packit 4a16fb
    		if (err < 0 || cchannel < 0) {
    Packit 4a16fb
    			SNDERR("Invalid channel number: %s", id);
    Packit 4a16fb
    			return -EINVAL;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if ((unsigned long)cchannel >= channels_count)
    Packit 4a16fb
    			channels_count = cchannel + 1;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (channels_count == 0) {
    Packit 4a16fb
    		SNDERR("No channels defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	slaves_id = calloc(slaves_count, sizeof(*slaves_id));
    Packit 4a16fb
    	slaves_conf = calloc(slaves_count, sizeof(*slaves_conf));
    Packit 4a16fb
    	slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm));
    Packit 4a16fb
    	slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
    Packit 4a16fb
    	channels_sidx = calloc(channels_count, sizeof(*channels_sidx));
    Packit 4a16fb
    	channels_schannel = calloc(channels_count, sizeof(*channels_schannel));
    Packit 4a16fb
    	if (!slaves_id || !slaves_conf || !slaves_pcm || !slaves_channels ||
    Packit 4a16fb
    	    !channels_sidx || !channels_schannel) {
    Packit 4a16fb
    		err = -ENOMEM;
    Packit 4a16fb
    		goto _free;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	idx = 0;
    Packit 4a16fb
    	for (idx = 0; idx < channels_count; ++idx)
    Packit 4a16fb
    		channels_sidx[idx] = -1;
    Packit 4a16fb
    	idx = 0;
    Packit 4a16fb
    	snd_config_for_each(i, inext, slaves) {
    Packit 4a16fb
    		snd_config_t *m = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		int channels;
    Packit 4a16fb
    		if (snd_config_get_id(m, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		slaves_id[idx] = id;
    Packit 4a16fb
    		err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1,
    Packit 4a16fb
    					 SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels);
    Packit 4a16fb
    		if (err < 0)
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		slaves_channels[idx] = channels;
    Packit 4a16fb
    		++idx;
    Packit 4a16fb
    	}
    Packit 4a16fb
    Packit 4a16fb
    	snd_config_for_each(i, inext, bindings) {
    Packit 4a16fb
    		snd_config_t *m = snd_config_iterator_entry(i);
    Packit 4a16fb
    		long cchannel = -1;
    Packit 4a16fb
    		long schannel = -1;
    Packit 4a16fb
    		int slave = -1;
    Packit 4a16fb
    		long val;
    Packit 4a16fb
    		const char *str;
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(m, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		err = safe_strtol(id, &cchannel);
    Packit 4a16fb
    		if (err < 0 || cchannel < 0) {
    Packit 4a16fb
    			SNDERR("Invalid channel number: %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		snd_config_for_each(j, jnext, m) {
    Packit 4a16fb
    			snd_config_t *n = snd_config_iterator_entry(j);
    Packit 4a16fb
    			const char *id;
    Packit 4a16fb
    			if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			if (strcmp(id, "comment") == 0)
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			if (strcmp(id, "slave") == 0) {
    Packit 4a16fb
    				char buf[32];
    Packit 4a16fb
    				unsigned int k;
    Packit 4a16fb
    				err = snd_config_get_string(n, &str);
    Packit 4a16fb
    				if (err < 0) {
    Packit 4a16fb
    					err = snd_config_get_integer(n, &val;;
    Packit 4a16fb
    					if (err < 0) {
    Packit 4a16fb
    						SNDERR("Invalid value for %s", id);
    Packit 4a16fb
    						goto _free;
    Packit 4a16fb
    					}
    Packit 4a16fb
    					sprintf(buf, "%ld", val);
    Packit 4a16fb
    					str = buf;
    Packit 4a16fb
    				}
    Packit 4a16fb
    				for (k = 0; k < slaves_count; ++k) {
    Packit 4a16fb
    					if (strcmp(slaves_id[k], str) == 0)
    Packit 4a16fb
    						slave = k;
    Packit 4a16fb
    				}
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			if (strcmp(id, "channel") == 0) {
    Packit 4a16fb
    				err = snd_config_get_integer(n, &schannel);
    Packit 4a16fb
    				if (err < 0) {
    Packit 4a16fb
    					SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    					goto _free;
    Packit 4a16fb
    				}
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			SNDERR("Unknown field %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (slave < 0 || (unsigned int)slave >= slaves_count) {
    Packit 4a16fb
    			SNDERR("Invalid or missing sidx for channel %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (schannel < 0 || 
    Packit 4a16fb
    		    (unsigned int) schannel >= slaves_channels[slave]) {
    Packit 4a16fb
    			SNDERR("Invalid or missing schannel for channel %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		channels_sidx[cchannel] = slave;
    Packit 4a16fb
    		channels_schannel[cchannel] = schannel;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	
    Packit 4a16fb
    	for (idx = 0; idx < slaves_count; ++idx) {
    Packit 4a16fb
    		err = snd_pcm_open_slave(&slaves_pcm[idx], root,
    Packit 4a16fb
    					 slaves_conf[idx], stream, mode,
    Packit 4a16fb
    					 conf);
    Packit 4a16fb
    		if (err < 0)
    Packit 4a16fb
    			goto _free;
    Packit 4a16fb
    		snd_config_delete(slaves_conf[idx]);
    Packit 4a16fb
    		slaves_conf[idx] = NULL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_multi_open(pcmp, name, slaves_count, master_slave,
    Packit 4a16fb
    				 slaves_pcm, slaves_channels,
    Packit 4a16fb
    				 channels_count,
    Packit 4a16fb
    				 channels_sidx, channels_schannel,
    Packit 4a16fb
    				 1);
    Packit 4a16fb
    _free:
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		for (idx = 0; idx < slaves_count; ++idx) {
    Packit 4a16fb
    			if (slaves_pcm[idx])
    Packit 4a16fb
    				snd_pcm_close(slaves_pcm[idx]);
    Packit 4a16fb
    		}
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (slaves_conf) {
    Packit 4a16fb
    		for (idx = 0; idx < slaves_count; ++idx) {
    Packit 4a16fb
    			if (slaves_conf[idx])
    Packit 4a16fb
    				snd_config_delete(slaves_conf[idx]);
    Packit 4a16fb
    		}
    Packit 4a16fb
    		free(slaves_conf);
    Packit 4a16fb
    	}
    Packit 4a16fb
    	free(slaves_pcm);
    Packit 4a16fb
    	free(slaves_channels);
    Packit 4a16fb
    	free(channels_sidx);
    Packit 4a16fb
    	free(channels_schannel);
    Packit 4a16fb
    	free(slaves_id);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif