[Spice-devel] [PATCH spice-gtk 1/2] audio: use weak references to channel

Fabiano Fidêncio fabiano at fidencio.org
Fri Nov 7 17:17:04 PST 2014


On Fri, Nov 7, 2014 at 8:41 PM, Marc-André Lureau
<marcandre.lureau at redhat.com> wrote:
> The audio channels are currently referenced and released on channel
> close events. However, this event may not happen if the channel never
> was connected. Keeping channels alive also prevent session from
> finishing.
>
> By not holding the ref, the channel can go to dispose
> when it is no longer needed, and the session can be disposed too.
> ---
>  gtk/spice-gstaudio.c | 81 ++++++++++++++++++++--------------------------------
>  gtk/spice-pulse.c    | 65 ++++++++++++++++-------------------------
>  2 files changed, 56 insertions(+), 90 deletions(-)
>
> diff --git a/gtk/spice-gstaudio.c b/gtk/spice-gstaudio.c
> index e6cf6a9..d784aa1 100644
> --- a/gtk/spice-gstaudio.c
> +++ b/gtk/spice-gstaudio.c
> @@ -53,9 +53,8 @@ struct _SpiceGstaudioPrivate {
>      guint                   mmtime_id;
>  };
>
> -static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
> -                          gpointer data);
>  static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel);
> +static void channel_weak_notified(gpointer data, GObject *where_the_object_was);
>
>  static void spice_gstaudio_finalize(GObject *obj)
>  {
> @@ -91,27 +90,21 @@ static void spice_gstaudio_dispose(GObject *obj)
>      stream_dispose(&p->playback);
>      stream_dispose(&p->record);
>
> -    if (p->pchannel != NULL) {
> -        g_signal_handlers_disconnect_by_func(p->pchannel,
> -                                             channel_event, obj);
> -        g_object_unref(p->pchannel);
> -        p->pchannel = NULL;
> -    }
> +    if (p->pchannel)
> +        g_object_weak_unref(G_OBJECT(p->pchannel), channel_weak_notified, gstaudio);
> +    p->pchannel = NULL;

Please, keep the explicit comparison here.
Using explicit comparisons for everything but booleans help a lot the
understanding when people are quick reading the code.

>
> -    if (p->rchannel != NULL) {
> -        g_signal_handlers_disconnect_by_func(p->rchannel,
> -                                             channel_event, obj);
> -        g_object_unref(p->rchannel);
> -        p->rchannel = NULL;
> -    }
> +    if (p->rchannel)
> +        g_object_weak_unref(G_OBJECT(p->rchannel), channel_weak_notified, gstaudio);
> +    p->rchannel = NULL;
>
>      if (G_OBJECT_CLASS(spice_gstaudio_parent_class)->dispose)
>          G_OBJECT_CLASS(spice_gstaudio_parent_class)->dispose(obj);
>  }
>
> -static void spice_gstaudio_init(SpiceGstaudio *pulse)
> +static void spice_gstaudio_init(SpiceGstaudio *gstaudio)
>  {
> -    pulse->priv = SPICE_GSTAUDIO_GET_PRIVATE(pulse);
> +    gstaudio->priv = SPICE_GSTAUDIO_GET_PRIVATE(gstaudio);
>  }
>
>  static void spice_gstaudio_class_init(SpiceGstaudioClass *klass)
> @@ -144,9 +137,8 @@ static void record_new_buffer(GstAppSink *appsink, gpointer data)
>      gst_element_post_message(p->record.pipe, msg);
>  }
>
> -static void record_stop(SpiceRecordChannel *channel, gpointer data)
> +static void record_stop(SpiceGstaudio *gstaudio)
>  {
> -    SpiceGstaudio *gstaudio = data;
>      SpiceGstaudioPrivate *p = gstaudio->priv;
>
>      SPICE_DEBUG("%s", __FUNCTION__);
> @@ -230,7 +222,7 @@ static void record_start(SpiceRecordChannel *channel, gint format, gint channels
>      if (p->record.pipe &&
>          (p->record.rate != frequency ||
>           p->record.channels != channels)) {
> -        record_stop(channel, data);
> +        record_stop(gstaudio);
>          gst_object_unref(p->record.pipe);
>          p->record.pipe = NULL;
>      }
> @@ -285,31 +277,6 @@ lerr:
>          gst_element_set_state(p->record.pipe, GST_STATE_PLAYING);
>  }
>
> -static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
> -                          gpointer data)
> -{
> -    SpiceGstaudio *gstaudio = data;
> -    SpiceGstaudioPrivate *p = gstaudio->priv;
> -
> -    switch (event) {
> -    case SPICE_CHANNEL_OPENED:
> -        break;
> -    case SPICE_CHANNEL_CLOSED:
> -        if (channel == p->pchannel) {
> -            p->pchannel = NULL;
> -            g_object_unref(channel);
> -        } else if (channel == p->rchannel) {
> -            record_stop(SPICE_RECORD_CHANNEL(channel), gstaudio);
> -            p->rchannel = NULL;
> -            g_object_unref(channel);
> -        } else /* if (p->pchannel || p->rchannel) */
> -            g_warn_if_reached();
> -        break;
> -    default:
> -        break;
> -    }
> -}
> -
>  static void playback_stop(SpicePlaybackChannel *channel, gpointer data)
>  {
>      SpiceGstaudio *gstaudio = data;
> @@ -542,6 +509,22 @@ static void record_mute_changed(GObject *object, GParamSpec *pspec, gpointer dat
>      g_object_unref(e);
>  }
>
> +static void
> +channel_weak_notified(gpointer data,
> +                      GObject *where_the_object_was)
> +{
> +    SpiceGstaudio *gstaudio = SPICE_GSTAUDIO(data);
> +    SpiceGstaudioPrivate *p = gstaudio->priv;
> +
> +    if (where_the_object_was == (GObject *)p->pchannel) {
> +        p->pchannel = NULL;
> +    } else if (where_the_object_was == (GObject *)p->rchannel) {
> +        SPICE_DEBUG("record closed");
> +        record_stop(gstaudio);
> +        p->rchannel = NULL;
> +    }
> +}
> +
>  static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>  {
>      SpiceGstaudio *gstaudio = SPICE_GSTAUDIO(audio);
> @@ -550,15 +533,14 @@ static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>      if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
>          g_return_val_if_fail(p->pchannel == NULL, FALSE);
>
> -        p->pchannel = g_object_ref(channel);
> +        p->pchannel = channel;
> +        g_object_weak_ref(G_OBJECT(p->pchannel), channel_weak_notified, audio);
>          spice_g_signal_connect_object(channel, "playback-start",
>                                        G_CALLBACK(playback_start), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "playback-data",
>                                        G_CALLBACK(playback_data), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "playback-stop",
>                                        G_CALLBACK(playback_stop), gstaudio, 0);
> -        spice_g_signal_connect_object(channel, "channel-event",
> -                                      G_CALLBACK(channel_event), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "notify::volume",
>                                        G_CALLBACK(playback_volume_changed), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "notify::mute",
> @@ -571,12 +553,11 @@ static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>          g_return_val_if_fail(p->rchannel == NULL, FALSE);
>
>          p->rchannel = g_object_ref(channel);

Do not ref channel here.

> +        g_object_weak_ref(G_OBJECT(p->rchannel), channel_weak_notified, audio);
>          spice_g_signal_connect_object(channel, "record-start",
>                                        G_CALLBACK(record_start), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "record-stop",
> -                                      G_CALLBACK(record_stop), gstaudio, 0);
> -        spice_g_signal_connect_object(channel, "channel-event",
> -                                      G_CALLBACK(channel_event), gstaudio, 0);
> +                                      G_CALLBACK(record_stop), gstaudio, G_CONNECT_SWAPPED);
>          spice_g_signal_connect_object(channel, "notify::volume",
>                                        G_CALLBACK(record_volume_changed), gstaudio, 0);
>          spice_g_signal_connect_object(channel, "notify::mute",
> diff --git a/gtk/spice-pulse.c b/gtk/spice-pulse.c
> index 744ce4d..fc1662e 100644
> --- a/gtk/spice-pulse.c
> +++ b/gtk/spice-pulse.c
> @@ -74,10 +74,9 @@ static const char *context_state_names[] = {
>  #define STATE_NAME(array, state) \
>      ((state < G_N_ELEMENTS(array)) ? array[state] : NULL)
>
> -static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
> -                          gpointer data);
>  static void stream_stop(SpicePulse *pulse, struct stream *s);
>  static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel);
> +static void channel_weak_notified(gpointer data, GObject *where_the_object_was);
>
>  static void spice_pulse_finalize(GObject *obj)
>  {
> @@ -120,11 +119,11 @@ static void spice_pulse_dispose(GObject *obj)
>      p->record.cork_op = NULL;
>
>      if (p->pchannel)
> -        g_object_unref(p->pchannel);
> +        g_object_weak_unref(G_OBJECT(p->pchannel), channel_weak_notified, pulse);
>      p->pchannel = NULL;
>
>      if (p->rchannel)
> -        g_object_unref(p->rchannel);
> +        g_object_weak_unref(G_OBJECT(p->rchannel), channel_weak_notified, pulse);
>      p->rchannel = NULL;
>
>      G_OBJECT_CLASS(spice_pulse_parent_class)->dispose(obj);
> @@ -567,9 +566,8 @@ static void record_start(SpiceRecordChannel *channel, gint format, gint channels
>      p->state = state;
>  }
>
> -static void record_stop(SpiceRecordChannel *channel, gpointer data)
> +static void record_stop(SpicePulse *pulse)
>  {
> -    SpicePulse *pulse = data;
>      SpicePulsePrivate *p = pulse->priv;
>
>      SPICE_DEBUG("%s", __FUNCTION__);
> @@ -581,33 +579,6 @@ static void record_stop(SpiceRecordChannel *channel, gpointer data)
>      stream_stop(pulse, &p->record);
>  }
>
> -static void channel_event(SpiceChannel *channel, SpiceChannelEvent event,
> -                          gpointer data)
> -{
> -    SpicePulse *pulse = data;
> -    SpicePulsePrivate *p = pulse->priv;
> -
> -    switch (event) {
> -    case SPICE_CHANNEL_OPENED:
> -        break;
> -    case SPICE_CHANNEL_CLOSED:
> -        if (channel == p->pchannel) {
> -            SPICE_DEBUG("playback closed");
> -            p->pchannel = NULL;
> -            g_object_unref(channel);
> -        } else if (channel == p->rchannel) {
> -            SPICE_DEBUG("record closed");
> -            record_stop(SPICE_RECORD_CHANNEL(channel), pulse);
> -            p->rchannel = NULL;
> -            g_object_unref(channel);
> -        } else /* if (p->pchannel || p->rchannel) */
> -            g_warn_if_reached();
> -        break;
> -    default:
> -        break;
> -    }
> -}
> -
>  static void playback_volume_changed(GObject *object, GParamSpec *pspec, gpointer data)
>  {
>      SpicePulse *pulse = data;
> @@ -748,6 +719,22 @@ static void record_volume_changed(GObject *object, GParamSpec *pspec, gpointer d
>          pa_operation_unref(op);
>  }
>
> +static void
> +channel_weak_notified(gpointer data,
> +                      GObject *where_the_object_was)
> +{
> +    SpicePulse *pulse = SPICE_PULSE(data);
> +    SpicePulsePrivate *p = pulse->priv;
> +
> +    if (where_the_object_was == (GObject *)p->pchannel) {
> +        p->pchannel = NULL;
> +    } else if (where_the_object_was == (GObject *)p->rchannel) {
> +        SPICE_DEBUG("record closed");
> +        record_stop(pulse);
> +        p->rchannel = NULL;
> +    }
> +}
> +
>  static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>  {
>      SpicePulse *pulse = SPICE_PULSE(audio);
> @@ -756,15 +743,14 @@ static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>      if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
>          g_return_val_if_fail(p->pchannel == NULL, FALSE);
>
> -        p->pchannel = g_object_ref(channel);
> +        p->pchannel = channel;
> +        g_object_weak_ref(G_OBJECT(p->pchannel), channel_weak_notified, audio);
>          spice_g_signal_connect_object(channel, "playback-start",
>                                        G_CALLBACK(playback_start), pulse, 0);
>          spice_g_signal_connect_object(channel, "playback-data",
>                                        G_CALLBACK(playback_data), pulse, 0);
>          spice_g_signal_connect_object(channel, "playback-stop",
>                                        G_CALLBACK(playback_stop), pulse, 0);
> -        spice_g_signal_connect_object(channel, "channel-event",
> -                                      G_CALLBACK(channel_event), pulse, 0);
>          spice_g_signal_connect_object(channel, "notify::volume",
>                                        G_CALLBACK(playback_volume_changed), pulse, 0);
>          spice_g_signal_connect_object(channel, "notify::mute",
> @@ -778,13 +764,12 @@ static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
>      if (SPICE_IS_RECORD_CHANNEL(channel)) {
>          g_return_val_if_fail(p->rchannel == NULL, FALSE);
>
> -        p->rchannel = g_object_ref(channel);
> +        p->rchannel = channel;
> +        g_object_weak_ref(G_OBJECT(p->rchannel), channel_weak_notified, audio);
>          spice_g_signal_connect_object(channel, "record-start",
>                                        G_CALLBACK(record_start), pulse, 0);
>          spice_g_signal_connect_object(channel, "record-stop",
> -                                      G_CALLBACK(record_stop), pulse, 0);
> -        spice_g_signal_connect_object(channel, "channel-event",
> -                                      G_CALLBACK(channel_event), pulse, 0);
> +                                      G_CALLBACK(record_stop), pulse, G_CONNECT_SWAPPED);
>          spice_g_signal_connect_object(channel, "notify::volume",
>                                        G_CALLBACK(record_volume_changed), pulse, 0);
>          spice_g_signal_connect_object(channel, "notify::mute",
> --
> 1.9.3
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel


Looks good. Please, consider the comment about the explicit comparisons.
ACK with ref change.
-- 
Fabiano Fidêncio


More information about the Spice-devel mailing list