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.
This commit is contained in:
Wim Taymans 2015-04-17 17:27:26 +02:00
parent 75d5fa91e2
commit 752494621c
19 changed files with 775 additions and 388 deletions

View file

@ -121,7 +121,8 @@ noinst_LTLIBRARIES =
TESTS_default = TESTS_default =
TESTS_norun = test-client \ TESTS_norun = test-client \
test-subscribe test-subscribe \
test-v4l2
# These tests need a running pulsevideo daemon # These tests need a running pulsevideo daemon
TESTS_daemon = TESTS_daemon =
@ -138,6 +139,11 @@ test_subscribe_CFLAGS = $(AM_CFLAGS)
test_subscribe_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la test_subscribe_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la
test_subscribe_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) 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 # # Client library #
################################### ###################################
@ -153,6 +159,8 @@ pulsevideoinclude_HEADERS = \
client/pv-enumtypes.h \ client/pv-enumtypes.h \
client/pv-stream.h \ client/pv-stream.h \
client/pv-subscribe.h \ client/pv-subscribe.h \
client/pv-source.h \
client/pv-source-output.h \
dbus/org-pulsevideo.h dbus/org-pulsevideo.h
lib_LTLIBRARIES = \ lib_LTLIBRARIES = \
@ -163,7 +171,10 @@ libpulsevideo_@PV_MAJORMINOR@_la_SOURCES = \
client/pv-context.h client/pv-context.c \ client/pv-context.h client/pv-context.c \
client/pv-enumtypes.h client/pv-enumtypes.c \ client/pv-enumtypes.h client/pv-enumtypes.c \
client/pv-stream.h client/pv-stream.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 \ dbus/org-pulsevideo.c \
$(pulsevideogstsource) $(pulsevideogstsource)
@ -182,8 +193,6 @@ lib_LTLIBRARIES += libpulsevideocore-@PV_MAJORMINOR@.la
libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \ libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \
server/pv-client.c server/pv-client.h \ server/pv-client.c server/pv-client.h \
server/pv-daemon.c server/pv-daemon.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 modules/v4l2/pv-v4l2-source.c
libpulsevideocore_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS) libpulsevideocore_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS)

View file

@ -20,10 +20,18 @@
#ifndef __PULSEVIDEO_H__ #ifndef __PULSEVIDEO_H__
#define __PULSEVIDEO_H__ #define __PULSEVIDEO_H__
#include <client/pv-context.h> #include <client/pv-source.h>
#include <client/pv-source-output.h>
#include <client/pv-stream.h> #include <client/pv-stream.h>
#include <client/pv-context.h>
#include <client/pv-subscribe.h> #include <client/pv-subscribe.h>
#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[]); void pv_init (int *argc, char **argv[]);
#endif /* __PULSEVIDEO_H__ */ #endif /* __PULSEVIDEO_H__ */

View file

