Initial commit

This commit is contained in:
Wim Taymans 2015-04-16 16:58:33 +02:00
commit 3fba92fb74
41 changed files with 5544 additions and 0 deletions

279
src/server/pv-client.c Normal file
View file

@ -0,0 +1,279 @@
/* 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-client.h"
#include "server/pv-source.h"
#include "server/pv-source-output.h"
#include "client/pv-enumtypes.h"
#include "dbus/org-pulsevideo.h"
struct _PvClientPrivate
{
PvDaemon *daemon;
gchar *object_path;
PvSource *source;
GHashTable *source_outputs;
};
#define PV_CLIENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_CLIENT, PvClientPrivate))
G_DEFINE_TYPE (PvClient, pv_client, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH,
};
static void
pv_client_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PvClient *client = PV_CLIENT (_object);
PvClientPrivate *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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static void
pv_client_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PvClient *client = PV_CLIENT (_object);
PvClientPrivate *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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static gboolean
handle_create_source_output (PvCapture1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_source,
GVariant *arg_properties,
gpointer user_data)
{
PvClient *client = user_data;
PvClientPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
PvSource *source;
PvSourceOutput *output;
const gchar *object_path;
source = pv_daemon_get_source (daemon, arg_source);
output = pv_source_create_source_output (source, NULL, priv->object_path);
object_path = pv_source_output_get_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;
}
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;
}
static void
client_register_object (PvClient *client, const gchar *prefix)
{
PvClientPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/client", 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_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-remove-source-output", (GCallback) handle_remove_source_output, client);
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
client_unregister_object (PvClient *client)
{
PvClientPrivate *priv = client->priv;
PvDaemon *daemon = priv->daemon;
g_hash_table_unref (priv->source_outputs);
g_clear_object (&priv->source);
pv_daemon_unexport (daemon, priv->object_path);
g_free (priv->object_path);
}
static void
pv_client_finalize (GObject * object)
{
PvClient *client = PV_CLIENT (object);
client_unregister_object (client);
G_OBJECT_CLASS (pv_client_parent_class)->finalize (object);
}
static void
pv_client_constructed (GObject * object)
{
PvClient *client = PV_CLIENT (object);
PvClientPrivate *priv = client->priv;
client_register_object (client, priv->object_path);
G_OBJECT_CLASS (pv_client_parent_class)->constructed (object);
}
static void
pv_client_class_init (PvClientClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PvClientPrivate));
gobject_class->finalize = pv_client_finalize;
gobject_class->set_property = pv_client_set_property;
gobject_class->get_property = pv_client_get_property;
gobject_class->constructed = pv_client_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));
}
static void
pv_client_init (PvClient * client)
{
PvClientPrivate *priv = client->priv = PV_CLIENT_GET_PRIVATE (client);
priv->source_outputs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
/**
* pv_client_new:
*
* Make a new unconnected #PvClient
*
* Returns: a new unconnected #PvClient
*/
PvClient *
pv_client_new (PvDaemon * daemon, const gchar *prefix)
{
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
g_return_val_if_fail (g_variant_is_object_path (prefix), NULL);
return g_object_new (PV_TYPE_CLIENT, "daemon", daemon, "object-path", prefix, NULL);
}
const gchar *
pv_client_get_object_path (PvClient *client)
{
PvClientPrivate *priv;
g_return_val_if_fail (PV_IS_CLIENT (client), NULL);
priv = client->priv;
return priv->object_path;
}

72
src/server/pv-client.h Normal file
View file

