All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/27] Audio patches
@ 2023-03-06  6:51 marcandre.lureau
  2023-03-06  6:51 ` [PULL 01/27] MAINTAINERS: add myself to ui/ and audio/ marcandre.lureau
                   ` (27 more replies)
  0 siblings, 28 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The following changes since commit 2946e1af2704bf6584f57d4e3aec49d1d5f3ecc0:

  configure: Disable thread-safety warnings on macOS (2023-03-04 14:03:46 +0000)

are available in the Git repository at:

  https://gitlab.com/marcandre.lureau/qemu.git tags/audio-pull-request

for you to fetch changes up to 2f886a34bb7e6f6fcf39d64829f4499476f26dba:

  audio: remove sw->ratio (2023-03-06 10:30:24 +0400)

----------------------------------------------------------------
Audio patches for QEMU 8.0

Cleanups and improvements from Volker Rümelin.

----------------------------------------------------------------

Marc-André Lureau (1):
  MAINTAINERS: add myself to ui/ and audio/

Volker Rümelin (26):
  audio: log unimplemented audio device sample rates
  audio: don't show unnecessary error messages
  audio: rename hardware store to backend
  audio: remove unused #define AUDIO_STRINGIFY
  audio/mixeng: use g_new0() instead of audio_calloc()
  audio/alsaaudio: use g_new0() instead of audio_calloc()
  audio/audio_template: use g_malloc0() to replace audio_calloc()
  audio/audio_template: use g_new0() to replace audio_calloc()
  audio: remove audio_calloc() function
  alsaaudio: change default playback settings
  alsaaudio: reintroduce default recording settings
  audio: change type of mix_buf and conv_buf
  audio: change type and name of the resample buffer
  audio: make the resampling code greedy
  audio: replace the resampling loop in audio_pcm_sw_write()
  audio: remove sw == NULL check
  audio: rename variables in audio_pcm_sw_write()
  audio: don't misuse audio_pcm_sw_write()
  audio: remove unused noop_conv() function
  audio: make playback packet length calculation exact
  audio: replace the resampling loop in audio_pcm_sw_read()
  audio: rename variables in audio_pcm_sw_read()
  audio: make recording packet length calculation exact
  audio: handle leftover audio frame from upsampling
  audio/audio_template: substitute sw->hw with hw
  audio: remove sw->ratio

 MAINTAINERS            |   2 +
 audio/audio_int.h      |  20 +--
 audio/audio_template.h | 105 +++++------
 audio/mixeng.h         |   2 +
 audio/rate_template.h  |  21 ++-
 audio/alsaaudio.c      |  27 +--
 audio/audio.c          | 392 ++++++++++++++++++++---------------------
 audio/mixeng.c         |  87 ++++++++-
 8 files changed, 359 insertions(+), 297 deletions(-)

-- 
2.39.2



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

* [PULL 01/27] MAINTAINERS: add myself to ui/ and audio/
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 02/27] audio: log unimplemented audio device sample rates marcandre.lureau
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Helping out with patch review & queue handling.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230207085610.1033536-1-marcandre.lureau@redhat.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 011fd85a09..da29661b37 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2490,6 +2490,7 @@ Subsystems
 ----------
 Overall Audio backends
 M: Gerd Hoffmann <kraxel@redhat.com>
+M: Marc-André Lureau <marcandre.lureau@redhat.com>
 S: Odd Fixes
 F: audio/
 X: audio/alsaaudio.c
@@ -2785,6 +2786,7 @@ F: docs/spice-port-fqdn.txt
 
 Graphics
 M: Gerd Hoffmann <kraxel@redhat.com>
+M: Marc-André Lureau <marcandre.lureau@redhat.com>
 S: Odd Fixes
 F: ui/
 F: include/ui/
-- 
2.39.2



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

* [PULL 02/27] audio: log unimplemented audio device sample rates
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
  2023-03-06  6:51 ` [PULL 01/27] MAINTAINERS: add myself to ui/ and audio/ marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 03/27] audio: don't show unnecessary error messages marcandre.lureau
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Some emulated audio devices allow guests to select very low
sample rates that the audio subsystem doesn't support. The lowest
supported sample rate depends on the audio backend used and in
most cases can be changed with various -audiodev arguments. Until
now, the audio_bug function emits an error message similar to the
following error message

A bug was just triggered in audio_calloc
Save all your work and restart without audio
I am sorry
Context:
audio_pcm_sw_alloc_resources_out passed invalid arguments to
 audio_calloc
nmemb=0 size=16 (len=0)
audio: Could not allocate buffer for `ac97.po' (0 samples)

and the audio subsystem continues without sound for the affected
device.

The fact that the selected sample rate is not supported is not a
guest error. Instead of displaying an error message, the missing
audio support is now logged. Simply continuing without sound is
correct, since the audio stream won't transport anything
reasonable at such high resample ratios anyway.

The AUD_open_* functions return NULL like before. The opened
audio device will not be registered in the audio subsystem and
consequently the audio frontend callback functions will not be
called. The AUD_read and AUD_write functions return early in this
case. This is necessary because, for example, the Sound Blaster 16
emulation calls AUD_write from the DMA callback function.

Acked-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-1-vr_qemu@t-online.de>
---
 audio/audio_template.h | 13 +++++++++++++
 audio/audio.c          |  1 +
 2 files changed, 14 insertions(+)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 42b4712acb..dbfb4fee4c 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -115,6 +115,19 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 #else
     samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
 #endif
+    if (samples == 0) {
+        HW *hw = sw->hw;
+        size_t f_fe_min;
+
+        /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
+        f_fe_min = (hw->info.freq + HWBUF->size - 1) / HWBUF->size;
+        qemu_log_mask(LOG_UNIMP,
+                      AUDIO_CAP ": The guest selected a " NAME " sample rate"
+                      " of %d Hz for %s. Only sample rates >= %zu Hz are"
+                      " supported.\n",
+                      sw->info.freq, sw->name, f_fe_min);
+        return -1;
+    }
 
     sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
     if (!sw->buf) {
diff --git a/audio/audio.c b/audio/audio.c
index 4290309d18..81f5c0bb1e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -33,6 +33,7 @@
 #include "qapi/qapi-visit-audio.h"
 #include "qapi/qapi-commands-audio.h"
 #include "qemu/cutils.h"
+#include "qemu/log.h"
 #include "qemu/module.h"
 #include "qemu/help_option.h"
 #include "sysemu/sysemu.h"
-- 
2.39.2



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

* [PULL 03/27] audio: don't show unnecessary error messages
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
  2023-03-06  6:51 ` [PULL 01/27] MAINTAINERS: add myself to ui/ and audio/ marcandre.lureau
  2023-03-06  6:51 ` [PULL 02/27] audio: log unimplemented audio device sample rates marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 04/27] audio: rename hardware store to backend marcandre.lureau
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Let the audio_pcm_create_voice_pair_* functions handle error
reporting. This avoids an additional error message in case
the guest selected an unimplemented sample rate.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-2-vr_qemu@t-online.de>
---
 audio/audio_template.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index dbfb4fee4c..f0ef262ab3 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -441,6 +441,7 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
 
     hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
     if (!hw) {
+        dolog("Could not create a backend for voice `%s'\n", sw_name);
         goto err2;
     }
 
@@ -540,7 +541,6 @@ SW *glue (AUD_open_, TYPE) (
     } else {
         sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
         if (!sw) {
-            dolog ("Failed to create voice `%s'\n", name);
             return NULL;
         }
     }
-- 
2.39.2



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

* [PULL 04/27] audio: rename hardware store to backend
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (2 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 03/27] audio: don't show unnecessary error messages marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 05/27] audio: remove unused #define AUDIO_STRINGIFY marcandre.lureau
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Use a consistent friendly name for the HWVoiceOut and HWVoiceIn
structures.

Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230121094735.11644-3-vr_qemu@t-online.de>
---
 audio/audio_template.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index f0ef262ab3..33af42ed8b 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -529,8 +529,8 @@ SW *glue (AUD_open_, TYPE) (
         HW *hw = sw->hw;
 
         if (!hw) {
-            dolog ("Internal logic error voice `%s' has no hardware store\n",
-                   SW_NAME (sw));
+            dolog("Internal logic error: voice `%s' has no backend\n",
+                  SW_NAME(sw));
             goto fail;
         }
 
-- 
2.39.2



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

* [PULL 05/27] audio: remove unused #define AUDIO_STRINGIFY
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (3 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 04/27] audio: rename hardware store to backend marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 06/27] audio/mixeng: use g_new0() instead of audio_calloc() marcandre.lureau
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Remove the unused #define AUDIO_STRINGIFY. It was last used before
commit 470bcabd8f ("audio: Replace AUDIO_FUNC with __func__").

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-4-vr_qemu@t-online.de>
---
 audio/audio_int.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index e87ce014a0..4632cdf9cc 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -294,9 +294,6 @@ static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
 #define ldebug(fmt, ...) (void)0
 #endif
 
-#define AUDIO_STRINGIFY_(n) #n
-#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
-
 typedef struct AudiodevListEntry {
     Audiodev *dev;
     QSIMPLEQ_ENTRY(AudiodevListEntry) next;
-- 
2.39.2



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

* [PULL 06/27] audio/mixeng: use g_new0() instead of audio_calloc()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (4 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 05/27] audio: remove unused #define AUDIO_STRINGIFY marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 07/27] audio/alsaaudio: " marcandre.lureau
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Replace audio_calloc() with the equivalent g_new0().

With a n_structs argument of 1, g_new0() never returns NULL.
Also remove the unnecessary NULL checks.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-5-vr_qemu@t-online.de>
---
 audio/audio_template.h | 6 +-----
 audio/audio.c          | 5 -----
 audio/mixeng.c         | 7 +------
 3 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 33af42ed8b..dfa440f778 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -141,11 +141,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 #else
     sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
 #endif
-    if (!sw->rate) {
-        g_free (sw->buf);
-        sw->buf = NULL;
-        return -1;
-    }
+
     return 0;
 }
 
