[PATCH 31/37] audio: make AudioBackend truly abstract

marcandre.lureau@redhat.com posted 37 patches 2 weeks, 4 days ago
Maintainers: Gerd Hoffmann <kraxel@redhat.com>, Christian Schoenebeck <qemu_oss@crudebyte.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Thomas Huth <huth@tuxfamily.org>, Alexandre Ratchov <alex@caoua.org>, Laurent Vivier <laurent@vivier.eu>, Manos Pitsidianakis <manos.pitsidianakis@linaro.org>, "Michael S. Tsirkin" <mst@redhat.com>, Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Peter Maydell <peter.maydell@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, "Alex Bennée" <alex.bennee@linaro.org>, "Daniel P. Berrangé" <berrange@redhat.com>, Eduardo Habkost <eduardo@habkost.net>, John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>
[PATCH 31/37] audio: make AudioBackend truly abstract
Posted by marcandre.lureau@redhat.com 2 weeks, 4 days ago
From: Marc-André Lureau <marcandre.lureau@redhat.com>

Add virtual methods to be implemented by concrete classes, like
AudioMixengBackendClass.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 audio/audio_template.h       |   9 +-
 include/qemu/audio-capture.h |  13 ---
 include/qemu/audio.h         |  58 +++++++++--
 audio/audio.c                | 187 ++++++++++++++++++++++++++++++++---
 4 files changed, 227 insertions(+), 40 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 33f2ff432eb..a7733f9e1d9 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -478,7 +478,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
     g_free (sw);
 }
 