@ -0,0 +1,72 @@
/* 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_CLIENT_H__
#define __PV_CLIENT_H__
#include <glib-object.h>
#include "pv-daemon.h"
G_BEGIN_DECLS
#define PV_TYPE_CLIENT (pv_client_get_type ())
#define PV_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_CLIENT))
#define PV_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_CLIENT))
#define PV_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_CLIENT, PvClientClass))
#define PV_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_CLIENT, PvClient))
#define PV_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_CLIENT, PvClientClass))
#define PV_CLIENT_CAST(obj) ((PvClient*)(obj))
#define PV_CLIENT_CLASS_CAST(klass) ((PvClientClass*)(klass))
typedef struct _PvClient PvClient;
typedef struct _PvClientClass PvClientClass;
typedef struct _PvClientPrivate PvClientPrivate;
/**
* PvClient:
*
* Pulsevideo client object class.
*/
struct _PvClient {
GObject object;
PvClientPrivate *priv;
};
/**
* PvClientClass:
*
* Pulsevideo client object class.
*/
struct _PvClientClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pv_client_get_type (void);
PvClient * pv_client_new (PvDaemon *daemon, const gchar *prefix);
const gchar * pv_client_get_object_path (PvClient *client);
G_END_DECLS
#endif /* __PV_CLIENT_H__ */

354
src/server/pv-daemon.c Normal file
View file

