blob: ee065fa49688eb1ac68f72ad42ff807849c8d306 [file] [log] [blame]
/* 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)