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 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 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 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 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