@ -0,0 +1,354 @@
/* 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 <gio/gio.h>
#include "config.h"
#include "server/pv-daemon.h"
#include "server/pv-client.h"
#include "modules/v4l2/pv-v4l2-source.h"
#include "dbus/org-pulsevideo.h"
#define PV_DAEMON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_DAEMON, PvDaemonPrivate))
struct _PvDaemonPrivate
{
guint id;
GDBusConnection *connection;
GDBusObjectManagerServer *server_manager;
GHashTable *senders;
PvSource *source;
};
typedef struct {
PvDaemon *daemon;
gchar *sender;
guint id;
GHashTable *clients;
} SenderData;
static void
client_name_appeared_handler (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
}
static void
client_name_vanished_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
SenderData *data = user_data;
PvDaemonPrivate *priv = data->daemon->priv;
g_print ("vanished client %s\n", name);
g_hash_table_unref (data->clients);
g_hash_table_remove (priv->senders, data->sender);
g_free (data->sender);
g_bus_unwatch_name (data->id);
g_free (data);
}
static SenderData *
sender_data_new (PvDaemon *daemon, const gchar *sender)
{
PvDaemonPrivate *priv = daemon->priv;
SenderData *data;
data = g_new0 (SenderData, 1);
data->daemon = daemon;
data->sender = g_strdup (sender);
data->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
data->id = g_bus_watch_name_on_connection (priv->connection,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
client_name_appeared_handler,
client_name_vanished_handler,
data,
NULL);
g_hash_table_insert (priv->senders, data->sender, data);
return data;
}
static gboolean
handle_connect_client (PvDaemon1 *interface,
GDBusMethodInvocation *invocation,
GVariant *arg_properties,
gpointer user_data)
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
PvClient *client;
const gchar *sender, *object_path;
SenderData *data;
sender = g_dbus_method_invocation_get_sender (invocation);
g_print ("connect client %s\n", sender);
data = g_hash_table_lookup (priv->senders, sender);
if (data == NULL) {
data = sender_data_new (daemon, sender);
}
client = pv_client_new (daemon, PV_DBUS_OBJECT_PREFIX);
object_path = pv_client_get_object_path (client);
g_hash_table_insert (data->clients, g_strdup (object_path), client);
pv_daemon1_complete_connect_client (interface, invocation, object_path);
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 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
export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager)
{
GDBusObjectSkeleton *skel;
skel = g_dbus_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));
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_object_unref (skel);
}
static void
bus_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
priv->connection = connection;
}
static void
name_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager;
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);
}
static void
name_lost_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PvDaemon *daemon = user_data;
PvDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager = priv->server_manager;
g_dbus_object_manager_server_unexport (manager, PV_DBUS_OBJECT_SERVER);
g_clear_object (&priv->server_manager);
}
PvDaemon *
pv_daemon_new (void)
{
return g_object_new (PV_TYPE_DAEMON, NULL);
}
void
pv_daemon_start (PvDaemon *daemon)
{
PvDaemonPrivate *priv;
g_return_if_fail (PV_IS_DAEMON (daemon));
priv = daemon->priv;
g_return_if_fail (priv->id == 0);
priv->id = g_bus_own_name (G_BUS_TYPE_SESSION,
PV_DBUS_SERVICE,
G_BUS_NAME_OWNER_FLAGS_REPLACE,
bus_acquired_handler,
name_acquired_handler,
name_lost_handler,
daemon,
NULL);
}
void
pv_daemon_stop (PvDaemon *daemon)
{
PvDaemonPrivate *priv = daemon->priv;
g_return_if_fail (PV_IS_DAEMON (daemon));
g_bus_unown_name (priv->id);
priv->id = 0;
}
gchar *
pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel)
{
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (skel), NULL);
g_dbus_object_manager_server_export_uniquely (daemon->priv->server_manager, skel);
return g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));
}
void
pv_daemon_unexport (PvDaemon *daemon, const gchar *object_path)
{
g_return_if_fail (PV_IS_DAEMON (daemon));
g_return_if_fail (g_variant_is_object_path (object_path));
g_dbus_object_manager_server_unexport (daemon->priv->server_manager, object_path);
}
PvSource *
pv_daemon_get_source (PvDaemon *daemon, const gchar *name)
{
PvDaemonPrivate *priv;
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
priv = daemon->priv;
if (priv->source == NULL) {
priv->source = pv_v4l2_source_new (daemon);
}
return priv->source;
}
G_DEFINE_TYPE (PvDaemon, pv_daemon, G_TYPE_OBJECT);
static void
pv_daemon_finalize (GObject * object)
{
PvDaemon *daemon = PV_DAEMON_CAST (object);
PvDaemonPrivate *priv = daemon->priv;
g_hash_table_unref (priv->senders);
pv_daemon_stop (daemon);
G_OBJECT_CLASS (pv_daemon_parent_class)->finalize (object);
}
static void
pv_daemon_class_init (PvDaemonClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PvDaemonPrivate));
gobject_class->finalize = pv_daemon_finalize;
}
static void
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);
}

85
src/server/pv-daemon.h Normal file
View file

@ -0,0 +1,85 @@
/* 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_DAEMON_H__
#define __PV_DAEMON_H__
#include <glib-object.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#define PV_TYPE_DAEMON (pv_daemon_get_type ())
#define PV_IS_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_DAEMON))
#define PV_IS_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_DAEMON))
#define PV_DAEMON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_DAEMON, PvDaemonClass))
#define PV_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_DAEMON, PvDaemon))
#define PV_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_DAEMON, PvDaemonClass))
#define PV_DAEMON_CAST(obj) ((PvDaemon*)(obj))
#define PV_DAEMON_CLASS_CAST(klass) ((PvDaemonClass*)(klass))
typedef struct _PvDaemon PvDaemon;
typedef struct _PvDaemonClass PvDaemonClass;
typedef struct _PvDaemonPrivate PvDaemonPrivate;
#include "server/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:
*
* Pulsevideo daemon object class.
*/
struct _PvDaemon {
GObject object;
PvDaemonPrivate *priv;
};
/**
* PvDaemonClass:
*
* Pulsevideo daemon object class.
*/
struct _PvDaemonClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pv_daemon_get_type (void);
PvDaemon * pv_daemon_new (void);
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);
PvSource * pv_daemon_get_source (PvDaemon *daemon, const gchar *name);
G_END_DECLS
#endif /* __PV_DAEMON_H__ */

View file

