From 09de2d3db9ac236f426445bc39119e0f46b903ed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 20 Apr 2015 17:24:58 +0200 Subject: [PATCH] handle remote and local sources better Track remote and local sources separately and make SourceProvider1 interfaces for remote objects so that we get the subscription right. Move disconnect from the Manager1 to Client1 interface and implement in the context. --- src/client/pv-context.c | 43 ++++++++++ src/client/pv-context.h | 1 + src/client/pv-source-output.c | 8 +- src/client/pv-source.c | 8 +- src/client/pv-subscribe.c | 13 +++ src/client/pv-subscribe.h | 9 +- src/daemon/main.c | 5 ++ src/dbus/org.pulsevideo.xml | 5 +- src/server/pv-client.c | 8 +- src/server/pv-daemon.c | 143 +++++++++++++++++++++----------- src/server/pv-daemon.h | 3 + src/server/pv-source-provider.c | 8 +- 12 files changed, 184 insertions(+), 70 deletions(-) diff --git a/src/client/pv-context.c b/src/client/pv-context.c index 66f4918d3..ee111a3bb 100644 --- a/src/client/pv-context.c +++ b/src/client/pv-context.c @@ -455,6 +455,49 @@ pv_context_connect (PvContext *context, PvContextFlags flags) return TRUE; } +static void +on_client_disconnected (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + PvContext *context = user_data; + PvContextPrivate *priv = context->priv; + GError *error = NULL; + + if (!pv_client1_call_disconnect_finish (priv->client, res, &error)) { + context_set_state (context, PV_CONTEXT_STATE_ERROR); + g_error ("failed to disconnect client: %s", error->message); + g_clear_error (&error); + return; + } + context_set_state (context, PV_CONTEXT_STATE_UNCONNECTED); +} + +/** + * pv_context_disconnect: + * @context: a #PvContext + * + * Disonnect from the daemon. + * + * Returns: %TRUE on success. + */ +gboolean +pv_context_disconnect (PvContext *context) +{ + PvContextPrivate *priv; + + g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE); + + priv = context->priv; + g_return_val_if_fail (priv->client != NULL, FALSE); + + pv_client1_call_disconnect (priv->client, + NULL, /* GCancellable *cancellable */ + on_client_disconnected, + context); + return TRUE; +} + gboolean pv_context_register_source (PvContext *context, PvSource *source) { diff --git a/src/client/pv-context.h b/src/client/pv-context.h index 1c2781c0e..e8cadeb9d 100644 --- a/src/client/pv-context.h +++ b/src/client/pv-context.h @@ -103,6 +103,7 @@ PvContext * pv_context_new (const gchar *name, GVariant gboolean pv_context_set_subscribe (PvContext *context, PvSubscribe *subscribe); gboolean pv_context_connect (PvContext *context, PvContextFlags flags); +gboolean pv_context_disconnect (PvContext *context); gboolean pv_context_register_source (PvContext *context, PvSource *source); gboolean pv_context_unregister_source (PvContext *context, PvSource *source); diff --git a/src/client/pv-source-output.c b/src/client/pv-source-output.c index 64ef9f7c1..88c8729b4 100644 --- a/src/client/pv-source-output.c +++ b/src/client/pv-source-output.c @@ -174,11 +174,11 @@ static void output_register_object (PvSourceOutput *output, const gchar *prefix) { PvSourceOutputPrivate *priv = output->priv; - GDBusObjectSkeleton *skel; + PvObjectSkeleton *skel; gchar *name; name = g_strdup_printf ("%s/output", prefix); - skel = g_dbus_object_skeleton_new (name); + skel = pv_object_skeleton_new (name); g_free (name); { @@ -188,10 +188,10 @@ output_register_object (PvSourceOutput *output, const gchar *prefix) g_signal_connect (iface, "handle-start", (GCallback) handle_start, output); g_signal_connect (iface, "handle-stop", (GCallback) handle_stop, output); g_signal_connect (iface, "handle-remove", (GCallback) handle_remove, output); - g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); + pv_object_skeleton_set_source_output1 (skel, iface); g_object_unref (iface); } - g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel); + g_dbus_object_manager_server_export_uniquely (priv->server_manager, G_DBUS_OBJECT_SKELETON (skel)); g_free (priv->object_path); priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); diff --git a/src/client/pv-source.c b/src/client/pv-source.c index 7071372dc..5c7f68df4 100644 --- a/src/client/pv-source.c +++ b/src/client/pv-source.c @@ -118,18 +118,18 @@ static void source_register_object (PvSource *source) { PvSourcePrivate *priv = source->priv; - GDBusObjectSkeleton *skel; + PvObjectSkeleton *skel; - skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE); + skel = pv_object_skeleton_new (PV_DBUS_OBJECT_SOURCE); { PvSource1 *iface; iface = pv_source1_skeleton_new (); g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, source); - g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); + pv_object_skeleton_set_source1 (skel, iface); g_object_unref (iface); } - g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel); + g_dbus_object_manager_server_export_uniquely (priv->server_manager, G_DBUS_OBJECT_SKELETON (skel)); g_free (priv->object_path); priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); diff --git a/src/client/pv-subscribe.c b/src/client/pv-subscribe.c index c7ae06f6e..e4cf7aff1 100644 --- a/src/client/pv-subscribe.c +++ b/src/client/pv-subscribe.c @@ -70,6 +70,12 @@ notify_subscription (PvSubscribe *subscribe, g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, PV_SUBSCRIPTION_FLAGS_CLIENT, object); } + if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER) { + if ((interface == NULL && pv_object_peek_source_provider1 (PV_OBJECT (object))) || + PV_IS_SOURCE_PROVIDER1_PROXY (interface)) + g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, + PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER, object); + } if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) { if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) || PV_IS_SOURCE1_PROXY (interface)) @@ -172,11 +178,18 @@ on_client_manager_ready (GObject *source_object, PvSubscribe *subscribe = user_data; PvSubscribePrivate *priv = subscribe->priv; GError *error = NULL; + GList *objects, *walk; priv->client_manager = pv_object_manager_client_new_finish (res, &error); if (priv->client_manager == NULL) goto manager_error; + objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->client_manager)); + for (walk = objects; walk ; walk = g_list_next (walk)) { + on_client_manager_object_added (G_DBUS_OBJECT_MANAGER (priv->client_manager), + walk->data, + subscribe); + } connect_client_signals (subscribe); return; diff --git a/src/client/pv-subscribe.h b/src/client/pv-subscribe.h index c74025c0c..d1a5278ec 100644 --- a/src/client/pv-subscribe.h +++ b/src/client/pv-subscribe.h @@ -38,12 +38,13 @@ typedef struct _PvSubscribeClass PvSubscribeClass; typedef struct _PvSubscribePrivate PvSubscribePrivate; typedef enum { - PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0), - PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 1), - PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 2), + PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0), + PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER = (1 << 1), + PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2), + PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3), } PvSubscriptionFlags; -#define PV_SUBSCRIPTION_FLAGS_ALL 0x3 +#define PV_SUBSCRIPTION_FLAGS_ALL 0xf typedef enum { PV_SUBSCRIPTION_EVENT_NEW = 0, diff --git a/src/daemon/main.c b/src/daemon/main.c index 3b6e79b18..cb0fbbfed 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -22,18 +22,23 @@ #include #include +#include gint main (gint argc, gchar *argv[]) { PvDaemon *daemon; GMainLoop *loop; + PvSource *source; pv_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); daemon = pv_daemon_new (); + + source = pv_v4l2_source_new(); + pv_daemon_add_source (daemon, source); pv_daemon_start (daemon); g_main_loop_run (loop); diff --git a/src/dbus/org.pulsevideo.xml b/src/dbus/org.pulsevideo.xml index bd17635c5..2fd478f51 100644 --- a/src/dbus/org.pulsevideo.xml +++ b/src/dbus/org.pulsevideo.xml @@ -9,9 +9,6 @@ - - - @@ -29,6 +26,8 @@ + + diff --git a/src/server/pv-client.c b/src/server/pv-client.c index 437665ed5..28c582433 100644 --- a/src/server/pv-client.c +++ b/src/server/pv-client.c @@ -180,20 +180,20 @@ client_register_object (PvClient *client, const gchar *prefix) { PvClientPrivate *priv = client->priv; PvDaemon *daemon = priv->daemon; - GDBusObjectSkeleton *skel; + PvObjectSkeleton *skel; gchar *name; name = g_strdup_printf ("%s/client", prefix); - skel = g_dbus_object_skeleton_new (name); + skel = pv_object_skeleton_new (name); g_free (name); priv->client1 = pv_client1_skeleton_new (); pv_client1_set_name (priv->client1, "poppy"); g_signal_connect (priv->client1, "handle-create-source-output", (GCallback) handle_create_source_output, client); - g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (priv->client1)); + pv_object_skeleton_set_client1 (skel, priv->client1); g_free (priv->object_path); - priv->object_path = pv_daemon_export_uniquely (daemon, skel); + priv->object_path = pv_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel)); } static void diff --git a/src/server/pv-daemon.c b/src/server/pv-daemon.c index 946059d31..3afefaef6 100644 --- a/src/server/pv-daemon.c +++ b/src/server/pv-daemon.c @@ -35,6 +35,7 @@ struct _PvDaemonPrivate guint id; GDBusConnection *connection; GDBusObjectManagerServer *server_manager; + PvSubscribe *subscribe; GHashTable *senders; GList *sources; @@ -52,33 +53,32 @@ typedef struct { } SenderData; static void -on_subscription_event (PvSubscribe *subscribe, - PvSubscriptionEvent event, - PvSubscriptionFlags flags, - GDBusObjectProxy *object, - gpointer user_data) +on_server_subscription_event (PvSubscribe *subscribe, + PvSubscriptionEvent event, + PvSubscriptionFlags flags, + GDBusObjectProxy *object, + gpointer user_data) { - SenderData *data = user_data; - PvDaemon *daemon = data->daemon; + PvDaemon *daemon = user_data; PvDaemonPrivate *priv = daemon->priv; const gchar *object_path; PvSource1 *source1; - - object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); - - g_print ("got event %d %d %s.%s\n", event, flags, data->sender, object_path); + gchar *service; if (flags != PV_SUBSCRIPTION_FLAGS_SOURCE) return; + object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); + + g_object_get (subscribe, "service", &service, NULL); + g_print ("got event %d %d %s.%s\n", event, flags, service, object_path); + source1 = pv_object_peek_source1 (PV_OBJECT (object)); switch (event) { case PV_SUBSCRIPTION_EVENT_NEW: { - g_object_set_data (G_OBJECT (source1), "org.pulsevideo.name", data->sender); - - g_hash_table_insert (data->sources, g_strdup (object_path), source1); + g_object_set_data (G_OBJECT (source1), "org.pulsevideo.name", service); priv->sources = g_list_prepend (priv->sources, source1); break; } @@ -89,12 +89,49 @@ on_subscription_event (PvSubscribe *subscribe, case PV_SUBSCRIPTION_EVENT_REMOVE: { priv->sources = g_list_remove (priv->sources, source1); + break; + } + } +} + +static void +on_sender_subscription_event (PvSubscribe *subscribe, + PvSubscriptionEvent event, + PvSubscriptionFlags flags, + GDBusObjectProxy *object, + gpointer user_data) +{ + SenderData *data = user_data; + PvDaemon *daemon = data->daemon; + const gchar *object_path; + + on_server_subscription_event (subscribe, event, flags, object, daemon); + + object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); + + switch (event) { + case PV_SUBSCRIPTION_EVENT_NEW: + { + PvSourceProvider *provider; + + provider = pv_source_provider_new (daemon, PV_DBUS_OBJECT_PREFIX, data->sender, + object_path); + g_hash_table_insert (data->sources, g_strdup (object_path), provider); + break; + } + + case PV_SUBSCRIPTION_EVENT_CHANGE: + break; + + case PV_SUBSCRIPTION_EVENT_REMOVE: + { g_hash_table_remove (data->sources, object_path); break; } } } + static void client_name_appeared_handler (GDBusConnection *connection, const gchar *name, @@ -113,7 +150,7 @@ client_name_appeared_handler (GDBusConnection *connection, g_signal_connect (data->subscribe, "subscription-event", - (GCallback) on_subscription_event, + (GCallback) on_sender_subscription_event, data); } @@ -192,50 +229,25 @@ handle_connect_client (PvDaemon1 *interface, return TRUE; } -static gboolean -handle_disconnect_client (PvDaemon1 *interface, - GDBusMethodInvocation *invocation, - const gchar *arg_client, - gpointer user_data) -{ - PvDaemon *daemon = user_data; - PvDaemonPrivate *priv = daemon->priv; - const gchar *sender; - SenderData *data; - - sender = g_dbus_method_invocation_get_sender (invocation); - - g_print ("disconnect client %s\n", sender); - data = g_hash_table_lookup (priv->senders, sender); - if (data != NULL) { - g_hash_table_remove (data->clients, arg_client); - } - - pv_daemon1_complete_disconnect_client (interface, invocation); - - return TRUE; -} - static void export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager) { - GDBusObjectSkeleton *skel; + PvObjectSkeleton *skel; - skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SERVER); + skel = pv_object_skeleton_new (PV_DBUS_OBJECT_SERVER); { PvDaemon1 *iface; iface = pv_daemon1_skeleton_new (); g_signal_connect (iface, "handle-connect-client", (GCallback) handle_connect_client, daemon); - g_signal_connect (iface, "handle-disconnect-client", (GCallback) handle_disconnect_client, daemon); pv_daemon1_set_user_name (iface, g_get_user_name ()); pv_daemon1_set_host_name (iface, g_get_host_name ()); pv_daemon1_set_version (iface, PACKAGE_VERSION); pv_daemon1_set_name (iface, PACKAGE_NAME); - g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); + pv_object_skeleton_set_daemon1 (skel, iface); g_object_unref (iface); } - g_dbus_object_manager_server_export (manager, skel); + g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (skel)); g_object_unref (skel); } @@ -257,10 +269,16 @@ name_acquired_handler (GDBusConnection *connection, { PvDaemon *daemon = user_data; PvDaemonPrivate *priv = daemon->priv; - GDBusObjectManagerServer *manager; + GDBusObjectManagerServer *manager = priv->server_manager; + + g_object_set (priv->subscribe, "service", PV_DBUS_SERVICE, + "subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE, + "connection", connection, + NULL); + - priv->server_manager = manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX); export_server_object (daemon, manager); + g_dbus_object_manager_server_set_connection (manager, connection); } @@ -273,8 +291,10 @@ name_lost_handler (GDBusConnection *connection, PvDaemonPrivate *priv = daemon->priv; GDBusObjectManagerServer *manager = priv->server_manager; + g_object_set (priv->subscribe, "connection", connection, NULL); + g_dbus_object_manager_server_unexport (manager, PV_DBUS_OBJECT_SERVER); - g_clear_object (&priv->server_manager); + g_dbus_object_manager_server_set_connection (manager, connection); } PvDaemon * @@ -334,6 +354,27 @@ pv_daemon_unexport (PvDaemon *daemon, const gchar *object_path) g_dbus_object_manager_server_unexport (daemon->priv->server_manager, object_path); } +void +pv_daemon_add_source (PvDaemon *daemon, PvSource *source) +{ + PvDaemonPrivate *priv; + + g_return_if_fail (PV_IS_DAEMON (daemon)); + g_return_if_fail (PV_IS_SOURCE (source)); + priv = daemon->priv; + + pv_source_set_manager (source, priv->server_manager); +} + +void +pv_daemon_remove_source (PvDaemon *daemon, PvSource *source) +{ + g_return_if_fail (PV_IS_DAEMON (daemon)); + g_return_if_fail (PV_IS_SOURCE (source)); + + pv_source_set_manager (source, NULL); +} + PvSource1 * pv_daemon_get_source (PvDaemon *daemon, const gchar *name) { @@ -359,6 +400,7 @@ pv_daemon_finalize (GObject * object) PvDaemon *daemon = PV_DAEMON_CAST (object); PvDaemonPrivate *priv = daemon->priv; + g_clear_object (&priv->server_manager); g_hash_table_unref (priv->senders); pv_daemon_stop (daemon); @@ -381,5 +423,12 @@ pv_daemon_init (PvDaemon * daemon) PvDaemonPrivate *priv = daemon->priv = PV_DAEMON_GET_PRIVATE (daemon); priv->senders = g_hash_table_new (g_str_hash, g_str_equal); + priv->server_manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX); + + priv->subscribe = pv_subscribe_new (); + g_signal_connect (priv->subscribe, + "subscription-event", + (GCallback) on_server_subscription_event, + daemon); } diff --git a/src/server/pv-daemon.h b/src/server/pv-daemon.h index 4eddcb28b..bdb9c9471 100644 --- a/src/server/pv-daemon.h +++ b/src/server/pv-daemon.h @@ -74,6 +74,9 @@ void pv_daemon_stop (PvDaemon *daemon); gchar * pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel); void pv_daemon_unexport (PvDaemon *daemon, const gchar *name); +void pv_daemon_add_source (PvDaemon *daemon, PvSource *source); +void pv_daemon_remove_source (PvDaemon *daemon, PvSource *source); + PvSource1 * pv_daemon_get_source (PvDaemon *daemon, const gchar *name); G_END_DECLS diff --git a/src/server/pv-source-provider.c b/src/server/pv-source-provider.c index 0c3fbc0ae..2350c8e7a 100644 --- a/src/server/pv-source-provider.c +++ b/src/server/pv-source-provider.c @@ -113,11 +113,11 @@ source_provider_register_object (PvSourceProvider *client, const gchar *prefix) { PvSourceProviderPrivate *priv = client->priv; PvDaemon *daemon = priv->daemon; - GDBusObjectSkeleton *skel; + PvObjectSkeleton *skel; gchar *name; name = g_strdup_printf ("%s/source", prefix); - skel = g_dbus_object_skeleton_new (name); + skel = pv_object_skeleton_new (name); g_free (name); { @@ -126,12 +126,12 @@ source_provider_register_object (PvSourceProvider *client, const gchar *prefix) iface = pv_source_provider1_skeleton_new (); g_object_set (iface, "name", priv->name, NULL); g_object_set (iface, "path", priv->path, NULL); - g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); + pv_object_skeleton_set_source_provider1 (skel, iface); g_object_unref (iface); } g_free (priv->object_path); - priv->object_path = pv_daemon_export_uniquely (daemon, skel); + priv->object_path = pv_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel)); } static void