xref: /linux/sound/core/oss/route.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
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