diff --git a/audio/audio.c b/audio/audio.c
index 81f5c0bb1e..012d10996b 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -509,11 +509,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
         sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
         sw->vol = nominal_volume;
         sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
-        if (!sw->rate) {
-            dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
-            g_free (sw);
-            return -1;
-        }
         QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
         QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
 #ifdef DEBUG_CAPTURE
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 100a306d6f..fe454e0725 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -414,12 +414,7 @@ struct rate {
  */
 void *st_rate_start (int inrate, int outrate)
 {
-    struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate));
-
-    if (!rate) {
-        dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
-        return NULL;
-    }
+    struct rate *rate = g_new0(struct rate, 1);
 
     rate->opos = 0;
 
-- 
2.39.2



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

* [PULL 07/27] audio/alsaaudio: use g_new0() instead of audio_calloc()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (5 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 06/27] audio/mixeng: use g_new0() instead of audio_calloc() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 08/27] audio/audio_template: use g_malloc0() to replace audio_calloc() marcandre.lureau
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Replace audio_calloc() with the equivalent g_new0().

The value of the g_new0() argument count is >= 1, which means
g_new0() will never return NULL. Also remove the unnecessary
NULL check.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-6-vr_qemu@t-online.de>
---
 audio/alsaaudio.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 714bfb6453..5f50dfa0bf 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -222,11 +222,7 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
         return -1;
     }
 
-    pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
-    if (!pfds) {
-        dolog ("Could not initialize poll mode\n");
-        return -1;
-    }
+    pfds = g_new0(struct pollfd, count);
 
     err = snd_pcm_poll_descriptors (handle, pfds, count);
     if (err < 0) {
-- 
2.39.2



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

* [PULL 08/27] audio/audio_template: use g_malloc0() to replace audio_calloc()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (6 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 07/27] audio/alsaaudio: " marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 09/27] audio/audio_template: use g_new0() " marcandre.lureau
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Use g_malloc0() as a direct replacement for audio_calloc().

Since the type of the parameter n_bytes of the function g_malloc0()
is unsigned, the type of the variables voice_size_out and
voice_size_in has been changed to size_t. This means that the
function argument no longer has to be checked for negative values.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-7-vr_qemu@t-online.de>
---
 audio/audio_int.h      |  4 ++--
 audio/audio_template.h | 18 ++++++++----------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 4632cdf9cc..ce2d6bf92c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -151,8 +151,8 @@ struct audio_driver {
     int can_be_default;
     int max_voices_out;
     int max_voices_in;
-    int voice_size_out;
-    int voice_size_in;
+    size_t voice_size_out;
+    size_t voice_size_in;
     QLIST_ENTRY(audio_driver) next;
 };
 
diff --git a/audio/audio_template.h b/audio/audio_template.h
index dfa440f778..592866f14a 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -40,7 +40,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
                                               struct audio_driver *drv)
 {
     int max_voices = glue (drv->max_voices_, TYPE);
-    int voice_size = glue (drv->voice_size_, TYPE);
+    size_t voice_size = glue(drv->voice_size_, TYPE);
 
     if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
         if (!max_voices) {
@@ -63,8 +63,8 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
     }
 
     if (audio_bug(__func__, voice_size && !max_voices)) {
-        dolog ("drv=`%s' voice_size=%d max_voices=0\n",
-               drv->name, voice_size);
+        dolog("drv=`%s' voice_size=%zu max_voices=0\n",
+              drv->name, voice_size);
     }
 }
 
@@ -273,13 +273,11 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
         return NULL;
     }
 
-    hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
-    if (!hw) {
-        dolog ("Can not allocate voice `%s' size %d\n",
-               drv->name, glue (drv->voice_size_, TYPE));
-        return NULL;
-    }
-
+    /*
+     * Since glue(s->nb_hw_voices_, TYPE) is != 0, glue(drv->voice_size_, TYPE)
+     * is guaranteed to be != 0. See the audio_init_nb_voices_* functions.
+     */
+    hw = g_malloc0(glue(drv->voice_size_, TYPE));
     hw->s = s;
     hw->pcm_ops = drv->pcm_ops;
 
-- 
2.39.2



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

* [PULL 09/27] audio/audio_template: use g_new0() to replace audio_calloc()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (7 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 08/27] audio/audio_template: use g_malloc0() to replace audio_calloc() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 10/27] audio: remove audio_calloc() function marcandre.lureau
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Replace audio_calloc() with the equivalent g_new0().

With a n_structs argument >= 1, g_new0() never returns NULL.
Also remove the unnecessary NULL checks.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-8-vr_qemu@t-online.de>
---
 audio/audio_template.h | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 592866f14a..980e1f4bd0 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -115,6 +115,12 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 #else
     samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
 #endif
+    if (audio_bug(__func__, samples < 0)) {
+        dolog("Can not allocate buffer for `%s' (%d samples)\n",
+              SW_NAME(sw), samples);
+        return -1;
+    }
+
     if (samples == 0) {
         HW *hw = sw->hw;
         size_t f_fe_min;
@@ -129,12 +135,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
         return -1;
     }
 
-    sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
-    if (!sw->buf) {
-        dolog ("Could not allocate buffer for `%s' (%d samples)\n",
-               SW_NAME (sw), samples);
-        return -1;
-    }
+    sw->buf = g_new0(st_sample, samples);
 
 #ifdef DAC
     sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
@@ -425,34 +426,28 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
         hw_as = *as;
     }
 
-    sw = audio_calloc(__func__, 1, sizeof(*sw));
-    if (!sw) {
-        dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
-               sw_name ? sw_name : "unknown", sizeof (*sw));
-        goto err1;
-    }
+    sw = g_new0(SW, 1);
     sw->s = s;
 
     hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
     if (!hw) {
         dolog("Could not create a backend for voice `%s'\n", sw_name);
-        goto err2;
+        goto err1;
     }
 
     glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
 
     if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
-        goto err3;
+        goto err2;
     }
 
     return sw;
 
-err3:
+err2:
     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
     glue (audio_pcm_hw_gc_, TYPE) (&hw);
-err2:
-    g_free (sw);
 err1:
+    g_free(sw);
     return NULL;
 }
 
-- 
2.39.2



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

* [PULL 10/27] audio: remove audio_calloc() function
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (8 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 09/27] audio/audio_template: use g_new0() " marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 11/27] alsaaudio: change default playback settings marcandre.lureau
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Now that the last call site of audio_calloc() was removed, remove
the unused audio_calloc() function.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-9-vr_qemu@t-online.de>
---
 audio/audio_int.h |  1 -
 audio/audio.c     | 20 --------------------
 2 files changed, 21 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index ce2d6bf92c..5028f2354a 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -251,7 +251,6 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
 
 int audio_bug (const char *funcname, int cond);
-void *audio_calloc (const char *funcname, int nmemb, size_t size);
 
 void audio_run(AudioState *s, const char *msg);
 
diff --git a/audio/audio.c b/audio/audio.c
index 012d10996b..772c3cc320 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -149,26 +149,6 @@ static inline int audio_bits_to_index (int bits)
     }
 }
 
-void *audio_calloc (const char *funcname, int nmemb, size_t size)
-{
-    int cond;
-    size_t len;
-
-    len = nmemb * size;
-    cond = !nmemb || !size;
-    cond |= nmemb < 0;
-    cond |= len < size;
-
-    if (audio_bug ("audio_calloc", cond)) {
-        AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
-                 funcname);
-        AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
-        return NULL;
-    }
-
-    return g_malloc0 (len);
-}
-
 void AUD_vlog (const char *cap, const char *fmt, va_list ap)
 {
     if (cap) {
-- 
2.39.2



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

* [PULL 11/27] alsaaudio: change default playback settings
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (9 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 10/27] audio: remove audio_calloc() function marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 12/27] alsaaudio: reintroduce default recording settings marcandre.lureau
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

The currently used default playback settings in the ALSA audio
backend are a bit unfortunate. With a few emulated audio devices,
audio playback does not work properly. Here is a short part of
the debug log while audio is playing (elapsed time in seconds).

audio: Elapsed since last alsa run (running): 0.046244
audio: Elapsed since last alsa run (running): 0.023137
audio: Elapsed since last alsa run (running): 0.023170
audio: Elapsed since last alsa run (running): 0.023650
audio: Elapsed since last alsa run (running): 0.060802
audio: Elapsed since last alsa run (running): 0.031931

For some audio devices the time of more than 23ms between updates
is too long.

Set the period time to 5.8ms so that the maximum time between
two updates typically does not exceed 11ms. This roughly matches
the 10ms period time when doing playback with the audio timer.
After this patch the debug log looks like this.

audio: Elapsed since last alsa run (running): 0.011919
audio: Elapsed since last alsa run (running): 0.005788
audio: Elapsed since last alsa run (running): 0.005995
audio: Elapsed since last alsa run (running): 0.011069
audio: Elapsed since last alsa run (running): 0.005901
audio: Elapsed since last alsa run (running): 0.006084

Acked-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-10-vr_qemu@t-online.de>
---
 audio/alsaaudio.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 5f50dfa0bf..0cc982e61f 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -913,17 +913,14 @@ static void *alsa_audio_init(Audiodev *dev)
     alsa_init_per_direction(aopts->in);
     alsa_init_per_direction(aopts->out);
 
-    /*
-     * need to define them, as otherwise alsa produces no sound
-     * doesn't set has_* so alsa_open can identify it wasn't set by the user
-     */
+    /* don't set has_* so alsa_open can identify it wasn't set by the user */
     if (!dev->u.alsa.out->has_period_length) {
-        /* 1024 frames assuming 44100Hz */
-        dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
+        /* 256 frames assuming 44100Hz */
+        dev->u.alsa.out->period_length = 5805;
     }
     if (!dev->u.alsa.out->has_buffer_length) {
         /* 4096 frames assuming 44100Hz */
-        dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
+        dev->u.alsa.out->buffer_length = 92880;
     }
 
     /*
-- 
2.39.2



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

* [PULL 12/27] alsaaudio: reintroduce default recording settings
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (10 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 11/27] alsaaudio: change default playback settings marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 13/27] audio: change type of mix_buf and conv_buf marcandre.lureau
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Audio recording with ALSA default settings currently doesn't
work. The debug log shows updates every 0.75s and 1.5s.

audio: Elapsed since last alsa run (running): 0.743030
audio: Elapsed since last alsa run (running): 1.486048
audio: Elapsed since last alsa run (running): 0.743008
audio: Elapsed since last alsa run (running): 1.485878
audio: Elapsed since last alsa run (running): 1.486040
audio: Elapsed since last alsa run (running): 1.485886

The time between updates should be in the 10ms range. Audio
recording with ALSA has the same timing contraints as playback.
Reintroduce the default recording settings and use the same
default settings for recording as for playback.

The term "reintroduce" is correct because commit a93f328177
("alsaaudio: port to -audiodev config") removed the default
settings for recording.

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20230121094735.11644-11-vr_qemu@t-online.de>
---
 audio/alsaaudio.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 0cc982e61f..057571dd1e 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -923,15 +923,13 @@ static void *alsa_audio_init(Audiodev *dev)
         dev->u.alsa.out->buffer_length = 92880;
     }
 
-    /*
-     * OptsVisitor sets unspecified optional fields to zero, but do not depend
-     * on it...
-     */
     if (!dev->u.alsa.in->has_period_length) {
-        dev->u.alsa.in->period_length = 0;
+        /* 256 frames assuming 44100Hz */
+        dev->u.alsa.in->period_length = 5805;
     }
     if (!dev->u.alsa.in->has_buffer_length) {
-        dev->u.alsa.in->buffer_length = 0;
+        /* 4096 frames assuming 44100Hz */
+        dev->u.alsa.in->buffer_length = 92880;
     }
 
     return dev;
-- 
2.39.2



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

* [PULL 13/27] audio: change type of mix_buf and conv_buf
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (11 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 12/27] alsaaudio: reintroduce default recording settings marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 14/27] audio: change type and name of the resample buffer marcandre.lureau
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Change the type of mix_buf in struct HWVoiceOut and conv_buf
in struct HWVoiceIn from STSampleBuffer * to STSampleBuffer.
However, a buffer pointer is still needed. For this reason in
struct STSampleBuffer samples[] is changed to *buffer.

