handle remote and local sources better

Track remote and local sources separately and make SourceProvider1
interfaces for remote objects so that we get the subscription right.

Move disconnect from the Manager1 to Client1 interface and implement
in the context.
This commit is contained in:
Wim Taymans 2015-04-20 17:24:58 +02:00
parent 93c246c4ce
commit 09de2d3db9
12 changed files with 184 additions and 70 deletions

View file

@ -455,6 +455,49 @@ pv_context_connect (PvContext *context, PvContextFlags flags)
return TRUE;
}
static void
on_client_disconnected (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PvContext *context = user_data;
PvContextPrivate *priv = context->priv;
GError *error = NULL;
if (!pv_client1_call_disconnect_finish (priv->client, res, &error)) {
context_set_state (context, PV_CONTEXT_STATE_ERROR);
g_error ("failed to disconnect client: %s", error->message);
g_clear_error (&error);
return;
}
context_set_state (context, PV_CONTEXT_STATE_UNCONNECTED);
}
/**
* pv_context_disconnect:
* @context: a #PvContext
*
* Disonnect from the daemon.
*
* Returns: %TRUE on success.
*/
gboolean
pv_context_disconnect (PvContext *context)
{
PvContextPrivate *priv;
g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE);
priv = context->priv;
g_return_val_if_fail (priv->client != NULL, FALSE);
pv_client1_call_disconnect (priv->client,
NULL, /* GCancellable *cancellable */
on_client_disconnected,
context);
return TRUE;
}
gboolean
pv_context_register_source (PvContext *context, PvSource *source)
{

View file

@ -103,6 +103,7 @@ PvContext * pv_context_new (const gchar *name, GVariant
gboolean pv_context_set_subscribe (PvContext *context, PvSubscribe *subscribe);
gboolean pv_context_connect (PvContext *context, PvContextFlags flags);
gboolean pv_context_disconnect (PvContext *context);
gboolean pv_context_register_source (PvContext *context, PvSource *source);
gboolean pv_context_unregister_source (PvContext *context, PvSource *source);

View file

@ -174,11 +174,11 @@ static void
output_register_object (PvSourceOutput *output, const gchar *prefix)
{
PvSourceOutputPrivate *priv = output->priv;
GDBusObjectSkeleton *skel;
PvObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/output", prefix);
skel = g_dbus_object_skeleton_new (name);
skel = pv_object_skeleton_new (name);
g_free (name);
{
@ -188,10 +188,10 @@ output_register_object (PvSourceOutput *output, const gchar *prefix)
g_signal_connect (iface, "handle-start", (GCallback) handle_start, output);
g_signal_connect (iface, "handle-stop", (GCallback) handle_stop, output);
g_signal_connect (iface, "handle-remove", (GCallback) handle_remove, output);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
pv_object_skeleton_set_source_output1 (skel, iface);
g_object_unref (iface);
}
g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel);
g_dbus_object_manager_server_export_uniquely (priv->server_manager, G_DBUS_OBJECT_SKELETON (skel));
g_free (priv->object_path);
priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));

View file

@ -118,18 +118,18 @@ static void
source_register_object (PvSource *source)
{
PvSourcePrivate *priv = source->priv;
GDBusObjectSkeleton *skel;
PvObjectSkeleton *skel;
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE);
skel = pv_object_skeleton_new (PV_DBUS_OBJECT_SOURCE);
{
PvSource1 *iface;
iface = pv_source1_skeleton_new ();
g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, source);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
pv_object_skeleton_set_source1 (skel, iface);
g_object_unref (iface);
}
g_dbus_object_manager_server_export_uniquely (priv->server_manager, skel);
g_dbus_object_manager_server_export_uniquely (priv->server_manager, G_DBUS_OBJECT_SKELETON (skel));
g_free (priv->object_path);
priv->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));

View file

