qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] pulseaudio buffering fixes
@ 2010-10-29 12:55 Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 1/3] pulseaudio: process 1/4 buffer max at once Gerd Hoffmann
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Gerd Hoffmann @ 2010-10-29 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: fengguang.wu, Gerd Hoffmann

  Hi,

These patches improve the pulseaudio driver's buffer handling.
Separated from the win7 sound patch series, it is completely
independant stuff.  Except maybe for the fact that the usb-audio
driver magnifies the pulseaudio buffering issues.

Fengguang, can you please have a look?
malc wants your review comments before applying them.

thanks,
  Gerd

Gerd Hoffmann (3):
  pulseaudio: process 1/4 buffer max at once
  pulseaudio: setup buffer attrs
  pulseaudio: tweak config

 audio/paaudio.c |   44 +++++++++++++++++++++-----------------------
 1 files changed, 21 insertions(+), 23 deletions(-)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PATCH 1/3] pulseaudio: process 1/4 buffer max at once
  2010-10-29 12:55 [Qemu-devel] [PATCH 0/3] pulseaudio buffering fixes Gerd Hoffmann
@ 2010-10-29 12:55 ` Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 2/3] pulseaudio: setup buffer attrs Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 3/3] pulseaudio: tweak config Gerd Hoffmann
  2 siblings, 0 replies; 4+ messages in thread
From: Gerd Hoffmann @ 2010-10-29 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: fengguang.wu, Gerd Hoffmann

Limit the size of data pieces processed by the pulseaudio worker
threads.  Never ever process more than 1/4 of the buffer at once.

Background: The buffer area currently processed by the pulseaudio thread
is blocked, i.e. the main thread (or iothread) can't fill in more data
there.  The buffer processing time is roughly real-time due to the
pa_simple_write() call blocking when the output queue to the pulse
server is full.  Thus processing big chunks at once means blocking
a large part of the buffer for a long time.  This brings high latency
and can lead to dropouts.

When processing the buffer in smaller chunks the rpos handling becomes a
problem though.  The thread reads hw->rpos without knowing whenever
qpa_run_out has already seen the last (small) chunk processed and
updated rpos accordingly.  There is no point in reading hw->rpos though,
pa->rpos can be used instead.  We just need to take care to initialize
pa->rpos before kicking the thread.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 audio/paaudio.c |   22 +++++++++-------------
 1 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index ff71dac..f99ca73 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -57,9 +57,6 @@ static void *qpa_thread_out (void *arg)
 {
     PAVoiceOut *pa = arg;
     HWVoiceOut *hw = &pa->hw;
-    int threshold;
-
-    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 
     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
         return NULL;
@@ -73,7 +70,7 @@ static void *qpa_thread_out (void *arg)
                 goto exit;
             }
 
-            if (pa->live > threshold) {
+            if (pa->live > 0) {
                 break;
             }
 
@@ -82,8 +79,8 @@ static void *qpa_thread_out (void *arg)
             }
         }
 
-        decr = to_mix = pa->live;
-        rpos = hw->rpos;
+        decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+        rpos = pa->rpos;
 
         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
             return NULL;
@@ -110,8 +107,8 @@ static void *qpa_thread_out (void *arg)
             return NULL;
         }
 
-        pa->live = 0;
         pa->rpos = rpos;
+        pa->live -= decr;
         pa->decr += decr;
     }
 
@@ -152,9 +149,6 @@ static void *qpa_thread_in (void *arg)
 {
     PAVoiceIn *pa = arg;
     HWVoiceIn *hw = &pa->hw;
-    int threshold;
-
-    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
 
     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
         return NULL;
@@ -168,7 +162,7 @@ static void *qpa_thread_in (void *arg)
                 goto exit;
             }
 
-            if (pa->dead > threshold) {
+            if (pa->dead > 0) {
                 break;
             }
 
@@ -177,8 +171,8 @@ static void *qpa_thread_in (void *arg)
             }
         }
 
-        incr = to_grab = pa->dead;
-        wpos = hw->wpos;
+        incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+        wpos = pa->wpos;
 
         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
             return NULL;
@@ -323,6 +317,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = conf.samples;
     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    pa->rpos = hw->rpos;
     if (!pa->pcm_buf) {
         dolog ("Could not allocate buffer (%d bytes)\n",
                hw->samples << hw->info.shift);
@@ -377,6 +372,7 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
     audio_pcm_init_info (&hw->info, &obt_as);
     hw->samples = conf.samples;
     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    pa->wpos = hw->wpos;
     if (!pa->pcm_buf) {
         dolog ("Could not allocate buffer (%d bytes)\n",
                hw->samples << hw->info.shift);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PATCH 2/3] pulseaudio: setup buffer attrs
  2010-10-29 12:55 [Qemu-devel] [PATCH 0/3] pulseaudio buffering fixes Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 1/3] pulseaudio: process 1/4 buffer max at once Gerd Hoffmann
@ 2010-10-29 12:55 ` Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 3/3] pulseaudio: tweak config Gerd Hoffmann
  2 siblings, 0 replies; 4+ messages in thread
