aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-07-16 15:56:39 +0200
committerJaroslav Kysela <perex@perex.cz>2010-07-16 15:56:39 +0200
commit031f47be4fdefb7097101294717e3a736a03f081 (patch)
tree16aa0586f1f30c6f94bba5fe7404dd7096392bdd
parent78564f0c9bfc2a8e4f9fcdc0f05df2efc3fd7496 (diff)
downloadalsa-driver-build-unstable-031f47be4fdefb7097101294717e3a736a03f081.tar.gz
aloop: add pcm_notify module parameter
In some use cases, it is not good to restrict to one sample format/ channel count/rate the both playback and capture. For grabbers or any other applications, it would be necessary to stop the capture stream when playback parameters change to allow restart capturing with the proper setup. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--drivers/aloop-kernel.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/aloop-kernel.c b/drivers/aloop-kernel.c
index a5c386251..9fc3c3f54 100644
--- a/drivers/aloop-kernel.c
+++ b/drivers/aloop-kernel.c
@@ -52,6 +52,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
@@ -61,6 +62,8 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
module_param_array(pcm_substreams, int, NULL, 0444);
MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
struct loopback_pcm;
@@ -78,6 +81,7 @@ struct loopback {
struct mutex cable_lock;
struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
struct snd_pcm *pcm[2];
+ unsigned int notify: 1;
};
struct loopback_pcm {
@@ -125,14 +129,47 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
del_timer(&dpcm->timer);
}
+#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+ struct snd_pcm_runtime *runtime;
+ int check;
+
+ if (cable->valid != CABLE_VALID_BOTH)
+ return 0;
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+ check = cable->hw.formats != (1ULL << runtime->format) ||
+ cable->hw.rate_min != runtime->rate ||
+ cable->hw.rate_max != runtime->rate ||
+ cable->hw.channels_min != runtime->channels ||
+ cable->hw.channels_max != runtime->channels;
+ if (!check)
+ return 0;
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ return -EIO;
+ } else {
+ snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream, SNDRV_PCM_STATE_DRAINING);
+ }
+ return 0;
+}
+
static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct loopback_pcm *dpcm = runtime->private_data;
struct loopback_cable *cable = dpcm->cable;
+ int err;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ err = loopback_check_format(cable, substream->stream);
+ if (err < 0)
+ return err;
dpcm->last_jiffies = jiffies;
loopback_timer_start(dpcm);
cable->running |= (1 << substream->stream);
@@ -431,7 +468,12 @@ static int loopback_open(struct snd_pcm_substream *substream)
runtime->private_data = dpcm;
runtime->private_free = loopback_runtime_free;
- runtime->hw = cable->hw;
+ if (loopback->notify &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = loopback_pcm_hardware;
+ } else {
+ runtime->hw = cable->hw;
+ }
unlock:
mutex_unlock(&loopback->cable_lock);
return err;
@@ -533,6 +575,7 @@ static int __devinit loopback_probe(struct platform_device *devptr)
pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
loopback->card = card;
+ loopback->notify = pcm_notify[dev] ? 1 : 0;
mutex_init(&loopback->cable_lock);
err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);