support remote sources

Watch client object-manager and keep the remote source object in a
SourceProvider object. Keep a list of all sources in the daemon.

Handle the Client CreateSourceOutput by calling the method on a
registered source in the daemon.

Pass GDBusObject in the subscription signal so that we can get to more
details.
This commit is contained in:
Wim Taymans 2015-04-20 15:03:14 +02:00
parent 752494621c
commit 93c246c4ce
14 changed files with 531 additions and 70 deletions

View file

@ -32,7 +32,7 @@ struct _PvClientPrivate
PvDaemon *daemon;
gchar *object_path;
PvSource *source;
PvClient1 *client1;
GHashTable *source_outputs;
};
@ -97,6 +97,46 @@ pv_client_set_property (GObject *_object,
}
}
typedef struct {
PvClient *client;
GDBusMethodInvocation *invocation;
} CreateData;
static void
on_source_output_created (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
CreateData *data = user_data;
PvClient *client = data->client;
PvClientPrivate *priv = client->priv;
PvSource1 *source1 = PV_SOURCE1 (source_object);
GDBusMethodInvocation *invocation = data->invocation;
GError *error = NULL;
gchar *object_path, *name;
if (!pv_source1_call_create_source_output_finish (source1, &object_path, res, &error))
goto create_failed;
name = g_object_get_data (G_OBJECT (source1), "org.pulsevideo.name");
pv_client1_complete_create_source_output (priv->client1, invocation, name, object_path);
g_free (name);
g_free (data);
return;
/* ERRORS */
create_failed:
{
g_print ("failed to get connect capture: %s", error->message);
g_clear_error (&error);
g_free (data);
return;
}
}
static gboolean
handle_create_source_output (PvClient1 *interface,
GDBusMethodInvocation *invocation,
@ -107,18 +147,30 @@ handle_create_source_output (PvClient1 *interface,
PvClient *client = user_data;
PvClientPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
PvSource *source;
PvSourceOutput *output;
const gchar *object_path;
PvSource1 *source1;
GVariantBuilder builder;
CreateData *data;
source = pv_daemon_get_source (daemon, arg_source);
source1 = pv_daemon_get_source (daemon, arg_source);
if (source1 == NULL) {
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pulsevideo.NotFound",
"No source found");
return TRUE;
}
output = pv_source_create_source_output (source, NULL, priv->object_path);
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
object_path = pv_source_output_get_object_path (output);
g_hash_table_insert (priv->source_outputs, g_strdup (object_path), output);
data = g_new0 (CreateData, 1);
data->client = client;
data->invocation = invocation;
pv_client1_complete_create_source_output (interface, invocation, PV_DBUS_SERVICE, object_path);
pv_source1_call_create_source_output (source1,
g_variant_builder_end (&builder),
NULL,
on_source_output_created,
data);
return TRUE;
}
@ -135,15 +187,10 @@ client_register_object (PvClient *client, const gchar *prefix)
skel = g_dbus_object_skeleton_new (name);
g_free (name);
{
PvClient1 *iface;
iface = pv_client1_skeleton_new ();
pv_client1_set_name (iface, "poppy");
g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, client);
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
g_object_unref (iface);
}
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));
g_free (priv->object_path);
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
@ -156,7 +203,7 @@ client_unregister_object (PvClient *client)
PvDaemon *daemon = priv->daemon;
g_hash_table_unref (priv->source_outputs);
g_clear_object (&priv->source);
g_clear_object (&priv->client1);
pv_daemon_unexport (daemon, priv->object_path);
g_free (priv->object_path);

View file