-void glue(AUD_close_, TYPE)(AudioBackend *be, SW *sw)
+static void glue(audio_mixeng_backend_close_, TYPE)(AudioBackend *be, SW *sw)
 {
     if (sw) {
         if (audio_bug(__func__, !be)) {
@@ -490,14 +490,13 @@ void glue(AUD_close_, TYPE)(AudioBackend *be, SW *sw)
     }
 }
 
-SW *glue (AUD_open_, TYPE) (
+static SW *glue(audio_mixeng_backend_open_, TYPE) (
     AudioBackend *be,
     SW *sw,
     const char *name,
     void *callback_opaque ,
     audio_callback_fn callback_fn,
-    const struct audsettings *as
-    )
+    const struct audsettings *as)
 {
     AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(be);
     AudiodevPerDirectionOptions *pdo;
@@ -569,7 +568,7 @@ SW *glue (AUD_open_, TYPE) (
     return NULL;
 }
 
-bool glue(AUD_is_active_, TYPE)(AudioBackend *be, SW *sw)
+static bool glue(audio_mixeng_backend_is_active_, TYPE)(AudioBackend *be, SW *sw)
 {
     return sw ? sw->active : 0;
 }
diff --git a/include/qemu/audio-capture.h b/include/qemu/audio-capture.h
index f500b0a7f8c..5bfbdd02985 100644
--- a/include/qemu/audio-capture.h
+++ b/include/qemu/audio-capture.h
@@ -8,19 +8,6 @@
 
 #include "audio.h"
 
-typedef struct CaptureVoiceOut CaptureVoiceOut;
-
-typedef enum {
-    AUD_CNOTIFY_ENABLE,
-    AUD_CNOTIFY_DISABLE
-} audcnotification_e;
-
-struct audio_capture_ops {
-    void (*notify) (void *opaque, audcnotification_e cmd);
-    void (*capture) (void *opaque, const void *buf, int size);
-    void (*destroy) (void *opaque);
-};
-
 struct capture_ops {
     void (*info) (void *opaque);
     void (*destroy) (void *opaque);
diff --git a/include/qemu/audio.h b/include/qemu/audio.h
index e87708e3d1e..4fae48886ba 100644
--- a/include/qemu/audio.h
+++ b/include/qemu/audio.h
@@ -43,6 +43,25 @@ typedef struct audsettings {
 
 typedef struct SWVoiceOut SWVoiceOut;
 typedef struct SWVoiceIn SWVoiceIn;
+typedef struct CaptureVoiceOut CaptureVoiceOut;
+
+typedef enum {
+    AUD_CNOTIFY_ENABLE,
+    AUD_CNOTIFY_DISABLE
+} audcnotification_e;
+
+struct audio_capture_ops {
+    void (*notify) (void *opaque, audcnotification_e cmd);
+    void (*capture) (void *opaque, const void *buf, int size);
+    void (*destroy) (void *opaque);
+};
+
+#define AUDIO_MAX_CHANNELS 16
+typedef struct Volume {
+    bool mute;
+    int channels;
+    uint8_t vol[AUDIO_MAX_CHANNELS];
+} Volume;
 
 typedef struct AudioBackend {
     Object parent_obj;
@@ -53,6 +72,35 @@ typedef struct AudioBackendClass {
 
     bool (*realize)(AudioBackend *be, Audiodev *dev, Error **errp);
     const char *(*get_id)(AudioBackend *be);
+    SWVoiceOut *(*open_out)(AudioBackend *be,
+                            SWVoiceOut *sw,
+                            const char *name,
+                            void *callback_opaque,
+                            audio_callback_fn callback_fn,
+                            const struct audsettings *as);
+    SWVoiceIn *(*open_in)(AudioBackend *be,
+                          SWVoiceIn *sw,
+                          const char *name,
+                          void *callback_opaque,
+                          audio_callback_fn callback_fn,
+                          const struct audsettings *as);
+    void (*close_out)(AudioBackend *be, SWVoiceOut *sw);
+    void (*close_in)(AudioBackend *be, SWVoiceIn *sw);
+    bool (*is_active_out)(AudioBackend *be, SWVoiceOut *sw);
+    bool (*is_active_in)(AudioBackend *be, SWVoiceIn *sw);
+    void (*set_active_out)(AudioBackend *be, SWVoiceOut *sw, bool on);
+    void (*set_active_in)(AudioBackend *be, SWVoiceIn *sw, bool on);
+    void (*set_volume_out)(AudioBackend *be, SWVoiceOut *sw, Volume *vol);
+    void (*set_volume_in)(AudioBackend *be, SWVoiceIn *sw, Volume *vol);
+    size_t (*write)(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size);
+    size_t (*read)(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size);
+    int (*get_buffer_size_out)(AudioBackend *be, SWVoiceOut *sw);
+    CaptureVoiceOut *(*add_capture)(AudioBackend *be,
+                                    struct audsettings *as,
+                                    struct audio_capture_ops *ops,
+                                    void *cb_opaque);
+    void (*del_capture)(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque);
+
 #ifdef CONFIG_GIO
     bool (*set_dbus_server)(AudioBackend *be,
                             GDBusObjectManagerServer *manager,
@@ -69,8 +117,7 @@ SWVoiceOut *AUD_open_out(
     const char *name,
     void *callback_opaque,
     audio_callback_fn callback_fn,
-    const struct audsettings *settings
-    );
+    const struct audsettings *settings);
 
 void AUD_close_out(AudioBackend *be, SWVoiceOut *sw);
 size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *pcm_buf, size_t size);
@@ -78,13 +125,6 @@ int  AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw);
 void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on);
 bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw);
 
-#define AUDIO_MAX_CHANNELS 16
-typedef struct Volume {
-    bool mute;
-    int channels;
-    uint8_t vol[AUDIO_MAX_CHANNELS];
-} Volume;
-
 void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol);
 void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol);
 
diff --git a/audio/audio.c b/audio/audio.c
index 6bfec5e1d75..3f09452e300 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -846,7 +846,8 @@ static void audio_timer (void *opaque)
 /*
  * Public API
  */
-size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
+static size_t audio_mixeng_backend_write(AudioBackend *be, SWVoiceOut *sw,
+                                         void *buf, size_t size)
 {
     HWVoiceOut *hw;
 
@@ -857,7 +858,7 @@ size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
     hw = sw->hw;
 
     if (!hw->enabled) {
-        dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
+        dolog("Writing to disabled voice %s\n", SW_NAME(sw));
         return 0;
     }
 
@@ -868,7 +869,15 @@ size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
     }
 }
 
-size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
+size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->write(be, sw, buf, size);
+}
+
+static size_t audio_mixeng_backend_read(AudioBackend *be, SWVoiceIn *sw,
+                                        void *buf, size_t size)
 {
     HWVoiceIn *hw;
 
@@ -879,7 +888,7 @@ size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
     hw = sw->hw;
 
     if (!hw->enabled) {
-        dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
+        dolog("Reading from disabled voice %s\n", SW_NAME(sw));
         return 0;
     }
 
@@ -888,9 +897,17 @@ size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
     } else {
         return hw->pcm_ops->read(hw, buf, size);
     }
