All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Kővágó, Zoltán" <dirty.ice.hu@gmail.com>
To: qemu-devel@nongnu.org
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH v2 28/52] audio: api for mixeng code free backends
Date: Sun, 23 Dec 2018 21:52:04 +0100	[thread overview]
Message-ID: <59bee9fad02c04c6600eba20dafb0c4cd1b31007.1545598229.git.DirtY.iCE.hu@gmail.com> (raw)
In-Reply-To: <cover.1545598229.git.DirtY.iCE.hu@gmail.com>

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
---
 audio/audio.c          | 211 ++++++++++++++++++++++++++++++++++++++++-
 audio/audio_int.h      |  45 +++++++--
 audio/audio_template.h |   1 +
 3 files changed, 247 insertions(+), 10 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 27a8a31a64..1897e22444 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -575,6 +575,25 @@ size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
     return clipped;
 }
 
+static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t len)
+{
+    size_t clipped = 0;
+    size_t pos = hw->rpos;
+
+    while (len) {
+        st_sample *src = hw->mix_buf + pos;
+        uint8_t *dst = advance (pcm_buf, clipped << hw->info.shift);
+        size_t samples_till_end_of_buf = hw->samples - 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->samples;
+        len -= samples_to_clip;
+        clipped += samples_to_clip;
+    }
+}
+
 /*
  * Soft voice (capture)
  */
@@ -1052,6 +1071,31 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
     mixeng_clear(hw->mix_buf, samples - n);
 }
 
+static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
+{
+    size_t clipped = 0;
+
+    while (live) {
+        size_t size, decr, proc;
+        void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
+
+        decr = MIN(size >> hw->info.shift, live);
+        audio_pcm_hw_clip_out2(hw, buf, decr);
+        proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >>
+            hw->info.shift;
+
+        live -= proc;
+        clipped += proc;
+        hw->rpos = (hw->rpos + proc) % hw->samples;
+
+        if (proc == 0 || proc < decr) {
+            break;
+        }
+    }
+
+    return clipped;
+}
+
 static void audio_run_out (AudioState *s)
 {
     HWVoiceOut *hw = NULL;
@@ -1099,7 +1143,11 @@ static void audio_run_out (AudioState *s)
         }
 
         prev_rpos = hw->rpos;
-        played = hw->pcm_ops->run_out (hw, live);
+        if (hw->pcm_ops->run_out) {
+            played = hw->pcm_ops->run_out(hw, live);
+        } else {
+            played = audio_pcm_hw_run_out(hw, live);
+        }
         replay_audio_out(&played);
         if (audio_bug(__func__, hw->rpos >= hw->samples)) {
             dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
@@ -1158,6 +1206,35 @@ static void audio_run_out (AudioState *s)
     }
 }
 
+static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
+{
+    size_t conv = 0;
+
+    while (samples) {
+        size_t proc;
+        size_t size = samples << hw->info.shift;
+        void *buf = hw->pcm_ops->get_buffer_in(hw, &size);
+
+        assert((size & hw->info.align) == 0);
+        if (size == 0) {
+            hw->pcm_ops->put_buffer_in(hw, buf, size);
+            break;
+        }
+
+        proc = MIN(size >> hw->info.shift,
+                   hw->samples - hw->wpos);
+
+        hw->conv(hw->conv_buf + hw->wpos, buf, proc);
+        hw->wpos = (hw->wpos + proc) % hw->samples;
+
+        samples -= proc;
+        conv += proc;
+        hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift);
+    }
+
+    return conv;
+}
+
 static void audio_run_in (AudioState *s)
 {
     HWVoiceIn *hw = NULL;
@@ -1167,7 +1244,12 @@ static void audio_run_in (AudioState *s)
         size_t captured = 0, min;
 
         if (replay_mode != REPLAY_MODE_PLAY) {
-            captured = hw->pcm_ops->run_in(hw);
+            if (hw->pcm_ops->run_in) {
+                captured = hw->pcm_ops->run_in(hw);
+            } else {
+                captured = audio_pcm_hw_run_in(
+                    hw, hw->samples - audio_pcm_hw_get_live_in(hw));
+            }
         }
         replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples);
 
