mirror of
https://github.com/qemu/qemu.git
synced 2026-04-05 21:50:33 +00:00
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>
275 lines
5.8 KiB
C
275 lines
5.8 KiB
C
/* 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)
|