123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- /*
- * QEMU DBus audio
- *
- * Copyright (c) 2021 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include "qemu/osdep.h"
- #include "qemu/error-report.h"
- #include "qemu/host-utils.h"
- #include "qemu/module.h"
- #include "qemu/timer.h"
- #include "qemu/dbus.h"
- #ifdef G_OS_UNIX
- #include <gio/gunixfdlist.h>
- #endif
- #include "ui/dbus.h"
- #include "ui/dbus-display1.h"
- #define AUDIO_CAP "dbus"
- #include "audio.h"
- #include "audio_int.h"
- #include "trace.h"
- #define DBUS_DISPLAY1_AUDIO_PATH DBUS_DISPLAY1_ROOT "/Audio"
- #define DBUS_DEFAULT_AUDIO_NSAMPLES 480
- typedef struct DBusAudio {
- Audiodev *dev;
- GDBusObjectManagerServer *server;
- bool p2p;
- GDBusObjectSkeleton *audio;
- QemuDBusDisplay1Audio *iface;
- GHashTable *out_listeners;
- GHashTable *in_listeners;
- } DBusAudio;
- typedef struct DBusVoiceOut {
- HWVoiceOut hw;
- bool enabled;
- RateCtl rate;
- void *buf;
- size_t buf_pos;
- size_t buf_size;
- bool has_volume;
- Volume volume;
- } DBusVoiceOut;
- typedef struct DBusVoiceIn {
- HWVoiceIn hw;
- bool enabled;
- RateCtl rate;
- bool has_volume;
- Volume volume;
- } DBusVoiceIn;
- static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
- {
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- if (!vo->buf) {
- vo->buf_size = hw->samples * hw->info.bytes_per_frame;
- vo->buf = g_malloc(vo->buf_size);
- vo->buf_pos = 0;
- }
- *size = MIN(vo->buf_size - vo->buf_pos, *size);
- *size = audio_rate_get_bytes(&vo->rate, &hw->info, *size);
- return vo->buf + vo->buf_pos;
- }
- static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioOutListener *listener = NULL;
- g_autoptr(GBytes) bytes = NULL;
- g_autoptr(GVariant) v_data = NULL;
- assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
- vo->buf_pos += size;
- trace_dbus_audio_put_buffer_out(vo->buf_pos, vo->buf_size);
- if (vo->buf_pos < vo->buf_size) {
- return size;
- }
- bytes = g_bytes_new_take(g_steal_pointer(&vo->buf), vo->buf_size);
- v_data = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
- g_variant_ref_sink(v_data);
- g_hash_table_iter_init(&iter, da->out_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- qemu_dbus_display1_audio_out_listener_call_write(
- listener,
- (uintptr_t)hw,
- v_data,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- return size;
- }
- #if HOST_BIG_ENDIAN
- #define AUDIO_HOST_BE TRUE
- #else
- #define AUDIO_HOST_BE FALSE
- #endif
- static void
- dbus_init_out_listener(QemuDBusDisplay1AudioOutListener *listener,
- HWVoiceOut *hw)
- {
- qemu_dbus_display1_audio_out_listener_call_init(
- listener,
- (uintptr_t)hw,
- hw->info.bits,
- hw->info.is_signed,
- hw->info.is_float,
- hw->info.freq,
- hw->info.nchannels,
- hw->info.bytes_per_frame,
- hw->info.bytes_per_second,
- hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- static guint
- dbus_audio_get_nsamples(DBusAudio *da)
- {
- AudiodevDBusOptions *opts = &da->dev->u.dbus;
- if (opts->has_nsamples && opts->nsamples) {
- return opts->nsamples;
- } else {
- return DBUS_DEFAULT_AUDIO_NSAMPLES;
- }
- }
- static int
- dbus_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioOutListener *listener = NULL;
- audio_pcm_init_info(&hw->info, as);
- hw->samples = dbus_audio_get_nsamples(da);
- audio_rate_start(&vo->rate);
- g_hash_table_iter_init(&iter, da->out_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- dbus_init_out_listener(listener, hw);
- }
- return 0;
- }
- static void
- dbus_fini_out(HWVoiceOut *hw)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioOutListener *listener = NULL;
- g_hash_table_iter_init(&iter, da->out_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- qemu_dbus_display1_audio_out_listener_call_fini(
- listener,
- (uintptr_t)hw,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- g_clear_pointer(&vo->buf, g_free);
- }
- static void
- dbus_enable_out(HWVoiceOut *hw, bool enable)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioOutListener *listener = NULL;
- vo->enabled = enable;
- if (enable) {
- audio_rate_start(&vo->rate);
- }
- g_hash_table_iter_init(&iter, da->out_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- qemu_dbus_display1_audio_out_listener_call_set_enabled(
- listener, (uintptr_t)hw, enable,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- }
- static void
- dbus_volume_out_listener(HWVoiceOut *hw,
- QemuDBusDisplay1AudioOutListener *listener)
- {
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- Volume *vol = &vo->volume;
- g_autoptr(GBytes) bytes = NULL;
- GVariant *v_vol = NULL;
- if (!vo->has_volume) {
- return;
- }
- assert(vol->channels < sizeof(vol->vol));
- bytes = g_bytes_new(vol->vol, vol->channels);
- v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
- qemu_dbus_display1_audio_out_listener_call_set_volume(
- listener, (uintptr_t)hw, vol->mute, v_vol,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- static void
- dbus_volume_out(HWVoiceOut *hw, Volume *vol)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioOutListener *listener = NULL;
- vo->has_volume = true;
- vo->volume = *vol;
- g_hash_table_iter_init(&iter, da->out_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- dbus_volume_out_listener(hw, listener);
- }
- }
- static void
- dbus_init_in_listener(QemuDBusDisplay1AudioInListener *listener, HWVoiceIn *hw)
- {
- qemu_dbus_display1_audio_in_listener_call_init(
- listener,
- (uintptr_t)hw,
- hw->info.bits,
- hw->info.is_signed,
- hw->info.is_float,
- hw->info.freq,
- hw->info.nchannels,
- hw->info.bytes_per_frame,
- hw->info.bytes_per_second,
- hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- static int
- dbus_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioInListener *listener = NULL;
- audio_pcm_init_info(&hw->info, as);
- hw->samples = dbus_audio_get_nsamples(da);
- audio_rate_start(&vo->rate);
- g_hash_table_iter_init(&iter, da->in_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- dbus_init_in_listener(listener, hw);
- }
- return 0;
- }
- static void
- dbus_fini_in(HWVoiceIn *hw)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- GHashTableIter iter;
- QemuDBusDisplay1AudioInListener *listener = NULL;
- g_hash_table_iter_init(&iter, da->in_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- qemu_dbus_display1_audio_in_listener_call_fini(
- listener,
- (uintptr_t)hw,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- }
- static void
- dbus_volume_in_listener(HWVoiceIn *hw,
- QemuDBusDisplay1AudioInListener *listener)
- {
- DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
- Volume *vol = &vo->volume;
- g_autoptr(GBytes) bytes = NULL;
- GVariant *v_vol = NULL;
- if (!vo->has_volume) {
- return;
- }
- assert(vol->channels < sizeof(vol->vol));
- bytes = g_bytes_new(vol->vol, vol->channels);
- v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
- qemu_dbus_display1_audio_in_listener_call_set_volume(
- listener, (uintptr_t)hw, vol->mute, v_vol,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- static void
- dbus_volume_in(HWVoiceIn *hw, Volume *vol)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioInListener *listener = NULL;
- vo->has_volume = true;
- vo->volume = *vol;
- g_hash_table_iter_init(&iter, da->in_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- dbus_volume_in_listener(hw, listener);
- }
- }
- static size_t
- dbus_read(HWVoiceIn *hw, void *buf, size_t size)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- /* DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw); */
- GHashTableIter iter;
- QemuDBusDisplay1AudioInListener *listener = NULL;
- trace_dbus_audio_read(size);
- /* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */
- g_hash_table_iter_init(&iter, da->in_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- g_autoptr(GVariant) v_data = NULL;
- const char *data;
- gsize n = 0;
- if (qemu_dbus_display1_audio_in_listener_call_read_sync(
- listener,
- (uintptr_t)hw,
- size,
- G_DBUS_CALL_FLAGS_NONE, -1,
- &v_data, NULL, NULL)) {
- data = g_variant_get_fixed_array(v_data, &n, 1);
- g_warn_if_fail(n <= size);
- size = MIN(n, size);
- memcpy(buf, data, size);
- break;
- }
- }
- return size;
- }
- static void
- dbus_enable_in(HWVoiceIn *hw, bool enable)
- {
- DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
- DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
- GHashTableIter iter;
- QemuDBusDisplay1AudioInListener *listener = NULL;
- vo->enabled = enable;
- if (enable) {
- audio_rate_start(&vo->rate);
- }
- g_hash_table_iter_init(&iter, da->in_listeners);
- while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
- qemu_dbus_display1_audio_in_listener_call_set_enabled(
- listener, (uintptr_t)hw, enable,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- }
- static void *
- dbus_audio_init(Audiodev *dev, Error **errp)
- {
- DBusAudio *da = g_new0(DBusAudio, 1);
- da->dev = dev;
- da->out_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, g_object_unref);
- da->in_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, g_object_unref);
- return da;
- }
- static void
- dbus_audio_fini(void *opaque)
- {
- DBusAudio *da = opaque;
- if (da->server) {
- g_dbus_object_manager_server_unexport(da->server,
- DBUS_DISPLAY1_AUDIO_PATH);
- }
- g_clear_object(&da->audio);
- g_clear_object(&da->iface);
- g_clear_pointer(&da->in_listeners, g_hash_table_unref);
- g_clear_pointer(&da->out_listeners, g_hash_table_unref);
- g_clear_object(&da->server);
- g_free(da);
- }
- static void
- listener_out_vanished_cb(GDBusConnection *connection,
- gboolean remote_peer_vanished,
- GError *error,
- DBusAudio *da)
- {
- char *name = g_object_get_data(G_OBJECT(connection), "name");
- g_hash_table_remove(da->out_listeners, name);
- }
- static void
- listener_in_vanished_cb(GDBusConnection *connection,
- gboolean remote_peer_vanished,
- GError *error,
- DBusAudio *da)
- {
- char *name = g_object_get_data(G_OBJECT(connection), "name");
- g_hash_table_remove(da->in_listeners, name);
- }
- static gboolean
- dbus_audio_register_listener(AudioState *s,
- GDBusMethodInvocation *invocation,
- #ifdef G_OS_UNIX
- GUnixFDList *fd_list,
- #endif
- GVariant *arg_listener,
- bool out)
- {
- DBusAudio *da = s->drv_opaque;
- const char *sender =
- da->p2p ? "p2p" : g_dbus_method_invocation_get_sender(invocation);
- g_autoptr(GDBusConnection) listener_conn = NULL;
- g_autoptr(GError) err = NULL;
- g_autoptr(GSocket) socket = NULL;
- g_autoptr(GSocketConnection) socket_conn = NULL;
- g_autofree char *guid = g_dbus_generate_guid();
- GHashTable *listeners = out ? da->out_listeners : da->in_listeners;
- GObject *listener;
- int fd;
- trace_dbus_audio_register(sender, out ? "out" : "in");
- if (g_hash_table_contains(listeners, sender)) {
- g_dbus_method_invocation_return_error(invocation,
- DBUS_DISPLAY_ERROR,
- DBUS_DISPLAY_ERROR_INVALID,
- "`%s` is already registered!",
- sender);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- #ifdef G_OS_WIN32
- if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- #else
- fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
- if (err) {
- g_dbus_method_invocation_return_error(invocation,
- DBUS_DISPLAY_ERROR,
- DBUS_DISPLAY_ERROR_FAILED,
- "Couldn't get peer fd: %s",
- err->message);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- #endif
- socket = g_socket_new_from_fd(fd, &err);
- if (err) {
- g_dbus_method_invocation_return_error(invocation,
- DBUS_DISPLAY_ERROR,
- DBUS_DISPLAY_ERROR_FAILED,
- "Couldn't make a socket: %s",
- err->message);
- #ifdef G_OS_WIN32
- closesocket(fd);
- #else
- close(fd);
- #endif
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- socket_conn = g_socket_connection_factory_create_connection(socket);
- if (out) {
- qemu_dbus_display1_audio_complete_register_out_listener(
- da->iface, invocation
- #ifdef G_OS_UNIX
- , NULL
- #endif
- );
- } else {
- qemu_dbus_display1_audio_complete_register_in_listener(
- da->iface, invocation
- #ifdef G_OS_UNIX
- , NULL
- #endif
- );
- }
- GDBusConnectionFlags flags =
- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER;
- #ifdef WIN32
- flags |= G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
- #endif
- listener_conn =
- g_dbus_connection_new_sync(
- G_IO_STREAM(socket_conn),
- guid,
- flags,
- NULL, NULL, &err);
- if (err) {
- error_report("Failed to setup peer connection: %s", err->message);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- listener = out ?
- G_OBJECT(qemu_dbus_display1_audio_out_listener_proxy_new_sync(
- listener_conn,
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- NULL,
- "/org/qemu/Display1/AudioOutListener",
- NULL,
- &err)) :
- G_OBJECT(qemu_dbus_display1_audio_in_listener_proxy_new_sync(
- listener_conn,
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- NULL,
- "/org/qemu/Display1/AudioInListener",
- NULL,
- &err));
- if (!listener) {
- error_report("Failed to setup proxy: %s", err->message);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- if (out) {
- HWVoiceOut *hw;
- QLIST_FOREACH(hw, &s->hw_head_out, entries) {
- DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
- QemuDBusDisplay1AudioOutListener *l =
- QEMU_DBUS_DISPLAY1_AUDIO_OUT_LISTENER(listener);
- dbus_init_out_listener(l, hw);
- qemu_dbus_display1_audio_out_listener_call_set_enabled(
- l, (uintptr_t)hw, vo->enabled,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- } else {
- HWVoiceIn *hw;
- QLIST_FOREACH(hw, &s->hw_head_in, entries) {
- DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
- QemuDBusDisplay1AudioInListener *l =
- QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener);
- dbus_init_in_listener(
- QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener), hw);
- qemu_dbus_display1_audio_in_listener_call_set_enabled(
- l, (uintptr_t)hw, vo->enabled,
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
- }
- }
- g_object_set_data_full(G_OBJECT(listener_conn), "name",
- g_strdup(sender), g_free);
- g_hash_table_insert(listeners, g_strdup(sender), listener);
- g_object_connect(listener_conn,
- "signal::closed",
- out ? listener_out_vanished_cb : listener_in_vanished_cb,
- da,
- NULL);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
- static gboolean
- dbus_audio_register_out_listener(AudioState *s,
- GDBusMethodInvocation *invocation,
- #ifdef G_OS_UNIX
- GUnixFDList *fd_list,
- #endif
- GVariant *arg_listener)
- {
- return dbus_audio_register_listener(s, invocation,
- #ifdef G_OS_UNIX
- fd_list,
- #endif
- arg_listener, true);
- }
- static gboolean
- dbus_audio_register_in_listener(AudioState *s,
- GDBusMethodInvocation *invocation,
- #ifdef G_OS_UNIX
- GUnixFDList *fd_list,
- #endif
- GVariant *arg_listener)
- {
- return dbus_audio_register_listener(s, invocation,
- #ifdef G_OS_UNIX
- fd_list,
- #endif
- arg_listener, false);
- }
- static void
- dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
- {
- DBusAudio *da = s->drv_opaque;
- g_assert(da);
- g_assert(!da->server);
- da->server = g_object_ref(server);
- da->p2p = p2p;
- da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
- da->iface = qemu_dbus_display1_audio_skeleton_new();
- g_object_connect(da->iface,
- "swapped-signal::handle-register-in-listener",
- dbus_audio_register_in_listener, s,
- "swapped-signal::handle-register-out-listener",
- dbus_audio_register_out_listener, s,
- NULL);
- qemu_dbus_display1_audio_set_nsamples(da->iface, dbus_audio_get_nsamples(da));
- g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
- G_DBUS_INTERFACE_SKELETON(da->iface));
- g_dbus_object_manager_server_export(da->server, da->audio);
- }
- static struct audio_pcm_ops dbus_pcm_ops = {
- .init_out = dbus_init_out,
- .fini_out = dbus_fini_out,
- .write = audio_generic_write,
- .get_buffer_out = dbus_get_buffer_out,
- .put_buffer_out = dbus_put_buffer_out,
- .enable_out = dbus_enable_out,
- .volume_out = dbus_volume_out,
- .init_in = dbus_init_in,
- .fini_in = dbus_fini_in,
- .read = dbus_read,
- .run_buffer_in = audio_generic_run_buffer_in,
- .enable_in = dbus_enable_in,
- .volume_in = dbus_volume_in,
- };
- static struct audio_driver dbus_audio_driver = {
- .name = "dbus",
- .descr = "Timer based audio exposed with DBus interface",
- .init = dbus_audio_init,
- .fini = dbus_audio_fini,
- .set_dbus_server = dbus_audio_set_server,
- .pcm_ops = &dbus_pcm_ops,
- .max_voices_out = INT_MAX,
- .max_voices_in = INT_MAX,
- .voice_size_out = sizeof(DBusVoiceOut),
- .voice_size_in = sizeof(DBusVoiceIn)
- };
- static void register_audio_dbus(void)
- {
- audio_driver_register(&dbus_audio_driver);
- }
- type_init(register_audio_dbus);
- module_dep("ui-dbus")
|