summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorVolker RĂ¼melin2020-01-04 10:11:21 +0100
committerGerd Hoffmann2020-01-06 08:47:16 +0100
commitacc3b63e1bdf806de1a520522dd43e494461d3bb (patch)
tree46b225a36811a8aaaa52a7d602b342168fd50341 /audio
parentpaaudio: drop recording stream in qpa_fini_in (diff)
downloadqemu-acc3b63e1bdf806de1a520522dd43e494461d3bb.tar.gz
qemu-acc3b63e1bdf806de1a520522dd43e494461d3bb.tar.xz
qemu-acc3b63e1bdf806de1a520522dd43e494461d3bb.zip
paaudio: try to drain the recording stream
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 <vr_qemu@t-online.de> Message-id: 20200104091122.13971-4-vr_qemu@t-online.de Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'audio')
-rw-r--r--audio/paaudio.c41
1 files 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);