@ -70,6 +70,12 @@ notify_subscription (PvSubscribe *subscribe,
g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
PV_SUBSCRIPTION_FLAGS_CLIENT, object);
}
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER) {
if ((interface == NULL && pv_object_peek_source_provider1 (PV_OBJECT (object))) ||
PV_IS_SOURCE_PROVIDER1_PROXY (interface))
g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER, object);
}
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) {
if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) ||
PV_IS_SOURCE1_PROXY (interface))
@ -172,11 +178,18 @@ on_client_manager_ready (GObject *source_object,
PvSubscribe *subscribe = user_data;
PvSubscribePrivate *priv = subscribe->priv;
GError *error = NULL;
GList *objects, *walk;
priv->client_manager = pv_object_manager_client_new_finish (res, &error);
if (priv->client_manager == NULL)
goto manager_error;
objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->client_manager));
for (walk = objects; walk ; walk = g_list_next (walk)) {
on_client_manager_object_added (G_DBUS_OBJECT_MANAGER (priv->client_manager),
walk->data,
subscribe);
}
connect_client_signals (subscribe);
return;

View file

@ -38,12 +38,13 @@ typedef struct _PvSubscribeClass PvSubscribeClass;
typedef struct _PvSubscribePrivate PvSubscribePrivate;
typedef enum {
PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0),
PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 1),
PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 2),
PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0),
PV_SUBSCRIPTION_FLAGS_SOURCE_PROVIDER = (1 << 1),
PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2),
PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3),
} PvSubscriptionFlags;
#define PV_SUBSCRIPTION_FLAGS_ALL 0x3
#define PV_SUBSCRIPTION_FLAGS_ALL 0xf
typedef enum {
PV_SUBSCRIPTION_EVENT_NEW = 0,

View file

@ -22,18 +22,23 @@
#include <client/pulsevideo.h>
#include <server/pv-daemon.h>
#include <modules/v4l2/pv-v4l2-source.h>
gint
main (gint argc, gchar *argv[])
{
PvDaemon *daemon;
GMainLoop *loop;
PvSource *source;
pv_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
daemon = pv_daemon_new ();
source = pv_v4l2_source_new();
pv_daemon_add_source (daemon, source);
pv_daemon_start (daemon);
g_main_loop_run (loop);

View file

@ -9,9 +9,6 @@
<arg type='a{sv}' name='properties' direction='in'/>
<arg type='o' name='client' direction='out'/>
</method>
<method name='DisconnectClient'>
<arg type='o' name='client' direction='in'/>
</method>
</interface>
<interface name='org.pulsevideo.Client1'>
@ -29,6 +26,8 @@
<method name='UnregisterSource'>
<arg type='o' name='source' direction='in'/>
</method>
<method name='Disconnect'>
</method>
</interface>
<interface name='org.pulsevideo.Introspect1'>

View file

@ -180,20 +180,20 @@ client_register_object (PvClient *client, const gchar *prefix)
{
PvClientPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
PvObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/client", prefix);
skel = g_dbus_object_skeleton_new (name);
skel = pv_object_skeleton_new (name);
g_free (name);
priv->client1 = pv_client1_skeleton_new ();
pv_client1_set_name (priv->client1, "poppy");
g_signal_connect (priv->client1, "handle-create-source-output", (GCallback) handle_create_source_output, client);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (priv->client1));
pv_object_skeleton_set_client1 (skel, priv->client1);
g_free (priv->object_path);
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
priv->object_path = pv_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
}
static void

View file

@ -35,6 +35,7 @@ struct _PvDaemonPrivate
guint id;
GDBusConnection *connection;
GDBusObjectManagerServer *server_manager;
PvSubscribe *subscribe;
GHashTable *senders;
GList *sources;
@ -52,33 +53,32 @@ typedef struct {
} SenderData;
static void
on_subscription_event (PvSubscribe *subscribe,
PvSubscriptionEvent event,
PvSubscriptionFlags flags,
GDBusObjectProxy *object,
gpointer user_data)
on_server_subscription_event (PvSubscribe *subscribe,
PvSubscriptionEvent event,
PvSubscriptionFlags flags,
GDBusObjectProxy *object,
gpointer user_data)
{
SenderData *data = user_data;
PvDaemon *daemon = data->daemon;
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
const gchar *object_path;
PvSource1 *source1;
object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
g_print ("got event %d %d %s.%s\n", event, flags, data->sender, object_path);
gchar *service;
if (flags != PV_SUBSCRIPTION_FLAGS_SOURCE)
return;
object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
g_object_get (subscribe, "service", &service, NULL);
g_print ("got event %d %d %s.%s\n", event, flags, service, object_path);
source1 = pv_object_peek_source1 (PV_OBJECT (object));
switch (event) {
case PV_SUBSCRIPTION_EVENT_NEW:
{
g_object_set_data (G_OBJECT (source1), "org.pulsevideo.name", data->sender);
g_hash_table_insert (data->sources, g_strdup (object_path), source1);
g_object_set_data (G_OBJECT (source1), "org.pulsevideo.name", service);
priv->sources = g_list_prepend (priv->sources, source1);
break;
}
@ -89,12 +89,49 @@ on_subscription_event (PvSubscribe *subscribe,
case PV_SUBSCRIPTION_EVENT_REMOVE:
{
priv->sources = g_list_remove (priv->sources, source1);
break;
}
}
}
static void
on_sender_subscription_event (PvSubscribe *subscribe,
PvSubscriptionEvent event,
PvSubscriptionFlags flags,
GDBusObjectProxy *object,
gpointer user_data)
{
SenderData *data = user_data;
PvDaemon *daemon = data->daemon;
const gchar *object_path;
on_server_subscription_event (subscribe, event, flags, object, daemon);
object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
switch (event) {
case PV_SUBSCRIPTION_EVENT_NEW:
{
PvSourceProvider *provider;
provider = pv_source_provider_new (daemon, PV_DBUS_OBJECT_PREFIX, data->sender,
object_path);
g_hash_table_insert (data->sources, g_strdup (object_path), provider);
break;
}
case PV_SUBSCRIPTION_EVENT_CHANGE:
break;
case PV_SUBSCRIPTION_EVENT_REMOVE:
{
g_hash_table_remove (data->sources, object_path);
break;
}
}
}
static void
client_name_appeared_handler (GDBusConnection *connection,
const gchar *name,
@ -113,7 +150,7 @@ client_name_appeared_handler (GDBusConnection *connection,
g_signal_connect (data->subscribe,
"subscription-event",
(GCallback) on_subscription_event,
(GCallback) on_sender_subscription_event,
data);
}
@ -192,50 +229,25 @@ handle_connect_client (PvDaemon1 *interface,
return TRUE;
}
static gboolean
handle_disconnect_client (PvDaemon1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_client,
gpointer user_data)
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
const gchar *sender;
SenderData *data;
sender = g_dbus_method_invocation_get_sender (invocation);
g_print ("disconnect client %s\n", sender);
data = g_hash_table_lookup (priv->senders, sender);
if (data != NULL) {
g_hash_table_remove (data->clients, arg_client);
}
pv_daemon1_complete_disconnect_client (interface, invocation);
return TRUE;
}
static void
export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager)
{
GDBusObjectSkeleton *skel;
PvObjectSkeleton *skel;
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SERVER);
skel = pv_object_skeleton_new (PV_DBUS_OBJECT_SERVER);
{
PvDaemon1 *iface;
iface = pv_daemon1_skeleton_new ();
g_signal_connect (iface, "handle-connect-client", (GCallback) handle_connect_client, daemon);
g_signal_connect (iface, "handle-disconnect-client", (GCallback) handle_disconnect_client, daemon);
pv_daemon1_set_user_name (iface, g_get_user_name ());
pv_daemon1_set_host_name (iface, g_get_host_name ());
pv_daemon1_set_version (iface, PACKAGE_VERSION);
pv_daemon1_set_name (iface, PACKAGE_NAME);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
pv_object_skeleton_set_daemon1 (skel, iface);
g_object_unref (iface);
}
g_dbus_object_manager_server_export (manager, skel);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
}
@ -257,10 +269,16 @@ name_acquired_handler (GDBusConnection *connection,
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager;
GDBusObjectManagerServer *manager = priv->server_manager;
g_object_set (priv->subscribe, "service", PV_DBUS_SERVICE,
"subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE,
"connection", connection,
NULL);
priv->server_manager = manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX);
export_server_object (daemon, manager);
g_dbus_object_manager_server_set_connection (manager, connection);
}
@ -273,8 +291,10 @@ name_lost_handler (GDBusConnection *connection,
PvDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager = priv->server_manager;
g_object_set (priv->subscribe, "connection", connection, NULL);
g_dbus_object_manager_server_unexport (manager, PV_DBUS_OBJECT_SERVER);
g_clear_object (&priv->server_manager);
g_dbus_object_manager_server_set_connection (manager, connection);
}
PvDaemon *
@ -334,6 +354,27 @@ pv_daemon_unexport (PvDaemon *daemon, const gchar *object_path)
g_dbus_object_manager_server_unexport (daemon->priv->server_manager, object_path);
}
void
pv_daemon_add_source (PvDaemon *daemon, PvSource *source)
{
PvDaemonPrivate *priv;
g_return_if_fail (PV_IS_DAEMON (daemon));
g_return_if_fail (PV_IS_SOURCE (source));
priv = daemon->priv;
pv_source_set_manager (source, priv->server_manager);
}
void
pv_daemon_remove_source (PvDaemon *daemon, PvSource *source)
{
g_return_if_fail (PV_IS_DAEMON (daemon));
g_return_if_fail (PV_IS_SOURCE (source));
pv_source_set_manager (source, NULL);
}
PvSource1 *
pv_daemon_get_source (PvDaemon *daemon, const gchar *name)
{
@ -359,6 +400,7 @@ pv_daemon_finalize (GObject * object)
PvDaemon *daemon = PV_DAEMON_CAST (object);
PvDaemonPrivate *priv = daemon->priv;
g_clear_object (&priv->server_manager);
g_hash_table_unref (priv->senders);
pv_daemon_stop (daemon);
@ -381,5 +423,12 @@ pv_daemon_init (PvDaemon * daemon)
PvDaemonPrivate *priv = daemon->priv = PV_DAEMON_GET_PRIVATE (daemon);
priv->senders = g_hash_table_new (g_str_hash, g_str_equal);
priv->server_manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX);
priv->subscribe = pv_subscribe_new ();
g_signal_connect (priv->subscribe,
"subscription-event",
(GCallback) on_server_subscription_event,
daemon);
}

View file

@ -74,6 +74,9 @@ void pv_daemon_stop (PvDaemon *daemon);
gchar * pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel);
void pv_daemon_unexport (PvDaemon *daemon, const gchar *name);
void pv_daemon_add_source (PvDaemon *daemon, PvSource *source);
void pv_daemon_remove_source (PvDaemon *daemon, PvSource *source);
PvSource1 * pv_daemon_get_source (PvDaemon *daemon, const gchar *name);
G_END_DECLS

View file

@ -113,11 +113,11 @@ source_provider_register_object (PvSourceProvider *client, const gchar *prefix)
{
PvSourceProviderPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
PvObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/source", prefix);
skel = g_dbus_object_skeleton_new (name);
skel = pv_object_skeleton_new (name);
g_free (name);
{
@ -126,12 +126,12 @@ source_provider_register_object (PvSourceProvider *client, const gchar *prefix)
iface = pv_source_provider1_skeleton_new ();
g_object_set (iface, "name", priv->name, NULL);
g_object_set (iface, "path", priv->path, NULL);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
pv_object_skeleton_set_source_provider1 (skel, iface);
g_object_unref (iface);
}
g_free (priv->object_path);
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
priv->object_path = pv_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
}
static void