+
 }
 
-int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
+size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->read(be, sw, buf, size);
+}
+
+static int audio_mixeng_backend_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
 {
     if (!sw) {
         return 0;
@@ -903,7 +920,15 @@ int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
     return sw->hw->samples * sw->hw->info.bytes_per_frame;
 }
 
-void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
+int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->get_buffer_size_out(be, sw);
+}
+
+static void audio_mixeng_backend_set_active_out(AudioBackend *be, SWVoiceOut *sw,
+                                                bool on)
 {
     HWVoiceOut *hw;
 
@@ -949,9 +974,17 @@ void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
         }
         sw->active = on;
     }
+
 }
 
-void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
+void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->set_active_out(be, sw, on);
+}
+
+static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
 {
     HWVoiceIn *hw;
 
@@ -996,6 +1029,13 @@ void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
     }
 }
 
+void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->set_active_in(be, sw, on);
+}
+
 static size_t audio_get_avail(SWVoiceIn *sw)
 {
     size_t live;
@@ -1657,12 +1697,97 @@ static const char *audio_mixeng_backend_get_id(AudioBackend *be)
     return AUDIO_MIXENG_BACKEND(be)->dev->id;
 }
 
+static CaptureVoiceOut *audio_mixeng_backend_add_capture(
+    AudioBackend *be,
+    struct audsettings *as,
+    struct audio_capture_ops *ops,
+    void *cb_opaque);
+
+static void audio_mixeng_backend_del_capture(
+    AudioBackend *be,
+    CaptureVoiceOut *cap,
+    void *cb_opaque);
+
+static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw,
+                                                Volume *vol);
+static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
+                                               Volume *vol);
+
+SWVoiceOut *AUD_open_out(
+    AudioBackend *be,
+    SWVoiceOut *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn callback_fn,
+    const struct audsettings *as)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->open_out(be, sw, name, callback_opaque, callback_fn, as);
+}
+
+SWVoiceIn *AUD_open_in(
+    AudioBackend *be,
+    SWVoiceIn *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn callback_fn,
+    const struct audsettings *as)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->open_in(be, sw, name, callback_opaque, callback_fn, as);
+}
+
+void AUD_close_out(AudioBackend *be, SWVoiceOut *sw)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->close_out(be, sw);
+}
+
+void AUD_close_in(AudioBackend *be, SWVoiceIn *sw)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->close_in(be, sw);
+}
+
+bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->is_active_out(be, sw);
+}
+
+bool AUD_is_active_in(AudioBackend *be, SWVoiceIn *sw)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->is_active_in(be, sw);
+}
+
 static void audio_mixeng_backend_class_init(ObjectClass *klass, const void *data)
 {
     AudioBackendClass *be = AUDIO_BACKEND_CLASS(klass);
 
     be->realize = audio_mixeng_backend_realize;
     be->get_id = audio_mixeng_backend_get_id;
+    be->open_in = audio_mixeng_backend_open_in;
+    be->open_out = audio_mixeng_backend_open_out;
+    be->close_in = audio_mixeng_backend_close_in;
+    be->close_out = audio_mixeng_backend_close_out;
+    be->is_active_out = audio_mixeng_backend_is_active_out;
+    be->is_active_in = audio_mixeng_backend_is_active_in;
+    be->set_active_out = audio_mixeng_backend_set_active_out;
+    be->set_active_in = audio_mixeng_backend_set_active_in;
+    be->set_volume_out = audio_mixeng_backend_set_volume_out;
+    be->set_volume_in = audio_mixeng_backend_set_volume_in;
+    be->read = audio_mixeng_backend_read;
+    be->write = audio_mixeng_backend_write;
+    be->get_buffer_size_out = audio_mixeng_backend_get_buffer_size_out;
+    be->add_capture = audio_mixeng_backend_add_capture;
+    be->del_capture = audio_mixeng_backend_del_capture;
 }
 
 static void audio_mixeng_backend_init(Object *obj)