This is a preparation for the next patch. The next patch will
add this line, which is not possible with the current struct
STSampleBuffer definition.

+        sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;

There are no functional changes.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-1-vr_qemu@t-online.de>
---
 audio/audio_int.h      |   6 +--
 audio/audio_template.h |  19 ++++----
 audio/audio.c          | 106 ++++++++++++++++++++---------------------
 3 files changed, 67 insertions(+), 64 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 5028f2354a..061845dcc2 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -58,7 +58,7 @@ typedef struct SWVoiceCap SWVoiceCap;
 
 typedef struct STSampleBuffer {
     size_t pos, size;
-    st_sample samples[];
+    st_sample *buffer;
 } STSampleBuffer;
 
 typedef struct HWVoiceOut {
@@ -71,7 +71,7 @@ typedef struct HWVoiceOut {
     f_sample *clip;
     uint64_t ts_helper;
 
-    STSampleBuffer *mix_buf;
+    STSampleBuffer mix_buf;
     void *buf_emul;
     size_t pos_emul, pending_emul, size_emul;
 
@@ -93,7 +93,7 @@ typedef struct HWVoiceIn {
     size_t total_samples_captured;
     uint64_t ts_helper;
 
-    STSampleBuffer *conv_buf;
+    STSampleBuffer conv_buf;
     void *buf_emul;
     size_t pos_emul, pending_emul, size_emul;
 
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 980e1f4bd0..dd87170cbd 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,8 +71,9 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
 static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
 {
     g_free(hw->buf_emul);
-    g_free (HWBUF);
-    HWBUF = NULL;
+    g_free(HWBUF.buffer);
+    HWBUF.buffer = NULL;
+    HWBUF.size = 0;
 }
 
 static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
@@ -83,10 +84,12 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
             dolog("Attempted to allocate empty buffer\n");
         }
 
-        HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
-        HWBUF->size = samples;
+        HWBUF.buffer = g_new0(st_sample, samples);
+        HWBUF.size = samples;
+        HWBUF.pos = 0;
     } else {
-        HWBUF = NULL;
+        HWBUF.buffer = NULL;
+        HWBUF.size = 0;
     }
 }
 
@@ -111,9 +114,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
     }
 
 #ifdef DAC
-    samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
+    samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
 #else
