master
c 274 lines 5.8 KB
Raw
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 #include "trace.h"
8 #include "qapi-types-audio.h"
9
10 bool audio_be_check(AudioBackend **be, Error **errp)
11 {
12 assert(be != NULL);
13
14 if (!*be) {
15 *be = audio_get_default_audio_be(errp);
16 if (!*be) {
17 return false;
18 }
19 }
20
21 return true;
22 }
23
24 SWVoiceIn *audio_be_open_in(
25 AudioBackend *be,
26 SWVoiceIn *sw,
27 const char *name,
28 void *callback_opaque,
29 audio_callback_fn callback_fn,
30 const struct audsettings *as)
31 {
32 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
33
34 assert(name != NULL);
35 assert(callback_fn != NULL);
36 assert(as != NULL);
37
38 return klass->open_in(be, sw, name, callback_opaque, callback_fn, as);
39 }
40
41 SWVoiceOut *audio_be_open_out(
42 AudioBackend *be,
43 SWVoiceOut *sw,
44 const char *name,
45 void *callback_opaque,
46 audio_callback_fn callback_fn,
47 const struct audsettings *as)
48 {
49 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
50
51 assert(name != NULL);
52 assert(callback_fn != NULL);
53 assert(as != NULL);
54
55 return klass->open_out(be, sw, name, callback_opaque, callback_fn, as);
56 }
57
58 void audio_be_close_out(AudioBackend *be, SWVoiceOut *sw)
59 {
60 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
61
62 if (!sw) {
63 return;
64 }
65
66 return klass->close_out(be, sw);
67 }
68
69 void audio_be_close_in(AudioBackend *be, SWVoiceIn *sw)
70 {
71 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
72
73 if (!sw) {
74 return;
75 }
76
77 return klass->close_in(be, sw);
78 }
79
80 bool audio_be_is_active_out(AudioBackend *be, SWVoiceOut *sw)
81 {
82 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
83
84 if (!sw) {
85 return false;
86 }
87
88 return klass->is_active_out(be, sw);
89 }
90
91 bool audio_be_is_active_in(AudioBackend *be, SWVoiceIn *sw)
92 {
93 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
94
95 if (!sw) {
96 return false;
97 }
98
99 return klass->is_active_in(be, sw);
100 }
101
102 size_t audio_be_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size)
103 {
104 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
105
106 if (!sw) {
107 return 0;
108 }
109
110 return klass->write(be, sw, buf, size);
111 }
112
113 size_t audio_be_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size)
114 {
115 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
116
117 if (!sw) {
118 return 0;
119 }
120
121 return klass->read(be, sw, buf, size);
122 }
123
124 int audio_be_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw)
125 {
126 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
127
128 if (!sw) {
129 return 0;
130 }
131
132 return klass->get_buffer_size_out(be, sw);
133 }
134
135 void audio_be_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on)
136 {
137 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
138
139 trace_audio_be_set_active_out(sw, on);
140
141 if (!sw) {
142 return;
143 }
144
145 return klass->set_active_out(be, sw, on);
146 }
147
148 void audio_be_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on)
149 {
150 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
151
152 trace_audio_be_set_active_in(sw, on);
153
154 if (!sw) {
155 return;
156 }
157
158 return klass->set_active_in(be, sw, on);
159 }
160
161 void audio_be_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol)
162 {
163 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
164
165 if (!sw) {
166 return;
167 }
168
169 klass->set_volume_out(be, sw, vol);
170 }
171
172 void audio_be_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol)
173 {
174 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
175
176 if (!sw) {
177 return;
178 }
179
180 klass->set_volume_in(be, sw, vol);
181 }
182
183 CaptureVoiceOut *audio_be_add_capture(
184 AudioBackend *be,
185 const struct audsettings *as,
186 const struct audio_capture_ops *ops,
187 void *cb_opaque)
188 {
189 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
190
191 assert(as != NULL);
192 assert(ops != NULL);
193
194 return klass->add_capture(be, as, ops, cb_opaque);
195 }
196
197 void audio_be_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque)
198 {
199 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
200
201 if (!cap) {
202 return;
203 }
204
205 klass->del_capture(be, cap, cb_opaque);
206 }
207
208 #ifdef CONFIG_GIO
209 bool audio_be_can_set_dbus_server(AudioBackend *be)
210 {
211 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
212
213 return klass->set_dbus_server != NULL;
214 }
215
216 bool audio_be_set_dbus_server(AudioBackend *be,
217 GDBusObjectManagerServer *server,
218 bool p2p,
219 Error **errp)
220 {
221 AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be);
222
223 assert(server != NULL);
224
225 if (!audio_be_can_set_dbus_server(be)) {
226 error_setg(errp, "Audiodev '%s' is not compatible with DBus",
227 audio_be_get_id(be));
228 return false;
229 }
230
231 return klass->set_dbus_server(be, server, p2p, errp);
232 }
233 #endif
234
235 const char *audio_be_get_id(AudioBackend *be)
236 {
237 if (be) {
238 return AUDIO_BACKEND_GET_CLASS(be)->get_id(be);
239 } else {
240 return "";
241 }
242 }
243
244 AudioBackend *audio_be_new(Audiodev *dev, Error **errp)
245 {
246 const char *drvname = AudiodevDriver_str(dev->driver);
247 g_autofree char *type = g_strconcat("audio-", drvname, NULL);
248 AudioBackend *be = AUDIO_BACKEND(object_new(type));
249
250 if (!be) {
251 error_setg(errp, "Unknown audio driver `%s'", drvname);
252 qapi_free_Audiodev(dev);
253 return NULL;
254 }
255
256 if (!AUDIO_BACKEND_GET_CLASS(be)->realize(be, dev, errp)) {
257 object_unref(OBJECT(be));
258 return NULL;
259 }
260
261 return be;
262 }
263
264 static const TypeInfo audio_types[] = {
265 {
266 .name = TYPE_AUDIO_BACKEND,
267 .parent = TYPE_OBJECT,
268 .instance_size = sizeof(AudioBackend),
269 .abstract = true,
270 .class_size = sizeof(AudioBackendClass),
271 },
272 };
273
274 DEFINE_TYPES(audio_types)