[PATCH 07/43] audio/pa: convert to QOM lifecycle methods

marcandre.lureau@redhat.com posted 43 patches 1 week, 6 days ago
Maintainers: Gerd Hoffmann <kraxel@redhat.com>, Christian Schoenebeck <qemu_oss@crudebyte.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Thomas Huth <huth@tuxfamily.org>, Alexandre Ratchov <alex@caoua.org>, Laurent Vivier <laurent@vivier.eu>, Manos Pitsidianakis <manos.pitsidianakis@linaro.org>, "Michael S. Tsirkin" <mst@redhat.com>, Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Peter Maydell <peter.maydell@linaro.org>
[PATCH 07/43] audio/pa: convert to QOM lifecycle methods
Posted by marcandre.lureau@redhat.com 1 week, 6 days ago
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