So to recap a little on the fighting rewinds issue - the one that makes
pulseaudio crash due to spending too much time in RT prio, and with the
pulseaudio log filled with rewinds.
A month ago I provided five patches in total, two in gstreamer[1] and
three in pulseaudio.
GStreamer #1: we have the "don't start the stream until we have written
some samples" - this fix is in gstreamer HEAD, committed by Wim Taymans.
GStreamer #2: send larger packages by removing a strange limit to
gstreamer's "segment size". This fix has been posted to the
gstreamer-devel mailinglist, but not committed AFAIK. I'm attaching a
version of the patch which has proper git headers and against git head.
Both GStreamer fixes have recently been uploaded to Ubuntu Natty, the
development version of Ubuntu.
PulseAudio #1 and #2: I believe these should be applied to PulseAudio
upstream.
PulseAudio #3: A person with alias h31 helped out here, and noticed this
patch was the one causing a regression in Skype. While I haven't exactly
figured out why, I do notice that this patch could cause problems for
very short samples. So let's drop this one for the time being.
For reference I resend the three patches (one in GStreamer, two in
pulseaudio) that I would like to see applied.
--
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic
[1] Well, Wim Taymans has some credit for the helping out with the first
one.
>From f07d6d2f692a6e51b01dabd5b4ac4a0c8ad3e270 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 6 Dec 2010 16:25:25 +0100
Subject: [PATCH 1/3] Fighting rewinds: Seek and write data in the same message
Allow a message in the queue to perform both a seek and a post data.
For clients that do not use PA_SEEK_RELATIVE (e g gstreamer), this
cuts the message count - and sometimes even the rewinds - in half.
Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
src/pulsecore/protocol-native.c | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 337869d..af44126 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1351,6 +1351,7 @@ static void flush_write_no_account(pa_memblockq *q) {
static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink_input *i = PA_SINK_INPUT(o);
playback_stream *s;
+ int64_t windex_seek = 0;
pa_sink_input_assert_ref(i);
s = PLAYBACK_STREAM(i->userdata);
@@ -1359,18 +1360,19 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
switch (code) {
case SINK_INPUT_MESSAGE_SEEK: {
- int64_t windex;
- windex = pa_memblockq_get_write_index(s->memblockq);
+ windex_seek = pa_memblockq_get_write_index(s->memblockq);
/* The client side is incapable of accounting correctly
* for seeks of a type != PA_SEEK_RELATIVE. We need to be
* able to deal with that. */
pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
-
- handle_seek(s, windex);
- return 0;
+ if (!chunk) {
+ handle_seek(s, windex_seek);
+ return 0;
+ }
+ /* else fall through and write some data */
}
case SINK_INPUT_MESSAGE_POST_DATA: {
@@ -1379,6 +1381,8 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
pa_assert(chunk);
windex = pa_memblockq_get_write_index(s->memblockq);
+ if (code == SINK_INPUT_MESSAGE_SEEK)
+ windex = PA_MIN(windex, windex_seek);
/* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
@@ -4440,9 +4444,9 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
if (chunk->memblock) {
if (seek != PA_SEEK_RELATIVE || offset != 0)
- pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
-
- pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
+ pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
+ else
+ pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
} else
pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL);
--
1.7.1
>From 08bd6b67ee32d6a6747545a0ebf9df4a8a54b9dc Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Thu, 9 Dec 2010 11:08:37 +0100
Subject: [PATCH 2/3] Fighting rewinds: Reduce calls to handle_seek
If many small blocks are in queue, handle_seek is being called
for every one of them, sometimes causing a rewind. Delay the
call until all blocks are handled, then call handle_seek only
once.
Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
src/pulsecore/protocol-native.c | 56 ++++++++++++++++++---------------------
1 files changed, 26 insertions(+), 30 deletions(-)
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index af44126..5dab80e 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -125,6 +125,10 @@ typedef struct playback_stream {
uint32_t drain_tag;
uint32_t syncid;
+ /* Optimization to avoid too many rewinds with a lot of small blocks */
+ pa_atomic_t seek_or_post_in_queue;
+ int64_t seek_windex;
+
pa_atomic_t missing;
pa_usec_t configured_sink_latency;
pa_buffer_attr buffer_attr;
@@ -1099,6 +1103,8 @@ static playback_stream* playback_stream_new(
s->buffer_attr = *a;
s->adjust_latency = adjust_latency;
s->early_requests = early_requests;
+ pa_atomic_store(&s->seek_or_post_in_queue, 0);
+ s->seek_windex = -1;
s->sink_input->parent.process_msg = sink_input_process_msg;
s->sink_input->pop = sink_input_pop_cb;
@@ -1351,7 +1357,6 @@ static void flush_write_no_account(pa_memblockq *q) {
static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink_input *i = PA_SINK_INPUT(o);
playback_stream *s;
- int64_t windex_seek = 0;
pa_sink_input_assert_ref(i);
s = PLAYBACK_STREAM(i->userdata);
@@ -1359,45 +1364,35 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
switch (code) {
- case SINK_INPUT_MESSAGE_SEEK: {
-
- windex_seek = pa_memblockq_get_write_index(s->memblockq);
-
- /* The client side is incapable of accounting correctly
- * for seeks of a type != PA_SEEK_RELATIVE. We need to be
- * able to deal with that. */
-
- pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
- if (!chunk) {
- handle_seek(s, windex_seek);
- return 0;
- }
- /* else fall through and write some data */
- }
-
+ case SINK_INPUT_MESSAGE_SEEK:
case SINK_INPUT_MESSAGE_POST_DATA: {
- int64_t windex;
-
- pa_assert(chunk);
+ int64_t windex = pa_memblockq_get_write_index(s->memblockq);
- windex = pa_memblockq_get_write_index(s->memblockq);
- if (code == SINK_INPUT_MESSAGE_SEEK)
- windex = PA_MIN(windex, windex_seek);
-
-/* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
+ if (code == SINK_INPUT_MESSAGE_SEEK) {
+ /* The client side is incapable of accounting correctly
+ * for seeks of a type != PA_SEEK_RELATIVE. We need to be
+ * able to deal with that. */
- if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
+ pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
+ windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
+ }
+ if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
if (pa_log_ratelimit())
pa_log_warn("Failed to push data into queue");
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
}
- handle_seek(s, windex);
-
-/* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
-
+ /* If more data is in queue, we rewind later instead. */
+ if (s->seek_windex != -1)
+ windex = PA_MIN(windex, s->seek_windex);
+ if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
+ s->seek_windex = windex;
+ else {
+ s->seek_windex = -1;
+ handle_seek(s, windex);
+ }
return 0;
}
@@ -4442,6 +4437,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
if (playback_stream_isinstance(stream)) {
playback_stream *ps = PLAYBACK_STREAM(stream);
+ pa_atomic_inc(&ps->seek_or_post_in_queue);
if (chunk->memblock) {
if (seek != PA_SEEK_RELATIVE || offset != 0)
pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
--
1.7.1
>From 51f56adfc341adb5022b96154fcc390c113d3118 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 31 Jan 2011 05:58:36 +0100
Subject: [PATCH] Pulsesink: Allow chunks up to bufsize instead of segsize
By allowing larger chunks to be sent, PulseAudio will have a
lower CPU usage. This is especially important on low-end machines,
where PulseAudio can crash if packets are coming in at a higher
rate than PulseAudio can process them.
Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
ext/pulse/pulsesink.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
index 9bebfec..295d93f 100644
--- a/ext/pulse/pulsesink.c
+++ b/ext/pulse/pulsesink.c
@@ -1339,11 +1339,11 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
towrite = out_samples * bps;
- /* Only ever write segsize bytes at once. This will
- * also limit the PA shm buffer to segsize
+ /* Only ever write bufsize bytes at once. This will
+ * also limit the PA shm buffer to bufsize
*/
- if (towrite > buf->spec.segsize)
- towrite = buf->spec.segsize;
+ if (towrite > bufsize)
+ towrite = bufsize;
if ((pbuf->m_writable < towrite) || (offset != pbuf->m_lastoffset)) {
/* if no room left or discontinuity in offset,
@@ -1392,9 +1392,9 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
}
/* make sure we only buffer up latency-time samples */
- if (pbuf->m_writable > buf->spec.segsize) {
+ if (pbuf->m_writable > bufsize) {
/* limit buffering to latency-time value */
- pbuf->m_writable = buf->spec.segsize;
+ pbuf->m_writable = bufsize;
GST_LOG_OBJECT (psink, "Limiting buffering to %" G_GSIZE_FORMAT,
pbuf->m_writable);
@@ -1413,9 +1413,9 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
pbuf->m_writable);
/* Just to make sure that we didn't get more than requested */
- if (pbuf->m_writable > buf->spec.segsize) {
+ if (pbuf->m_writable > bufsize) {
/* limit buffering to latency-time value */
- pbuf->m_writable = buf->spec.segsize;
+ pbuf->m_writable = bufsize;
}
}
--
1.7.1
_______________________________________________
pulseaudio-discuss mailing list
pulseaudio-discuss@mail.0pointer.de
https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss