qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] Audio fixes and improvements
@ 2020-09-20 17:14 Volker Rümelin
  2020-09-20 17:17 ` [PATCH 1/9] audio: handle buf == NULL in put_buffer_out() Volker Rümelin
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:14 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

A few fixes and improvements from my audio patch queue.

It's currently still not possible to reach the function
audio_generic_read(). I tested the patch
 
audio: align audio_generic_read with audio_pcm_hw_run_in

with a modified audio/paaudio.c version. If someone wants
to reproduce the test, replace .read = qpa_read with
.read = audio_generic_read in the audio/paaudio.c pcm_ops
table and start qemu with
-audiodev pa,id=audio0,in.mixing-engine=off.

With best regards,
Volker

Volker Rümelin (9):
  audio: handle buf == NULL in put_buffer_out()
  audio/audio: fix video playback slowdown with spiceaudio
  audio/spiceaudio: always rate limit playback stream
  audio: align audio_generic_read with audio_pcm_hw_run_in
  audio: remove unnecessary calls to put_buffer_in
  audio: align audio_generic_write with audio_pcm_hw_run_out
  audio: run downstream playback queue unconditionally
  audio: restore mixing-engine playback buffer size
  audio: revert tests for pcm_ops table

 audio/alsaaudio.c   |   1 +
 audio/audio.c       | 136 +++++++++++++++++++++++++++++++++-----------
 audio/audio_int.h   |   7 ++-
 audio/coreaudio.c   |   3 +
 audio/dsoundaudio.c |   6 ++
 audio/jackaudio.c   |   1 +
 audio/noaudio.c     |   1 +
 audio/ossaudio.c    |  12 ++++
 audio/paaudio.c     |   6 ++
 audio/sdlaudio.c    |   3 +
 audio/spiceaudio.c  |  27 +++++----
 audio/wavaudio.c    |   1 +
 12 files changed, 161 insertions(+), 43 deletions(-)

-- 
2.26.2



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

* [PATCH 1/9] audio: handle buf == NULL in put_buffer_out()
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 2/9] audio/audio: fix video playback slowdown with spiceaudio Volker Rümelin
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

With the next patch all audio backends put_buffer_out() functions
have to handle the buf == NULL case, provided the get_buffer_out()
function may return buf = NULL and size > 0.

It turns out that all audio backends get_buffer_out() functions
either can't return buf = NULL or return buf = NULL and size = 0
at the same time. The only exception is the spiceaudio backend
where size may be uninitialized.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/spiceaudio.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index b6b5da4812..c8d81ba442 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -135,6 +135,7 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
             (out->fsize - out->fpos) * hw->info.bytes_per_frame);
     } else {
         audio_rate_start(&out->rate);
+        *size = LINE_OUT_SAMPLES << 2;
     }
     return out->frame + out->fpos;
 }
@@ -143,12 +144,14 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
 {
     SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
 
-    assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
-    out->fpos += size >> 2;
+    if (buf) {
+        assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
+        out->fpos += size >> 2;
 
-    if (out->fpos == out->fsize) { /* buffer full */
-        spice_server_playback_put_samples(&out->sin, out->frame);
-        out->frame = NULL;
+        if (out->fpos == out->fsize) { /* buffer full */
+            spice_server_playback_put_samples(&out->sin, out->frame);
+            out->frame = NULL;
+        }
     }
 
     return size;
-- 
2.26.2



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

* [PATCH 2/9] audio/audio: fix video playback slowdown with spiceaudio
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
  2020-09-20 17:17 ` [PATCH 1/9] audio: handle buf == NULL in put_buffer_out() Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 3/9] audio/spiceaudio: always rate limit playback stream Volker Rümelin
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

This patch allows the audio backends get_buffer_out() functions
to drop audio data and mitigates a bug reported on the qemu-devel
mailing list.

https://lists.nongnu.org/archive/html/qemu-devel/2020-09/msg03832.html

The new rules for the variables buf and size returned by
get_buffer_out() are:
size == 0: Downstream playback buffer is full. Retry later.
size > 0, buf != NULL: Copy size bytes to buf for playback.
size > 0, buf == NULL: Drop size bytes.

The audio playback rate with spiceaudio for the no audio case is
too fast, but that's what we had before commit fb35c2cec5
"audio/dsound: fix invalid parameters error". The complete fix
comes with the next patch.

Reported-by: Qi Zhou <atmgnd@outlook.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index ce8c6dec5f..ad3f57b4c4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1091,12 +1091,15 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
     while (live) {
         size_t size, decr, proc;
         void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
-        if (!buf || size == 0) {
+
+        if (size == 0) {
             break;
         }
 
         decr = MIN(size / hw->info.bytes_per_frame, live);
-        audio_pcm_hw_clip_out(hw, buf, decr);
+        if (buf) {
+            audio_pcm_hw_clip_out(hw, buf, decr);
+        }
         proc = hw->pcm_ops->put_buffer_out(hw, buf,
                                            decr * hw->info.bytes_per_frame) /
             hw->info.bytes_per_frame;
-- 
2.26.2



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

* [PATCH 3/9] audio/spiceaudio: always rate limit playback stream
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
  2020-09-20 17:17 ` [PATCH 1/9] audio: handle buf == NULL in put_buffer_out() Volker Rümelin
  2020-09-20 17:17 ` [PATCH 2/9] audio/audio: fix video playback slowdown with spiceaudio Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 4/9] audio: align audio_generic_read with audio_pcm_hw_run_in Volker Rümelin
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

The playback rate with the spiceaudio backend is currently too
fast if there's no spice client connected or the spice client
can't play audio. Rate limit the audio playback stream in all
cases. To calculate the rate correctly the limiter has to know
the maximum buffer size.

Fixes: 8c198ff065 ("spiceaudio: port to the new audio backend api")
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c      |  3 ++-
 audio/spiceaudio.c | 10 ++++------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index ad3f57b4c4..ba52259050 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1089,7 +1089,8 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
     size_t clipped = 0;
 
     while (live) {
-        size_t size, decr, proc;
+        size_t size = live * hw->info.bytes_per_frame;
+        size_t decr, proc;
         void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
 
         if (size == 0) {
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index c8d81ba442..c062742622 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -130,13 +130,11 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
     }
 
     if (out->frame) {
-        *size = audio_rate_get_bytes(
-            &hw->info, &out->rate,
-            (out->fsize - out->fpos) * hw->info.bytes_per_frame);
-    } else {
-        audio_rate_start(&out->rate);
-        *size = LINE_OUT_SAMPLES << 2;
+        *size = MIN((out->fsize - out->fpos) << 2, *size);
     }
+
+    *size = audio_rate_get_bytes(&hw->info, &out->rate, *size);
+
     return out->frame + out->fpos;
 }
 
-- 
2.26.2



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

* [PATCH 4/9] audio: align audio_generic_read with audio_pcm_hw_run_in
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (2 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 3/9] audio/spiceaudio: always rate limit playback stream Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 5/9] audio: remove unnecessary calls to put_buffer_in Volker Rümelin
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

The function audio_generic_read should work exactly like
audio_pcm_hw_run_in. It's a very similar function working
on a different buffer.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index ba52259050..f1f0d72389 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1495,12 +1495,23 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
 
 size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
 {
-    void *src = hw->pcm_ops->get_buffer_in(hw, &size);
+    size_t total = 0;
 
-    memcpy(buf, src, size);
-    hw->pcm_ops->put_buffer_in(hw, src, size);
+    while (total < size) {
+        size_t src_size = size - total;
+        void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
 
-    return size;
+        if (src_size == 0) {
+            hw->pcm_ops->put_buffer_in(hw, src, src_size);
+            break;
+        }
+
+        memcpy((char *)buf + total, src, src_size);
+        hw->pcm_ops->put_buffer_in(hw, src, src_size);
+        total += src_size;
+    }
+
+    return total;
 }
 
 static int audio_driver_init(AudioState *s, struct audio_driver *drv,
-- 
2.26.2



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

* [PATCH 5/9] audio: remove unnecessary calls to put_buffer_in
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (3 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 4/9] audio: align audio_generic_read with audio_pcm_hw_run_in Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 6/9] audio: align audio_generic_write with audio_pcm_hw_run_out Volker Rümelin
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

