diff options
author | Sandeep Shinde <sashinde@nvidia.com> | 2010-04-26 14:48:05 +0530 |
---|---|---|
committer | Yu-Huan Hsu <yhsu@nvidia.com> | 2010-04-27 17:23:51 -0700 |
commit | 1a6769405dbaa37775cf8ea0018f57d93d171319 (patch) | |
tree | ce01854e786f24e2f48398220ecb8f273e4d3b82 | |
parent | 0570c93445adbe2f7156b2eb26190e9987eacf53 (diff) |
tegra ALSA: Fixing a hang in streaming playback
In playback, play_thread hangs in case there is no
continuous flow of buffers. That is when buffer_queue
variable becomes 0 inside play_thread, it might hang on
waiting for a semaphore. This conditions always happens in
case of streaming playback, where buffer supply may not be
continuous at the start.
Resolved this hang by making use
of ack function available for ALSA driver, this function
is called from ALSA middleware whenever application buffer
is supplied.
Incorporated few more review comments.
Fix for bug 674653
Synopsis: kernel spam when playing flash videos
Change-Id: I4eeebdc3369b02b849955bd8dab1f8172a85c407
Reviewed-on: http://git-master/r/1211
Reviewed-by: Manjula Gupta <magupta@nvidia.com>
Tested-by: Manjula Gupta <magupta@nvidia.com>
Reviewed-by: Vijay Mali <vmali@nvidia.com>
Tested-by: Vijay Mali <vmali@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r-- | sound/soc/tegra/tegra_pcm_rpc.c | 29 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_transport.h | 2 |
2 files changed, 30 insertions, 1 deletions
diff --git a/sound/soc/tegra/tegra_pcm_rpc.c b/sound/soc/tegra/tegra_pcm_rpc.c index afa17e4b43e8..3ddd08a471ad 100644 --- a/sound/soc/tegra/tegra_pcm_rpc.c +++ b/sound/soc/tegra/tegra_pcm_rpc.c @@ -131,6 +131,13 @@ static int play_thread( void *arg) size); } + if (buffer_in_queue == 0) { + prtd->play_thread_waiting = TRUE; + wait_for_completion(&prtd->appl_ptr_comp); + prtd->play_thread_waiting = FALSE; + init_completion(&prtd->appl_ptr_comp); + } + if ((buffer_to_prime == buffer_in_queue) || (prtd->audiofx_frames >= runtime->control->appl_ptr)) { @@ -463,6 +470,12 @@ static int pcm_common_close(struct snd_pcm_substream *substream) prtd->state = SNDRV_PCM_TRIGGER_STOP; + if (completion_done(&prtd->thread_comp) == 0) + complete(&prtd->thread_comp); + + if (completion_done(&prtd->appl_ptr_comp) == 0) + complete(&prtd->appl_ptr_comp); + if (prtd->play_thread) kthread_stop(prtd->play_thread); @@ -534,6 +547,8 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) goto fail; init_completion(&prtd->thread_comp); + init_completion(&prtd->appl_ptr_comp); + prtd->play_thread_waiting = FALSE; sema_init(&prtd->buf_done_sem, 0); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ @@ -671,6 +686,17 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream, return err; } +static int tegra_pcm_ack(struct snd_pcm_substream *substream) +{ + struct pcm_runtime_data *prtd = substream->runtime->private_data; + + if (prtd->play_thread_waiting) { + complete(&prtd->appl_ptr_comp); + } + + return 0; +} + static struct snd_pcm_ops tegra_pcm_ops = { .open = tegra_pcm_open, .close = tegra_pcm_close, @@ -680,7 +706,8 @@ static struct snd_pcm_ops tegra_pcm_ops = { .prepare = tegra_pcm_prepare, .trigger = tegra_pcm_trigger, .pointer = tegra_pcm_pointer, - .mmap = tegra_pcm_mmap, + .mmap = tegra_pcm_mmap, + .ack = tegra_pcm_ack, }; static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) diff --git a/sound/soc/tegra/tegra_transport.h b/sound/soc/tegra/tegra_transport.h index 9f8cfcc57bc9..74ff22004ce8 100644 --- a/sound/soc/tegra/tegra_transport.h +++ b/sound/soc/tegra/tegra_transport.h @@ -391,8 +391,10 @@ struct pcm_runtime_data { int state; int stream; int shutdown_thrd; + bool play_thread_waiting; unsigned int audiofx_frames; struct completion thread_comp; + struct completion appl_ptr_comp; struct semaphore buf_done_sem; StandardPath* stdoutpath; StandardPath* stdinpath; |