-    samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
+    samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
 #endif
     if (audio_bug(__func__, samples < 0)) {
         dolog("Can not allocate buffer for `%s' (%d samples)\n",
@@ -126,7 +129,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
         size_t f_fe_min;
 
         /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
-        f_fe_min = (hw->info.freq + HWBUF->size - 1) / HWBUF->size;
+        f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
         qemu_log_mask(LOG_UNIMP,
                       AUDIO_CAP ": The guest selected a " NAME " sample rate"
                       " of %d Hz for %s. Only sample rates >= %zu Hz are"
diff --git a/audio/audio.c b/audio/audio.c
index 772c3cc320..a0b54e4a2e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -523,8 +523,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 {
     size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
-    if (audio_bug(__func__, live > hw->conv_buf->size)) {
-        dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
+    if (audio_bug(__func__, live > hw->conv_buf.size)) {
+        dolog("live=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
         return 0;
     }
     return live;
@@ -533,13 +533,13 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
 {
     size_t conv = 0;
-    STSampleBuffer *conv_buf = hw->conv_buf;
+    STSampleBuffer *conv_buf = &hw->conv_buf;
 
     while (samples) {
         uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
         size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
 
-        hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
+        hw->conv(conv_buf->buffer + conv_buf->pos, src, proc);
         conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
         samples -= proc;
         conv += proc;
@@ -561,12 +561,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
     if (!live) {
         return 0;
     }
-    if (audio_bug(__func__, live > hw->conv_buf->size)) {
-        dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
+    if (audio_bug(__func__, live > hw->conv_buf.size)) {
+        dolog("live_in=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
         return 0;
     }
 
-    rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
+    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
 
     samples = size / sw->info.bytes_per_frame;
 
@@ -574,11 +574,11 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
     swlim = MIN (swlim, samples);
 
     while (swlim) {
-        src = hw->conv_buf->samples + rpos;
-        if (hw->conv_buf->pos > rpos) {
-            isamp = hw->conv_buf->pos - rpos;
+        src = hw->conv_buf.buffer + rpos;
+        if (hw->conv_buf.pos > rpos) {
+            isamp = hw->conv_buf.pos - rpos;
         } else {
-            isamp = hw->conv_buf->size - rpos;
+            isamp = hw->conv_buf.size - rpos;
         }
 
         if (!isamp) {
@@ -588,7 +588,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
 
         st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
         swlim -= osamp;
-        rpos = (rpos + isamp) % hw->conv_buf->size;
+        rpos = (rpos + isamp) % hw->conv_buf.size;
         dst += osamp;
         ret += osamp;
         total += isamp;
@@ -636,8 +636,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
     if (nb_live1) {
         size_t live = smin;
 
-        if (audio_bug(__func__, live > hw->mix_buf->size)) {
-            dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
+        if (audio_bug(__func__, live > hw->mix_buf.size)) {
+            dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
             return 0;
         }
         return live;
@@ -654,17 +654,17 @@ static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
 static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
 {
     size_t clipped = 0;
-    size_t pos = hw->mix_buf->pos;
+    size_t pos = hw->mix_buf.pos;
 
     while (len) {
-        st_sample *src = hw->mix_buf->samples + pos;
+        st_sample *src = hw->mix_buf.buffer + pos;
         uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
-        size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
+        size_t samples_till_end_of_buf = hw->mix_buf.size - pos;
         size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
 
         hw->clip(dst, src, samples_to_clip);
 
-        pos = (pos + samples_to_clip) % hw->mix_buf->size;
+        pos = (pos + samples_to_clip) % hw->mix_buf.size;
         len -= samples_to_clip;
         clipped += samples_to_clip;
     }
@@ -683,11 +683,11 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         return size;
     }
 
-    hwsamples = sw->hw->mix_buf->size;
+    hwsamples = sw->hw->mix_buf.size;
 
     live = sw->total_hw_samples_mixed;
     if (audio_bug(__func__, live > hwsamples)) {
-        dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
+        dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
         return 0;
     }
 
@@ -698,7 +698,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         return 0;
     }
 
-    wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
+    wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
 
     dead = hwsamples - live;
     hw_free = audio_pcm_hw_get_free(sw->hw);
@@ -725,7 +725,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         st_rate_flow_mix (
             sw->rate,
             sw->buf + pos,
-            sw->hw->mix_buf->samples + wpos,
+            sw->hw->mix_buf.buffer + wpos,
             &isamp,
             &osamp
             );
@@ -989,9 +989,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
     }
 
     live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
-    if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
-        dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
-              sw->hw->conv_buf->size);
+    if (audio_bug(__func__, live > sw->hw->conv_buf.size)) {
+        dolog("live=%zu sw->hw->conv_buf.size=%zu\n", live,
+              sw->hw->conv_buf.size);
         return 0;
     }
 
@@ -1026,13 +1026,13 @@ static size_t audio_get_free(SWVoiceOut *sw)
 
     live = sw->total_hw_samples_mixed;
 
-    if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
-        dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
-              sw->hw->mix_buf->size);
+    if (audio_bug(__func__, live > sw->hw->mix_buf.size)) {
+        dolog("live=%zu sw->hw->mix_buf.size=%zu\n", live,
+              sw->hw->mix_buf.size);
         return 0;
     }
 
-    dead = sw->hw->mix_buf->size - live;
+    dead = sw->hw->mix_buf.size - live;
 
 #ifdef DEBUG_OUT
     dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
@@ -1056,12 +1056,12 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
 
             n = samples;
             while (n) {
-                size_t till_end_of_hw = hw->mix_buf->size - rpos2;
+                size_t till_end_of_hw = hw->mix_buf.size - rpos2;
                 size_t to_write = MIN(till_end_of_hw, n);
                 size_t bytes = to_write * hw->info.bytes_per_frame;
                 size_t written;
 
-                sw->buf = hw->mix_buf->samples + rpos2;
+                sw->buf = hw->mix_buf.buffer + rpos2;
                 written = audio_pcm_sw_write (sw, NULL, bytes);
                 if (written - bytes) {
                     dolog("Could not mix %zu bytes into a capture "
@@ -1070,14 +1070,14 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
                     break;
                 }
                 n -= to_write;
-                rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
+                rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
             }
         }
     }
 
-    n = MIN(samples, hw->mix_buf->size - rpos);
-    mixeng_clear(hw->mix_buf->samples + rpos, n);
-    mixeng_clear(hw->mix_buf->samples, samples - n);
+    n = MIN(samples, hw->mix_buf.size - rpos);
+    mixeng_clear(hw->mix_buf.buffer + rpos, n);
+    mixeng_clear(hw->mix_buf.buffer, samples - n);
 }
 
 static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
@@ -1103,7 +1103,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
 
         live -= proc;
         clipped += proc;
-        hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
+        hw->mix_buf.pos = (hw->mix_buf.pos + proc) % hw->mix_buf.size;
 
         if (proc == 0 || proc < decr) {
             break;
@@ -1174,8 +1174,8 @@ static void audio_run_out (AudioState *s)
             live = 0;
         }
 
-        if (audio_bug(__func__, live > hw->mix_buf->size)) {
-            dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
+        if (audio_bug(__func__, live > hw->mix_buf.size)) {
+            dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
             continue;
         }
 
@@ -1203,13 +1203,13 @@ static void audio_run_out (AudioState *s)
             continue;
         }
 
-        prev_rpos = hw->mix_buf->pos;
+        prev_rpos = hw->mix_buf.pos;
         played = audio_pcm_hw_run_out(hw, live);
         replay_audio_out(&played);
-        if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
-            dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
-                  hw->mix_buf->pos, hw->mix_buf->size, played);
-            hw->mix_buf->pos = 0;
+        if (audio_bug(__func__, hw->mix_buf.pos >= hw->mix_buf.size)) {
+            dolog("hw->mix_buf.pos=%zu hw->mix_buf.size=%zu played=%zu\n",
+                  hw->mix_buf.pos, hw->mix_buf.size, played);
+            hw->mix_buf.pos = 0;
         }
 
 #ifdef DEBUG_OUT
@@ -1290,10 +1290,10 @@ static void audio_run_in (AudioState *s)
 
         if (replay_mode != REPLAY_MODE_PLAY) {
             captured = audio_pcm_hw_run_in(
-                hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
+                hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
         }
-        replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
-                        hw->conv_buf->size);
+        replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
+                        hw->conv_buf.size);
 
         min = audio_pcm_hw_find_min_in (hw);
         hw->total_samples_captured += captured - min;
@@ -1326,14 +1326,14 @@ static void audio_run_capture (AudioState *s)
         SWVoiceOut *sw;
 
         captured = live = audio_pcm_hw_get_live_out (hw, NULL);
-        rpos = hw->mix_buf->pos;
+        rpos = hw->mix_buf.pos;
         while (live) {
-            size_t left = hw->mix_buf->size - rpos;
+            size_t left = hw->mix_buf.size - rpos;
             size_t to_capture = MIN(live, left);
             struct st_sample *src;
             struct capture_callback *cb;
 
-            src = hw->mix_buf->samples + rpos;
+            src = hw->mix_buf.buffer + rpos;
             hw->clip (cap->buf, src, to_capture);
             mixeng_clear (src, to_capture);
 
@@ -1341,10 +1341,10 @@ static void audio_run_capture (AudioState *s)
                 cb->ops.capture (cb->opaque, cap->buf,
                                  to_capture * hw->info.bytes_per_frame);
             }
-            rpos = (rpos + to_capture) % hw->mix_buf->size;
+            rpos = (rpos + to_capture) % hw->mix_buf.size;
             live -= to_capture;
         }
-        hw->mix_buf->pos = rpos;
+        hw->mix_buf.pos = rpos;
 
         for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
             if (!sw->active && sw->empty) {
@@ -1903,7 +1903,7 @@ CaptureVoiceOut *AUD_add_capture(
 
         audio_pcm_init_info (&hw->info, as);
 
-        cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
+        cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
 
         if (hw->info.is_float) {
             hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
@@ -1955,7 +1955,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
                     sw = sw1;
                 }
                 QLIST_REMOVE (cap, entries);
-                g_free (cap->hw.mix_buf);
+                g_free(cap->hw.mix_buf.buffer);
                 g_free (cap->buf);
                 g_free (cap);
             }
-- 
2.39.2



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

* [PULL 14/27] audio: change type and name of the resample buffer
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (12 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 13/27] audio: change type of mix_buf and conv_buf marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 15/27] audio: make the resampling code greedy marcandre.lureau
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Change the type of the resample buffer from struct st_sample *
to STSampleBuffer. Also change the name from buf to resample_buf
for better readability.

The new variables resample_buf.size and resample_buf.pos will be
used after the next patches. There is no functional change.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-2-vr_qemu@t-online.de>
---
 audio/audio_int.h      |  4 ++--
 audio/audio_template.h | 10 ++++++----
 audio/audio.c          | 15 ++++++++-------
 3 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 061845dcc2..8b163e1759 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -109,7 +109,7 @@ struct SWVoiceOut {
     struct audio_pcm_info info;
     t_sample *conv;
     int64_t ratio;
-    struct st_sample *buf;
+    STSampleBuffer resample_buf;
     void *rate;
     size_t total_hw_samples_mixed;
     int active;
@@ -129,7 +129,7 @@ struct SWVoiceIn {
     int64_t ratio;
     void *rate;
     size_t total_hw_samples_acquired;
-    struct st_sample *buf;
+    STSampleBuffer resample_buf;
     f_sample *clip;
     HWVoiceIn *hw;
     char *name;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index dd87170cbd..a0b653f52c 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -95,13 +95,13 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
 
 static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 {
-    g_free (sw->buf);
+    g_free(sw->resample_buf.buffer);
+    sw->resample_buf.buffer = NULL;
+    sw->resample_buf.size = 0;
 
     if (sw->rate) {
         st_rate_stop (sw->rate);
     }
-
-    sw->buf = NULL;
     sw->rate = NULL;
 }
 
@@ -138,7 +138,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
         return -1;
     }
 
-    sw->buf = g_new0(st_sample, samples);
+    sw->resample_buf.buffer = g_new0(st_sample, samples);
+    sw->resample_buf.size = samples;
+    sw->resample_buf.pos = 0;
 
 #ifdef DAC
     sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
diff --git a/audio/audio.c b/audio/audio.c
index a0b54e4a2e..a399147486 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -555,7 +555,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
 {
     HWVoiceIn *hw = sw->hw;
     size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
-    struct st_sample *src, *dst = sw->buf;
+    struct st_sample *src, *dst = sw->resample_buf.buffer;
 
     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
     if (!live) {
@@ -595,10 +595,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
     }
 
     if (!hw->pcm_ops->volume_in) {
-        mixeng_volume (sw->buf, ret, &sw->vol);
+        mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
     }
 
-    sw->clip (buf, sw->buf, ret);
+    sw->clip(buf, sw->resample_buf.buffer, ret);
     sw->total_hw_samples_acquired += total;
     return ret * sw->info.bytes_per_frame;
 }
@@ -706,10 +706,10 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
     samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
     samples = MIN(samples, size / sw->info.bytes_per_frame);
     if (samples) {
-        sw->conv(sw->buf, buf, samples);
+        sw->conv(sw->resample_buf.buffer, buf, samples);
 
         if (!sw->hw->pcm_ops->volume_out) {
-            mixeng_volume(sw->buf, samples, &sw->vol);
+            mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
         }
     }
 
@@ -724,7 +724,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         osamp = blck;
         st_rate_flow_mix (
             sw->rate,
-            sw->buf + pos,
+            sw->resample_buf.buffer + pos,
             sw->hw->mix_buf.buffer + wpos,
             &isamp,
             &osamp
@@ -1061,7 +1061,8 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
                 size_t bytes = to_write * hw->info.bytes_per_frame;
                 size_t written;
 
-                sw->buf = hw->mix_buf.buffer + rpos2;
+                sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
+                sw->resample_buf.size = to_write;
                 written = audio_pcm_sw_write (sw, NULL, bytes);
                 if (written - bytes) {
                     dolog("Could not mix %zu bytes into a capture "
-- 
2.39.2



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

* [PULL 15/27] audio: make the resampling code greedy
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (13 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 14/27] audio: change type and name of the resample buffer marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 16/27] audio: replace the resampling loop in audio_pcm_sw_write() marcandre.lureau
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Read the maximum possible number of audio frames instead of the
minimum necessary number of frames when the audio stream is
downsampled and the output buffer is limited. This makes the
function symmetrical to upsampling when the input buffer is
limited. The maximum possible number of frames is written here.

With this change it's easier to calculate the exact number of
audio frames the resample function will read or write. These two
functions will be introduced later.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-3-vr_qemu@t-online.de>
---
 audio/rate_template.h | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/audio/rate_template.h b/audio/rate_template.h
index b432719ebb..6648f0d2e5 100644
--- a/audio/rate_template.h
+++ b/audio/rate_template.h
@@ -40,8 +40,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
     int64_t t;
 #endif
 
-    ilast = rate->ilast;
-
     istart = ibuf;
     iend = ibuf + *isamp;
 
@@ -59,15 +57,17 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
         return;
     }
 
-    while (obuf < oend) {
+    /* without input samples, there's nothing to do */
+    if (ibuf >= iend) {
+        *osamp = 0;
+        return;
+    }
 
-        /* Safety catch to make sure we have input samples.  */
-        if (ibuf >= iend) {
-            break;
-        }
+    ilast = rate->ilast;
 
-        /* read as many input samples so that ipos > opos */
+    while (true) {
 
+        /* read as many input samples so that ipos > opos */
         while (rate->ipos <= (rate->opos >> 32)) {
             ilast = *ibuf++;
             rate->ipos++;
@@ -78,6 +78,11 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
             }
         }
 
+        /* make sure that the next output sample can be written */
+        if (obuf >= oend) {
+            break;
+        }
+
         icur = *ibuf;
 
         /* wrap ipos and opos around long before they overflow */
-- 
2.39.2



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

* [PULL 16/27] audio: replace the resampling loop in audio_pcm_sw_write()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (14 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 15/27] audio: make the resampling code greedy marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 17/27] audio: remove sw == NULL check marcandre.lureau
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Replace the resampling loop in audio_pcm_sw_write() with the new
function audio_pcm_sw_resample_out(). Unlike the old resample
loop the new function will try to consume input frames even if
the output buffer is full. This is necessary when downsampling
to avoid reading less audio frames than calculated in advance.
The loop was unrolled to avoid complicated loop control conditions
in this case.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-4-vr_qemu@t-online.de>
---
 audio/audio.c | 63 +++++++++++++++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 27 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index a399147486..4412b5fad8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -673,11 +673,44 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
 /*
  * Soft voice (playback)
  */
+static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
+    size_t frames_in_max, size_t frames_out_max,
+    size_t *total_in, size_t *total_out)
+{
+    HWVoiceOut *hw = sw->hw;
+    struct st_sample *src, *dst;
+    size_t live, wpos, frames_in, frames_out;
+
+    live = sw->total_hw_samples_mixed;
+    wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
+
+    /* write to mix_buf from wpos to end of buffer */
+    src = sw->resample_buf.buffer;
+    frames_in = frames_in_max;
+    dst = hw->mix_buf.buffer + wpos;
+    frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
+    st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+    wpos += frames_out;
+    *total_in = frames_in;
+    *total_out = frames_out;
+
+    /* write to mix_buf from start of buffer if there are input frames left */
+    if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
+        src += frames_in;
+        frames_in = frames_in_max - frames_in;
+        dst = hw->mix_buf.buffer;
+        frames_out = frames_out_max - frames_out;
+        st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+        *total_in += frames_in;
+        *total_out += frames_out;
+    }
+}
+
 static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
 {
-    size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
+    size_t hwsamples, samples, live, dead;
     size_t hw_free;
-    size_t ret = 0, pos = 0, total = 0;
+    size_t ret, total;
 
     if (!sw) {
         return size;
@@ -698,8 +731,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         return 0;
     }
 
-    wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
-
     dead = hwsamples - live;
     hw_free = audio_pcm_hw_get_free(sw->hw);
     hw_free = hw_free > live ? hw_free - live : 0;
@@ -713,29 +744,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         }
     }
 
-    while (samples) {
-        dead = hwsamples - live;
-        left = hwsamples - wpos;
-        blck = MIN (dead, left);
-        if (!blck) {
-            break;
-        }
-        isamp = samples;
-        osamp = blck;
-        st_rate_flow_mix (
-            sw->rate,
-            sw->resample_buf.buffer + pos,
-            sw->hw->mix_buf.buffer + wpos,
-            &isamp,
-            &osamp
-            );
-        ret += isamp;
-        samples -= isamp;
-        pos += isamp;
-        live += osamp;
-        wpos = (wpos + osamp) % hwsamples;
-        total += osamp;
-    }
+    audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
 
     sw->total_hw_samples_mixed += total;
     sw->empty = sw->total_hw_samples_mixed == 0;
-- 
2.39.2



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

* [PULL 17/27] audio: remove sw == NULL check
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (15 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 16/27] audio: replace the resampling loop in audio_pcm_sw_write() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 18/27] audio: rename variables in audio_pcm_sw_write() marcandre.lureau
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

All call sites of audio_pcm_sw_write() guarantee that sw is not
NULL. Remove the unnecessary NULL check.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-5-vr_qemu@t-online.de>
---
 audio/audio.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 4412b5fad8..8f1c0e77b0 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -712,10 +712,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
     size_t hw_free;
     size_t ret, total;
 
-    if (!sw) {
-        return size;
-    }
-
     hwsamples = sw->hw->mix_buf.size;
 
     live = sw->total_hw_samples_mixed;
-- 
2.39.2



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

* [PULL 18/27] audio: rename variables in audio_pcm_sw_write()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (16 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 17/27] audio: remove sw == NULL check marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 19/27] audio: don't misuse audio_pcm_sw_write() marcandre.lureau
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

The audio_pcm_sw_write() function uses a lot of very unspecific
variable names. Rename them for better readability.

ret => total_in
total => total_out
size => buf_len
hwsamples => hw->mix_buf.size
samples => frames_in_max

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-6-vr_qemu@t-online.de>
---
 audio/audio.c | 45 ++++++++++++++++++++++-----------------------
 1 file changed, 22 insertions(+), 23 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 8f1c0e77b0..cd10f1ec10 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -706,56 +706,55 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
     }
 }
 
-static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
+static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
 {
-    size_t hwsamples, samples, live, dead;
-    size_t hw_free;
-    size_t ret, total;
-
-    hwsamples = sw->hw->mix_buf.size;
+    HWVoiceOut *hw = sw->hw;
+    size_t live, dead, hw_free;
+    size_t frames_in_max, total_in, total_out;
 
     live = sw->total_hw_samples_mixed;
-    if (audio_bug(__func__, live > hwsamples)) {
-        dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
+    if (audio_bug(__func__, live > hw->mix_buf.size)) {
+        dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
         return 0;
     }
 
-    if (live == hwsamples) {
+    if (live == hw->mix_buf.size) {
 #ifdef DEBUG_OUT
         dolog ("%s is full %zu\n", sw->name, live);
 #endif
         return 0;
     }
 
-    dead = hwsamples - live;
-    hw_free = audio_pcm_hw_get_free(sw->hw);
+    dead = hw->mix_buf.size - live;
+    hw_free = audio_pcm_hw_get_free(hw);
     hw_free = hw_free > live ? hw_free - live : 0;
-    samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
-    samples = MIN(samples, size / sw->info.bytes_per_frame);
-    if (samples) {
-        sw->conv(sw->resample_buf.buffer, buf, samples);
+    frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
+    frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
+    if (frames_in_max) {
+        sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
 
         if (!sw->hw->pcm_ops->volume_out) {
-            mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
+            mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
         }
     }
 
-    audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
+    audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
+                              &total_in, &total_out);
 
-    sw->total_hw_samples_mixed += total;
+    sw->total_hw_samples_mixed += total_out;
     sw->empty = sw->total_hw_samples_mixed == 0;
 
 #ifdef DEBUG_OUT
     dolog (
-        "%s: write size %zu ret %zu total sw %zu\n",
-        SW_NAME (sw),
-        size / sw->info.bytes_per_frame,
-        ret,
+        "%s: write size %zu written %zu total mixed %zu\n",
+        SW_NAME(sw),
+        buf_len / sw->info.bytes_per_frame,
+        total_in,
         sw->total_hw_samples_mixed
         );
 #endif
 
-    return ret * sw->info.bytes_per_frame;
+    return total_in * sw->info.bytes_per_frame;
 }
 
 #ifdef DEBUG_AUDIO
-- 
2.39.2



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

* [PULL 19/27] audio: don't misuse audio_pcm_sw_write()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (17 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 18/27] audio: rename variables in audio_pcm_sw_write() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 20/27] audio: remove unused noop_conv() function marcandre.lureau
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

The audio_pcm_sw_write() function is intended to convert a
PCM audio stream to the internal representation, adjust the
volume, and then mix it with the other audio streams with a
possibly changed sample rate in mix_buf. In order for the
audio_capture_mix_and_clear() function to use audio_pcm_sw_write(),
it must bypass the first two tasks of audio_pcm_sw_write().

Since patch "audio: split out the resampling loop in
audio_pcm_sw_write()" this is no longer necessary, because now
the audio_pcm_sw_resample_out() function can be used instead of
audio_pcm_sw_write().

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-7-vr_qemu@t-online.de>
---
 audio/audio.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index cd10f1ec10..44eb7b63b4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1056,26 +1056,33 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
 
         for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
             SWVoiceOut *sw = &sc->sw;
-            int rpos2 = rpos;
+            size_t rpos2 = rpos;
 
             n = samples;
             while (n) {
                 size_t till_end_of_hw = hw->mix_buf.size - rpos2;
-                size_t to_write = MIN(till_end_of_hw, n);
-                size_t bytes = to_write * hw->info.bytes_per_frame;
-                size_t written;
+                size_t to_read = MIN(till_end_of_hw, n);
+                size_t live, frames_in, frames_out;
 
                 sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
-                sw->resample_buf.size = to_write;
-                written = audio_pcm_sw_write (sw, NULL, bytes);
-                if (written - bytes) {
-                    dolog("Could not mix %zu bytes into a capture "
+                sw->resample_buf.size = to_read;
+                live = sw->total_hw_samples_mixed;
+
+                audio_pcm_sw_resample_out(sw,
+                                          to_read, sw->hw->mix_buf.size - live,
+                                          &frames_in, &frames_out);
+
+                sw->total_hw_samples_mixed += frames_out;
+                sw->empty = sw->total_hw_samples_mixed == 0;
+
+                if (to_read - frames_in) {
+                    dolog("Could not mix %zu frames into a capture "
                           "buffer, mixed %zu\n",
-                          bytes, written);
+                          to_read, frames_in);
                     break;
                 }
-                n -= to_write;
-                rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
+                n -= to_read;
+                rpos2 = (rpos2 + to_read) % hw->mix_buf.size;
             }
         }
     }
-- 
2.39.2



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

* [PULL 20/27] audio: remove unused noop_conv() function
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (18 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 19/27] audio: don't misuse audio_pcm_sw_write() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 21/27] audio: make playback packet length calculation exact marcandre.lureau
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

The function audio_capture_mix_and_clear() no longer uses
audio_pcm_sw_write() to resample audio frames from one internal
buffer to another. For this reason, the noop_conv() function is
now unused. Remove it.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-8-vr_qemu@t-online.de>
---
 audio/audio.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 44eb7b63b4..556696b095 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -381,13 +381,6 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
 /*
  * Capture
  */
-static void noop_conv (struct st_sample *dst, const void *src, int samples)
-{
-    (void) src;
-    (void) dst;
-    (void) samples;
-}
-
 static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
                                                         struct audsettings *as)
 {
@@ -485,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
         sw->info = hw->info;
         sw->empty = 1;
         sw->active = hw->enabled;
-        sw->conv = noop_conv;
         sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
         sw->vol = nominal_volume;
         sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
-- 
2.39.2



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

* [PULL 21/27] audio: make playback packet length calculation exact
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (19 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 20/27] audio: remove unused noop_conv() function marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 22/27] audio: replace the resampling loop in audio_pcm_sw_read() marcandre.lureau
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Introduce the new function st_rate_frames_in() to calculate the
exact number of audio input frames needed to get a given number
of audio output frames. The exact number of frames depends only
on the difference of opos - ipos and the number of output frames.
When downsampling, this function returns the maximum number of
input frames needed.

This new function replaces the audio_frontend_frames_out() function,
which calculated the average number of input frames rounded down
to the nearest integer. Because audio_frontend_frames_out() also
limited the number of input frames to the size of the resample
buffer, st_rate_frames_in() is not a direct replacement and two
additional MIN() functions are needed. One to prevent resample
buffer overflows and one to limit the available bytes for the audio
frontends.

After this patch the audio packet length calculation for playback is
exact. When upsampling, it's still possible that the audio frontends
can't write the last audio frame. This will be fixed later.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-9-vr_qemu@t-online.de>
---
 audio/mixeng.h |  1 +
 audio/audio.c  | 43 ++++++++++++++++++-------------------------
 audio/mixeng.c | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 25 deletions(-)

diff --git a/audio/mixeng.h b/audio/mixeng.h
index 2dcd6df245..64c1e231cc 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
 void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
                       size_t *isamp, size_t *osamp);
 void st_rate_stop (void *opaque);
+uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
 void mixeng_clear (struct st_sample *buf, int len);
 void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
 
diff --git a/audio/audio.c b/audio/audio.c
index 556696b095..e18b5e98c5 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -701,8 +701,8 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
 static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
 {
     HWVoiceOut *hw = sw->hw;
-    size_t live, dead, hw_free;
-    size_t frames_in_max, total_in, total_out;
+    size_t live, dead, hw_free, sw_max, fe_max;
+    size_t frames_in_max, frames_out_max, total_in, total_out;
 
     live = sw->total_hw_samples_mixed;
     if (audio_bug(__func__, live > hw->mix_buf.size)) {
@@ -720,17 +720,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
     dead = hw->mix_buf.size - live;
     hw_free = audio_pcm_hw_get_free(hw);
     hw_free = hw_free > live ? hw_free - live : 0;
-    frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
-    frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
-    if (frames_in_max) {
-        sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
+    frames_out_max = MIN(dead, hw_free);
+    sw_max = st_rate_frames_in(sw->rate, frames_out_max);
+    fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
+    frames_in_max = MIN(sw_max, fe_max);
 
-        if (!sw->hw->pcm_ops->volume_out) {
-            mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
-        }
+    if (!frames_in_max) {
+        return 0;
     }
 
-    audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
+    sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
+    if (!sw->hw->pcm_ops->volume_out) {
+        mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
+    }
+
+    audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
                               &total_in, &total_out);
 
     sw->total_hw_samples_mixed += total_out;
@@ -1000,18 +1004,6 @@ static size_t audio_get_avail (SWVoiceIn *sw)
     return live;
 }
 
-/**
- * audio_frontend_frames_out() - returns the number of frames needed to
- * get frames_out frames after resampling
- *
- * @sw: audio playback frontend
- * @frames_out: number of frames
- */
-static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
-{
-    return ((int64_t)frames_out << 32) / sw->ratio;
-}
-
 static size_t audio_get_free(SWVoiceOut *sw)
 {
     size_t live, dead;
@@ -1031,8 +1023,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
     dead = sw->hw->mix_buf.size - live;
 
 #ifdef DEBUG_OUT
-    dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
-          SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
+    dolog("%s: get_free live %zu dead %zu frontend frames %u\n",
+          SW_NAME(sw), live, dead, st_rate_frames_in(sw->rate, dead));
 #endif
 
     return dead;
@@ -1161,12 +1153,13 @@ static void audio_run_out (AudioState *s)
                 size_t free;
 
                 if (hw_free > sw->total_hw_samples_mixed) {
-                    free = audio_frontend_frames_out(sw,
+                    free = st_rate_frames_in(sw->rate,
                         MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
                 } else {
                     free = 0;
                 }
                 if (free > 0) {
+                    free = MIN(free, sw->resample_buf.size);
                     sw->callback.fn(sw->callback.opaque,
                                     free * sw->info.bytes_per_frame);
                 }
diff --git a/audio/mixeng.c b/audio/mixeng.c
index fe454e0725..a24c8c45a7 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -440,6 +440,45 @@ void st_rate_stop (void *opaque)
     g_free (opaque);
 }
 
+/**
+ * st_rate_frames_in() - returns the number of frames needed to
+ * get frames_out frames after resampling
+ *
+ * @opaque: pointer to struct rate
+ * @frames_out: number of frames
+ *
+ * When downsampling, there may be more than one correct result. In this
+ * case, the function returns the maximum number of input frames needed.
+ */
+uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
+{
+    struct rate *rate = opaque;
+    uint64_t opos_start, opos_end;
+    uint32_t ipos_start, ipos_end;
+
+    if (rate->opos_inc == 1ULL << 32) {
+        return frames_out;
+    }
+
+    if (frames_out) {
+        opos_start = rate->opos;
+        ipos_start = rate->ipos;
+    } else {
+        uint64_t offset;
+
+        /* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
+        offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
+        opos_start = rate->opos + offset;
+        ipos_start = rate->ipos + (offset >> 32);
+    }
+    /* last frame written was at opos_start - rate->opos_inc */
+    opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
+    ipos_end = (opos_end >> 32) + 1;
+
+    /* last frame read was at ipos_start - 1 */
+    return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
+}
+
 void mixeng_clear (struct st_sample *buf, int len)
 {
     memset (buf, 0, len * sizeof (struct st_sample));
-- 
2.39.2



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

* [PULL 22/27] audio: replace the resampling loop in audio_pcm_sw_read()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (20 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 21/27] audio: make playback packet length calculation exact marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 23/27] audio: rename variables " marcandre.lureau
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Replace the resampling loop in audio_pcm_sw_read() with the new
function audio_pcm_sw_resample_in(). Unlike the old resample
loop the new function will try to consume input frames even if
the output buffer is full. This is necessary when downsampling
to avoid reading less audio frames than calculated in advance.
The loop was unrolled to avoid complicated loop control conditions
in this case.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-10-vr_qemu@t-online.de>
---
 audio/audio.c | 59 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index e18b5e98c5..9e9c03a42e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -543,11 +543,43 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
 /*
  * Soft voice (capture)
  */
+static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
+    size_t frames_in_max, size_t frames_out_max,
+    size_t *total_in, size_t *total_out)
+{
+    HWVoiceIn *hw = sw->hw;
+    struct st_sample *src, *dst;
+    size_t live, rpos, frames_in, frames_out;
+
+    live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
+
+    /* resample conv_buf from rpos to end of buffer */
+    src = hw->conv_buf.buffer + rpos;
+    frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
+    dst = sw->resample_buf.buffer;
+    frames_out = frames_out_max;
+    st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+    rpos += frames_in;
+    *total_in = frames_in;
+    *total_out = frames_out;
+
+    /* resample conv_buf from start of buffer if there are input frames left */
+    if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
+        src = hw->conv_buf.buffer;
+        frames_in = frames_in_max - frames_in;
+        dst += frames_out;
+        frames_out = frames_out_max - frames_out;
+        st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+        *total_in += frames_in;
+        *total_out += frames_out;
+    }
+}
+
 static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
 {
     HWVoiceIn *hw = sw->hw;
-    size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
-    struct st_sample *src, *dst = sw->resample_buf.buffer;
+    size_t samples, live, ret, swlim, total;
 
     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
     if (!live) {
@@ -558,33 +590,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
         return 0;
     }
 
-    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
-
     samples = size / sw->info.bytes_per_frame;
 
     swlim = (live * sw->ratio) >> 32;
     swlim = MIN (swlim, samples);
 
-    while (swlim) {
-        src = hw->conv_buf.buffer + rpos;
-        if (hw->conv_buf.pos > rpos) {
-            isamp = hw->conv_buf.pos - rpos;
-        } else {
-            isamp = hw->conv_buf.size - rpos;
-        }
-
-        if (!isamp) {
-            break;
-        }
-        osamp = swlim;
-
-        st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
-        swlim -= osamp;
-        rpos = (rpos + isamp) % hw->conv_buf.size;
-        dst += osamp;
-        ret += osamp;
-        total += isamp;
-    }
+    audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
 
     if (!hw->pcm_ops->volume_in) {
         mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
-- 
2.39.2



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

* [PULL 23/27] audio: rename variables in audio_pcm_sw_read()
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (21 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 22/27] audio: replace the resampling loop in audio_pcm_sw_read() marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:51 ` [PULL 24/27] audio: make recording packet length calculation exact marcandre.lureau
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

The audio_pcm_sw_read() function uses a few very unspecific
variable names. Rename them for better readability.

ret => total_out
total => total_in
size => buf_len
samples => frames_out_max

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-11-vr_qemu@t-online.de>
---
 audio/audio.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 9e9c03a42e..22c36d6660 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -576,10 +576,10 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
     }
 }
 
-static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
+static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
 {
     HWVoiceIn *hw = sw->hw;
-    size_t samples, live, ret, swlim, total;
+    size_t live, frames_out_max, swlim, total_in, total_out;
 
     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
     if (!live) {
@@ -590,20 +590,20 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
         return 0;
     }
 
-    samples = size / sw->info.bytes_per_frame;
+    frames_out_max = buf_len / sw->info.bytes_per_frame;
 
     swlim = (live * sw->ratio) >> 32;
-    swlim = MIN (swlim, samples);
+    swlim = MIN(swlim, frames_out_max);
 
-    audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
+    audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
 
     if (!hw->pcm_ops->volume_in) {
-        mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
+        mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
     }
+    sw->clip(buf, sw->resample_buf.buffer, total_out);
 
-    sw->clip(buf, sw->resample_buf.buffer, ret);
-    sw->total_hw_samples_acquired += total;
-    return ret * sw->info.bytes_per_frame;
+    sw->total_hw_samples_acquired += total_in;
+    return total_out * sw->info.bytes_per_frame;
 }
 
 /*
-- 
2.39.2



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

* [PULL 24/27] audio: make recording packet length calculation exact
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (22 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 23/27] audio: rename variables " marcandre.lureau
@ 2023-03-06  6:51 ` marcandre.lureau
  2023-03-06  6:52 ` [PULL 25/27] audio: handle leftover audio frame from upsampling marcandre.lureau
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Introduce the new function st_rate_frames_out() to calculate the
exact number of audio output frames the resampling code can
generate from a given number of audio input frames. When upsampling,
this function returns the maximum number of output frames.

This new function replaces the audio_frontend_frames_in()
function, which calculated the average number of output frames
rounded down to the nearest integer. The audio_frontend_frames_in()
function was additionally used to limit the number of output frames
to the resample buffer size. In audio_pcm_sw_read() the variable
resample_buf.size replaces the open coded audio_frontend_frames_in()
function. In audio_run_in() an additional MIN() function is
necessary.

After this patch the audio packet length calculation for audio
recording is exact.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-12-vr_qemu@t-online.de>
---
 audio/mixeng.h |  1 +
 audio/audio.c  | 29 ++++++++---------------------
 audio/mixeng.c | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/audio/mixeng.h b/audio/mixeng.h
index 64c1e231cc..f9de7cffeb 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
 void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
                       size_t *isamp, size_t *osamp);
 void st_rate_stop (void *opaque);
+uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in);
 uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
 void mixeng_clear (struct st_sample *buf, int len);
 void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
diff --git a/audio/audio.c b/audio/audio.c
index 22c36d6660..dad17e59b8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -579,7 +579,7 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
 static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
 {
     HWVoiceIn *hw = sw->hw;
-    size_t live, frames_out_max, swlim, total_in, total_out;
+    size_t live, frames_out_max, total_in, total_out;
 
     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
     if (!live) {
@@ -590,12 +590,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
         return 0;
     }
 
-    frames_out_max = buf_len / sw->info.bytes_per_frame;
+    frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
+                         sw->resample_buf.size);
 
-    swlim = (live * sw->ratio) >> 32;
-    swlim = MIN(swlim, frames_out_max);
-
-    audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
+    audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
 
     if (!hw->pcm_ops->volume_in) {
         mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
@@ -979,18 +977,6 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
     }
 }
 
-/**
- * audio_frontend_frames_in() - returns the number of frames the resampling
- * code generates from frames_in frames
- *
- * @sw: audio recording frontend
- * @frames_in: number of frames
- */
-static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
-{
-    return (int64_t)frames_in * sw->ratio >> 32;
-}
-
 static size_t audio_get_avail (SWVoiceIn *sw)
 {
     size_t live;
@@ -1007,9 +993,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
     }
 
     ldebug (
-        "%s: get_avail live %zu frontend frames %zu\n",
+        "%s: get_avail live %zu frontend frames %u\n",
         SW_NAME (sw),
-        live, audio_frontend_frames_in(sw, live)
+        live, st_rate_frames_out(sw->rate, live)
         );
 
     return live;
@@ -1314,8 +1300,9 @@ static void audio_run_in (AudioState *s)
                 size_t sw_avail = audio_get_avail(sw);
                 size_t avail;
 
-                avail = audio_frontend_frames_in(sw, sw_avail);
+                avail = st_rate_frames_out(sw->rate, sw_avail);
                 if (avail > 0) {
+                    avail = MIN(avail, sw->resample_buf.size);
                     sw->callback.fn(sw->callback.opaque,
                                     avail * sw->info.bytes_per_frame);
                 }
diff --git a/audio/mixeng.c b/audio/mixeng.c
index a24c8c45a7..69f6549224 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -440,6 +440,47 @@ void st_rate_stop (void *opaque)
     g_free (opaque);
 }
 
+/**
+ * st_rate_frames_out() - returns the number of frames the resampling code
+ * generates from frames_in frames
+ *
+ * @opaque: pointer to struct rate
+ * @frames_in: number of frames
+ *
+ * When upsampling, there may be more than one correct result. In this case,
+ * the function returns the maximum number of output frames the resampling
+ * code can generate.
+ */
+uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
+{
+    struct rate *rate = opaque;
+    uint64_t opos_end, opos_delta;
+    uint32_t ipos_end;
+    uint32_t frames_out;
+
+    if (rate->opos_inc == 1ULL << 32) {
+        return frames_in;
+    }
+
+    /* no output frame without at least one input frame */
+    if (!frames_in) {
+        return 0;
+    }
+
+    /* last frame read was at rate->ipos - 1 */
+    ipos_end = rate->ipos - 1 + frames_in;
+    opos_end = (uint64_t)ipos_end << 32;
+
+    /* last frame written was at rate->opos - rate->opos_inc */
+    if (opos_end + rate->opos_inc <= rate->opos) {
+        return 0;
+    }
+    opos_delta = opos_end - rate->opos + rate->opos_inc;
+    frames_out = opos_delta / rate->opos_inc;
+
+    return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
+}
+
 /**
  * st_rate_frames_in() - returns the number of frames needed to
  * get frames_out frames after resampling
-- 
2.39.2



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

* [PULL 25/27] audio: handle leftover audio frame from upsampling
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (23 preceding siblings ...)
  2023-03-06  6:51 ` [PULL 24/27] audio: make recording packet length calculation exact marcandre.lureau
@ 2023-03-06  6:52 ` marcandre.lureau
  2023-03-06  6:52 ` [PULL 26/27] audio/audio_template: substitute sw->hw with hw marcandre.lureau
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Upsampling may leave one remaining audio frame in the input
buffer. The emulated audio playback devices are currently
resposible to write this audio frame again in the next write
cycle. Push that task down to audio_pcm_sw_write.

This is another step towards an audio callback interface that
guarantees that when audio frontends are told they can write
n audio frames, they can actually do so.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-13-vr_qemu@t-online.de>
---
 audio/audio_template.h |  6 ++++++
 audio/audio.c          | 34 ++++++++++++++++++++++++++++------
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index a0b653f52c..0d8aab6fad 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -138,6 +138,12 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
         return -1;
     }
 
+    /*
+     * Allocate one additional audio frame that is needed for upsampling
+     * if the resample buffer size is small. For large buffer sizes take
+     * care of overflows.
+     */
+    samples = samples < INT_MAX ? samples + 1 : INT_MAX;
     sw->resample_buf.buffer = g_new0(st_sample, samples);
     sw->resample_buf.size = samples;
     sw->resample_buf.pos = 0;
diff --git a/audio/audio.c b/audio/audio.c
index dad17e59b8..4836ab8ca8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -731,16 +731,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
     hw_free = hw_free > live ? hw_free - live : 0;
     frames_out_max = MIN(dead, hw_free);
     sw_max = st_rate_frames_in(sw->rate, frames_out_max);
-    fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
+    fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
+                 sw->resample_buf.size);
     frames_in_max = MIN(sw_max, fe_max);
 
     if (!frames_in_max) {
         return 0;
     }
 
-    sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
-    if (!sw->hw->pcm_ops->volume_out) {
-        mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
+    if (frames_in_max > sw->resample_buf.pos) {
+        sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
+                 buf, frames_in_max - sw->resample_buf.pos);
+        if (!sw->hw->pcm_ops->volume_out) {
+            mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
+                          frames_in_max - sw->resample_buf.pos, &sw->vol);
+        }
     }
 
     audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
@@ -749,6 +754,22 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
     sw->total_hw_samples_mixed += total_out;
     sw->empty = sw->total_hw_samples_mixed == 0;
 
+    /*
+     * Upsampling may leave one audio frame in the resample buffer. Decrement
+     * total_in by one if there was a leftover frame from the previous resample
+     * pass in the resample buffer. Increment total_in by one if the current
+     * resample pass left one frame in the resample buffer.
+     */
+    if (frames_in_max - total_in == 1) {
+        /* copy one leftover audio frame to the beginning of the buffer */
+        *sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
+        total_in += 1 - sw->resample_buf.pos;
+        sw->resample_buf.pos = 1;
+    } else if (total_in >= sw->resample_buf.pos) {
+        total_in -= sw->resample_buf.pos;
+        sw->resample_buf.pos = 0;
+    }
+
 #ifdef DEBUG_OUT
     dolog (
         "%s: write size %zu written %zu total mixed %zu\n",
@@ -1155,8 +1176,9 @@ static void audio_run_out (AudioState *s)
                 } else {
                     free = 0;
                 }
-                if (free > 0) {
-                    free = MIN(free, sw->resample_buf.size);
+                if (free > sw->resample_buf.pos) {
+                    free = MIN(free, sw->resample_buf.size)
+                           - sw->resample_buf.pos;
                     sw->callback.fn(sw->callback.opaque,
                                     free * sw->info.bytes_per_frame);
                 }
-- 
2.39.2



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

* [PULL 26/27] audio/audio_template: substitute sw->hw with hw
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (24 preceding siblings ...)
  2023-03-06  6:52 ` [PULL 25/27] audio: handle leftover audio frame from upsampling marcandre.lureau
@ 2023-03-06  6:52 ` marcandre.lureau
  2023-03-06  6:52 ` [PULL 27/27] audio: remove sw->ratio marcandre.lureau
  2023-03-06 18:21 ` [PULL 00/27] Audio patches Peter Maydell
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Substitute sw->hw with hw in the audio_pcm_sw_alloc_resources_*
functions.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-14-vr_qemu@t-online.de>
---
 audio/audio_template.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 0d8aab6fad..7e116426c7 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -107,6 +107,7 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 
 static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 {
+    HW *hw = sw->hw;
     int samples;
 
     if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
@@ -125,7 +126,6 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
     }
 
     if (samples == 0) {
-        HW *hw = sw->hw;
         size_t f_fe_min;
 
         /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
@@ -149,9 +149,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
     sw->resample_buf.pos = 0;
 
 #ifdef DAC
-    sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
+    sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
 #else
-    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
+    sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
 #endif
 
     return 0;
-- 
2.39.2



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

* [PULL 27/27] audio: remove sw->ratio
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (25 preceding siblings ...)
  2023-03-06  6:52 ` [PULL 26/27] audio/audio_template: substitute sw->hw with hw marcandre.lureau
@ 2023-03-06  6:52 ` marcandre.lureau
  2023-03-06 18:21 ` [PULL 00/27] Audio patches Peter Maydell
  27 siblings, 0 replies; 29+ messages in thread
From: marcandre.lureau @ 2023-03-06  6:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Gerd Hoffmann, Marc-André Lureau, Christian Schoenebeck,
	Volker Rümelin

From: Volker Rümelin <vr_qemu@t-online.de>

Simplify the resample buffer size calculation.

For audio playback we have
sw->ratio = ((int64_t)sw->hw->info.freq << 32) / sw->info.freq;
samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;

This can be simplified to
samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);

For audio recording we have
sw->ratio = ((int64_t)sw->info.freq << 32) / sw->hw->info.freq;
samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;

This can be simplified to
samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);

With hw = sw->hw this becomes in both cases
samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);

Now that sw->ratio is no longer needed, remove sw->ratio.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Message-Id: <20230224190555.7409-15-vr_qemu@t-online.de>
---
 audio/audio_int.h      |  2 --
 audio/audio_template.h | 30 +++++++++---------------------
 audio/audio.c          |  1 -
 3 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 8b163e1759..d51d63f08d 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -108,7 +108,6 @@ struct SWVoiceOut {
     AudioState *s;
     struct audio_pcm_info info;
     t_sample *conv;
-    int64_t ratio;
     STSampleBuffer resample_buf;
     void *rate;
     size_t total_hw_samples_mixed;
@@ -126,7 +125,6 @@ struct SWVoiceIn {
     AudioState *s;
     int active;
     struct audio_pcm_info info;
-    int64_t ratio;
     void *rate;
     size_t total_hw_samples_acquired;
     STSampleBuffer resample_buf;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7e116426c7..e42326c20d 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -108,32 +108,23 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
 static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
 {
     HW *hw = sw->hw;
-    int samples;
+    uint64_t samples;
 
     if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
         return 0;
     }
 
-#ifdef DAC
-    samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
-#else
-    samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
-#endif
-    if (audio_bug(__func__, samples < 0)) {
-        dolog("Can not allocate buffer for `%s' (%d samples)\n",
-              SW_NAME(sw), samples);
-        return -1;
-    }
-
+    samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
     if (samples == 0) {
-        size_t f_fe_min;
+        uint64_t f_fe_min;
+        uint64_t f_be = (uint32_t)hw->info.freq;
 
         /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
-        f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
+        f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
         qemu_log_mask(LOG_UNIMP,
                       AUDIO_CAP ": The guest selected a " NAME " sample rate"
-                      " of %d Hz for %s. Only sample rates >= %zu Hz are"
-                      " supported.\n",
+                      " of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
+                      " are supported.\n",
                       sw->info.freq, sw->name, f_fe_min);
         return -1;
     }
@@ -141,9 +132,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
     /*
      * Allocate one additional audio frame that is needed for upsampling
      * if the resample buffer size is small. For large buffer sizes take
-     * care of overflows.
+     * care of overflows and truncation.
      */
-    samples = samples < INT_MAX ? samples + 1 : INT_MAX;
+    samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
     sw->resample_buf.buffer = g_new0(st_sample, samples);
     sw->resample_buf.size = samples;
     sw->resample_buf.pos = 0;
@@ -170,11 +161,8 @@ static int glue (audio_pcm_sw_init_, TYPE) (
     sw->hw = hw;
     sw->active = 0;
 #ifdef DAC
-    sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
     sw->total_hw_samples_mixed = 0;
     sw->empty = 1;
-#else
-    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
 #endif
 
     if (sw->info.is_float) {
diff --git a/audio/audio.c b/audio/audio.c
index 4836ab8ca8..70b096713c 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -478,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
         sw->info = hw->info;
         sw->empty = 1;
         sw->active = hw->enabled;
-        sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
         sw->vol = nominal_volume;
         sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
         QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
-- 
2.39.2



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

* Re: [PULL 00/27] Audio patches
  2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
                   ` (26 preceding siblings ...)
  2023-03-06  6:52 ` [PULL 27/27] audio: remove sw->ratio marcandre.lureau
@ 2023-03-06 18:21 ` Peter Maydell
  27 siblings, 0 replies; 29+ messages in thread
From: Peter Maydell @ 2023-03-06 18:21 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: qemu-devel, Gerd Hoffmann, Christian Schoenebeck

On Mon, 6 Mar 2023 at 06:52, <marcandre.lureau@redhat.com> wrote:
>
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> The following changes since commit 2946e1af2704bf6584f57d4e3aec49d1d5f3ecc0:
>
>   configure: Disable thread-safety warnings on macOS (2023-03-04 14:03:46 +0000)
>
> are available in the Git repository at:
>
>   https://gitlab.com/marcandre.lureau/qemu.git tags/audio-pull-request
>
> for you to fetch changes up to 2f886a34bb7e6f6fcf39d64829f4499476f26dba:
>
>   audio: remove sw->ratio (2023-03-06 10:30:24 +0400)
>
> ----------------------------------------------------------------
> Audio patches for QEMU 8.0
>
> Cleanups and improvements from Volker Rümelin.


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/8.0
for any user-visible changes.

-- PMM


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

end of thread, other threads:[~2023-03-06 18:22 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-06  6:51 [PULL 00/27] Audio patches marcandre.lureau
2023-03-06  6:51 ` [PULL 01/27] MAINTAINERS: add myself to ui/ and audio/ marcandre.lureau
2023-03-06  6:51 ` [PULL 02/27] audio: log unimplemented audio device sample rates marcandre.lureau
2023-03-06  6:51 ` [PULL 03/27] audio: don't show unnecessary error messages marcandre.lureau
2023-03-06  6:51 ` [PULL 04/27] audio: rename hardware store to backend marcandre.lureau
2023-03-06  6:51 ` [PULL 05/27] audio: remove unused #define AUDIO_STRINGIFY marcandre.lureau
2023-03-06  6:51 ` [PULL 06/27] audio/mixeng: use g_new0() instead of audio_calloc() marcandre.lureau
2023-03-06  6:51 ` [PULL 07/27] audio/alsaaudio: " marcandre.lureau
2023-03-06  6:51 ` [PULL 08/27] audio/audio_template: use g_malloc0() to replace audio_calloc() marcandre.lureau
2023-03-06  6:51 ` [PULL 09/27] audio/audio_template: use g_new0() " marcandre.lureau
2023-03-06  6:51 ` [PULL 10/27] audio: remove audio_calloc() function marcandre.lureau
2023-03-06  6:51 ` [PULL 11/27] alsaaudio: change default playback settings marcandre.lureau
2023-03-06  6:51 ` [PULL 12/27] alsaaudio: reintroduce default recording settings marcandre.lureau
2023-03-06  6:51 ` [PULL 13/27] audio: change type of mix_buf and conv_buf marcandre.lureau
2023-03-06  6:51 ` [PULL 14/27] audio: change type and name of the resample buffer marcandre.lureau
2023-03-06  6:51 ` [PULL 15/27] audio: make the resampling code greedy marcandre.lureau
2023-03-06  6:51 ` [PULL 16/27] audio: replace the resampling loop in audio_pcm_sw_write() marcandre.lureau
2023-03-06  6:51 ` [PULL 17/27] audio: remove sw == NULL check marcandre.lureau
2023-03-06  6:51 ` [PULL 18/27] audio: rename variables in audio_pcm_sw_write() marcandre.lureau
2023-03-06  6:51 ` [PULL 19/27] audio: don't misuse audio_pcm_sw_write() marcandre.lureau
2023-03-06  6:51 ` [PULL 20/27] audio: remove unused noop_conv() function marcandre.lureau
2023-03-06  6:51 ` [PULL 21/27] audio: make playback packet length calculation exact marcandre.lureau
2023-03-06  6:51 ` [PULL 22/27] audio: replace the resampling loop in audio_pcm_sw_read() marcandre.lureau
2023-03-06  6:51 ` [PULL 23/27] audio: rename variables " marcandre.lureau
2023-03-06  6:51 ` [PULL 24/27] audio: make recording packet length calculation exact marcandre.lureau
2023-03-06  6:52 ` [PULL 25/27] audio: handle leftover audio frame from upsampling marcandre.lureau
2023-03-06  6:52 ` [PULL 26/27] audio/audio_template: substitute sw->hw with hw marcandre.lureau
2023-03-06  6:52 ` [PULL 27/27] audio: remove sw->ratio marcandre.lureau
2023-03-06 18:21 ` [PULL 00/27] Audio patches Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.