qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 4/5] paaudio: try to drain the recording stream


From: Volker Rümelin
Subject: [PATCH v2 4/5] paaudio: try to drain the recording stream
Date: Sat, 4 Jan 2020 10:11:21 +0100

There is no guarantee a single call to pa_stream_peek every
timer_period microseconds can read a recording stream faster
than the data gets produced at the source. Let qpa_read try to
drain the recording stream.

To reproduce the problem:

Start qemu with -audiodev pa,id=audio0,in.mixing-engine=off

On the host connect the qemu recording stream to the monitor of
a hardware output device. While the problem can also be seen
with a hardware input device, it's obvious with the monitor of
a hardware output device.

In the guest start audio recording with audacity and notice the
slow recording data rate.

Signed-off-by: Volker Rümelin <address@hidden>
---
 audio/paaudio.c | 41 +++++++++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 7db1dc15f0..b23274550e 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -156,34 +156,43 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t 
length)
 {
     PAVoiceIn *p = (PAVoiceIn *) hw;
     PAConnection *c = p->g->conn;
-    size_t l;
-    int r;
+    size_t total = 0;
 
     pa_threaded_mainloop_lock(c->mainloop);
 
     CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
                     "pa_threaded_mainloop_lock failed\n");
 
-    if (!p->read_length) {
-        r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
-        CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
-                           "pa_stream_peek failed\n");
-    }
+    while (total < length) {
+        size_t l;
+        int r;
+
+        if (!p->read_length) {
+            r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
+            CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+                               "pa_stream_peek failed\n");
+            if (!p->read_length) {
+                /* buffer is empty */
+                break;
+            }
+        }
 
-    l = MIN(p->read_length, length);
-    memcpy(data, p->read_data, l);
+        l = MIN(p->read_length, length - total);
+        memcpy((char *)data + total, p->read_data, l);
 
-    p->read_data += l;
-    p->read_length -= l;
+        p->read_data += l;
+        p->read_length -= l;
+        total += l;
 
-    if (!p->read_length) {
-        r = pa_stream_drop(p->stream);
-        CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
-                           "pa_stream_drop failed\n");
+        if (!p->read_length) {
+            r = pa_stream_drop(p->stream);
+            CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+                               "pa_stream_drop failed\n");
+        }
     }
 
     pa_threaded_mainloop_unlock(c->mainloop);
-    return l;
+    return total;
 
 unlock_and_fail:
     pa_threaded_mainloop_unlock(c->mainloop);
-- 
2.16.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]