@@ -1261,12 +1343,137 @@ void audio_run(AudioState *s, const char *msg)
 #endif
 }
 
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
+{
+    ssize_t start;
+
+    if (unlikely(!hw->buf_emul)) {
+        size_t calc_size = hw->samples << hw->info.shift;
+        hw->buf_emul = g_malloc(calc_size);
+        hw->size_emul = calc_size;
+        hw->pos_emul = hw->pending_emul = 0;
+    }
+
+    while (hw->pending_emul < hw->size_emul) {
+        size_t read_len = MIN(hw->size_emul - hw->pos_emul,
+                              hw->size_emul - hw->pending_emul);
+        size_t read = hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul,
+                                        read_len);
+        hw->pending_emul += read;
+        if (read < read_len) {
+            break;
+        }
+    }
+
+    start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+    if (start < 0) {
+        start += hw->size_emul;
+    }
+    assert(start >= 0 && start < hw->size_emul);
+
+    *size = MIN(hw->pending_emul, hw->size_emul - start);
+    return hw->buf_emul + start;
+}
+
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
+{
+    assert(size <= hw->pending_emul);
+    hw->pending_emul -= size;
+}
+
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+    if (unlikely(!hw->buf_emul)) {
+        size_t calc_size = hw->samples << hw->info.shift;
+
+        hw->buf_emul = g_malloc(calc_size);
+        hw->size_emul = calc_size;
+        hw->pos_emul = hw->pending_emul = 0;
+    }
+
+    *size = MIN(hw->size_emul - hw->pending_emul,
+                hw->size_emul - hw->pos_emul);
+    return hw->buf_emul + hw->pos_emul;
+}
+
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+                                            size_t size)
+{
+    assert(buf == hw->buf_emul + hw->pos_emul &&
+           size + hw->pending_emul <= hw->size_emul);
+
+    hw->pending_emul += size;
+    hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
+
+    return size;
+}
+
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+    audio_generic_put_buffer_out_nowrite(hw, buf, size);
+
+    while (hw->pending_emul) {
+        size_t write_len, written;
+        ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+        if (start < 0) {
+            start += hw->size_emul;
+        }
+        assert(start >= 0 && start < hw->size_emul);
+
+        write_len = MIN(hw->pending_emul, hw->size_emul - start);
+
+        written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
+        hw->pending_emul -= written;
+
+        if (written < write_len) {
+            break;
+        }
+    }
+
+    /*
+     * fake we have written everything. non-written data remain in pending_emul,
+     * so we do not have to clip them multiple times
+     */
+    return size;
+}
+
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
+{
+    size_t dst_size, copy_size;
+    void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
+    copy_size = MIN(size, dst_size);
+
+    memcpy(dst, buf, copy_size);
+    return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
+}
+
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
+{
+    size_t dst_size, copy_size;
+    void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
+    copy_size = MIN(size, dst_size);
+
+    memcpy(dst, buf, copy_size);
+    hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
+    return copy_size;
+}
+
+
 static int audio_driver_init(AudioState *s, struct audio_driver *drv,
                              Audiodev *dev)
 {
     s->drv_opaque = drv->init(dev);
 
     if (s->drv_opaque) {
+        if (!drv->pcm_ops->get_buffer_in) {
+            drv->pcm_ops->get_buffer_in = audio_generic_get_buffer_in;
+            drv->pcm_ops->put_buffer_in = audio_generic_put_buffer_in;
+        }
+        if (!drv->pcm_ops->get_buffer_out) {
+            drv->pcm_ops->get_buffer_out = audio_generic_get_buffer_out;
+            drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out;
+        }
+
         audio_init_nb_voices_out(s, drv);
         audio_init_nb_voices_in(s, drv);
         s->drv = drv;
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 330c465d0b..5c361d9451 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -64,6 +64,8 @@ typedef struct HWVoiceOut {
     uint64_t ts_helper;
 
     struct st_sample *mix_buf;
+    void *buf_emul;
+    size_t pos_emul, pending_emul, size_emul;
 
     size_t samples;
     QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
@@ -86,6 +88,8 @@ typedef struct HWVoiceIn {
     uint64_t ts_helper;
 
     struct st_sample *conv_buf;
+    void *buf_emul;
+    size_t pos_emul, pending_emul, size_emul;
 
     size_t samples;
     QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
@@ -146,17 +150,42 @@ struct audio_driver {
 };
 
 struct audio_pcm_ops {
-    int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
-    void (*fini_out)(HWVoiceOut *hw);
-    int  (*run_out) (HWVoiceOut *hw, int live);
-    int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+    int    (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
+    void   (*fini_out)(HWVoiceOut *hw);
+    int    (*run_out) (HWVoiceOut *hw, int live);
+    size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
+    /*
+     * get a buffer that after later can be passed to put_buffer_out; optional
+     * returns the buffer, and writes it's size to size (in bytes)
+     * this is unrelated to the above buffer_size_out function
+     */
+    void  *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
+    /*
+     * put back the buffer returned by get_buffer_out; optional
+     * buf must be equal the pointer returned by get_buffer_out,
+     * size may be smaller
+     */
+    size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
+    int    (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
-    int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
-    void (*fini_in) (HWVoiceIn *hw);
-    int  (*run_in)  (HWVoiceIn *hw);
-    int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
+    int    (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
+    void   (*fini_in) (HWVoiceIn *hw);
+    int    (*run_in)  (HWVoiceIn *hw);
+    size_t (*read)    (HWVoiceIn *hw, void *buf, size_t size);
+    void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
+    void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
+    int    (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+                                            size_t size);
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
+
 struct capture_callback {
     struct audio_capture_ops ops;
     void *opaque;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index fecbf1a046..33cdb66d7f 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,6 +71,7 @@ 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;
 }
-- 
2.20.1

  parent reply	other threads:[~2018-12-23 20:53 UTC|newest]

Thread overview: 78+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-23 20:51 [Qemu-devel] [PATCH v2 00/52] Audio 5.1 patches Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 01/52] qapi: support alternates in OptsVisitor Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 02/52] qapi: support nested structs " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 03/52] qapi: qapi for audio backends Kővágó, Zoltán
2019-01-10  2:49   ` Eric Blake
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 04/52] audio: use qapi AudioFormat instead of audfmt_e Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 05/52] audio: -audiodev command line option: documentation Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 06/52] audio: -audiodev command line option basic implementation Kővágó, Zoltán
2019-01-07 13:13   ` Markus Armbruster
2019-01-07 20:48     ` Zoltán Kővágó
2019-01-08  3:42       ` Markus Armbruster
2019-01-10  0:13         ` Zoltán Kővágó
2019-01-10  7:25           ` Gerd Hoffmann
2019-01-10  9:40             ` Zoltán Kővágó
2019-01-10 10:37               ` Gerd Hoffmann
2019-01-08  6:06       ` Gerd Hoffmann
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 07/52] alsaaudio: port to -audiodev config Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 08/52] coreaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 09/52] dsoundaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 10/52] noaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 11/52] ossaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 12/52] paaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 13/52] sdlaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 14/52] spiceaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 15/52] wavaudio: " Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 16/52] audio: -audiodev command line option: cleanup Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 17/52] audio: reduce glob_audio_state usage Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 18/52] audio: basic support for multi backend audio Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 19/52] audio: add audiodev properties to frontends Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 20/52] audio: audiodev= parameters no longer optional when -audiodev present Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 21/52] paaudio: do not move stream when sink/source name is specified Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 22/52] paaudio: properly disconnect streams in fini_* Kővágó, Zoltán
2018-12-23 20:51 ` [Qemu-devel] [PATCH v2 23/52] audio: remove audio_MIN, audio_MAX Kővágó, Zoltán
2018-12-23 23:49   ` Philippe Mathieu-Daudé
2018-12-24  2:16     ` Zoltán Kővágó
2018-12-24 17:16       ` Philippe Mathieu-Daudé
2018-12-24 20:48         ` Kővágó Zoltán
2018-12-25 10:40           ` Philippe Mathieu-Daudé
2018-12-27 12:49             ` Kővágó Zoltán
2019-01-07  9:54               ` Gerd Hoffmann
2019-01-07 14:26                 ` Eric Blake
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 24/52] audio: do not run each backend in audio_run Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 25/52] paaudio: fix playback glitches Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 26/52] audio: remove read and write pcm_ops Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 27/52] audio: use size_t where makes sense Kővágó, Zoltán
2018-12-24  6:19   ` Pavel Dovgalyuk
2018-12-25 11:08   ` Philippe Mathieu-Daudé
2019-01-07  9:58     ` Gerd Hoffmann
2018-12-23 20:52 ` Kővágó, Zoltán [this message]
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 29/52] alsaaudio: port to the new audio backend api Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 30/52] coreaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 31/52] dsoundaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 32/52] noaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 33/52] ossaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 34/52] paaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 35/52] sdlaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 36/52] spiceaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 37/52] wavaudio: " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 38/52] audio: remove remains of the old " Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 39/52] audio: unify input and output mixeng buffer management Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 40/52] audio: remove hw->samples, buffer_size_in/out pcm_ops Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 41/52] audio: common rate control code for timer based outputs Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 42/52] audio: split ctl_* functions into enable_* and volume_* Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 43/52] audio: add mixeng option (documentation) Kővágó, Zoltán
2019-01-10  1:43   ` Eric Blake
2019-01-10  9:12     ` Markus Armbruster
2019-01-16 20:27     ` Zoltán Kővágó
2019-01-16 22:40       ` Eric Blake
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 44/52] audio: make mixeng optional Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 46/52] audio: support more than two channels in volume setting Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 47/52] audio: replace shift in audio_pcm_info with bytes_per_frame Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 48/52] audio: basic support for multichannel audio Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 49/52] paaudio: channel-map option Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 50/52] usb-audio: do not count on avail bytes actually available Kővágó, Zoltán
2018-12-23 20:52 ` [Qemu-devel] [PATCH v2 52/52] usbaudio: change playback counters to 64 bit Kővágó, Zoltán
2018-12-25 10:50   ` Philippe Mathieu-Daudé
2018-12-27 22:08     ` Kővágó Zoltán
2018-12-25 10:43 ` [Qemu-devel] [PATCH v2 00/52] Audio 5.1 patches Philippe Mathieu-Daudé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=59bee9fad02c04c6600eba20dafb0c4cd1b31007.1545598229.git.DirtY.iCE.hu@gmail.com \
    --to=dirty.ice.hu@gmail.com \
    --cc=kraxel@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.