From: Marc-André Lureau <marcandre.lureau@redhat.com>
Migrate the PulseAudio backend from the legacy driver init/fini
callbacks to proper QOM realize and finalize methods.
The paaudio struct fields are now embedded directly in the AudioPa
QOM object instead of being allocated separately as drv_opaque. This
allows accessing the backend state through proper QOM type casting
with AUDIO_PA() rather than casting drv_opaque pointers.
The PulseAudio connection is now managed through the QOM lifecycle,
with the connection reference acquired in realize and released in
finalize.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
audio/paaudio.c | 109 +++++++++++++++++++++++++-----------------------
1 file changed, 57 insertions(+), 52 deletions(-)
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 941f75f25e8..8191b54468e 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -14,19 +14,10 @@
#define TYPE_AUDIO_PA "audio-pa"
OBJECT_DECLARE_SIMPLE_TYPE(AudioPa, AUDIO_PA)
-struct AudioPa {
- AudioMixengBackend parent;
-};
+static AudioBackendClass *audio_pa_parent_class;
static struct audio_driver pa_audio_driver;
-static void audio_pa_class_init(ObjectClass *klass, const void *data)
-{
- AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);
-
- k->driver = &pa_audio_driver;
-}
-
typedef struct PAConnection {
char *server;
int refcount;
@@ -36,18 +27,19 @@ typedef struct PAConnection {
pa_context *context;
} PAConnection;
-static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
- QTAILQ_HEAD_INITIALIZER(pa_conns);
+struct AudioPa {
+ AudioMixengBackend parent;
-typedef struct {
- Audiodev *dev;
PAConnection *conn;
-} paaudio;
+};
+
+static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
+ QTAILQ_HEAD_INITIALIZER(pa_conns);
typedef struct {
HWVoiceOut hw;
pa_stream *stream;
- paaudio *g;
+ AudioPa *g;
} PAVoiceOut;
typedef struct {
@@ -55,7 +47,7 @@ typedef struct {
pa_stream *stream;
const void *read_data;
size_t read_length;
- paaudio *g;
+ AudioPa *g;
} PAVoiceIn;
static void qpa_conn_fini(PAConnection *c);
@@ -529,23 +521,25 @@ fail:
static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
+ AudioMixengBackend *amb = hw->s;
+ AudioPa *apa = AUDIO_PA(amb);
int error;
pa_sample_spec ss;
pa_buffer_attr ba;
struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
- paaudio *g = pa->g = drv_opaque;
- AudiodevPaOptions *popts = &g->dev->u.pa;
+ AudiodevPaOptions *popts = &amb->dev->u.pa;
AudiodevPaPerDirectionOptions *ppdo = popts->out;
- PAConnection *c = g->conn;
+ PAConnection *c = apa->conn;
+ pa->g = apa;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
ss.rate = as->freq;
ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
ba.minreq = pa_usec_to_bytes(MIN(ppdo->latency >> 2,
- (g->dev->timer_period >> 2) * 3), &ss);
+ (amb->dev->timer_period >> 2) * 3), &ss);
ba.maxlength = -1;
ba.prebuf = -1;
@@ -553,7 +547,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
pa->stream = qpa_simple_new (
c,
- ppdo->stream_name ?: g->dev->id,
+ ppdo->stream_name ?: amb->dev->id,
PA_STREAM_PLAYBACK,
ppdo->name,
&ss,
@@ -578,23 +572,25 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
+ AudioMixengBackend *amb = hw->s;
+ AudioPa *apa = AUDIO_PA(amb);
int error;
pa_sample_spec ss;
pa_buffer_attr ba;
struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw;
- paaudio *g = pa->g = drv_opaque;
- AudiodevPaOptions *popts = &g->dev->u.pa;
+ AudiodevPaOptions *popts = &amb->dev->u.pa;
AudiodevPaPerDirectionOptions *ppdo = popts->in;
- PAConnection *c = g->conn;
+ PAConnection *c = apa->conn;
+ pa->g = apa;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
ss.rate = as->freq;
- ba.fragsize = pa_usec_to_bytes((g->dev->timer_period >> 1) * 3, &ss);
+ ba.fragsize = pa_usec_to_bytes((amb->dev->timer_period >> 1) * 3, &ss);
ba.maxlength = pa_usec_to_bytes(
- MAX(ppdo->latency, g->dev->timer_period * 3), &ss);
+ MAX(ppdo->latency, amb->dev->timer_period * 3), &ss);
ba.minreq = -1;
ba.prebuf = -1;
@@ -602,7 +598,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
pa->stream = qpa_simple_new (
c,
- ppdo->stream_name ?: g->dev->id,
+ ppdo->stream_name ?: amb->dev->id,
PA_STREAM_RECORD,
ppdo->name,
&ss,
@@ -834,15 +830,20 @@ fail:
return NULL;
}
-static void *qpa_audio_init(Audiodev *dev, Error **errp)
+static bool
+audio_pa_realize(AudioBackend *abe, Audiodev *dev, Error **errp)
{
- paaudio *g;
+ AudioPa *apa = AUDIO_PA(abe);
AudiodevPaOptions *popts = &dev->u.pa;
const char *server;
PAConnection *c;
assert(dev->driver == AUDIODEV_DRIVER_PA);
+ if (!audio_pa_parent_class->realize(abe, dev, errp)) {
+ return false;
+ }
+
if (!popts->server) {
char pidfile[64];
char *runtime;
@@ -851,42 +852,38 @@ static void *qpa_audio_init(Audiodev *dev, Error **errp)
runtime = getenv("XDG_RUNTIME_DIR");
if (!runtime) {
error_setg(errp, "XDG_RUNTIME_DIR not set");
- return NULL;
+ return false;
}
snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
if (stat(pidfile, &st) != 0) {
error_setg_errno(errp, errno, "could not stat pidfile %s", pidfile);
- return NULL;
+ return false;
}
}
qpa_validate_per_direction_opts(dev, popts->in);
qpa_validate_per_direction_opts(dev, popts->out);
- g = g_new0(paaudio, 1);
server = popts->server;
-
- g->dev = dev;
-
QTAILQ_FOREACH(c, &pa_conns, list) {
if (server == NULL || c->server == NULL ?
server == c->server :
strcmp(server, c->server) == 0) {
- g->conn = c;
+ apa->conn = c;
break;
}
}
- if (!g->conn) {
- g->conn = qpa_conn_init(server);
+ if (!apa->conn) {
+ apa->conn = qpa_conn_init(server);
}
- if (!g->conn) {
- g_free(g);
+ if (!apa->conn) {
error_setg(errp, "could not connect to PulseAudio server");
- return NULL;
+ return false;
}
- ++g->conn->refcount;
- return g;
+ ++apa->conn->refcount;
+
+ return true;
}
static void qpa_conn_fini(PAConnection *c)
@@ -908,16 +905,14 @@ static void qpa_conn_fini(PAConnection *c)
g_free(c);
}
-static void qpa_audio_fini (void *opaque)
+static void audio_pa_finalize(Object *obj)
{
- paaudio *g = opaque;
- PAConnection *c = g->conn;
+ AudioPa *apa = AUDIO_PA(obj);
+ PAConnection *c = apa->conn;
- if (--c->refcount == 0) {
+ if (c && --c->refcount == 0) {
qpa_conn_fini(c);
}
-
- g_free(g);
}
static struct audio_pcm_ops qpa_pcm_ops = {
@@ -939,8 +934,6 @@ static struct audio_pcm_ops qpa_pcm_ops = {
static struct audio_driver pa_audio_driver = {
.name = "pa",
- .init = qpa_audio_init,
- .fini = qpa_audio_fini,
.pcm_ops = &qpa_pcm_ops,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
@@ -948,11 +941,23 @@ static struct audio_driver pa_audio_driver = {
.voice_size_in = sizeof (PAVoiceIn),
};
+static void audio_pa_class_init(ObjectClass *klass, const void *data)
+{
+ AudioBackendClass *b = AUDIO_BACKEND_CLASS(klass);
+ AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_CLASS(klass);
+
+ audio_pa_parent_class = AUDIO_BACKEND_CLASS(object_class_get_parent(klass));
+
+ b->realize = audio_pa_realize;
+ k->driver = &pa_audio_driver;
+}
+
static const TypeInfo audio_pa_info = {
.name = TYPE_AUDIO_PA,
.parent = TYPE_AUDIO_MIXENG_BACKEND,
.instance_size = sizeof(AudioPa),
.class_init = audio_pa_class_init,
+ .instance_finalize = audio_pa_finalize,
};
static void register_audio_pa(void)
--
2.52.0