@ -0,0 +1,273 @@
/* 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 <sys/socket.h>
#include <gio/gunixfdlist.h>
#include "server/pv-daemon.h"
#include "server/pv-source-output.h"
#include "client/pv-enumtypes.h"
#include "dbus/org-pulsevideo.h"
struct _PvSourceOutputPrivate
{
PvDaemon *daemon;
gchar *object_path;
GSocket *socket;
};
#define PV_SOURCE_OUTPUT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputPrivate))
G_DEFINE_TYPE (PvSourceOutput, pv_source_output, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH,
PROP_SOCKET,
};
static void
pv_source_output_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PvSourceOutput *output = PV_SOURCE_OUTPUT (_object);
PvSourceOutputPrivate *priv = output->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_SOCKET:
g_value_set_object (value, priv->socket);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
break;
}
}
static void
pv_source_output_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PvSourceOutput *output = PV_SOURCE_OUTPUT (_object);
PvSourceOutputPrivate *priv = output->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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
break;
}
}
static gboolean
handle_acquire (PvSourceOutput1 *interface,
GDBusMethodInvocation *invocation,
GVariant *arg_properties,
gpointer user_data)
{
PvSourceOutput *output = user_data;
PvSourceOutputPrivate *priv = output->priv;
GUnixFDList *fdlist;
GVariantBuilder props;
gint fd[2];
g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&props, "{sv}", "name", g_variant_new_string ("hello"));
socketpair (AF_UNIX, SOCK_STREAM, 0, fd);
priv->socket = g_socket_new_from_fd (fd[0], NULL);
g_object_notify (G_OBJECT (output), "socket");
fdlist = g_unix_fd_list_new ();
g_unix_fd_list_append (fdlist, fd[1], NULL);
g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
g_variant_new ("(h@a{sv})", 0, g_variant_builder_end (&props)),
fdlist);
return TRUE;
}
static void
stop_transfer (PvSourceOutput *output)
{
PvSourceOutputPrivate *priv = output->priv;
if (priv->socket) {
g_clear_object (&priv->socket);
g_object_notify (G_OBJECT (output), "socket");
}
}
static gboolean
handle_release (PvSourceOutput1 *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
PvSourceOutput *output = user_data;
stop_transfer (output);
pv_source_output1_complete_release (interface, invocation);
return TRUE;
}
static void
output_register_object (PvSourceOutput *output, const gchar *prefix)
{
PvSourceOutputPrivate *priv = output->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/output", prefix);
skel = g_dbus_object_skeleton_new (name);
g_free (name);
{
PvSourceOutput1 *iface;
iface = pv_source_output1_skeleton_new ();
g_signal_connect (iface, "handle-acquire", (GCallback) handle_acquire, output);
g_signal_connect (iface, "handle-release", (GCallback) handle_release, output);
g_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
output_unregister_object (PvSourceOutput *output)
{
PvSourceOutputPrivate *priv = output->priv;
PvDaemon *daemon = priv->daemon;
stop_transfer (output);
pv_daemon_unexport (daemon, priv->object_path);
}
static void
pv_source_output_finalize (GObject * object)
{
PvSourceOutput *output = PV_SOURCE_OUTPUT (object);
PvSourceOutputPrivate *priv = output->priv;
output_unregister_object (output);
g_object_unref (priv->daemon);
g_free (priv->object_path);
G_OBJECT_CLASS (pv_source_output_parent_class)->finalize (object);
}
static void
pv_source_output_constructed (GObject * object)
{
PvSourceOutput *output = PV_SOURCE_OUTPUT (object);
PvSourceOutputPrivate *priv = output->priv;
output_register_object (output, priv->object_path);
G_OBJECT_CLASS (pv_source_output_parent_class)->constructed (object);
}
static void
pv_source_output_class_init (PvSourceOutputClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PvSourceOutputPrivate));
gobject_class->finalize = pv_source_output_finalize;
gobject_class->set_property = pv_source_output_set_property;
gobject_class->get_property = pv_source_output_get_property;
gobject_class->constructed = pv_source_output_constructed;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The daemon",
PV_TYPE_DAEMON,
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_SOCKET,
g_param_spec_object ("socket",
"Socket",
"The socket with data",
G_TYPE_SOCKET,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
static void
pv_source_output_init (PvSourceOutput * output)
{
output->priv = PV_SOURCE_OUTPUT_GET_PRIVATE (output);
}
const gchar *
pv_source_output_get_object_path (PvSourceOutput *output)
{
PvSourceOutputPrivate *priv;
g_return_val_if_fail (PV_IS_SOURCE_OUTPUT (output), NULL);
priv = output->priv;
return priv->object_path;
}

View file

@ -0,0 +1,68 @@
/* 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_OUTPUT_H__
#define __PV_SOURCE_OUTPUT_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define PV_TYPE_SOURCE_OUTPUT (pv_source_output_get_type ())
#define PV_IS_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE_OUTPUT))
#define PV_IS_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SOURCE_OUTPUT))
#define PV_SOURCE_OUTPUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputClass))
#define PV_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutput))
#define PV_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputClass))
#define PV_SOURCE_OUTPUT_CAST(obj) ((PvSourceOutput*)(obj))
#define PV_SOURCE_OUTPUT_CLASS_CAST(klass) ((PvSourceOutputClass*)(klass))
typedef struct _PvSourceOutput PvSourceOutput;
typedef struct _PvSourceOutputClass PvSourceOutputClass;
typedef struct _PvSourceOutputPrivate PvSourceOutputPrivate;
/**
* PvSourceOutput:
*
* Pulsevideo source output object class.
*/
struct _PvSourceOutput {
GObject object;
PvSourceOutputPrivate *priv;
};
/**
* PvSourceOutputClass:
*
* Pulsevideo source output object class.
*/
struct _PvSourceOutputClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pv_source_output_get_type (void);
const gchar * pv_source_output_get_object_path (PvSourceOutput *output);
G_END_DECLS
#endif /* __PV_SOURCE_OUTPUT_H__ */