@ -17,7 +17,7 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include "server/pv-daemon.h" #include "client/pulsevideo.h"
#include "client/pv-context.h" #include "client/pv-context.h"
#include "client/pv-enumtypes.h" #include "client/pv-enumtypes.h"
@ -41,8 +41,9 @@ struct _PvContextPrivate
gchar *client_path; gchar *client_path;
PvClient1 *client; PvClient1 *client;
PvSubscriptionFlags subscription_mask; PvSubscribe *subscribe;
GDBusObjectManager *client_manager;
GDBusObjectManagerServer *server_manager;
}; };
@ -57,21 +58,10 @@ enum
PROP_NAME, PROP_NAME,
PROP_PROPERTIES, PROP_PROPERTIES,
PROP_STATE, PROP_STATE,
PROP_SUBSCRIPTION_MASK,
PROP_CONNECTION, PROP_CONNECTION,
PROP_CLIENT_PATH PROP_CLIENT_PATH
}; };
enum
{
SIGNAL_SUBSCRIPTION_EVENT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
#include "pv-subscribe.c"
static void static void
pv_context_get_property (GObject *_object, pv_context_get_property (GObject *_object,
guint prop_id, guint prop_id,
@ -94,10 +84,6 @@ pv_context_get_property (GObject *_object,
g_value_set_enum (value, priv->state); g_value_set_enum (value, priv->state);
break; break;
case PROP_SUBSCRIPTION_MASK:
g_value_set_flags (value, priv->subscription_mask);
break;
case PROP_CONNECTION: case PROP_CONNECTION:
g_value_set_object (value, priv->connection); g_value_set_object (value, priv->connection);
break; break;
@ -133,16 +119,24 @@ pv_context_set_property (GObject *_object,
priv->properties = g_value_dup_variant (value); priv->properties = g_value_dup_variant (value);
break; break;
case PROP_SUBSCRIPTION_MASK:
priv->subscription_mask = g_value_get_flags (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec);
break; 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 static void
pv_context_class_init (PvContextClass * klass) pv_context_class_init (PvContextClass * klass)
{ {
@ -150,6 +144,7 @@ pv_context_class_init (PvContextClass * klass)
g_type_class_add_private (klass, sizeof (PvContextPrivate)); g_type_class_add_private (klass, sizeof (PvContextPrivate));
gobject_class->finalize = pv_context_finalize;
gobject_class->set_property = pv_context_set_property; gobject_class->set_property = pv_context_set_property;
gobject_class->get_property = pv_context_get_property; gobject_class->get_property = pv_context_get_property;
@ -194,21 +189,6 @@ pv_context_class_init (PvContextClass * klass)
PV_CONTEXT_STATE_UNCONNECTED, PV_CONTEXT_STATE_UNCONNECTED,
G_PARAM_READABLE | G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS)); 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 * PvContext:connection
* *
@ -235,27 +215,6 @@ pv_context_class_init (PvContextClass * klass)
NULL, NULL,
G_PARAM_READABLE | G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS)); 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 static void
@ -264,6 +223,7 @@ pv_context_init (PvContext * context)
PvContextPrivate *priv = context->priv = PV_CONTEXT_GET_PRIVATE (context); PvContextPrivate *priv = context->priv = PV_CONTEXT_GET_PRIVATE (context);
priv->state = PV_CONTEXT_STATE_UNCONNECTED; 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; PvContextPrivate *priv = context->priv;
priv->connection = connection; 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, pv_daemon1_proxy_new (priv->connection,
G_DBUS_PROXY_FLAGS_NONE, G_DBUS_PROXY_FLAGS_NONE,
@ -418,9 +382,11 @@ on_name_vanished (GDBusConnection *connection,
PvContext *context = user_data; PvContext *context = user_data;
PvContextPrivate *priv = context->priv; PvContextPrivate *priv = context->priv;
uninstall_subscription (context);
priv->connection = connection; 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) { if (priv->flags & PV_CONTEXT_FLAGS_NOFAIL) {
context_set_state (context, PV_CONTEXT_STATE_CONNECTING); 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: * pv_context_connect:
* @context: a #PvContext * @context: a #PvContext
@ -467,6 +455,32 @@ pv_context_connect (PvContext *context, PvContextFlags flags)
return TRUE; 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: * pv_context_get_connection:
* @context: a #PvContext * @context: a #PvContext
@ -483,6 +497,23 @@ pv_context_get_connection (PvContext *context)
return context->priv->connection; 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: * pv_context_get_client_path:
* @context: a #PvContext * @context: a #PvContext

View file

@ -23,6 +23,9 @@
#include <glib-object.h> #include <glib-object.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <client/pv-source.h>
#include <client/pv-subscribe.h>
G_BEGIN_DECLS G_BEGIN_DECLS
#define PV_TYPE_CONTEXT (pv_context_get_type ()) #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); 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_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); GDBusConnection * pv_context_get_connection (PvContext *context);
GDBusProxy * pv_context_get_client_proxy (PvContext *context);
const gchar * pv_context_get_client_path (PvContext *context); const gchar * pv_context_get_client_path (PvContext *context);
PvContextState pv_context_get_state (PvContext *context); PvContextState pv_context_get_state (PvContext *context);

View file

@ -21,16 +21,17 @@
#include <gio/gunixfdlist.h> #include <gio/gunixfdlist.h>
#include "server/pv-daemon.h" #include "client/pv-source-output.h"
#include "server/pv-source-output.h"
#include "client/pv-enumtypes.h" #include "client/pv-enumtypes.h"
#include "dbus/org-pulsevideo.h" #include "dbus/org-pulsevideo.h"
struct _PvSourceOutputPrivate struct _PvSourceOutputPrivate
{ {
PvDaemon *daemon; GDBusObjectManagerServer *server_manager;
gchar *object_path; gchar *object_path;
GSocket *socket; GSocket *socket;
}; };
@ -42,7 +43,7 @@ G_DEFINE_TYPE (PvSourceOutput, pv_source_output, G_TYPE_OBJECT);
enum enum
{ {
PROP_0, PROP_0,
PROP_DAEMON, PROP_MANAGER,
PROP_OBJECT_PATH, PROP_OBJECT_PATH,
PROP_SOCKET, PROP_SOCKET,
}; };
@ -57,8 +58,8 @@ pv_source_output_get_property (GObject *_object,
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
switch (prop_id) { switch (prop_id) {
case PROP_DAEMON: case PROP_MANAGER:
g_value_set_object (value, priv->daemon); g_value_set_object (value, priv->server_manager);
break; break;
case PROP_OBJECT_PATH: case PROP_OBJECT_PATH:
@ -85,8 +86,8 @@ pv_source_output_set_property (GObject *_object,
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
switch (prop_id) { switch (prop_id) {
case PROP_DAEMON: case PROP_MANAGER:
priv->daemon = g_value_dup_object (value); priv->server_manager = g_value_dup_object (value);
break; break;
case PROP_OBJECT_PATH: case PROP_OBJECT_PATH:
@ -100,10 +101,10 @@ pv_source_output_set_property (GObject *_object,
} }
static gboolean static gboolean
handle_acquire (PvSourceOutput1 *interface, handle_start (PvSourceOutput1 *interface,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
GVariant *arg_properties, GVariant *arg_properties,
gpointer user_data) gpointer user_data)
{ {
PvSourceOutput *output = user_data; PvSourceOutput *output = user_data;
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
@ -111,18 +112,21 @@ handle_acquire (PvSourceOutput1 *interface,
GVariantBuilder props; GVariantBuilder props;
gint fd[2]; 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); socketpair (AF_UNIX, SOCK_STREAM, 0, fd);
priv->socket = g_socket_new_from_fd (fd[0], NULL); priv->socket = g_socket_new_from_fd (fd[0], NULL);
g_object_notify (G_OBJECT (output), "socket"); 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 (); fdlist = g_unix_fd_list_new ();
g_unix_fd_list_append (fdlist, fd[1], NULL); g_unix_fd_list_append (fdlist, fd[1], NULL);
g_dbus_method_invocation_return_value_with_unix_fd_list (invocation, g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
g_variant_new ("(h@a{sv})", 0, g_variant_builder_end (&props)), g_variant_new ("(h@a{sv})",
fdlist); 0,
g_variant_builder_end (&props)),
fdlist);
return TRUE; return TRUE;
} }
@ -139,15 +143,29 @@ stop_transfer (PvSourceOutput *output)
} }
static gboolean static gboolean
handle_release (PvSourceOutput1 *interface, handle_stop (PvSourceOutput1 *interface,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
gpointer user_data) gpointer user_data)
{ {
PvSourceOutput *output = user_data; PvSourceOutput *output = user_data;
stop_transfer (output); 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; return TRUE;
} }
@ -156,7 +174,6 @@ static void
output_register_object (PvSourceOutput *output, const gchar *prefix) output_register_object (PvSourceOutput *output, const gchar *prefix)
{ {
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel; GDBusObjectSkeleton *skel;
gchar *name; gchar *name;
@ -168,25 +185,26 @@ output_register_object (PvSourceOutput *output, const gchar *prefix)
PvSourceOutput1 *iface; PvSourceOutput1 *iface;
iface = pv_source_output1_skeleton_new (); iface = pv_source_output1_skeleton_new ();
g_signal_connect (iface, "handle-acquire", (GCallback) handle_acquire, output); g_signal_connect (iface, "handle-start", (GCallback) handle_start, output);
g_signal_connect (iface, "handle-release", (GCallback) handle_release, 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_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface); g_object_unref (iface);
} }
g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel);
g_free (priv->object_path); 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 static void
output_unregister_object (PvSourceOutput *output) output_unregister_object (PvSourceOutput *output)
{ {
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
PvDaemon *daemon = priv->daemon;
stop_transfer (output); stop_transfer (output);
pv_daemon_unexport (daemon, priv->object_path); g_dbus_object_manager_server_unexport (priv->server_manager, priv->object_path);
} }
static void static void
@ -196,7 +214,7 @@ pv_source_output_finalize (GObject * object)
PvSourceOutputPrivate *priv = output->priv; PvSourceOutputPrivate *priv = output->priv;
output_unregister_object (output); output_unregister_object (output);
g_object_unref (priv->daemon); g_object_unref (priv->server_manager);
g_free (priv->object_path); g_free (priv->object_path);
G_OBJECT_CLASS (pv_source_output_parent_class)->finalize (object); 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; gobject_class->constructed = pv_source_output_constructed;
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_DAEMON, PROP_MANAGER,
g_param_spec_object ("daemon", g_param_spec_object ("manager",
"Daemon", "Manager",
"The daemon", "The manager",
PV_TYPE_DAEMON, G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));

View file

@ -60,6 +60,7 @@ struct _PvSourceOutputClass {
/* normal GObject stuff */ /* normal GObject stuff */
GType pv_source_output_get_type (void); 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); const gchar * pv_source_output_get_object_path (PvSourceOutput *output);
G_END_DECLS G_END_DECLS

View file

@ -19,8 +19,8 @@
#include <gio/gio.h> #include <gio/gio.h>
#include "server/pv-source.h" #include "client/pulsevideo.h"
#include "server/pv-daemon.h" #include "client/pv-source.h"
#include "dbus/org-pulsevideo.h" #include "dbus/org-pulsevideo.h"
@ -30,7 +30,8 @@
struct _PvSourcePrivate struct _PvSourcePrivate
{ {
PvDaemon *daemon; GDBusObjectManagerServer *server_manager;
gchar *object_path; gchar *object_path;
}; };
@ -39,7 +40,7 @@ G_DEFINE_ABSTRACT_TYPE (PvSource, pv_source, G_TYPE_OBJECT);
enum enum
{ {
PROP_0, PROP_0,
PROP_DAEMON, PROP_MANAGER,
PROP_OBJECT_PATH PROP_OBJECT_PATH
}; };
@ -53,8 +54,8 @@ pv_source_get_property (GObject *_object,
PvSourcePrivate *priv = source->priv; PvSourcePrivate *priv = source->priv;
switch (prop_id) { switch (prop_id) {
case PROP_DAEMON: case PROP_MANAGER:
g_value_set_object (value, priv->daemon); g_value_set_object (value, priv->server_manager);
break; break;
case PROP_OBJECT_PATH: case PROP_OBJECT_PATH:
@ -77,8 +78,13 @@ pv_source_set_property (GObject *_object,
PvSourcePrivate *priv = source->priv; PvSourcePrivate *priv = source->priv;
switch (prop_id) { switch (prop_id) {
case PROP_DAEMON: case PROP_MANAGER:
priv->daemon = g_value_dup_object (value); 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; break;
default: default:
@ -90,7 +96,6 @@ static void
source_register_object (PvSource *source) source_register_object (PvSource *source)
{ {
PvSourcePrivate *priv = source->priv; PvSourcePrivate *priv = source->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel; GDBusObjectSkeleton *skel;
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE); 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_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface); g_object_unref (iface);
} }
g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel);
g_free (priv->object_path); 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 static void
source_unregister_object (PvSource *source) source_unregister_object (PvSource *source)
{ {
PvSourcePrivate *priv = source->priv; 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 static void
@ -120,29 +128,21 @@ pv_source_finalize (GObject * object)
PvSource *source = PV_SOURCE (object); PvSource *source = PV_SOURCE (object);
PvSourcePrivate *priv = source->priv; PvSourcePrivate *priv = source->priv;
source_unregister_object (source); if (priv->server_manager) {
g_object_unref (priv->daemon); source_unregister_object (source);
g_object_unref (priv->server_manager);
}
g_free (priv->object_path); g_free (priv->object_path);
G_OBJECT_CLASS (pv_source_parent_class)->finalize (object); 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 * static PvSourceOutput *
default_create_source_output (PvSource *source, GVariant *props, const gchar *prefix) default_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
{ {
PvSourcePrivate *priv = source->priv; 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 static gboolean
@ -163,16 +163,14 @@ pv_source_class_init (PvSourceClass * klass)
gobject_class->finalize = pv_source_finalize; gobject_class->finalize = pv_source_finalize;
gobject_class->set_property = pv_source_set_property; gobject_class->set_property = pv_source_set_property;
gobject_class->get_property = pv_source_get_property; gobject_class->get_property = pv_source_get_property;
gobject_class->constructed = pv_source_constructed;
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
PROP_DAEMON, PROP_MANAGER,
g_param_spec_object ("daemon", g_param_spec_object ("manager",
"Daemon", "Manager",
"The daemon", "The manager",
PV_TYPE_DAEMON, G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
@ -181,7 +179,7 @@ pv_source_class_init (PvSourceClass * klass)
"Object Path", "Object Path",
"The object path", "The object path",
NULL, NULL,
G_PARAM_READABLE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
klass->create_source_output = default_create_source_output; klass->create_source_output = default_create_source_output;
@ -194,6 +192,25 @@ pv_source_init (PvSource * source)
source->priv = PV_SOURCE_GET_PRIVATE (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 * GVariant *
pv_source_get_capabilities (PvSource *source, GVariant *props) pv_source_get_capabilities (PvSource *source, GVariant *props)
{ {

View file

@ -21,6 +21,7 @@
#define __PV_SOURCE_H__ #define __PV_SOURCE_H__
#include <glib-object.h> #include <glib-object.h>
#include <gio/gio.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -28,8 +29,7 @@ typedef struct _PvSource PvSource;
typedef struct _PvSourceClass PvSourceClass; typedef struct _PvSourceClass PvSourceClass;
typedef struct _PvSourcePrivate PvSourcePrivate; typedef struct _PvSourcePrivate PvSourcePrivate;
#include "server/pv-daemon.h" #include "client/pv-source-output.h"
#include "server/pv-source-output.h"
#define PV_TYPE_SOURCE (pv_source_get_type ()) #define PV_TYPE_SOURCE (pv_source_get_type ())
#define PV_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE)) #define PV_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE))
@ -71,7 +71,7 @@ struct _PvSourceClass {
/* normal GObject stuff */ /* normal GObject stuff */
GType pv_source_get_type (void); 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); GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props);

View file

@ -33,7 +33,7 @@ struct _PvStreamPrivate
gchar *target; gchar *target;
PvStreamState state; PvStreamState state;
PvCapture1 *capture; gchar *source_output_sender;
gchar *source_output_path; gchar *source_output_path;
PvSourceOutput1 *source_output; PvSourceOutput1 *source_output;
@ -275,6 +275,14 @@ pv_stream_get_state (PvStream *stream)
return stream->priv->state; return stream->priv->state;
} }
static void
on_request_reconfigure (PvSourceOutput1 *interface,
GVariant *props,
gpointer user_data)
{
g_print ("on request reconfigure\n");
}
static void static void
on_source_output1_proxy (GObject *source_object, on_source_output1_proxy (GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
@ -285,13 +293,21 @@ on_source_output1_proxy (GObject *source_object,
GError *error = NULL; GError *error = NULL;
priv->source_output = pv_source_output1_proxy_new_finish (res, &error); 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); stream_set_state (stream, PV_STREAM_STATE_ERROR);
g_error ("failed to get source output proxy: %s", error->message); g_error ("failed to get source output proxy: %s", error->message);
g_clear_error (&error); g_clear_error (&error);
return; return;
} }
stream_set_state (stream, PV_STREAM_STATE_READY);
} }
static void static void
@ -303,22 +319,31 @@ on_source_output_created (GObject *source_object,
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
PvContext *context = priv->context; PvContext *context = priv->context;
GError *error = NULL; GError *error = NULL;
PvClient1 *proxy;
if (!pv_capture1_call_create_source_output_finish (priv->capture, proxy = PV_CLIENT1 (pv_context_get_client_proxy (priv->context));
&priv->source_output_path, res, &error)) {
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); stream_set_state (stream, PV_STREAM_STATE_ERROR);
g_print ("failed to get connect capture: %s", error->message); g_print ("failed to get connect capture: %s", error->message);
g_clear_error (&error); g_clear_error (&error);
return; 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 static gboolean
@ -326,16 +351,19 @@ create_source_output (PvStream *stream)
{ {
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
GVariantBuilder builder; GVariantBuilder builder;
PvClient1 *proxy;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
pv_capture1_call_create_source_output (priv->capture, proxy = PV_CLIENT1 (pv_context_get_client_proxy (priv->context));
priv->target ? priv->target : "/", /* const gchar *arg_source */
g_variant_builder_end (&builder), /* GVariant *arg_props */ pv_client1_call_create_source_output (proxy,
NULL, /* GCancellable *cancellable */ priv->target ? priv->target : "/", /* const gchar *arg_source */
on_source_output_created, g_variant_builder_end (&builder), /* GVariant *arg_props */
stream); NULL, /* GCancellable *cancellable */
on_source_output_created,
stream);
return TRUE; return TRUE;
} }
@ -348,13 +376,14 @@ on_source_output_removed (GObject *source_object,
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
GError *error = NULL; 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)) { res, &error)) {
stream_set_state (stream, PV_STREAM_STATE_ERROR); stream_set_state (stream, PV_STREAM_STATE_ERROR);
g_print ("failed to disconnect: %s", error->message); g_print ("failed to disconnect: %s", error->message);
g_clear_error (&error); g_clear_error (&error);
return; return;
} }
g_clear_pointer (&priv->source_output_sender, g_free);
g_clear_pointer (&priv->source_output_path, g_free); g_clear_pointer (&priv->source_output_path, g_free);
g_clear_object (&priv->source_output); g_clear_object (&priv->source_output);
} }
@ -364,35 +393,13 @@ remove_source_output (PvStream *stream)
{ {
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
pv_capture1_call_remove_source_output (priv->capture, pv_source_output1_call_remove (priv->source_output,
priv->source_output_path, NULL, /* GCancellable *cancellable */
NULL, /* GCancellable *cancellable */ on_source_output_removed,
on_source_output_removed, stream);
stream);
return TRUE; 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: * pv_stream_connect_capture:
* @stream: a #PvStream * @stream: a #PvStream
@ -420,19 +427,7 @@ pv_stream_connect_capture (PvStream *stream,
stream_set_state (stream, PV_STREAM_STATE_CONNECTING); stream_set_state (stream, PV_STREAM_STATE_CONNECTING);
if (priv->capture == NULL) { return create_source_output (stream);
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);
}
} }
/** /**
@ -452,7 +447,7 @@ pv_stream_disconnect (PvStream *stream)
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE); g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
priv = stream->priv; priv = stream->priv;
g_return_val_if_fail (priv->state >= PV_STREAM_STATE_READY, FALSE); 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; context = priv->context;
g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE); 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); g_print ("got fd %d\n", fd);
priv->socket = g_socket_new_from_fd (fd, &error); priv->socket = g_socket_new_from_fd (fd, &error);
if (priv->socket == NULL) { if (priv->socket == NULL)
stream_set_state (stream, PV_STREAM_STATE_ERROR); goto socket_failed;
g_error ("failed to create socket: %s", error->message);
g_clear_error (&error);
return;
}
switch (priv->mode) { switch (priv->mode) {
case PV_STREAM_MODE_SOCKET: case PV_STREAM_MODE_SOCKET:
@ -554,6 +545,16 @@ handle_socket (PvStream *stream, gint fd)
default: default:
break; 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 static void
@ -573,9 +574,9 @@ unhandle_socket (PvStream *stream)
} }
static void static void
on_stream_acquired (GObject *source_object, on_stream_started (GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
gpointer user_data) gpointer user_data)
{ {
PvStream *stream = user_data; PvStream *stream = user_data;
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
@ -585,13 +586,12 @@ on_stream_acquired (GObject *source_object,
GError *error = NULL; GError *error = NULL;
GVariant *result; GVariant *result;
result = g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (priv->source_output), &out_fd_list, res, &error); result = g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (priv->source_output),
if (result == NULL) { &out_fd_list,
stream_set_state (stream, PV_STREAM_STATE_ERROR); res,
g_error ("failed to acquire: %s", error->message); &error);
g_clear_error (&error); if (result == NULL)
return; goto start_failed;
}
g_variant_get (result, g_variant_get (result,
"(h@a{sv})", "(h@a{sv})",
@ -601,16 +601,32 @@ on_stream_acquired (GObject *source_object,
g_variant_unref (result); g_variant_unref (result);
g_variant_unref (out_props); g_variant_unref (out_props);
if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0) { if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0)
stream_set_state (stream, PV_STREAM_STATE_ERROR); goto fd_failed;
g_error ("failed to get FD: %s", error->message);
g_clear_error (&error);
return;
}
handle_socket (stream, fd); handle_socket (stream, fd);
stream_set_state (stream, PV_STREAM_STATE_STREAMING); 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_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello")); g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
pv_source_output1_call_acquire (priv->source_output, pv_source_output1_call_start (priv->source_output,
g_variant_builder_end (&builder), /* GVariant *arg_properties */ g_variant_builder_end (&builder), /* GVariant *arg_properties */
NULL, /* GCancellable *cancellable */ NULL, /* GCancellable *cancellable */
on_stream_acquired, on_stream_started,
stream); stream);
} }
return TRUE; return TRUE;
} }
static void static void
on_stream_released (GObject *source_object, on_stream_stopped (GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
gpointer user_data) gpointer user_data)
{ {
PvStream *stream = user_data; PvStream *stream = user_data;
PvStreamPrivate *priv = stream->priv; PvStreamPrivate *priv = stream->priv;
GError *error = NULL; GError *error = NULL;
if (!pv_source_output1_call_release_finish (priv->source_output, if (!pv_source_output1_call_stop_finish (priv->source_output,
res, &error)) { 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); stream_set_state (stream, PV_STREAM_STATE_ERROR);
g_error ("failed to release: %s", error->message); g_error ("failed to release: %s", error->message);
g_clear_error (&error); g_clear_error (&error);
return; return;
} }
unhandle_socket (stream);
stream_set_state (stream, PV_STREAM_STATE_READY);
} }
/** /**
@ -696,10 +720,10 @@ pv_stream_stop (PvStream *stream)
priv = stream->priv; priv = stream->priv;
g_return_val_if_fail (priv->state == PV_STREAM_STATE_STREAMING, FALSE); g_return_val_if_fail (priv->state == PV_STREAM_STATE_STREAMING, FALSE);
pv_source_output1_call_release (priv->source_output, pv_source_output1_call_stop (priv->source_output,
NULL, /* GCancellable *cancellable */ NULL, /* GCancellable *cancellable */
on_stream_released, on_stream_stopped,
stream); stream);
return TRUE; return TRUE;
} }