@@ -1862,12 +1987,11 @@ bool AUD_backend_check(AudioBackend **be, Error **errp)
 
 static struct audio_pcm_ops capture_pcm_ops;
 
-CaptureVoiceOut *AUD_add_capture(
+static CaptureVoiceOut *audio_mixeng_backend_add_capture(
     AudioBackend *be,
     struct audsettings *as,
     struct audio_capture_ops *ops,
-    void *cb_opaque
-    )
+    void *cb_opaque)
 {
     AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(be);
     CaptureVoiceOut *cap;
@@ -1937,7 +2061,21 @@ CaptureVoiceOut *AUD_add_capture(
     return cap;
 }
 
-void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
+CaptureVoiceOut *AUD_add_capture(
+    AudioBackend *be,
+    struct audsettings *as,
+    struct audio_capture_ops *ops,
+    void *cb_opaque)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    return klass->add_capture(be, as, ops, cb_opaque);
+}
+
+static void audio_mixeng_backend_del_capture(
+    AudioBackend *be,
+    CaptureVoiceOut *cap,
+    void *cb_opaque)
 {
     struct capture_callback *cb;
 
@@ -1976,7 +2114,15 @@ void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
     }
 }
 
-void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
+void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    klass->del_capture(be, cap, cb_opaque);
+}
+
+static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw,
+                                                Volume *vol)
 {
     if (sw) {
         HWVoiceOut *hw = sw->hw;
@@ -1992,7 +2138,15 @@ void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
     }
 }
 
-void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
+void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    klass->set_volume_out(be, sw, vol);
+}
+
+static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
+                                               Volume *vol)
 {
     if (sw) {
         HWVoiceIn *hw = sw->hw;
@@ -2008,6 +2162,13 @@ void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
     }
 }
 