@ -23,6 +23,7 @@
#include "server/pv-daemon.h"
#include "server/pv-client.h"
#include "server/pv-source-provider.h"
#include "modules/v4l2/pv-v4l2-source.h"
#include "dbus/org-pulsevideo.h"
@ -36,7 +37,7 @@ struct _PvDaemonPrivate
GDBusObjectManagerServer *server_manager;
GHashTable *senders;
PvSource *source;
GList *sources;
};
typedef struct {
@ -46,14 +47,74 @@ typedef struct {
GHashTable *clients;
PvSubscribe *subscribe;
GHashTable *sources;
} SenderData;
static void
on_subscription_event (PvSubscribe *subscribe,
PvSubscriptionEvent event,
PvSubscriptionFlags flags,
GDBusObjectProxy *object,
gpointer user_data)
{
SenderData *data = user_data;
PvDaemon *daemon = data->daemon;
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);
if (flags != PV_SUBSCRIPTION_FLAGS_SOURCE)
return;
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);
priv->sources = g_list_prepend (priv->sources, source1);
break;
}
case PV_SUBSCRIPTION_EVENT_CHANGE:
break;
case PV_SUBSCRIPTION_EVENT_REMOVE:
{
priv->sources = g_list_remove (priv->sources, source1);
g_hash_table_remove (data->sources, object_path);
break;
}
}
}
static void
client_name_appeared_handler (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
SenderData *data = user_data;
/* subscribe to Source events. We want to be notified when this new
* sender add/change/remove sources */
data->subscribe = pv_subscribe_new ();
g_object_set (data->subscribe, "service", data->sender,
"subscription-mask", PV_SUBSCRIPTION_FLAGS_SOURCE,
"connection", connection,
NULL);
g_signal_connect (data->subscribe,
"subscription-event",
(GCallback) on_subscription_event,
data);
}
static void
@ -66,22 +127,16 @@ client_name_vanished_handler (GDBusConnection *connection,
g_print ("vanished client %s\n", name);
g_hash_table_unref (data->clients);
g_hash_table_remove (priv->senders, data->sender);
g_hash_table_unref (data->clients);
g_hash_table_unref (data->sources);
g_object_unref (data->subscribe);
g_free (data->sender);
g_bus_unwatch_name (data->id);
g_free (data);
}
static 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 *
sender_data_new (PvDaemon *daemon, const gchar *sender)
{
@ -92,6 +147,7 @@ sender_data_new (PvDaemon *daemon, const gchar *sender)
data->daemon = daemon;
data->sender = g_strdup (sender);
data->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
data->sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
data->id = g_bus_watch_name_on_connection (priv->connection,
sender,
@ -101,16 +157,6 @@ sender_data_new (PvDaemon *daemon, const gchar *sender)
data,
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);
return data;
@ -288,19 +334,21 @@ pv_daemon_unexport (PvDaemon *daemon, const gchar *object_path)
g_dbus_object_manager_server_unexport (daemon->priv->server_manager, object_path);
}
PvSource *
PvSource1 *
pv_daemon_get_source (PvDaemon *daemon, const gchar *name)
{
PvDaemonPrivate *priv;
PvSource1 *source;
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
priv = daemon->priv;
if (priv->source == NULL) {
priv->source = pv_v4l2_source_new ();
pv_source_set_manager (priv->source, priv->server_manager);
}
return priv->source;
if (priv->sources == NULL)
return NULL;
source = priv->sources->data;
return source;
}
G_DEFINE_TYPE (PvDaemon, pv_daemon, G_TYPE_OBJECT);

View file

@ -23,6 +23,8 @@
#include <glib-object.h>
#include <gio/gio.h>
#include "dbus/org-pulsevideo.h"
G_BEGIN_DECLS
#define PV_TYPE_DAEMON (pv_daemon_get_type ())
@ -38,7 +40,8 @@ typedef struct _PvDaemon PvDaemon;
typedef struct _PvDaemonClass PvDaemonClass;
typedef struct _PvDaemonPrivate PvDaemonPrivate;
#include "client/pv-source.h"
#include <client/pv-source.h>
#include <server/pv-source-provider.h>
/**
* PvDaemon:
@ -61,17 +64,17 @@ struct _PvDaemonClass {
};
/* normal GObject stuff */
GType pv_daemon_get_type (void);
GType pv_daemon_get_type (void);
PvDaemon * pv_daemon_new (void);
PvDaemon * pv_daemon_new (void);
void pv_daemon_start (PvDaemon *daemon);
void pv_daemon_stop (PvDaemon *daemon);
void pv_daemon_start (PvDaemon *daemon);
void pv_daemon_stop (PvDaemon *daemon);
gchar * pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel);
void pv_daemon_unexport (PvDaemon *daemon, const gchar *name);
gchar * pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel);
void pv_daemon_unexport (PvDaemon *daemon, const gchar *name);
PvSource * pv_daemon_get_source (PvDaemon *daemon, const gchar *name);
PvSource1 * pv_daemon_get_source (PvDaemon *daemon, const gchar *name);
G_END_DECLS

View file