This patch removes unnecessary calls to the pcm_ops function
put_buffer_in(). No audio backend needs this call if the
returned length of pcm_ops function get_buffer_in() is zero.

For the DirectSound backend this prevents a call to
dsound_unlock_in() without a preceding call to dsound_lock_in().
While Windows doesn't complain it seems wrong anyway.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index f1f0d72389..75107a12d0 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1261,7 +1261,6 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
 
         assert(size % hw->info.bytes_per_frame == 0);
         if (size == 0) {
-            hw->pcm_ops->put_buffer_in(hw, buf, size);
             break;
         }
 
@@ -1502,7 +1501,6 @@ size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
         void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
 
         if (src_size == 0) {
-            hw->pcm_ops->put_buffer_in(hw, src, src_size);
             break;
         }
 
-- 
2.26.2



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

* [PATCH 6/9] audio: align audio_generic_write with audio_pcm_hw_run_out
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (4 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 5/9] audio: remove unnecessary calls to put_buffer_in Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 7/9] audio: run downstream playback queue unconditionally Volker Rümelin
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

The function audio_generic_write should work exactly like
audio_pcm_hw_run_out. It's a very similar function working on a
different buffer.

This patch significantly reduces the number of drop-outs with
the DirectSound backend. To hear the difference start qemu with
-audiodev dsound,id=audio0,out.mixing-engine=off and play a
song in the guest with and without this patch.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 75107a12d0..57eddb3324 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1484,12 +1484,34 @@ size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
 
 size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
 {
-    size_t dst_size, copy_size;
-    void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
-    copy_size = MIN(size, dst_size);
+    size_t total = 0;
+
+    while (total < size) {
+        size_t dst_size = size - total;
+        size_t copy_size, proc;
+        void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
 
-    memcpy(dst, buf, copy_size);
-    return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
+        if (dst_size == 0) {
+            break;
+        }
+
+        copy_size = MIN(size - total, dst_size);
+        if (dst) {
+            memcpy(dst, (char *)buf + total, copy_size);
+        }
+        proc = hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
+        total += proc;
+
+        if (proc == 0 || proc < copy_size) {
+            break;
+        }
+    }
+
+    if (hw->pcm_ops->run_buffer_out) {
+        hw->pcm_ops->run_buffer_out(hw);
+    }
+
+    return total;
 }
 
 size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
-- 
2.26.2



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

* [PATCH 7/9] audio: run downstream playback queue unconditionally
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (5 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 6/9] audio: align audio_generic_write with audio_pcm_hw_run_out Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-20 17:17 ` [PATCH 8/9] audio: restore mixing-engine playback buffer size Volker Rümelin
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

Run the downstream playback queue even if there are no samples
in the mixing engine buffer. The downstream queue may still have
queued samples.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/audio/audio.c b/audio/audio.c
index 57eddb3324..a2c4c55477 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1186,6 +1186,9 @@ static void audio_run_out (AudioState *s)
                     }
                 }
             }
+            if (hw->pcm_ops->run_buffer_out) {
+                hw->pcm_ops->run_buffer_out(hw);
+            }
             continue;
         }
 
-- 
2.26.2



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

* [PATCH 8/9] audio: restore mixing-engine playback buffer size
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (6 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 7/9] audio: run downstream playback queue unconditionally Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-23  6:36   ` Gerd Hoffmann
  2020-09-20 17:17 ` [PATCH 9/9] audio: revert tests for pcm_ops table Volker Rümelin
  2020-09-23  9:07 ` [PATCH 0/9] Audio fixes and improvements Gerd Hoffmann
  9 siblings, 1 reply; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

Commit ff095e5231 "audio: api for mixeng code free backends"
introduced another FIFO for the audio subsystem with exactly the
same size as the mixing-engine FIFO. Most audio backends use
this generic FIFO. The generic FIFO used together with the
mixing-engine FIFO doubles the audio FIFO size, because that's
just two independent FIFOs connected together in series.

