• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

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
9 * PCM - Multi
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
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"
37 #ifndef PIC
38 /* entry for static linking */
39 const char *_snd_module_pcm_multi = "";
40 #endif
42 #ifndef DOC_HIDDEN
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;
51 typedef struct {
52 int slave_idx;
53 unsigned int slave_channel;
54 } snd_pcm_multi_channel_t;
56 typedef 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;
64 #endif
66 static int snd_pcm_multi_close(snd_pcm_t *pcm)
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;
79 free(multi->slaves);
80 free(multi->channels);
81 free(multi);
82 return ret;
85 static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
87 return 0;
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;
107 snd_pcm_t *slave;
108 snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
109 int err;
110 unsigned int i;
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;
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;
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;
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;
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;
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,
172 &saccess_mask);
173 _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
174 slave->channels_count, 0);
175 return 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)
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;
205 err = _snd_pcm_hw_params_refine(sparams, links, params);
206 if (err < 0)
207 return err;
208 return 0;
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)
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;
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;
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;
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;
283 err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
284 if (err < 0)
285 return err;
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;
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);
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;
313 return 0;
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)
322 unsigned int i;
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;
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;
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;
352 reset_links(multi);
353 return 0;
356 static int snd_pcm_multi_hw_free(snd_pcm_t *pcm)
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;
373 return err;
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;
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;
387 return 0;
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;
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;
431 return ret;
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;
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.
451 err = snd_pcm_prepare(multi->slaves[i].pcm);
452 if (err < 0)
453 result = err;
455 return result;
458 static int snd_pcm_multi_reset(snd_pcm_t *pcm)
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;
469 return result;
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;
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;
490 return err;
493 static int snd_pcm_multi_drop(snd_pcm_t *pcm)
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;
507 return err;
510 static int snd_pcm_multi_drain(snd_pcm_t *pcm)
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;
524 return err;
527 static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
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;
541 return err;
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];
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;
558 static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
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;
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;
585 return frames;
588 static snd_pcm_sframes_t snd_pcm_multi_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
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;
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;
615 return frames;
618 static int snd_pcm_multi_resume(snd_pcm_t *pcm)
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;
632 return err;
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.
638 static int snd_pcm_multi_link_slaves(snd_pcm_t *pcm, snd_pcm_t *master)
640 snd_pcm_multi_t *multi = pcm->private_data;
641 unsigned int i;
642 int err;
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;
652 multi->slaves[i].linked = master;
654 return 0;
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.
660 static int snd_pcm_multi_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
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;
668 static int snd_pcm_multi_unlink(snd_pcm_t *pcm)
670 snd_pcm_multi_t *multi = pcm->private_data;
671 unsigned int i;
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;
678 return 0;
681 static 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)
685 snd_pcm_multi_t *multi = pcm->private_data;
686 snd_pcm_t *slave;
687 unsigned int i;
688 snd_pcm_sframes_t result;
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;
698 return size;
701 static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
703 free(pcm->mmap_channels);
704 free(pcm->running_areas);
705 pcm->mmap_channels = NULL;
706 pcm->running_areas = NULL;
707 return 0;
710 static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
712 snd_pcm_multi_t *multi = pcm->private_data;
713 unsigned int c;
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;
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;
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];
739 return 0;
742 static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
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);
755 if (pcm->setup) {
756 snd_output_printf(out, "Its setup is:\n");
757 snd_pcm_dump_setup(pcm, out);
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);
765 static 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,
780 static 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,
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.
826 int 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)
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;
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);
845 multi = calloc(1, sizeof(snd_pcm_multi_t));
846 if (!multi) {
847 return -ENOMEM;
850 stream = slaves_pcm[0]->stream;
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;
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;
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;
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;
884 multi->channels_count = channels_count;
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;
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;
908 /*! \page pcm_plugins
910 \section pcm_plugins_multi Plugin: Multiple streams to One
912 This plugin converts multiple streams to one.
914 \code
915 pcm.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
927 bindings { # Bindings table
928 N {
929 slave STR # Slave key
930 channel INT # Slave channel
933 [master INT] # Define the master slave
935 \endcode
937 For example, to bind two PCM streams with two-channel stereo (hw:0,0 and
938 hw:0,1) as one 4-channel stereo PCM stream, define like this:
939 \code
940 pcm.quad {
941 type multi
943 slaves.a.pcm "hw:0,0"
944 slaves.a.channels 2
945 slaves.b.pcm "hw:0,1"
946 slaves.b.channels 2
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
957 \endcode
958 Note that the resultant pcm "quad" is not in the interleaved format
959 but in the "complex" format. Hence, it's not accessible by applications
960 which can handle only the interleaved (or the non-interleaved) format.
961 In such a case, wrap this PCM with \ref pcm_plugins_route "route" or
962 \ref pcm_plugins_plug "plug" plugin.
963 \code
964 pcm.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
972 \endcode
974 \subsection pcm_plugins_multi_funcref Function reference
976 <UL>
977 <LI>snd_pcm_multi_open()
978 <LI>_snd_pcm_multi_open()
979 </UL>
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.
996 int _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)
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;
1026 slaves = n;
1027 continue;
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;
1034 bindings = n;
1035 continue;
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;
1042 continue;
1044 SNDERR("Unknown field %s", id);
1045 return -EINVAL;
1047 if (!slaves) {
1048 SNDERR("slaves is not defined");
1049 return -EINVAL;
1051 if (!bindings) {
1052 SNDERR("bindings is not defined");
1053 return -EINVAL;
1055 snd_config_for_each(i, inext, slaves) {
1056 ++slaves_count;
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;
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;
1073 if ((unsigned long)cchannel >= channels_count)
1074 channels_count = cchannel + 1;
1076 if (channels_count == 0) {
1077 SNDERR("No channels defined");
1078 return -EINVAL;
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;
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;
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;
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;
1143 sprintf(buf, "%ld", val);
1144 str = buf;
1146 for (k = 0; k < slaves_count; ++k) {
1147 if (strcmp(slaves_id[k], str) == 0)
1148 slave = k;
1150 continue;
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;
1158 continue;
1160 SNDERR("Unknown field %s", id);
1161 err = -EINVAL;
1162 goto _free;
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;
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;
1175 channels_sidx[cchannel] = slave;
1176 channels_schannel[cchannel] = schannel;
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;
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]);
1200 if (slaves_conf) {
1201 for (idx = 0; idx < slaves_count; ++idx) {
1202 if (slaves_conf[idx])
1203 snd_config_delete(slaves_conf[idx]);
1205 free(slaves_conf);
1207 free(slaves_pcm);
1208 free(slaves_channels);
1209 free(channels_sidx);
1210 free(channels_schannel);
1211 free(slaves_id);
1212 return err;
1214 #ifndef DOC_HIDDEN
1215 SND_DLSYM_BUILD_VERSION(_snd_pcm_multi_open, SND_PCM_DLSYM_VERSION);
1216 #endif