* [PATCH v2 1/5] hda-codec: fix playback rate control
2020-01-04 9:07 [PATCH v2 0/5] audio fixes Volker Rümelin
@ 2020-01-04 9:11 ` Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 2/5] hda-codec: fix recording " Volker Rümelin
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Volker Rümelin @ 2020-01-04 9:11 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: QEMU, Zoltán Kővágó
Since commit 1930616b98 "audio: make mixeng optional" the
function hda_audio_output_cb can no longer assume the function
parameter avail contains the free buffer size. With the playback
mixing-engine turned off this leads to a broken playback rate
control and playback buffer drops in regular intervals.
This patch moves down the rate calculation, so the correct
buffer fill level is used for the calculation.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
hw/audio/hda-codec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index f17e8d8dce..768ba31e79 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -338,8 +338,6 @@ static void hda_audio_output_cb(void *opaque, int avail)
return;
}
- hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1));
-
while (to_transfer) {
uint32_t start = (uint32_t) (rpos & B_MASK);
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
@@ -351,6 +349,8 @@ static void hda_audio_output_cb(void *opaque, int avail)
break;
}
}
+
+ hda_timer_sync_adjust(st, (wpos - rpos) - (B_SIZE >> 1));
}
static void hda_audio_compat_input_cb(void *opaque, int avail)
--
2.16.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/5] hda-codec: fix recording rate control
2020-01-04 9:07 [PATCH v2 0/5] audio fixes Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 1/5] hda-codec: fix playback rate control Volker Rümelin
@ 2020-01-04 9:11 ` Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 3/5] paaudio: drop recording stream in qpa_fini_in Volker Rümelin
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Volker Rümelin @ 2020-01-04 9:11 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: QEMU, Zoltán Kővágó
Apply previous commit to hda_audio_input_cb for the same
reasons.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
hw/audio/hda-codec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 768ba31e79..e711a99a41 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -265,8 +265,6 @@ static void hda_audio_input_cb(void *opaque, int avail)
int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail);
- hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1)));
-
while (to_transfer) {
uint32_t start = (uint32_t) (wpos & B_MASK);
uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
@@ -278,6 +276,8 @@ static void hda_audio_input_cb(void *opaque, int avail)
break;
}
}
+
+ hda_timer_sync_adjust(st, -((wpos - rpos) - (B_SIZE >> 1)));
}
static void hda_audio_output_timer(void *opaque)
--
2.16.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 3/5] paaudio: drop recording stream in qpa_fini_in
2020-01-04 9:07 [PATCH v2 0/5] audio fixes Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 1/5] hda-codec: fix playback rate control Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 2/5] hda-codec: fix recording " Volker Rümelin
@ 2020-01-04 9:11 ` Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 4/5] paaudio: try to drain the recording stream Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 5/5] paaudio: wait until the recording stream is ready Volker Rümelin
4 siblings, 0 replies; 6+ messages in thread
From: Volker Rümelin @ 2020-01-04 9:11 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: QEMU, Zoltán Kővágó
Every call to pa_stream_peek which returns a data length > 0
should have a corresponding pa_stream_drop. A call to qpa_read
does not necessarily call pa_stream_drop immediately after a
call to pa_stream_peek. Test in qpa_fini_in if a last
pa_stream_drop is needed.
This prevents following messages in the libvirt log file after
a recording stream gets closed and a new one opened.
pulseaudio: pa_stream_drop failed
pulseaudio: Reason: Bad state
pulseaudio: pa_stream_drop failed
pulseaudio: Reason: Bad state
To reproduce start qemu with
-audiodev pa,id=audio0,in.mixing-engine=off
and in the guest start and stop Audacity several times.
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/paaudio.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 55a91f8980..7db1dc15f0 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -536,7 +536,6 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
{
int err;
- pa_threaded_mainloop_lock(c->mainloop);
/*
* wait until actually connects. workaround pa bug #247
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
@@ -550,7 +549,6 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
dolog("Failed to disconnect! err=%d\n", err);
}
pa_stream_unref(stream);
- pa_threaded_mainloop_unlock(c->mainloop);
}
static void qpa_fini_out (HWVoiceOut *hw)
@@ -558,8 +556,12 @@ static void qpa_fini_out (HWVoiceOut *hw)
PAVoiceOut *pa = (PAVoiceOut *) hw;
if (pa->stream) {
- qpa_simple_disconnect(pa->g->conn, pa->stream);
+ PAConnection *c = pa->g->conn;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+ qpa_simple_disconnect(c, pa->stream);
pa->stream = NULL;
+ pa_threaded_mainloop_unlock(c->mainloop);
}
}
@@ -568,8 +570,20 @@ static void qpa_fini_in (HWVoiceIn *hw)
PAVoiceIn *pa = (PAVoiceIn *) hw;
if (pa->stream) {
- qpa_simple_disconnect(pa->g->conn, pa->stream);
+ PAConnection *c = pa->g->conn;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+ if (pa->read_length) {
+ int r = pa_stream_drop(pa->stream);
+ if (r) {
+ qpa_logerr(pa_context_errno(c->context),
+ "pa_stream_drop failed\n");
+ }
+ pa->read_length = 0;
+ }
+ qpa_simple_disconnect(c, pa->stream);
pa->stream = NULL;
+ pa_threaded_mainloop_unlock(c->mainloop);
}
}
--
2.16.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 4/5] paaudio: try to drain the recording stream
2020-01-04 9:07 [PATCH v2 0/5] audio fixes Volker Rümelin
` (2 preceding siblings ...)
2020-01-04 9:11 ` [PATCH v2 3/5] paaudio: drop recording stream in qpa_fini_in Volker Rümelin
@ 2020-01-04 9:11 ` Volker Rümelin
2020-01-04 9:11 ` [PATCH v2 5/5] paaudio: wait until the recording stream is ready Volker Rümelin
4 siblings, 0 replies; 6+ messages in thread
From: Volker Rümelin @ 2020-01-04 9:11 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: QEMU, Zoltán Kővágó
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>
---
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 5/5] paaudio: wait until the recording stream is ready
2020-01-04 9:07 [PATCH v2 0/5] audio fixes Volker Rümelin
` (3 preceding siblings ...)
2020-01-04 9:11 ` [PATCH v2 4/5] paaudio: try to drain the recording stream Volker Rümelin
@ 2020-01-04 9:11 ` Volker Rümelin
4 siblings, 0 replies; 6+ messages in thread
From: Volker Rümelin @ 2020-01-04 9:11 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: QEMU, Zoltán Kővágó
Don't call pa_stream_peek before the recording stream is ready.
Information to reproduce the problem.
Start and stop Audacity in the guest several times because the
problem is racy.
libvirt log file:
-audiodev pa,id=audio0,server=localhost,out.latency=30000,
out.mixing-engine=off,in.mixing-engine=off \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,
resourcecontrol=deny \
-msg timestamp=on
: Domain id=4 is tainted: custom-argv
char device redirected to /dev/pts/1 (label charserial0)
audio: Device pcspk: audiodev default parameter is deprecated,
please specify audiodev=audio0
audio: Device hda: audiodev default parameter is deprecated,
please specify audiodev=audio0
pulseaudio: pa_stream_peek failed
pulseaudio: Reason: Bad state
pulseaudio: pa_stream_peek failed
pulseaudio: Reason: Bad state
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/paaudio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/audio/paaudio.c b/audio/paaudio.c
index b23274550e..dbfe48c03a 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -162,6 +162,10 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
"pa_threaded_mainloop_lock failed\n");
+ if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
+ /* wait for stream to become ready */
+ goto unlock;
+ }
while (total < length) {
size_t l;
@@ -191,6 +195,7 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
}
}
+unlock:
pa_threaded_mainloop_unlock(c->mainloop);
return total;
--
2.16.4
^ permalink raw reply related [flat|nested] 6+ messages in thread