2 * PCM - Linear conversion
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "pcm_local.h"
25 #include "pcm_plugin.h"
27 /* The best possible hack to support missing optimization in gcc 2.7.2.3 */
28 #if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
29 #define div(a) a /= ROUTE_PLUGIN_RESOLUTION
30 #elif ROUTE_PLUGIN_RESOLUTION == 16
31 #define div(a) a >>= 4
33 #error "Add some code here"
39 #if ROUTE_PLUGIN_FLOAT
42 } snd_pcm_route_ttable_src_t;
44 typedef struct snd_pcm_route_ttable_dst snd_pcm_route_ttable_dst_t;
47 enum {UINT32=0, UINT64=1, FLOAT=2} sum_idx;
52 snd_pcm_format_t dst_sfmt;
54 snd_pcm_route_ttable_dst_t *dsts;
55 } snd_pcm_route_params_t;
58 typedef void (*route_f)(const snd_pcm_channel_area_t *dst_area,
59 snd_pcm_uframes_t dst_offset,
60 const snd_pcm_channel_area_t *src_areas,
61 snd_pcm_uframes_t src_offset,
62 snd_pcm_uframes_t frames,
63 const snd_pcm_route_ttable_dst_t *ttable,
64 const snd_pcm_route_params_t *params);
66 struct snd_pcm_route_ttable_dst {
67 int att; /* Attenuated */
69 snd_pcm_route_ttable_src_t* srcs;
76 #if ROUTE_PLUGIN_FLOAT
82 /* This field need to be the first */
83 snd_pcm_plugin_t plug;
84 snd_pcm_format_t sformat;
86 snd_pcm_route_params_t params;
90 void snd_pcm_route_convert1_zero(const snd_pcm_channel_area_t *dst_area,
91 snd_pcm_uframes_t dst_offset,
92 const snd_pcm_channel_area_t *src_areas ATTRIBUTE_UNUSED,
93 snd_pcm_uframes_t src_offset ATTRIBUTE_UNUSED,
94 snd_pcm_uframes_t frames,
95 const snd_pcm_route_ttable_dst_t* ttable ATTRIBUTE_UNUSED,
96 const snd_pcm_route_params_t *params)
98 snd_pcm_area_silence(dst_area, dst_offset, frames, params->dst_sfmt);
101 void snd_pcm_route_convert1_one(const snd_pcm_channel_area_t *dst_area,
102 snd_pcm_uframes_t dst_offset,
103 const snd_pcm_channel_area_t *src_areas,
104 snd_pcm_uframes_t src_offset,
105 snd_pcm_uframes_t frames,
106 const snd_pcm_route_ttable_dst_t* ttable,
107 const snd_pcm_route_params_t *params)
110 #include "plugin_ops.h"
113 const snd_pcm_channel_area_t *src_area = 0;
117 int src_step, dst_step;
118 for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
119 src_area = &src_areas[ttable->srcs[srcidx].channel];
120 if (src_area->addr != NULL)
123 if (srcidx == ttable->nsrcs) {
124 snd_pcm_route_convert1_zero(dst_area, dst_offset,
125 src_areas, src_offset,
126 frames, ttable, params);
130 conv = conv_labels[params->conv_idx];
131 src = snd_pcm_channel_area_addr(src_area, src_offset);
132 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
133 src_step = snd_pcm_channel_area_step(src_area);
134 dst_step = snd_pcm_channel_area_step(dst_area);
135 while (frames-- > 0) {
137 #define CONV_END after
138 #include "plugin_ops.h"
146 void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
147 snd_pcm_uframes_t dst_offset,
148 const snd_pcm_channel_area_t *src_areas,
149 snd_pcm_uframes_t src_offset,
150 snd_pcm_uframes_t frames,
151 const snd_pcm_route_ttable_dst_t* ttable,
152 const snd_pcm_route_params_t *params)
156 #include "plugin_ops.h"
159 static void *zero_labels[3] = {
160 &&zero_int32, &&zero_int64,
161 #if ROUTE_PLUGIN_FLOAT
166 static void *add_labels[3 * 2] = {
167 &&add_int32_noatt, &&add_int32_att,
168 &&add_int64_noatt, &&add_int64_att,
169 #if ROUTE_PLUGIN_FLOAT
170 &&add_float_noatt, &&add_float_att
173 /* sum_type att shift */
174 static void *norm_labels[3 * 2 * 4] = {
176 &&norm_int32_8_noatt,
177 &&norm_int32_16_noatt,
178 &&norm_int32_24_noatt,
183 &&norm_int64_0_noatt,
184 &&norm_int64_8_noatt,
185 &&norm_int64_16_noatt,
186 &&norm_int64_24_noatt,
191 #if ROUTE_PLUGIN_FLOAT
202 void *zero, *get, *add, *norm, *put32;
203 int nsrcs = ttable->nsrcs;
206 const char *srcs[nsrcs];
207 int src_steps[nsrcs];
208 snd_pcm_route_ttable_src_t src_tt[nsrcs];
209 u_int32_t sample = 0;
210 int srcidx, srcidx1 = 0;
211 for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
212 const snd_pcm_channel_area_t *src_area = &src_areas[ttable->srcs[srcidx].channel];
213 srcs[srcidx1] = snd_pcm_channel_area_addr(src_area, src_offset);
214 src_steps[srcidx1] = snd_pcm_channel_area_step(src_area);
215 src_tt[srcidx1] = ttable->srcs[srcidx];
220 snd_pcm_route_convert1_zero(dst_area, dst_offset,
221 src_areas, src_offset,
222 frames, ttable, params);
224 } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
225 snd_pcm_route_convert1_one(dst_area, dst_offset,
226 src_areas, src_offset,
227 frames, ttable, params);
231 zero = zero_labels[params->sum_idx];
232 get = getu_labels[params->get_idx];
233 add = add_labels[params->sum_idx * 2 + ttable->att];
234 norm = norm_labels[params->sum_idx * 8 + ttable->att * 4 + 4 - params->src_size];
235 put32 = put32_labels[params->put_idx];
236 dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
237 dst_step = snd_pcm_channel_area_step(dst_area);
239 while (frames-- > 0) {
240 snd_pcm_route_ttable_src_t *ttp = src_tt;
251 #if ROUTE_PLUGIN_FLOAT
257 for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
258 const char *src = srcs[srcidx];
262 #define GETU_END after_get
263 #include "plugin_ops.h"
270 sum.as_uint32 += sample * ttp->as_int;
274 sum.as_uint32 += sample;
277 sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
281 sum.as_uint64 += sample;
283 #if ROUTE_PLUGIN_FLOAT
285 sum.as_float += sample * ttp->as_float;
289 sum.as_float += sample;
293 srcs[srcidx] += src_steps[srcidx];
300 sum.as_uint64 = sum.as_uint32;
308 sum.as_uint64 = sum.as_uint32;
310 sum.as_uint64 <<= 16;
315 sum.as_uint64 = sum.as_uint32;
317 sum.as_uint64 <<= 24;
322 sum.as_uint64 = sum.as_uint32;
328 sum.as_uint64 = sum.as_uint32;
330 sum.as_uint64 <<= 16;
334 sum.as_uint64 = sum.as_uint32;
336 sum.as_uint64 <<= 24;
341 if (sum.as_uint64 > (u_int32_t)0xffffffff)
342 sample = (u_int32_t)0xffffffff;
344 sample = sum.as_uint64;
347 #if ROUTE_PLUGIN_FLOAT
349 sum.as_float *= 1 << 8;
352 sum.as_float *= 1 << 16;
355 sum.as_float *= 1 << 24;
359 sum.as_float = floor(sum.as_float + 0.5);
360 if (sum.as_float > (u_int32_t)0xffffffff)
361 sample = (u_int32_t)0xffffffff;
363 sample = sum.as_float;
370 #define PUT32_END after_put32
371 #include "plugin_ops.h"
379 void snd_pcm_route_convert(const snd_pcm_channel_area_t *dst_areas,
380 snd_pcm_uframes_t dst_offset,
381 const snd_pcm_channel_area_t *src_areas,
382 snd_pcm_uframes_t src_offset,
383 snd_pcm_uframes_t dst_channels,
384 snd_pcm_uframes_t frames,
385 snd_pcm_route_params_t *params)
387 unsigned int dst_channel;
388 snd_pcm_route_ttable_dst_t *dstp;
389 const snd_pcm_channel_area_t *dst_area;
392 dst_area = dst_areas;
393 for (dst_channel = 0; dst_channel < dst_channels; ++dst_channel) {
394 if (dst_channel >= params->ndsts)
395 snd_pcm_route_convert1_zero(dst_area, dst_offset,
396 src_areas, src_offset,
397 frames, dstp, params);
399 dstp->func(dst_area, dst_offset,
400 src_areas, src_offset,
401 frames, dstp, params);
407 static int snd_pcm_route_close(snd_pcm_t *pcm)
409 snd_pcm_route_t *route = pcm->private_data;
410 snd_pcm_route_params_t *params = &route->params;
412 unsigned int dst_channel;
413 if (route->plug.close_slave)
414 err = snd_pcm_close(route->plug.slave);
416 for (dst_channel = 0; dst_channel < params->ndsts; ++dst_channel) {
417 if (params->dsts[dst_channel].srcs != NULL)
418 free(params->dsts[dst_channel].srcs);
426 static int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
429 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_PLUGIN };
430 snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
431 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
435 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
439 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
442 err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
445 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
449 static int snd_pcm_route_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
451 snd_pcm_route_t *route = pcm->private_data;
452 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
453 _snd_pcm_hw_params_any(sparams);
454 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
456 if (route->sformat != SND_PCM_FORMAT_UNKNOWN) {
457 _snd_pcm_hw_params_set_format(sparams, route->sformat);
458 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
460 if (route->schannels >= 0) {
461 _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
462 route->schannels, 0);
467 static int snd_pcm_route_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
468 snd_pcm_hw_params_t *sparams)
470 snd_pcm_route_t *route = pcm->private_data;
472 unsigned int links = (SND_PCM_HW_PARBIT_RATE |
473 SND_PCM_HW_PARBIT_PERIODS |
474 SND_PCM_HW_PARBIT_PERIOD_SIZE |
475 SND_PCM_HW_PARBIT_PERIOD_TIME |
476 SND_PCM_HW_PARBIT_BUFFER_SIZE |
477 SND_PCM_HW_PARBIT_BUFFER_TIME |
478 SND_PCM_HW_PARBIT_TICK_TIME);
479 if (route->sformat == SND_PCM_FORMAT_UNKNOWN)
480 links |= (SND_PCM_HW_PARBIT_FORMAT |
481 SND_PCM_HW_PARBIT_SUBFORMAT |
482 SND_PCM_HW_PARBIT_SAMPLE_BITS);
483 if (route->schannels < 0)
484 links |= SND_PCM_HW_PARBIT_CHANNELS;
485 err = _snd_pcm_hw_params_refine(sparams, links, params);
491 static int snd_pcm_route_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
492 snd_pcm_hw_params_t *sparams)
494 snd_pcm_route_t *route = pcm->private_data;
496 unsigned int links = (SND_PCM_HW_PARBIT_RATE |
497 SND_PCM_HW_PARBIT_PERIODS |
498 SND_PCM_HW_PARBIT_PERIOD_SIZE |
499 SND_PCM_HW_PARBIT_PERIOD_TIME |
500 SND_PCM_HW_PARBIT_BUFFER_SIZE |
501 SND_PCM_HW_PARBIT_BUFFER_TIME |
502 SND_PCM_HW_PARBIT_TICK_TIME);
503 if (route->sformat == SND_PCM_FORMAT_UNKNOWN)
504 links |= (SND_PCM_HW_PARBIT_FORMAT |
505 SND_PCM_HW_PARBIT_SUBFORMAT |
506 SND_PCM_HW_PARBIT_SAMPLE_BITS);
507 if (route->schannels < 0)
508 links |= SND_PCM_HW_PARBIT_CHANNELS;
509 err = _snd_pcm_hw_params_refine(params, links, sparams);
515 static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
517 return snd_pcm_hw_refine_slave(pcm, params,
518 snd_pcm_route_hw_refine_cprepare,
519 snd_pcm_route_hw_refine_cchange,
520 snd_pcm_route_hw_refine_sprepare,
521 snd_pcm_route_hw_refine_schange,
522 snd_pcm_plugin_hw_refine_slave);
525 static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
527 snd_pcm_route_t *route = pcm->private_data;
528 snd_pcm_t *slave = route->plug.slave;
529 snd_pcm_format_t src_format, dst_format;
530 int err = snd_pcm_hw_params_slave(pcm, params,
531 snd_pcm_route_hw_refine_cchange,
532 snd_pcm_route_hw_refine_sprepare,
533 snd_pcm_route_hw_refine_schange,
534 snd_pcm_plugin_hw_params_slave);
538 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
539 src_format = snd_pcm_hw_params_get_format(params);
540 dst_format = slave->format;
542 src_format = slave->format;
543 dst_format = snd_pcm_hw_params_get_format(params);
545 route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_U16);
546 route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_U32, dst_format);
547 route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
548 route->params.src_size = snd_pcm_format_width(src_format) / 8;
549 route->params.dst_sfmt = dst_format;
550 #if ROUTE_PLUGIN_FLOAT
551 route->params.sum_idx = FLOAT;
554 route->params.sum_idx = UINT64;
556 route->params.sum_idx = UINT32;
561 static snd_pcm_uframes_t
562 snd_pcm_route_write_areas(snd_pcm_t *pcm,
563 const snd_pcm_channel_area_t *areas,
564 snd_pcm_uframes_t offset,
565 snd_pcm_uframes_t size,
566 const snd_pcm_channel_area_t *slave_areas,
567 snd_pcm_uframes_t slave_offset,
568 snd_pcm_uframes_t *slave_sizep)
570 snd_pcm_route_t *route = pcm->private_data;
571 snd_pcm_t *slave = route->plug.slave;
572 if (size > *slave_sizep)
574 snd_pcm_route_convert(slave_areas, slave_offset,
576 slave->channels, size, &route->params);
581 static snd_pcm_uframes_t
582 snd_pcm_route_read_areas(snd_pcm_t *pcm,
583 const snd_pcm_channel_area_t *areas,
584 snd_pcm_uframes_t offset,
585 snd_pcm_uframes_t size,
586 const snd_pcm_channel_area_t *slave_areas,
587 snd_pcm_uframes_t slave_offset,
588 snd_pcm_uframes_t *slave_sizep)
590 snd_pcm_route_t *route = pcm->private_data;
591 if (size > *slave_sizep)
593 snd_pcm_route_convert(areas, offset,
594 slave_areas, slave_offset,
595 pcm->channels, size, &route->params);
600 static void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out)
602 snd_pcm_route_t *route = pcm->private_data;
604 if (route->sformat == SND_PCM_FORMAT_UNKNOWN)
605 snd_output_printf(out, "Route conversion PCM\n");
607 snd_output_printf(out, "Route conversion PCM (sformat=%s)\n",
608 snd_pcm_format_name(route->sformat));
609 snd_output_puts(out, "Transformation table:\n");
610 for (dst = 0; dst < route->params.ndsts; dst++) {
611 snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
615 snd_output_printf(out, "%d <- ", dst);
618 snd_pcm_route_ttable_src_t *s = &d->srcs[src];
620 snd_output_printf(out, "%d*%g", s->channel, s->as_float);
622 snd_output_printf(out, "%d", s->channel);
626 snd_output_puts(out, " + ");
628 snd_output_putc(out, '\n');
631 snd_output_printf(out, "Its setup is:\n");
632 snd_pcm_dump_setup(pcm, out);
634 snd_output_printf(out, "Slave: ");
635 snd_pcm_dump(route->plug.slave, out);
638 snd_pcm_ops_t snd_pcm_route_ops = {
639 close: snd_pcm_route_close,
640 info: snd_pcm_plugin_info,
641 hw_refine: snd_pcm_route_hw_refine,
642 hw_params: snd_pcm_route_hw_params,
643 hw_free: snd_pcm_plugin_hw_free,
644 sw_params: snd_pcm_plugin_sw_params,
645 channel_info: snd_pcm_plugin_channel_info,
646 dump: snd_pcm_route_dump,
647 nonblock: snd_pcm_plugin_nonblock,
648 async: snd_pcm_plugin_async,
649 mmap: snd_pcm_plugin_mmap,
650 munmap: snd_pcm_plugin_munmap,
653 int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t stream,
654 unsigned int tt_ssize,
655 snd_pcm_route_ttable_entry_t *ttable,
656 unsigned int tt_cused, unsigned int tt_sused)
658 unsigned int src_channel, dst_channel;
659 snd_pcm_route_ttable_dst_t *dptr;
660 unsigned int sused, dused, smul, dmul;
661 if (stream == SND_PCM_STREAM_PLAYBACK) {
672 params->ndsts = dused;
673 dptr = calloc(dused, sizeof(*params->dsts));
677 for (dst_channel = 0; dst_channel < dused; ++dst_channel) {
678 snd_pcm_route_ttable_entry_t t = 0;
681 snd_pcm_route_ttable_src_t srcs[sused];
682 for (src_channel = 0; src_channel < sused; ++src_channel) {
683 snd_pcm_route_ttable_entry_t v;
684 v = ttable[src_channel * smul + dst_channel * dmul];
685 assert(v >= 0 && v <= FULL);
687 srcs[nsrcs].channel = src_channel;
688 #if ROUTE_PLUGIN_FLOAT
689 /* Also in user space for non attenuated */
690 srcs[nsrcs].as_int = (v == FULL ? ROUTE_PLUGIN_RESOLUTION : 0);
691 srcs[nsrcs].as_float = v;
693 srcs[nsrcs].as_int = v;
707 dptr->func = snd_pcm_route_convert1_zero;
708 else if (nsrcs == 1 && !att)
709 dptr->func = snd_pcm_route_convert1_one;
711 dptr->func = snd_pcm_route_convert1_many;
713 dptr->srcs = calloc(nsrcs, sizeof(*srcs));
716 memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
725 int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
726 snd_pcm_format_t sformat, unsigned int schannels,
727 snd_pcm_route_ttable_entry_t *ttable,
728 unsigned int tt_ssize,
729 unsigned int tt_cused, unsigned int tt_sused,
730 snd_pcm_t *slave, int close_slave)
733 snd_pcm_route_t *route;
735 assert(pcmp && slave && ttable);
736 if (sformat != SND_PCM_FORMAT_UNKNOWN &&
737 snd_pcm_format_linear(sformat) != 1)
739 route = calloc(1, sizeof(snd_pcm_route_t));
743 route->sformat = sformat;
744 route->schannels = schannels;
745 route->plug.read = snd_pcm_route_read_areas;
746 route->plug.write = snd_pcm_route_write_areas;
747 route->plug.slave = slave;
748 route->plug.close_slave = close_slave;
750 pcm = calloc(1, sizeof(snd_pcm_t));
756 pcm->name = strdup(name);
757 pcm->type = SND_PCM_TYPE_ROUTE;
758 pcm->stream = slave->stream;
759 pcm->mode = slave->mode;
760 pcm->ops = &snd_pcm_route_ops;
762 pcm->fast_ops = &snd_pcm_plugin_fast_ops;
763 pcm->fast_op_arg = pcm;
764 pcm->private_data = route;
765 pcm->poll_fd = slave->poll_fd;
766 pcm->hw_ptr = &route->plug.hw_ptr;
767 pcm->appl_ptr = &route->plug.appl_ptr;
768 err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
778 int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable,
779 unsigned int tt_csize, unsigned int tt_ssize,
780 unsigned int *tt_cused, unsigned int *tt_sused,
785 snd_config_iterator_t i, inext;
787 for (k = 0; k < tt_csize * tt_ssize; ++k)
789 snd_config_for_each(i, inext, tt) {
790 snd_config_t *in = snd_config_iterator_entry(i);
791 snd_config_iterator_t j, jnext;
795 cchannel = strtol(snd_config_get_id(in), &p, 10);
797 cchannel < 0 || (unsigned int) cchannel > tt_csize) {
798 SNDERR("Invalid client channel: %s", snd_config_get_id(in));
801 if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND)
803 snd_config_for_each(j, jnext, in) {
804 snd_config_t *jn = snd_config_iterator_entry(j);
808 const char *id = snd_config_get_id(jn);
810 schannel = strtol(id, &p, 10);
812 schannel < 0 || (unsigned int) schannel > tt_ssize ||
813 (schannels > 0 && schannel >= schannels)) {
814 SNDERR("Invalid slave channel: %s", id);
817 err = snd_config_get_real(jn, &value);
820 err = snd_config_get_integer(jn, &v);
822 SNDERR("Invalid type for %s", id);
827 ttable[cchannel * tt_ssize + schannel] = value;
828 if (schannel > sused)
831 if (cchannel > cused)
834 *tt_sused = sused + 1;
835 *tt_cused = cused + 1;
839 #define MAX_CHANNELS 32
841 int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
843 snd_pcm_stream_t stream, int mode)
845 snd_config_iterator_t i, next;
846 const char *sname = NULL;
849 snd_config_t *slave = NULL;
850 snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
852 snd_config_t *tt = NULL;
853 snd_pcm_route_ttable_entry_t ttable[MAX_CHANNELS*MAX_CHANNELS];
854 unsigned int cused, sused;
855 snd_config_for_each(i, next, conf) {
856 snd_config_t *n = snd_config_iterator_entry(i);
857 const char *id = snd_config_get_id(n);
858 if (strcmp(id, "comment") == 0)
860 if (strcmp(id, "type") == 0)
862 if (strcmp(id, "slave") == 0) {
866 if (strcmp(id, "ttable") == 0) {
867 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
868 SNDERR("Invalid type for %s", id);
874 SNDERR("Unknown field %s", id);
878 SNDERR("slave is not defined");
882 SNDERR("ttable is not defined");
885 err = snd_pcm_slave_conf(slave, &sname, 2,
886 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
887 SND_PCM_HW_PARAM_CHANNELS, 0, &schannels);
890 if (sformat != SND_PCM_FORMAT_UNKNOWN &&
891 snd_pcm_format_linear(sformat) != 1) {
892 SNDERR("slave format is not linear");
896 err = snd_pcm_route_load_ttable(tt, ttable, MAX_CHANNELS, MAX_CHANNELS,
897 &cused, &sused, schannels);
901 /* This is needed cause snd_config_update may destroy config */
902 sname = strdup(sname);
905 err = snd_pcm_open(&spcm, sname, stream, mode);
906 free((void *) sname);
909 err = snd_pcm_route_open(pcmp, name, sformat, schannels,
910 ttable, MAX_CHANNELS,