View file

@ -17,36 +17,69 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
static void #include <gio/gio.h>
notify_subscription (PvContext *context,
GDBusObject *object, #include "client/pulsevideo.h"
GDBusInterface *interface, #include "client/pv-enumtypes.h"
PvSubscriptionEvent event)
#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 (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_CLIENT) {
if ((interface == NULL && pv_object_peek_client1 (PV_OBJECT (object))) || if ((interface == NULL && pv_object_peek_client1 (PV_OBJECT (object))) ||
PV_IS_CLIENT1_PROXY (interface)) 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)); 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 (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) {
if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) || if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) ||
PV_IS_SOURCE1_PROXY (interface)) 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)); PV_SUBSCRIPTION_FLAGS_SOURCE, g_dbus_object_get_object_path (object));
} }
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT) { if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT) {
if ((interface == NULL && pv_object_peek_source_output1 (PV_OBJECT (object))) || if ((interface == NULL && pv_object_peek_source_output1 (PV_OBJECT (object))) ||
PV_IS_SOURCE_OUTPUT1_PROXY (interface)) 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)); 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, GDBusInterface *interface,
gpointer user_data) gpointer user_data)
{ {
PvContext *context = user_data; PvSubscribe *subscribe = user_data;
notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_NEW); notify_subscription (subscribe, object, interface, PV_SUBSCRIPTION_EVENT_NEW);
} }
static void static void
@ -67,8 +100,8 @@ on_client_manager_interface_removed (GDBusObjectManager *manager,
GDBusInterface *interface, GDBusInterface *interface,
gpointer user_data) gpointer user_data)
{ {
PvContext *context = user_data; PvSubscribe *subscribe = user_data;
notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_REMOVE); notify_subscription (subscribe, object, interface, PV_SUBSCRIPTION_EVENT_REMOVE);
} }
static void static void
@ -76,8 +109,8 @@ on_client_manager_object_added (GDBusObjectManager *manager,
GDBusObject *object, GDBusObject *object,
gpointer user_data) gpointer user_data)
{ {
PvContext *context = user_data; PvSubscribe *subscribe = user_data;
notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_NEW); notify_subscription (subscribe, object, NULL, PV_SUBSCRIPTION_EVENT_NEW);
} }
static void static void
@ -85,8 +118,8 @@ on_client_manager_object_removed (GDBusObjectManager *manager,
GDBusObject *object, GDBusObject *object,
gpointer user_data) gpointer user_data)
{ {
PvContext *context = user_data; PvSubscribe *subscribe = user_data;
notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_REMOVE); notify_subscription (subscribe, object, NULL, PV_SUBSCRIPTION_EVENT_REMOVE);
} }
static void static void
@ -113,22 +146,22 @@ on_client_manager_signal (GDBusObjectManagerClient *manager,
} }
static void 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", 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", 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", 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", 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", 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", 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 static void
@ -136,15 +169,15 @@ on_client_manager_ready (GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
gpointer user_data) gpointer user_data)
{ {
PvContext *context = user_data; PvSubscribe *subscribe = user_data;
PvContextPrivate *priv = context->priv; PvSubscribePrivate *priv = subscribe->priv;
GError *error = NULL; GError *error = NULL;
priv->client_manager = pv_object_manager_client_new_finish (res, &error); priv->client_manager = pv_object_manager_client_new_finish (res, &error);
if (priv->client_manager == NULL) if (priv->client_manager == NULL)
goto manager_error; goto manager_error;
connect_client_signals (context); connect_client_signals (subscribe);
return; return;
@ -158,26 +191,196 @@ manager_error:
} }
static void static void
install_subscription (PvContext *context) install_subscription (PvSubscribe *subscribe)
{ {
PvContextPrivate *priv = context->priv; PvSubscribePrivate *priv = subscribe->priv;
if (priv->client_manager) pv_object_manager_client_new (priv->connection,
return;
pv_object_manager_client_new (pv_context_get_connection (context),
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
PV_DBUS_SERVICE, priv->service,
PV_DBUS_OBJECT_PREFIX, PV_DBUS_OBJECT_PREFIX,
NULL, NULL,
on_client_manager_ready, on_client_manager_ready,
context); subscribe);
} }
static void static void
uninstall_subscription (PvContext *context) uninstall_subscription (PvSubscribe *subscribe)
{ {
PvContextPrivate *priv = context->priv; PvSubscribePrivate *priv = subscribe->priv;
g_clear_object (&priv->client_manager); 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);
}

