]> git.proxmox.com Git - mirror_qemu.git/blame - audio/dbusaudio.c
Merge tag 'misc-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging
[mirror_qemu.git] / audio / dbusaudio.c
CommitLineData
739362d4
MAL
1/*
2 * QEMU DBus audio
3 *
4 * Copyright (c) 2021 Red Hat, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "qemu/osdep.h"
26#include "qemu/error-report.h"
27#include "qemu/host-utils.h"
28#include "qemu/module.h"
29#include "qemu/timer.h"
30#include "qemu/dbus.h"
31
29c5c7e5 32#ifdef G_OS_UNIX
739362d4 33#include <gio/gunixfdlist.h>
29c5c7e5
MAL
34#endif
35
6cc5a615 36#include "ui/dbus.h"
739362d4
MAL
37#include "ui/dbus-display1.h"
38
39#define AUDIO_CAP "dbus"
40#include "audio.h"
41#include "audio_int.h"
42#include "trace.h"
43
44#define DBUS_DISPLAY1_AUDIO_PATH DBUS_DISPLAY1_ROOT "/Audio"
45
46#define DBUS_AUDIO_NSAMPLES 1024 /* could be configured? */
47
48typedef struct DBusAudio {
49 GDBusObjectManagerServer *server;
e74fec9a 50 bool p2p;
739362d4
MAL
51 GDBusObjectSkeleton *audio;
52 QemuDBusDisplay1Audio *iface;
53 GHashTable *out_listeners;
54 GHashTable *in_listeners;
55} DBusAudio;
56
57typedef struct DBusVoiceOut {
58 HWVoiceOut hw;
59 bool enabled;
60 RateCtl rate;
61
62 void *buf;
63 size_t buf_pos;
64 size_t buf_size;
65
66 bool has_volume;
67 Volume volume;
68} DBusVoiceOut;
69
70typedef struct DBusVoiceIn {
71 HWVoiceIn hw;
72 bool enabled;
73 RateCtl rate;
74
75 bool has_volume;
76 Volume volume;
77} DBusVoiceIn;
78
79static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
80{
81 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
82
83 if (!vo->buf) {
84 vo->buf_size = hw->samples * hw->info.bytes_per_frame;
85 vo->buf = g_malloc(vo->buf_size);
86 vo->buf_pos = 0;
87 }
88
89 *size = MIN(vo->buf_size - vo->buf_pos, *size);
613fe02b 90 *size = audio_rate_get_bytes(&vo->rate, &hw->info, *size);
739362d4
MAL
91
92 return vo->buf + vo->buf_pos;
93
94}
95
96static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
97{
98 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
99 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
100 GHashTableIter iter;
101 QemuDBusDisplay1AudioOutListener *listener = NULL;
102 g_autoptr(GBytes) bytes = NULL;
103 g_autoptr(GVariant) v_data = NULL;
104
105 assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
106 vo->buf_pos += size;
107
108 trace_dbus_audio_put_buffer_out(size);
109
110 if (vo->buf_pos < vo->buf_size) {
111 return size;
112 }
113
114 bytes = g_bytes_new_take(g_steal_pointer(&vo->buf), vo->buf_size);
115 v_data = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
116 g_variant_ref_sink(v_data);
117
118 g_hash_table_iter_init(&iter, da->out_listeners);
119 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
120 qemu_dbus_display1_audio_out_listener_call_write(
121 listener,
122 (uintptr_t)hw,
123 v_data,
124 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
125 }
126
127 return size;
128}
129
e03b5686 130#if HOST_BIG_ENDIAN
739362d4
MAL
131#define AUDIO_HOST_BE TRUE
132#else
133#define AUDIO_HOST_BE FALSE
134#endif
135
136static void
137dbus_init_out_listener(QemuDBusDisplay1AudioOutListener *listener,
138 HWVoiceOut *hw)
139{
140 qemu_dbus_display1_audio_out_listener_call_init(
141 listener,
142 (uintptr_t)hw,
143 hw->info.bits,
144 hw->info.is_signed,
145 hw->info.is_float,
146 hw->info.freq,
147 hw->info.nchannels,
148 hw->info.bytes_per_frame,
149 hw->info.bytes_per_second,
150 hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
151 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
152}
153
154static int
155dbus_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
156{
157 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
158 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
159 GHashTableIter iter;
160 QemuDBusDisplay1AudioOutListener *listener = NULL;
161
162 audio_pcm_init_info(&hw->info, as);
163 hw->samples = DBUS_AUDIO_NSAMPLES;
164 audio_rate_start(&vo->rate);
165
166 g_hash_table_iter_init(&iter, da->out_listeners);
167 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
168 dbus_init_out_listener(listener, hw);
169 }
170 return 0;
171}
172
173static void
174dbus_fini_out(HWVoiceOut *hw)
175{
176 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
177 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
178 GHashTableIter iter;
179 QemuDBusDisplay1AudioOutListener *listener = NULL;
180
181 g_hash_table_iter_init(&iter, da->out_listeners);
182 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
183 qemu_dbus_display1_audio_out_listener_call_fini(
184 listener,
185 (uintptr_t)hw,
186 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
187 }
188
189 g_clear_pointer(&vo->buf, g_free);
190}
191
192static void
193dbus_enable_out(HWVoiceOut *hw, bool enable)
194{
195 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
196 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
197 GHashTableIter iter;
198 QemuDBusDisplay1AudioOutListener *listener = NULL;
199
200 vo->enabled = enable;
201 if (enable) {
202 audio_rate_start(&vo->rate);
203 }
204
205 g_hash_table_iter_init(&iter, da->out_listeners);
206 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
207 qemu_dbus_display1_audio_out_listener_call_set_enabled(
208 listener, (uintptr_t)hw, enable,
209 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
210 }
211}
212
213static void
214dbus_volume_out_listener(HWVoiceOut *hw,
215 QemuDBusDisplay1AudioOutListener *listener)
216{
217 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
218 Volume *vol = &vo->volume;
219 g_autoptr(GBytes) bytes = NULL;
220 GVariant *v_vol = NULL;
221
222 if (!vo->has_volume) {
223 return;
224 }
225
226 assert(vol->channels < sizeof(vol->vol));
227 bytes = g_bytes_new(vol->vol, vol->channels);
228 v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
229 qemu_dbus_display1_audio_out_listener_call_set_volume(
230 listener, (uintptr_t)hw, vol->mute, v_vol,
231 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
232}
233
234static void
235dbus_volume_out(HWVoiceOut *hw, Volume *vol)
236{
237 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
238 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
239 GHashTableIter iter;
240 QemuDBusDisplay1AudioOutListener *listener = NULL;
241
242 vo->has_volume = true;
243 vo->volume = *vol;
244
245 g_hash_table_iter_init(&iter, da->out_listeners);
246 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
247 dbus_volume_out_listener(hw, listener);
248 }
249}
250
251static void
252dbus_init_in_listener(QemuDBusDisplay1AudioInListener *listener, HWVoiceIn *hw)
253{
254 qemu_dbus_display1_audio_in_listener_call_init(
255 listener,
256 (uintptr_t)hw,
257 hw->info.bits,
258 hw->info.is_signed,
259 hw->info.is_float,
260 hw->info.freq,
261 hw->info.nchannels,
262 hw->info.bytes_per_frame,
263 hw->info.bytes_per_second,
264 hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
265 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
266}
267
268static int
269dbus_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
270{
271 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
272 DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
273 GHashTableIter iter;
274 QemuDBusDisplay1AudioInListener *listener = NULL;
275
276 audio_pcm_init_info(&hw->info, as);
277 hw->samples = DBUS_AUDIO_NSAMPLES;
278 audio_rate_start(&vo->rate);
279
280 g_hash_table_iter_init(&iter, da->in_listeners);
281 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
282 dbus_init_in_listener(listener, hw);
283 }
284 return 0;
285}
286
287static void
288dbus_fini_in(HWVoiceIn *hw)
289{
290 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
291 GHashTableIter iter;
292 QemuDBusDisplay1AudioInListener *listener = NULL;
293
294 g_hash_table_iter_init(&iter, da->in_listeners);
295 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
296 qemu_dbus_display1_audio_in_listener_call_fini(
297 listener,
298 (uintptr_t)hw,
299 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
300 }
301}
302
303static void
304dbus_volume_in_listener(HWVoiceIn *hw,
305 QemuDBusDisplay1AudioInListener *listener)
306{
307 DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
308 Volume *vol = &vo->volume;
309 g_autoptr(GBytes) bytes = NULL;
310 GVariant *v_vol = NULL;
311
312 if (!vo->has_volume) {
313 return;
314 }
315
316 assert(vol->channels < sizeof(vol->vol));
317 bytes = g_bytes_new(vol->vol, vol->channels);
318 v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
319 qemu_dbus_display1_audio_in_listener_call_set_volume(
320 listener, (uintptr_t)hw, vol->mute, v_vol,
321 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
322}
323
324static void
325dbus_volume_in(HWVoiceIn *hw, Volume *vol)
326{
327 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
328 DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
329 GHashTableIter iter;
330 QemuDBusDisplay1AudioInListener *listener = NULL;
331
332 vo->has_volume = true;
333 vo->volume = *vol;
334
335 g_hash_table_iter_init(&iter, da->in_listeners);
336 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
337 dbus_volume_in_listener(hw, listener);
338 }
339}
340
341static size_t
342dbus_read(HWVoiceIn *hw, void *buf, size_t size)
343{
344 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
345 /* DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw); */
346 GHashTableIter iter;
347 QemuDBusDisplay1AudioInListener *listener = NULL;
348
349 trace_dbus_audio_read(size);
350
613fe02b 351 /* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */
739362d4
MAL
352
353 g_hash_table_iter_init(&iter, da->in_listeners);
354 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
355 g_autoptr(GVariant) v_data = NULL;
356 const char *data;
357 gsize n = 0;
358
359 if (qemu_dbus_display1_audio_in_listener_call_read_sync(
360 listener,
361 (uintptr_t)hw,
362 size,
363 G_DBUS_CALL_FLAGS_NONE, -1,
364 &v_data, NULL, NULL)) {
365 data = g_variant_get_fixed_array(v_data, &n, 1);
366 g_warn_if_fail(n <= size);
367 size = MIN(n, size);
368 memcpy(buf, data, size);
369 break;
370 }
371 }
372
373 return size;
374}
375
376static void
377dbus_enable_in(HWVoiceIn *hw, bool enable)
378{
379 DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
380 DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
381 GHashTableIter iter;
382 QemuDBusDisplay1AudioInListener *listener = NULL;
383
384 vo->enabled = enable;
385 if (enable) {
386 audio_rate_start(&vo->rate);
387 }
388
389 g_hash_table_iter_init(&iter, da->in_listeners);
390 while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
391 qemu_dbus_display1_audio_in_listener_call_set_enabled(
392 listener, (uintptr_t)hw, enable,
393 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
394 }
395}
396
397static void *
f6061733 398dbus_audio_init(Audiodev *dev, Error **errp)
739362d4
MAL
399{
400 DBusAudio *da = g_new0(DBusAudio, 1);
401
402 da->out_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
403 g_free, g_object_unref);
404 da->in_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
405 g_free, g_object_unref);
406 return da;
407}
408
409static void
410dbus_audio_fini(void *opaque)
411{
412 DBusAudio *da = opaque;
413
414 if (da->server) {
415 g_dbus_object_manager_server_unexport(da->server,
416 DBUS_DISPLAY1_AUDIO_PATH);
417 }
418 g_clear_object(&da->audio);
419 g_clear_object(&da->iface);
420 g_clear_pointer(&da->in_listeners, g_hash_table_unref);
421 g_clear_pointer(&da->out_listeners, g_hash_table_unref);
422 g_clear_object(&da->server);
423 g_free(da);
424}
425
426static void
427listener_out_vanished_cb(GDBusConnection *connection,
428 gboolean remote_peer_vanished,
429 GError *error,
430 DBusAudio *da)
431{
432 char *name = g_object_get_data(G_OBJECT(connection), "name");
433
434 g_hash_table_remove(da->out_listeners, name);
435}
436
437static void
438listener_in_vanished_cb(GDBusConnection *connection,
439 gboolean remote_peer_vanished,
440 GError *error,
441 DBusAudio *da)
442{
443 char *name = g_object_get_data(G_OBJECT(connection), "name");
444
445 g_hash_table_remove(da->in_listeners, name);
446}
447
448static gboolean
449dbus_audio_register_listener(AudioState *s,
450 GDBusMethodInvocation *invocation,
6cc5a615 451#ifdef G_OS_UNIX
739362d4 452 GUnixFDList *fd_list,
6cc5a615 453#endif
739362d4
MAL
454 GVariant *arg_listener,
455 bool out)
456{
457 DBusAudio *da = s->drv_opaque;
e74fec9a
MAL
458 const char *sender =
459 da->p2p ? "p2p" : g_dbus_method_invocation_get_sender(invocation);
739362d4
MAL
460 g_autoptr(GDBusConnection) listener_conn = NULL;
461 g_autoptr(GError) err = NULL;
462 g_autoptr(GSocket) socket = NULL;
463 g_autoptr(GSocketConnection) socket_conn = NULL;
464 g_autofree char *guid = g_dbus_generate_guid();
465 GHashTable *listeners = out ? da->out_listeners : da->in_listeners;
466 GObject *listener;
467 int fd;
468
469 trace_dbus_audio_register(sender, out ? "out" : "in");
470
471 if (g_hash_table_contains(listeners, sender)) {
472 g_dbus_method_invocation_return_error(invocation,
473 DBUS_DISPLAY_ERROR,
474 DBUS_DISPLAY_ERROR_INVALID,
475 "`%s` is already registered!",
476 sender);
477 return DBUS_METHOD_INVOCATION_HANDLED;
478 }
479
6cc5a615
MAL
480#ifdef G_OS_WIN32
481 if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
482 return DBUS_METHOD_INVOCATION_HANDLED;
483 }
484#else
739362d4
MAL
485 fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
486 if (err) {
487 g_dbus_method_invocation_return_error(invocation,
488 DBUS_DISPLAY_ERROR,
489 DBUS_DISPLAY_ERROR_FAILED,
490 "Couldn't get peer fd: %s",
491 err->message);
492 return DBUS_METHOD_INVOCATION_HANDLED;
493 }
6cc5a615 494#endif
739362d4
MAL
495
496 socket = g_socket_new_from_fd(fd, &err);
497 if (err) {
498 g_dbus_method_invocation_return_error(invocation,
499 DBUS_DISPLAY_ERROR,
500 DBUS_DISPLAY_ERROR_FAILED,
501 "Couldn't make a socket: %s",
502 err->message);
6cc5a615
MAL
503#ifdef G_OS_WIN32
504 closesocket(fd);
505#else
506 close(fd);
507#endif
739362d4
MAL
508 return DBUS_METHOD_INVOCATION_HANDLED;
509 }
510 socket_conn = g_socket_connection_factory_create_connection(socket);
511 if (out) {
512 qemu_dbus_display1_audio_complete_register_out_listener(
6cc5a615
MAL
513 da->iface, invocation
514#ifdef G_OS_UNIX
515 , NULL
516#endif
517 );
739362d4
MAL
518 } else {
519 qemu_dbus_display1_audio_complete_register_in_listener(
6cc5a615
MAL
520 da->iface, invocation
521#ifdef G_OS_UNIX
522 , NULL
523#endif
524 );
739362d4
MAL
525 }
526
527 listener_conn =
528 g_dbus_connection_new_sync(
529 G_IO_STREAM(socket_conn),
530 guid,
531 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
532 NULL, NULL, &err);
533 if (err) {
534 error_report("Failed to setup peer connection: %s", err->message);
535 return DBUS_METHOD_INVOCATION_HANDLED;
536 }
537
538 listener = out ?
539 G_OBJECT(qemu_dbus_display1_audio_out_listener_proxy_new_sync(
540 listener_conn,
541 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
542 NULL,
543 "/org/qemu/Display1/AudioOutListener",
544 NULL,
545 &err)) :
546 G_OBJECT(qemu_dbus_display1_audio_in_listener_proxy_new_sync(
547 listener_conn,
548 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
549 NULL,
550 "/org/qemu/Display1/AudioInListener",
551 NULL,
552 &err));
553 if (!listener) {
554 error_report("Failed to setup proxy: %s", err->message);
555 return DBUS_METHOD_INVOCATION_HANDLED;
556 }
557
558 if (out) {
559 HWVoiceOut *hw;
560
561 QLIST_FOREACH(hw, &s->hw_head_out, entries) {
562 DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
563 QemuDBusDisplay1AudioOutListener *l =
564 QEMU_DBUS_DISPLAY1_AUDIO_OUT_LISTENER(listener);
565
566 dbus_init_out_listener(l, hw);
567 qemu_dbus_display1_audio_out_listener_call_set_enabled(
568 l, (uintptr_t)hw, vo->enabled,
569 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
570 }
571 } else {
572 HWVoiceIn *hw;
573
574 QLIST_FOREACH(hw, &s->hw_head_in, entries) {
575 DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
576 QemuDBusDisplay1AudioInListener *l =
577 QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener);
578
579 dbus_init_in_listener(
580 QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener), hw);
581 qemu_dbus_display1_audio_in_listener_call_set_enabled(
582 l, (uintptr_t)hw, vo->enabled,
583 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
584 }
585 }
586
587 g_object_set_data_full(G_OBJECT(listener_conn), "name",
588 g_strdup(sender), g_free);
589 g_hash_table_insert(listeners, g_strdup(sender), listener);
590 g_object_connect(listener_conn,
591 "signal::closed",
592 out ? listener_out_vanished_cb : listener_in_vanished_cb,
593 da,
594 NULL);
595
596 return DBUS_METHOD_INVOCATION_HANDLED;
597}
598
599static gboolean
600dbus_audio_register_out_listener(AudioState *s,
601 GDBusMethodInvocation *invocation,
6cc5a615 602#ifdef G_OS_UNIX
739362d4 603 GUnixFDList *fd_list,
6cc5a615 604#endif
739362d4
MAL
605 GVariant *arg_listener)
606{
607 return dbus_audio_register_listener(s, invocation,
6cc5a615
MAL
608#ifdef G_OS_UNIX
609 fd_list,
610#endif
611 arg_listener, true);
739362d4
MAL
612
613}
614
615static gboolean
616dbus_audio_register_in_listener(AudioState *s,
617 GDBusMethodInvocation *invocation,
6cc5a615 618#ifdef G_OS_UNIX
739362d4 619 GUnixFDList *fd_list,
6cc5a615 620#endif
739362d4
MAL
621 GVariant *arg_listener)
622{
623 return dbus_audio_register_listener(s, invocation,
6cc5a615
MAL
624#ifdef G_OS_UNIX
625 fd_list,
29c5c7e5 626#endif
6cc5a615
MAL
627 arg_listener, false);
628}
739362d4
MAL
629
630static void
e74fec9a 631dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
739362d4
MAL
632{
633 DBusAudio *da = s->drv_opaque;
634
635 g_assert(da);
636 g_assert(!da->server);
637
638 da->server = g_object_ref(server);
e74fec9a 639 da->p2p = p2p;
739362d4
MAL
640
641 da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
642 da->iface = qemu_dbus_display1_audio_skeleton_new();
643 g_object_connect(da->iface,
644 "swapped-signal::handle-register-in-listener",
645 dbus_audio_register_in_listener, s,
646 "swapped-signal::handle-register-out-listener",
647 dbus_audio_register_out_listener, s,
648 NULL);
649
650 g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
651 G_DBUS_INTERFACE_SKELETON(da->iface));
652 g_dbus_object_manager_server_export(da->server, da->audio);
653}
654
655static struct audio_pcm_ops dbus_pcm_ops = {
656 .init_out = dbus_init_out,
657 .fini_out = dbus_fini_out,
658 .write = audio_generic_write,
659 .get_buffer_out = dbus_get_buffer_out,
660 .put_buffer_out = dbus_put_buffer_out,
661 .enable_out = dbus_enable_out,
662 .volume_out = dbus_volume_out,
663
664 .init_in = dbus_init_in,
665 .fini_in = dbus_fini_in,
666 .read = dbus_read,
667 .run_buffer_in = audio_generic_run_buffer_in,
668 .enable_in = dbus_enable_in,
669 .volume_in = dbus_volume_in,
670};
671
672static struct audio_driver dbus_audio_driver = {
673 .name = "dbus",
674 .descr = "Timer based audio exposed with DBus interface",
675 .init = dbus_audio_init,
676 .fini = dbus_audio_fini,
677 .set_dbus_server = dbus_audio_set_server,
678 .pcm_ops = &dbus_pcm_ops,
739362d4
MAL
679 .max_voices_out = INT_MAX,
680 .max_voices_in = INT_MAX,
681 .voice_size_out = sizeof(DBusVoiceOut),
682 .voice_size_in = sizeof(DBusVoiceIn)
683};
684
685static void register_audio_dbus(void)
686{
687 audio_driver_register(&dbus_audio_driver);
688}
689type_init(register_audio_dbus);
690
691module_dep("ui-dbus")