For audio playback this nearly doubles the playback latency.

This patch restores the effective mixing-engine playback buffer
size to a pre v4.2.0 size by only accepting the amount of
samples for the mixing-engine queue which the downstream queue
accepts.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/alsaaudio.c   |  1 +
 audio/audio.c       | 68 +++++++++++++++++++++++++++++++++------------
 audio/audio_int.h   |  7 ++++-
 audio/coreaudio.c   |  3 ++
 audio/dsoundaudio.c |  6 ++++
 audio/jackaudio.c   |  1 +
 audio/noaudio.c     |  1 +
 audio/ossaudio.c    | 12 ++++++++
 audio/paaudio.c     |  6 ++++
 audio/sdlaudio.c    |  3 ++
 audio/spiceaudio.c  |  6 ++++
 audio/wavaudio.c    |  1 +
 12 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index a8e62542f9..80235ddf94 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -923,6 +923,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
     .init_out = alsa_init_out,
     .fini_out = alsa_fini_out,
     .write    = alsa_write,
+    .buffer_get_free = audio_generic_buffer_get_free,
     .run_buffer_out = audio_generic_run_buffer_out,
     .enable_out = alsa_enable_out,
 
diff --git a/audio/audio.c b/audio/audio.c
index a2c4c55477..b908e041dd 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -700,12 +700,18 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
     return 0;
 }
 
+static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
+{
+    return hw->pcm_ops->buffer_get_free(hw) / hw->info.bytes_per_frame;
+}
+
 /*
  * Soft voice (playback)
  */
 static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
 {
-    size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
+    size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, limit;
+    size_t blck;
     size_t ret = 0, pos = 0, total = 0;
 
     if (!sw) {
@@ -728,27 +734,28 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
     }
 
     wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
-    samples = size / sw->info.bytes_per_frame;
 
     dead = hwsamples - live;
-    swlim = ((int64_t) dead << 32) / sw->ratio;
-    swlim = MIN (swlim, samples);
-    if (swlim) {
-        sw->conv (sw->buf, buf, swlim);
+    limit = audio_pcm_hw_get_free(sw->hw);
+    samples = ((int64_t)MIN(dead, limit) << 32) / sw->ratio;
+    limit = size / sw->info.bytes_per_frame;
+    samples = MIN(samples, limit);
+    if (samples) {
+        sw->conv(sw->buf, buf, samples);
 
         if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
-            mixeng_volume (sw->buf, swlim, &sw->vol);
+            mixeng_volume(sw->buf, samples, &sw->vol);
         }
     }
 
-    while (swlim) {
+    while (samples) {
         dead = hwsamples - live;
         left = hwsamples - wpos;
         blck = MIN (dead, left);
         if (!blck) {
             break;
         }
-        isamp = swlim;
+        isamp = samples;
         osamp = blck;
         st_rate_flow_mix (
             sw->rate,
@@ -758,7 +765,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
             &osamp
             );
         ret += isamp;
-        swlim -= isamp;
+        samples -= isamp;
         pos += isamp;
         live += osamp;
         wpos = (wpos + osamp) % hwsamples;
@@ -1018,6 +1025,11 @@ static size_t audio_get_avail (SWVoiceIn *sw)
     return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
 }
 
+static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free)
+{
+    return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame;
+}
+
 static size_t audio_get_free(SWVoiceOut *sw)
 {
     size_t live, dead;
@@ -1037,13 +1049,11 @@ static size_t audio_get_free(SWVoiceOut *sw)
     dead = sw->hw->mix_buf->size - live;
 
 #ifdef DEBUG_OUT
-    dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
-           SW_NAME (sw),
-           live, dead, (((int64_t) dead << 32) / sw->ratio) *
-           sw->info.bytes_per_frame);
+    dolog("%s: get_free live %d dead %d sw_bytes %d\n",
+          SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead));
 #endif
 
-    return (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame;
+    return dead;
 }
 
 static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
