From: Lennart Poettering Date: Fri, 3 Aug 2007 23:48:52 +0000 (+0000) Subject: Don't stop hardware on buffer underruns. Instead continue playing to guarantee that... X-Git-Tag: submit/2.0-panda/20130828.192557~2837^2~1^2~400 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95fab184d5448bff9f262589390c7374fb1370c8;p=profile%2Fivi%2Fpulseaudio-panda.git Don't stop hardware on buffer underruns. Instead continue playing to guarantee that our time function stays as linear as possible. git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1566 fefdeb5f-60dc-0310-8127-8f9354f1896f --- diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c index dd9ac79..dd063f3 100644 --- a/src/modules/alsa-util.c +++ b/src/modules/alsa-util.c @@ -289,10 +289,11 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p pa_assert(periods); pa_assert(period_size); + snd_pcm_hw_params_alloca(&hwparams); + buffer_size = *periods * *period_size; - if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 || - (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || + if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 || (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) goto finish; @@ -355,12 +356,36 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p ret = 0; finish: - if (hwparams) - snd_pcm_hw_params_free(hwparams); return ret; } +int pa_alsa_set_sw_params(snd_pcm_t *pcm) { + snd_pcm_sw_params_t *swparams; + int err; + + pa_assert(pcm); + + snd_pcm_sw_params_alloca(&swparams); + + if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) { + pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) { + pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err)); + return err; + } + + if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) { + pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err)); + return err; + } + + return 0; +} + int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) { int err; diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h index f79325c..6f1f927 100644 --- a/src/modules/alsa-util.h +++ b/src/modules/alsa-util.h @@ -39,6 +39,7 @@ void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl); int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m); int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap); +int pa_alsa_set_sw_params(snd_pcm_t *pcm); int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback); diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index ced42ee..5765d78 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -545,18 +545,23 @@ static void thread_func(void *userdata) { goto fail; } else { - ssize_t l; - - if ((err = snd_pcm_status(u->pcm_handle, status)) >= 0) - l = snd_pcm_status_get_avail(status) * u->frame_size; - else - l = u->fragment_size; - - while (l > 0) { + for (;;) { void *p; snd_pcm_sframes_t t; + ssize_t l; + + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) { + pa_log("Failed to query DSP status data: %s", snd_strerror(t)); + goto fail; + } - pa_assert(l > 0); + if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size) + pa_log_debug("Buffer underrun!"); + + l = snd_pcm_status_get_avail(status) * u->frame_size; + + if (l <= 0) + break; if (u->memchunk.length <= 0) pa_sink_render(u->sink, l, &u->memchunk); @@ -573,10 +578,7 @@ static void thread_func(void *userdata) { if (t < 0) { - if (t == -EPIPE) { - pa_log_debug("Buffer underrun!"); - u->first = 1; - } + pa_assert(t != -EPIPE); if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0) continue; @@ -588,21 +590,20 @@ static void thread_func(void *userdata) { pa_log("Failed to write data to DSP: %s", snd_strerror(t)); goto fail; } + } - } else { - - u->memchunk.index += t * u->frame_size; - u->memchunk.length -= t * u->frame_size; - - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - pa_memchunk_reset(&u->memchunk); - } - - l -= t * u->frame_size; - - work_done = 1; + u->memchunk.index += t * u->frame_size; + u->memchunk.length -= t * u->frame_size; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); } + + work_done = 1; + + if (t * u->frame_size >= (unsigned) l) + break; } } @@ -756,6 +757,11 @@ int pa__init(pa_core *c, pa_module*m) { if (u->use_mmap) pa_log_info("Successfully enabled mmap() mode."); + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); + goto fail; + } + /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 0fd7bca..9a5d5ac 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -533,19 +533,25 @@ static void thread_func(void *userdata) { goto fail; } else { - ssize_t l; - if ((err = snd_pcm_status(u->pcm_handle, status)) >= 0) - l = snd_pcm_status_get_avail(status) * u->frame_size; - else - l = u->fragment_size; - - while (l > 0) { + for (;;) { void *p; snd_pcm_sframes_t t; + ssize_t l; - pa_assert(l > 0); + if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) { + pa_log("Failed to query DSP status data: %s", snd_strerror(t)); + goto fail; + } + if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size) + pa_log_debug("Buffer overrun!"); + + l = snd_pcm_status_get_avail(status) * u->frame_size; + + if (l <= 0) + break; + chunk.memblock = pa_memblock_new(u->core->mempool, l); p = pa_memblock_acquire(chunk.memblock); @@ -559,8 +565,7 @@ static void thread_func(void *userdata) { if (t < 0) { pa_memblock_unref(chunk.memblock); - if (t == -EPIPE) - pa_log_debug("Buffer underrun!"); + pa_assert(t != -EPIPE); if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0) continue; @@ -573,18 +578,18 @@ static void thread_func(void *userdata) { goto fail; } - } else { + } - chunk.index = 0; - chunk.length = t * u->frame_size; + chunk.index = 0; + chunk.length = t * u->frame_size; - pa_source_post(u->source, &chunk); - pa_memblock_unref(chunk.memblock); - - l -= t * u->frame_size; + pa_source_post(u->source, &chunk); + pa_memblock_unref(chunk.memblock); + + work_done = 1; - work_done = 1; - } + if (t * u->frame_size >= (unsigned) l) + break; } } @@ -730,6 +735,11 @@ int pa__init(pa_core *c, pa_module*m) { if (u->use_mmap) pa_log_info("Successfully enabled mmap() mode."); + + if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) { + pa_log("Failed to set software parameters: %s", snd_strerror(err)); + goto fail; + } /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss);