1/**
2 * \file pcm/pcm_multi.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Multi Streams to One Conversion Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
6 * \date 2000-2001
7 */
8/*
9 *  PCM - Multi
10 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
11 *
12 *
13 *   This library is free software; you can redistribute it and/or modify
14 *   it under the terms of the GNU Lesser General Public License as
15 *   published by the Free Software Foundation; either version 2.1 of
16 *   the License, or (at your option) any later version.
17 *
18 *   This program is distributed in the hope that it will be useful,
19 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *   GNU Lesser General Public License for more details.
22 *
23 *   You should have received a copy of the GNU Lesser General Public
24 *   License along with this library; if not, write to the Free Software
25 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26 *
27 */
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <math.h>
34#include "pcm_local.h"
35#include "pcm_generic.h"
36
37#ifndef PIC
38/* entry for static linking */
39const char *_snd_module_pcm_multi = "";
40#endif
41
42#ifndef DOC_HIDDEN
43
44typedef struct {
45	snd_pcm_t *pcm;
46	unsigned int channels_count;
47	int close_slave;
48	snd_pcm_t *linked;
49} snd_pcm_multi_slave_t;
50
51typedef struct {
52	int slave_idx;
53	unsigned int slave_channel;
54} snd_pcm_multi_channel_t;
55
56typedef struct {
57	unsigned int slaves_count;
58	unsigned int master_slave;
59	snd_pcm_multi_slave_t *slaves;
60	unsigned int channels_count;
61	snd_pcm_multi_channel_t *channels;
62} snd_pcm_multi_t;
63
64#endif
65
66static int snd_pcm_multi_close(snd_pcm_t *pcm)
67{
68	snd_pcm_multi_t *multi = pcm->private_data;
69	unsigned int i;
70	int ret = 0;
71	for (i = 0; i < multi->slaves_count; ++i) {
72		snd_pcm_multi_slave_t *slave = &multi->slaves[i];
73		if (slave->close_slave) {
74			int err = snd_pcm_close(slave->pcm);
75			if (err < 0)
76				ret = err;
77		}
78	}
79	free(multi->slaves);
80	free(multi->channels);
81	free(multi);
82	return ret;
83}
84
85static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
86{
87	return 0;
88}
89
90static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid)
91{
92	snd_pcm_multi_t *multi = pcm->private_data;
93	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
94	return snd_pcm_async(slave_0, sig, pid);
95}
96
97static int snd_pcm_multi_poll_descriptors_count(snd_pcm_t *pcm)
98{
99	snd_pcm_multi_t *multi = pcm->private_data;
100	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
101	return snd_pcm_poll_descriptors_count(slave_0);
102}
103
104static int snd_pcm_multi_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
105{
106	snd_pcm_multi_t *multi = pcm->private_data;
107	snd_pcm_t *slave;
108	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
109	int err;
110	unsigned int i;
111
112	for (i = 0; i < multi->slaves_count; ++i) {
113		slave = multi->slaves[i].pcm;
114		if (slave == slave_0)
115			continue;
116		err = snd_pcm_poll_descriptors(slave, pfds, space);
117		if (err < 0)
118			return err;
119	}
120	/* finally overwrite with master's pfds */
121	return snd_pcm_poll_descriptors(slave_0, pfds, space);
122}
123
124static int snd_pcm_multi_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
125{
126	snd_pcm_multi_t *multi = pcm->private_data;
127	snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
128	return snd_pcm_poll_descriptors_revents(slave_0, pfds, nfds, revents);
129}
130
131static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
132{
133	snd_pcm_multi_t *multi = pcm->private_data;
134	int err, n;
135	assert(info->subdevice < multi->slaves_count);
136	n = info->subdevice;
137	info->subdevice = 0;
138	err = snd_pcm_info(multi->slaves[n].pcm, info);
139	if (err < 0)
140		return err;
141	info->subdevices_count = multi->slaves_count;
142	return 0;
143}
144
145static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
146{
147	snd_pcm_multi_t *multi = pcm->private_data;
148	snd_pcm_access_mask_t access_mask;
149	int err;
150	snd_pcm_access_mask_any(&access_mask);
151	snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
152	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
153					 &access_mask);
154	if (err < 0)
155		return err;
156	err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
157				    multi->channels_count, 0);
158	if (err < 0)
159		return err;
160	params->info = ~0U;
161	return 0;
162}
163
164static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, unsigned int slave_idx,
165					    snd_pcm_hw_params_t *sparams)
166{
167	snd_pcm_multi_t *multi = pcm->private_data;
168	snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx];
169	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
170	_snd_pcm_hw_params_any(sparams);
171	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
172				   &saccess_mask);
173	_snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
174			      slave->channels_count, 0);
175	return 0;
176}
177
178static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
179					   unsigned int slave_idx ATTRIBUTE_UNUSED,
180					   snd_pcm_hw_params_t *params,
181					   snd_pcm_hw_params_t *sparams)
182{
183	int err;
184	unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
185			      SND_PCM_HW_PARBIT_SUBFORMAT |
186			      SND_PCM_HW_PARBIT_RATE |
187			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
188			      SND_PCM_HW_PARBIT_PERIOD_TIME |
189			      SND_PCM_HW_PARBIT_PERIODS |
190			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
191			      SND_PCM_HW_PARBIT_BUFFER_TIME |
192			      SND_PCM_HW_PARBIT_TICK_TIME);
193	const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
194	if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
195	    !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
196	    !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
197		snd_pcm_access_mask_t saccess_mask;
198		snd_pcm_access_mask_any(&saccess_mask);
199		snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
200		err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
201						 &saccess_mask);
202		if (err < 0)
203			return err;
204	}
205	err = _snd_pcm_hw_params_refine(sparams, links, params);
206	if (err < 0)
207		return err;
208	return 0;
209}
210
211static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
212					   unsigned int slave_idx ATTRIBUTE_UNUSED,
213					   snd_pcm_hw_params_t *params,
214					   snd_pcm_hw_params_t *sparams)
215{
216	int err;
217	unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
218			      SND_PCM_HW_PARBIT_SUBFORMAT |
219			      SND_PCM_HW_PARBIT_RATE |
220			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
221			      SND_PCM_HW_PARBIT_PERIOD_TIME |
222			      SND_PCM_HW_PARBIT_PERIODS |
223			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
224			      SND_PCM_HW_PARBIT_BUFFER_TIME |
225			      SND_PCM_HW_PARBIT_TICK_TIME);
226	snd_pcm_access_mask_t access_mask;
227	const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
228	snd_pcm_access_mask_any(&access_mask);
229	snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
230	if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
231		snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
232	if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
233	    !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
234		snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
235	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
236					 &access_mask);
237	if (err < 0)
238		return err;
239	err = _snd_pcm_hw_params_refine(params, links, sparams);
240	if (err < 0)
241		return err;
242	params->info &= sparams->info;
243	return 0;
244}
245
246static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm,
247					 unsigned int slave_idx,
248					 snd_pcm_hw_params_t *sparams)
249{
250	snd_pcm_multi_t *multi = pcm->private_data;
251	snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
252	return snd_pcm_hw_refine(slave, sparams);
253}
254
255static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
256{
257	snd_pcm_multi_t *multi = pcm->private_data;
258	unsigned int k;
259	snd_pcm_hw_params_t sparams[multi->slaves_count];
260	int err;
261	unsigned int cmask, changed;
262	err = snd_pcm_multi_hw_refine_cprepare(pcm, params);
263	if (err < 0)
264		return err;
265	for (k = 0; k < multi->slaves_count; ++k) {
266		err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
267		if (err < 0) {
268			SNDERR("Slave PCM #%d not usable", k);
269			return err;
270		}
271	}
272	do {
273		cmask = params->cmask;
274		params->cmask = 0;
275		for (k = 0; k < multi->slaves_count; ++k) {
276			err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
277			if (err >= 0)
278				err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]);
279			if (err < 0) {
280				snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
281				return err;
282			}
283			err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
284			if (err < 0)
285				return err;
286		}
287		err = snd_pcm_hw_refine_soft(pcm, params);
288		changed = params->cmask;
289		params->cmask |= cmask;
290		if (err < 0)
291			return err;
292	} while (changed);
293	return 0;
294}
295
296static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm,
297					 unsigned int slave_idx,
298					 snd_pcm_hw_params_t *sparams)
299{
300	snd_pcm_multi_t *multi = pcm->private_data;
301	snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
302	int err = snd_pcm_hw_params(slave, sparams);
303	if (err < 0)
304		return err;
305	err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
306	if (err < 0)
307		return err;
308	if (slave->stopped_areas) {
309		err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
310		if (err < 0)
311			return err;
312	}
313	return 0;
314}
315
316/* reset links to the normal state
317 * slave #0 = trigger master
318 * slave #1-(N-1) = trigger slaves, linked is set to #0
319 */
320static void reset_links(snd_pcm_multi_t *multi)
321{
322	unsigned int i;
323
324	for (i = 0; i < multi->slaves_count; ++i) {
325		if (multi->slaves[i].linked)
326			snd_pcm_unlink(multi->slaves[i].linked);
327		multi->slaves[0].linked = NULL;
328		if (! i)
329			continue;
330		if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0)
331			multi->slaves[i].linked = multi->slaves[0].pcm;
332	}
333}
334
335static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
336{
337	snd_pcm_multi_t *multi = pcm->private_data;
338	unsigned int i;
339	snd_pcm_hw_params_t sparams[multi->slaves_count];
340	int err;
341	for (i = 0; i < multi->slaves_count; ++i) {
342		err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]);
343		assert(err >= 0);
344		err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]);
345		assert(err >= 0);
346		err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]);
347		if (err < 0) {
348			snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]);
349			return err;
350		}
351	}
352	reset_links(multi);
353	return 0;
354}
355
356static int snd_pcm_multi_hw_free(snd_pcm_t *pcm)
357{
358	snd_pcm_multi_t *multi = pcm->private_data;
359	unsigned int i;
360	int err = 0;
361	for (i = 0; i < multi->slaves_count; ++i) {
362		snd_pcm_t *slave = multi->slaves[i].pcm;
363		int e = snd_pcm_hw_free(slave);
364		if (e < 0)
365			err = e;
366		if (!multi->slaves[i].linked)
367			continue;
368		e = snd_pcm_unlink(slave);
369		if (e < 0)
370			err = e;
371		multi->slaves[i].linked = NULL;
372	}
373	return err;
374}
375
376static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
377{
378	snd_pcm_multi_t *multi = pcm->private_data;
379	unsigned int i;
380	int err;
381	for (i = 0; i < multi->slaves_count; ++i) {
382		snd_pcm_t *slave = multi->slaves[i].pcm;
383		err = snd_pcm_sw_params(slave, params);
384		if (err < 0)
385			return err;
386	}
387	return 0;
388}
389
390static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
391{
392	snd_pcm_multi_t *multi = pcm->private_data;
393	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
394	return snd_pcm_status(slave, status);
395}
396
397static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm)
398{
399	snd_pcm_multi_t *multi = pcm->private_data;
400	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
401	return snd_pcm_state(slave);
402}
403
404static int snd_pcm_multi_hwsync(snd_pcm_t *pcm)
405{
406	snd_pcm_multi_t *multi = pcm->private_data;
407	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
408	return snd_pcm_hwsync(slave);
409}
410
411static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
412{
413	snd_pcm_multi_t *multi = pcm->private_data;
414	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
415	return snd_pcm_delay(slave, delayp);
416}
417
418static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
419{
420	snd_pcm_multi_t *multi = pcm->private_data;
421	snd_pcm_sframes_t ret = LONG_MAX;
422	unsigned int i;
423	for (i = 0; i < multi->slaves_count; ++i) {
424		snd_pcm_sframes_t avail;
425		avail = snd_pcm_avail_update(multi->slaves[i].pcm);
426		if (avail < 0)
427			return avail;
428		if (ret > avail)
429			ret = avail;
430	}
431	return ret;
432}
433
434static int snd_pcm_multi_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
435				    snd_htimestamp_t *tstamp)
436{
437	snd_pcm_multi_t *multi = pcm->private_data;
438	snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
439	return snd_pcm_htimestamp(slave, avail, tstamp);
440}
441
442static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
443{
444	snd_pcm_multi_t *multi = pcm->private_data;
445	int result = 0, err;
446	unsigned int i;
447	for (i = 0; i < multi->slaves_count; ++i) {
448		/* We call prepare to each slave even if it's linked.
449		 * This is to make sure to sync non-mmaped control/status.
450		 */
451		err = snd_pcm_prepare(multi->slaves[i].pcm);
452		if (err < 0)
453			result = err;
454	}
455	return result;
456}
457
458static int snd_pcm_multi_reset(snd_pcm_t *pcm)
459{
460	snd_pcm_multi_t *multi = pcm->private_data;
461	int result = 0, err;
462	unsigned int i;
463	for (i = 0; i < multi->slaves_count; ++i) {
464		/* Reset each slave, as well as in prepare */
465		err = snd_pcm_reset(multi->slaves[i].pcm);
466		if (err < 0)
467			result = err;
468	}
469	return result;
470}
471
472/* when the first slave PCM is linked, it means that the whole multi
473 * plugin instance is linked manually to another PCM.  in this case,
474 * we need to trigger the master.
475 */
476static int snd_pcm_multi_start(snd_pcm_t *pcm)
477{
478	snd_pcm_multi_t *multi = pcm->private_data;
479	int err = 0;
480	unsigned int i;
481	if (multi->slaves[0].linked)
482		return snd_pcm_start(multi->slaves[0].linked);
483	for (i = 0; i < multi->slaves_count; ++i) {
484		if (multi->slaves[i].linked)
485			continue;
486		err = snd_pcm_start(multi->slaves[i].pcm);
487		if (err < 0)
488			return err;
489	}
490	return err;
491}
492
493static int snd_pcm_multi_drop(snd_pcm_t *pcm)
494{
495	snd_pcm_multi_t *multi = pcm->private_data;
496	int err = 0;
497	unsigned int i;
498	if (multi->slaves[0].linked)
499		return snd_pcm_drop(multi->slaves[0].linked);
500	for (i = 0; i < multi->slaves_count; ++i) {
501		if (multi->slaves[i].linked)
502			continue;
503		err = snd_pcm_drop(multi->slaves[i].pcm);
504		if (err < 0)
505			return err;
506	}
507	return err;
508}
509
510static int snd_pcm_multi_drain(snd_pcm_t *pcm)
511{
512	snd_pcm_multi_t *multi = pcm->private_data;
513	int err = 0;
514	unsigned int i;
515	if (multi->slaves[0].linked)
516		return snd_pcm_drain(multi->slaves[0].linked);
517	for (i = 0; i < multi->slaves_count; ++i) {
518		if (multi->slaves[i].linked)
519			continue;
520		err = snd_pcm_drain(multi->slaves[i].pcm);
521		if (err < 0)
522			return err;
523	}
524	return err;
525}
526
527static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
528{
529	snd_pcm_multi_t *multi = pcm->private_data;
530	int err = 0;
531	unsigned int i;
532	if (multi->slaves[0].linked)
533		return snd_pcm_pause(multi->slaves[0].linked, enable);
534	for (i = 0; i < multi->slaves_count; ++i) {
535		if (multi->slaves[i].linked)
536			continue;
537		err = snd_pcm_pause(multi->slaves[i].pcm, enable);
538		if (err < 0)
539			return err;
540	}
541	return err;
542}
543
544static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
545{
546	snd_pcm_multi_t *multi = pcm->private_data;
547	unsigned int channel = info->channel;
548	snd_pcm_multi_channel_t *c = &multi->channels[channel];
549	int err;
550	if (c->slave_idx < 0)
551		return -ENXIO;
552	info->channel = c->slave_channel;
553	err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info);
554	info->channel = channel;
555	return err;
556}
557
558static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
559{
560	snd_pcm_multi_t *multi = pcm->private_data;
561	unsigned int i;
562	snd_pcm_uframes_t pos[multi->slaves_count];
563	memset(pos, 0, sizeof(pos));
564	for (i = 0; i < multi->slaves_count; ++i) {
565		snd_pcm_t *slave_i = multi->slaves[i].pcm;
566		snd_pcm_sframes_t f = snd_pcm_rewind(slave_i, frames);
567		if (f < 0)
568			return f;
569		pos[i] = f;
570		frames = f;
571	}
572	/* Realign the pointers */
573	for (i = 0; i < multi->slaves_count; ++i) {
574		snd_pcm_t *slave_i = multi->slaves[i].pcm;
575		snd_pcm_uframes_t f = pos[i] - frames;
576		snd_pcm_sframes_t result;
577		if (f > 0) {
578			result = INTERNAL(snd_pcm_forward)(slave_i, f);
579			if (result < 0)
580				return result;
581			if ((snd_pcm_uframes_t)result != f)
582				return -EIO;
583		}
584	}
585	return frames;
586}
587
588static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
589{
590	snd_pcm_multi_t *multi = pcm->private_data;
591	unsigned int i;
592	snd_pcm_uframes_t pos[multi->slaves_count];
593	memset(pos, 0, sizeof(pos));
594	for (i = 0; i < multi->slaves_count; ++i) {
595		snd_pcm_t *slave_i = multi->slaves[i].pcm;
596		snd_pcm_sframes_t f = INTERNAL(snd_pcm_forward)(slave_i, frames);
597		if (f < 0)
598			return f;
599		pos[i] = f;
600		frames = f;
601	}
602	/* Realign the pointers */
603	for (i = 0; i < multi->slaves_count; ++i) {
604		snd_pcm_t *slave_i = multi->slaves[i].pcm;
605		snd_pcm_uframes_t f = pos[i] - frames;
606		snd_pcm_sframes_t result;
607		if (f > 0) {
608			result = snd_pcm_rewind(slave_i, f);
609			if (result < 0)
610				return result;
611			if ((snd_pcm_uframes_t)result != f)
612				return -EIO;
613		}
614	}
615	return frames;
616}
617
618static int snd_pcm_multi_resume(snd_pcm_t *pcm)
619{
620	snd_pcm_multi_t *multi = pcm->private_data;
621	int err = 0;
622	unsigned int i;
623	if (multi->slaves[0].linked)
624		return snd_pcm_resume(multi->slaves[0].linked);
625	for (i = 0; i < multi->slaves_count; ++i) {
626		if (multi->slaves[i].linked)
627			continue;
628		err = snd_pcm_resume(multi->slaves[i].pcm);
629		if (err < 0)
630			return err;
631	}
632	return err;
633}
634
635/* if a multi plugin instance is linked as slaves, every slave PCMs
636 * including the first one has to be relinked to the given master.
637 */
638static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
639{
640	snd_pcm_multi_t *multi = pcm->private_data;
641	unsigned int i;
642	int err;
643
644	for (i = 0; i < multi->slaves_count; ++i) {
645		snd_pcm_unlink(multi->slaves[i].pcm);
646		multi->slaves[i].linked = NULL;
647		err = snd_pcm_link(master, multi->slaves[i].pcm);
648		if (err < 0) {
649			reset_links(multi);
650			return err;
651		}
652		multi->slaves[i].linked = master;
653	}
654	return 0;
655}
656
657/* linking to a multi as a master is easy - simply link to the first
658 * slave element as its own slaves are already linked.
659 */
660static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
661{
662	snd_pcm_multi_t *multi = pcm1->private_data;
663	if (multi->slaves[0].pcm->fast_ops->link)
664		return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2);
665	return -ENOSYS;
666}
667
668static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
669{
670	snd_pcm_multi_t *multi = pcm->private_data;
671	unsigned int i;
672
673	for (i = 0; i < multi->slaves_count; ++i) {
674		if (multi->slaves[i].linked)
675			snd_pcm_unlink(multi->slaves[i].linked);
676		multi->slaves[0].linked = NULL;
677	}
678	return 0;
679}
680
681static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
682						   snd_pcm_uframes_t offset,
683						   snd_pcm_uframes_t size)
684{
685	snd_pcm_multi_t *multi = pcm->private_data;
686	snd_pcm_t *slave;
687	unsigned int i;
688	snd_pcm_sframes_t result;
689
690	for (i = 0; i < multi->slaves_count; ++i) {
691		slave = multi->slaves[i].pcm;
692		result = snd_pcm_mmap_commit(slave, offset, size);
693		if (result < 0)
694			return result;
695		if ((snd_pcm_uframes_t)result != size)
696			return -EIO;
697	}
698	return size;
699}
700
701static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
702{
703	free(pcm->mmap_channels);
704	free(pcm->running_areas);
705	pcm->mmap_channels = NULL;
706	pcm->running_areas = NULL;
707	return 0;
708}
709
710static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
711{
712	snd_pcm_multi_t *multi = pcm->private_data;
713	unsigned int c;
714
715	pcm->mmap_channels = calloc(pcm->channels,
716				    sizeof(pcm->mmap_channels[0]));
717	pcm->running_areas = calloc(pcm->channels,
718				    sizeof(pcm->running_areas[0]));
719	if (!pcm->mmap_channels || !pcm->running_areas) {
720		snd_pcm_multi_munmap(pcm);
721		return -ENOMEM;
722	}
723
724	/* Copy the slave mmapped buffer data */
725	for (c = 0; c < pcm->channels; c++) {
726		snd_pcm_multi_channel_t *chan = &multi->channels[c];
727		snd_pcm_t *slave;
728		if (chan->slave_idx < 0) {
729			snd_pcm_multi_munmap(pcm);
730			return -ENXIO;
731		}
732		slave = multi->slaves[chan->slave_idx].pcm;
733		pcm->mmap_channels[c] =
734			slave->mmap_channels[chan->slave_channel];
735		pcm->mmap_channels[c].channel = c;
736		pcm->running_areas[c] =
737			slave->running_areas[chan->slave_channel];
738	}
739	return 0;
740}
741
742static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
743{
744	snd_pcm_multi_t *multi = pcm->private_data;
745	unsigned int k;
746	snd_output_printf(out, "Multi PCM\n");
747	snd_output_printf(out, "  Channel bindings:\n");
748	for (k = 0; k < multi->channels_count; ++k) {
749		snd_pcm_multi_channel_t *c = &multi->channels[k];
750		if (c->slave_idx < 0)
751			continue;
752		snd_output_printf(out, "    %d: slave %d, channel %d\n",
753			k, c->slave_idx, c->slave_channel);
754	}
755	if (pcm->setup) {
756		snd_output_printf(out, "Its setup is:\n");
757		snd_pcm_dump_setup(pcm, out);
758	}
759	for (k = 0; k < multi->slaves_count; ++k) {
760		snd_output_printf(out, "Slave #%d: ", k);
761		snd_pcm_dump(multi->slaves[k].pcm, out);
762	}
763}
764
765static const snd_pcm_ops_t snd_pcm_multi_ops = {
766	.close = snd_pcm_multi_close,
767	.info = snd_pcm_multi_info,
768	.hw_refine = snd_pcm_multi_hw_refine,
769	.hw_params = snd_pcm_multi_hw_params,
770	.hw_free = snd_pcm_multi_hw_free,
771	.sw_params = snd_pcm_multi_sw_params,
772	.channel_info = snd_pcm_multi_channel_info,
773	.dump = snd_pcm_multi_dump,
774	.nonblock = snd_pcm_multi_nonblock,
775	.async = snd_pcm_multi_async,
776	.mmap = snd_pcm_multi_mmap,
777	.munmap = snd_pcm_multi_munmap,
778};
779
780static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
781	.status = snd_pcm_multi_status,
782	.state = snd_pcm_multi_state,
783	.hwsync = snd_pcm_multi_hwsync,
784	.delay = snd_pcm_multi_delay,
785	.prepare = snd_pcm_multi_prepare,
786	.reset = snd_pcm_multi_reset,
787	.start = snd_pcm_multi_start,
788	.drop = snd_pcm_multi_drop,
789	.drain = snd_pcm_multi_drain,
790	.pause = snd_pcm_multi_pause,
791	.writei = snd_pcm_mmap_writei,
792	.writen = snd_pcm_mmap_writen,
793	.readi = snd_pcm_mmap_readi,
794	.readn = snd_pcm_mmap_readn,
795	.rewind = snd_pcm_multi_rewind,
796	.forward = snd_pcm_multi_forward,
797	.resume = snd_pcm_multi_resume,
798	.link = snd_pcm_multi_link,
799	.link_slaves = snd_pcm_multi_link_slaves,
800	.unlink = snd_pcm_multi_unlink,
801	.avail_update = snd_pcm_multi_avail_update,
802	.mmap_commit = snd_pcm_multi_mmap_commit,
803	.htimestamp = snd_pcm_multi_htimestamp,
804	.poll_descriptors_count = snd_pcm_multi_poll_descriptors_count,
805	.poll_descriptors = snd_pcm_multi_poll_descriptors,
806	.poll_revents = snd_pcm_multi_poll_revents,
807};
808
809/**
810 * \brief Creates a new Multi PCM
811 * \param pcmp Returns created PCM handle
812 * \param name Name of PCM
813 * \param slaves_count Count of slaves
814 * \param master_slave Master slave number
815 * \param slaves_pcm Array with slave PCMs
816 * \param schannels_count Array with slave channel counts
817 * \param channels_count Count of channels
818 * \param sidxs Array with channels indexes to slaves
819 * \param schannels Array with slave channels
820 * \param close_slaves When set, the slave PCM handle is closed
821 * \retval zero on success otherwise a negative error code
822 * \warning Using of this function might be dangerous in the sense
823 *          of compatibility reasons. The prototype might be freely
824 *          changed in future.
825 */
826int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
827		       unsigned int slaves_count, unsigned int master_slave,
828		       snd_pcm_t **slaves_pcm, unsigned int *schannels_count,
829		       unsigned int channels_count,
830		       int *sidxs, unsigned int *schannels,
831		       int close_slaves)
832{
833	snd_pcm_t *pcm;
834	snd_pcm_multi_t *multi;
835	unsigned int i;
836	snd_pcm_stream_t stream;
837	char slave_map[64][64] = { { 0 } };
838	int err;
839
840	assert(pcmp);
841	assert(slaves_count > 0 && slaves_pcm && schannels_count);
842	assert(channels_count > 0 && sidxs && schannels);
843	assert(master_slave < slaves_count);
844
845	multi = calloc(1, sizeof(snd_pcm_multi_t));
846	if (!multi) {
847		return -ENOMEM;
848	}
849
850	stream = slaves_pcm[0]->stream;
851
852	multi->slaves_count = slaves_count;
853	multi->master_slave = master_slave;
854	multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
855	if (!multi->slaves) {
856		free(multi);
857		return -ENOMEM;
858	}
859	multi->channels_count = channels_count;
860	multi->channels = calloc(channels_count, sizeof(*multi->channels));
861	if (!multi->channels) {
862		free(multi->slaves);
863		free(multi);
864		return -ENOMEM;
865	}
866	for (i = 0; i < slaves_count; ++i) {
867		snd_pcm_multi_slave_t *slave = &multi->slaves[i];
868		assert(slaves_pcm[i]->stream == stream);
869		slave->pcm = slaves_pcm[i];
870		slave->channels_count = schannels_count[i];
871		slave->close_slave = close_slaves;
872	}
873	for (i = 0; i < channels_count; ++i) {
874		snd_pcm_multi_channel_t *bind = &multi->channels[i];
875		assert(sidxs[i] < (int)slaves_count);
876		assert(schannels[i] < schannels_count[sidxs[i]]);
877		bind->slave_idx = sidxs[i];
878		bind->slave_channel = schannels[i];
879		if (sidxs[i] < 0)
880			continue;
881		assert(!slave_map[sidxs[i]][schannels[i]]);
882		slave_map[sidxs[i]][schannels[i]] = 1;
883	}
884	multi->channels_count = channels_count;
885
886	err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream,
887			  multi->slaves[0].pcm->mode);
888	if (err < 0) {
889		free(multi->slaves);
890		free(multi->channels);
891		free(multi);
892		return err;
893	}
894	pcm->mmap_rw = 1;
895	pcm->mmap_shadow = 1; /* has own mmap method */
896	pcm->ops = &snd_pcm_multi_ops;
897	pcm->fast_ops = &snd_pcm_multi_fast_ops;
898	pcm->private_data = multi;
899	pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
900	pcm->poll_events = multi->slaves[master_slave].pcm->poll_events;
901	pcm->monotonic = multi->slaves[master_slave].pcm->monotonic;
902	snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm);
903	snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
904	*pcmp = pcm;
905	return 0;
906}
907
908/*! \page pcm_plugins
909
910\section pcm_plugins_multi Plugin: Multiple streams to One
911
912This plugin converts multiple streams to one.
913
914\code
915pcm.name {
916        type multi              # Multiple streams conversion PCM
917        slaves {		# Slaves definition
918		ID STR		# Slave PCM name
919		# or
920		ID {
921			pcm STR		# Slave PCM name
922			# or
923			pcm { } 	# Slave PCM definition
924			channels INT	# Slave channels
925		}
926        }
927	bindings {		# Bindings table
928		N {
929			slave STR	# Slave key
930			channel INT	# Slave channel
931		}
932	}
933	[master INT]		# Define the master slave
934}
935\endcode
936
937For example, to bind two PCM streams with two-channel stereo (hw:0,0 and
938hw:0,1) as one 4-channel stereo PCM stream, define like this:
939\code
940pcm.quad {
941	type multi
942
943	slaves.a.pcm "hw:0,0"
944	slaves.a.channels 2
945	slaves.b.pcm "hw:0,1"
946	slaves.b.channels 2
947
948	bindings.0.slave a
949	bindings.0.channel 0
950	bindings.1.slave a
951	bindings.1.channel 1
952	bindings.2.slave b
953	bindings.2.channel 0
954	bindings.3.slave b
955	bindings.3.channel 1
956}
957\endcode
958Note that the resultant pcm "quad" is not in the interleaved format
959but in the "complex" format.  Hence, it's not accessible by applications
960which can handle only the interleaved (or the non-interleaved) format.
961In such a case, wrap this PCM with \ref pcm_plugins_route "route" or
962\ref pcm_plugins_plug "plug" plugin.
963\code
964pcm.quad2 {
965	type route
966	slave.pcm "quad"
967	ttable.0.0 1
968	ttable.1.1 1
969	ttable.2.2 1
970	ttable.3.3 1
971}
972\endcode
973
974\subsection pcm_plugins_multi_funcref Function reference
975
976<UL>
977  <LI>snd_pcm_multi_open()
978  <LI>_snd_pcm_multi_open()
979</UL>
980
981*/
982
983/**
984 * \brief Creates a new Multi PCM
985 * \param pcmp Returns created PCM handle
986 * \param name Name of PCM
987 * \param root Root configuration node
988 * \param conf Configuration node with Multi PCM description
989 * \param stream Stream type
990 * \param mode Stream mode
991 * \retval zero on success otherwise a negative error code
992 * \warning Using of this function might be dangerous in the sense
993 *          of compatibility reasons. The prototype might be freely
994 *          changed in future.
995 */
996int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
997			snd_config_t *root, snd_config_t *conf,
998			snd_pcm_stream_t stream, int mode)
999{
1000	snd_config_iterator_t i, inext, j, jnext;
1001	snd_config_t *slaves = NULL;
1002	snd_config_t *bindings = NULL;
1003	int err;
1004	unsigned int idx;
1005	const char **slaves_id = NULL;
1006	snd_config_t **slaves_conf = NULL;
1007	snd_pcm_t **slaves_pcm = NULL;
1008	unsigned int *slaves_channels = NULL;
1009	int *channels_sidx = NULL;
1010	unsigned int *channels_schannel = NULL;
1011	unsigned int slaves_count = 0;
1012	long master_slave = 0;
1013	unsigned int channels_count = 0;
1014	snd_config_for_each(i, inext, conf) {
1015		snd_config_t *n = snd_config_iterator_entry(i);
1016		const char *id;
1017		if (snd_config_get_id(n, &id) < 0)
1018			continue;
1019		if (snd_pcm_conf_generic_id(id))
1020			continue;
1021		if (strcmp(id, "slaves") == 0) {
1022			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1023				SNDERR("Invalid type for %s", id);
1024				return -EINVAL;
1025			}
1026			slaves = n;
1027			continue;
1028		}
1029		if (strcmp(id, "bindings") == 0) {
1030			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1031				SNDERR("Invalid type for %s", id);
1032				return -EINVAL;
1033			}
1034			bindings = n;
1035			continue;
1036		}
1037		if (strcmp(id, "master") == 0) {
1038			if (snd_config_get_integer(n, &master_slave) < 0) {
1039				SNDERR("Invalid type for %s", id);
1040				return -EINVAL;
1041			}
1042			continue;
1043		}
1044		SNDERR("Unknown field %s", id);
1045		return -EINVAL;
1046	}
1047	if (!slaves) {
1048		SNDERR("slaves is not defined");
1049		return -EINVAL;
1050	}
1051	if (!bindings) {
1052		SNDERR("bindings is not defined");
1053		return -EINVAL;
1054	}
1055	snd_config_for_each(i, inext, slaves) {
1056		++slaves_count;
1057	}
1058	if (master_slave < 0 || master_slave >= (long)slaves_count) {
1059		SNDERR("Master slave is out of range (0-%u)\n", slaves_count-1);
1060		return -EINVAL;
1061	}
1062	snd_config_for_each(i, inext, bindings) {
1063		long cchannel;
1064		snd_config_t *m = snd_config_iterator_entry(i);
1065		const char *id;
1066		if (snd_config_get_id(m, &id) < 0)
1067			continue;
1068		err = safe_strtol(id, &cchannel);
1069		if (err < 0 || cchannel < 0) {
1070			SNDERR("Invalid channel number: %s", id);
1071			return -EINVAL;
1072		}
1073		if ((unsigned long)cchannel >= channels_count)
1074			channels_count = cchannel + 1;
1075	}
1076	if (channels_count == 0) {
1077		SNDERR("No channels defined");
1078		return -EINVAL;
1079	}
1080	slaves_id = calloc(slaves_count, sizeof(*slaves_id));
1081	slaves_conf = calloc(slaves_count, sizeof(*slaves_conf));
1082	slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm));
1083	slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
1084	channels_sidx = calloc(channels_count, sizeof(*channels_sidx));
1085	channels_schannel = calloc(channels_count, sizeof(*channels_schannel));
1086	if (!slaves_id || !slaves_conf || !slaves_pcm || !slaves_channels ||
1087	    !channels_sidx || !channels_schannel) {
1088		err = -ENOMEM;
1089		goto _free;
1090	}
1091	idx = 0;
1092	for (idx = 0; idx < channels_count; ++idx)
1093		channels_sidx[idx] = -1;
1094	idx = 0;
1095	snd_config_for_each(i, inext, slaves) {
1096		snd_config_t *m = snd_config_iterator_entry(i);
1097		const char *id;
1098		int channels;
1099		if (snd_config_get_id(m, &id) < 0)
1100			continue;
1101		slaves_id[idx] = id;
1102		err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1,
1103					 SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels);
1104		if (err < 0)
1105			goto _free;
1106		slaves_channels[idx] = channels;
1107		++idx;
1108	}
1109
1110	snd_config_for_each(i, inext, bindings) {
1111		snd_config_t *m = snd_config_iterator_entry(i);
1112		long cchannel = -1;
1113		long schannel = -1;
1114		int slave = -1;
1115		long val;
1116		const char *str;
1117		const char *id;
1118		if (snd_config_get_id(m, &id) < 0)
1119			continue;
1120		err = safe_strtol(id, &cchannel);
1121		if (err < 0 || cchannel < 0) {
1122			SNDERR("Invalid channel number: %s", id);
1123			err = -EINVAL;
1124			goto _free;
1125		}
1126		snd_config_for_each(j, jnext, m) {
1127			snd_config_t *n = snd_config_iterator_entry(j);
1128			const char *id;
1129			if (snd_config_get_id(n, &id) < 0)
1130				continue;
1131			if (strcmp(id, "comment") == 0)
1132				continue;
1133			if (strcmp(id, "slave") == 0) {
1134				char buf[32];
1135				unsigned int k;
1136				err = snd_config_get_string(n, &str);
1137				if (err < 0) {
1138					err = snd_config_get_integer(n, &val);
1139					if (err < 0) {
1140						SNDERR("Invalid value for %s", id);
1141						goto _free;
1142					}
1143					sprintf(buf, "%ld", val);
1144					str = buf;
1145				}
1146				for (k = 0; k < slaves_count; ++k) {
1147					if (strcmp(slaves_id[k], str) == 0)
1148						slave = k;
1149				}
1150				continue;
1151			}
1152			if (strcmp(id, "channel") == 0) {
1153				err = snd_config_get_integer(n, &schannel);
1154				if (err < 0) {
1155					SNDERR("Invalid type for %s", id);
1156					goto _free;
1157				}
1158				continue;
1159			}
1160			SNDERR("Unknown field %s", id);
1161			err = -EINVAL;
1162			goto _free;
1163		}
1164		if (slave < 0 || (unsigned int)slave >= slaves_count) {
1165			SNDERR("Invalid or missing sidx for channel %s", id);
1166			err = -EINVAL;
1167			goto _free;
1168		}
1169		if (schannel < 0 ||
1170		    (unsigned int) schannel >= slaves_channels[slave]) {
1171			SNDERR("Invalid or missing schannel for channel %s", id);
1172			err = -EINVAL;
1173			goto _free;
1174		}
1175		channels_sidx[cchannel] = slave;
1176		channels_schannel[cchannel] = schannel;
1177	}
1178
1179	for (idx = 0; idx < slaves_count; ++idx) {
1180		err = snd_pcm_open_slave(&slaves_pcm[idx], root,
1181					 slaves_conf[idx], stream, mode,
1182					 conf);
1183		if (err < 0)
1184			goto _free;
1185		snd_config_delete(slaves_conf[idx]);
1186		slaves_conf[idx] = NULL;
1187	}
1188	err = snd_pcm_multi_open(pcmp, name, slaves_count, master_slave,
1189				 slaves_pcm, slaves_channels,
1190				 channels_count,
1191				 channels_sidx, channels_schannel,
1192				 1);
1193_free:
1194	if (err < 0) {
1195		for (idx = 0; idx < slaves_count; ++idx) {
1196			if (slaves_pcm[idx])
1197				snd_pcm_close(slaves_pcm[idx]);
1198		}
1199	}
1200	if (slaves_conf) {
1201		for (idx = 0; idx < slaves_count; ++idx) {
1202			if (slaves_conf[idx])
1203				snd_config_delete(slaves_conf[idx]);
1204		}
1205		free(slaves_conf);
1206	}
1207	free(slaves_pcm);
1208	free(slaves_channels);
1209	free(channels_sidx);
1210	free(channels_schannel);
1211	free(slaves_id);
1212	return err;
1213}
1214#ifndef DOC_HIDDEN
1215SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION);
1216#endif
1217