View file

@ -24,11 +24,23 @@
G_BEGIN_DECLS 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 { typedef enum {
PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0), PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0),
PV_SUBSCRIPTION_FLAGS_DEVICE = (1 << 1), PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 1),
PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2), PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 2),
PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3),
PV_SUBSCRIPTION_FLAGS_ALL = 0xf PV_SUBSCRIPTION_FLAGS_ALL = 0xf
} PvSubscriptionFlags; } PvSubscriptionFlags;
@ -39,6 +51,31 @@ typedef enum {
PV_SUBSCRIPTION_EVENT_REMOVE = 2, PV_SUBSCRIPTION_EVENT_REMOVE = 2,
} PvSubscriptionEvent; } 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 G_END_DECLS
#endif /* __PV_SUBSCRIBE_H__ */ #endif /* __PV_SUBSCRIBE_H__ */

View file

@ -17,26 +17,17 @@
<interface name='org.pulsevideo.Client1'> <interface name='org.pulsevideo.Client1'>
<property name='Name' type='s' access='read' /> <property name='Name' type='s' access='read' />
<property name='Properties' type='a{sv}' access='read' /> <property name='Properties' type='a{sv}' access='read' />
</interface>
<interface name='org.pulsevideo.Capture1'>
<method name='CreateSourceOutput'> <method name='CreateSourceOutput'>
<arg type='o' name='source' direction='in'/> <arg type='o' name='source' direction='in'/>
<arg type='a{sv}' name='props' direction='in'/> <arg type='a{sv}' name='props' direction='in'/>
<arg type='s' name='sender' direction='out'/>
<arg type='o' name='output' direction='out'/> <arg type='o' name='output' direction='out'/>
</method> </method>
<method name='RemoveSourceOutput'> <method name='RegisterSource'>
<arg type='o' name='output' direction='in'/> <arg type='o' name='source' direction='in'/>
</method> </method>
</interface> <method name='UnregisterSource'>
<arg type='o' name='source' direction='in'/>
<interface name='org.pulsevideo.Manager1'>
<method name='AddProvider'>
<arg type='o' name='provider' direction='in'/>
<arg type='a{sv}' name='properties' direction='in'/>
</method>
<method name='RemoveProvider'>
<arg type='o' name='provider' direction='in'/>
</method> </method>
</interface> </interface>
@ -52,11 +43,6 @@
</method> </method>
</interface> </interface>
<interface name='org.pulsevideo.Device1'>
<property name='Name' type='s' access='read' />
<property name='Properties' type='a{sv}' access='read' />
</interface>
<interface name='org.pulsevideo.Source1'> <interface name='org.pulsevideo.Source1'>
<property name='Name' type='s' access='read' /> <property name='Name' type='s' access='read' />
<property name='Suspended' type='b' access='read' /> <property name='Suspended' type='b' access='read' />
@ -65,16 +51,25 @@
<arg type='a{sv}' name='props' direction='in'/> <arg type='a{sv}' name='props' direction='in'/>
<arg type='aa{sv}' name='caps' direction='out'/> <arg type='aa{sv}' name='caps' direction='out'/>
</method> </method>
<method name='CreateSourceOutput'>
<arg type='o' name='source' direction='in'/>
<arg type='a{sv}' name='props' direction='in'/>
<arg type='o' name='output' direction='out'/>
</method>
</interface> </interface>
<interface name='org.pulsevideo.SourceOutput1'> <interface name='org.pulsevideo.SourceOutput1'>
<method name='Acquire'> <property name='Source' type='o' access='read' />
<method name='Start'>
<arg type='a{sv}' name='props' direction='in'/> <arg type='a{sv}' name='props' direction='in'/>
<arg type='h' name='fd' direction='out'/> <arg type='h' name='fd' direction='out'/>
<arg type='a{sv}' name='props' direction='out'/> <arg type='a{sv}' name='props' direction='out'/>
</method> </method>
<method name='Release'> <signal name='RequestReconfigure'>
</method> <arg type='a{sv}' name='props' direction='in'/>
</signal>
<method name='Stop'/>
<method name='Remove'/>
<!-- <!--
<method name='Start'> <method name='Start'>

