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,