+void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
+{
+    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
+
+    klass->set_volume_in(be, sw, vol);
+}
+
 static void audio_create_pdos(Audiodev *dev)
 {
     switch (dev->driver) {
-- 
2.52.0


Re: [PATCH 31/37] audio: make AudioBackend truly abstract
Posted by Mark Cave-Ayland 6 days, 1 hour ago
On 23/01/2026 07:49, marcandre.lureau@redhat.com wrote:

> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Add virtual methods to be implemented by concrete classes, like
> AudioMixengBackendClass.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>   audio/audio_template.h       |   9 +-
>   include/qemu/audio-capture.h |  13 ---
>   include/qemu/audio.h         |  58 +++++++++--
>   audio/audio.c                | 187 ++++++++++++++++++++++++++++++++---
>   4 files changed, 227 insertions(+), 40 deletions(-)
> 
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index 33f2ff432eb..a7733f9e1d9 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -478,7 +478,7 @@ static void glue (audio_close_, TYPE) (SW *sw)
>       g_free (sw);
>   }
>   
> -void glue(AUD_close_, TYPE)(AudioBackend *be, SW *sw)
> +static void glue(audio_mixeng_backend_close_, TYPE)(AudioBackend *be, SW *sw)
>   {
>       if (sw) {
>           if (audio_bug(__func__, !be)) {
> @@ -490,14 +490,13 @@ void glue(AUD_close_, TYPE)(AudioBackend *be, SW *sw)
>       }
>   }
>   
> -SW *glue (AUD_open_, TYPE) (
> +static SW *glue(audio_mixeng_backend_open_, TYPE) (
>       AudioBackend *be,
>       SW *sw,
>       const char *name,
>       void *callback_opaque ,
>       audio_callback_fn callback_fn,
> -    const struct audsettings *as
> -    )
> +    const struct audsettings *as)
>   {
>       AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(be);
>       AudiodevPerDirectionOptions *pdo;
> @@ -569,7 +568,7 @@ SW *glue (AUD_open_, TYPE) (
>       return NULL;
>   }
>   
> -bool glue(AUD_is_active_, TYPE)(AudioBackend *be, SW *sw)
> +static bool glue(audio_mixeng_backend_is_active_, TYPE)(AudioBackend *be, SW *sw)
>   {
>       return sw ? sw->active : 0;
>   }
> diff --git a/include/qemu/audio-capture.h b/include/qemu/audio-capture.h
> index f500b0a7f8c..5bfbdd02985 100644
> --- a/include/qemu/audio-capture.h
> +++ b/include/qemu/audio-capture.h
> @@ -8,19 +8,6 @@
>   
>   #include "audio.h"
>   
> -typedef struct CaptureVoiceOut CaptureVoiceOut;
> -
> -typedef enum {
> -    AUD_CNOTIFY_ENABLE,
> -    AUD_CNOTIFY_DISABLE
> -} audcnotification_e;
> -
> -struct audio_capture_ops {
> -    void (*notify) (void *opaque, audcnotification_e cmd);
> -    void (*capture) (void *opaque, const void *buf, int size);
> -    void (*destroy) (void *opaque);
> -};
> -
>   struct capture_ops {
>       void (*info) (void *opaque);
>       void (*destroy) (void *opaque);
> diff --git a/include/qemu/audio.h b/include/qemu/audio.h
> index e87708e3d1e..4fae48886ba 100644
> --- a/include/qemu/audio.h
> +++ b/include/qemu/audio.h
> @@ -43,6 +43,25 @@ typedef struct audsettings {
>   
>   typedef struct SWVoiceOut SWVoiceOut;
>   typedef struct SWVoiceIn SWVoiceIn;
> +typedef struct CaptureVoiceOut CaptureVoiceOut;
> +
> +typedef enum {
> +    AUD_CNOTIFY_ENABLE,
> +    AUD_CNOTIFY_DISABLE
> +} audcnotification_e;
> +
> +struct audio_capture_ops {
> +    void (*notify) (void *opaque, audcnotification_e cmd);
> +    void (*capture) (void *opaque, const void *buf, int size);
> +    void (*destroy) (void *opaque);
> +};
> +
> +#define AUDIO_MAX_CHANNELS 16
> +typedef struct Volume {
> +    bool mute;
> +    int channels;
> +    uint8_t vol[AUDIO_MAX_CHANNELS];
> +} Volume;
>   
>   typedef struct AudioBackend {
>       Object parent_obj;
> @@ -53,6 +72,35 @@ typedef struct AudioBackendClass {
>   
>       bool (*realize)(AudioBackend *be, Audiodev *dev, Error **errp);
>       const char *(*get_id)(AudioBackend *be);
> +    SWVoiceOut *(*open_out)(AudioBackend *be,
> +                            SWVoiceOut *sw,
> +                            const char *name,
> +                            void *callback_opaque,
> +                            audio_callback_fn callback_fn,
> +                            const struct audsettings *as);
> +    SWVoiceIn *(*open_in)(AudioBackend *be,
> +                          SWVoiceIn *sw,
> +                          const char *name,
> +                          void *callback_opaque,
> +                          audio_callback_fn callback_fn,
> +                          const struct audsettings *as);
> +    void (*close_out)(AudioBackend *be, SWVoiceOut *sw);
> +    void (*close_in)(AudioBackend *be, SWVoiceIn *sw);
> +    bool (*is_active_out)(AudioBackend *be, SWVoiceOut *sw);
> +    bool (*is_active_in)(AudioBackend *be, SWVoiceIn *sw);
> +    void (*set_active_out)(AudioBackend *be, SWVoiceOut *sw, bool on);
> +    void (*set_active_in)(AudioBackend *be, SWVoiceIn *sw, bool on);
> +    void (*set_volume_out)(AudioBackend *be, SWVoiceOut *sw, Volume *vol);
> +    void (*set_volume_in)(AudioBackend *be, SWVoiceIn *sw, Volume *vol);
> +    size_t (*write)(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size);
> +    size_t (*read)(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size);
> +    int (*get_buffer_size_out)(AudioBackend *be, SWVoiceOut *sw);
> +    CaptureVoiceOut *(*add_capture)(AudioBackend *be,
> +                                    struct audsettings *as,
> +                                    struct audio_capture_ops *ops,
> +                                    void *cb_opaque);
> +    void (*del_capture)(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque);
> +
>   #ifdef CONFIG_GIO
>       bool (*set_dbus_server)(AudioBackend *be,
>                               GDBusObjectManagerServer *manager,
> @@ -69,8 +117,7 @@ SWVoiceOut *AUD_open_out(
>       const char *name,
>       void *callback_opaque,
>       audio_callback_fn callback_fn,
> -    const struct audsettings *settings
> -    );
> +    const struct audsettings *settings);
>   
>   void AUD_close_out(AudioBackend *be, SWVoiceOut *sw);
>   size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *pcm_buf, size_t size);
> @@ -78,13 +125,6 @@ int  AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw);
>   void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on);
>   bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw);
>   
> -#define AUDIO_MAX_CHANNELS 16
> -typedef struct Volume {
> -    bool mute;
> -    int channels;
> -    uint8_t vol[AUDIO_MAX_CHANNELS];
> -} Volume;
> -
>   void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol);
>   void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol);
>   
> diff --git a/audio/audio.c b/audio/audio.c
> index 6bfec5e1d75..3f09452e300 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -846,7 +846,8 @@ static void audio_timer (void *opaque)
>   /*
>    * Public API
>    */
> -size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
> +static size_t audio_mixeng_backend_write(AudioBackend *be, SWVoiceOut *sw,
> +                                         void *buf, size_t size)
>   {
>       HWVoiceOut *hw;
>   
> @@ -857,7 +858,7 @@ size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
>       hw = sw->hw;
>   
>       if (!hw->enabled) {
> -        dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
> +        dolog("Writing to disabled voice %s\n", SW_NAME(sw));
>           return 0;
>       }
>   
> @@ -868,7 +869,15 @@ size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
>       }
>   }
>   
> -size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
> +size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->write(be, sw, buf, size);
> +}
> +
> +static size_t audio_mixeng_backend_read(AudioBackend *be, SWVoiceIn *sw,
> +                                        void *buf, size_t size)
>   {
>       HWVoiceIn *hw;
>   
> @@ -879,7 +888,7 @@ size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
>       hw = sw->hw;
>   
>       if (!hw->enabled) {
> -        dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
> +        dolog("Reading from disabled voice %s\n", SW_NAME(sw));
>           return 0;
>       }
>   
> @@ -888,9 +897,17 @@ size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
>       } else {
>           return hw->pcm_ops->read(hw, buf, size);
>       }
> +
>   }
>   
> -int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
> +size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->read(be, sw, buf, size);
> +}
> +
> +static int audio_mixeng_backend_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
>   {
>       if (!sw) {
>           return 0;
> @@ -903,7 +920,15 @@ int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
>       return sw->hw->samples * sw->hw->info.bytes_per_frame;
>   }
>   
> -void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
> +int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->get_buffer_size_out(be, sw);
> +}
> +
> +static void audio_mixeng_backend_set_active_out(AudioBackend *be, SWVoiceOut *sw,
> +                                                bool on)
>   {
>       HWVoiceOut *hw;
>   
> @@ -949,9 +974,17 @@ void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
>           }
>           sw->active = on;
>       }
> +
>   }
>   
> -void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
> +void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->set_active_out(be, sw, on);
> +}
> +
> +static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
>   {
>       HWVoiceIn *hw;
>   
> @@ -996,6 +1029,13 @@ void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
>       }
>   }
>   
> +void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->set_active_in(be, sw, on);
> +}
> +
>   static size_t audio_get_avail(SWVoiceIn *sw)
>   {
>       size_t live;
> @@ -1657,12 +1697,97 @@ static const char *audio_mixeng_backend_get_id(AudioBackend *be)
>       return AUDIO_MIXENG_BACKEND(be)->dev->id;
>   }
>   
> +static CaptureVoiceOut *audio_mixeng_backend_add_capture(
> +    AudioBackend *be,
> +    struct audsettings *as,
> +    struct audio_capture_ops *ops,
> +    void *cb_opaque);
> +
> +static void audio_mixeng_backend_del_capture(
> +    AudioBackend *be,
> +    CaptureVoiceOut *cap,
> +    void *cb_opaque);
> +
> +static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw,
> +                                                Volume *vol);
> +static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
> +                                               Volume *vol);
> +
> +SWVoiceOut *AUD_open_out(
> +    AudioBackend *be,
> +    SWVoiceOut *sw,
> +    const char *name,
> +    void *callback_opaque,
> +    audio_callback_fn callback_fn,
> +    const struct audsettings *as)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->open_out(be, sw, name, callback_opaque, callback_fn, as);
> +}
> +
> +SWVoiceIn *AUD_open_in(
> +    AudioBackend *be,
> +    SWVoiceIn *sw,
> +    const char *name,
> +    void *callback_opaque,
> +    audio_callback_fn callback_fn,
> +    const struct audsettings *as)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->open_in(be, sw, name, callback_opaque, callback_fn, as);
> +}
> +
> +void AUD_close_out(AudioBackend *be, SWVoiceOut *sw)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->close_out(be, sw);
> +}
> +
> +void AUD_close_in(AudioBackend *be, SWVoiceIn *sw)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->close_in(be, sw);
> +}
> +
> +bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->is_active_out(be, sw);
> +}
> +
> +bool AUD_is_active_in(AudioBackend *be, SWVoiceIn *sw)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->is_active_in(be, sw);
> +}
> +
>   static void audio_mixeng_backend_class_init(ObjectClass *klass, const void *data)
>   {
>       AudioBackendClass *be = AUDIO_BACKEND_CLASS(klass);
>   
>       be->realize = audio_mixeng_backend_realize;
>       be->get_id = audio_mixeng_backend_get_id;
> +    be->open_in = audio_mixeng_backend_open_in;
> +    be->open_out = audio_mixeng_backend_open_out;
> +    be->close_in = audio_mixeng_backend_close_in;
> +    be->close_out = audio_mixeng_backend_close_out;
> +    be->is_active_out = audio_mixeng_backend_is_active_out;
> +    be->is_active_in = audio_mixeng_backend_is_active_in;
> +    be->set_active_out = audio_mixeng_backend_set_active_out;
> +    be->set_active_in = audio_mixeng_backend_set_active_in;
> +    be->set_volume_out = audio_mixeng_backend_set_volume_out;
> +    be->set_volume_in = audio_mixeng_backend_set_volume_in;
> +    be->read = audio_mixeng_backend_read;
> +    be->write = audio_mixeng_backend_write;
> +    be->get_buffer_size_out = audio_mixeng_backend_get_buffer_size_out;
> +    be->add_capture = audio_mixeng_backend_add_capture;
> +    be->del_capture = audio_mixeng_backend_del_capture;
>   }
>   
>   static void audio_mixeng_backend_init(Object *obj)
> @@ -1862,12 +1987,11 @@ bool AUD_backend_check(AudioBackend **be, Error **errp)
>   
>   static struct audio_pcm_ops capture_pcm_ops;
>   
> -CaptureVoiceOut *AUD_add_capture(
> +static CaptureVoiceOut *audio_mixeng_backend_add_capture(
>       AudioBackend *be,
>       struct audsettings *as,
>       struct audio_capture_ops *ops,
> -    void *cb_opaque
> -    )
> +    void *cb_opaque)
>   {
>       AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(be);
>       CaptureVoiceOut *cap;
> @@ -1937,7 +2061,21 @@ CaptureVoiceOut *AUD_add_capture(
>       return cap;
>   }
>   
> -void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
> +CaptureVoiceOut *AUD_add_capture(
> +    AudioBackend *be,
> +    struct audsettings *as,
> +    struct audio_capture_ops *ops,
> +    void *cb_opaque)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    return klass->add_capture(be, as, ops, cb_opaque);
> +}
> +
> +static void audio_mixeng_backend_del_capture(
> +    AudioBackend *be,
> +    CaptureVoiceOut *cap,
> +    void *cb_opaque)
>   {
>       struct capture_callback *cb;
>   
> @@ -1976,7 +2114,15 @@ void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
>       }
>   }
>   
> -void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
> +void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    klass->del_capture(be, cap, cb_opaque);
> +}
> +
> +static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw,
> +                                                Volume *vol)
>   {
>       if (sw) {
>           HWVoiceOut *hw = sw->hw;
> @@ -1992,7 +2138,15 @@ void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
>       }
>   }
>   
> -void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
> +void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    klass->set_volume_out(be, sw, vol);
> +}
> +
> +static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
> +                                               Volume *vol)
>   {
>       if (sw) {
>           HWVoiceIn *hw = sw->hw;
> @@ -2008,6 +2162,13 @@ void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
>       }
>   }
>   
> +void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
> +{
> +    AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
> +
> +    klass->set_volume_in(be, sw, vol);
> +}
> +
>   static void audio_create_pdos(Audiodev *dev)
>   {
>       switch (dev->driver) {

Reviewed-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>


ATB,

Mark.