View file

@ -124,7 +124,7 @@ pv_v4l2_source_init (PvV4l2Source * source)
} }
PvSource * PvSource *
pv_v4l2_source_new (PvDaemon *daemon) pv_v4l2_source_new (void)
{ {
return g_object_new (PV_TYPE_V4L2_SOURCE, "daemon", daemon, NULL); return g_object_new (PV_TYPE_V4L2_SOURCE, NULL);
} }

View file

@ -21,7 +21,8 @@
#define __PV_V4L2_SOURCE_H__ #define __PV_V4L2_SOURCE_H__
#include <glib-object.h> #include <glib-object.h>
#include "server/pv-source.h"
#include <client/pulsevideo.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -50,7 +51,7 @@ struct _PvV4l2SourceClass {
GType pv_v4l2_source_get_type (void); GType pv_v4l2_source_get_type (void);
PvSource * pv_v4l2_source_new (PvDaemon *daemon); PvSource * pv_v4l2_source_new (void);
G_END_DECLS G_END_DECLS

View file

@ -17,10 +17,13 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include "server/pv-client.h" #include "client/pulsevideo.h"
#include "server/pv-source.h"
#include "server/pv-source-output.h"
#include "client/pv-enumtypes.h" #include "client/pv-enumtypes.h"
#include "client/pv-source.h"
#include "client/pv-source-output.h"
#include "server/pv-client.h"
#include "dbus/org-pulsevideo.h" #include "dbus/org-pulsevideo.h"
@ -95,7 +98,7 @@ pv_client_set_property (GObject *_object,
} }
static gboolean static gboolean
handle_create_source_output (PvCapture1 *interface, handle_create_source_output (PvClient1 *interface,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
const gchar *arg_source, const gchar *arg_source,
GVariant *arg_properties, GVariant *arg_properties,
@ -114,28 +117,8 @@ handle_create_source_output (PvCapture1 *interface,
object_path = pv_source_output_get_object_path (output); object_path = pv_source_output_get_object_path (output);
g_hash_table_insert (priv->source_outputs, g_strdup (object_path), output); g_hash_table_insert (priv->source_outputs, g_strdup (object_path), output);
pv_capture1_complete_create_source_output (interface, invocation, object_path);
return TRUE; pv_client1_complete_create_source_output (interface, invocation, PV_DBUS_SERVICE, object_path);
}
static gboolean
handle_remove_source_output (PvCapture1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_output,
gpointer user_data)
{
PvClient *client = user_data;
PvClientPrivate *priv = client->priv;
PvSourceOutput *output;
output = g_hash_table_lookup (priv->source_outputs, arg_output);
if (output) {
pv_source_release_source_output (priv->source, output);
g_hash_table_remove (priv->source_outputs, arg_output);
}
pv_capture1_complete_remove_source_output (interface, invocation);
return TRUE; return TRUE;
} }
@ -157,15 +140,7 @@ client_register_object (PvClient *client, const gchar *prefix)
iface = pv_client1_skeleton_new (); iface = pv_client1_skeleton_new ();
pv_client1_set_name (iface, "poppy"); pv_client1_set_name (iface, "poppy");
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface);
}
{
PvCapture1 *iface;
iface = pv_capture1_skeleton_new ();
g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, client); g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, client);
g_signal_connect (iface, "handle-remove-source-output", (GCallback) handle_remove_source_output, client);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface); g_object_unref (iface);
} }

