diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/client/pv-context.c | 106 | ||||
-rw-r--r-- | src/client/pv-context.h | 3 | ||||
-rw-r--r-- | src/client/pv-source.c | 86 | ||||
-rw-r--r-- | src/client/pv-source.h | 33 | ||||
-rw-r--r-- | src/client/pv-stream.c | 52 | ||||
-rw-r--r-- | src/client/pv-subscribe.c | 282 | ||||
-rw-r--r-- | src/client/pv-subscribe.h | 11 | ||||
-rw-r--r-- | src/daemon/main.c | 2 | ||||
-rw-r--r-- | src/dbus/org.pulsevideo.xml | 44 | ||||
-rw-r--r-- | src/modules/v4l2/pv-v4l2-source.c | 73 | ||||
-rw-r--r-- | src/server/pv-client.c | 105 | ||||
-rw-r--r-- | src/server/pv-client.h | 2 | ||||
-rw-r--r-- | src/server/pv-daemon.c | 161 | ||||
-rw-r--r-- | src/server/pv-daemon.h | 1 | ||||
-rw-r--r-- | src/server/pv-source-provider.c | 2 | ||||
-rw-r--r-- | src/tests/test-subscribe.c | 26 |
17 files changed, 603 insertions, 388 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e5770e7b..5d0788a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ dbuspolicy_DATA = \ ################################### enumtypesincludes = client/pv-context.h \ + client/pv-source.h \ client/pv-stream.h \ client/pv-subscribe.h @@ -193,7 +194,6 @@ lib_LTLIBRARIES += libpulsevideocore-@PV_MAJORMINOR@.la # Pure core stuff libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \ server/pv-client.c server/pv-client.h \ - server/pv-source-provider.c server/pv-source-provider.h \ server/pv-daemon.c server/pv-daemon.h \ modules/v4l2/pv-v4l2-source.c diff --git a/src/client/pv-context.c b/src/client/pv-context.c index eee417ab..90e319ef 100644 --- a/src/client/pv-context.c +++ b/src/client/pv-context.c @@ -40,8 +40,11 @@ struct _PvContextPrivate PvClient1 *client; + PvSubscribe *internal_subscribe; PvSubscribe *subscribe; + GList *sources; + GDBusObjectManagerServer *server_manager; }; @@ -51,6 +54,14 @@ struct _PvContextPrivate G_DEFINE_TYPE (PvContext, pv_context, G_TYPE_OBJECT); +static void subscription_state (GObject *object, GParamSpec *pspec, gpointer user_data); +static void +subscription_cb (PvSubscribe *subscribe, + PvSubscriptionEvent event, + PvSubscriptionFlags flags, + GDBusProxy *object, + gpointer user_data); + enum { PROP_0, @@ -223,6 +234,10 @@ pv_context_init (PvContext * context) priv->state = PV_CONTEXT_STATE_UNCONNECTED; priv->server_manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX); + priv->internal_subscribe = pv_subscribe_new (); + g_object_set (priv->internal_subscribe, "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, NULL); + g_signal_connect (priv->internal_subscribe, "subscription-event", (GCallback) subscription_cb, context); + g_signal_connect (priv->internal_subscribe, "notify::state", (GCallback) subscription_state, context); } /** @@ -302,15 +317,6 @@ on_daemon_connected (GObject *source_object, { PvContext *context = user_data; PvContextPrivate *priv = context->priv; - GError *error = NULL; - - priv->daemon = pv_daemon1_proxy_new_finish (res, &error); - if (priv->daemon == NULL) { - context_set_state (context, PV_CONTEXT_STATE_ERROR); - g_error ("failed to get daemon: %s", error->message); - g_clear_error (&error); - return; - } context_set_state (context, PV_CONTEXT_STATE_REGISTERING); @@ -329,6 +335,57 @@ on_daemon_connected (GObject *source_object, } } +static void +subscription_cb (PvSubscribe *subscribe, + PvSubscriptionEvent event, + PvSubscriptionFlags flags, + GDBusProxy *object, + gpointer user_data) +{ + PvContext *context = user_data; + PvContextPrivate *priv = context->priv; + + g_print ("got event %d %d\n", event, flags); + + switch (flags) { + case PV_SUBSCRIPTION_FLAGS_DAEMON: + priv->daemon = PV_DAEMON1 (object); + break; + + case PV_SUBSCRIPTION_FLAGS_CLIENT: + break; + + case PV_SUBSCRIPTION_FLAGS_SOURCE: + priv->sources = g_list_prepend (priv->sources, object); + break; + + case PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT: + break; + } +} + +static void +subscription_state (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + PvContext *context = user_data; + PvSubscriptionState state; + + g_object_get (object, "state", &state, NULL); + + g_print ("got subscription state %d\n", state); + + switch (state) { + case PV_SUBSCRIPTION_STATE_READY: + on_daemon_connected (NULL, NULL, context); + break; + + default: + break; + } + +} static void on_name_appeared (GDBusConnection *connection, @@ -343,17 +400,11 @@ on_name_appeared (GDBusConnection *connection, g_dbus_object_manager_server_set_connection (priv->server_manager, connection); if (priv->subscribe) { - g_object_set (priv->subscribe, "connection", priv->connection, NULL); - g_object_set (priv->subscribe, "service", name, NULL); + g_object_set (priv->subscribe, "connection", priv->connection, + "service", name, NULL); } - - pv_daemon1_proxy_new (priv->connection, - G_DBUS_PROXY_FLAGS_NONE, - name, - PV_DBUS_OBJECT_SERVER, - NULL, - on_daemon_connected, - user_data); + g_object_set (priv->internal_subscribe, "connection", priv->connection, + "service", name, NULL); } static void @@ -370,6 +421,8 @@ on_name_vanished (GDBusConnection *connection, if (priv->subscribe) g_object_set (priv->subscribe, "connection", connection, NULL); + g_object_set (priv->internal_subscribe, "connection", connection, NULL); + if (priv->flags & PV_CONTEXT_FLAGS_NOFAIL) { context_set_state (context, PV_CONTEXT_STATE_CONNECTING); } else { @@ -586,3 +639,18 @@ pv_context_get_client_proxy (PvContext *context) return G_DBUS_PROXY (context->priv->client); } + +GDBusProxy * +pv_context_find_source (PvContext *context, const gchar *name, GVariant *props) +{ + PvContextPrivate *priv; + + g_return_val_if_fail (PV_IS_CONTEXT (context), NULL); + priv = context->priv; + + if (priv->sources == NULL) + return NULL; + + return priv->sources->data; +} + diff --git a/src/client/pv-context.h b/src/client/pv-context.h index e208cc7c..03f9046f 100644 --- a/src/client/pv-context.h +++ b/src/client/pv-context.h @@ -109,9 +109,12 @@ gboolean pv_context_register_source (PvContext *context, PvSource gboolean pv_context_unregister_source (PvContext *context, PvSource *source); PvContextState pv_context_get_state (PvContext *context); + GDBusConnection * pv_context_get_connection (PvContext *context); GDBusProxy * pv_context_get_client_proxy (PvContext *context); +GDBusProxy * pv_context_find_source (PvContext *context, const gchar *name, GVariant *props); + G_END_DECLS diff --git a/src/client/pv-source.c b/src/client/pv-source.c index 90de27fc..26c1971b 100644 --- a/src/client/pv-source.c +++ b/src/client/pv-source.c @@ -21,6 +21,7 @@ #include "client/pulsevideo.h" #include "client/pv-source.h" +#include "client/pv-enumtypes.h" #include "dbus/org-pulsevideo.h" @@ -31,10 +32,11 @@ struct _PvSourcePrivate { GDBusObjectManagerServer *server_manager; + PvSource1 *iface; gchar *object_path; gchar *name; - gboolean suspended; + PvSourceState state; GVariant *properties; }; @@ -46,7 +48,7 @@ enum PROP_MANAGER, PROP_OBJECT_PATH, PROP_NAME, - PROP_SUSPENDED, + PROP_STATE, PROP_PROPERTIES }; @@ -72,8 +74,8 @@ pv_source_get_property (GObject *_object, g_value_set_string (value, priv->name); break; - case PROP_SUSPENDED: - g_value_set_boolean (value, priv->suspended); + case PROP_STATE: + g_value_set_enum (value, priv->state); break; case PROP_PROPERTIES: @@ -168,20 +170,22 @@ source_register_object (PvSource *source) PvObjectSkeleton *skel; skel = pv_object_skeleton_new (PV_DBUS_OBJECT_SOURCE); - { - PvSource1 *iface; - - iface = pv_source1_skeleton_new (); - g_object_set (iface, "name", priv->name, - "suspended", priv->suspended, - "properties", priv->properties, - NULL); - g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, source); - g_signal_connect (iface, "handle-get-capabilities", (GCallback) handle_get_capabilities, source); - pv_object_skeleton_set_source1 (skel, iface); - g_object_unref (iface); - } + + priv->iface = pv_source1_skeleton_new (); + g_object_set (priv->iface, "name", priv->name, + "state", priv->state, + "properties", priv->properties, + NULL); + g_signal_connect (priv->iface, "handle-create-source-output", + (GCallback) handle_create_source_output, + source); + g_signal_connect (priv->iface, "handle-get-capabilities", + (GCallback) handle_get_capabilities, + source); + pv_object_skeleton_set_source1 (skel, priv->iface); + g_dbus_object_manager_server_export_uniquely (priv->server_manager, G_DBUS_OBJECT_SKELETON (skel)); + g_object_unref (skel); g_free (priv->object_path); priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); @@ -195,6 +199,7 @@ source_unregister_object (PvSource *source) PvSourcePrivate *priv = source->priv; g_dbus_object_manager_server_unexport (priv->server_manager, priv->object_path); + g_clear_object (&priv->iface); } static void @@ -272,13 +277,14 @@ pv_source_class_init (PvSourceClass * klass) G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, - PROP_SUSPENDED, - g_param_spec_boolean ("suspended", - "Suspended", - "The suspended state of the source", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + PROP_STATE, + g_param_spec_enum ("state", + "State", + "The state of the source", + PV_TYPE_SOURCE_STATE, + PV_SOURCE_STATE_INIT, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PROPERTIES, @@ -339,7 +345,7 @@ pv_source_get_capabilities (PvSource *source, GVariant *props) } gboolean -pv_source_suspend (PvSource *source) +pv_source_set_state (PvSource *source, PvSourceState state) { PvSourceClass *klass; gboolean res; @@ -348,33 +354,31 @@ pv_source_suspend (PvSource *source) klass = PV_SOURCE_GET_CLASS (source); - if (klass->suspend) - res = klass->suspend (source); + if (klass->set_state) + res = klass->set_state (source, state); else res = FALSE; return res; } -gboolean -pv_source_resume (PvSource *source) +void +pv_source_update_state (PvSource *source, PvSourceState state) { - PvSourceClass *klass; - gboolean res; - - g_return_val_if_fail (PV_IS_SOURCE (source), FALSE); - - klass = PV_SOURCE_GET_CLASS (source); + PvSourcePrivate *priv; - if (klass->resume) - res = klass->resume (source); - else - res = FALSE; + g_return_if_fail (PV_IS_SOURCE (source)); + priv = source->priv; - return res; + if (priv->state != state) { + priv->state = state; + g_print ("source changed state %d\n", state); + if (priv->iface) + pv_source1_set_state (priv->iface, state); + g_object_notify (G_OBJECT (source), "state"); + } } - PvSourceOutput * pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix) { diff --git a/src/client/pv-source.h b/src/client/pv-source.h index 2ad46c58..e5b574cb 100644 --- a/src/client/pv-source.h +++ b/src/client/pv-source.h @@ -41,6 +41,26 @@ typedef struct _PvSourcePrivate PvSourcePrivate; #define PV_SOURCE_CLASS_CAST(klass) ((PvSourceClass*)(klass)) /** + * PvSourceState: + * @PV_SOURCE_STATE_ERROR: the source is in error + * @PV_SOURCE_STATE_SUSPENDED: the source is suspended, the device might + * be closed + * @PV_SOURCE_STATE_INIT: the source is initializing, it opens the device + * and gets the device capabilities + * @PV_SOURCE_STATE_IDLE: the source is running but there is no active + * source-output + * @PV_SOURCE_STATE_RUNNING: the source is running. + * + * The different source states + */ +typedef enum { + PV_SOURCE_STATE_ERROR = 0, + PV_SOURCE_STATE_SUSPENDED = 1, + PV_SOURCE_STATE_INIT = 2, + PV_SOURCE_STATE_IDLE = 3, + PV_SOURCE_STATE_RUNNING = 4, +} PvSourceState; +/** * PvSource: * * Pulsevideo source object class. @@ -53,16 +73,19 @@ struct _PvSource { /** * PvSourceClass: + * @get_capabilities: called to get a list of supported formats from the source + * @set_state: called to change the current state of the source + * @create_source_output: called to create a new source-output object + * @release_source_output: called to release a source-output object * * Pulsevideo source object class. */ struct _PvSourceClass { GObjectClass parent_class; - GVariant * (*get_capabilities) (PvSource *source, GVariant *props); + GVariant * (*get_capabilities) (PvSource *source, GVariant *props); - gboolean (*suspend) (PvSource *source); - gboolean (*resume) (PvSource *source); + gboolean (*set_state) (PvSource *source, PvSourceState); PvSourceOutput * (*create_source_output) (PvSource *source, GVariant *props, const gchar *prefix); gboolean (*release_source_output) (PvSource *source, PvSourceOutput *output); @@ -75,8 +98,8 @@ void pv_source_set_manager (PvSource *source, GDBusObject GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props); -gboolean pv_source_suspend (PvSource *source); -gboolean pv_source_resume (PvSource *source); +gboolean pv_source_set_state (PvSource *source, PvSourceState state); +void pv_source_update_state (PvSource *source, PvSourceState state); PvSourceOutput * pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix); gboolean pv_source_release_source_output (PvSource *source, PvSourceOutput *output); diff --git a/src/client/pv-stream.c b/src/client/pv-stream.c index 84890f9c..f28dbafe 100644 --- a/src/client/pv-stream.c +++ b/src/client/pv-stream.c @@ -33,8 +33,8 @@ struct _PvStreamPrivate gchar *target; PvStreamState state; - gchar *source_output_sender; gchar *source_output_path; + PvSource1 *source; PvSourceOutput1 *source_output; GSocket *socket; @@ -319,19 +319,16 @@ on_source_output_created (GObject *source_object, PvStreamPrivate *priv = stream->priv; PvContext *context = priv->context; GError *error = NULL; - PvClient1 *proxy; - proxy = PV_CLIENT1 (pv_context_get_client_proxy (priv->context)); - - if (!pv_client1_call_create_source_output_finish (proxy, - &priv->source_output_sender, &priv->source_output_path, res, &error)) + if (!pv_source1_call_create_source_output_finish (priv->source, + &priv->source_output_path, res, &error)) goto create_failed; - g_print ("got source-output %s %s\n", priv->source_output_sender, priv->source_output_path); + g_print ("got source-output %s\n", priv->source_output_path); pv_source_output1_proxy_new (pv_context_get_connection (context), G_DBUS_PROXY_FLAGS_NONE, - priv->source_output_sender, + g_dbus_proxy_get_name (G_DBUS_PROXY (priv->source)), priv->source_output_path, NULL, on_source_output1_proxy, @@ -348,27 +345,6 @@ create_failed: } } -static gboolean -create_source_output (PvStream *stream) -{ - PvStreamPrivate *priv = stream->priv; - GVariantBuilder builder; - PvClient1 *proxy; - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); - - proxy = PV_CLIENT1 (pv_context_get_client_proxy (priv->context)); - - pv_client1_call_create_source_output (proxy, - priv->target ? priv->target : "/", /* const gchar *arg_source */ - g_variant_builder_end (&builder), /* GVariant *arg_props */ - NULL, /* GCancellable *cancellable */ - on_source_output_created, - stream); - return TRUE; -} - static void on_source_output_removed (GObject *source_object, GAsyncResult *res, @@ -385,7 +361,6 @@ on_source_output_removed (GObject *source_object, g_clear_error (&error); return; } - g_clear_pointer (&priv->source_output_sender, g_free); g_clear_pointer (&priv->source_output_path, g_free); g_clear_object (&priv->source_output); } @@ -418,6 +393,7 @@ pv_stream_connect_capture (PvStream *stream, PvStreamFlags flags) { PvStreamPrivate *priv; + GVariantBuilder builder; PvContext *context; g_return_val_if_fail (PV_IS_STREAM (stream), FALSE); @@ -429,7 +405,21 @@ pv_stream_connect_capture (PvStream *stream, stream_set_state (stream, PV_STREAM_STATE_CONNECTING); - return create_source_output (stream); + priv->source = PV_SOURCE1 (pv_context_find_source (context, priv->target, NULL)); + if (priv->source == NULL) { + g_warning ("can't find source"); + return FALSE; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); + + pv_source1_call_create_source_output (priv->source, + g_variant_builder_end (&builder), /* GVariant *arg_props */ + NULL, /* GCancellable *cancellable */ + on_source_output_created, + stream); + return TRUE; } /** diff --git a/src/client/pv-subscribe.c b/src/client/pv-subscribe.c index e4cf7aff..03eac08d 100644 --- a/src/client/pv-subscribe.c +++ b/src/client/pv-subscribe.c @@ -26,12 +26,16 @@ struct _PvSubscribePrivate { + PvSubscriptionState state; GDBusConnection *connection; gchar *service; PvSubscriptionFlags subscription_mask; GDBusObjectManager *client_manager; + guint pending_subscribes; + + GHashTable *senders; }; @@ -45,7 +49,8 @@ enum PROP_0, PROP_CONNECTION, PROP_SERVICE, - PROP_SUBSCRIPTION_MASK + PROP_SUBSCRIPTION_MASK, + PROP_STATE, }; enum @@ -56,6 +61,161 @@ enum static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + PvSubscribe *subscribe; + gchar *sender; + guint id; + PvSubscribe *sender_subscribe; + GList *clients; +} SenderData; + +static void +notify_subscription (PvSubscribe *subscribe, + GDBusObject *object, + GDBusInterface *interface, + PvSubscriptionEvent event); + +static void +on_sender_subscription_event (PvSubscribe *sender_subscribe, + PvSubscriptionEvent event, + PvSubscriptionFlags flags, + GDBusProxy *object, + gpointer user_data) +{ + SenderData *data = user_data; + PvSubscribe *subscribe = data->subscribe; + + g_signal_emit (subscribe, + signals[SIGNAL_SUBSCRIPTION_EVENT], + 0, + event, + flags, + object); +} + +static void +subscription_set_state (PvSubscribe *subscribe, PvSubscriptionState state) +{ + PvSubscribePrivate *priv = subscribe->priv; + + if (state != priv->state) { + priv->state = state; + g_object_notify (G_OBJECT (subscribe), "state"); + } +} + +static void +on_sender_subscription_state (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + SenderData *data = user_data; + PvSubscribe *subscribe = data->subscribe; + PvSubscribePrivate *priv = subscribe->priv; + PvSubscriptionState state; + + g_object_get (object, "state", &state, NULL); + + switch (state) { + case PV_SUBSCRIPTION_STATE_READY: + if (--priv->pending_subscribes == 0) + subscription_set_state (subscribe, state); + break; + + case PV_SUBSCRIPTION_STATE_ERROR: + subscription_set_state (subscribe, state); + break; + + default: + break; + } +} + +static void +client_name_appeared_handler (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + SenderData *data = user_data; + + /* subscribe to Source events. We want to be notified when this new + * sender add/change/remove sources and outputs */ + data->sender_subscribe = pv_subscribe_new (); + g_object_set (data->sender_subscribe, "service", data->sender, + "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, + "connection", connection, + NULL); + + g_signal_connect (data->sender_subscribe, + "subscription-event", + (GCallback) on_sender_subscription_event, + data); + g_signal_connect (data->sender_subscribe, + "notify::state", + (GCallback) on_sender_subscription_state, + data); +} + +static void +remove_client (PvClient1 *client, SenderData *data) +{ + g_signal_emit (data->subscribe, + signals[SIGNAL_SUBSCRIPTION_EVENT], + 0, + PV_SUBSCRIPTION_EVENT_REMOVE, + PV_SUBSCRIPTION_FLAGS_CLIENT, + client); +} + +static void +client_name_vanished_handler (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + SenderData *data = user_data; + PvSubscribePrivate *priv = data->subscribe->priv; + + g_print ("vanished client %s\n", name); + + g_list_foreach (data->clients, (GFunc) remove_client, data); + + g_hash_table_remove (priv->senders, data->sender); + + if (data->sender_subscribe) + g_object_unref (data->sender_subscribe); + g_free (data->sender); + g_bus_unwatch_name (data->id); + g_free (data); +} + +static SenderData * +sender_data_new (PvSubscribe *subscribe, const gchar *sender) +{ + PvSubscribePrivate *priv = subscribe->priv; + SenderData *data; + + g_print ("watch name %s\n", sender); + + data = g_new0 (SenderData, 1); + data->subscribe = subscribe; + data->sender = g_strdup (sender); + + data->id = g_bus_watch_name_on_connection (priv->connection, + sender, + G_BUS_NAME_WATCHER_FLAGS_NONE, + client_name_appeared_handler, + client_name_vanished_handler, + data, + NULL); + + g_hash_table_insert (priv->senders, data->sender, data); + priv->pending_subscribes++; + + return data; +} + static void notify_subscription (PvSubscribe *subscribe, GDBusObject *object, @@ -64,29 +224,81 @@ notify_subscription (PvSubscribe *subscribe, { PvSubscribePrivate *priv = subscribe->priv; - if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_CLIENT) { - if ((interface == NULL && pv_object_peek_client1 (PV_OBJECT (object))) || - PV_IS_CLIENT1_PROXY (interface)) + if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_DAEMON) { + PvDaemon1 *daemon; + + if (interface == NULL) + daemon = pv_object_peek_daemon1 (PV_OBJECT (object)); + else if (PV_IS_DAEMON1_PROXY (interface)) + daemon = PV_DAEMON1 (interface); + else + daemon = NULL; + + if (daemon) { g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, - PV_SUBSCRIPTION_FLAGS_CLIENT, object); + PV_SUBSCRIPTION_FLAGS_DAEMON, daemon); + } } - 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_CLIENT) { + PvClient1 *client; + + if (interface == NULL) + client = pv_object_peek_client1 (PV_OBJECT (object)); + else if (PV_IS_CLIENT1_PROXY (interface)) + client = PV_CLIENT1 (interface); + else + client = NULL; + + if (client) { + const gchar *sender; + SenderData *data; + + sender = pv_client1_get_name (client); + + data = g_hash_table_lookup (priv->senders, sender); + if (data == NULL && event != PV_SUBSCRIPTION_EVENT_REMOVE) { + data = sender_data_new (subscribe, sender); + } + if (data) { + if (event == PV_SUBSCRIPTION_EVENT_NEW) + data->clients = g_list_prepend (data->clients, client); + else if (event == PV_SUBSCRIPTION_EVENT_REMOVE) + data->clients = g_list_remove (data->clients, client); + + g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, + PV_SUBSCRIPTION_FLAGS_CLIENT, client); + } + } } if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) { - if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) || - PV_IS_SOURCE1_PROXY (interface)) + PvSource1 *source; + + if (interface == NULL) + source = pv_object_peek_source1 (PV_OBJECT (object)); + else if (PV_IS_SOURCE1_PROXY (interface)) + source = PV_SOURCE1 (interface); + else + source = NULL; + + if (source) { g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, - PV_SUBSCRIPTION_FLAGS_SOURCE, object); + PV_SUBSCRIPTION_FLAGS_SOURCE, source); + } } if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT) { - if ((interface == NULL && pv_object_peek_source_output1 (PV_OBJECT (object))) || - PV_IS_SOURCE_OUTPUT1_PROXY (interface)) + PvSourceOutput1 *output; + + if (interface == NULL) + output = pv_object_peek_source_output1 (PV_OBJECT (object)); + else if PV_IS_SOURCE_OUTPUT1_PROXY (interface) + output = PV_SOURCE_OUTPUT1 (interface); + else + output = NULL; + + if (output) { g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, - PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT, object); + PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT, output); + } } } @@ -184,13 +396,20 @@ on_client_manager_ready (GObject *source_object, if (priv->client_manager == NULL) goto manager_error; + g_print ("client manager %s %s\n", + g_dbus_object_manager_client_get_name (G_DBUS_OBJECT_MANAGER_CLIENT (priv->client_manager)), + g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->client_manager))); + + connect_client_signals (subscribe); + 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); + if (--priv->pending_subscribes == 0) + subscription_set_state (subscribe, PV_SUBSCRIPTION_STATE_READY); return; @@ -199,6 +418,7 @@ manager_error: { g_warning ("could not create client manager: %s", error->message); g_clear_error (&error); + subscription_set_state (subscribe, PV_SUBSCRIPTION_STATE_ERROR); return; } } @@ -208,6 +428,9 @@ install_subscription (PvSubscribe *subscribe) { PvSubscribePrivate *priv = subscribe->priv; + subscription_set_state (subscribe, PV_SUBSCRIPTION_STATE_CONNECTING); + + g_print ("new client manager for %s\n", priv->service); pv_object_manager_client_new (priv->connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, priv->service, @@ -215,6 +438,7 @@ install_subscription (PvSubscribe *subscribe) NULL, on_client_manager_ready, subscribe); + priv->pending_subscribes++; } static void @@ -223,6 +447,7 @@ uninstall_subscription (PvSubscribe *subscribe) PvSubscribePrivate *priv = subscribe->priv; g_clear_object (&priv->client_manager); + subscription_set_state (subscribe, PV_SUBSCRIPTION_STATE_UNCONNECTED); } static void @@ -247,6 +472,10 @@ pv_subscribe_get_property (GObject *_object, g_value_set_flags (value, priv->subscription_mask); break; + case PROP_STATE: + g_value_set_enum (value, priv->state); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec); break; @@ -296,6 +525,7 @@ pv_subscribe_finalize (GObject * object) g_free (priv->service); g_object_unref (priv->client_manager); + g_hash_table_unref (priv->senders); G_OBJECT_CLASS (pv_subscribe_parent_class)->finalize (object); } @@ -353,6 +583,20 @@ pv_subscribe_class_init (PvSubscribeClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** + * PvSubscribe:state + * + * The state of the subscription + */ + g_object_class_install_property (gobject_class, + PROP_STATE, + g_param_spec_enum ("state", + "State", + "The state", + PV_TYPE_SUBSCRIPTION_STATE, + PV_SUBSCRIPTION_STATE_UNCONNECTED, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** * PvSubscribe:subscription-event * @subscribe: The #PvSubscribe emitting the signal. * @event: A #PvSubscriptionEvent @@ -372,7 +616,7 @@ pv_subscribe_class_init (PvSubscribeClass * klass) 3, PV_TYPE_SUBSCRIPTION_EVENT, PV_TYPE_SUBSCRIPTION_FLAGS, - G_TYPE_DBUS_OBJECT_PROXY); + G_TYPE_DBUS_PROXY); } static void @@ -381,6 +625,8 @@ pv_subscribe_init (PvSubscribe * subscribe) PvSubscribePrivate *priv = subscribe->priv = PV_SUBSCRIBE_GET_PRIVATE (subscribe); priv->service = g_strdup (PV_DBUS_SERVICE); + priv->senders = g_hash_table_new (g_str_hash, g_str_equal); + priv->state = PV_SUBSCRIPTION_STATE_UNCONNECTED; } /** diff --git a/src/client/pv-subscribe.h b/src/client/pv-subscribe.h index d1a5278e..8b6038b9 100644 --- a/src/client/pv-subscribe.h +++ b/src/client/pv-subscribe.h @@ -38,8 +38,15 @@ typedef struct _PvSubscribeClass PvSubscribeClass; typedef struct _PvSubscribePrivate PvSubscribePrivate; typedef enum { - PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0), - PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER = (1 << 1), + PV_SUBSCRIPTION_STATE_UNCONNECTED = 0, + PV_SUBSCRIPTION_STATE_CONNECTING = 1, + PV_SUBSCRIPTION_STATE_READY = 2, + PV_SUBSCRIPTION_STATE_ERROR = 3, +} PvSubscriptionState; + +typedef enum { + PV_SUBSCRIPTION_FLAGS_DAEMON = (1 << 0), + PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 1), PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2), PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3), } PvSubscriptionFlags; diff --git a/src/daemon/main.c b/src/daemon/main.c index cb0fbbfe..3fc4749f 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -38,7 +38,7 @@ main (gint argc, gchar *argv[]) daemon = pv_daemon_new (); source = pv_v4l2_source_new(); - pv_daemon_add_source (daemon, source); + //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 4e6de9fe..86b85996 100644 --- a/src/dbus/org.pulsevideo.xml +++ b/src/dbus/org.pulsevideo.xml @@ -46,25 +46,6 @@ <property name='Name' type='s' access='read' /> <!-- Name: Properties of the client --> <property name='Properties' type='a{sv}' access='read' /> - <!-- CreateSourceOutput: - @source: the name of a source or an empty string - @props: properties to use - @sender: the result sender of the output - @output: the result output object - - This method requests an output from @source with given @props. - @source can be the empty string, in which case the server will - select a good source. - - @sender and @output contain the unique name and object of the - owner of the source. - --> - <method name='CreateSourceOutput'> - <arg type='s' name='source' direction='in'/> - <arg type='a{sv}' name='props' direction='in'/> - <arg type='s' name='sender' direction='out'/> - <arg type='o' name='output' direction='out'/> - </method> <!-- Disconnect: Disconnect the client from the server. @@ -99,20 +80,6 @@ </interface> <!-- - org.pulsevideo.SourceProvider1: - @short_description: Interface for source provider - - This interface lists the unique name and path of a - source - --> - <interface name='org.pulsevideo.SourceProvider1'> - <!-- Name: unique name of the provider --> - <property name='Name' type='s' access='read' /> - <!-- Path: object path of the source --> - <property name='Path' type='o' access='read' /> - </interface> - - <!-- org.pulsevideo.Source1: @short_description: Main source interface @@ -123,8 +90,15 @@ <property name='Name' type='s' access='read' /> <!-- Properties: extra source properties --> <property name='Properties' type='a{sv}' access='read' /> - <!-- Suspended: if the source is suspended --> - <property name='Suspended' type='b' access='read' /> + <!-- state: state of the source + 0 = the source is in error + 1 = the source is initializing + 2 = the source is suspended, this means the device is closed + 3 = the source is idle, this means the device is opened but + no source-output is consuming the data + 4 = the source is running + --> + <property name='State' type='u' access='read' /> <!-- GetCapabilities: @props: input properties @caps: result capabilities diff --git a/src/modules/v4l2/pv-v4l2-source.c b/src/modules/v4l2/pv-v4l2-source.c index 5f51e829..3c18224e 100644 --- a/src/modules/v4l2/pv-v4l2-source.c +++ b/src/modules/v4l2/pv-v4l2-source.c @@ -28,6 +28,7 @@ struct _PvV4l2SourcePrivate { GstElement *pipeline; + GstElement *src; GstElement *sink; GSocket *socket; @@ -40,13 +41,70 @@ setup_pipeline (PvV4l2Source *source) { PvV4l2SourcePrivate *priv = source->priv; - priv->pipeline = gst_parse_launch ("v4l2src ! video/x-raw,width=640,height=480,framerate=30/1 ! " - "pvfdpay ! multisocketsink buffers-max=2 buffers-soft-max=1 " - "recover-policy=latest sync-method=latest name=sink sync=true " - "enable-last-sample=false", NULL); + priv->pipeline = gst_parse_launch ("v4l2src name=src ! " + "video/x-raw,width=640,height=480,framerate=30/1 ! " + "pvfdpay ! " + "multisocketsink " + "buffers-max=2 " + "buffers-soft-max=1 " + "recover-policy=latest " + "sync-method=latest " + "name=sink " + "sync=true " + "enable-last-sample=false", + NULL); priv->sink = gst_bin_get_by_name (GST_BIN (priv->pipeline), "sink"); + priv->src = gst_bin_get_by_name (GST_BIN (priv->pipeline), "src"); +} - gst_element_set_state (priv->pipeline, GST_STATE_READY); +static void +collect_capabilities (PvSource * source) +{ + PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv; + GstCaps *res; + GstQuery *query; + + query = gst_query_new_caps (NULL); + gst_element_query (priv->src, query); + gst_query_parse_caps_result (query, &res); + g_print ("%s\n", gst_caps_to_string (res)); + gst_query_unref (query); +} + +static gboolean +v4l2_set_state (PvSource *source, PvSourceState state) +{ + PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv; + + switch (state) { + case PV_SOURCE_STATE_SUSPENDED: + gst_element_set_state (priv->pipeline, GST_STATE_NULL); + break; + + case PV_SOURCE_STATE_INIT: + gst_element_set_state (priv->pipeline, GST_STATE_READY); + collect_capabilities (source); + break; + + case PV_SOURCE_STATE_IDLE: + gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + break; + + case PV_SOURCE_STATE_RUNNING: + gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + break; + + case PV_SOURCE_STATE_ERROR: + break; + } + pv_source_update_state (source, state); + return TRUE; +} + +static GVariant * +v4l2_get_capabilities (PvSource *source, GVariant *props) +{ + return NULL; } static void @@ -80,10 +138,13 @@ on_socket_notify (GObject *gobject, static PvSourceOutput * v4l2_create_source_output (PvSource *source, GVariant *props, const gchar *prefix) { + PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv; PvSourceOutput *output; output = PV_SOURCE_CLASS (pv_v4l2_source_parent_class)->create_source_output (source, props, prefix); + gst_element_set_state (priv->pipeline, GST_STATE_READY); + g_signal_connect (output, "notify::socket", (GCallback) on_socket_notify, source); return output; @@ -111,6 +172,8 @@ pv_v4l2_source_class_init (PvV4l2SourceClass * klass) gobject_class->finalize = v4l2_source_finalize; + source_class->get_capabilities = v4l2_get_capabilities; + source_class->set_state = v4l2_set_state; source_class->create_source_output = v4l2_create_source_output; source_class->release_source_output = v4l2_release_source_output; } diff --git a/src/server/pv-client.c b/src/server/pv-client.c index 38ec8227..a67cad94 100644 --- a/src/server/pv-client.c +++ b/src/server/pv-client.c @@ -30,6 +30,7 @@ struct _PvClientPrivate { PvDaemon *daemon; + gchar *sender; gchar *object_path; PvClient1 *client1; @@ -46,6 +47,7 @@ enum { PROP_0, PROP_DAEMON, + PROP_SENDER, PROP_OBJECT_PATH, }; @@ -63,6 +65,10 @@ pv_client_get_property (GObject *_object, g_value_set_object (value, priv->daemon); break; + case PROP_SENDER: + g_value_set_string (value, priv->sender); + break; + case PROP_OBJECT_PATH: g_value_set_string (value, priv->object_path); break; @@ -87,6 +93,10 @@ pv_client_set_property (GObject *_object, priv->daemon = g_value_dup_object (value); break; + case PROP_SENDER: + priv->sender = g_value_dup_string (value); + break; + case PROP_OBJECT_PATH: priv->object_path = g_value_dup_string (value); break; @@ -97,84 +107,6 @@ pv_client_set_property (GObject *_object, } } -typedef struct { - PvClient *client; - GDBusMethodInvocation *invocation; -} CreateData; - -static void -on_source_output_created (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - CreateData *data = user_data; - PvClient *client = data->client; - PvClientPrivate *priv = client->priv; - PvSource1 *source1 = PV_SOURCE1 (source_object); - GDBusMethodInvocation *invocation = data->invocation; - GError *error = NULL; - gchar *object_path, *name; - - if (!pv_source1_call_create_source_output_finish (source1, &object_path, res, &error)) - goto create_failed; - - name = g_object_get_data (G_OBJECT (source1), "org.pulsevideo.name"); - pv_client1_complete_create_source_output (priv->client1, invocation, name, object_path); - g_free (name); - - g_free (data); - - return; - - /* ERRORS */ -create_failed: - { - g_print ("failed to get connect capture: %s", error->message); - g_clear_error (&error); - g_free (data); - return; - } -} - - -static gboolean -handle_create_source_output (PvClient1 *interface, - GDBusMethodInvocation *invocation, - const gchar *arg_source, - GVariant *arg_properties, - gpointer user_data) -{ - PvClient *client = user_data; - PvClientPrivate *priv = client->priv; - PvDaemon *daemon = priv->daemon; - PvSource1 *source1; - GVariantBuilder builder; - CreateData *data; - - source1 = pv_daemon_get_source (daemon, arg_source); - if (source1 == NULL) { - g_dbus_method_invocation_return_dbus_error (invocation, - "org.pulsevideo.NotFound", - "No source found"); - return TRUE; - } - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); - - data = g_new0 (CreateData, 1); - data->client = client; - data->invocation = invocation; - - pv_source1_call_create_source_output (source1, - g_variant_builder_end (&builder), - NULL, - on_source_output_created, - data); - - return TRUE; -} - static void client_register_object (PvClient *client, const gchar *prefix) { @@ -188,8 +120,7 @@ client_register_object (PvClient *client, const gchar *prefix) 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); + pv_client1_set_name (priv->client1, priv->sender); pv_object_skeleton_set_client1 (skel, priv->client1); g_free (priv->object_path); @@ -253,6 +184,16 @@ pv_client_class_init (PvClientClass * klass) G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, + PROP_SENDER, + g_param_spec_string ("sender", + "Sender", + "The sender", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_OBJECT_PATH, g_param_spec_string ("object-path", "Object Path", @@ -282,12 +223,12 @@ pv_client_init (PvClient * client) * Returns: a new #PvClient */ PvClient * -pv_client_new (PvDaemon * daemon, const gchar *prefix) +pv_client_new (PvDaemon * daemon, const gchar *sender, const gchar *prefix) { g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL); g_return_val_if_fail (g_variant_is_object_path (prefix), NULL); - return g_object_new (PV_TYPE_CLIENT, "daemon", daemon, "object-path", prefix, NULL); + return g_object_new (PV_TYPE_CLIENT, "daemon", daemon, "sender", sender, "object-path", prefix, NULL); } /** diff --git a/src/server/pv-client.h b/src/server/pv-client.h index 41bac328..58387070 100644 --- a/src/server/pv-client.h +++ b/src/server/pv-client.h @@ -62,7 +62,7 @@ struct _PvClientClass { /* normal GObject stuff */ GType pv_client_get_type (void); -PvClient * pv_client_new (PvDaemon *daemon, const gchar *prefix); +PvClient * pv_client_new (PvDaemon *daemon, const gchar *sender, const gchar *prefix); const gchar * pv_client_get_object_path (PvClient *client); diff --git a/src/server/pv-daemon.c b/src/server/pv-daemon.c index a662e321..2b01aa6b 100644 --- a/src/server/pv-daemon.c +++ b/src/server/pv-daemon.c @@ -23,7 +23,6 @@ #include "server/pv-daemon.h" #include "server/pv-client.h" -#include "server/pv-source-provider.h" #include "modules/v4l2/pv-v4l2-source.h" #include "dbus/org-pulsevideo.h" @@ -37,86 +36,32 @@ struct _PvDaemonPrivate GDBusObjectManagerServer *server_manager; PvSubscribe *subscribe; - GHashTable *senders; + GHashTable *clients; GList *sources; }; -typedef struct { - PvDaemon *daemon; - gchar *sender; - guint id; - - GHashTable *clients; - PvSubscribe *subscribe; - - GHashTable *sources; -} SenderData; - static void on_server_subscription_event (PvSubscribe *subscribe, PvSubscriptionEvent event, PvSubscriptionFlags flags, - GDBusObjectProxy *object, + GDBusProxy *object, gpointer user_data) { PvDaemon *daemon = user_data; PvDaemonPrivate *priv = daemon->priv; - const gchar *object_path; - PvSource1 *source1; - 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", service); - priv->sources = g_list_prepend (priv->sources, source1); - break; - } - - case PV_SUBSCRIPTION_EVENT_CHANGE: - break; - - 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; + const gchar *name, *object_path; - on_server_subscription_event (subscribe, event, flags, object, daemon); + name = g_dbus_proxy_get_name (object); + object_path = g_dbus_proxy_get_object_path (object); - object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); + g_print ("got event %d %d %s:%s\n", event, flags, name, object_path); 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); + if (PV_IS_SOURCE1 (object)) { + priv->sources = g_list_prepend (priv->sources, object); + } break; } @@ -125,80 +70,16 @@ on_sender_subscription_event (PvSubscribe *subscribe, case PV_SUBSCRIPTION_EVENT_REMOVE: { - g_hash_table_remove (data->sources, object_path); + if (PV_IS_SOURCE1 (object)) { + priv->sources = g_list_remove (priv->sources, object); + } else if (PV_IS_CLIENT1 (object)) { + g_hash_table_remove (priv->clients, object_path); + } break; } } } - -static void -client_name_appeared_handler (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - SenderData *data = user_data; - - /* subscribe to Source events. We want to be notified when this new - * sender add/change/remove sources */ - data->subscribe = pv_subscribe_new (); - g_object_set (data->subscribe, "service", data->sender, - "subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE, - "connection", connection, - NULL); - - g_signal_connect (data->subscribe, - "subscription-event", - (GCallback) on_sender_subscription_event, - data); -} - -static void -client_name_vanished_handler (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - SenderData *data = user_data; - PvDaemonPrivate *priv = data->daemon->priv; - - g_print ("vanished client %s\n", name); - - g_hash_table_remove (priv->senders, data->sender); - - g_hash_table_unref (data->clients); - g_hash_table_unref (data->sources); - g_object_unref (data->subscribe); - g_free (data->sender); - g_bus_unwatch_name (data->id); - g_free (data); -} - -static SenderData * -sender_data_new (PvDaemon *daemon, const gchar *sender) -{ - PvDaemonPrivate *priv = daemon->priv; - SenderData *data; - - data = g_new0 (SenderData, 1); - data->daemon = daemon; - data->sender = g_strdup (sender); - data->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - data->sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - - data->id = g_bus_watch_name_on_connection (priv->connection, - sender, - G_BUS_NAME_WATCHER_FLAGS_NONE, - client_name_appeared_handler, - client_name_vanished_handler, - data, - NULL); - - g_hash_table_insert (priv->senders, data->sender, data); - - return data; -} - static gboolean handle_connect_client (PvDaemon1 *interface, GDBusMethodInvocation *invocation, @@ -209,20 +90,15 @@ handle_connect_client (PvDaemon1 *interface, PvDaemonPrivate *priv = daemon->priv; PvClient *client; const gchar *sender, *object_path; - SenderData *data; sender = g_dbus_method_invocation_get_sender (invocation); g_print ("connect client %s\n", sender); - data = g_hash_table_lookup (priv->senders, sender); - if (data == NULL) { - data = sender_data_new (daemon, sender); - } - client = pv_client_new (daemon, PV_DBUS_OBJECT_PREFIX); + client = pv_client_new (daemon, sender, PV_DBUS_OBJECT_PREFIX); object_path = pv_client_get_object_path (client); - g_hash_table_insert (data->clients, g_strdup (object_path), client); + g_hash_table_insert (priv->clients, g_strdup (object_path), client); pv_daemon1_complete_connect_client (interface, invocation, object_path); @@ -272,7 +148,7 @@ name_acquired_handler (GDBusConnection *connection, GDBusObjectManagerServer *manager = priv->server_manager; g_object_set (priv->subscribe, "service", PV_DBUS_SERVICE, - "subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE, + "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, "connection", connection, NULL); @@ -461,7 +337,6 @@ pv_daemon_finalize (GObject * object) PvDaemonPrivate *priv = daemon->priv; g_clear_object (&priv->server_manager); - g_hash_table_unref (priv->senders); pv_daemon_stop (daemon); G_OBJECT_CLASS (pv_daemon_parent_class)->finalize (object); @@ -482,8 +357,8 @@ 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->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); priv->subscribe = pv_subscribe_new (); g_signal_connect (priv->subscribe, diff --git a/src/server/pv-daemon.h b/src/server/pv-daemon.h index bdb9c947..3be38392 100644 --- a/src/server/pv-daemon.h +++ b/src/server/pv-daemon.h @@ -41,7 +41,6 @@ typedef struct _PvDaemonClass PvDaemonClass; typedef struct _PvDaemonPrivate PvDaemonPrivate; #include <client/pv-source.h> -#include <server/pv-source-provider.h> /** * PvDaemon: diff --git a/src/server/pv-source-provider.c b/src/server/pv-source-provider.c index 2350c8e7..c377be4f 100644 --- a/src/server/pv-source-provider.c +++ b/src/server/pv-source-provider.c @@ -116,7 +116,7 @@ source_provider_register_object (PvSourceProvider *client, const gchar *prefix) PvObjectSkeleton *skel; gchar *name; - name = g_strdup_printf ("%s/source", prefix); + name = g_strdup_printf ("%s/source_provider", prefix); skel = pv_object_skeleton_new (name); g_free (name); diff --git a/src/tests/test-subscribe.c b/src/tests/test-subscribe.c index c0c3e328..a87b813c 100644 --- a/src/tests/test-subscribe.c +++ b/src/tests/test-subscribe.c @@ -24,10 +24,32 @@ static GMainLoop *loop; static void +dump_object (GDBusProxy *proxy) +{ + +} + +static void subscription_cb (PvContext *context, PvSubscriptionEvent type, PvSubscriptionFlags flags, - GDBusObject *object, gpointer user_data) + GDBusProxy *object, gpointer user_data) { - g_print ("got event %d %d %s\n", type, flags, g_dbus_object_get_object_path (object)); + g_print ("got event %d %d %s:%s\n", type, flags, + g_dbus_proxy_get_name (object), + g_dbus_proxy_get_object_path (object)); + + switch (type) { + case PV_SUBSCRIPTION_EVENT_NEW: + dump_object (object); + break; + + case PV_SUBSCRIPTION_EVENT_CHANGE: + dump_object (object); + break; + + case PV_SUBSCRIPTION_EVENT_REMOVE: + g_print ("object removed %s\n", g_dbus_proxy_get_object_path (object)); + break; + } } static void |