From 273a5d35dcffba533c7c341b571a7c60e4e048ed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 May 2015 18:16:52 +0200 Subject: [PATCH] more cleanup fixes --- src/client/pv-context.c | 55 +++++++++---------- src/client/pv-private.h | 2 - src/client/pv-stream.c | 64 +++++++++++++++------- src/gst/gstpvsink.c | 32 ++++++++++- src/server/pv-client.c | 100 +++++++++++++++++++++++++++++++--- src/server/pv-client.h | 1 + src/server/pv-daemon.c | 19 +++++++ src/server/pv-source-output.c | 25 ++++++++- src/server/pv-source.c | 26 +++++++-- 9 files changed, 257 insertions(+), 67 deletions(-) diff --git a/src/client/pv-context.c b/src/client/pv-context.c index fd339cac7..084a659a3 100644 --- a/src/client/pv-context.c +++ b/src/client/pv-context.c @@ -68,7 +68,7 @@ pv_context_get_property (GObject *_object, switch (prop_id) { case PROP_MAIN_CONTEXT: - g_value_set_pointer (value, priv->context); + g_value_set_boxed (value, priv->context); break; case PROP_NAME: @@ -108,7 +108,7 @@ pv_context_set_property (GObject *_object, switch (prop_id) { case PROP_MAIN_CONTEXT: - priv->context = g_value_get_pointer (value); + priv->context = g_value_dup_boxed (value); break; case PROP_NAME: @@ -138,15 +138,17 @@ pv_context_finalize (GObject * object) PvContext *context = PV_CONTEXT (object); PvContextPrivate *priv = context->priv; + g_clear_pointer (&priv->context, g_main_context_unref); g_free (priv->name); - g_clear_error (&priv->error); if (priv->properties) g_variant_unref (priv->properties); + g_clear_object (&priv->subscribe); + g_clear_error (&priv->error); + G_OBJECT_CLASS (pv_context_parent_class)->finalize (object); } - static void pv_context_class_init (PvContextClass * klass) { @@ -165,12 +167,13 @@ pv_context_class_init (PvContextClass * klass) */ g_object_class_install_property (gobject_class, PROP_MAIN_CONTEXT, - g_param_spec_pointer ("main-context", - "Main Context", - "The main context to use", - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + g_param_spec_boxed ("main-context", + "Main Context", + "The main context to use", + G_TYPE_MAIN_CONTEXT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); /** * PvContext:name * @@ -344,8 +347,7 @@ on_client_connected (GObject *source_object, PvContextPrivate *priv = context->priv; GVariant *ret; GError *error = NULL; - - g_assert (g_main_context_get_thread_default () == priv->context); + const gchar *client_path; ret = g_dbus_proxy_call_finish (priv->daemon, res, &error); if (ret == NULL) { @@ -355,16 +357,16 @@ on_client_connected (GObject *source_object, return; } - g_variant_get (ret, "(o)", &priv->client_path); - g_variant_unref (ret); + g_variant_get (ret, "(&o)", &client_path); pv_subscribe_get_proxy (priv->subscribe, PV_DBUS_SERVICE, - priv->client_path, + client_path, "org.pulsevideo.Client1", NULL, on_client_proxy, context); + g_variant_unref (ret); } static void @@ -375,8 +377,6 @@ on_daemon_connected (GObject *source_object, PvContext *context = user_data; PvContextPrivate *priv = context->priv; - g_assert (g_main_context_get_thread_default () == priv->context); - context_set_state (context, PV_CONTEXT_STATE_REGISTERING); g_dbus_proxy_call (priv->daemon, @@ -399,11 +399,9 @@ subscription_cb (PvSubscribe *subscribe, PvContext *context = user_data; PvContextPrivate *priv = context->priv; - g_assert (g_main_context_get_thread_default () == priv->context); - switch (flags) { case PV_SUBSCRIPTION_FLAGS_DAEMON: - priv->daemon = object; + priv->daemon = g_object_ref (object); break; case PV_SUBSCRIPTION_FLAGS_CLIENT: @@ -439,7 +437,6 @@ subscription_state (GObject *object, PvContextPrivate *priv = context->priv; PvSubscriptionState state; - g_assert (g_main_context_get_thread_default () == priv->context); g_assert (object == G_OBJECT (priv->subscribe)); state = pv_subscribe_get_state (priv->subscribe); @@ -464,8 +461,6 @@ on_name_appeared (GDBusConnection *connection, PvContext *context = user_data; PvContextPrivate *priv = context->priv; - g_assert (g_main_context_get_thread_default () == priv->context); - priv->connection = connection; g_object_set (priv->subscribe, "connection", priv->connection, @@ -480,8 +475,6 @@ on_name_vanished (GDBusConnection *connection, PvContext *context = user_data; PvContextPrivate *priv = context->priv; - g_assert (g_main_context_get_thread_default () == priv->context); - priv->connection = connection; g_object_set (priv->subscribe, "connection", connection, NULL); @@ -510,7 +503,7 @@ do_connect (PvContext *context) on_name_appeared, on_name_vanished, context, - NULL); + g_object_unref); return FALSE; } @@ -536,7 +529,9 @@ pv_context_connect (PvContext *context, PvContextFlags flags) priv->flags = flags; context_set_state (context, PV_CONTEXT_STATE_CONNECTING); - g_main_context_invoke (priv->context, (GSourceFunc) do_connect, context); + g_main_context_invoke (priv->context, + (GSourceFunc) do_connect, + g_object_ref (context)); return TRUE; } @@ -556,6 +551,7 @@ on_client_disconnected (GObject *source_object, g_error ("failed to disconnect client: %s", error->message); priv->error = error; context_set_state (context, PV_CONTEXT_STATE_ERROR); + g_object_unref (context); return; } g_variant_unref (ret); @@ -566,6 +562,7 @@ on_client_disconnected (GObject *source_object, priv->id = 0; context_set_state (context, PV_CONTEXT_STATE_UNCONNECTED); + g_object_unref (context); } static gboolean @@ -603,7 +600,9 @@ pv_context_disconnect (PvContext *context) priv = context->priv; g_return_val_if_fail (priv->client != NULL, FALSE); - g_main_context_invoke (priv->context, (GSourceFunc) do_disconnect, context); + g_main_context_invoke (priv->context, + (GSourceFunc) do_disconnect, + g_object_ref (context)); return TRUE; } diff --git a/src/client/pv-private.h b/src/client/pv-private.h index 61e4b8f40..3e4141357 100644 --- a/src/client/pv-private.h +++ b/src/client/pv-private.h @@ -33,8 +33,6 @@ struct _PvContextPrivate GError *error; GDBusProxy *daemon; - - gchar *client_path; GDBusProxy *client; PvSubscriptionFlags subscription_mask; diff --git a/src/client/pv-stream.c b/src/client/pv-stream.c index c15cbe132..588a80b37 100644 --- a/src/client/pv-stream.c +++ b/src/client/pv-stream.c @@ -33,15 +33,17 @@ struct _PvStreamPrivate PvContext *context; gchar *name; GVariant *properties; - gchar *target; + PvStreamState state; GError *error; + + gchar *target; + GBytes *accepted_formats; gboolean provide; - GBytes *accepted_formats; GBytes *possible_formats; GBytes *format; - gchar *source_output_path; + GDBusProxy *source_output; PvStreamMode mode; @@ -156,6 +158,22 @@ pv_stream_finalize (GObject * object) PvStream *stream = PV_STREAM (object); PvStreamPrivate *priv = stream->priv; + g_clear_object (&priv->source_output); + + if (priv->possible_formats) + g_bytes_unref (priv->possible_formats); + if (priv->format) + g_bytes_unref (priv->format); + + g_free (priv->target); + if (priv->accepted_formats) + g_bytes_unref (priv->accepted_formats); + + g_clear_error (&priv->error); + + if (priv->properties) + g_variant_unref (priv->properties); + g_clear_object (&priv->context); g_free (priv->name); G_OBJECT_CLASS (pv_stream_parent_class)->finalize (object); @@ -408,6 +426,7 @@ on_source_output_proxy (GObject *source_object, stream); stream_set_state (stream, PV_STREAM_STATE_READY); + g_object_unref (stream); return; @@ -416,6 +435,7 @@ source_output_failed: priv->error = error; stream_set_state (stream, PV_STREAM_STATE_ERROR); g_error ("failed to get source output proxy: %s", error->message); + g_object_unref (stream); return; } } @@ -430,23 +450,22 @@ on_source_output_created (GObject *source_object, PvContext *context = priv->context; GVariant *ret; GError *error = NULL; - - g_assert (g_main_context_get_thread_default () == priv->context->priv->context); + const gchar *source_output_path; ret = g_dbus_proxy_call_finish (context->priv->client, res, &error); if (ret == NULL) goto create_failed; - g_variant_get (ret, "(o)", &priv->source_output_path); - g_variant_unref (ret); + g_variant_get (ret, "(o)", &source_output_path); pv_subscribe_get_proxy (context->priv->subscribe, PV_DBUS_SERVICE, - priv->source_output_path, + source_output_path, "org.pulsevideo.SourceOutput1", NULL, on_source_output_proxy, stream); + g_variant_unref (ret); return; @@ -456,6 +475,7 @@ create_failed: priv->error = error; stream_set_state (stream, PV_STREAM_STATE_ERROR); g_warning ("failed to get connect capture: %s", error->message); + g_object_unref (stream); return; } } @@ -466,8 +486,6 @@ do_connect_capture (PvStream *stream) PvStreamPrivate *priv = stream->priv; PvContext *context = priv->context; - g_assert (g_main_context_get_thread_default () == priv->context->priv->context); - g_dbus_proxy_call (context->priv->client, "CreateSourceOutput", g_variant_new ("(ss)", @@ -509,13 +527,18 @@ pv_stream_connect_capture (PvStream *stream, context = priv->context; g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE); + g_free (priv->target); priv->target = g_strdup (source); + if (priv->accepted_formats) + g_bytes_unref (priv->accepted_formats); priv->accepted_formats = g_bytes_ref (accepted_formats); priv->provide = FALSE; stream_set_state (stream, PV_STREAM_STATE_CONNECTING); - g_main_context_invoke (context->priv->context, (GSourceFunc) do_connect_capture, stream); + g_main_context_invoke (context->priv->context, + (GSourceFunc) do_connect_capture, + g_object_ref (stream)); return TRUE; } @@ -526,8 +549,6 @@ do_connect_provide (PvStream *stream) PvStreamPrivate *priv = stream->priv; PvContext *context = priv->context; - g_assert (g_main_context_get_thread_default () == priv->context->priv->context); - g_dbus_proxy_call (context->priv->client, "CreateSourceInput", g_variant_new ("(s)", g_bytes_get_data (priv->possible_formats, NULL)), @@ -565,12 +586,16 @@ pv_stream_connect_provide (PvStream *stream, context = priv->context; g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE); + if (priv->possible_formats) + g_bytes_unref (priv->possible_formats); priv->possible_formats = g_bytes_ref (possible_formats); priv->provide = TRUE; stream_set_state (stream, PV_STREAM_STATE_CONNECTING); - g_main_context_invoke (context->priv->context, (GSourceFunc) do_connect_provide, stream); + g_main_context_invoke (context->priv->context, + (GSourceFunc) do_connect_provide, + g_object_ref (stream)); return TRUE; } @@ -585,19 +610,18 @@ on_source_output_removed (GObject *source_object, GVariant *ret; GError *error = NULL; - g_assert (g_main_context_get_thread_default () == priv->context->priv->context); - ret = g_dbus_proxy_call_finish (priv->source_output, res, &error); if (ret == NULL) { priv->error = error; stream_set_state (stream, PV_STREAM_STATE_ERROR); g_warning ("failed to disconnect: %s", error->message); + g_object_unref (stream); return; } - g_clear_pointer (&priv->source_output_path, g_free); g_clear_object (&priv->source_output); stream_set_state (stream, PV_STREAM_STATE_UNCONNECTED); + g_object_unref (stream); } static gboolean @@ -605,8 +629,6 @@ do_disconnect (PvStream *stream) { PvStreamPrivate *priv = stream->priv; - g_assert (g_main_context_get_thread_default () == priv->context->priv->context); - g_dbus_proxy_call (priv->source_output, "Remove", g_variant_new ("()"), @@ -640,7 +662,9 @@ pv_stream_disconnect (PvStream *stream) context = priv->context; g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE); - g_main_context_invoke (context->priv->context, (GSourceFunc) do_disconnect, stream); + g_main_context_invoke (context->priv->context, + (GSourceFunc) do_disconnect, + g_object_ref (stream)); return TRUE; } diff --git a/src/gst/gstpvsink.c b/src/gst/gstpvsink.c index e90ec65fe..505c2fa32 100644 --- a/src/gst/gstpvsink.c +++ b/src/gst/gstpvsink.c @@ -395,7 +395,6 @@ on_state_notify (GObject *gobject, static gboolean gst_pulsevideo_sink_open (GstPulsevideoSink * pvsink) { - pvsink->ctx = pv_context_new (pvsink->context, "test-client", NULL); g_signal_connect (pvsink->ctx, "notify::state", (GCallback) on_state_notify, pvsink); @@ -425,6 +424,36 @@ connect_error: } } +static gboolean +gst_pulsevideo_sink_close (GstPulsevideoSink * pvsink) +{ + if (pvsink->stream) { + pv_stream_disconnect (pvsink->stream); + } + if (pvsink->ctx) { + pv_context_disconnect(pvsink->ctx); + + g_mutex_lock (&pvsink->lock); + while (TRUE) { + PvContextState state = pv_context_get_state (pvsink->ctx); + + if (state == PV_CONTEXT_STATE_UNCONNECTED) + break; + + if (state == PV_CONTEXT_STATE_ERROR) + break; + + g_cond_wait (&pvsink->cond, &pvsink->lock); + } + g_mutex_unlock (&pvsink->lock); + } + + g_clear_object (&pvsink->stream); + g_clear_object (&pvsink->ctx); + + return TRUE; +} + static GstStateChangeReturn gst_pulsevideo_sink_change_state (GstElement * element, GstStateChange transition) { @@ -460,6 +489,7 @@ gst_pulsevideo_sink_change_state (GstElement * element, GstStateChange transitio case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_pulsevideo_sink_close (this); break; case GST_STATE_CHANGE_READY_TO_NULL: g_main_loop_quit (this->loop); diff --git a/src/server/pv-client.c b/src/server/pv-client.c index d72d87390..97cc65dcf 100644 --- a/src/server/pv-client.c +++ b/src/server/pv-client.c @@ -51,6 +51,14 @@ enum PROP_PROPERTIES, }; +enum +{ + SIGNAL_DISCONNECT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + static void pv_client_get_property (GObject *_object, guint prop_id, @@ -132,6 +140,10 @@ handle_create_source_output (PvClient1 *interface, GBytes *formats; GError *error = NULL; + sender = g_dbus_method_invocation_get_sender (invocation); + if (g_strcmp0 (pv_client_get_sender (client), sender) != 0) + goto not_allowed; + formats = g_bytes_new (arg_accepted_formats, strlen (arg_accepted_formats) + 1); source = pv_daemon_find_source (priv->daemon, @@ -150,17 +162,25 @@ handle_create_source_output (PvClient1 *interface, if (output == NULL) goto no_output; - sender = g_dbus_method_invocation_get_sender (invocation); - - pv_daemon_track_object (priv->daemon, sender, G_OBJECT (output)); - object_path = pv_source_output_get_object_path (output); + + g_object_set_data_full (G_OBJECT (client), + object_path, + output, + g_object_unref); + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", object_path)); return TRUE; /* ERRORS */ +not_allowed: + { + g_dbus_method_invocation_return_dbus_error (invocation, + "org.pulsevideo.Error", "not client owner"); + return TRUE; + } no_source: { g_dbus_method_invocation_return_gerror (invocation, error); @@ -191,13 +211,20 @@ handle_create_source_input (PvClient1 *interface, GBytes *formats; GError *error = NULL; + sender = g_dbus_method_invocation_get_sender (invocation); + if (g_strcmp0 (pv_client_get_sender (client), sender) != 0) + goto not_allowed; + source = pv_client_source_new (priv->daemon); if (source == NULL) goto no_source; - sender = g_dbus_method_invocation_get_sender (invocation); + g_object_set_data_full (G_OBJECT (client), + pv_source_get_object_path (PV_SOURCE (source)), + source, + g_object_unref); - pv_daemon_track_object (priv->daemon, sender, G_OBJECT (source)); + sender = g_dbus_method_invocation_get_sender (invocation); formats = g_bytes_new (arg_possible_formats, strlen (arg_possible_formats) + 1); @@ -209,9 +236,13 @@ handle_create_source_input (PvClient1 *interface, if (input == NULL) goto no_input; - pv_daemon_track_object (priv->daemon, sender, G_OBJECT (input)); - source_input_path = pv_source_output_get_object_path (input); + + g_object_set_data_full (G_OBJECT (client), + source_input_path, + input, + g_object_unref); + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", source_input_path)); @@ -219,6 +250,12 @@ handle_create_source_input (PvClient1 *interface, return TRUE; /* ERRORS */ +not_allowed: + { + g_dbus_method_invocation_return_dbus_error (invocation, + "org.pulsevideo.Error", "not client owner"); + return TRUE; + } no_source: { g_dbus_method_invocation_return_dbus_error (invocation, @@ -233,6 +270,19 @@ no_input: return TRUE; } } +static gboolean +handle_disconnect (PvClient1 *interface, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + PvClient *client = user_data; + + g_signal_emit (client, signals[SIGNAL_DISCONNECT], 0, NULL); + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("()")); + return TRUE; +} static void client_register_object (PvClient *client, const gchar *prefix) @@ -254,6 +304,9 @@ client_register_object (PvClient *client, const gchar *prefix) g_signal_connect (priv->client1, "handle-create-source-input", (GCallback) handle_create_source_input, client); + g_signal_connect (priv->client1, "handle-disconnect", + (GCallback) handle_disconnect, + client); pv_object_skeleton_set_client1 (skel, priv->client1); g_free (priv->object_path); @@ -347,6 +400,18 @@ pv_client_class_init (PvClientClass * klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + signals[SIGNAL_DISCONNECT] = g_signal_new ("disconnect", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 0, + G_TYPE_NONE); + } static void @@ -381,6 +446,25 @@ pv_client_new (PvDaemon *daemon, NULL); } +/** + * pv_client_get_sender: + * @client: a #PvClient + * + * Get the sender of @client. + * + * Returns: the sender of @client + */ +const gchar * +pv_client_get_sender (PvClient *client) +{ + PvClientPrivate *priv; + + g_return_val_if_fail (PV_IS_CLIENT (client), NULL); + priv = client->priv; + + return priv->sender; +} + /** * pv_client_get_object_path: * @client: a #PvClient diff --git a/src/server/pv-client.h b/src/server/pv-client.h index 5ac5c2c59..dbaa01d28 100644 --- a/src/server/pv-client.h +++ b/src/server/pv-client.h @@ -67,6 +67,7 @@ PvClient * pv_client_new (PvDaemon *daemon, const gchar *prefix, GVariant *properties); +const gchar * pv_client_get_sender (PvClient *client); const gchar * pv_client_get_object_path (PvClient *client); G_END_DECLS diff --git a/src/server/pv-daemon.c b/src/server/pv-daemon.c index 86ef3828a..ed160d177 100644 --- a/src/server/pv-daemon.c +++ b/src/server/pv-daemon.c @@ -105,6 +105,24 @@ sender_data_new (PvDaemon *daemon, const gchar *sender) return data; } +static void +handle_disconnect_client (PvClient *client, + gpointer user_data) +{ + PvDaemon *daemon = user_data; + PvDaemonPrivate *priv = daemon->priv; + const gchar *sender; + SenderData *data; + + sender = pv_client_get_sender (client); + + data = g_hash_table_lookup (priv->senders, sender); + if (data == NULL) + return; + + data->objects = g_list_remove (data->objects, client); + g_object_unref (client); +} static gboolean handle_connect_client (PvDaemon1 *interface, @@ -119,6 +137,7 @@ handle_connect_client (PvDaemon1 *interface, sender = g_dbus_method_invocation_get_sender (invocation); client = pv_client_new (daemon, sender, PV_DBUS_OBJECT_PREFIX, arg_properties); + g_signal_connect (client, "disconnect", (GCallback) handle_disconnect_client, daemon); pv_daemon_track_object (daemon, sender, G_OBJECT (client)); diff --git a/src/server/pv-source-output.c b/src/server/pv-source-output.c index 09f4b2c06..52a47693a 100644 --- a/src/server/pv-source-output.c +++ b/src/server/pv-source-output.c @@ -63,6 +63,14 @@ enum PROP_SOCKET, }; +enum +{ + SIGNAL_REMOVE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + static void pv_source_output_get_property (GObject *_object, guint prop_id, @@ -239,6 +247,8 @@ handle_remove (PvSourceOutput1 *interface, stop_transfer (output); + g_signal_emit (output, signals[SIGNAL_REMOVE], 0, NULL); + g_dbus_method_invocation_return_value (invocation, NULL); return TRUE; @@ -287,8 +297,8 @@ pv_source_output_finalize (GObject * object) PvSourceOutput *output = PV_SOURCE_OUTPUT (object); PvSourceOutputPrivate *priv = output->priv; - g_object_unref (priv->daemon); - g_object_unref (priv->iface); + g_clear_object (&priv->daemon); + g_clear_object (&priv->iface); g_free (priv->client_path); g_free (priv->object_path); g_free (priv->source_path); @@ -395,6 +405,17 @@ pv_source_output_class_init (PvSourceOutputClass * klass) G_TYPE_SOCKET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + signals[SIGNAL_REMOVE] = g_signal_new ("remove", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 0, + G_TYPE_NONE); } static void diff --git a/src/server/pv-source.c b/src/server/pv-source.c index dfa28594d..f878c68be 100644 --- a/src/server/pv-source.c +++ b/src/server/pv-source.c @@ -194,6 +194,15 @@ default_set_state (PvSource *source, PvSourceState state) return TRUE; } +static void +handle_remove_output (PvSourceOutput *output, + gpointer user_data) +{ + PvSource *source = user_data; + + pv_source_release_source_output (source, output); +} + static PvSourceOutput * default_create_source_output (PvSource *source, const gchar *client_path, @@ -202,13 +211,18 @@ default_create_source_output (PvSource *source, GError **error) { PvSourcePrivate *priv = source->priv; + PvSourceOutput *output; - return g_object_new (PV_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon, - "object-path", prefix, - "client-path", client_path, - "source-path", priv->object_path, - "possible-formats", format_filter, - NULL); + output = g_object_new (PV_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon, + "object-path", prefix, + "client-path", client_path, + "source-path", priv->object_path, + "possible-formats", format_filter, + NULL); + + g_signal_connect (output, "remove", (GCallback) handle_remove_output, source); + + return output; } static gboolean