@ -0,0 +1,261 @@
/* 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 "server/pv-source-provider.h"
#include "dbus/org-pulsevideo.h"
struct _PvSourceProviderPrivate
{
PvDaemon *daemon;
gchar *object_path;
gchar *name;
gchar *path;
};
#define PV_SOURCE_PROVIDER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SOURCE_PROVIDER, PvSourceProviderPrivate))
G_DEFINE_TYPE (PvSourceProvider, pv_source_provider, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH,
PROP_NAME,
PROP_PATH,
};
static void
pv_source_provider_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PvSourceProvider *client = PV_SOURCE_PROVIDER (_object);
PvSourceProviderPrivate *priv = client->priv;
switch (prop_id) {
case PROP_DAEMON:
g_value_set_object (value, priv->daemon);
break;
case PROP_OBJECT_PATH:
g_value_set_string (value, priv->object_path);
break;
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_PATH:
g_value_set_string (value, priv->path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static void
pv_source_provider_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PvSourceProvider *client = PV_SOURCE_PROVIDER (_object);
PvSourceProviderPrivate *priv = client->priv;
switch (prop_id) {
case PROP_DAEMON:
priv->daemon = g_value_dup_object (value);
break;
case PROP_OBJECT_PATH:
priv->object_path = g_value_dup_string (value);
break;
case PROP_NAME:
priv->name = g_value_dup_string (value);
break;
case PROP_PATH:
priv->path = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static void
source_provider_register_object (PvSourceProvider *client, const gchar *prefix)
{
PvSourceProviderPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/source", prefix);
skel = g_dbus_object_skeleton_new (name);
g_free (name);
{
PvSourceProvider1 *iface;
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));
g_object_unref (iface);
}
g_free (priv->object_path);
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
}
static void
source_provider_unregister_object (PvSourceProvider *client)
{
PvSourceProviderPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
pv_daemon_unexport (daemon, priv->object_path);
g_free (priv->object_path);
}
static void
pv_source_provider_finalize (GObject * object)
{
PvSourceProvider *client = PV_SOURCE_PROVIDER (object);
PvSourceProviderPrivate *priv = client->priv;
source_provider_unregister_object (client);
g_free (priv->name);
g_free (priv->path);
G_OBJECT_CLASS (pv_source_provider_parent_class)->finalize (object);
}
static void
pv_source_provider_constructed (GObject * object)
{
PvSourceProvider *client = PV_SOURCE_PROVIDER (object);
PvSourceProviderPrivate *priv = client->priv;
source_provider_register_object (client, priv->object_path);
G_OBJECT_CLASS (pv_source_provider_parent_class)->constructed (object);
}
static void
pv_source_provider_class_init (PvSourceProviderClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PvSourceProviderPrivate));
gobject_class->finalize = pv_source_provider_finalize;
gobject_class->set_property = pv_source_provider_set_property;
gobject_class->get_property = pv_source_provider_get_property;
gobject_class->constructed = pv_source_provider_constructed;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The daemon",
PV_TYPE_DAEMON,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_OBJECT_PATH,
g_param_spec_string ("object-path",
"Object Path",
"The object path",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"The name of the owner",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_PATH,
g_param_spec_string ("path",
"Path",
"The path",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
static void
pv_source_provider_init (PvSourceProvider * client)
{
client->priv = PV_SOURCE_PROVIDER_GET_PRIVATE (client);
}
/**
* pv_source_provider_new:
*
* Make a new unconnected #PvSourceProvider
*
* Returns: a new #PvSourceProvider
*/
PvSourceProvider *
pv_source_provider_new (PvDaemon *daemon,
const gchar *prefix,
const gchar *name,
const gchar *path)
{
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
g_return_val_if_fail (g_variant_is_object_path (prefix), NULL);
return g_object_new (PV_TYPE_SOURCE_PROVIDER, "daemon", daemon, "object-path", prefix,
"name", name, "path", path, NULL);
}
const gchar *
pv_source_provider_get_object_path (PvSourceProvider *client)
{
PvSourceProviderPrivate *priv;
g_return_val_if_fail (PV_IS_SOURCE_PROVIDER (client), NULL);
priv = client->priv;
return priv->object_path;
}

View file

@ -0,0 +1,74 @@
/* 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.
*/
#ifndef __PV_SOURCE_PROVIDER_H__
#define __PV_SOURCE_PROVIDER_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define PV_TYPE_SOURCE_PROVIDER (pv_source_provider_get_type ())
#define PV_IS_SOURCE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE_PROVIDER))
#define PV_IS_SOURCE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SOURCE_PROVIDER))
#define PV_SOURCE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SOURCE_PROVIDER, PvSourceProviderClass))
#define PV_SOURCE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SOURCE_PROVIDER, PvSourceProvider))
#define PV_SOURCE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SOURCE_PROVIDER, PvSourceProviderClass))
#define PV_SOURCE_PROVIDER_CAST(obj) ((PvSourceProvider*)(obj))
#define PV_SOURCE_PROVIDER_CLASS_CAST(klass) ((PvSourceProviderClass*)(klass))
typedef struct _PvSourceProvider PvSourceProvider;
typedef struct _PvSourceProviderClass PvSourceProviderClass;
typedef struct _PvSourceProviderPrivate PvSourceProviderPrivate;
#include "pv-daemon.h"
/**
* PvSourceProvider:
*
* Pulsevideo source provider object class.
*/
struct _PvSourceProvider {
GObject object;
PvSourceProviderPrivate *priv;
};
/**
* PvSourceProviderClass:
*
* Pulsevideo source provider object class.
*/
struct _PvSourceProviderClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pv_source_provider_get_type (void);
PvSourceProvider * pv_source_provider_new (PvDaemon *daemon, const gchar *prefix,
const gchar *name, const gchar *path);
const gchar * pv_source_provider_get_object_path (PvSourceProvider *client);
G_END_DECLS
#endif /* __PV_SOURCE_PROVIDER_H__ */