@samitouri / QOSamiQemu / commits / 25153b29f8

audio: split AudioBackend

Code clean-up, to allow building bare abstract class separately. The original file is MIT-licensed. Reviewed-by: Mark Cave-Ayland <mark.caveayland@nutanix.com> Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Marc-André Lureau committed Nov 10, 2025 at 14:25 UTC 25153b29f8307ffe403289a92150e4d7b0b134c5
4 files changed +211 -207
audio/audio-be.c new
+206
@@ -0,0 +1,206 @@
1 +/* SPDX-License-Identifier: MIT */
2 +
3 +#include "qemu/osdep.h"
4 +#include "qemu/audio.h"
5 +#include "qemu/audio-capture.h"
6 +#include "qapi/error.h"
7 +
8 +bool AUD_backend_check(AudioBackend **be, Error **errp)
9 +{
10 + assert(be != NULL);
11 +
12 + if (!*be) {
13 + *be = audio_get_default_audio_be(errp);
14 + if (!*be) {
15 + return false;
16 + }
17 + }
18 +
19 + return true;
20 +}
21 +
22 +SWVoiceIn *AUD_open_in(
23 + AudioBackend *be,
24 + SWVoiceIn *sw,
25 + const char *name,
26 + void *callback_opaque,
27 + audio_callback_fn callback_fn,
28 + const struct audsettings *as)
29 +{
30 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
31 +
32 + return klass->open_in(be, sw, name, callback_opaque, callback_fn, as);
33 +}
34 +
35 +SWVoiceOut *AUD_open_out(
36 + AudioBackend *be,
37 + SWVoiceOut *sw,
38 + const char *name,
39 + void *callback_opaque,
40 + audio_callback_fn callback_fn,
41 + const struct audsettings *as)
42 +{
43 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
44 +
45 + return klass->open_out(be, sw, name, callback_opaque, callback_fn, as);
46 +}
47 +
48 +void AUD_close_out(AudioBackend *be, SWVoiceOut *sw)
49 +{
50 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
51 +
52 + return klass->close_out(be, sw);
53 +}
54 +
55 +void AUD_close_in(AudioBackend *be, SWVoiceIn *sw)
56 +{
57 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
58 +
59 + return klass->close_in(be, sw);
60 +}
61 +
62 +bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw)
63 +{
64 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
65 +
66 + return klass->is_active_out(be, sw);
67 +}
68 +
69 +bool AUD_is_active_in(AudioBackend *be, SWVoiceIn *sw)
70 +{
71 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
72 +
73 + return klass->is_active_in(be, sw);
74 +}
75 +
76 +size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
77 +{
78 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
79 +
80 + return klass->write(be, sw, buf, size);
81 +}
82 +
83 +size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
84 +{
85 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
86 +
87 + return klass->read(be, sw, buf, size);
88 +}
89 +
90 +int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
91 +{
92 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
93 +
94 + return klass->get_buffer_size_out(be, sw);
95 +}
96 +
97 +void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
98 +{
99 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
100 +
101 + return klass->set_active_out(be, sw, on);
102 +}
103 +
104 +void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
105 +{
106 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
107 +
108 + return klass->set_active_in(be, sw, on);
109 +}
110 +
111 +void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
112 +{
113 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
114 +
115 + klass->set_volume_out(be, sw, vol);
116 +}
117 +
118 +void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
119 +{
120 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
121 +
122 + klass->set_volume_in(be, sw, vol);
123 +}
124 +
125 +CaptureVoiceOut *AUD_add_capture(
126 + AudioBackend *be,
127 + struct audsettings *as,
128 + struct audio_capture_ops *ops,
129 + void *cb_opaque)
130 +{
131 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
132 +
133 + return klass->add_capture(be, as, ops, cb_opaque);
134 +}
135 +
136 +void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
137 +{
138 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
139 +
140 + klass->del_capture(be, cap, cb_opaque);
141 +}
142 +
143 +#ifdef CONFIG_GIO
144 +bool audio_be_can_set_dbus_server(AudioBackend *be)
145 +{
146 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
147 +
148 + return klass->set_dbus_server != NULL;
149 +}
150 +
151 +bool audio_be_set_dbus_server(AudioBackend *be,
152 + GDBusObjectManagerServer *server,
153 + bool p2p,
154 + Error **errp)
155 +{
156 + AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
157 +
158 + if (!audio_be_can_set_dbus_server(be)) {
159 + error_setg(errp, "Audiodev '%s' is not compatible with DBus",
160 + audio_be_get_id(be));
161 + return false;
162 + }
163 +
164 + return klass->set_dbus_server(be, server, p2p, errp);
165 +}
166 +#endif
167 +
168 +const char *audio_be_get_id(AudioBackend *be)
169 +{
170 + if (be) {
171 + return AUDIO_BACKEND_GET_CLASS(be)->get_id(be);
172 + } else {
173 + return "";
174 + }
175 +}
176 +
177 +AudioBackend *audio_be_new(Audiodev *dev, Error **errp)
178 +{
179 + const char *drvname = AudiodevDriver_str(dev->driver);
180 + g_autofree char *type = g_strconcat("audio-", drvname, NULL);
181 + AudioBackend *be = AUDIO_BACKEND(object_new(type));
182 +
183 + if (!be) {
184 + error_setg(errp, "Unknown audio driver `%s'", drvname);
185 + return NULL;
186 + }
187 +
188 + if (!AUDIO_BACKEND_GET_CLASS(be)->realize(be, dev, errp)) {
189 + object_unref(OBJECT(be));
190 + return NULL;
191 + }
192 +
193 + return be;
194 +}
195 +
196 +static const TypeInfo audio_types[] = {
197 + {
198 + .name = TYPE_AUDIO_BACKEND,
199 + .parent = TYPE_OBJECT,
200 + .instance_size = sizeof(AudioBackend),
201 + .abstract = true,
202 + .class_size = sizeof(AudioBackendClass),
203 + },
204 +};
205 +
206 +DEFINE_TYPES(audio_types)
audio/audio.c
+2 -207
@@ -870,15 +870,8 @@ static size_t audio_mixeng_backend_write(AudioBackend *be, SWVoiceOut *sw,
870 }
871 }
872
873 -size_t AUD_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
874 -{
875 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
876 -
877 - return klass->write(be, sw, buf, size);
878 -}
879 -
880 -static size_t audio_mixeng_backend_read(AudioBackend *be, SWVoiceIn *sw,
881 - void *buf, size_t size)
873 +static size_t audio_mixeng_backend_read(AudioBackend *be,
874 + SWVoiceIn *sw, void *buf, size_t size)
875 {
876 HWVoiceIn *hw;
877
@@ -901,13 +894,6 @@ static size_t audio_mixeng_backend_read(AudioBackend *be, SWVoiceIn *sw,
894
895 }
896
904 -size_t AUD_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
905 -{
906 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
907 -
908 - return klass->read(be, sw, buf, size);
909 -}
910 -
897 static int audio_mixeng_backend_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
898 {
899 if (!sw) {
@@ -921,13 +907,6 @@ static int audio_mixeng_backend_get_buffer_size_out(AudioBackend *be, SWVoiceOut
907 return sw->hw->samples * sw->hw->info.bytes_per_frame;
908 }
909
924 -int AUD_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
925 -{
926 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
927 -
928 - return klass->get_buffer_size_out(be, sw);
929 -}
930 -
910 static void audio_mixeng_backend_set_active_out(AudioBackend *be, SWVoiceOut *sw,
911 bool on)
912 {
@@ -978,13 +957,6 @@ static void audio_mixeng_backend_set_active_out(AudioBackend *be, SWVoiceOut *sw
957
958 }
959
981 -void AUD_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
982 -{
983 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
984 -
985 - return klass->set_active_out(be, sw, on);
986 -}
987 -
960 static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
961 {
962 HWVoiceIn *hw;
@@ -1030,13 +1002,6 @@ static void audio_mixeng_backend_set_active_in(AudioBackend *be, SWVoiceIn *sw,
1002 }
1003 }
1004
1033 -void AUD_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
1034 -{
1035 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1036 -
1037 - return klass->set_active_in(be, sw, on);
1038 -}
1039 -
1005 static size_t audio_get_avail(SWVoiceIn *sw)
1006 {
1007 size_t live;
@@ -1643,25 +1608,6 @@ static bool audio_mixeng_backend_realize(AudioBackend *abe,
1608 return true;
1609 }
1610
1646 -static AudioBackend *audio_be_new(Audiodev *dev, Error **errp)
1647 -{
1648 - const char *drvname = AudiodevDriver_str(dev->driver);
1649 - g_autofree char *type = g_strconcat("audio-", drvname, NULL);
1650 - AudioBackend *be = AUDIO_BACKEND(object_new(type));
1651 -
1652 - if (!be) {
1653 - error_setg(errp, "Unknown audio driver `%s'", drvname);
1654 - return NULL;
1655 - }
1656 -
1657 - if (!AUDIO_BACKEND_GET_CLASS(be)->realize(be, dev, errp)) {
1658 - object_unref(OBJECT(be));
1659 - return NULL;
1660 - }
1661 -
1662 - return be;
1663 -}
1664 -
1611 static void audio_vm_change_state_handler (void *opaque, bool running,
1612 RunState state)
1613 {
@@ -1685,14 +1631,6 @@ static void audio_vm_change_state_handler (void *opaque, bool running,
1631
1632 static const VMStateDescription vmstate_audio;
1633
1688 -static void audio_be_init(Object *obj)
1689 -{
1690 -}
1691 -
1692 -static void audio_be_finalize(Object *obj)
1693 -{
1694 -}
1695 -
1634 static const char *audio_mixeng_backend_get_id(AudioBackend *be)
1635 {
1636 return AUDIO_MIXENG_BACKEND(be)->dev->id;
@@ -1714,60 +1652,6 @@ static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw
1652 static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
1653 Volume *vol);
1654
1717 -SWVoiceOut *AUD_open_out(
1718 - AudioBackend *be,
1719 - SWVoiceOut *sw,
1720 - const char *name,
1721 - void *callback_opaque,
1722 - audio_callback_fn callback_fn,
1723 - const struct audsettings *as)
1724 -{
1725 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1726 -
1727 - return klass->open_out(be, sw, name, callback_opaque, callback_fn, as);
1728 -}
1729 -
1730 -SWVoiceIn *AUD_open_in(
1731 - AudioBackend *be,
1732 - SWVoiceIn *sw,
1733 - const char *name,
1734 - void *callback_opaque,
1735 - audio_callback_fn callback_fn,
1736 - const struct audsettings *as)
1737 -{
1738 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1739 -
1740 - return klass->open_in(be, sw, name, callback_opaque, callback_fn, as);
1741 -}
1742 -
1743 -void AUD_close_out(AudioBackend *be, SWVoiceOut *sw)
1744 -{
1745 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1746 -
1747 - return klass->close_out(be, sw);
1748 -}
1749 -
1750 -void AUD_close_in(AudioBackend *be, SWVoiceIn *sw)
1751 -{
1752 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1753 -
1754 - return klass->close_in(be, sw);
1755 -}
1756 -
1757 -bool AUD_is_active_out(AudioBackend *be, SWVoiceOut *sw)
1758 -{
1759 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1760 -
1761 - return klass->is_active_out(be, sw);
1762 -}
1763 -
1764 -bool AUD_is_active_in(AudioBackend *be, SWVoiceIn *sw)
1765 -{
1766 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
1767 -
1768 - return klass->is_active_in(be, sw);
1769 -}
1770 -
1655 static void audio_mixeng_backend_class_init(ObjectClass *klass, const void *data)
1656 {
1657 AudioBackendClass *be = AUDIO_BACKEND_CLASS(klass);
@@ -1972,20 +1856,6 @@ AudioBackend *audio_get_default_audio_be(Error **errp)
1856 return default_audio_be;
1857 }
1858
1975 -bool AUD_backend_check(AudioBackend **be, Error **errp)
1976 -{
1977 - assert(be != NULL);
1978 -
1979 - if (!*be) {
1980 - *be = audio_get_default_audio_be(errp);
1981 - if (!*be) {
1982 - return false;
1983 - }
1984 - }
1985 -
1986 - return true;
1987 -}
1988 -
1859 static struct audio_pcm_ops capture_pcm_ops;
1860
1861 static CaptureVoiceOut *audio_mixeng_backend_add_capture(
@@ -2062,17 +1932,6 @@ static CaptureVoiceOut *audio_mixeng_backend_add_capture(
1932 return cap;
1933 }
1934
2065 -CaptureVoiceOut *AUD_add_capture(
2066 - AudioBackend *be,
2067 - struct audsettings *as,
2068 - struct audio_capture_ops *ops,
2069 - void *cb_opaque)
2070 -{
2071 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2072 -
2073 - return klass->add_capture(be, as, ops, cb_opaque);
2074 -}
2075 -
1935 static void audio_mixeng_backend_del_capture(
1936 AudioBackend *be,
1937 CaptureVoiceOut *cap,
@@ -2115,13 +1974,6 @@ static void audio_mixeng_backend_del_capture(
1974 }
1975 }
1976
2118 -void AUD_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
2119 -{
2120 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2121 -
2122 - klass->del_capture(be, cap, cb_opaque);
2123 -}
2124 -
1977 static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw,
1978 Volume *vol)
1979 {
@@ -2139,13 +1991,6 @@ static void audio_mixeng_backend_set_volume_out(AudioBackend *be, SWVoiceOut *sw
1991 }
1992 }
1993
2142 -void AUD_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
2143 -{
2144 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2145 -
2146 - klass->set_volume_out(be, sw, vol);
2147 -}
2148 -
1994 static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
1995 Volume *vol)
1996 {
@@ -2163,13 +2008,6 @@ static void audio_mixeng_backend_set_volume_in(AudioBackend *be, SWVoiceIn *sw,
2008 }
2009 }
2010
2166 -void AUD_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
2167 -{
2168 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2169 -
2170 - klass->set_volume_in(be, sw, vol);
2171 -}
2172 -
2011 static void audio_create_pdos(Audiodev *dev)
2012 {
2013 switch (dev->driver) {
@@ -2423,40 +2261,6 @@ AudioBackend *audio_be_by_name(const char *name, Error **errp)
2261 }
2262 }
2263
2426 -#ifdef CONFIG_GIO
2427 -bool audio_be_can_set_dbus_server(AudioBackend *be)
2428 -{
2429 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2430 -
2431 - return klass->set_dbus_server != NULL;
2432 -}
2433 -
2434 -bool audio_be_set_dbus_server(AudioBackend *be,
2435 - GDBusObjectManagerServer *server,
2436 - bool p2p,
2437 - Error **errp)
2438 -{
2439 - AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
2440 -
2441 - if (!audio_be_can_set_dbus_server(be)) {
2442 - error_setg(errp, "Audiodev '%s' is not compatible with DBus",
2443 - audio_be_get_id(be));
2444 - return false;
2445 - }
2446 -
2447 - return klass->set_dbus_server(be, server, p2p, errp);
2448 -}
2449 -#endif
2450 -
2451 -const char *audio_be_get_id(AudioBackend *be)
2452 -{
2453 - if (be) {
2454 - return AUDIO_BACKEND_GET_CLASS(be)->get_id(be);
2455 - } else {
2456 - return "";
2457 - }
2458 -}
2459 -
2264 const char *audio_application_name(void)
2265 {
2266 const char *vm_name;
@@ -2521,15 +2325,6 @@ AudiodevList *qmp_query_audiodevs(Error **errp)
2325 }
2326
2327 static const TypeInfo audio_types[] = {
2524 - {
2525 - .name = TYPE_AUDIO_BACKEND,
2526 - .parent = TYPE_OBJECT,
2527 - .instance_size = sizeof(AudioBackend),
2528 - .instance_init = audio_be_init,
2529 - .instance_finalize = audio_be_finalize,
2530 - .abstract = true,
2531 - .class_size = sizeof(AudioBackendClass),
2532 - },
2328 {
2329 .name = TYPE_AUDIO_MIXENG_BACKEND,
2330 .parent = TYPE_AUDIO_BACKEND,
audio/meson.build
+1
@@ -1,6 +1,7 @@
1 audio_ss = ss.source_set()
2 audio_ss.add(files(
3 'audio.c',
4 + 'audio-be.c',
5 'mixeng.c',
6 'noaudio.c',
7 'wavaudio.c',
include/qemu/audio.h
+2
@@ -111,6 +111,8 @@ typedef struct AudioBackendClass {
111
112 bool AUD_backend_check(AudioBackend **be, Error **errp);
113
114 +AudioBackend *audio_be_new(Audiodev *dev, Error **errp);
115 +
116 SWVoiceOut *AUD_open_out(
117 AudioBackend *be,
118 SWVoiceOut *sw,