get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2196837/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2196837,
    "url": "http://patchwork.ozlabs.org/api/patches/2196837/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260216-audio-v1-57-e676662e4514@redhat.com/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260216-audio-v1-57-e676662e4514@redhat.com>",
    "list_archive_url": null,
    "date": "2026-02-16T11:15:46",
    "name": "[57/85] audio: move pcm_ops into AudioMixengBackendClass",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "3befb7a0d094babe63810a5aa704c09d1de09e7e",
    "submitter": {
        "id": 66774,
        "url": "http://patchwork.ozlabs.org/api/people/66774/?format=api",
        "name": "Marc-André Lureau",
        "email": "marcandre.lureau@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260216-audio-v1-57-e676662e4514@redhat.com/mbox/",
    "series": [
        {
            "id": 492294,
            "url": "http://patchwork.ozlabs.org/api/series/492294/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=492294",
            "date": "2026-02-16T11:14:52",
            "name": "audio: cleanups & add a manual test",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/492294/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2196837/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2196837/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=EXiojmyg;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fF0lq2Zpyz1xpY\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 16 Feb 2026 22:24:07 +1100 (AEDT)",
            "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1vrwfN-0006U3-8z; Mon, 16 Feb 2026 06:21:25 -0500",
            "from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <marcandre.lureau@redhat.com>)\n id 1vrwcZ-0006rp-OY\n for qemu-devel@nongnu.org; Mon, 16 Feb 2026 06:18:37 -0500",
            "from us-smtp-delivery-124.mimecast.com ([170.10.133.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <marcandre.lureau@redhat.com>)\n id 1vrwcS-0008FJ-JW\n for qemu-devel@nongnu.org; Mon, 16 Feb 2026 06:18:28 -0500",
            "from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-464--KjTidx7Ol62MRLWvdh55g-1; Mon,\n 16 Feb 2026 06:18:20 -0500",
            "from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 872D818004BB; Mon, 16 Feb 2026 11:18:18 +0000 (UTC)",
            "from localhost (unknown [10.45.242.26])\n by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 661F618003F5; Mon, 16 Feb 2026 11:18:17 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1771240704;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=9squzf3KFb5y+JqzrvGK8siM2naJv6a7ZvlyYN1J/Ik=;\n b=EXiojmygOKDIy3BanyhW7683fduoMw+/z3dbi7z1P+BL5SaRdDGceP/nJEOuuzD9xAuMbN\n DUwR7BZuJrDu+GOYZDK6uAzoZMk8mczRt/7ZNGQ70dQDmnkpIquwmfVXYRpXIIRGNz00+G\n RRB0gtG0xY+dwLpOB2cst8oSKjn8+8s=",
        "X-MC-Unique": "-KjTidx7Ol62MRLWvdh55g-1",
        "X-Mimecast-MFC-AGG-ID": "-KjTidx7Ol62MRLWvdh55g_1771240698",
        "From": "=?utf-8?q?Marc-Andr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>",
        "Date": "Mon, 16 Feb 2026 12:15:46 +0100",
        "Subject": "[PATCH 57/85] audio: move pcm_ops into AudioMixengBackendClass",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "8bit",
        "Message-Id": "<20260216-audio-v1-57-e676662e4514@redhat.com>",
        "References": "<20260216-audio-v1-0-e676662e4514@redhat.com>",
        "In-Reply-To": "<20260216-audio-v1-0-e676662e4514@redhat.com>",
        "To": "qemu-devel@nongnu.org",
        "Cc": "Gerd Hoffmann <kraxel@redhat.com>,  Eduardo Habkost <eduardo@habkost.net>,\n Paolo Bonzini <pbonzini@redhat.com>,\n =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= <berrange@redhat.com>, =?utf-8?q?Phil?=\n\t=?utf-8?q?ippe_Mathieu-Daud=C3=A9?= <philmd@linaro.org>,\n  John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>,\n  Christian Schoenebeck <qemu_oss@crudebyte.com>,\n  Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>,\n  Thomas Huth <huth@tuxfamily.org>, Alexandre Ratchov <alex@caoua.org>,\n\t=?utf-8?q?Alex_Benn=C3=A9e?= <alex.bennee@linaro.org>,\n  Laurent Vivier <laurent@vivier.eu>, \"Michael S. Tsirkin\" <mst@redhat.com>,\n  Manos Pitsidianakis <manos.pitsidianakis@linaro.org>,\n  Alistair Francis <alistair@alistair23.me>,\n  \"Edgar E. Iglesias\" <edgar.iglesias@gmail.com>,\n  Peter Maydell <peter.maydell@linaro.org>, qemu-arm@nongnu.org, =?utf-8?q?M?=\n\t=?utf-8?q?arc-Andr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>,\n  Mark Cave-Ayland <mark.caveayland@nutanix.com>",
        "X-Developer-Signature": "v=1; a=openpgp-sha256; l=49522;\n i=marcandre.lureau@redhat.com; h=from:subject:message-id;\n bh=H80VC2lmA1mgIJAS1IeeAPq8vKiezekJkNE6YmZhgfo=;\n b=owEBbQKS/ZANAwAKAdro4Ql1lpzlAcsmYgBpkvxRwnHg4NQCTXkbpLvmjT9GG+yIxCuqoFnO4\n wqdqd3jfuCJAjMEAAEKAB0WIQSHqb2TP4fGBtJ29i3a6OEJdZac5QUCaZL8UQAKCRDa6OEJdZac\n 5asTEACr/OnDWhPMHSQtkAzGdxKeTZiM7+mcEJthlaZQNVWR8yvwwWpMbAUD8crtCeWM8cLGTz1\n iPA/z3FvbZjegrftUlnjh56kEIp/tup9ToE+Qvbz+b2paa9dFvGFzTNtF2fpxirSP1U0mnax2Vz\n hWZ9CnaIj4D4sRs+Mcj/i73AuYMvX0XVeCp89GtElWAwk91sbq6vfCZC6mTKgmSKCd+geauFJEw\n oxXeQanzgyotGc8CItWSfMpRk3qiGmDZXX7YLZz4v1EzaeNlIT2jX19lXxLl1fAoWNCtsT8rIBp\n 64L7R576aiRisvWkNT59j11DxnvFPW7XpyK4HpxYSRvuEHZECJq+iWe3gYVVfYvxbzO3SqMG2b7\n MIftsFjAfjjvRdiVDKDM+1xDKr+8646YmeirFj1cc5AJFs1RNaiDwggg/mHJB0VMb32Fa4YyH6o\n rAiRXGzisi1ie5spDKCGG5PKZ5enwXBwrWJLW1SwgSjZUfLaamiKoGHNm0XLrOg/Z/+S2XMvB7S\n ZXDiqCCMc48uY/sGWET02KeRGxcnfaL7sQYZeRjS+Dwzw7VixNwdowcJ4qvawDjs3Ld0MoYJbcB\n B8lMpkj/cWKeNmenm66CqhESZhOi3h3DYh3ixrFx40wRbR9mPPDEawa7MDfhrnSzOAjHnu9QLe7\n 9OHRd/UMJPj5ybw==",
        "X-Developer-Key": "i=marcandre.lureau@redhat.com; a=openpgp;\n fpr=87A9BD933F87C606D276F62DDAE8E10975969CE5",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.111",
        "Received-SPF": "pass client-ip=170.10.133.124;\n envelope-from=marcandre.lureau@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com",
        "X-Spam_score_int": "-20",
        "X-Spam_score": "-2.1",
        "X-Spam_bar": "--",
        "X-Spam_report": "(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001,\n RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001,\n SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "qemu development <qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"
    },
    "content": "Remove the separate audio_pcm_ops structure and move its function\npointers directly into AudioMixengBackendClass. This is a cleaner\nQOM-style design where the PCM operations are part of the class\nvtable rather than a separate indirection through hw->pcm_ops.\n\nThe HWVoiceOut and HWVoiceIn structures no longer need to store\na pcm_ops pointer, as the operations are now accessed through\nthe class with AUDIO_MIXENG_BACKEND_GET_CLASS().\n\nSigned-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>\nReviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>\nReviewed-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>\n---\n audio/audio_int.h       |  71 +++++++++++--------------\n audio/audio_template.h  |  16 +++---\n audio/alsaaudio.c       |  29 +++++-----\n audio/audio-mixeng-be.c | 139 ++++++++++++++++++++++++++----------------------\n audio/dbusaudio.c       |  33 ++++++------\n audio/dsoundaudio.c     |  33 ++++++------\n audio/jackaudio.c       |  29 +++++-----\n audio/noaudio.c         |  29 +++++-----\n audio/ossaudio.c        |  33 ++++++------\n audio/paaudio.c         |  33 ++++++------\n audio/pwaudio.c         |  33 ++++++------\n audio/sdlaudio.c        |  46 ++++++++--------\n audio/sndioaudio.c      |  32 ++++++-----\n audio/spiceaudio.c      |  45 ++++++++--------\n audio/wavaudio.c        |  17 +++---\n audio/coreaudio.m       |  27 +++++-----\n 16 files changed, 308 insertions(+), 337 deletions(-)",
    "diff": "diff --git a/audio/audio_int.h b/audio/audio_int.h\nindex bd9c7a29e41..5334c4baad2 100644\n--- a/audio/audio_int.h\n+++ b/audio/audio_int.h\n@@ -39,8 +39,6 @@ AUD_vlog(const char *cap, const char *fmt, va_list ap);\n void G_GNUC_PRINTF(2, 3)\n AUD_log(const char *cap, const char *fmt, ...);\n \n-struct audio_pcm_ops;\n-\n struct audio_callback {\n     void *opaque;\n     audio_callback_fn fn;\n@@ -81,7 +79,6 @@ typedef struct HWVoiceOut {\n     size_t samples;\n     QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;\n     QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;\n-    struct audio_pcm_ops *pcm_ops;\n     QLIST_ENTRY (HWVoiceOut) entries;\n } HWVoiceOut;\n \n@@ -101,7 +98,6 @@ typedef struct HWVoiceIn {\n \n     size_t samples;\n     QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;\n-    struct audio_pcm_ops *pcm_ops;\n     QLIST_ENTRY (HWVoiceIn) entries;\n } HWVoiceIn;\n \n@@ -136,40 +132,6 @@ struct SWVoiceIn {\n     QLIST_ENTRY (SWVoiceIn) entries;\n };\n \n-struct audio_pcm_ops {\n-    int    (*init_out)(HWVoiceOut *hw, audsettings *as);\n-    void   (*fini_out)(HWVoiceOut *hw);\n-    size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);\n-    void   (*run_buffer_out)(HWVoiceOut *hw);\n-    /*\n-     * Get the free output buffer size. This is an upper limit. The size\n-     * returned by function get_buffer_out may be smaller.\n-     */\n-    size_t (*buffer_get_free)(HWVoiceOut *hw);\n-    /*\n-     * get a buffer that after later can be passed to put_buffer_out; optional\n-     * returns the buffer, and writes it's size to size (in bytes)\n-     */\n-    void  *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);\n-    /*\n-     * put back the buffer returned by get_buffer_out; optional\n-     * buf must be equal the pointer returned by get_buffer_out,\n-     * size may be smaller\n-     */\n-    size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);\n-    void   (*enable_out)(HWVoiceOut *hw, bool enable);\n-    void   (*volume_out)(HWVoiceOut *hw, Volume *vol);\n-\n-    int    (*init_in) (HWVoiceIn *hw, audsettings *as);\n-    void   (*fini_in) (HWVoiceIn *hw);\n-    size_t (*read)    (HWVoiceIn *hw, void *buf, size_t size);\n-    void   (*run_buffer_in)(HWVoiceIn *hw);\n-    void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);\n-    void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);\n-    void   (*enable_in)(HWVoiceIn *hw, bool enable);\n-    void   (*volume_in)(HWVoiceIn *hw, Volume *vol);\n-};\n-\n audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo);\n int audioformat_bytes_per_sample(AudioFormat fmt);\n int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,\n@@ -220,11 +182,42 @@ struct AudioMixengBackendClass {\n     AudioBackendClass parent_class;\n \n     const char *name;\n-    struct audio_pcm_ops *pcm_ops;\n     int max_voices_out;\n     int max_voices_in;\n     size_t voice_size_out;\n     size_t voice_size_in;\n+\n+    int    (*init_out)(HWVoiceOut *hw, audsettings *as);\n+    void   (*fini_out)(HWVoiceOut *hw);\n+    size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);\n+    void   (*run_buffer_out)(HWVoiceOut *hw);\n+    /*\n+     * Get the free output buffer size. This is an upper limit. The size\n+     * returned by function get_buffer_out may be smaller.\n+     */\n+    size_t (*buffer_get_free)(HWVoiceOut *hw);\n+    /*\n+     * get a buffer that after later can be passed to put_buffer_out; optional\n+     * returns the buffer, and writes it's size to size (in bytes)\n+     */\n+    void  *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);\n+    /*\n+     * put back the buffer returned by get_buffer_out; optional\n+     * buf must be equal the pointer returned by get_buffer_out,\n+     * size may be smaller\n+     */\n+    size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);\n+    void   (*enable_out)(HWVoiceOut *hw, bool enable);\n+    void   (*volume_out)(HWVoiceOut *hw, Volume *vol);\n+\n+    int    (*init_in) (HWVoiceIn *hw, audsettings *as);\n+    void   (*fini_in) (HWVoiceIn *hw);\n+    size_t (*read)    (HWVoiceIn *hw, void *buf, size_t size);\n+    void   (*run_buffer_in)(HWVoiceIn *hw);\n+    void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);\n+    void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);\n+    void   (*enable_in)(HWVoiceIn *hw, bool enable);\n+    void   (*volume_in)(HWVoiceIn *hw, Volume *vol);\n };\n \n struct AudioMixengBackend {\ndiff --git a/audio/audio_template.h b/audio/audio_template.h\nindex 7187571c668..08d60422589 100644\n--- a/audio/audio_template.h\n+++ b/audio/audio_template.h\n@@ -223,13 +223,14 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)\n {\n     HW *hw = *hwp;\n     AudioMixengBackend *s = hw->s;\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n \n     if (!hw->sw_head.lh_first) {\n #ifdef DAC\n         audio_detach_capture(hw);\n #endif\n         QLIST_REMOVE(hw, entries);\n-        glue(hw->pcm_ops->fini_, TYPE) (hw);\n+        glue(k->fini_, TYPE)(hw);\n         glue(s->nb_hw_voices_, TYPE) += 1;\n         glue(audio_pcm_hw_free_resources_ , TYPE) (hw);\n         object_unref(hw->s);\n@@ -274,8 +275,8 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioMixengBackend *s,\n         return NULL;\n     }\n \n-    if (audio_bug(__func__, !k->pcm_ops)) {\n-        dolog(\"No host audio driver or missing pcm_ops\\n\");\n+    if (audio_bug(__func__, !glue(k->init_, TYPE))) {\n+        dolog(\"No host audio driver or missing init_%s\\n\", NAME);\n         return NULL;\n     }\n \n@@ -285,13 +286,12 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioMixengBackend *s,\n      */\n     hw = g_malloc0(glue(k->voice_size_, TYPE));\n     hw->s = AUDIO_MIXENG_BACKEND(object_ref(s));\n-    hw->pcm_ops = k->pcm_ops;\n \n     QLIST_INIT (&hw->sw_head);\n #ifdef DAC\n     QLIST_INIT (&hw->cap_head);\n #endif\n-    if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {\n+    if (glue(k->init_, TYPE)(hw, as)) {\n         goto err0;\n     }\n \n@@ -330,7 +330,7 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioMixengBackend *s,\n     return hw;\n \n  err1:\n-    glue (hw->pcm_ops->fini_, TYPE) (hw);\n+    glue(k->fini_, TYPE)(hw);\n  err0:\n     object_unref(hw->s);\n     g_free (hw);\n@@ -495,6 +495,7 @@ static SW *glue(audio_mixeng_backend_open_, TYPE) (\n     const struct audsettings *as)\n {\n     AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(be);\n+    AudioMixengBackendClass *k;\n     AudiodevPerDirectionOptions *pdo;\n \n     if (audio_bug(__func__, !be || !name || !callback_fn || !as)) {\n@@ -503,6 +504,7 @@ static SW *glue(audio_mixeng_backend_open_, TYPE) (\n         goto fail;\n     }\n \n+    k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n     pdo = glue(audio_get_pdo_, TYPE)(s->dev);\n \n     ldebug (\"open %s, freq %d, nchannels %d, fmt %d\\n\",\n@@ -513,7 +515,7 @@ static SW *glue(audio_mixeng_backend_open_, TYPE) (\n         goto fail;\n     }\n \n-    if (audio_bug(__func__, !AUDIO_MIXENG_BACKEND_GET_CLASS(s)->pcm_ops)) {\n+    if (audio_bug(__func__, !glue(k->init_, TYPE))) {\n         dolog(\"Can not open `%s' (no host audio driver)\\n\", name);\n         goto fail;\n     }\ndiff --git a/audio/alsaaudio.c b/audio/alsaaudio.c\nindex d008ce7b627..8f226b42612 100644\n--- a/audio/alsaaudio.c\n+++ b/audio/alsaaudio.c\n@@ -922,21 +922,6 @@ audio_alsa_realize(AudioBackend *abe, Audiodev *dev, Error **errp)\n     return audio_alsa_parent_class->realize(abe, dev, errp);\n }\n \n-static struct audio_pcm_ops alsa_pcm_ops = {\n-    .init_out = alsa_init_out,\n-    .fini_out = alsa_fini_out,\n-    .write    = alsa_write,\n-    .buffer_get_free = alsa_buffer_get_free,\n-    .run_buffer_out = audio_generic_run_buffer_out,\n-    .enable_out = alsa_enable_out,\n-\n-    .init_in  = alsa_init_in,\n-    .fini_in  = alsa_fini_in,\n-    .read     = alsa_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = alsa_enable_in,\n-};\n-\n static void audio_alsa_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -946,11 +931,23 @@ static void audio_alsa_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_alsa_realize;\n     k->name = \"alsa\";\n-    k->pcm_ops = &alsa_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(ALSAVoiceOut);\n     k->voice_size_in = sizeof(ALSAVoiceIn);\n+\n+    k->init_out = alsa_init_out;\n+    k->fini_out = alsa_fini_out;\n+    k->write = alsa_write;\n+    k->buffer_get_free = alsa_buffer_get_free;\n+    k->run_buffer_out = audio_generic_run_buffer_out;\n+    k->enable_out = alsa_enable_out;\n+\n+    k->init_in = alsa_init_in;\n+    k->fini_in = alsa_fini_in;\n+    k->read = alsa_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = alsa_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/audio-mixeng-be.c b/audio/audio-mixeng-be.c\nindex 3a0a537713e..17301ec80e7 100644\n--- a/audio/audio-mixeng-be.c\n+++ b/audio/audio-mixeng-be.c\n@@ -526,7 +526,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)\n \n     audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);\n \n-    if (!hw->pcm_ops->volume_in) {\n+    if (!AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s)->volume_in) {\n         mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);\n     }\n     sw->clip(buf, sw->resample_buf.buffer, total_out);\n@@ -579,8 +579,10 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)\n \n static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)\n {\n-    return (hw->pcm_ops->buffer_get_free ? hw->pcm_ops->buffer_get_free(hw) :\n-            INT_MAX) / hw->info.bytes_per_frame;\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n+\n+    return (k->buffer_get_free ? k->buffer_get_free(hw) : INT_MAX) /\n+        hw->info.bytes_per_frame;\n }\n \n static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)\n@@ -673,7 +675,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)\n     if (frames_in_max > sw->resample_buf.pos) {\n         sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,\n                  buf, frames_in_max - sw->resample_buf.pos);\n-        if (!sw->hw->pcm_ops->volume_out) {\n+        if (!AUDIO_MIXENG_BACKEND_GET_CLASS(sw->hw->s)->volume_out) {\n             mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,\n                           frames_in_max - sw->resample_buf.pos, &sw->vol);\n         }\n@@ -806,7 +808,7 @@ static size_t audio_mixeng_backend_write(AudioBackend *be, SWVoiceOut *sw,\n     if (audio_get_pdo_out(hw->s->dev)->mixing_engine) {\n         return audio_pcm_sw_write(sw, buf, size);\n     } else {\n-        return hw->pcm_ops->write(hw, buf, size);\n+        return AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s)->write(hw, buf, size);\n     }\n }\n \n@@ -829,7 +831,7 @@ static size_t audio_mixeng_backend_read(AudioBackend *be,\n     if (audio_get_pdo_in(hw->s->dev)->mixing_engine) {\n         return audio_pcm_sw_read(sw, buf, size);\n     } else {\n-        return hw->pcm_ops->read(hw, buf, size);\n+        return AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s)->read(hw, buf, size);\n     }\n \n }\n@@ -863,12 +865,14 @@ static void audio_mixeng_backend_set_active_out(AudioBackend *be, SWVoiceOut *sw\n         SWVoiceCap *sc;\n \n         if (on) {\n+            AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n+\n             hw->pending_disable = 0;\n             if (!hw->enabled) {\n                 hw->enabled = true;\n                 if (runstate_is_running()) {\n-                    if (hw->pcm_ops->enable_out) {\n-                        hw->pcm_ops->enable_out(hw, true);\n+                    if (k->enable_out) {\n+                        k->enable_out(hw, true);\n                     }\n                     audio_reset_timer (s);\n                 }\n@@ -908,14 +912,15 @@ static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw,\n     hw = sw->hw;\n     if (sw->active != on) {\n         AudioMixengBackend *s = sw->s;\n+        AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n         SWVoiceIn *temp_sw;\n \n         if (on) {\n             if (!hw->enabled) {\n                 hw->enabled = true;\n                 if (runstate_is_running()) {\n-                    if (hw->pcm_ops->enable_in) {\n-                        hw->pcm_ops->enable_in(hw, true);\n+                    if (k->enable_in) {\n+                        k->enable_in(hw, true);\n                     }\n                     audio_reset_timer (s);\n                 }\n@@ -932,8 +937,8 @@ static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw,\n \n                 if (nb_active == 1) {\n                     hw->enabled = false;\n-                    if (hw->pcm_ops->enable_in) {\n-                        hw->pcm_ops->enable_in(hw, false);\n+                    if (k->enable_in) {\n+                        k->enable_in(hw, false);\n                     }\n                 }\n             }\n@@ -1040,12 +1045,13 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,\n \n static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n     size_t clipped = 0;\n \n     while (live) {\n         size_t size = live * hw->info.bytes_per_frame;\n         size_t decr, proc;\n-        void *buf = hw->pcm_ops->get_buffer_out(hw, &size);\n+        void *buf = k->get_buffer_out(hw, &size);\n \n         if (size == 0) {\n             break;\n@@ -1055,8 +1061,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)\n         if (buf) {\n             audio_pcm_hw_clip_out(hw, buf, decr);\n         }\n-        proc = hw->pcm_ops->put_buffer_out(hw, buf,\n-                                           decr * hw->info.bytes_per_frame) /\n+        proc = k->put_buffer_out(hw, buf, decr * hw->info.bytes_per_frame) /\n             hw->info.bytes_per_frame;\n \n         live -= proc;\n@@ -1068,8 +1073,8 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)\n         }\n     }\n \n-    if (hw->pcm_ops->run_buffer_out) {\n-        hw->pcm_ops->run_buffer_out(hw);\n+    if (k->run_buffer_out) {\n+        k->run_buffer_out(hw);\n     }\n \n     return clipped;\n@@ -1077,6 +1082,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)\n \n static void audio_run_out(AudioMixengBackend *s)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n     HWVoiceOut *hw = NULL;\n     SWVoiceOut *sw;\n \n@@ -1092,8 +1098,8 @@ static void audio_run_out(AudioMixengBackend *s)\n             if (hw->pending_disable) {\n                 hw->enabled = false;\n                 hw->pending_disable = false;\n-                if (hw->pcm_ops->enable_out) {\n-                    hw->pcm_ops->enable_out(hw, false);\n+                if (k->enable_out) {\n+                    k->enable_out(hw, false);\n                 }\n             }\n \n@@ -1102,8 +1108,8 @@ static void audio_run_out(AudioMixengBackend *s)\n                                 hw_free * sw->info.bytes_per_frame);\n             }\n \n-            if (hw->pcm_ops->run_buffer_out) {\n-                hw->pcm_ops->run_buffer_out(hw);\n+            if (k->run_buffer_out) {\n+                k->run_buffer_out(hw);\n             }\n \n             continue;\n@@ -1146,8 +1152,8 @@ static void audio_run_out(AudioMixengBackend *s)\n #endif\n             hw->enabled = false;\n             hw->pending_disable = false;\n-            if (hw->pcm_ops->enable_out) {\n-                hw->pcm_ops->enable_out(hw, false);\n+            if (k->enable_out) {\n+                k->enable_out(hw, false);\n             }\n             for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {\n                 sc->sw.active = false;\n@@ -1157,8 +1163,8 @@ static void audio_run_out(AudioMixengBackend *s)\n         }\n \n         if (!live) {\n-            if (hw->pcm_ops->run_buffer_out) {\n-                hw->pcm_ops->run_buffer_out(hw);\n+            if (k->run_buffer_out) {\n+                k->run_buffer_out(hw);\n             }\n             continue;\n         }\n@@ -1202,16 +1208,17 @@ static void audio_run_out(AudioMixengBackend *s)\n \n static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n     size_t conv = 0;\n \n-    if (hw->pcm_ops->run_buffer_in) {\n-        hw->pcm_ops->run_buffer_in(hw);\n+    if (k->run_buffer_in) {\n+        k->run_buffer_in(hw);\n     }\n \n     while (samples) {\n         size_t proc;\n         size_t size = samples * hw->info.bytes_per_frame;\n-        void *buf = hw->pcm_ops->get_buffer_in(hw, &size);\n+        void *buf = k->get_buffer_in(hw, &size);\n \n         assert(size % hw->info.bytes_per_frame == 0);\n         if (size == 0) {\n@@ -1222,7 +1229,7 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)\n \n         samples -= proc;\n         conv += proc;\n-        hw->pcm_ops->put_buffer_in(hw, buf, proc * hw->info.bytes_per_frame);\n+        k->put_buffer_in(hw, buf, proc * hw->info.bytes_per_frame);\n     }\n \n     return conv;\n@@ -1367,6 +1374,8 @@ void audio_run(AudioMixengBackend *s, const char *msg)\n \n void audio_generic_run_buffer_in(HWVoiceIn *hw)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n+\n     if (unlikely(!hw->buf_emul)) {\n         hw->size_emul = hw->samples * hw->info.bytes_per_frame;\n         hw->buf_emul = g_malloc(hw->size_emul);\n@@ -1376,8 +1385,7 @@ void audio_generic_run_buffer_in(HWVoiceIn *hw)\n     while (hw->pending_emul < hw->size_emul) {\n         size_t read_len = MIN(hw->size_emul - hw->pos_emul,\n                               hw->size_emul - hw->pending_emul);\n-        size_t read = hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul,\n-                                        read_len);\n+        size_t read = k->read(hw, hw->buf_emul + hw->pos_emul, read_len);\n         hw->pending_emul += read;\n         hw->pos_emul = (hw->pos_emul + read) % hw->size_emul;\n         if (read < read_len) {\n@@ -1415,6 +1423,8 @@ size_t audio_generic_buffer_get_free(HWVoiceOut *hw)\n \n void audio_generic_run_buffer_out(HWVoiceOut *hw)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n+\n     while (hw->pending_emul) {\n         size_t write_len, written, start;\n \n@@ -1423,7 +1433,7 @@ void audio_generic_run_buffer_out(HWVoiceOut *hw)\n \n         write_len = MIN(hw->pending_emul, hw->size_emul - start);\n \n-        written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);\n+        written = k->write(hw, hw->buf_emul + start, write_len);\n         hw->pending_emul -= written;\n \n         if (written < write_len) {\n@@ -1458,10 +1468,11 @@ size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)\n \n size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n     size_t total = 0;\n \n-    if (hw->pcm_ops->buffer_get_free) {\n-        size_t free = hw->pcm_ops->buffer_get_free(hw);\n+    if (k->buffer_get_free) {\n+        size_t free = k->buffer_get_free(hw);\n \n         size = MIN(size, free);\n     }\n@@ -1469,7 +1480,7 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)\n     while (total < size) {\n         size_t dst_size = size - total;\n         size_t copy_size, proc;\n-        void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);\n+        void *dst = k->get_buffer_out(hw, &dst_size);\n \n         if (dst_size == 0) {\n             break;\n@@ -1479,7 +1490,7 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)\n         if (dst) {\n             memcpy(dst, (char *)buf + total, copy_size);\n         }\n-        proc = hw->pcm_ops->put_buffer_out(hw, dst, copy_size);\n+        proc = k->put_buffer_out(hw, dst, copy_size);\n         total += proc;\n \n         if (proc == 0 || proc < copy_size) {\n@@ -1492,22 +1503,23 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)\n \n size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)\n {\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n     size_t total = 0;\n \n-    if (hw->pcm_ops->run_buffer_in) {\n-        hw->pcm_ops->run_buffer_in(hw);\n+    if (k->run_buffer_in) {\n+        k->run_buffer_in(hw);\n     }\n \n     while (total < size) {\n         size_t src_size = size - total;\n-        void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);\n+        void *src = k->get_buffer_in(hw, &src_size);\n \n         if (src_size == 0) {\n             break;\n         }\n \n         memcpy((char *)buf + total, src, src_size);\n-        hw->pcm_ops->put_buffer_in(hw, src, src_size);\n+        k->put_buffer_in(hw, src, src_size);\n         total += src_size;\n     }\n \n@@ -1521,13 +1533,13 @@ static bool audio_mixeng_backend_realize(AudioBackend *abe,\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(be);\n \n     be->dev = dev;\n-    if (!k->pcm_ops->get_buffer_in) {\n-        k->pcm_ops->get_buffer_in = audio_generic_get_buffer_in;\n-        k->pcm_ops->put_buffer_in = audio_generic_put_buffer_in;\n+    if (!k->get_buffer_in) {\n+        k->get_buffer_in = audio_generic_get_buffer_in;\n+        k->put_buffer_in = audio_generic_put_buffer_in;\n     }\n-    if (!k->pcm_ops->get_buffer_out) {\n-        k->pcm_ops->get_buffer_out = audio_generic_get_buffer_out;\n-        k->pcm_ops->put_buffer_out = audio_generic_put_buffer_out;\n+    if (!k->get_buffer_out) {\n+        k->get_buffer_out = audio_generic_get_buffer_out;\n+        k->put_buffer_out = audio_generic_put_buffer_out;\n     }\n \n     audio_init_nb_voices_out(be, k, 1);\n@@ -1546,18 +1558,19 @@ static void audio_vm_change_state_handler (void *opaque, bool running,\n                                            RunState state)\n {\n     AudioMixengBackend *s = opaque;\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n     HWVoiceOut *hwo = NULL;\n     HWVoiceIn *hwi = NULL;\n \n     while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {\n-        if (hwo->pcm_ops->enable_out) {\n-            hwo->pcm_ops->enable_out(hwo, running);\n+        if (k->enable_out) {\n+            k->enable_out(hwo, running);\n         }\n     }\n \n     while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {\n-        if (hwi->pcm_ops->enable_in) {\n-            hwi->pcm_ops->enable_in(hwi, running);\n+        if (k->enable_in) {\n+            k->enable_in(hwi, running);\n         }\n     }\n     audio_reset_timer (s);\n@@ -1627,16 +1640,17 @@ static void audio_mixeng_backend_init(Object *obj)\n static void audio_mixeng_backend_finalize(Object *obj)\n {\n     AudioMixengBackend *s = AUDIO_MIXENG_BACKEND(obj);\n+    AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(s);\n     HWVoiceOut *hwo, *hwon;\n     HWVoiceIn *hwi, *hwin;\n \n     QLIST_FOREACH_SAFE(hwo, &s->hw_head_out, entries, hwon) {\n         SWVoiceCap *sc;\n \n-        if (hwo->enabled && hwo->pcm_ops->enable_out) {\n-            hwo->pcm_ops->enable_out(hwo, false);\n+        if (hwo->enabled && k->enable_out) {\n+            k->enable_out(hwo, false);\n         }\n-        hwo->pcm_ops->fini_out (hwo);\n+        k->fini_out(hwo);\n \n         for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {\n             CaptureVoiceOut *cap = sc->cap;\n@@ -1650,10 +1664,10 @@ static void audio_mixeng_backend_finalize(Object *obj)\n     }\n \n     QLIST_FOREACH_SAFE(hwi, &s->hw_head_in, entries, hwin) {\n-        if (hwi->enabled && hwi->pcm_ops->enable_in) {\n-            hwi->pcm_ops->enable_in(hwi, false);\n+        if (hwi->enabled && k->enable_in) {\n+            k->enable_in(hwi, false);\n         }\n-        hwi->pcm_ops->fini_in (hwi);\n+        k->fini_in(hwi);\n         QLIST_REMOVE(hwi, entries);\n     }\n \n@@ -1694,8 +1708,6 @@ static const VMStateDescription vmstate_audio = {\n     }\n };\n \n-static struct audio_pcm_ops capture_pcm_ops;\n-\n static CaptureVoiceOut *audio_mixeng_backend_add_capture(\n     AudioBackend *be,\n     struct audsettings *as,\n@@ -1736,7 +1748,6 @@ static CaptureVoiceOut *audio_mixeng_backend_add_capture(\n \n         hw = &cap->hw;\n         hw->s = s;\n-        hw->pcm_ops = &capture_pcm_ops;\n         QLIST_INIT (&hw->sw_head);\n         QLIST_INIT (&cap->cb_head);\n \n@@ -1817,14 +1828,15 @@ static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw\n {\n     if (sw) {\n         HWVoiceOut *hw = sw->hw;\n+        AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n \n         sw->vol.mute = vol->mute;\n         sw->vol.l = nominal_volume.l * vol->vol[0] / 255;\n         sw->vol.r = nominal_volume.l * vol->vol[vol->channels > 1 ? 1 : 0] /\n             255;\n \n-        if (hw->pcm_ops->volume_out) {\n-            hw->pcm_ops->volume_out(hw, vol);\n+        if (k->volume_out) {\n+            k->volume_out(hw, vol);\n         }\n     }\n }\n@@ -1834,14 +1846,15 @@ static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,\n {\n     if (sw) {\n         HWVoiceIn *hw = sw->hw;\n+        AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s);\n \n         sw->vol.mute = vol->mute;\n         sw->vol.l = nominal_volume.l * vol->vol[0] / 255;\n         sw->vol.r = nominal_volume.r * vol->vol[vol->channels > 1 ? 1 : 0] /\n             255;\n \n-        if (hw->pcm_ops->volume_in) {\n-            hw->pcm_ops->volume_in(hw, vol);\n+        if (k->volume_in) {\n+            k->volume_in(hw, vol);\n         }\n     }\n }\ndiff --git a/audio/dbusaudio.c b/audio/dbusaudio.c\nindex 82e76c41f9f..d8e548bf469 100644\n--- a/audio/dbusaudio.c\n+++ b/audio/dbusaudio.c\n@@ -691,23 +691,6 @@ dbus_audio_set_server(AudioBackend *s,\n     return true;\n }\n \n-static struct audio_pcm_ops dbus_pcm_ops = {\n-    .init_out = dbus_init_out,\n-    .fini_out = dbus_fini_out,\n-    .write    = audio_generic_write,\n-    .get_buffer_out = dbus_get_buffer_out,\n-    .put_buffer_out = dbus_put_buffer_out,\n-    .enable_out = dbus_enable_out,\n-    .volume_out = dbus_volume_out,\n-\n-    .init_in  = dbus_init_in,\n-    .fini_in  = dbus_fini_in,\n-    .read     = dbus_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = dbus_enable_in,\n-    .volume_in = dbus_volume_in,\n-};\n-\n static void audio_dbus_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -718,11 +701,25 @@ static void audio_dbus_class_init(ObjectClass *klass, const void *data)\n     b->realize = audio_dbus_realize;\n     b->set_dbus_server = dbus_audio_set_server;\n     k->name = \"dbus\";\n-    k->pcm_ops = &dbus_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(DBusVoiceOut);\n     k->voice_size_in = sizeof(DBusVoiceIn);\n+\n+    k->init_out = dbus_init_out;\n+    k->fini_out = dbus_fini_out;\n+    k->write = audio_generic_write;\n+    k->get_buffer_out = dbus_get_buffer_out;\n+    k->put_buffer_out = dbus_put_buffer_out;\n+    k->enable_out = dbus_enable_out;\n+    k->volume_out = dbus_volume_out;\n+\n+    k->init_in = dbus_init_in;\n+    k->fini_in = dbus_fini_in;\n+    k->read = dbus_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = dbus_enable_in;\n+    k->volume_in = dbus_volume_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c\nindex e35b7fc233f..2c592c56663 100644\n--- a/audio/dsoundaudio.c\n+++ b/audio/dsoundaudio.c\n@@ -667,23 +667,6 @@ audio_dsound_realize(AudioBackend *abe, Audiodev *dev, Error **errp)\n     return true;\n }\n \n-static struct audio_pcm_ops dsound_pcm_ops = {\n-    .init_out = dsound_init_out,\n-    .fini_out = dsound_fini_out,\n-    .write    = audio_generic_write,\n-    .buffer_get_free = dsound_buffer_get_free,\n-    .get_buffer_out = dsound_get_buffer_out,\n-    .put_buffer_out = dsound_put_buffer_out,\n-    .enable_out = dsound_enable_out,\n-\n-    .init_in  = dsound_init_in,\n-    .fini_in  = dsound_fini_in,\n-    .read     = audio_generic_read,\n-    .get_buffer_in = dsound_get_buffer_in,\n-    .put_buffer_in = dsound_put_buffer_in,\n-    .enable_in = dsound_enable_in,\n-};\n-\n static void audio_dsound_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -693,11 +676,25 @@ static void audio_dsound_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_dsound_realize;\n     k->name = \"dsound\";\n-    k->pcm_ops = &dsound_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = 1;\n     k->voice_size_out = sizeof(DSoundVoiceOut);\n     k->voice_size_in = sizeof(DSoundVoiceIn);\n+\n+    k->init_out = dsound_init_out;\n+    k->fini_out = dsound_fini_out;\n+    k->write = audio_generic_write;\n+    k->buffer_get_free = dsound_buffer_get_free;\n+    k->get_buffer_out = dsound_get_buffer_out;\n+    k->put_buffer_out = dsound_put_buffer_out;\n+    k->enable_out = dsound_enable_out;\n+\n+    k->init_in = dsound_init_in;\n+    k->fini_in = dsound_fini_in;\n+    k->read = audio_generic_read;\n+    k->get_buffer_in = dsound_get_buffer_in;\n+    k->put_buffer_in = dsound_put_buffer_in;\n+    k->enable_in = dsound_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/jackaudio.c b/audio/jackaudio.c\nindex 7caa2ddf43f..e415e94e6e6 100644\n--- a/audio/jackaudio.c\n+++ b/audio/jackaudio.c\n@@ -652,21 +652,6 @@ static int qjack_thread_creator(jack_native_thread_t *thread,\n }\n #endif\n \n-static struct audio_pcm_ops jack_pcm_ops = {\n-    .init_out       = qjack_init_out,\n-    .fini_out       = qjack_fini_out,\n-    .write          = qjack_write,\n-    .buffer_get_free = audio_generic_buffer_get_free,\n-    .run_buffer_out = audio_generic_run_buffer_out,\n-    .enable_out     = qjack_enable_out,\n-\n-    .init_in        = qjack_init_in,\n-    .fini_in        = qjack_fini_in,\n-    .read           = qjack_read,\n-    .run_buffer_in  = audio_generic_run_buffer_in,\n-    .enable_in      = qjack_enable_in\n-};\n-\n static void qjack_error(const char *msg)\n {\n     dolog(\"E: %s\\n\", msg);\n@@ -682,11 +667,23 @@ static void audio_jack_class_init(ObjectClass *klass, const void *data)\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);\n \n     k->name = \"jack\";\n-    k->pcm_ops = &jack_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(QJackOut);\n     k->voice_size_in = sizeof(QJackIn);\n+\n+    k->init_out = qjack_init_out;\n+    k->fini_out = qjack_fini_out;\n+    k->write = qjack_write;\n+    k->buffer_get_free = audio_generic_buffer_get_free;\n+    k->run_buffer_out = audio_generic_run_buffer_out;\n+    k->enable_out = qjack_enable_out;\n+\n+    k->init_in = qjack_init_in;\n+    k->fini_in = qjack_fini_in;\n+    k->read = qjack_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = qjack_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/noaudio.c b/audio/noaudio.c\nindex be2e2e684ce..e056813181a 100644\n--- a/audio/noaudio.c\n+++ b/audio/noaudio.c\n@@ -110,31 +110,28 @@ static void no_enable_in(HWVoiceIn *hw, bool enable)\n     }\n }\n \n-static struct audio_pcm_ops no_pcm_ops = {\n-    .init_out = no_init_out,\n-    .fini_out = no_fini_out,\n-    .write    = no_write,\n-    .buffer_get_free = audio_generic_buffer_get_free,\n-    .run_buffer_out = audio_generic_run_buffer_out,\n-    .enable_out = no_enable_out,\n-\n-    .init_in  = no_init_in,\n-    .fini_in  = no_fini_in,\n-    .read     = no_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = no_enable_in\n-};\n-\n static void audio_none_class_init(ObjectClass *klass, const void *data)\n {\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);\n \n     k->name = \"none\";\n-    k->pcm_ops = &no_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(NoVoiceOut);\n     k->voice_size_in = sizeof(NoVoiceIn);\n+\n+    k->init_out = no_init_out;\n+    k->fini_out = no_fini_out;\n+    k->write = no_write;\n+    k->buffer_get_free = audio_generic_buffer_get_free;\n+    k->run_buffer_out = audio_generic_run_buffer_out;\n+    k->enable_out = no_enable_out;\n+\n+    k->init_in = no_init_in;\n+    k->fini_in = no_fini_in;\n+    k->read = no_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = no_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/ossaudio.c b/audio/ossaudio.c\nindex 0ad974e20cc..d12c65dd0d7 100644\n--- a/audio/ossaudio.c\n+++ b/audio/ossaudio.c\n@@ -755,23 +755,6 @@ audio_oss_realize(AudioBackend *abe, Audiodev *dev, Error **errp)\n     return audio_oss_parent_class->realize(abe, dev, errp);\n }\n \n-static struct audio_pcm_ops oss_pcm_ops = {\n-    .init_out = oss_init_out,\n-    .fini_out = oss_fini_out,\n-    .write    = oss_write,\n-    .buffer_get_free = oss_buffer_get_free,\n-    .run_buffer_out = oss_run_buffer_out,\n-    .get_buffer_out = oss_get_buffer_out,\n-    .put_buffer_out = oss_put_buffer_out,\n-    .enable_out = oss_enable_out,\n-\n-    .init_in  = oss_init_in,\n-    .fini_in  = oss_fini_in,\n-    .read     = oss_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = oss_enable_in\n-};\n-\n static void audio_oss_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -781,11 +764,25 @@ static void audio_oss_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_oss_realize;\n     k->name = \"oss\";\n-    k->pcm_ops = &oss_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(OSSVoiceOut);\n     k->voice_size_in = sizeof(OSSVoiceIn);\n+\n+    k->init_out = oss_init_out;\n+    k->fini_out = oss_fini_out;\n+    k->write = oss_write;\n+    k->buffer_get_free = oss_buffer_get_free;\n+    k->run_buffer_out = oss_run_buffer_out;\n+    k->get_buffer_out = oss_get_buffer_out;\n+    k->put_buffer_out = oss_put_buffer_out;\n+    k->enable_out = oss_enable_out;\n+\n+    k->init_in = oss_init_in;\n+    k->fini_in = oss_fini_in;\n+    k->read = oss_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = oss_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/paaudio.c b/audio/paaudio.c\nindex 5758050cb55..b7826402e12 100644\n--- a/audio/paaudio.c\n+++ b/audio/paaudio.c\n@@ -913,23 +913,6 @@ static void audio_pa_finalize(Object *obj)\n     }\n }\n \n-static struct audio_pcm_ops qpa_pcm_ops = {\n-    .init_out = qpa_init_out,\n-    .fini_out = qpa_fini_out,\n-    .write    = qpa_write,\n-    .buffer_get_free = qpa_buffer_get_free,\n-    .get_buffer_out = qpa_get_buffer_out,\n-    .put_buffer_out = qpa_put_buffer_out,\n-    .volume_out = qpa_volume_out,\n-\n-    .init_in  = qpa_init_in,\n-    .fini_in  = qpa_fini_in,\n-    .read     = qpa_read,\n-    .get_buffer_in = qpa_get_buffer_in,\n-    .put_buffer_in = qpa_put_buffer_in,\n-    .volume_in = qpa_volume_in\n-};\n-\n static void audio_pa_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -939,11 +922,25 @@ static void audio_pa_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_pa_realize;\n     k->name = \"pa\";\n-    k->pcm_ops = &qpa_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(PAVoiceOut);\n     k->voice_size_in = sizeof(PAVoiceIn);\n+\n+    k->init_out = qpa_init_out;\n+    k->fini_out = qpa_fini_out;\n+    k->write = qpa_write;\n+    k->buffer_get_free = qpa_buffer_get_free;\n+    k->get_buffer_out = qpa_get_buffer_out;\n+    k->put_buffer_out = qpa_put_buffer_out;\n+    k->volume_out = qpa_volume_out;\n+\n+    k->init_in = qpa_init_in;\n+    k->fini_in = qpa_fini_in;\n+    k->read = qpa_read;\n+    k->get_buffer_in = qpa_get_buffer_in;\n+    k->put_buffer_in = qpa_put_buffer_in;\n+    k->volume_in = qpa_volume_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/pwaudio.c b/audio/pwaudio.c\nindex f7f7dfbe0ad..7a009a94f3a 100644\n--- a/audio/pwaudio.c\n+++ b/audio/pwaudio.c\n@@ -822,23 +822,6 @@ audio_pw_finalize(Object *obj)\n     g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);\n }\n \n-static struct audio_pcm_ops qpw_pcm_ops = {\n-    .init_out = qpw_init_out,\n-    .fini_out = qpw_fini_out,\n-    .write = qpw_write,\n-    .buffer_get_free = qpw_buffer_get_free,\n-    .run_buffer_out = audio_generic_run_buffer_out,\n-    .enable_out = qpw_enable_out,\n-    .volume_out = qpw_volume_out,\n-    .volume_in = qpw_volume_in,\n-\n-    .init_in = qpw_init_in,\n-    .fini_in = qpw_fini_in,\n-    .read = qpw_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = qpw_enable_in\n-};\n-\n static void audio_pw_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -848,11 +831,25 @@ static void audio_pw_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_pw_realize;\n     k->name = \"pipewire\";\n-    k->pcm_ops = &qpw_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(PWVoiceOut);\n     k->voice_size_in = sizeof(PWVoiceIn);\n+\n+    k->init_out = qpw_init_out;\n+    k->fini_out = qpw_fini_out;\n+    k->write = qpw_write;\n+    k->buffer_get_free = qpw_buffer_get_free;\n+    k->run_buffer_out = audio_generic_run_buffer_out;\n+    k->enable_out = qpw_enable_out;\n+    k->volume_out = qpw_volume_out;\n+\n+    k->init_in = qpw_init_in;\n+    k->fini_in = qpw_fini_in;\n+    k->read = qpw_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = qpw_enable_in;\n+    k->volume_in = qpw_volume_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/sdlaudio.c b/audio/sdlaudio.c\nindex 62f7ac8d76b..d974d7eac46 100644\n--- a/audio/sdlaudio.c\n+++ b/audio/sdlaudio.c\n@@ -468,29 +468,6 @@ static void audio_sdl_finalize(Object *obj)\n     SDL_QuitSubSystem(SDL_INIT_AUDIO);\n }\n \n-static struct audio_pcm_ops sdl_pcm_ops = {\n-    .init_out = sdl_init_out,\n-    .fini_out = sdl_fini_out,\n-  /* wrapper for audio_generic_write */\n-    .write    = sdl_write,\n-  /* wrapper for audio_generic_buffer_get_free */\n-    .buffer_get_free = sdl_buffer_get_free,\n-  /* wrapper for audio_generic_get_buffer_out */\n-    .get_buffer_out = sdl_get_buffer_out,\n-  /* wrapper for audio_generic_put_buffer_out */\n-    .put_buffer_out = sdl_put_buffer_out,\n-    .enable_out = sdl_enable_out,\n-    .init_in = sdl_init_in,\n-    .fini_in = sdl_fini_in,\n-  /* wrapper for audio_generic_read */\n-    .read = sdl_read,\n-  /* wrapper for audio_generic_get_buffer_in */\n-    .get_buffer_in = sdl_get_buffer_in,\n-  /* wrapper for audio_generic_put_buffer_in */\n-    .put_buffer_in = sdl_put_buffer_in,\n-    .enable_in = sdl_enable_in,\n-};\n-\n static void audio_sdl_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -500,11 +477,32 @@ static void audio_sdl_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = audio_sdl_realize;\n     k->name = \"sdl\";\n-    k->pcm_ops = &sdl_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(SDLVoiceOut);\n     k->voice_size_in = sizeof(SDLVoiceIn);\n+\n+    k->init_out = sdl_init_out;\n+    k->fini_out = sdl_fini_out;\n+    /* wrapper for audio_generic_write */\n+    k->write = sdl_write;\n+    /* wrapper for audio_generic_buffer_get_free */\n+    k->buffer_get_free = sdl_buffer_get_free;\n+    /* wrapper for audio_generic_get_buffer_out */\n+    k->get_buffer_out = sdl_get_buffer_out;\n+    /* wrapper for audio_generic_put_buffer_out */\n+    k->put_buffer_out = sdl_put_buffer_out;\n+    k->enable_out = sdl_enable_out;\n+\n+    k->init_in = sdl_init_in;\n+    k->fini_in = sdl_fini_in;\n+    /* wrapper for audio_generic_read */\n+    k->read = sdl_read;\n+    /* wrapper for audio_generic_get_buffer_in */\n+    k->get_buffer_in = sdl_get_buffer_in;\n+    /* wrapper for audio_generic_put_buffer_in */\n+    k->put_buffer_in = sdl_put_buffer_in;\n+    k->enable_in = sdl_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/sndioaudio.c b/audio/sndioaudio.c\nindex 5cd6250775b..21f43836fd1 100644\n--- a/audio/sndioaudio.c\n+++ b/audio/sndioaudio.c\n@@ -527,32 +527,30 @@ static void sndio_fini_in(HWVoiceIn *hw)\n     sndio_fini(self);\n }\n \n-static struct audio_pcm_ops sndio_pcm_ops = {\n-    .init_out        = sndio_init_out,\n-    .fini_out        = sndio_fini_out,\n-    .enable_out      = sndio_enable_out,\n-    .write           = audio_generic_write,\n-    .buffer_get_free = sndio_buffer_get_free,\n-    .get_buffer_out  = sndio_get_buffer_out,\n-    .put_buffer_out  = sndio_put_buffer_out,\n-    .init_in         = sndio_init_in,\n-    .fini_in         = sndio_fini_in,\n-    .read            = audio_generic_read,\n-    .enable_in       = sndio_enable_in,\n-    .get_buffer_in   = sndio_get_buffer_in,\n-    .put_buffer_in   = sndio_put_buffer_in,\n-};\n-\n static void audio_sndio_class_init(ObjectClass *klass, const void *data)\n {\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);\n \n     k->name = \"sndio\";\n-    k->pcm_ops = &sndio_pcm_ops;\n     k->max_voices_out = INT_MAX;\n     k->max_voices_in = INT_MAX;\n     k->voice_size_out = sizeof(SndioVoice);\n     k->voice_size_in = sizeof(SndioVoice);\n+\n+    k->init_out = sndio_init_out;\n+    k->fini_out = sndio_fini_out;\n+    k->write = audio_generic_write;\n+    k->buffer_get_free = sndio_buffer_get_free;\n+    k->get_buffer_out = sndio_get_buffer_out;\n+    k->put_buffer_out = sndio_put_buffer_out;\n+    k->enable_out = sndio_enable_out;\n+\n+    k->init_in = sndio_init_in;\n+    k->fini_in = sndio_fini_in;\n+    k->read = audio_generic_read;\n+    k->get_buffer_in = sndio_get_buffer_in;\n+    k->put_buffer_in = sndio_put_buffer_in;\n+    k->enable_in = sndio_enable_in;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/spiceaudio.c b/audio/spiceaudio.c\nindex 995e0f6faa3..0d188e974df 100644\n--- a/audio/spiceaudio.c\n+++ b/audio/spiceaudio.c\n@@ -296,29 +296,6 @@ static void line_in_volume(HWVoiceIn *hw, Volume *vol)\n }\n #endif\n \n-static struct audio_pcm_ops audio_callbacks = {\n-    .init_out = line_out_init,\n-    .fini_out = line_out_fini,\n-    .write    = audio_generic_write,\n-    .buffer_get_free = line_out_get_free,\n-    .get_buffer_out = line_out_get_buffer,\n-    .put_buffer_out = line_out_put_buffer,\n-    .enable_out = line_out_enable,\n-#if (SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && \\\n-        (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)\n-    .volume_out = line_out_volume,\n-#endif\n-\n-    .init_in  = line_in_init,\n-    .fini_in  = line_in_fini,\n-    .read     = line_in_read,\n-    .run_buffer_in = audio_generic_run_buffer_in,\n-    .enable_in = line_in_enable,\n-#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))\n-    .volume_in = line_in_volume,\n-#endif\n-};\n-\n static void audio_spice_class_init(ObjectClass *klass, const void *data)\n {\n     AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);\n@@ -328,11 +305,31 @@ static void audio_spice_class_init(ObjectClass *klass, const void *data)\n \n     b->realize = spice_audio_realize;\n     k->name = \"spice\";\n-    k->pcm_ops = &audio_callbacks;\n     k->max_voices_out = 1;\n     k->max_voices_in = 1;\n     k->voice_size_out = sizeof(SpiceVoiceOut);\n     k->voice_size_in = sizeof(SpiceVoiceIn);\n+\n+    k->init_out = line_out_init;\n+    k->fini_out = line_out_fini;\n+    k->write = audio_generic_write;\n+    k->buffer_get_free = line_out_get_free;\n+    k->get_buffer_out = line_out_get_buffer;\n+    k->put_buffer_out = line_out_put_buffer;\n+    k->enable_out = line_out_enable;\n+#if (SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && \\\n+        (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)\n+    k->volume_out = line_out_volume;\n+#endif\n+\n+    k->init_in = line_in_init;\n+    k->fini_in = line_in_fini;\n+    k->read = line_in_read;\n+    k->run_buffer_in = audio_generic_run_buffer_in;\n+    k->enable_in = line_in_enable;\n+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))\n+    k->volume_in = line_in_volume;\n+#endif\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/wavaudio.c b/audio/wavaudio.c\nindex 153e50fa0be..ade8fd1d8c3 100644\n--- a/audio/wavaudio.c\n+++ b/audio/wavaudio.c\n@@ -190,25 +190,22 @@ static void wav_enable_out(HWVoiceOut *hw, bool enable)\n     }\n }\n \n-static struct audio_pcm_ops wav_pcm_ops = {\n-    .init_out = wav_init_out,\n-    .fini_out = wav_fini_out,\n-    .write    = wav_write_out,\n-    .buffer_get_free = audio_generic_buffer_get_free,\n-    .run_buffer_out = audio_generic_run_buffer_out,\n-    .enable_out = wav_enable_out,\n-};\n-\n static void audio_wav_class_init(ObjectClass *klass, const void *data)\n {\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);\n \n     k->name = \"wav\";\n-    k->pcm_ops = &wav_pcm_ops;\n     k->max_voices_out = 1;\n     k->max_voices_in = 0;\n     k->voice_size_out = sizeof(WAVVoiceOut);\n     k->voice_size_in = 0;\n+\n+    k->init_out = wav_init_out;\n+    k->fini_out = wav_fini_out;\n+    k->write = wav_write_out;\n+    k->buffer_get_free = audio_generic_buffer_get_free;\n+    k->run_buffer_out = audio_generic_run_buffer_out;\n+    k->enable_out = wav_enable_out;\n }\n \n static const TypeInfo audio_types[] = {\ndiff --git a/audio/coreaudio.m b/audio/coreaudio.m\nindex e9274976f94..561c08f47c1 100644\n--- a/audio/coreaudio.m\n+++ b/audio/coreaudio.m\n@@ -646,30 +646,27 @@ static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)\n     update_device_playback_state(core);\n }\n \n-static struct audio_pcm_ops coreaudio_pcm_ops = {\n-    .init_out = coreaudio_init_out,\n-    .fini_out = coreaudio_fini_out,\n-  /* wrapper for audio_generic_write */\n-    .write    = coreaudio_write,\n-  /* wrapper for audio_generic_buffer_get_free */\n-    .buffer_get_free = coreaudio_buffer_get_free,\n-  /* wrapper for audio_generic_get_buffer_out */\n-    .get_buffer_out = coreaudio_get_buffer_out,\n-  /* wrapper for audio_generic_put_buffer_out */\n-    .put_buffer_out = coreaudio_put_buffer_out,\n-    .enable_out = coreaudio_enable_out\n-};\n-\n static void audio_coreaudio_class_init(ObjectClass *klass, const void *data)\n {\n     AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);\n \n     k->name = \"coreaudio\";\n-    k->pcm_ops = &coreaudio_pcm_ops;\n     k->max_voices_out = 1;\n     k->max_voices_in = 0;\n     k->voice_size_out = sizeof(coreaudioVoiceOut);\n     k->voice_size_in = 0;\n+\n+    k->init_out = coreaudio_init_out;\n+    k->fini_out = coreaudio_fini_out;\n+    /* wrapper for audio_generic_write */\n+    k->write = coreaudio_write;\n+    /* wrapper for audio_generic_buffer_get_free */\n+    k->buffer_get_free = coreaudio_buffer_get_free;\n+    /* wrapper for audio_generic_get_buffer_out */\n+    k->get_buffer_out = coreaudio_get_buffer_out;\n+    /* wrapper for audio_generic_put_buffer_out */\n+    k->put_buffer_out = coreaudio_put_buffer_out;\n+    k->enable_out = coreaudio_enable_out;\n }\n \n static const TypeInfo audio_types[] = {\n",
    "prefixes": [
        "57/85"
    ]
}