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