View file

@ -45,6 +45,7 @@ typedef struct {
guint id; guint id;
GHashTable *clients; GHashTable *clients;
PvSubscribe *subscribe;
} SenderData; } SenderData;
static void static void
@ -72,6 +73,15 @@ client_name_vanished_handler (GDBusConnection *connection,
g_free (data); g_free (data);
} }
static void
on_subscription_event (PvSubscribe *subscribe,
PvSubscriptionEvent event,
PvSubscriptionFlags flags,
const gchar *object_path)
{
g_print ("got event %d %d %s\n", event, flags, object_path);
}
static SenderData * static SenderData *
sender_data_new (PvDaemon *daemon, const gchar *sender) sender_data_new (PvDaemon *daemon, const gchar *sender)
{ {
@ -91,6 +101,16 @@ sender_data_new (PvDaemon *daemon, const gchar *sender)
data, data,
NULL); NULL);
data->subscribe = pv_subscribe_new ();
g_object_set (data->subscribe, "service", sender,
"subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE,
"connection", priv->connection,
NULL);
g_signal_connect (data->subscribe,
"subscription-event",
(GCallback) on_subscription_event,
data);
g_hash_table_insert (priv->senders, data->sender, data); g_hash_table_insert (priv->senders, data->sender, data);
return data; return data;
@ -150,34 +170,6 @@ handle_disconnect_client (PvDaemon1 *interface,
return TRUE; return TRUE;
} }
static gboolean
handle_add_provider (PvManager1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_provider,
GVariant *arg_properties,
gpointer user_data)
{
g_print ("add provider\n");
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pulseaudio.Error.NotImplemented",
"Operation add not yet implemented");
return TRUE;
}
static gboolean
handle_remove_provider (PvManager1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_provider,
gpointer user_data)
{
g_print ("remove provider\n");
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pulseaudio.Error.NotImplemented",
"Operation remove not yet implemented");
return TRUE;
}
static void static void
export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager) export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager)
{ {
@ -197,16 +189,6 @@ export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager)
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface)); g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface); g_object_unref (iface);
} }
{
PvManager1 *iface;
iface = pv_manager1_skeleton_new ();
g_signal_connect (iface, "handle-add-provider", (GCallback) handle_add_provider, daemon);
g_signal_connect (iface, "handle-remove-provider", (GCallback) handle_remove_provider, daemon);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface);
}
g_dbus_object_manager_server_export (manager, skel); g_dbus_object_manager_server_export (manager, skel);
g_object_unref (skel); g_object_unref (skel);
} }
@ -315,7 +297,8 @@ pv_daemon_get_source (PvDaemon *daemon, const gchar *name)
priv = daemon->priv; priv = daemon->priv;
if (priv->source == NULL) { if (priv->source == NULL) {
priv->source = pv_v4l2_source_new (daemon); priv->source = pv_v4l2_source_new ();
pv_source_set_manager (priv->source, priv->server_manager);
} }
return priv->source; return priv->source;
} }

