| /* SPDX-License-Identifier: MIT */ |
| |
| #include "qemu/osdep.h" |
| #include "qemu/audio.h" |
| #include "qemu/audio-capture.h" |
| #include "qapi/error.h" |
| #include "trace.h" |
| #include "qapi-types-audio.h" |
| |
| bool audio_be_check(AudioBackend **be, Error **errp) |
| { |
| assert(be != NULL); |
| |
| if (!*be) { |
| *be = audio_get_default_audio_be(errp); |
| if (!*be) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| SWVoiceIn *audio_be_open_in( |
| AudioBackend *be, |
| SWVoiceIn *sw, |
| const char *name, |
| void *callback_opaque, |
| audio_callback_fn callback_fn, |
| const struct audsettings *as) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| assert(name != NULL); |
| assert(callback_fn != NULL); |
| assert(as != NULL); |
| |
| return klass->open_in(be, sw, name, callback_opaque, callback_fn, as); |
| } |
| |
| SWVoiceOut *audio_be_open_out( |
| AudioBackend *be, |
| SWVoiceOut *sw, |
| const char *name, |
| void *callback_opaque, |
| audio_callback_fn callback_fn, |
| const struct audsettings *as) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| assert(name != NULL); |
| assert(callback_fn != NULL); |
| assert(as != NULL); |
| |
| return klass->open_out(be, sw, name, callback_opaque, callback_fn, as); |
| } |
| |
| void audio_be_close_out(AudioBackend *be, SWVoiceOut *sw) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return; |
| } |
| |
| return klass->close_out(be, sw); |
| } |
| |
| void audio_be_close_in(AudioBackend *be, SWVoiceIn *sw) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return; |
| } |
| |
| return klass->close_in(be, sw); |
| } |
| |
| bool audio_be_is_active_out(AudioBackend *be, SWVoiceOut *sw) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return false; |
| } |
| |
| return klass->is_active_out(be, sw); |
| } |
| |
| bool audio_be_is_active_in(AudioBackend *be, SWVoiceIn *sw) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return false; |
| } |
| |
| return klass->is_active_in(be, sw); |
| } |
| |
| size_t audio_be_write(AudioBackend *be, SWVoiceOut *sw, void *buf, size_t size) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return 0; |
| } |
| |
| return klass->write(be, sw, buf, size); |
| } |
| |
| size_t audio_be_read(AudioBackend *be, SWVoiceIn *sw, void *buf, size_t size) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return 0; |
| } |
| |
| return klass->read(be, sw, buf, size); |
| } |
| |
| int audio_be_get_buffer_size_out(AudioBackend *be, SWVoiceOut *sw) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return 0; |
| } |
| |
| return klass->get_buffer_size_out(be, sw); |
| } |
| |
| void audio_be_set_active_out(AudioBackend *be, SWVoiceOut *sw, bool on) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| trace_audio_be_set_active_out(sw, on); |
| |
| if (!sw) { |
| return; |
| } |
| |
| return klass->set_active_out(be, sw, on); |
| } |
| |
| void audio_be_set_active_in(AudioBackend *be, SWVoiceIn *sw, bool on) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| trace_audio_be_set_active_in(sw, on); |
| |
| if (!sw) { |
| return; |
| } |
| |
| return klass->set_active_in(be, sw, on); |
| } |
| |
| void audio_be_set_volume_out(AudioBackend *be, SWVoiceOut *sw, Volume *vol) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return; |
| } |
| |
| klass->set_volume_out(be, sw, vol); |
| } |
| |
| void audio_be_set_volume_in(AudioBackend *be, SWVoiceIn *sw, Volume *vol) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!sw) { |
| return; |
| } |
| |
| klass->set_volume_in(be, sw, vol); |
| } |
| |
| CaptureVoiceOut *audio_be_add_capture( |
| AudioBackend *be, |
| const struct audsettings *as, |
| const struct audio_capture_ops *ops, |
| void *cb_opaque) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| assert(as != NULL); |
| assert(ops != NULL); |
| |
| return klass->add_capture(be, as, ops, cb_opaque); |
| } |
| |
| void audio_be_del_capture(AudioBackend *be, CaptureVoiceOut *cap, void *cb_opaque) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| if (!cap) { |
| return; |
| } |
| |
| klass->del_capture(be, cap, cb_opaque); |
| } |
| |
| #ifdef CONFIG_GIO |
| bool audio_be_can_set_dbus_server(AudioBackend *be) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| return klass->set_dbus_server != NULL; |
| } |
| |
| bool audio_be_set_dbus_server(AudioBackend *be, |
| GDBusObjectManagerServer *server, |
| bool p2p, |
| Error **errp) |
| { |
| AudioBackendClass *klass = AUDIO_BACKEND_GET_CLASS(be); |
| |
| assert(server != NULL); |
| |
| if (!audio_be_can_set_dbus_server(be)) { |
| error_setg(errp, "Audiodev '%s' is not compatible with DBus", |
| audio_be_get_id(be)); |
| return false; |
| } |
| |
| return klass->set_dbus_server(be, server, p2p, errp); |
| } |
| #endif |
| |
| const char *audio_be_get_id(AudioBackend *be) |
| { |
| if (be) { |
| return AUDIO_BACKEND_GET_CLASS(be)->get_id(be); |
| } else { |
| return ""; |
| } |
| } |
| |
| AudioBackend *audio_be_new(Audiodev *dev, Error **errp) |
| { |
| const char *drvname = AudiodevDriver_str(dev->driver); |
| g_autofree char *type = g_strconcat("audio-", drvname, NULL); |
| AudioBackend *be = AUDIO_BACKEND(object_new(type)); |
| |
| if (!be) { |
| error_setg(errp, "Unknown audio driver `%s'", drvname); |
| qapi_free_Audiodev(dev); |
| return NULL; |
| } |
| |
| if (!AUDIO_BACKEND_GET_CLASS(be)->realize(be, dev, errp)) { |
| object_unref(OBJECT(be)); |
| return NULL; |
| } |
| |
| return be; |
| } |
| |
| static const TypeInfo audio_types[] = { |
| { |
| .name = TYPE_AUDIO_BACKEND, |
| .parent = TYPE_OBJECT, |
| .instance_size = sizeof(AudioBackend), |
| .abstract = true, |
| .class_size = sizeof(AudioBackendClass), |
| }, |
| }; |
| |
| DEFINE_TYPES(audio_types) |