2 * \file pcm/pcm_multi.c
4 * \brief PCM Multi Streams to One Conversion Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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.
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.
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
34 #include "pcm_local.h"
35 #include "pcm_generic.h"
38 /* entry for static linking */
39 const char *_snd_module_pcm_multi = "";
46 unsigned int channels_count;
49 } snd_pcm_multi_slave_t;
53 unsigned int slave_channel;
54 } snd_pcm_multi_channel_t;
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;
66 static int snd_pcm_multi_close(snd_pcm_t *pcm)
68 snd_pcm_multi_t *multi = pcm->private_data;
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);
80 free(multi->channels);
85 static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
90 static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid)
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);
97 static int snd_pcm_multi_poll_descriptors_count(snd_pcm_t *pcm)
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);
104 static int snd_pcm_multi_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
106 snd_pcm_multi_t *multi = pcm->private_data;
108 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
112 for (i = 0; i < multi->slaves_count; ++i) {
113 slave = multi->slaves[i].pcm;
114 if (slave == slave_0)
116 err = snd_pcm_poll_descriptors(slave, pfds, space);
120 /* finally overwrite with master's pfds */
121 return snd_pcm_poll_descriptors(slave_0, pfds, space);
124 static int snd_pcm_multi_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
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);
131 static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
133 snd_pcm_multi_t *multi = pcm->private_data;
135 assert(info->subdevice < multi->slaves_count);
138 err = snd_pcm_info(multi->slaves[n].pcm, info);
141 info->subdevices_count = multi->slaves_count;
145 static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
147 snd_pcm_multi_t *multi = pcm->private_data;
148 snd_pcm_access_mask_t access_mask;
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,
156 err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
157 multi->channels_count, 0);
164 static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, unsigned int slave_idx,
165 snd_pcm_hw_params_t *sparams)
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,
173 _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
174 slave->channels_count, 0);
178 static 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)
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,
205 err = _snd_pcm_hw_params_refine(sparams, links, params);
211 static 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)
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,
239 err = _snd_pcm_hw_params_refine(params, links, sparams);
242 params->info &= sparams->info;
246 static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm,
247 unsigned int slave_idx,
248 snd_pcm_hw_params_t *sparams)
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);
255 static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
257 snd_pcm_multi_t *multi = pcm->private_data;
259 snd_pcm_hw_params_t sparams[multi->slaves_count];
261 unsigned int cmask, changed;
262 err = snd_pcm_multi_hw_refine_cprepare(pcm, params);
265 for (k = 0; k < multi->slaves_count; ++k) {
266 err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
268 SNDERR("Slave PCM #%d not usable", k);
273 cmask = params->cmask;
275 for (k = 0; k < multi->slaves_count; ++k) {
276 err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
278 err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]);
280 snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
283 err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
287 err = snd_pcm_hw_refine_soft(pcm, params);
288 changed = params->cmask;
289 params->cmask |= cmask;
296 static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm,
297 unsigned int slave_idx,
298 snd_pcm_hw_params_t *sparams)
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);
305 err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
308 if (slave->stopped_areas) {
309 err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
316 /* reset links to the normal state
317 * slave #0 = trigger master
318 * slave #1-(N-1) = trigger slaves, linked is set to #0
320 static void reset_links(snd_pcm_multi_t *multi)
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;
330 if (snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm) >= 0)
331 multi->slaves[i].linked = multi->slaves[0].pcm;
335 static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
337 snd_pcm_multi_t *multi = pcm->private_data;
339 snd_pcm_hw_params_t sparams[multi->slaves_count];
341 for (i = 0; i < multi->slaves_count; ++i) {
342 err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]);
344 err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]);
346 err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]);
348 snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]);
356 static int snd_pcm_multi_hw_free(snd_pcm_t *pcm)
358 snd_pcm_multi_t *multi = pcm->private_data;
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);
366 if (!multi->slaves[i].linked)
368 e = snd_pcm_unlink(slave);
371 multi->slaves[i].linked = NULL;
376 static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
378 snd_pcm_multi_t *multi = pcm->private_data;
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);
390 static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
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);
397 static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm)
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);
404 static int snd_pcm_multi_hwsync(snd_pcm_t *pcm)
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);
411 static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
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);
418 static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
420 snd_pcm_multi_t *multi = pcm->private_data;
421 snd_pcm_sframes_t ret = LONG_MAX;
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);
434 static int snd_pcm_multi_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
435 snd_htimestamp_t *tstamp)
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);
442 static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
444 snd_pcm_multi_t *multi = pcm->private_data;
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.
451 err = snd_pcm_prepare(multi->slaves[i].pcm);
458 static int snd_pcm_multi_reset(snd_pcm_t *pcm)
460 snd_pcm_multi_t *multi = pcm->private_data;
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);
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.
476 static int snd_pcm_multi_start(snd_pcm_t *pcm)
478 snd_pcm_multi_t *multi = pcm->private_data;
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)
486 err = snd_pcm_start(multi->slaves[i].pcm);
493 static int snd_pcm_multi_drop(snd_pcm_t *pcm)
495 snd_pcm_multi_t *multi = pcm->private_data;
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)
503 err = snd_pcm_drop(multi->slaves[i].pcm);
510 static int snd_pcm_multi_drain(snd_pcm_t *pcm)
512 snd_pcm_multi_t *multi = pcm->private_data;
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)
520 err = snd_pcm_drain(multi->slaves[i].pcm);
527 static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
529 snd_pcm_multi_t *multi = pcm->private_data;
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)
537 err = snd_pcm_pause(multi->slaves[i].pcm, enable);
544 static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
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];
550 if (c->slave_idx < 0)
552 info->channel = c->slave_channel;
553 err = snd_pcm_channel_info(multi->slaves[c->slave_idx].pcm, info);
554 info->channel = channel;
558 static snd_pcm_sframes_t snd_pcm_multi_rewindable(snd_pcm_t *pcm)
560 snd_pcm_multi_t *multi = pcm->private_data;
562 snd_pcm_sframes_t frames = LONG_MAX;
564 for (i = 0; i < multi->slaves_count; ++i) {
565 snd_pcm_sframes_t f = snd_pcm_rewindable(multi->slaves[i].pcm);
576 static snd_pcm_sframes_t snd_pcm_multi_forwardable(snd_pcm_t *pcm)
578 snd_pcm_multi_t *multi = pcm->private_data;
580 snd_pcm_sframes_t frames = LONG_MAX;
582 for (i = 0; i < multi->slaves_count; ++i) {
583 snd_pcm_sframes_t f = snd_pcm_forwardable(multi->slaves[i].pcm);
594 static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
596 snd_pcm_multi_t *multi = pcm->private_data;
598 snd_pcm_uframes_t pos[multi->slaves_count];
599 memset(pos, 0, sizeof(pos));
600 for (i = 0; i < multi->slaves_count; ++i) {
601 snd_pcm_t *slave_i = multi->slaves[i].pcm;
602 snd_pcm_sframes_t f = snd_pcm_rewind(slave_i, frames);
608 /* Realign the pointers */
609 for (i = 0; i < multi->slaves_count; ++i) {
610 snd_pcm_t *slave_i = multi->slaves[i].pcm;
611 snd_pcm_uframes_t f = pos[i] - frames;
612 snd_pcm_sframes_t result;
614 result = INTERNAL(snd_pcm_forward)(slave_i, f);
617 if ((snd_pcm_uframes_t)result != f)
624 static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
626 snd_pcm_multi_t *multi = pcm->private_data;
628 snd_pcm_uframes_t pos[multi->slaves_count];
629 memset(pos, 0, sizeof(pos));
630 for (i = 0; i < multi->slaves_count; ++i) {
631 snd_pcm_t *slave_i = multi->slaves[i].pcm;
632 snd_pcm_sframes_t f = INTERNAL(snd_pcm_forward)(slave_i, frames);
638 /* Realign the pointers */
639 for (i = 0; i < multi->slaves_count; ++i) {
640 snd_pcm_t *slave_i = multi->slaves[i].pcm;
641 snd_pcm_uframes_t f = pos[i] - frames;
642 snd_pcm_sframes_t result;
644 result = snd_pcm_rewind(slave_i, f);
647 if ((snd_pcm_uframes_t)result != f)
654 static int snd_pcm_multi_resume(snd_pcm_t *pcm)
656 snd_pcm_multi_t *multi = pcm->private_data;
659 if (multi->slaves[0].linked)
660 return snd_pcm_resume(multi->slaves[0].linked);
661 for (i = 0; i < multi->slaves_count; ++i) {
662 if (multi->slaves[i].linked)
664 err = snd_pcm_resume(multi->slaves[i].pcm);
671 /* if a multi plugin instance is linked as slaves, every slave PCMs
672 * including the first one has to be relinked to the given master.
674 static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
676 snd_pcm_multi_t *multi = pcm->private_data;
680 for (i = 0; i < multi->slaves_count; ++i) {
681 snd_pcm_unlink(multi->slaves[i].pcm);
682 multi->slaves[i].linked = NULL;
683 err = snd_pcm_link(master, multi->slaves[i].pcm);
688 multi->slaves[i].linked = master;
693 /* linking to a multi as a master is easy - simply link to the first
694 * slave element as its own slaves are already linked.
696 static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
698 snd_pcm_multi_t *multi = pcm1->private_data;
699 if (multi->slaves[0].pcm->fast_ops->link)
700 return multi->slaves[0].pcm->fast_ops->link(multi->slaves[0].pcm, pcm2);
704 static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
706 snd_pcm_multi_t *multi = pcm->private_data;
709 for (i = 0; i < multi->slaves_count; ++i) {
710 if (multi->slaves[i].linked)
711 snd_pcm_unlink(multi->slaves[i].linked);
712 multi->slaves[0].linked = NULL;
717 static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
718 snd_pcm_uframes_t offset,
719 snd_pcm_uframes_t size)
721 snd_pcm_multi_t *multi = pcm->private_data;
724 snd_pcm_sframes_t result;
726 for (i = 0; i < multi->slaves_count; ++i) {
727 slave = multi->slaves[i].pcm;
728 result = snd_pcm_mmap_commit(slave, offset, size);
731 if ((snd_pcm_uframes_t)result != size)
737 static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
739 free(pcm->mmap_channels);
740 free(pcm->running_areas);
741 pcm->mmap_channels = NULL;
742 pcm->running_areas = NULL;
746 static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
748 snd_pcm_multi_t *multi = pcm->private_data;
751 pcm->mmap_channels = calloc(pcm->channels,
752 sizeof(pcm->mmap_channels[0]));
753 pcm->running_areas = calloc(pcm->channels,
754 sizeof(pcm->running_areas[0]));
755 if (!pcm->mmap_channels || !pcm->running_areas) {
756 snd_pcm_multi_munmap(pcm);
760 /* Copy the slave mmapped buffer data */
761 for (c = 0; c < pcm->channels; c++) {
762 snd_pcm_multi_channel_t *chan = &multi->channels[c];
764 if (chan->slave_idx < 0) {
765 snd_pcm_multi_munmap(pcm);
768 slave = multi->slaves[chan->slave_idx].pcm;
769 pcm->mmap_channels[c] =
770 slave->mmap_channels[chan->slave_channel];
771 pcm->mmap_channels[c].channel = c;
772 pcm->running_areas[c] =
773 slave->running_areas[chan->slave_channel];
778 static int snd_pcm_multi_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)
780 snd_pcm_multi_t *multi = pcm->private_data;
781 snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
782 return snd_pcm_may_wait_for_avail_min(slave, snd_pcm_mmap_avail(slave));
785 static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm)
787 snd_pcm_multi_t *multi = pcm->private_data;
788 snd_pcm_chmap_query_t **slave_maps[multi->slaves_count];
789 snd_pcm_chmap_query_t **maps;
793 memset(slave_maps, 0, sizeof(slave_maps));
794 maps = calloc(2, sizeof(*maps));
797 maps[0] = calloc(multi->channels_count + 2, sizeof(int *));
800 maps[0]->type = SND_CHMAP_TYPE_FIXED;
801 maps[0]->map.channels = multi->channels_count;
803 for (i = 0; i < multi->slaves_count; i++) {
804 slave_maps[i] = snd_pcm_query_chmaps(multi->slaves[i].pcm);
809 for (i = 0; i < multi->channels_count; i++) {
810 snd_pcm_multi_channel_t *bind = &multi->channels[i];
811 unsigned int slave_channels =
812 multi->slaves[bind->slave_idx].channels_count;
813 snd_pcm_chmap_query_t **p;
815 for (p = slave_maps[bind->slave_idx]; *p; p++) {
816 if ((*p)->map.channels == slave_channels) {
817 maps[0]->map.pos[i] =
818 (*p)->map.pos[bind->slave_channel];
826 for (i = 0; i < multi->slaves_count; i++) {
828 snd_pcm_free_chmaps(slave_maps[i]);
832 snd_pcm_free_chmaps(maps);
839 static snd_pcm_chmap_t *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
841 snd_pcm_multi_t *multi = pcm->private_data;
842 snd_pcm_chmap_t *map;
843 snd_pcm_chmap_t *slave_maps[multi->slaves_count];
847 memset(slave_maps, 0, sizeof(slave_maps));
848 map = calloc(multi->channels_count + 1, sizeof(int));
852 for (i = 0; i < multi->slaves_count; i++) {
853 slave_maps[i] = snd_pcm_get_chmap(multi->slaves[i].pcm);
858 map->channels = multi->channels_count;
859 for (i = 0; i < multi->channels_count; i++) {
860 snd_pcm_multi_channel_t *bind = &multi->channels[i];
861 map->pos[i] = slave_maps[bind->slave_idx]->pos[bind->slave_channel];
866 for (i = 0; i < multi->slaves_count; i++)
877 static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
879 snd_pcm_multi_t *multi = pcm->private_data;
880 snd_pcm_chmap_t *slave_maps[multi->slaves_count];
884 if (map->channels != multi->channels_count)
887 for (i = 0; i < multi->slaves_count; i++) {
888 slave_maps[i] = calloc(multi->slaves[i].channels_count + 1,
890 if (!slave_maps[i]) {
896 for (i = 0; i < multi->channels_count; i++) {
897 snd_pcm_multi_channel_t *bind = &multi->channels[i];
898 slave_maps[bind->slave_idx]->pos[bind->slave_channel] =
902 for (i = 0; i < multi->slaves_count; i++) {
903 err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_maps[i]);
909 for (i = 0; i < multi->slaves_count; i++)
915 static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
917 snd_pcm_multi_t *multi = pcm->private_data;
919 snd_output_printf(out, "Multi PCM\n");
920 snd_output_printf(out, " Channel bindings:\n");
921 for (k = 0; k < multi->channels_count; ++k) {
922 snd_pcm_multi_channel_t *c = &multi->channels[k];
923 if (c->slave_idx < 0)
925 snd_output_printf(out, " %d: slave %d, channel %d\n",
926 k, c->slave_idx, c->slave_channel);
929 snd_output_printf(out, "Its setup is:\n");
930 snd_pcm_dump_setup(pcm, out);
932 for (k = 0; k < multi->slaves_count; ++k) {
933 snd_output_printf(out, "Slave #%d: ", k);
934 snd_pcm_dump(multi->slaves[k].pcm, out);
938 static const snd_pcm_ops_t snd_pcm_multi_ops = {
939 .close = snd_pcm_multi_close,
940 .info = snd_pcm_multi_info,
941 .hw_refine = snd_pcm_multi_hw_refine,
942 .hw_params = snd_pcm_multi_hw_params,
943 .hw_free = snd_pcm_multi_hw_free,
944 .sw_params = snd_pcm_multi_sw_params,
945 .channel_info = snd_pcm_multi_channel_info,
946 .dump = snd_pcm_multi_dump,
947 .nonblock = snd_pcm_multi_nonblock,
948 .async = snd_pcm_multi_async,
949 .mmap = snd_pcm_multi_mmap,
950 .munmap = snd_pcm_multi_munmap,
951 .query_chmaps = snd_pcm_multi_query_chmaps,
952 .get_chmap = snd_pcm_multi_get_chmap,
953 .set_chmap = snd_pcm_multi_set_chmap,
956 static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
957 .status = snd_pcm_multi_status,
958 .state = snd_pcm_multi_state,
959 .hwsync = snd_pcm_multi_hwsync,
960 .delay = snd_pcm_multi_delay,
961 .prepare = snd_pcm_multi_prepare,
962 .reset = snd_pcm_multi_reset,
963 .start = snd_pcm_multi_start,
964 .drop = snd_pcm_multi_drop,
965 .drain = snd_pcm_multi_drain,
966 .pause = snd_pcm_multi_pause,
967 .writei = snd_pcm_mmap_writei,
968 .writen = snd_pcm_mmap_writen,
969 .readi = snd_pcm_mmap_readi,
970 .readn = snd_pcm_mmap_readn,
971 .rewindable = snd_pcm_multi_rewindable,
972 .rewind = snd_pcm_multi_rewind,
973 .forwardable = snd_pcm_multi_forwardable,
974 .forward = snd_pcm_multi_forward,
975 .resume = snd_pcm_multi_resume,
976 .link = snd_pcm_multi_link,
977 .link_slaves = snd_pcm_multi_link_slaves,
978 .unlink = snd_pcm_multi_unlink,
979 .avail_update = snd_pcm_multi_avail_update,
980 .mmap_commit = snd_pcm_multi_mmap_commit,
981 .htimestamp = snd_pcm_multi_htimestamp,
982 .poll_descriptors_count = snd_pcm_multi_poll_descriptors_count,
983 .poll_descriptors = snd_pcm_multi_poll_descriptors,
984 .poll_revents = snd_pcm_multi_poll_revents,
985 .may_wait_for_avail_min = snd_pcm_multi_may_wait_for_avail_min,
989 * \brief Creates a new Multi PCM
990 * \param pcmp Returns created PCM handle
991 * \param name Name of PCM
992 * \param slaves_count Count of slaves
993 * \param master_slave Master slave number
994 * \param slaves_pcm Array with slave PCMs
995 * \param schannels_count Array with slave channel counts
996 * \param channels_count Count of channels
997 * \param sidxs Array with channels indexes to slaves
998 * \param schannels Array with slave channels
999 * \param close_slaves When set, the slave PCM handle is closed
1000 * \retval zero on success otherwise a negative error code
1001 * \warning Using of this function might be dangerous in the sense
1002 * of compatibility reasons. The prototype might be freely
1003 * changed in future.
1005 int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
1006 unsigned int slaves_count, unsigned int master_slave,
1007 snd_pcm_t **slaves_pcm, unsigned int *schannels_count,
1008 unsigned int channels_count,
1009 int *sidxs, unsigned int *schannels,
1013 snd_pcm_multi_t *multi;
1015 snd_pcm_stream_t stream;
1016 char slave_map[64][64] = { { 0 } };
1020 assert(slaves_count > 0 && slaves_pcm && schannels_count);
1021 assert(channels_count > 0 && sidxs && schannels);
1022 assert(master_slave < slaves_count);
1024 multi = calloc(1, sizeof(snd_pcm_multi_t));
1029 stream = slaves_pcm[0]->stream;
1031 multi->slaves_count = slaves_count;
1032 multi->master_slave = master_slave;
1033 multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
1034 if (!multi->slaves) {
1038 multi->channels_count = channels_count;
1039 multi->channels = calloc(channels_count, sizeof(*multi->channels));
1040 if (!multi->channels) {
1041 free(multi->slaves);
1045 for (i = 0; i < slaves_count; ++i) {
1046 snd_pcm_multi_slave_t *slave = &multi->slaves[i];
1047 assert(slaves_pcm[i]->stream == stream);
1048 slave->pcm = slaves_pcm[i];
1049 slave->channels_count = schannels_count[i];
1050 slave->close_slave = close_slaves;
1052 for (i = 0; i < channels_count; ++i) {
1053 snd_pcm_multi_channel_t *bind = &multi->channels[i];
1054 assert(sidxs[i] < (int)slaves_count);
1055 assert(schannels[i] < schannels_count[sidxs[i]]);
1056 bind->slave_idx = sidxs[i];
1057 bind->slave_channel = schannels[i];
1060 assert(!slave_map[sidxs[i]][schannels[i]]);
1061 slave_map[sidxs[i]][schannels[i]] = 1;
1063 multi->channels_count = channels_count;
1065 err = snd_pcm_new(&pcm, SND_PCM_TYPE_MULTI, name, stream,
1066 multi->slaves[0].pcm->mode);
1068 free(multi->slaves);
1069 free(multi->channels);
1074 pcm->mmap_shadow = 1; /* has own mmap method */
1075 pcm->ops = &snd_pcm_multi_ops;
1076 pcm->fast_ops = &snd_pcm_multi_fast_ops;
1077 pcm->private_data = multi;
1078 pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
1079 pcm->poll_events = multi->slaves[master_slave].pcm->poll_events;
1080 pcm->monotonic = multi->slaves[master_slave].pcm->monotonic;
1081 snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm);
1082 snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
1087 /*! \page pcm_plugins
1089 \section pcm_plugins_multi Plugin: Multiple streams to One
1091 This plugin converts multiple streams to one.
1095 type multi # Multiple streams conversion PCM
1096 slaves { # Slaves definition
1097 ID STR # Slave PCM name
1100 pcm STR # Slave PCM name
1102 pcm { } # Slave PCM definition
1103 channels INT # Slave channels
1106 bindings { # Bindings table
1108 slave STR # Slave key
1109 channel INT # Slave channel
1112 [master INT] # Define the master slave
1116 For example, to bind two PCM streams with two-channel stereo (hw:0,0 and
1117 hw:0,1) as one 4-channel stereo PCM stream, define like this:
1122 slaves.a.pcm "hw:0,0"
1124 slaves.b.pcm "hw:0,1"
1128 bindings.0.channel 0
1130 bindings.1.channel 1
1132 bindings.2.channel 0
1134 bindings.3.channel 1
1137 Note that the resultant pcm "quad" is not in the interleaved format
1138 but in the "complex" format. Hence, it's not accessible by applications
1139 which can handle only the interleaved (or the non-interleaved) format.
1140 In such a case, wrap this PCM with \ref pcm_plugins_route "route" or
1141 \ref pcm_plugins_plug "plug" plugin.
1153 \subsection pcm_plugins_multi_funcref Function reference
1156 <LI>snd_pcm_multi_open()
1157 <LI>_snd_pcm_multi_open()
1163 * \brief Creates a new Multi PCM
1164 * \param pcmp Returns created PCM handle
1165 * \param name Name of PCM
1166 * \param root Root configuration node
1167 * \param conf Configuration node with Multi PCM description
1168 * \param stream Stream type
1169 * \param mode Stream mode
1170 * \retval zero on success otherwise a negative error code
1171 * \warning Using of this function might be dangerous in the sense
1172 * of compatibility reasons. The prototype might be freely
1173 * changed in future.
1175 int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
1176 snd_config_t *root, snd_config_t *conf,
1177 snd_pcm_stream_t stream, int mode)
1179 snd_config_iterator_t i, inext, j, jnext;
1180 snd_config_t *slaves = NULL;
1181 snd_config_t *bindings = NULL;
1184 const char **slaves_id = NULL;
1185 snd_config_t **slaves_conf = NULL;
1186 snd_pcm_t **slaves_pcm = NULL;
1187 unsigned int *slaves_channels = NULL;
1188 int *channels_sidx = NULL;
1189 unsigned int *channels_schannel = NULL;
1190 unsigned int slaves_count = 0;
1191 long master_slave = 0;
1192 unsigned int channels_count = 0;
1193 snd_config_for_each(i, inext, conf) {
1194 snd_config_t *n = snd_config_iterator_entry(i);
1196 if (snd_config_get_id(n, &id) < 0)
1198 if (snd_pcm_conf_generic_id(id))
1200 if (strcmp(id, "slaves") == 0) {
1201 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1202 SNDERR("Invalid type for %s", id);
1208 if (strcmp(id, "bindings") == 0) {
1209 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1210 SNDERR("Invalid type for %s", id);
1216 if (strcmp(id, "master") == 0) {
1217 if (snd_config_get_integer(n, &master_slave) < 0) {
1218 SNDERR("Invalid type for %s", id);
1223 SNDERR("Unknown field %s", id);
1227 SNDERR("slaves is not defined");
1231 SNDERR("bindings is not defined");
1234 snd_config_for_each(i, inext, slaves) {
1237 if (master_slave < 0 || master_slave >= (long)slaves_count) {
1238 SNDERR("Master slave is out of range (0-%u)\n", slaves_count-1);
1241 snd_config_for_each(i, inext, bindings) {
1243 snd_config_t *m = snd_config_iterator_entry(i);
1245 if (snd_config_get_id(m, &id) < 0)
1247 err = safe_strtol(id, &cchannel);
1248 if (err < 0 || cchannel < 0) {
1249 SNDERR("Invalid channel number: %s", id);
1252 if ((unsigned long)cchannel >= channels_count)
1253 channels_count = cchannel + 1;
1255 if (channels_count == 0) {
1256 SNDERR("No channels defined");
1259 slaves_id = calloc(slaves_count, sizeof(*slaves_id));
1260 slaves_conf = calloc(slaves_count, sizeof(*slaves_conf));
1261 slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm));
1262 slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
1263 channels_sidx = calloc(channels_count, sizeof(*channels_sidx));
1264 channels_schannel = calloc(channels_count, sizeof(*channels_schannel));
1265 if (!slaves_id || !slaves_conf || !slaves_pcm || !slaves_channels ||
1266 !channels_sidx || !channels_schannel) {
1271 for (idx = 0; idx < channels_count; ++idx)
1272 channels_sidx[idx] = -1;
1274 snd_config_for_each(i, inext, slaves) {
1275 snd_config_t *m = snd_config_iterator_entry(i);
1278 if (snd_config_get_id(m, &id) < 0)
1280 slaves_id[idx] = id;
1281 err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1,
1282 SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels);
1285 slaves_channels[idx] = channels;
1289 snd_config_for_each(i, inext, bindings) {
1290 snd_config_t *m = snd_config_iterator_entry(i);
1297 if (snd_config_get_id(m, &id) < 0)
1299 err = safe_strtol(id, &cchannel);
1300 if (err < 0 || cchannel < 0) {
1301 SNDERR("Invalid channel number: %s", id);
1305 snd_config_for_each(j, jnext, m) {
1306 snd_config_t *n = snd_config_iterator_entry(j);
1308 if (snd_config_get_id(n, &id) < 0)
1310 if (strcmp(id, "comment") == 0)
1312 if (strcmp(id, "slave") == 0) {
1315 err = snd_config_get_string(n, &str);
1317 err = snd_config_get_integer(n, &val);
1319 SNDERR("Invalid value for %s", id);
1322 sprintf(buf, "%ld", val);
1325 for (k = 0; k < slaves_count; ++k) {
1326 if (strcmp(slaves_id[k], str) == 0)
1331 if (strcmp(id, "channel") == 0) {
1332 err = snd_config_get_integer(n, &schannel);
1334 SNDERR("Invalid type for %s", id);
1339 SNDERR("Unknown field %s", id);
1343 if (slave < 0 || (unsigned int)slave >= slaves_count) {
1344 SNDERR("Invalid or missing sidx for channel %s", id);
1349 (unsigned int) schannel >= slaves_channels[slave]) {
1350 SNDERR("Invalid or missing schannel for channel %s", id);
1354 channels_sidx[cchannel] = slave;
1355 channels_schannel[cchannel] = schannel;
1358 for (idx = 0; idx < slaves_count; ++idx) {
1359 err = snd_pcm_open_slave(&slaves_pcm[idx], root,
1360 slaves_conf[idx], stream, mode,
1364 snd_config_delete(slaves_conf[idx]);
1365 slaves_conf[idx] = NULL;
1367 err = snd_pcm_multi_open(pcmp, name, slaves_count, master_slave,
1368 slaves_pcm, slaves_channels,
1370 channels_sidx, channels_schannel,
1374 for (idx = 0; idx < slaves_count; ++idx) {
1375 if (slaves_pcm[idx])
1376 snd_pcm_close(slaves_pcm[idx]);
1380 for (idx = 0; idx < slaves_count; ++idx) {
1381 if (slaves_conf[idx])
1382 snd_config_delete(slaves_conf[idx]);
1387 free(slaves_channels);
1388 free(channels_sidx);
1389 free(channels_schannel);
1394 SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION);