From 752494621ccafb5b1f89bfd913bf64519c70451a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 Apr 2015 17:27:26 +0200 Subject: [PATCH] rework subscription Rework subscription so that we can use it for client and server. Move source and source-output to client to allow client provided sources. Still needs some work but registration seems to work partly. Rework DBUS API: move CreateSourceOutput to Client1 interface, remove Add/RemoveProvider and Device1 interface. Rework SourceOutput1 to allow for reconfigure. Add a client to test v4l2 source. --- src/Makefile.am | 17 +- src/client/pulsevideo.h | 10 +- src/client/pv-context.c | 153 +++++++----- src/client/pv-context.h | 9 + src/{server => client}/pv-source-output.c | 84 ++++--- src/{server => client}/pv-source-output.h | 1 + src/{server => client}/pv-source.c | 83 +++--- src/{server => client}/pv-source.h | 6 +- src/client/pv-stream.c | 222 +++++++++-------- src/client/pv-subscribe.c | 291 ++++++++++++++++++---- src/client/pv-subscribe.h | 43 +++- src/dbus/org.pulsevideo.xml | 39 ++- src/modules/v4l2/pv-v4l2-source.c | 4 +- src/modules/v4l2/pv-v4l2-source.h | 5 +- src/server/pv-client.c | 41 +-- src/server/pv-daemon.c | 61 ++--- src/server/pv-daemon.h | 8 +- src/tests/test-subscribe.c | 11 +- src/tests/test-v4l2.c | 75 ++++++ 19 files changed, 775 insertions(+), 388 deletions(-) rename src/{server => client}/pv-source-output.c (77%) rename src/{server => client}/pv-source-output.h (96%) rename src/{server => client}/pv-source.c (78%) rename src/{server => client}/pv-source.h (94%) create mode 100644 src/tests/test-v4l2.c diff --git a/src/Makefile.am b/src/Makefile.am index 9c33337cc..666d48fa2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,7 +121,8 @@ noinst_LTLIBRARIES = TESTS_default = TESTS_norun = test-client \ - test-subscribe + test-subscribe \ + test-v4l2 # These tests need a running pulsevideo daemon TESTS_daemon = @@ -138,6 +139,11 @@ test_subscribe_CFLAGS = $(AM_CFLAGS) test_subscribe_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la test_subscribe_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) +test_v4l2_SOURCES = tests/test-v4l2.c +test_v4l2_CFLAGS = $(AM_CFLAGS) +test_v4l2_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la libpulsevideocore-@PV_MAJORMINOR@.la +test_v4l2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Client library # ################################### @@ -153,6 +159,8 @@ pulsevideoinclude_HEADERS = \ client/pv-enumtypes.h \ client/pv-stream.h \ client/pv-subscribe.h \ + client/pv-source.h \ + client/pv-source-output.h \ dbus/org-pulsevideo.h lib_LTLIBRARIES = \ @@ -163,7 +171,10 @@ libpulsevideo_@PV_MAJORMINOR@_la_SOURCES = \ client/pv-context.h client/pv-context.c \ client/pv-enumtypes.h client/pv-enumtypes.c \ client/pv-stream.h client/pv-stream.c \ - client/pulsevideo.c \ + client/pulsevideo.c client/pulsevideo.h \ + client/pv-source-output.c client/pv-source-output.h \ + client/pv-source.c client/pv-source.h \ + client/pv-subscribe.c client/pv-subscribe.h \ dbus/org-pulsevideo.c \ $(pulsevideogstsource) @@ -182,8 +193,6 @@ lib_LTLIBRARIES += libpulsevideocore-@PV_MAJORMINOR@.la libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \ server/pv-client.c server/pv-client.h \ server/pv-daemon.c server/pv-daemon.h \ - server/pv-source-output.c server/pv-source-output.h \ - server/pv-source.c server/pv-source.h \ modules/v4l2/pv-v4l2-source.c libpulsevideocore_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS) diff --git a/src/client/pulsevideo.h b/src/client/pulsevideo.h index 377ce3f9f..e4e457e2c 100644 --- a/src/client/pulsevideo.h +++ b/src/client/pulsevideo.h @@ -20,10 +20,18 @@ #ifndef __PULSEVIDEO_H__ #define __PULSEVIDEO_H__ -#include +#include +#include #include +#include #include +#define PV_DBUS_SERVICE "org.pulsevideo" +#define PV_DBUS_OBJECT_PREFIX "/org/pulsevideo" +#define PV_DBUS_OBJECT_SERVER PV_DBUS_OBJECT_PREFIX "/server" +#define PV_DBUS_OBJECT_SOURCE PV_DBUS_OBJECT_PREFIX "/source" +#define PV_DBUS_OBJECT_CLIENT PV_DBUS_OBJECT_PREFIX "/client" + void pv_init (int *argc, char **argv[]); #endif /* __PULSEVIDEO_H__ */ diff --git a/src/client/pv-context.c b/src/client/pv-context.c index f56cf57e6..66f4918d3 100644 --- a/src/client/pv-context.c +++ b/src/client/pv-context.c @@ -17,7 +17,7 @@ * Boston, MA 02110-1301, USA. */ -#include "server/pv-daemon.h" +#include "client/pulsevideo.h" #include "client/pv-context.h" #include "client/pv-enumtypes.h" @@ -41,8 +41,9 @@ struct _PvContextPrivate gchar *client_path; PvClient1 *client; - PvSubscriptionFlags subscription_mask; - GDBusObjectManager *client_manager; + PvSubscribe *subscribe; + + GDBusObjectManagerServer *server_manager; }; @@ -57,21 +58,10 @@ enum PROP_NAME, PROP_PROPERTIES, PROP_STATE, - PROP_SUBSCRIPTION_MASK, PROP_CONNECTION, PROP_CLIENT_PATH }; -enum -{ - SIGNAL_SUBSCRIPTION_EVENT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -#include "pv-subscribe.c" - static void pv_context_get_property (GObject *_object, guint prop_id, @@ -94,10 +84,6 @@ pv_context_get_property (GObject *_object, g_value_set_enum (value, priv->state); break; - case PROP_SUBSCRIPTION_MASK: - g_value_set_flags (value, priv->subscription_mask); - break; - case PROP_CONNECTION: g_value_set_object (value, priv->connection); break; @@ -133,16 +119,24 @@ pv_context_set_property (GObject *_object, priv->properties = g_value_dup_variant (value); break; - case PROP_SUBSCRIPTION_MASK: - priv->subscription_mask = g_value_get_flags (value); - break; - default: G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec); break; } } +static void +pv_context_finalize (GObject * object) +{ + PvContext *context = PV_CONTEXT (object); + PvContextPrivate *priv = context->priv; + + g_object_unref (priv->server_manager); + + G_OBJECT_CLASS (pv_context_parent_class)->finalize (object); +} + + static void pv_context_class_init (PvContextClass * klass) { @@ -150,6 +144,7 @@ pv_context_class_init (PvContextClass * klass) g_type_class_add_private (klass, sizeof (PvContextPrivate)); + gobject_class->finalize = pv_context_finalize; gobject_class->set_property = pv_context_set_property; gobject_class->get_property = pv_context_get_property; @@ -194,21 +189,6 @@ pv_context_class_init (PvContextClass * klass) PV_CONTEXT_STATE_UNCONNECTED, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /** - * PvContext:subscription-mask - * - * A mask for what object notifications will be signaled with - * PvContext:subscription-event - */ - g_object_class_install_property (gobject_class, - PROP_SUBSCRIPTION_MASK, - g_param_spec_flags ("subscription-mask", - "Subscription Mask", - "The object to receive subscription events of", - PV_TYPE_SUBSCRIPTION_FLAGS, - 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); /** * PvContext:connection * @@ -235,27 +215,6 @@ pv_context_class_init (PvContextClass * klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /** - * PvContext:subscription-event - * @context: The #PvContext emitting the signal. - * @event: A #PvSubscriptionEvent - * @flags: #PvSubscriptionFlags indicating the object - * @path: the object path - * - * Notify about a new object that was added/removed/modified. - */ - signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 3, - PV_TYPE_SUBSCRIPTION_EVENT, - PV_TYPE_SUBSCRIPTION_FLAGS, - G_TYPE_STRING); } static void @@ -264,6 +223,7 @@ pv_context_init (PvContext * context) PvContextPrivate *priv = context->priv = PV_CONTEXT_GET_PRIVATE (context); priv->state = PV_CONTEXT_STATE_UNCONNECTED; + priv->server_manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX); } /** @@ -398,8 +358,12 @@ on_name_appeared (GDBusConnection *connection, PvContextPrivate *priv = context->priv; priv->connection = connection; + g_dbus_object_manager_server_set_connection (priv->server_manager, connection); - install_subscription (context); + if (priv->subscribe) { + g_object_set (priv->subscribe, "connection", priv->connection, NULL); + g_object_set (priv->subscribe, "service", name, NULL); + } pv_daemon1_proxy_new (priv->connection, G_DBUS_PROXY_FLAGS_NONE, @@ -418,9 +382,11 @@ on_name_vanished (GDBusConnection *connection, PvContext *context = user_data; PvContextPrivate *priv = context->priv; - uninstall_subscription (context); - priv->connection = connection; + g_dbus_object_manager_server_set_connection (priv->server_manager, connection); + + if (priv->subscribe) + g_object_set (priv->subscribe, "connection", connection, NULL); if (priv->flags & PV_CONTEXT_FLAGS_NOFAIL) { context_set_state (context, PV_CONTEXT_STATE_CONNECTING); @@ -429,6 +395,28 @@ on_name_vanished (GDBusConnection *connection, } } +gboolean +pv_context_set_subscribe (PvContext *context, PvSubscribe *subscribe) +{ + PvContextPrivate *priv; + + g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE); + + priv = context->priv; + + if (priv->subscribe) + g_object_unref (priv->subscribe); + priv->subscribe = subscribe; + + if (priv->subscribe && priv->connection) { + g_object_set (priv->subscribe, "connection", priv->connection, + "service", PV_DBUS_SERVICE, NULL); + } + + return TRUE; +} + + /** * pv_context_connect: * @context: a #PvContext @@ -467,6 +455,32 @@ pv_context_connect (PvContext *context, PvContextFlags flags) return TRUE; } +gboolean +pv_context_register_source (PvContext *context, PvSource *source) +{ + PvContextPrivate *priv; + + g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE); + g_return_val_if_fail (PV_IS_SOURCE (source), FALSE); + + priv = context->priv; + + pv_source_set_manager (source, priv->server_manager); + + return TRUE; +} + +gboolean +pv_context_unregister_source (PvContext *context, PvSource *source) +{ + g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE); + g_return_val_if_fail (PV_IS_SOURCE (source), FALSE); + + pv_source_set_manager (source, NULL); + + return TRUE; +} + /** * pv_context_get_connection: * @context: a #PvContext @@ -483,6 +497,23 @@ pv_context_get_connection (PvContext *context) return context->priv->connection; } +/** + * pv_context_get_client_proxy: + * @context: a #PvContext + * + * Get the client proxy that @context is registered with + * + * Returns: the client proxy of @context or %NULL when not + * registered. + */ +GDBusProxy * +pv_context_get_client_proxy (PvContext *context) +{ + g_return_val_if_fail (PV_IS_CONTEXT (context), NULL); + + return G_DBUS_PROXY (context->priv->client); +} + /** * pv_context_get_client_path: * @context: a #PvContext diff --git a/src/client/pv-context.h b/src/client/pv-context.h index 81ef3a244..1c2781c0e 100644 --- a/src/client/pv-context.h +++ b/src/client/pv-context.h @@ -23,6 +23,9 @@ #include #include +#include +#include + G_BEGIN_DECLS #define PV_TYPE_CONTEXT (pv_context_get_type ()) @@ -97,9 +100,15 @@ GType pv_context_get_type (void); PvContext * pv_context_new (const gchar *name, GVariant *properties); +gboolean pv_context_set_subscribe (PvContext *context, PvSubscribe *subscribe); + gboolean pv_context_connect (PvContext *context, PvContextFlags flags); +gboolean pv_context_register_source (PvContext *context, PvSource *source); +gboolean pv_context_unregister_source (PvContext *context, PvSource *source); + GDBusConnection * pv_context_get_connection (PvContext *context); +GDBusProxy * pv_context_get_client_proxy (PvContext *context); const gchar * pv_context_get_client_path (PvContext *context); PvContextState pv_context_get_state (PvContext *context); diff --git a/src/server/pv-source-output.c b/src/client/pv-source-output.c similarity index 77% rename from src/server/pv-source-output.c rename to src/client/pv-source-output.c index d28e614bd..64ef9f7c1 100644 --- a/src/server/pv-source-output.c +++ b/src/client/pv-source-output.c @@ -21,16 +21,17 @@ #include -#include "server/pv-daemon.h" -#include "server/pv-source-output.h" +#include "client/pv-source-output.h" #include "client/pv-enumtypes.h" #include "dbus/org-pulsevideo.h" struct _PvSourceOutputPrivate { - PvDaemon *daemon; + GDBusObjectManagerServer *server_manager; + gchar *object_path; + GSocket *socket; }; @@ -42,7 +43,7 @@ G_DEFINE_TYPE (PvSourceOutput, pv_source_output, G_TYPE_OBJECT); enum { PROP_0, - PROP_DAEMON, + PROP_MANAGER, PROP_OBJECT_PATH, PROP_SOCKET, }; @@ -57,8 +58,8 @@ pv_source_output_get_property (GObject *_object, PvSourceOutputPrivate *priv = output->priv; switch (prop_id) { - case PROP_DAEMON: - g_value_set_object (value, priv->daemon); + case PROP_MANAGER: + g_value_set_object (value, priv->server_manager); break; case PROP_OBJECT_PATH: @@ -85,8 +86,8 @@ pv_source_output_set_property (GObject *_object, PvSourceOutputPrivate *priv = output->priv; switch (prop_id) { - case PROP_DAEMON: - priv->daemon = g_value_dup_object (value); + case PROP_MANAGER: + priv->server_manager = g_value_dup_object (value); break; case PROP_OBJECT_PATH: @@ -100,10 +101,10 @@ pv_source_output_set_property (GObject *_object, } static gboolean -handle_acquire (PvSourceOutput1 *interface, - GDBusMethodInvocation *invocation, - GVariant *arg_properties, - gpointer user_data) +handle_start (PvSourceOutput1 *interface, + GDBusMethodInvocation *invocation, + GVariant *arg_properties, + gpointer user_data) { PvSourceOutput *output = user_data; PvSourceOutputPrivate *priv = output->priv; @@ -111,18 +112,21 @@ handle_acquire (PvSourceOutput1 *interface, GVariantBuilder props; gint fd[2]; - g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&props, "{sv}", "name", g_variant_new_string ("hello")); - socketpair (AF_UNIX, SOCK_STREAM, 0, fd); priv->socket = g_socket_new_from_fd (fd[0], NULL); g_object_notify (G_OBJECT (output), "socket"); + g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&props, "{sv}", "name", g_variant_new_string ("hello")); + fdlist = g_unix_fd_list_new (); g_unix_fd_list_append (fdlist, fd[1], NULL); + g_dbus_method_invocation_return_value_with_unix_fd_list (invocation, - g_variant_new ("(h@a{sv})", 0, g_variant_builder_end (&props)), - fdlist); + g_variant_new ("(h@a{sv})", + 0, + g_variant_builder_end (&props)), + fdlist); return TRUE; } @@ -139,15 +143,29 @@ stop_transfer (PvSourceOutput *output) } static gboolean -handle_release (PvSourceOutput1 *interface, - GDBusMethodInvocation *invocation, - gpointer user_data) +handle_stop (PvSourceOutput1 *interface, + GDBusMethodInvocation *invocation, + gpointer user_data) { PvSourceOutput *output = user_data; stop_transfer (output); - pv_source_output1_complete_release (interface, invocation); + pv_source_output1_complete_stop (interface, invocation); + + return TRUE; +} + +static gboolean +handle_remove (PvSourceOutput1 *interface, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + PvSourceOutput *output = user_data; + + stop_transfer (output); + + pv_source_output1_complete_remove (interface, invocation); return TRUE; } @@ -156,7 +174,6 @@ static void output_register_object (PvSourceOutput *output, const gchar *prefix) { PvSourceOutputPrivate *priv = output->priv; - PvDaemon *daemon = priv->daemon; GDBusObjectSkeleton *skel; gchar *name; @@ -168,25 +185,26 @@ output_register_object (PvSourceOutput *output, const gchar *prefix) PvSourceOutput1 *iface; iface = pv_source_output1_skeleton_new (); - g_signal_connect (iface, "handle-acquire", (GCallback) handle_acquire, output); - g_signal_connect (iface, "handle-release", (GCallback) handle_release, output); + 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)); g_object_unref (iface); } + g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel); g_free (priv->object_path); - priv->object_path = pv_daemon_export_uniquely (daemon, skel); + priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); } static void output_unregister_object (PvSourceOutput *output) { PvSourceOutputPrivate *priv = output->priv; - PvDaemon *daemon = priv->daemon; stop_transfer (output); - pv_daemon_unexport (daemon, priv->object_path); + g_dbus_object_manager_server_unexport (priv->server_manager, priv->object_path); } static void @@ -196,7 +214,7 @@ pv_source_output_finalize (GObject * object) PvSourceOutputPrivate *priv = output->priv; output_unregister_object (output); - g_object_unref (priv->daemon); + g_object_unref (priv->server_manager); g_free (priv->object_path); G_OBJECT_CLASS (pv_source_output_parent_class)->finalize (object); @@ -225,11 +243,11 @@ pv_source_output_class_init (PvSourceOutputClass * klass) gobject_class->constructed = pv_source_output_constructed; g_object_class_install_property (gobject_class, - PROP_DAEMON, - g_param_spec_object ("daemon", - "Daemon", - "The daemon", - PV_TYPE_DAEMON, + PROP_MANAGER, + g_param_spec_object ("manager", + "Manager", + "The manager", + G_TYPE_DBUS_OBJECT_MANAGER_SERVER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/src/server/pv-source-output.h b/src/client/pv-source-output.h similarity index 96% rename from src/server/pv-source-output.h rename to src/client/pv-source-output.h index f40b51feb..ee08c4099 100644 --- a/src/server/pv-source-output.h +++ b/src/client/pv-source-output.h @@ -60,6 +60,7 @@ struct _PvSourceOutputClass { /* normal GObject stuff */ GType pv_source_output_get_type (void); +const gchar * pv_source_output_get_sender (PvSourceOutput *output); const gchar * pv_source_output_get_object_path (PvSourceOutput *output); G_END_DECLS diff --git a/src/server/pv-source.c b/src/client/pv-source.c similarity index 78% rename from src/server/pv-source.c rename to src/client/pv-source.c index fe7e2801a..8adb0ea78 100644 --- a/src/server/pv-source.c +++ b/src/client/pv-source.c @@ -19,8 +19,8 @@ #include -#include "server/pv-source.h" -#include "server/pv-daemon.h" +#include "client/pulsevideo.h" +#include "client/pv-source.h" #include "dbus/org-pulsevideo.h" @@ -30,7 +30,8 @@ struct _PvSourcePrivate { - PvDaemon *daemon; + GDBusObjectManagerServer *server_manager; + gchar *object_path; }; @@ -39,7 +40,7 @@ G_DEFINE_ABSTRACT_TYPE (PvSource, pv_source, G_TYPE_OBJECT); enum { PROP_0, - PROP_DAEMON, + PROP_MANAGER, PROP_OBJECT_PATH }; @@ -53,8 +54,8 @@ pv_source_get_property (GObject *_object, PvSourcePrivate *priv = source->priv; switch (prop_id) { - case PROP_DAEMON: - g_value_set_object (value, priv->daemon); + case PROP_MANAGER: + g_value_set_object (value, priv->server_manager); break; case PROP_OBJECT_PATH: @@ -77,8 +78,13 @@ pv_source_set_property (GObject *_object, PvSourcePrivate *priv = source->priv; switch (prop_id) { - case PROP_DAEMON: - priv->daemon = g_value_dup_object (value); + case PROP_MANAGER: + pv_source_set_manager (source, g_value_dup_object (value)); + break; + + case PROP_OBJECT_PATH: + g_free (priv->object_path); + priv->object_path = g_value_dup_string (value); break; default: @@ -90,7 +96,6 @@ static void source_register_object (PvSource *source) { PvSourcePrivate *priv = source->priv; - PvDaemon *daemon = priv->daemon; GDBusObjectSkeleton *skel; skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE); @@ -101,17 +106,20 @@ source_register_object (PvSource *source) g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); g_object_unref (iface); } + g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel); + g_free (priv->object_path); - priv->object_path = pv_daemon_export_uniquely (daemon, skel); + priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); + + return; } static void source_unregister_object (PvSource *source) { PvSourcePrivate *priv = source->priv; - PvDaemon *daemon = priv->daemon; - pv_daemon_unexport (daemon, priv->object_path); + g_dbus_object_manager_server_unexport (priv->server_manager, priv->object_path); } static void @@ -120,29 +128,21 @@ pv_source_finalize (GObject * object) PvSource *source = PV_SOURCE (object); PvSourcePrivate *priv = source->priv; - source_unregister_object (source); - g_object_unref (priv->daemon); + if (priv->server_manager) { + source_unregister_object (source); + g_object_unref (priv->server_manager); + } g_free (priv->object_path); G_OBJECT_CLASS (pv_source_parent_class)->finalize (object); } -static void -pv_source_constructed (GObject * object) -{ - PvSource *source = PV_SOURCE (object); - - source_register_object (source); - - G_OBJECT_CLASS (pv_source_parent_class)->constructed (object); -} - static PvSourceOutput * default_create_source_output (PvSource *source, GVariant *props, const gchar *prefix) { PvSourcePrivate *priv = source->priv; - return g_object_new (PV_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon, "object-path", prefix, NULL); + return g_object_new (PV_TYPE_SOURCE_OUTPUT, "manager", priv->server_manager, "object-path", prefix, NULL); } static gboolean @@ -163,16 +163,14 @@ pv_source_class_init (PvSourceClass * klass) gobject_class->finalize = pv_source_finalize; gobject_class->set_property = pv_source_set_property; gobject_class->get_property = pv_source_get_property; - gobject_class->constructed = pv_source_constructed; g_object_class_install_property (gobject_class, - PROP_DAEMON, - g_param_spec_object ("daemon", - "Daemon", - "The daemon", - PV_TYPE_DAEMON, + PROP_MANAGER, + g_param_spec_object ("manager", + "Manager", + "The manager", + G_TYPE_DBUS_OBJECT_MANAGER_SERVER, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, @@ -181,7 +179,7 @@ pv_source_class_init (PvSourceClass * klass) "Object Path", "The object path", NULL, - G_PARAM_READABLE | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); klass->create_source_output = default_create_source_output; @@ -194,6 +192,25 @@ pv_source_init (PvSource * source) source->priv = PV_SOURCE_GET_PRIVATE (source); } +void +pv_source_set_manager (PvSource *source, GDBusObjectManagerServer *manager) +{ + PvSourcePrivate *priv; + + g_return_if_fail (PV_IS_SOURCE (source)); + priv = source->priv; + + if (priv->server_manager) { + source_unregister_object (source); + g_object_unref (priv->server_manager); + } + priv->server_manager = manager; + + if (priv->server_manager) { + source_register_object (source); + } +} + GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props) { diff --git a/src/server/pv-source.h b/src/client/pv-source.h similarity index 94% rename from src/server/pv-source.h rename to src/client/pv-source.h index fc61a0016..2ad46c58d 100644 --- a/src/server/pv-source.h +++ b/src/client/pv-source.h @@ -21,6 +21,7 @@ #define __PV_SOURCE_H__ #include +#include G_BEGIN_DECLS @@ -28,8 +29,7 @@ typedef struct _PvSource PvSource; typedef struct _PvSourceClass PvSourceClass; typedef struct _PvSourcePrivate PvSourcePrivate; -#include "server/pv-daemon.h" -#include "server/pv-source-output.h" +#include "client/pv-source-output.h" #define PV_TYPE_SOURCE (pv_source_get_type ()) #define PV_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE)) @@ -71,7 +71,7 @@ struct _PvSourceClass { /* normal GObject stuff */ GType pv_source_get_type (void); -PvSource * pv_source_new (PvDaemon *daemon, const gchar *prefix); +void pv_source_set_manager (PvSource *source, GDBusObjectManagerServer *manager); GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props); diff --git a/src/client/pv-stream.c b/src/client/pv-stream.c index 0cadde8fc..f93e4d1ac 100644 --- a/src/client/pv-stream.c +++ b/src/client/pv-stream.c @@ -33,7 +33,7 @@ struct _PvStreamPrivate gchar *target; PvStreamState state; - PvCapture1 *capture; + gchar *source_output_sender; gchar *source_output_path; PvSourceOutput1 *source_output; @@ -275,6 +275,14 @@ pv_stream_get_state (PvStream *stream) return stream->priv->state; } +static void +on_request_reconfigure (PvSourceOutput1 *interface, + GVariant *props, + gpointer user_data) +{ + g_print ("on request reconfigure\n"); +} + static void on_source_output1_proxy (GObject *source_object, GAsyncResult *res, @@ -285,13 +293,21 @@ on_source_output1_proxy (GObject *source_object, GError *error = NULL; priv->source_output = pv_source_output1_proxy_new_finish (res, &error); - if (priv->source_output == NULL) { + if (priv->source_output == NULL) + goto source_output_failed; + + g_signal_connect (priv->source_output, "request-reconfigure", (GCallback) on_request_reconfigure, stream); + stream_set_state (stream, PV_STREAM_STATE_READY); + return; + + /* ERRORS */ +source_output_failed: + { stream_set_state (stream, PV_STREAM_STATE_ERROR); g_error ("failed to get source output proxy: %s", error->message); g_clear_error (&error); return; } - stream_set_state (stream, PV_STREAM_STATE_READY); } static void @@ -303,22 +319,31 @@ on_source_output_created (GObject *source_object, PvStreamPrivate *priv = stream->priv; PvContext *context = priv->context; GError *error = NULL; + PvClient1 *proxy; - if (!pv_capture1_call_create_source_output_finish (priv->capture, - &priv->source_output_path, res, &error)) { + 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)) + goto create_failed; + + pv_source_output1_proxy_new (pv_context_get_connection (context), + G_DBUS_PROXY_FLAGS_NONE, + priv->source_output_sender, + priv->source_output_path, + NULL, + on_source_output1_proxy, + stream); + return; + + /* ERRORS */ +create_failed: + { stream_set_state (stream, PV_STREAM_STATE_ERROR); g_print ("failed to get connect capture: %s", error->message); g_clear_error (&error); return; } - - pv_source_output1_proxy_new (pv_context_get_connection (context), - G_DBUS_PROXY_FLAGS_NONE, - PV_DBUS_SERVICE, - priv->source_output_path, - NULL, - on_source_output1_proxy, - stream); } static gboolean @@ -326,16 +351,19 @@ 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")); - pv_capture1_call_create_source_output (priv->capture, - priv->target ? priv->target : "/", /* const gchar *arg_source */ - g_variant_builder_end (&builder), /* GVariant *arg_props */ - NULL, /* GCancellable *cancellable */ - on_source_output_created, - stream); + 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; } @@ -348,13 +376,14 @@ on_source_output_removed (GObject *source_object, PvStreamPrivate *priv = stream->priv; GError *error = NULL; - if (!pv_capture1_call_remove_source_output_finish (priv->capture, + if (!pv_source_output1_call_remove_finish (priv->source_output, res, &error)) { stream_set_state (stream, PV_STREAM_STATE_ERROR); g_print ("failed to disconnect: %s", error->message); 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); } @@ -364,35 +393,13 @@ remove_source_output (PvStream *stream) { PvStreamPrivate *priv = stream->priv; - pv_capture1_call_remove_source_output (priv->capture, - priv->source_output_path, - NULL, /* GCancellable *cancellable */ - on_source_output_removed, - stream); + pv_source_output1_call_remove (priv->source_output, + NULL, /* GCancellable *cancellable */ + on_source_output_removed, + stream); return TRUE; } -static void -on_capture_proxy (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PvStream *stream = user_data; - PvStreamPrivate *priv = stream->priv; - GError *error = NULL; - - priv->capture = pv_capture1_proxy_new_finish (res, &error); - if (priv->capture == NULL) { - stream_set_state (stream, PV_STREAM_STATE_ERROR); - g_error ("failed to get capture proxy: %s", error->message); - g_clear_error (&error); - return; - } - - create_source_output (stream); -} - - /** * pv_stream_connect_capture: * @stream: a #PvStream @@ -420,19 +427,7 @@ pv_stream_connect_capture (PvStream *stream, stream_set_state (stream, PV_STREAM_STATE_CONNECTING); - if (priv->capture == NULL) { - pv_capture1_proxy_new (pv_context_get_connection (context), - G_DBUS_PROXY_FLAGS_NONE, - PV_DBUS_SERVICE, - pv_context_get_client_path (context), - NULL, - on_capture_proxy, - stream); - - return TRUE; - } else { - return create_source_output (stream); - } + return create_source_output (stream); } /** @@ -452,7 +447,7 @@ pv_stream_disconnect (PvStream *stream) g_return_val_if_fail (PV_IS_STREAM (stream), FALSE); priv = stream->priv; g_return_val_if_fail (priv->state >= PV_STREAM_STATE_READY, FALSE); - g_return_val_if_fail (priv->capture != NULL, FALSE); + g_return_val_if_fail (priv->source_output != NULL, FALSE); context = priv->context; g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE); @@ -528,12 +523,8 @@ handle_socket (PvStream *stream, gint fd) g_print ("got fd %d\n", fd); priv->socket = g_socket_new_from_fd (fd, &error); - if (priv->socket == NULL) { - stream_set_state (stream, PV_STREAM_STATE_ERROR); - g_error ("failed to create socket: %s", error->message); - g_clear_error (&error); - return; - } + if (priv->socket == NULL) + goto socket_failed; switch (priv->mode) { case PV_STREAM_MODE_SOCKET: @@ -554,6 +545,16 @@ handle_socket (PvStream *stream, gint fd) default: break; } + return; + + /* ERRORS */ +socket_failed: + { + stream_set_state (stream, PV_STREAM_STATE_ERROR); + g_error ("failed to create socket: %s", error->message); + g_clear_error (&error); + return; + } } static void @@ -573,9 +574,9 @@ unhandle_socket (PvStream *stream) } static void -on_stream_acquired (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +on_stream_started (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { PvStream *stream = user_data; PvStreamPrivate *priv = stream->priv; @@ -585,13 +586,12 @@ on_stream_acquired (GObject *source_object, GError *error = NULL; GVariant *result; - result = g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (priv->source_output), &out_fd_list, res, &error); - if (result == NULL) { - stream_set_state (stream, PV_STREAM_STATE_ERROR); - g_error ("failed to acquire: %s", error->message); - g_clear_error (&error); - return; - } + result = g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (priv->source_output), + &out_fd_list, + res, + &error); + if (result == NULL) + goto start_failed; g_variant_get (result, "(h@a{sv})", @@ -601,16 +601,32 @@ on_stream_acquired (GObject *source_object, g_variant_unref (result); g_variant_unref (out_props); - if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0) { - stream_set_state (stream, PV_STREAM_STATE_ERROR); - g_error ("failed to get FD: %s", error->message); - g_clear_error (&error); - return; - } + if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0) + goto fd_failed; handle_socket (stream, fd); stream_set_state (stream, PV_STREAM_STATE_STREAMING); + + return; + + /* ERRORS */ +start_failed: + { + g_error ("failed to start: %s", error->message); + goto exit_error; + } +fd_failed: + { + g_error ("failed to get FD: %s", error->message); + goto exit_error; + } +exit_error: + { + stream_set_state (stream, PV_STREAM_STATE_ERROR); + g_clear_error (&error); + return; + } } /** @@ -648,34 +664,42 @@ pv_stream_start (PvStream *stream, PvStreamMode mode) g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); - pv_source_output1_call_acquire (priv->source_output, - g_variant_builder_end (&builder), /* GVariant *arg_properties */ - NULL, /* GCancellable *cancellable */ - on_stream_acquired, - stream); + pv_source_output1_call_start (priv->source_output, + g_variant_builder_end (&builder), /* GVariant *arg_properties */ + NULL, /* GCancellable *cancellable */ + on_stream_started, + stream); } return TRUE; } static void -on_stream_released (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +on_stream_stopped (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { PvStream *stream = user_data; PvStreamPrivate *priv = stream->priv; GError *error = NULL; - if (!pv_source_output1_call_release_finish (priv->source_output, - res, &error)) { + if (!pv_source_output1_call_stop_finish (priv->source_output, + res, &error)) + goto call_failed; + + unhandle_socket (stream); + + stream_set_state (stream, PV_STREAM_STATE_READY); + + return; + + /* ERRORS */ +call_failed: + { stream_set_state (stream, PV_STREAM_STATE_ERROR); g_error ("failed to release: %s", error->message); g_clear_error (&error); return; } - unhandle_socket (stream); - - stream_set_state (stream, PV_STREAM_STATE_READY); } /** @@ -696,10 +720,10 @@ pv_stream_stop (PvStream *stream) priv = stream->priv; g_return_val_if_fail (priv->state == PV_STREAM_STATE_STREAMING, FALSE); - pv_source_output1_call_release (priv->source_output, - NULL, /* GCancellable *cancellable */ - on_stream_released, - stream); + pv_source_output1_call_stop (priv->source_output, + NULL, /* GCancellable *cancellable */ + on_stream_stopped, + stream); return TRUE; } diff --git a/src/client/pv-subscribe.c b/src/client/pv-subscribe.c index e31427b15..963a07768 100644 --- a/src/client/pv-subscribe.c +++ b/src/client/pv-subscribe.c @@ -17,36 +17,69 @@ * Boston, MA 02110-1301, USA. */ -static void -notify_subscription (PvContext *context, - GDBusObject *object, - GDBusInterface *interface, - PvSubscriptionEvent event) +#include + +#include "client/pulsevideo.h" +#include "client/pv-enumtypes.h" + +#include "dbus/org-pulsevideo.h" + +struct _PvSubscribePrivate { - PvContextPrivate *priv = context->priv; + GDBusConnection *connection; + gchar *service; + + PvSubscriptionFlags subscription_mask; + + GDBusObjectManager *client_manager; +}; + + +#define PV_SUBSCRIBE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SUBSCRIBE, PvSubscribePrivate)) + +G_DEFINE_TYPE (PvSubscribe, pv_subscribe, G_TYPE_OBJECT); + +enum +{ + PROP_0, + PROP_CONNECTION, + PROP_SERVICE, + PROP_SUBSCRIPTION_MASK +}; + +enum +{ + SIGNAL_SUBSCRIPTION_EVENT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +notify_subscription (PvSubscribe *subscribe, + GDBusObject *object, + GDBusInterface *interface, + PvSubscriptionEvent event) +{ + 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)) - g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, + g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, PV_SUBSCRIPTION_FLAGS_CLIENT, g_dbus_object_get_object_path (object)); } - if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_DEVICE) { - if ((interface == NULL && pv_object_peek_device1 (PV_OBJECT (object))) || - PV_IS_DEVICE1_PROXY (interface)) - g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, - PV_SUBSCRIPTION_FLAGS_DEVICE, g_dbus_object_get_object_path (object)); - } if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) { if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) || PV_IS_SOURCE1_PROXY (interface)) - g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, + g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, PV_SUBSCRIPTION_FLAGS_SOURCE, g_dbus_object_get_object_path (object)); } 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)) - g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, + g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event, PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT, g_dbus_object_get_object_path (object)); } } @@ -57,8 +90,8 @@ on_client_manager_interface_added (GDBusObjectManager *manager, GDBusInterface *interface, gpointer user_data) { - PvContext *context = user_data; - notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_NEW); + PvSubscribe *subscribe = user_data; + notify_subscription (subscribe, object, interface, PV_SUBSCRIPTION_EVENT_NEW); } static void @@ -67,8 +100,8 @@ on_client_manager_interface_removed (GDBusObjectManager *manager, GDBusInterface *interface, gpointer user_data) { - PvContext *context = user_data; - notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_REMOVE); + PvSubscribe *subscribe = user_data; + notify_subscription (subscribe, object, interface, PV_SUBSCRIPTION_EVENT_REMOVE); } static void @@ -76,8 +109,8 @@ on_client_manager_object_added (GDBusObjectManager *manager, GDBusObject *object, gpointer user_data) { - PvContext *context = user_data; - notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_NEW); + PvSubscribe *subscribe = user_data; + notify_subscription (subscribe, object, NULL, PV_SUBSCRIPTION_EVENT_NEW); } static void @@ -85,8 +118,8 @@ on_client_manager_object_removed (GDBusObjectManager *manager, GDBusObject *object, gpointer user_data) { - PvContext *context = user_data; - notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_REMOVE); + PvSubscribe *subscribe = user_data; + notify_subscription (subscribe, object, NULL, PV_SUBSCRIPTION_EVENT_REMOVE); } static void @@ -113,22 +146,22 @@ on_client_manager_signal (GDBusObjectManagerClient *manager, } static void -connect_client_signals (PvContext *context) +connect_client_signals (PvSubscribe *subscribe) { - PvContextPrivate *priv = context->priv; + PvSubscribePrivate *priv = subscribe->priv; g_signal_connect (priv->client_manager, "interface-added", - (GCallback) on_client_manager_interface_added, context); + (GCallback) on_client_manager_interface_added, subscribe); g_signal_connect (priv->client_manager, "interface-removed", - (GCallback) on_client_manager_interface_removed, context); + (GCallback) on_client_manager_interface_removed, subscribe); g_signal_connect (priv->client_manager, "object-added", - (GCallback) on_client_manager_object_added, context); + (GCallback) on_client_manager_object_added, subscribe); g_signal_connect (priv->client_manager, "object-removed", - (GCallback) on_client_manager_object_removed, context); + (GCallback) on_client_manager_object_removed, subscribe); g_signal_connect (priv->client_manager, "interface-proxy-signal", - (GCallback) on_client_manager_signal, context); + (GCallback) on_client_manager_signal, subscribe); g_signal_connect (priv->client_manager, "interface-proxy-properties-changed", - (GCallback) on_client_manager_properties_changed, context); + (GCallback) on_client_manager_properties_changed, subscribe); } static void @@ -136,15 +169,15 @@ on_client_manager_ready (GObject *source_object, GAsyncResult *res, gpointer user_data) { - PvContext *context = user_data; - PvContextPrivate *priv = context->priv; + PvSubscribe *subscribe = user_data; + PvSubscribePrivate *priv = subscribe->priv; GError *error = NULL; priv->client_manager = pv_object_manager_client_new_finish (res, &error); if (priv->client_manager == NULL) goto manager_error; - connect_client_signals (context); + connect_client_signals (subscribe); return; @@ -158,26 +191,196 @@ manager_error: } static void -install_subscription (PvContext *context) +install_subscription (PvSubscribe *subscribe) { - PvContextPrivate *priv = context->priv; + PvSubscribePrivate *priv = subscribe->priv; - if (priv->client_manager) - return; - - pv_object_manager_client_new (pv_context_get_connection (context), + pv_object_manager_client_new (priv->connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, - PV_DBUS_SERVICE, + priv->service, PV_DBUS_OBJECT_PREFIX, NULL, on_client_manager_ready, - context); + subscribe); } static void -uninstall_subscription (PvContext *context) +uninstall_subscription (PvSubscribe *subscribe) { - PvContextPrivate *priv = context->priv; + PvSubscribePrivate *priv = subscribe->priv; g_clear_object (&priv->client_manager); } + +static void +pv_subscribe_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PvSubscribe *subscribe = PV_SUBSCRIBE (_object); + PvSubscribePrivate *priv = subscribe->priv; + + switch (prop_id) { + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + + case PROP_SERVICE: + g_value_set_string (value, priv->service); + break; + + case PROP_SUBSCRIPTION_MASK: + g_value_set_flags (value, priv->subscription_mask); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec); + break; + } +} + +static void +pv_subscribe_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PvSubscribe *subscribe = PV_SUBSCRIBE (_object); + PvSubscribePrivate *priv = subscribe->priv; + + switch (prop_id) { + case PROP_CONNECTION: + { + uninstall_subscription (subscribe); + if (priv->connection) + g_object_unref (priv->connection); + priv->connection = g_value_dup_object (value); + install_subscription (subscribe); + break; + } + + case PROP_SERVICE: + g_free (priv->service); + priv->service = g_value_dup_string (value); + break; + + case PROP_SUBSCRIPTION_MASK: + priv->subscription_mask = g_value_get_flags (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec); + break; + } +} + +static void +pv_subscribe_finalize (GObject * object) +{ + PvSubscribe *subscribe = PV_SUBSCRIBE (object); + PvSubscribePrivate *priv = subscribe->priv; + + g_free (priv->service); + g_object_unref (priv->client_manager); + + G_OBJECT_CLASS (pv_subscribe_parent_class)->finalize (object); +} + +static void +pv_subscribe_class_init (PvSubscribeClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PvSubscribePrivate)); + + gobject_class->finalize = pv_subscribe_finalize; + gobject_class->set_property = pv_subscribe_set_property; + gobject_class->get_property = pv_subscribe_get_property; + + /** + * PvSubscribe:connection + * + * The connection of the subscribe. + */ + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Connection", + "The DBus connection", + G_TYPE_DBUS_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * PvSubscribe:service + * + * The service of the subscribe. + */ + g_object_class_install_property (gobject_class, + PROP_SERVICE, + g_param_spec_string ("service", + "Service", + "The service", + PV_DBUS_SERVICE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * PvSubscribe:subscription-mask + * + * A mask for what object notifications will be signaled with + * PvSubscribe:subscription-event + */ + g_object_class_install_property (gobject_class, + PROP_SUBSCRIPTION_MASK, + g_param_spec_flags ("subscription-mask", + "Subscription Mask", + "The object to receive subscription events of", + PV_TYPE_SUBSCRIPTION_FLAGS, + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * PvSubscribe:subscription-event + * @subscribe: The #PvSubscribe emitting the signal. + * @event: A #PvSubscriptionEvent + * @flags: #PvSubscriptionFlags indicating the object + * @path: the object path + * + * Notify about a new object that was added/removed/modified. + */ + signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 3, + PV_TYPE_SUBSCRIPTION_EVENT, + PV_TYPE_SUBSCRIPTION_FLAGS, + G_TYPE_STRING); +} + +static void +pv_subscribe_init (PvSubscribe * subscribe) +{ + PvSubscribePrivate *priv = subscribe->priv = PV_SUBSCRIBE_GET_PRIVATE (subscribe); + + priv->service = g_strdup (PV_DBUS_SERVICE); +} + +/** + * pv_subscribe_new: + * @name: an application name + * @properties: optional properties + * + * Make a new unconnected #PvSubscribe + * + * Returns: a new unconnected #PvSubscribe + */ +PvSubscribe * +pv_subscribe_new (void) +{ + return g_object_new (PV_TYPE_SUBSCRIBE, NULL); +} diff --git a/src/client/pv-subscribe.h b/src/client/pv-subscribe.h index f27f1ccd4..f49e8704d 100644 --- a/src/client/pv-subscribe.h +++ b/src/client/pv-subscribe.h @@ -24,11 +24,23 @@ G_BEGIN_DECLS +#define PV_TYPE_SUBSCRIBE (pv_subscribe_get_type ()) +#define PV_IS_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SUBSCRIBE)) +#define PV_IS_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SUBSCRIBE)) +#define PV_SUBSCRIBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SUBSCRIBE, PvSubscribeClass)) +#define PV_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SUBSCRIBE, PvSubscribe)) +#define PV_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SUBSCRIBE, PvSubscribeClass)) +#define PV_SUBSCRIBE_CAST(obj) ((PvSubscribe*)(obj)) +#define PV_SUBSCRIBE_CLASS_CAST(klass) ((PvSubscribeClass*)(klass)) + +typedef struct _PvSubscribe PvSubscribe; +typedef struct _PvSubscribeClass PvSubscribeClass; +typedef struct _PvSubscribePrivate PvSubscribePrivate; + typedef enum { PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0), - PV_SUBSCRIPTION_FLAGS_DEVICE = (1 << 1), - PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2), - PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3), + PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 1), + PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 2), PV_SUBSCRIPTION_FLAGS_ALL = 0xf } PvSubscriptionFlags; @@ -39,6 +51,31 @@ typedef enum { PV_SUBSCRIPTION_EVENT_REMOVE = 2, } PvSubscriptionEvent; +/** + * PvSubscribe: + * + * Pulsevideo subscribe object class. + */ +struct _PvSubscribe { + GObject object; + + PvSubscribePrivate *priv; +}; + +/** + * PvSubscribeClass: + * + * Pulsevideo subscribe object class. + */ +struct _PvSubscribeClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType pv_subscribe_get_type (void); + +PvSubscribe * pv_subscribe_new (void); + G_END_DECLS #endif /* __PV_SUBSCRIBE_H__ */ diff --git a/src/dbus/org.pulsevideo.xml b/src/dbus/org.pulsevideo.xml index a82cb99f3..5fe67c8aa 100644 --- a/src/dbus/org.pulsevideo.xml +++ b/src/dbus/org.pulsevideo.xml @@ -17,26 +17,17 @@ - - - + - - + + - - - - - - - - - + + @@ -52,11 +43,6 @@ - - - - - @@ -65,16 +51,25 @@ + + + + + - + + - - + + + + +