From: Gerd Hoffmann @ 2010-10-29 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: fengguang.wu, Gerd Hoffmann

Request reasonable buffer sizes from pulseaudio.  Without this
pa_simple_write() can block quite long and lead to dropouts,
especially with guests which use small audio ring buffers.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 audio/paaudio.c |   12 +++++++++++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index f99ca73..61af0c5 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -289,6 +289,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     int error;
     static pa_sample_spec ss;
+    static pa_buffer_attr ba;
     struct audsettings obt_as = *as;
     PAVoiceOut *pa = (PAVoiceOut *) hw;
 
@@ -296,6 +297,15 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
     ss.channels = as->nchannels;
     ss.rate = as->freq;
 
+    /*
+     * qemu audio tick runs at 250 Hz (by default), so processing
+     * data chunks worth 4 ms of sound should be a good fit.
+     */
+    ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
+    ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
+    ba.maxlength = -1;
+    ba.prebuf = -1;
+
     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 
     pa->s = pa_simple_new (
@@ -306,7 +316,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
         "pcm.playback",
         &ss,
         NULL,                   /* channel map */
-        NULL,                   /* buffering attributes */
+        &ba,                    /* buffering attributes */
         &error
         );
     if (!pa->s) {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PATCH 3/3] pulseaudio: tweak config
  2010-10-29 12:55 [Qemu-devel] [PATCH 0/3] pulseaudio buffering fixes Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 1/3] pulseaudio: process 1/4 buffer max at once Gerd Hoffmann
  2010-10-29 12:55 ` [Qemu-devel] [PATCH 2/3] pulseaudio: setup buffer attrs Gerd Hoffmann
@ 2010-10-29 12:55 ` Gerd Hoffmann
  2 siblings, 0 replies; 4+ messages in thread
From: Gerd Hoffmann @ 2010-10-29 12:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: fengguang.wu, Gerd Hoffmann

Zap unused divisor field.
Raise the buffer size default.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 audio/paaudio.c |   10 +---------
 1 files changed, 1 insertions(+), 9 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 61af0c5..34bde23 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -33,13 +33,11 @@ typedef struct {
 
 static struct {
     int samples;
-    int divisor;
     char *server;
     char *sink;
     char *source;
 } conf = {
-    .samples = 1024,
-    .divisor = 2,
+    .samples = 4096,
 };
 
 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
@@ -478,12 +476,6 @@ struct audio_option qpa_options[] = {
         .descr = "buffer size in samples"
     },
     {
-        .name  = "DIVISOR",
-        .tag   = AUD_OPT_INT,
-        .valp  = &conf.divisor,
-        .descr = "threshold divisor"
-    },
-    {
         .name  = "SERVER",
         .tag   = AUD_OPT_STR,
         .valp  = &conf.server,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-10-29 13:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-29 12:55 [Qemu-devel] [PATCH 0/3] pulseaudio buffering fixes Gerd Hoffmann
2010-10-29 12:55 ` [Qemu-devel] [PATCH 1/3] pulseaudio: process 1/4 buffer max at once Gerd Hoffmann
2010-10-29 12:55 ` [Qemu-devel] [PATCH 2/3] pulseaudio: setup buffer attrs Gerd Hoffmann
2010-10-29 12:55 ` [Qemu-devel] [PATCH 3/3] pulseaudio: tweak config Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).