View file

@ -38,13 +38,7 @@ typedef struct _PvDaemon PvDaemon;
typedef struct _PvDaemonClass PvDaemonClass; typedef struct _PvDaemonClass PvDaemonClass;
typedef struct _PvDaemonPrivate PvDaemonPrivate; typedef struct _PvDaemonPrivate PvDaemonPrivate;
#include "server/pv-source.h" #include "client/pv-source.h"
#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"
/** /**
* PvDaemon: * PvDaemon:

View file

@ -46,9 +46,16 @@ on_state_notify (GObject *gobject,
g_main_loop_quit (loop); g_main_loop_quit (loop);
break; break;
case PV_CONTEXT_STATE_READY: case PV_CONTEXT_STATE_READY:
g_object_set (c, "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, NULL); {
g_signal_connect (c, "subscription-event", (GCallback) subscription_cb, NULL); PvSubscribe *subscribe;
subscribe = pv_subscribe_new ();
g_object_set (subscribe, "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, NULL);
g_signal_connect (subscribe, "subscription-event", (GCallback) subscription_cb, NULL);
pv_context_set_subscribe (c, subscribe);
break; break;
}
default: default:
break; break;
} }

75
src/tests/test-v4l2.c Normal file
View file

@ -0,0 +1,75 @@
/* Pulsevideo
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <gst/gst.h>
#include <gio/gio.h>
#include <client/pulsevideo.h>
#include <modules/v4l2/pv-v4l2-source.h>
static GMainLoop *loop;
static void
on_state_notify (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
PvContextState state;
PvContext *c = user_data;
g_object_get (gobject, "state", &state, NULL);
g_print ("got context state %d\n", state);
switch (state) {
case PV_CONTEXT_STATE_ERROR:
g_main_loop_quit (loop);
break;
case PV_CONTEXT_STATE_READY:
{
PvSource *source;
source = pv_v4l2_source_new ();
pv_context_register_source (c, source);
break;
}
default:
break;
}
}
gint
main (gint argc, gchar *argv[])
{
PvContext *c;
pv_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
c = pv_context_new ("test-client", NULL);
g_signal_connect (c, "notify::state", (GCallback) on_state_notify, c);
pv_context_connect(c, PV_CONTEXT_FLAGS_NONE);
g_main_loop_run (loop);
g_object_unref (c);
return 0;
}