288
src/server/pv-source.c Normal file
View file

@ -0,0 +1,288 @@
/* 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 <gio/gio.h>
#include "server/pv-source.h"
#include "server/pv-daemon.h"
#include "dbus/org-pulsevideo.h"
#define PV_SOURCE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SOURCE, PvSourcePrivate))
struct _PvSourcePrivate
{
PvDaemon *daemon;
gchar *object_path;
};
G_DEFINE_ABSTRACT_TYPE (PvSource, pv_source, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH
};
static void
pv_source_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PvSource *source = PV_SOURCE (_object);
PvSourcePrivate *priv = source->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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static void
pv_source_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PvSource *source = PV_SOURCE (_object);
PvSourcePrivate *priv = source->priv;
switch (prop_id) {
case PROP_DAEMON:
priv->daemon = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static void
source_register_object (PvSource *source)
{
PvSourcePrivate *priv = source->priv;
PvDaemon *daemon = priv->daemon;
GDBusObjectSkeleton *skel;
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE);
{
PvSource1 *iface;
iface = pv_source1_skeleton_new ();
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_unregister_object (PvSource *source)
{
PvSourcePrivate *priv = source->priv;
PvDaemon *daemon = priv->daemon;
pv_daemon_unexport (daemon, priv->object_path);
}
static void
pv_source_finalize (GObject * object)
{
PvSource *source = PV_SOURCE (object);
PvSourcePrivate *priv = source->priv;
source_unregister_object (source);
g_object_unref (priv->daemon);
g_free (priv->object_path);
G_OBJECT_CLASS (pv_source_parent_class)->finalize (object);
}
static void
pv_source_constructed (GObject * object)
{
PvSource *source = PV_SOURCE (object);
source_register_object (source);
G_OBJECT_CLASS (pv_source_parent_class)->constructed (object);
}
static PvSourceOutput *
default_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
{
PvSourcePrivate *priv = source->priv;
return g_object_new (PV_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon, "object-path", prefix, NULL);
}
static gboolean
default_release_source_output (PvSource *source, PvSourceOutput *output)
{
g_object_unref (output);
return TRUE;
}
static void
pv_source_class_init (PvSourceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PvSourcePrivate));
gobject_class->finalize = pv_source_finalize;
gobject_class->set_property = pv_source_set_property;
gobject_class->get_property = pv_source_get_property;
gobject_class->constructed = pv_source_constructed;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The daemon",
PV_TYPE_DAEMON,
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_READABLE |
G_PARAM_STATIC_STRINGS));
klass->create_source_output = default_create_source_output;
klass->release_source_output = default_release_source_output;
}
static void
pv_source_init (PvSource * source)
{
source->priv = PV_SOURCE_GET_PRIVATE (source);
}
GVariant *
pv_source_get_capabilities (PvSource *source, GVariant *props)
{
PvSourceClass *klass;
GVariant *res;
g_return_val_if_fail (PV_IS_SOURCE (source), NULL);
klass = PV_SOURCE_GET_CLASS (source);
if (klass->get_capabilities)
res = klass->get_capabilities (source, props);
else
res = NULL;
return res;
}
gboolean
pv_source_suspend (PvSource *source)
{
PvSourceClass *klass;
gboolean res;
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
klass = PV_SOURCE_GET_CLASS (source);
if (klass->suspend)
res = klass->suspend (source);
else
res = FALSE;
return res;
}
gboolean
pv_source_resume (PvSource *source)
{
PvSourceClass *klass;
gboolean res;
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
klass = PV_SOURCE_GET_CLASS (source);
if (klass->resume)
res = klass->resume (source);
else
res = FALSE;
return res;
}
PvSourceOutput *
pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
{
PvSourceClass *klass;
PvSourceOutput *res;
g_return_val_if_fail (PV_IS_SOURCE (source), NULL);
klass = PV_SOURCE_GET_CLASS (source);
if (klass->create_source_output)
res = klass->create_source_output (source, props, prefix);
else
res = NULL;
return res;
}
gboolean
pv_source_release_source_output (PvSource *source, PvSourceOutput *output)
{
PvSourceClass *klass;
gboolean res;
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
g_return_val_if_fail (PV_IS_SOURCE_OUTPUT (output), FALSE);
klass = PV_SOURCE_GET_CLASS (source);
if (klass->release_source_output)
res = klass->release_source_output (source, output);
else
res = FALSE;
return res;
}

87
src/server/pv-source.h Normal file
View file

@ -0,0 +1,87 @@
/* 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_H__
#define __PV_SOURCE_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _PvSource PvSource;
typedef struct _PvSourceClass PvSourceClass;
typedef struct _PvSourcePrivate PvSourcePrivate;
#include "server/pv-daemon.h"
#include "server/pv-source-output.h"
#define PV_TYPE_SOURCE (pv_source_get_type ())
#define PV_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE))
#define PV_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SOURCE))
#define PV_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SOURCE, PvSourceClass))
#define PV_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SOURCE, PvSource))
#define PV_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SOURCE, PvSourceClass))
#define PV_SOURCE_CAST(obj) ((PvSource*)(obj))
#define PV_SOURCE_CLASS_CAST(klass) ((PvSourceClass*)(klass))
/**
* PvSource:
*
* Pulsevideo source object class.
*/
struct _PvSource {
GObject object;
PvSourcePrivate *priv;
};
/**
* PvSourceClass:
*
* Pulsevideo source object class.
*/
struct _PvSourceClass {
GObjectClass parent_class;
GVariant * (*get_capabilities) (PvSource *source, GVariant *props);
gboolean (*suspend) (PvSource *source);
gboolean (*resume) (PvSource *source);
PvSourceOutput * (*create_source_output) (PvSource *source, GVariant *props, const gchar *prefix);
gboolean (*release_source_output) (PvSource *source, PvSourceOutput *output);
};
/* normal GObject stuff */
GType pv_source_get_type (void);
PvSource * pv_source_new (PvDaemon *daemon, const gchar *prefix);
GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props);
gboolean pv_source_suspend (PvSource *source);
gboolean pv_source_resume (PvSource *source);
PvSourceOutput * pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix);
gboolean pv_source_release_source_output (PvSource *source, PvSourceOutput *output);
G_END_DECLS
#endif /* __PV_SOURCE_H__ */