167 lines
6.6 KiB
Diff
167 lines
6.6 KiB
Diff
From 0796f5a2d6bf8e175a16d7f58cd0a18783fb4590 Mon Sep 17 00:00:00 2001
|
|
From: Lennart Poettering <lennart@poettering.net>
|
|
Date: Tue, 21 Oct 2008 20:00:36 +0200
|
|
Subject: [PATCH] Try to catch certain driver errors
|
|
|
|
... by verifying return values of snd_pcm_avail_update() and
|
|
snd_pcm_begin_mmap() for their sanenness.
|
|
---
|
|
src/modules/alsa-util.c | 60 ++++++++++++++++++++++++++++++++++++++
|
|
src/modules/alsa-util.h | 3 ++
|
|
src/modules/module-alsa-sink.c | 6 ++--
|
|
src/modules/module-alsa-source.c | 6 ++--
|
|
4 files changed, 69 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
|
|
index ffe7795..39cea49 100644
|
|
--- a/src/modules/alsa-util.c
|
|
+++ b/src/modules/alsa-util.c
|
|
@@ -30,6 +30,7 @@
|
|
|
|
#include <pulse/sample.h>
|
|
#include <pulse/xmalloc.h>
|
|
+#include <pulse/timeval.h>
|
|
|
|
#include <pulsecore/log.h>
|
|
#include <pulsecore/macro.h>
|
|
@@ -1109,3 +1110,62 @@ pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
|
|
|
|
return item;
|
|
}
|
|
+
|
|
+snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) {
|
|
+ snd_pcm_sframes_t n;
|
|
+ size_t k;
|
|
+
|
|
+ pa_assert(pcm);
|
|
+ pa_assert(hwbuf_size > 0);
|
|
+ pa_assert(ss);
|
|
+
|
|
+ /* Some ALSA driver expose weird bugs, let's inform the user about
|
|
+ * what is going on */
|
|
+
|
|
+ n = snd_pcm_avail_update(pcm);
|
|
+
|
|
+ if (n <= 0)
|
|
+ return n;
|
|
+
|
|
+ k = (size_t) n * pa_frame_size(ss);
|
|
+
|
|
+ if (k >= hwbuf_size * 3 ||
|
|
+ k >= pa_bytes_per_second(ss)*10)
|
|
+ pa_log("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms) "
|
|
+ "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.",
|
|
+ (unsigned long) k, (unsigned long) pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC);
|
|
+
|
|
+ return n;
|
|
+}
|
|
+
|
|
+int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss) {
|
|
+ int r;
|
|
+ snd_pcm_uframes_t before;
|
|
+ size_t k;
|
|
+
|
|
+ pa_assert(pcm);
|
|
+ pa_assert(areas);
|
|
+ pa_assert(offset);
|
|
+ pa_assert(frames);
|
|
+ pa_assert(hwbuf_size > 0);
|
|
+ pa_assert(ss);
|
|
+
|
|
+ before = *frames;
|
|
+
|
|
+ r = snd_pcm_mmap_begin(pcm, areas, offset, frames);
|
|
+
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ k = (size_t) *frames * pa_frame_size(ss);
|
|
+
|
|
+ if (*frames > before ||
|
|
+ k >= hwbuf_size * 3 ||
|
|
+ k >= pa_bytes_per_second(ss)*10)
|
|
+
|
|
+ pa_log("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms) "
|
|
+ "Most likely this is an ALSA driver bug. Please report this issue to the PulseAudio developers.",
|
|
+ (unsigned long) k, (unsigned long) pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC);
|
|
+
|
|
+ return r;
|
|
+}
|
|
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
|
|
index b66adc1..aaa01c7 100644
|
|
--- a/src/modules/alsa-util.h
|
|
+++ b/src/modules/alsa-util.h
|
|
@@ -92,4 +92,7 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
|
|
|
|
pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll);
|
|
|
|
+snd_pcm_sframes_t pa_alsa_safe_avail_update(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss);
|
|
+int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss);
|
|
+
|
|
#endif
|
|
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
|
|
index 4044de1..af83103 100644
|
|
--- a/src/modules/module-alsa-sink.c
|
|
+++ b/src/modules/module-alsa-sink.c
|
|
@@ -261,7 +261,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
/* First we determine how many samples are missing to fill the
|
|
* buffer up to 100% */
|
|
|
|
- if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
|
|
+ if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
|
|
continue;
|
|
@@ -299,7 +299,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
|
|
/* pa_log_debug("%lu frames to write", (unsigned long) frames); */
|
|
|
|
- if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) {
|
|
+ if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0)
|
|
continue;
|
|
@@ -374,7 +374,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
|
|
snd_pcm_hwsync(u->pcm_handle);
|
|
|
|
- if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
|
|
+ if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
|
|
continue;
|
|
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
|
|
index a743776..dd6ca97 100644
|
|
--- a/src/modules/module-alsa-source.c
|
|
+++ b/src/modules/module-alsa-source.c
|
|
@@ -255,7 +255,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
|
|
snd_pcm_hwsync(u->pcm_handle);
|
|
|
|
- if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
|
|
+ if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
|
|
continue;
|
|
@@ -282,7 +282,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
|
|
/* pa_log_debug("%lu frames to read", (unsigned long) frames); */
|
|
|
|
- if (PA_UNLIKELY((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0)) {
|
|
+ if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0)
|
|
continue;
|
|
@@ -353,7 +353,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) {
|
|
|
|
snd_pcm_hwsync(u->pcm_handle);
|
|
|
|
- if (PA_UNLIKELY((n = snd_pcm_avail_update(u->pcm_handle)) < 0)) {
|
|
+ if (PA_UNLIKELY((n = pa_alsa_safe_avail_update(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) {
|
|
|
|
if ((r = try_recover(u, "snd_pcm_avail_update", (int) n)) == 0)
|
|
continue;
|
|
--
|
|
1.6.0.3
|
|
|