ALSA: snd-aloop - add pause support
Jaroslav Kysela [Wed, 20 Oct 2010 07:33:03 +0000 (09:33 +0200)]
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

sound/drivers/aloop.c

index 38e8351..12b44b0 100644 (file)
@@ -77,6 +77,7 @@ struct loopback_cable {
        /* flags */
        unsigned int valid;
        unsigned int running;
+       unsigned int pause;
 };
 
 struct loopback_setup {
@@ -254,7 +255,7 @@ 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;
+       int err, stream = 1 << substream->stream;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -264,7 +265,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
                dpcm->last_jiffies = jiffies;
                dpcm->pcm_rate_shift = 0;
                spin_lock(&cable->lock);        
-               cable->running |= (1 << substream->stream);
+               cable->running |= stream;
+               cable->pause &= ~stream;
                spin_unlock(&cable->lock);
                loopback_timer_start(dpcm);
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -272,12 +274,26 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                spin_lock(&cable->lock);        
-               cable->running &= ~(1 << substream->stream);
+               cable->running &= ~stream;
+               cable->pause &= ~stream;
                spin_unlock(&cable->lock);
                loopback_timer_stop(dpcm);
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                        loopback_active_notify(dpcm);
                break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock(&cable->lock);        
+               cable->pause |= stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_stop(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock(&cable->lock);
+               dpcm->last_jiffies = jiffies;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_start(dpcm);
+               break;
        default:
                return -EINVAL;
        }
@@ -468,7 +484,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
        unsigned int running;
 
        spin_lock(&cable->lock);        
-       running = cable->running;
+       running = cable->running ^ cable->pause;
        if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
                delta_play = jiffies - dpcm_play->last_jiffies;
                dpcm_play->last_jiffies += delta_play;
@@ -532,7 +548,7 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
 static struct snd_pcm_hardware loopback_pcm_hardware =
 {
        .info =         (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
-                        SNDRV_PCM_INFO_MMAP_VALID),
+                        SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
        .formats =      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
                         SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
                         SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
@@ -1060,6 +1076,7 @@ static void print_substream_info(struct snd_info_buffer *buffer,
        }
        snd_iprintf(buffer, "  valid: %u\n", cable->valid);
        snd_iprintf(buffer, "  running: %u\n", cable->running);
+       snd_iprintf(buffer, "  pause: %u\n", cable->pause);
        print_dpcm_info(buffer, cable->streams[0], "Playback");
        print_dpcm_info(buffer, cable->streams[1], "Capture");
 }