diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-07-30 19:58:12 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-07-30 19:58:12 +0200 |
commit | 6d6173d248e5d54ae553e1f44e6147a2e5d93e8d (patch) | |
tree | 916c78b5f2a4912de3d70eca6d87af34a2df975a | |
parent | 433580cdc6bd71908743e47c429b5b5ad90d12bf (diff) | |
download | alsa-driver-build-unstable-6d6173d248e5d54ae553e1f44e6147a2e5d93e8d.tar.gz |
snd-aloop: Fix the garbage copy at the end of playback (draining)
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | drivers/aloop-kernel.c | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/drivers/aloop-kernel.c b/drivers/aloop-kernel.c index 9fc3c3f54..6f3724bb8 100644 --- a/drivers/aloop-kernel.c +++ b/drivers/aloop-kernel.c @@ -227,31 +227,6 @@ static int loopback_prepare(struct snd_pcm_substream *substream) return 0; } -static void copy_play_buf(struct loopback_pcm *play, - struct loopback_pcm *capt, - unsigned int bytes) -{ - char *src = play->substream->runtime->dma_area; - char *dst = capt->substream->runtime->dma_area; - unsigned int src_off = play->buf_pos; - unsigned int dst_off = capt->buf_pos; - - for (;;) { - unsigned int size = bytes; - if (src_off + size > play->pcm_buffer_size) - size = play->pcm_buffer_size - src_off; - if (dst_off + size > capt->pcm_buffer_size) - size = capt->pcm_buffer_size - dst_off; - memcpy(dst + dst_off, src + src_off, size); - capt->silent_size = 0; - bytes -= size; - if (!bytes) - break; - src_off = (src_off + size) % play->pcm_buffer_size; - dst_off = (dst_off + size) % capt->pcm_buffer_size; - } -} - static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) { struct snd_pcm_runtime *runtime = dpcm->substream->runtime; @@ -278,6 +253,53 @@ static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) } } +static void copy_play_buf(struct loopback_pcm *play, + struct loopback_pcm *capt, + unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = play->substream->runtime; + char *src = play->substream->runtime->dma_area; + char *dst = capt->substream->runtime->dma_area; + unsigned int src_off = play->buf_pos; + unsigned int dst_off = capt->buf_pos; + unsigned int clear_bytes = 0; + + /* check if playback is draining, trim the capture copy size + * when our pointer is at the end of playback ring buffer */ + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { + snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; + appl_ptr = appl_ptr1 = runtime->control->appl_ptr; + appl_ptr1 -= appl_ptr1 % runtime->buffer_size; + appl_ptr1 += play->buf_pos / play->pcm_salign; + if (appl_ptr < appl_ptr1) + appl_ptr1 -= runtime->buffer_size; + diff = (appl_ptr - appl_ptr1) * play->pcm_salign; + if (diff < bytes) { + clear_bytes = bytes - diff; + bytes = diff; + } + } + + for (;;) { + unsigned int size = bytes; + if (src_off + size > play->pcm_buffer_size) + size = play->pcm_buffer_size - src_off; + if (dst_off + size > capt->pcm_buffer_size) + size = capt->pcm_buffer_size - dst_off; + memcpy(dst + dst_off, src + src_off, size); + capt->silent_size = 0; + bytes -= size; + if (!bytes) + break; + src_off = (src_off + size) % play->pcm_buffer_size; + dst_off = (dst_off + size) % capt->pcm_buffer_size; + } + + if (clear_bytes > 0) + clear_capture_buf(capt, clear_bytes); +} + #define BYTEPOS_UPDATE_POSONLY 0 #define BYTEPOS_UPDATE_CLEAR 1 #define BYTEPOS_UPDATE_COPY 2 |