@@ -1180,7 +1190,10 @@ static void audio_run_out (AudioState *s)
         if (!live) {
             for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
                 if (sw->active) {
-                    free = audio_get_free (sw);
+                    size_t sw_free = audio_get_free(sw);
+                    size_t hw_free = audio_pcm_hw_get_free(hw);
+
+                    free = audio_sw_bytes_free(sw, MIN(sw_free, hw_free));
                     if (free > 0) {
                         sw->callback.fn (sw->callback.opaque, free);
                     }
@@ -1230,7 +1243,10 @@ static void audio_run_out (AudioState *s)
             }
 
             if (sw->active) {
-                free = audio_get_free (sw);
+                size_t sw_free = audio_get_free(sw);
+                size_t hw_free = audio_pcm_hw_get_free(hw);
+
+                free = audio_sw_bytes_free(sw, MIN(sw_free, hw_free));
                 if (free > 0) {
                     sw->callback.fn (sw->callback.opaque, free);
                 }
@@ -1437,6 +1453,15 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
     hw->pending_emul -= size;
 }
 
+size_t audio_generic_buffer_get_free(HWVoiceOut *hw)
+{
+    if (hw->buf_emul) {
+        return hw->size_emul - hw->pending_emul;
+    } else {
+        return hw->samples * hw->info.bytes_per_frame;
+    }
+}
+
 void audio_generic_run_buffer_out(HWVoiceOut *hw)
 {
     while (hw->pending_emul) {
@@ -1826,6 +1851,14 @@ void AUD_remove_card (QEMUSoundCard *card)
     g_free (card->name);
 }
 
+static size_t capture_buffer_get_free(HWVoiceOut *hw)
+{
+    return INT_MAX;
+}
+
+static struct audio_pcm_ops capture_pcm_ops = {
+    .buffer_get_free = capture_buffer_get_free,
+};
 
 CaptureVoiceOut *AUD_add_capture(
     AudioState *s,
@@ -1872,6 +1905,7 @@ CaptureVoiceOut *AUD_add_capture(
 
         hw = &cap->hw;
         hw->s = s;
+        hw->pcm_ops = &capture_pcm_ops;
         QLIST_INIT (&hw->sw_head);
         QLIST_INIT (&cap->cb_head);
 
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 4775857bf2..bb9425bc60 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -154,10 +154,14 @@ struct audio_pcm_ops {
     void   (*fini_out)(HWVoiceOut *hw);
     size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
     void   (*run_buffer_out)(HWVoiceOut *hw);
+    /*
+     * Get the free output buffer size. This is an upper limit. The size
+     * returned by function get_buffer_out may be smaller.
+     */
+    size_t (*buffer_get_free)(HWVoiceOut *hw);
     /*
      * get a buffer that after later can be passed to put_buffer_out; optional
      * returns the buffer, and writes it's size to size (in bytes)
-     * this is unrelated to the above buffer_size_out function
      */
     void  *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
     /*
@@ -181,6 +185,7 @@ struct audio_pcm_ops {
 void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
 void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
 void audio_generic_run_buffer_out(HWVoiceOut *hw);
+size_t audio_generic_buffer_get_free(HWVoiceOut *hw);
 void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
 size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
 size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 4b4365660f..deff0f2419 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -409,6 +409,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
         coreaudio_unlock(core, "coreaudio_" #name);             \
         return ret;                                             \
     }
+COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
 COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
                        (hw, size))
 COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
@@ -670,6 +671,8 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
     .fini_out = coreaudio_fini_out,
   /* wrapper for audio_generic_write */
     .write    = coreaudio_write,
+  /* wrapper for audio_generic_buffer_get_free */
+    .buffer_get_free = coreaudio_buffer_get_free,
   /* wrapper for audio_generic_get_buffer_out */
     .get_buffer_out = coreaudio_get_buffer_out,
   /* wrapper for audio_generic_put_buffer_out */
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 4cdf19ab67..a0c61fb11c 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -411,6 +411,11 @@ static void dsound_enable_out(HWVoiceOut *hw, bool enable)
     }
 }
 
+static size_t dsound_buffer_get_free(HWVoiceOut *hw)
+{
+    return INT_MAX;
+}
+
 static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
 {
     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
@@ -686,6 +691,7 @@ static struct audio_pcm_ops dsound_pcm_ops = {
     .init_out = dsound_init_out,
     .fini_out = dsound_fini_out,
     .write    = audio_generic_write,
+    .buffer_get_free = dsound_buffer_get_free,
     .get_buffer_out = dsound_get_buffer_out,
     .put_buffer_out = dsound_put_buffer_out,
     .enable_out = dsound_enable_out,
diff --git a/audio/jackaudio.c b/audio/jackaudio.c
index 72ed7c4929..07848d9991 100644
--- a/audio/jackaudio.c
+++ b/audio/jackaudio.c
@@ -628,6 +628,7 @@ static struct audio_pcm_ops jack_pcm_ops = {
     .init_out       = qjack_init_out,
     .fini_out       = qjack_fini_out,
     .write          = qjack_write,
+    .buffer_get_free = audio_generic_buffer_get_free,
     .run_buffer_out = audio_generic_run_buffer_out,
     .enable_out     = qjack_enable_out,
 
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 05798ea210..0b932056fa 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -118,6 +118,7 @@ static struct audio_pcm_ops no_pcm_ops = {
     .init_out = no_init_out,
     .fini_out = no_fini_out,
     .write    = no_write,
+    .buffer_get_free = audio_generic_buffer_get_free,
     .run_buffer_out = audio_generic_run_buffer_out,
     .enable_out = no_enable_out,
 
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index a7dcaa31ad..7c46fef68c 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -391,6 +391,17 @@ static void oss_run_buffer_out(HWVoiceOut *hw)
     }
 }
 
+static size_t oss_buffer_get_free(HWVoiceOut *hw)
+{
+    OSSVoiceOut *oss = (OSSVoiceOut *)hw;
+
+    if (oss->mmapped) {
+        return oss_get_available_bytes(oss);
+    } else {
+        return audio_generic_buffer_get_free(hw);
+    }
+}
+
 static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
 {
     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
@@ -754,6 +765,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
     .init_out = oss_init_out,
     .fini_out = oss_fini_out,
     .write    = oss_write,
+    .buffer_get_free = oss_buffer_get_free,
     .run_buffer_out = oss_run_buffer_out,
     .get_buffer_out = oss_get_buffer_out,
     .put_buffer_out = oss_put_buffer_out,
diff --git a/audio/paaudio.c b/audio/paaudio.c
index b052084698..0cb0c83546 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -202,6 +202,11 @@ unlock_and_fail:
     return 0;
 }
 
+static size_t qpa_buffer_get_free(HWVoiceOut *hw)
+{
+    return INT_MAX;
+}
+
 static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
 {
     PAVoiceOut *p = (PAVoiceOut *) hw;
@@ -860,6 +865,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
     .init_out = qpa_init_out,
     .fini_out = qpa_fini_out,
     .write    = qpa_write,
+    .buffer_get_free = qpa_buffer_get_free,
     .get_buffer_out = qpa_get_buffer_out,
     .put_buffer_out = qpa_write, /* pa handles it */
     .volume_out = qpa_volume_out,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 21b7a0484b..cb931d0fda 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -253,6 +253,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
         return ret;                                                     \
     }
 
+SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
 SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
                  (hw, size), *size = 0, sdl_unlock)
 SDL_WRAPPER_FUNC(put_buffer_out, size_t,
@@ -350,6 +351,8 @@ static struct audio_pcm_ops sdl_pcm_ops = {
     .fini_out = sdl_fini_out,
   /* wrapper for audio_generic_write */
     .write    = sdl_write,
+  /* wrapper for audio_generic_buffer_get_free */
+    .buffer_get_free = sdl_buffer_get_free,
   /* wrapper for audio_generic_get_buffer_out */
     .get_buffer_out = sdl_get_buffer_out,
   /* wrapper for audio_generic_put_buffer_out */
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index c062742622..1fb0571dcc 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -120,6 +120,11 @@ static void line_out_fini (HWVoiceOut *hw)
     spice_server_remove_interface (&out->sin.base);
 }
 
+static size_t line_out_buffer_get_free(HWVoiceOut *hw)
+{
+    return INT_MAX;
+}
+
 static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
 {
     SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
@@ -282,6 +287,7 @@ static struct audio_pcm_ops audio_callbacks = {
     .init_out = line_out_init,
     .fini_out = line_out_fini,
     .write    = audio_generic_write,
+    .buffer_get_free = line_out_buffer_get_free,
     .get_buffer_out = line_out_get_buffer,
     .put_buffer_out = line_out_put_buffer,
     .enable_out = line_out_enable,
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 20e6853f85..ac666335c7 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -197,6 +197,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
     .init_out = wav_init_out,
     .fini_out = wav_fini_out,
     .write    = wav_write_out,
+    .buffer_get_free = audio_generic_buffer_get_free,
     .run_buffer_out = audio_generic_run_buffer_out,
     .enable_out = wav_enable_out,
 };
-- 
2.26.2



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

* [PATCH 9/9] audio: revert tests for pcm_ops table
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (7 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 8/9] audio: restore mixing-engine playback buffer size Volker Rümelin
@ 2020-09-20 17:17 ` Volker Rümelin
  2020-09-23  9:07 ` [PATCH 0/9] Audio fixes and improvements Gerd Hoffmann
  9 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-20 17:17 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

With previous commit every audio backend has a pcm_ops function
table. It's no longer necessary to test if the table is
available. This reverts commit cbaf25d1f5: "audio: fix
wavcapture segfault"

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index b908e041dd..f63781b4db 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -649,7 +649,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
         total += isamp;
     }
 
-    if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
+    if (!hw->pcm_ops->volume_in) {
         mixeng_volume (sw->buf, ret, &sw->vol);
     }
 
@@ -743,7 +743,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
     if (samples) {
         sw->conv(sw->buf, buf, samples);
 
-        if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
+        if (!sw->hw->pcm_ops->volume_out) {
             mixeng_volume(sw->buf, samples, &sw->vol);
         }
     }
-- 
2.26.2



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

* Re: [PATCH 8/9] audio: restore mixing-engine playback buffer size
  2020-09-20 17:17 ` [PATCH 8/9] audio: restore mixing-engine playback buffer size Volker Rümelin
@ 2020-09-23  6:36   ` Gerd Hoffmann
  2020-09-24 17:42     ` Volker Rümelin
  0 siblings, 1 reply; 13+ messages in thread
From: Gerd Hoffmann @ 2020-09-23  6:36 UTC (permalink / raw)
  To: Volker Rümelin; +Cc: qemu-devel, Zoltán Kővágó

> diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
> index 21b7a0484b..cb931d0fda 100644
> --- a/audio/sdlaudio.c
> +++ b/audio/sdlaudio.c
> @@ -253,6 +253,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
>          return ret;                                                     \
>      }
>  
> +SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
>  SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
>                   (hw, size), *size = 0, sdl_unlock)
>  SDL_WRAPPER_FUNC(put_buffer_out, size_t,

Compiling C object libcommon.fa.p/audio_sdlaudio.c.o
../../audio/sdlaudio.c:256:65: error: macro "SDL_WRAPPER_FUNC" requires 6 arguments, but only 4 given
  256 | SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
      |                                                                 ^
../../audio/sdlaudio.c:243: note: macro "SDL_WRAPPER_FUNC" defined here
  243 | #define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
      | 
../../audio/sdlaudio.c:256:17: error: expected ‘;’ before ‘static’
  256 | SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
      |                 ^
      |                 ;
../../audio/sdlaudio.c:355:24: error: ‘sdl_buffer_get_free’ undeclared here (not in a function)
  355 |     .buffer_get_free = sdl_buffer_get_free,
      |                        ^~~~~~~~~~~~~~~~~~~
make: *** [Makefile.ninja:1113: libcommon.fa.p/audio_sdlaudio.c.o] Error 1

(I think coreaudio has the same problem ...).

take care,
  Gerd



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

* Re: [PATCH 0/9] Audio fixes and improvements
  2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
                   ` (8 preceding siblings ...)
  2020-09-20 17:17 ` [PATCH 9/9] audio: revert tests for pcm_ops table Volker Rümelin
@ 2020-09-23  9:07 ` Gerd Hoffmann
  9 siblings, 0 replies; 13+ messages in thread
From: Gerd Hoffmann @ 2020-09-23  9:07 UTC (permalink / raw)
  To: Volker Rümelin; +Cc: qemu-devel, Zoltán Kővágó

On Sun, Sep 20, 2020 at 07:14:12PM +0200, Volker Rümelin wrote:
> A few fixes and improvements from my audio patch queue.

cherry-picked 1-7 into the audio queue.

thanks,
  Gerd



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

* Re: [PATCH 8/9] audio: restore mixing-engine playback buffer size
  2020-09-23  6:36   ` Gerd Hoffmann
@ 2020-09-24 17:42     ` Volker Rümelin
  0 siblings, 0 replies; 13+ messages in thread
From: Volker Rümelin @ 2020-09-24 17:42 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Zoltán Kővágó

>> diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
>> index 21b7a0484b..cb931d0fda 100644
>> --- a/audio/sdlaudio.c
>> +++ b/audio/sdlaudio.c
>> @@ -253,6 +253,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
>>          return ret;                                                     \
>>      }
>>  
>> +SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
>>  SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
>>                   (hw, size), *size = 0, sdl_unlock)
>>  SDL_WRAPPER_FUNC(put_buffer_out, size_t,
> Compiling C object libcommon.fa.p/audio_sdlaudio.c.o
> ../../audio/sdlaudio.c:256:65: error: macro "SDL_WRAPPER_FUNC" requires 6 arguments, but only 4 given
>   256 | SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
>       |                                                                 ^
> ../../audio/sdlaudio.c:243: note: macro "SDL_WRAPPER_FUNC" defined here
>   243 | #define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
>       | 
> ../../audio/sdlaudio.c:256:17: error: expected ‘;’ before ‘static’
>   256 | SDL_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
>       |                 ^
>       |                 ;
> ../../audio/sdlaudio.c:355:24: error: ‘sdl_buffer_get_free’ undeclared here (not in a function)
>   355 |     .buffer_get_free = sdl_buffer_get_free,
>       |                        ^~~~~~~~~~~~~~~~~~~
> make: *** [Makefile.ninja:1113: libcommon.fa.p/audio_sdlaudio.c.o] Error 1
>
> (I think coreaudio has the same problem ...).
>
> take care,
>   Gerd
>

Sorry. This was caused by a bad rebase and my tests were insufficient. I guess I'll send my sdlaudio patches next. This patch has to wait.

With best regards,
Volker


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

end of thread, other threads:[~2020-09-24 17:46 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-20 17:14 [PATCH 0/9] Audio fixes and improvements Volker Rümelin
2020-09-20 17:17 ` [PATCH 1/9] audio: handle buf == NULL in put_buffer_out() Volker Rümelin
2020-09-20 17:17 ` [PATCH 2/9] audio/audio: fix video playback slowdown with spiceaudio Volker Rümelin
2020-09-20 17:17 ` [PATCH 3/9] audio/spiceaudio: always rate limit playback stream Volker Rümelin
2020-09-20 17:17 ` [PATCH 4/9] audio: align audio_generic_read with audio_pcm_hw_run_in Volker Rümelin
2020-09-20 17:17 ` [PATCH 5/9] audio: remove unnecessary calls to put_buffer_in Volker Rümelin
2020-09-20 17:17 ` [PATCH 6/9] audio: align audio_generic_write with audio_pcm_hw_run_out Volker Rümelin
2020-09-20 17:17 ` [PATCH 7/9] audio: run downstream playback queue unconditionally Volker Rümelin
2020-09-20 17:17 ` [PATCH 8/9] audio: restore mixing-engine playback buffer size Volker Rümelin
2020-09-23  6:36   ` Gerd Hoffmann
2020-09-24 17:42     ` Volker Rümelin
2020-09-20 17:17 ` [PATCH 9/9] audio: revert tests for pcm_ops table Volker Rümelin
2020-09-23  9:07 ` [PATCH 0/9] Audio fixes and improvements 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).