11da177e4SLinus Torvalds /*
20534ab42STakashi Iwai * Route Plug-In
31da177e4SLinus Torvalds * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * This library is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds * it under the terms of the GNU Library General Public License as
81da177e4SLinus Torvalds * published by the Free Software Foundation; either version 2 of
91da177e4SLinus Torvalds * the License, or (at your option) any later version.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful,
121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
141da177e4SLinus Torvalds * GNU Library General Public License for more details.
151da177e4SLinus Torvalds *
161da177e4SLinus Torvalds * You should have received a copy of the GNU Library General Public
171da177e4SLinus Torvalds * License along with this library; if not, write to the Free Software
181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds */
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds #include <linux/time.h>
231da177e4SLinus Torvalds #include <sound/core.h>
241da177e4SLinus Torvalds #include <sound/pcm.h>
251da177e4SLinus Torvalds #include "pcm_plugin.h"
261da177e4SLinus Torvalds
zero_areas(struct snd_pcm_plugin_channel * dvp,int ndsts,snd_pcm_uframes_t frames,snd_pcm_format_t format)270534ab42STakashi Iwai static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
28fea952e5SClemens Ladisch snd_pcm_uframes_t frames, snd_pcm_format_t format)
291da177e4SLinus Torvalds {
300534ab42STakashi Iwai int dst = 0;
310534ab42STakashi Iwai for (; dst < ndsts; ++dst) {
320534ab42STakashi Iwai if (dvp->wanted)
330534ab42STakashi Iwai snd_pcm_area_silence(&dvp->area, 0, frames, format);
340534ab42STakashi Iwai dvp->enabled = 0;
350534ab42STakashi Iwai dvp++;
360534ab42STakashi Iwai }
371da177e4SLinus Torvalds }
381da177e4SLinus Torvalds
copy_area(const struct snd_pcm_plugin_channel * src_channel,struct snd_pcm_plugin_channel * dst_channel,snd_pcm_uframes_t frames,snd_pcm_format_t format)390534ab42STakashi Iwai static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
406ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *dst_channel,
41fea952e5SClemens Ladisch snd_pcm_uframes_t frames, snd_pcm_format_t format)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds dst_channel->enabled = 1;
440534ab42STakashi Iwai snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds
route_transfer(struct snd_pcm_plugin * plugin,const struct snd_pcm_plugin_channel * src_channels,struct snd_pcm_plugin_channel * dst_channels,snd_pcm_uframes_t frames)476ac77bc1STakashi Iwai static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
486ac77bc1STakashi Iwai const struct snd_pcm_plugin_channel *src_channels,
496ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *dst_channels,
501da177e4SLinus Torvalds snd_pcm_uframes_t frames)
511da177e4SLinus Torvalds {
520534ab42STakashi Iwai int nsrcs, ndsts, dst;
536ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *dvp;
54fea952e5SClemens Ladisch snd_pcm_format_t format;
551da177e4SLinus Torvalds
567eaa943cSTakashi Iwai if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
577eaa943cSTakashi Iwai return -ENXIO;
581da177e4SLinus Torvalds if (frames == 0)
591da177e4SLinus Torvalds return 0;
60*4cc8d650STakashi Iwai if (frames > dst_channels[0].frames)
61*4cc8d650STakashi Iwai frames = dst_channels[0].frames;
621da177e4SLinus Torvalds
630534ab42STakashi Iwai nsrcs = plugin->src_format.channels;
640534ab42STakashi Iwai ndsts = plugin->dst_format.channels;
651da177e4SLinus Torvalds
660534ab42STakashi Iwai format = plugin->dst_format.format;
671da177e4SLinus Torvalds dvp = dst_channels;
680534ab42STakashi Iwai if (nsrcs <= 1) {
690534ab42STakashi Iwai /* expand to all channels */
700534ab42STakashi Iwai for (dst = 0; dst < ndsts; ++dst) {
710534ab42STakashi Iwai copy_area(src_channels, dvp, frames, format);
721da177e4SLinus Torvalds dvp++;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds return frames;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds
770534ab42STakashi Iwai for (dst = 0; dst < ndsts && dst < nsrcs; ++dst) {
780534ab42STakashi Iwai copy_area(src_channels, dvp, frames, format);
790534ab42STakashi Iwai dvp++;
800534ab42STakashi Iwai src_channels++;
811da177e4SLinus Torvalds }
820534ab42STakashi Iwai if (dst < ndsts)
830534ab42STakashi Iwai zero_areas(dvp, ndsts - dst, frames, format);
840534ab42STakashi Iwai return frames;
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds
snd_pcm_plugin_build_route(struct snd_pcm_substream * plug,struct snd_pcm_plugin_format * src_format,struct snd_pcm_plugin_format * dst_format,struct snd_pcm_plugin ** r_plugin)876ac77bc1STakashi Iwai int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug,
886ac77bc1STakashi Iwai struct snd_pcm_plugin_format *src_format,
896ac77bc1STakashi Iwai struct snd_pcm_plugin_format *dst_format,
906ac77bc1STakashi Iwai struct snd_pcm_plugin **r_plugin)
911da177e4SLinus Torvalds {
926ac77bc1STakashi Iwai struct snd_pcm_plugin *plugin;
931da177e4SLinus Torvalds int err;
941da177e4SLinus Torvalds
957eaa943cSTakashi Iwai if (snd_BUG_ON(!r_plugin))
967eaa943cSTakashi Iwai return -ENXIO;
971da177e4SLinus Torvalds *r_plugin = NULL;
987eaa943cSTakashi Iwai if (snd_BUG_ON(src_format->rate != dst_format->rate))
997eaa943cSTakashi Iwai return -ENXIO;
1007eaa943cSTakashi Iwai if (snd_BUG_ON(src_format->format != dst_format->format))
1017eaa943cSTakashi Iwai return -ENXIO;
1021da177e4SLinus Torvalds
1030534ab42STakashi Iwai err = snd_pcm_plugin_build(plug, "route conversion",
1040534ab42STakashi Iwai src_format, dst_format, 0, &plugin);
1051da177e4SLinus Torvalds if (err < 0)
1061da177e4SLinus Torvalds return err;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds plugin->transfer = route_transfer;
1091da177e4SLinus Torvalds *r_plugin = plugin;
1101da177e4SLinus Torvalds return 0;
1111da177e4SLinus Torvalds }
112