src -> pinos and fix include paths

Rename src to pinos and fix all the include paths so that they contain
pinos/ to avoid conflicts
This commit is contained in:
Wim Taymans 2016-02-01 15:40:48 +01:00
parent f4bd013dce
commit cdb2028f9b
57 changed files with 77 additions and 104 deletions

View file

@ -0,0 +1,454 @@
/* Pinos
* 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 <string.h>
#include <gst/gst.h>
#include <gio/gio.h>
#include <pinos/server/daemon.h>
#include <pinos/server/client-source.h>
#define PINOS_CLIENT_SOURCE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_CLIENT_SOURCE, PinosClientSourcePrivate))
struct _PinosClientSourcePrivate
{
GstElement *pipeline;
GstElement *src;
GstElement *sink;
guint id;
GstCaps *format;
GSocket *socket;
GBytes *possible_formats;
PinosSourceOutput *input;
};
G_DEFINE_TYPE (PinosClientSource, pinos_client_source, PINOS_TYPE_SOURCE);
enum
{
PROP_0,
PROP_POSSIBLE_FORMATS
};
static void
client_source_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PinosClientSource *source = PINOS_CLIENT_SOURCE (_object);
PinosClientSourcePrivate *priv = source->priv;
switch (prop_id) {
case PROP_POSSIBLE_FORMATS:
g_value_set_boxed (value, priv->possible_formats);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static void
client_source_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PinosClientSource *source = PINOS_CLIENT_SOURCE (_object);
PinosClientSourcePrivate *priv = source->priv;
switch (prop_id) {
case PROP_POSSIBLE_FORMATS:
if (priv->possible_formats)
g_bytes_unref (priv->possible_formats);
priv->possible_formats = g_value_dup_boxed (value);
pinos_source_update_possible_formats (PINOS_SOURCE (source),
priv->possible_formats);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static gboolean
bus_handler (GstBus *bus,
GstMessage *message,
gpointer user_data)
{
PinosSource *source = user_data;
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (source)->priv;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
{
GError *error;
gchar *debug;
gst_message_parse_error (message, &error, &debug);
g_warning ("got error %s (%s)\n", error->message, debug);
g_free (debug);
pinos_source_report_error (source, error);
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
break;
}
default:
break;
}
return TRUE;
}
static void
setup_pipeline (PinosClientSource *source)
{
PinosClientSourcePrivate *priv = source->priv;
GstBus *bus;
priv->pipeline = gst_parse_launch ("socketsrc "
"name=src "
"caps=application/x-pinos "
"send-messages=true ! "
"pinospay ! "
"multisocketsink "
"buffers-max=2 "
"buffers-soft-max=1 "
"recover-policy=latest "
"sync-method=latest "
"name=sink "
"sync=true "
"enable-last-sample=false "
"send-messages=true "
"send-dispatched=true",
NULL);
priv->sink = gst_bin_get_by_name (GST_BIN (priv->pipeline), "sink");
priv->src = gst_bin_get_by_name (GST_BIN (priv->pipeline), "src");
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
priv->id = gst_bus_add_watch (bus, bus_handler, source);
gst_object_unref (bus);
}
static GstCaps *
collect_caps (PinosSource *source,
GstCaps *filter)
{
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (source)->priv;
if (priv->format)
return gst_caps_ref (priv->format);
else
return gst_caps_new_any ();
}
static gboolean
client_set_state (PinosSource *source,
PinosSourceState state)
{
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (source)->priv;
switch (state) {
case PINOS_SOURCE_STATE_SUSPENDED:
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
break;
case PINOS_SOURCE_STATE_INITIALIZING:
gst_element_set_state (priv->pipeline, GST_STATE_READY);
break;
case PINOS_SOURCE_STATE_IDLE:
gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
break;
case PINOS_SOURCE_STATE_RUNNING:
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
break;
case PINOS_SOURCE_STATE_ERROR:
break;
}
pinos_source_update_state (source, state);
return TRUE;
}
static GBytes *
client_get_formats (PinosSource *source,
GBytes *filter,
GError **error)
{
GstCaps *caps, *cfilter;
gchar *str;
if (filter) {
cfilter = gst_caps_from_string (g_bytes_get_data (filter, NULL));
if (cfilter == NULL)
goto invalid_filter;
} else {
cfilter = NULL;
}
caps = collect_caps (source, cfilter);
if (caps == NULL)
goto no_format;
str = gst_caps_to_string (caps);
return g_bytes_new_take (str, strlen (str) + 1);
invalid_filter:
{
if (error)
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
"Invalid filter received");
return NULL;
}
no_format:
{
if (error)
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
"No compatible format found");
return NULL;
}
}
static void
on_socket_notify (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
PinosClientSource *source = user_data;
PinosClientSourcePrivate *priv = source->priv;
GSocket *socket;
guint num_handles;
g_object_get (gobject, "socket", &socket, NULL);
if (socket == NULL) {
GSocket *prev_socket = g_object_steal_data (gobject, "last-socket");
if (prev_socket) {
g_signal_emit_by_name (priv->sink, "remove", prev_socket);
g_object_unref (prev_socket);
}
} else {
g_signal_emit_by_name (priv->sink, "add", socket);
g_object_set_data_full (gobject, "last-socket", socket, g_object_unref);
}
g_object_get (priv->sink, "num-handles", &num_handles, NULL);
if (num_handles > 0 && socket) {
GBytes *format;
/* suggest what we provide */
g_object_get (priv->input, "format", &format, NULL);
g_object_set (gobject, "format", format, NULL);
g_bytes_unref (format);
}
}
static PinosSourceOutput *
client_create_source_output (PinosSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error)
{
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (source)->priv;
PinosSourceOutput *output;
/* propose format of input */
g_object_get (priv->input, "format", &format_filter, NULL);
output = PINOS_SOURCE_CLASS (pinos_client_source_parent_class)
->create_source_output (source,
client_path,
format_filter,
props,
prefix,
error);
if (output == NULL)
return NULL;
g_signal_connect (output, "notify::socket", (GCallback) on_socket_notify, source);
return output;
}
static gboolean
client_release_source_output (PinosSource *source,
PinosSourceOutput *output)
{
return PINOS_SOURCE_CLASS (pinos_client_source_parent_class)->release_source_output (source, output);
}
static void
client_source_dispose (GObject * object)
{
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (object)->priv;
g_source_remove (priv->id);
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
G_OBJECT_CLASS (pinos_client_source_parent_class)->dispose (object);
}
static void
client_source_finalize (GObject * object)
{
PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (object)->priv;
g_clear_object (&priv->input);
g_clear_object (&priv->sink);
g_clear_object (&priv->src);
g_clear_object (&priv->pipeline);
gst_caps_replace (&priv->format, NULL);
G_OBJECT_CLASS (pinos_client_source_parent_class)->finalize (object);
}
static void
on_input_socket_notify (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
PinosClientSource *source = user_data;
PinosClientSourcePrivate *priv = source->priv;
GSocket *socket;
GBytes *requested_format;
GstCaps *caps;
g_object_get (gobject, "socket", &socket, NULL);
if (socket) {
/* requested format is final format */
g_object_get (gobject, "requested-format", &requested_format, NULL);
g_assert (requested_format != NULL);
g_object_set (gobject, "format", requested_format, NULL);
/* and set as the current format */
caps = gst_caps_from_string (g_bytes_get_data (requested_format, NULL));
g_assert (caps != NULL);
gst_caps_replace (&priv->format, caps);
g_bytes_unref (requested_format);
} else {
gst_caps_replace (&priv->format, NULL);
}
g_object_set (priv->src, "socket", socket, NULL);
if (socket)
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
else
gst_element_set_state (priv->pipeline, GST_STATE_READY);
}
PinosSourceOutput *
pinos_client_source_get_source_input (PinosClientSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error)
{
PinosClientSourcePrivate *priv;
g_return_val_if_fail (PINOS_IS_CLIENT_SOURCE (source), NULL);
priv = source->priv;
if (priv->input == NULL) {
GstCaps *caps = gst_caps_from_string (g_bytes_get_data (format_filter, NULL));
gst_caps_replace (&priv->format, caps);
priv->input = PINOS_SOURCE_CLASS (pinos_client_source_parent_class)
->create_source_output (PINOS_SOURCE (source),
client_path,
format_filter,
props,
prefix,
error);
if (priv->input == NULL)
return NULL;
g_signal_connect (priv->input, "notify::socket", (GCallback) on_input_socket_notify, source);
}
return g_object_ref (priv->input);
}
static void
pinos_client_source_class_init (PinosClientSourceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
PinosSourceClass *source_class = PINOS_SOURCE_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosClientSourcePrivate));
gobject_class->dispose = client_source_dispose;
gobject_class->finalize = client_source_finalize;
gobject_class->get_property = client_source_get_property;
gobject_class->set_property = client_source_set_property;
g_object_class_install_property (gobject_class,
PROP_POSSIBLE_FORMATS,
g_param_spec_boxed ("possible-formats",
"Possible Format",
"The possible formats of the stream",
G_TYPE_BYTES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
source_class->get_formats = client_get_formats;
source_class->set_state = client_set_state;
source_class->create_source_output = client_create_source_output;
source_class->release_source_output = client_release_source_output;
}
static void
pinos_client_source_init (PinosClientSource * source)
{
source->priv = PINOS_CLIENT_SOURCE_GET_PRIVATE (source);
setup_pipeline (source);
}
PinosSource *
pinos_client_source_new (PinosDaemon *daemon,
GBytes *possible_formats)
{
return g_object_new (PINOS_TYPE_CLIENT_SOURCE,
"daemon", daemon,
"name", "client-source",
"possible-formats", possible_formats,
NULL);
}

View file

@ -0,0 +1,77 @@
/* Pinos
* 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 __PINOS_CLIENT_SOURCE_H__
#define __PINOS_CLIENT_SOURCE_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _PinosClientSource PinosClientSource;
typedef struct _PinosClientSourceClass PinosClientSourceClass;
typedef struct _PinosClientSourcePrivate PinosClientSourcePrivate;
#include <pinos/server/source.h>
#define PINOS_TYPE_CLIENT_SOURCE (pinos_client_source_get_type ())
#define PINOS_IS_CLIENT_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SOURCE))
#define PINOS_IS_CLIENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SOURCE))
#define PINOS_CLIENT_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SOURCE, PinosClientSourceClass))
#define PINOS_CLIENT_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SOURCE, PinosClientSource))
#define PINOS_CLIENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SOURCE, PinosClientSourceClass))
#define PINOS_CLIENT_SOURCE_CAST(obj) ((PinosClientSource*)(obj))
#define PINOS_CLIENT_SOURCE_CLASS_CAST(klass) ((PinosClientSourceClass*)(klass))
/**
* PinosClientSource:
*
* Pinos client source object class.
*/
struct _PinosClientSource {
PinosSource object;
PinosClientSourcePrivate *priv;
};
/**
* PinosClientSourceClass:
*
* Pinos client source object class.
*/
struct _PinosClientSourceClass {
PinosSourceClass parent_class;
};
/* normal GObject stuff */
GType pinos_client_source_get_type (void);
PinosSource * pinos_client_source_new (PinosDaemon *daemon,
GBytes *possible_formats);
PinosSourceOutput * pinos_client_source_get_source_input (PinosClientSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error);
G_END_DECLS
#endif /* __PINOS_CLIENT_SOURCE_H__ */

533
pinos/server/client.c Normal file
View file

@ -0,0 +1,533 @@
/* Pinos
* 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 <string.h>
#include "pinos/client/pinos.h"
#include "pinos/client/enumtypes.h"
#include "pinos/server/client.h"
#include "pinos/server/client-source.h"
#include "pinos/dbus/org-pinos.h"
struct _PinosClientPrivate
{
PinosDaemon *daemon;
gchar *sender;
gchar *object_path;
PinosProperties *properties;
PinosClient1 *client1;
GList *outputs;
};
#define PINOS_CLIENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_CLIENT, PinosClientPrivate))
G_DEFINE_TYPE (PinosClient, pinos_client, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_SENDER,
PROP_OBJECT_PATH,
PROP_PROPERTIES,
};
enum
{
SIGNAL_DISCONNECT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void
pinos_client_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PinosClient *client = PINOS_CLIENT (_object);
PinosClientPrivate *priv = client->priv;
switch (prop_id) {
case PROP_DAEMON:
g_value_set_object (value, priv->daemon);
break;
case PROP_SENDER:
g_value_set_string (value, priv->sender);
break;
case PROP_OBJECT_PATH:
g_value_set_string (value, priv->object_path);
break;
case PROP_PROPERTIES:
g_value_set_boxed (value, priv->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static void
pinos_client_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PinosClient *client = PINOS_CLIENT (_object);
PinosClientPrivate *priv = client->priv;
switch (prop_id) {
case PROP_DAEMON:
priv->daemon = g_value_dup_object (value);
break;
case PROP_SENDER:
priv->sender = g_value_dup_string (value);
break;
case PROP_OBJECT_PATH:
priv->object_path = g_value_dup_string (value);
break;
case PROP_PROPERTIES:
if (priv->properties)
pinos_properties_free (priv->properties);
priv->properties = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
break;
}
}
static void
handle_remove_source_output (PinosSourceOutput *output,
gpointer user_data)
{
PinosClient *client = user_data;
PinosClientPrivate *priv = client->priv;
priv->outputs = g_list_remove (priv->outputs, output);
g_object_unref (output);
}
static gboolean
handle_create_source_output (PinosClient1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_source,
const gchar *arg_accepted_formats,
GVariant *arg_properties,
gpointer user_data)
{
PinosClient *client = user_data;
PinosClientPrivate *priv = client->priv;
PinosSource *source;
PinosSourceOutput *output;
const gchar *object_path, *sender;
GBytes *formats;
PinosProperties *props;
GError *error = NULL;
sender = g_dbus_method_invocation_get_sender (invocation);
if (g_strcmp0 (pinos_client_get_sender (client), sender) != 0)
goto not_allowed;
formats = g_bytes_new (arg_accepted_formats, strlen (arg_accepted_formats) + 1);
props = pinos_properties_from_variant (arg_properties);
source = pinos_daemon_find_source (priv->daemon,
arg_source,
props,
formats,
&error);
if (source == NULL)
goto no_source;
output = pinos_source_create_source_output (source,
priv->object_path,
formats,
props,
priv->object_path,
&error);
if (output == NULL)
goto no_output;
priv->outputs = g_list_prepend (priv->outputs, output);
g_signal_connect (output,
"remove",
(GCallback) handle_remove_source_output,
client);
object_path = pinos_source_output_get_object_path (output);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(o)", object_path));
return TRUE;
/* ERRORS */
not_allowed:
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pinos.Error", "not client owner");
return TRUE;
}
no_source:
{
g_dbus_method_invocation_return_gerror (invocation, error);
g_clear_error (&error);
g_bytes_unref (formats);
return TRUE;
}
no_output:
{
g_dbus_method_invocation_return_gerror (invocation, error);
g_clear_error (&error);
g_bytes_unref (formats);
return TRUE;
}
}
static gboolean
handle_create_source_input (PinosClient1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_possible_formats,
GVariant *arg_properties,
gpointer user_data)
{
PinosClient *client = user_data;
PinosClientPrivate *priv = client->priv;
PinosSource *source;
PinosSourceOutput *input;
const gchar *source_input_path, *sender;
GBytes *formats;
GError *error = NULL;
PinosProperties *props;
sender = g_dbus_method_invocation_get_sender (invocation);
if (g_strcmp0 (pinos_client_get_sender (client), sender) != 0)
goto not_allowed;
formats = g_bytes_new (arg_possible_formats, strlen (arg_possible_formats) + 1);
props = pinos_properties_from_variant (arg_properties);
source = pinos_client_source_new (priv->daemon, formats);
if (source == NULL)
goto no_source;
g_object_set_data_full (G_OBJECT (client),
pinos_source_get_object_path (PINOS_SOURCE (source)),
source,
g_object_unref);
sender = g_dbus_method_invocation_get_sender (invocation);
input = pinos_client_source_get_source_input (PINOS_CLIENT_SOURCE (source),
priv->object_path,
formats,
props,
priv->object_path,
&error);
if (input == NULL)
goto no_input;
source_input_path = pinos_source_output_get_object_path (input);
priv->outputs = g_list_prepend (priv->outputs, input);
g_signal_connect (input,
"remove",
(GCallback) handle_remove_source_output,
client);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(o)",
source_input_path));
return TRUE;
/* ERRORS */
not_allowed:
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pinos.Error", "not client owner");
return TRUE;
}
no_source:
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pinos.Error", "Can't create source");
g_bytes_unref (formats);
pinos_properties_free (props);
return TRUE;
}
no_input:
{
g_dbus_method_invocation_return_gerror (invocation, error);
g_clear_error (&error);
g_bytes_unref (formats);
pinos_properties_free (props);
return TRUE;
}
}
static gboolean
handle_disconnect (PinosClient1 *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
PinosClient *client = user_data;
g_signal_emit (client, signals[SIGNAL_DISCONNECT], 0, NULL);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("()"));
return TRUE;
}
static void
client_register_object (PinosClient *client,
const gchar *prefix)
{
PinosClientPrivate *priv = client->priv;
PinosDaemon *daemon = priv->daemon;
PinosObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/client", prefix);
skel = pinos_object_skeleton_new (name);
g_free (name);
priv->client1 = pinos_client1_skeleton_new ();
pinos_client1_set_name (priv->client1, priv->sender);
pinos_client1_set_properties (priv->client1, pinos_properties_to_variant (priv->properties));
g_signal_connect (priv->client1, "handle-create-source-output",
(GCallback) handle_create_source_output,
client);
g_signal_connect (priv->client1, "handle-create-source-input",
(GCallback) handle_create_source_input,
client);
g_signal_connect (priv->client1, "handle-disconnect",
(GCallback) handle_disconnect,
client);
pinos_object_skeleton_set_client1 (skel, priv->client1);
g_free (priv->object_path);
priv->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
}
static void
client_unregister_object (PinosClient *client)
{
PinosClientPrivate *priv = client->priv;
PinosDaemon *daemon = priv->daemon;
g_clear_object (&priv->client1);
pinos_daemon_unexport (daemon, priv->object_path);
g_free (priv->object_path);
}
static void
do_remove_output (PinosSourceOutput *output,
PinosClient *client)
{
pinos_source_output_remove (output);
}
static void
pinos_client_dispose (GObject * object)
{
PinosClient *client = PINOS_CLIENT (object);
PinosClientPrivate *priv = client->priv;
g_list_foreach (priv->outputs, (GFunc) do_remove_output, client);
client_unregister_object (client);
G_OBJECT_CLASS (pinos_client_parent_class)->dispose (object);
}
static void
pinos_client_finalize (GObject * object)
{
PinosClient *client = PINOS_CLIENT (object);
PinosClientPrivate *priv = client->priv;
if (priv->properties)
pinos_properties_free (priv->properties);
G_OBJECT_CLASS (pinos_client_parent_class)->finalize (object);
}
static void
pinos_client_constructed (GObject * object)
{
PinosClient *client = PINOS_CLIENT (object);
PinosClientPrivate *priv = client->priv;
client_register_object (client, priv->object_path);
G_OBJECT_CLASS (pinos_client_parent_class)->constructed (object);
}
static void
pinos_client_class_init (PinosClientClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosClientPrivate));
gobject_class->constructed = pinos_client_constructed;
gobject_class->dispose = pinos_client_dispose;
gobject_class->finalize = pinos_client_finalize;
gobject_class->set_property = pinos_client_set_property;
gobject_class->get_property = pinos_client_get_property;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The daemon",
PINOS_TYPE_DAEMON,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SENDER,
g_param_spec_string ("sender",
"Sender",
"The sender",
NULL,
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_PROPERTIES,
g_param_spec_boxed ("properties",
"Properties",
"Client properties",
PINOS_TYPE_PROPERTIES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
signals[SIGNAL_DISCONNECT] = g_signal_new ("disconnect",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE,
0,
G_TYPE_NONE);
}
static void
pinos_client_init (PinosClient * client)
{
client->priv = PINOS_CLIENT_GET_PRIVATE (client);
}
/**
* pinos_client_new:
* @daemon: a #PinosDaemon
* @sender: the sender id
* @prefix: a prefix
* @properties: extra client properties
*
* Make a new #PinosClient object and register it to @daemon under the @prefix.
*
* Returns: a new #PinosClient
*/
PinosClient *
pinos_client_new (PinosDaemon *daemon,
const gchar *sender,
const gchar *prefix,
PinosProperties *properties)
{
g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL);
g_return_val_if_fail (g_variant_is_object_path (prefix), NULL);
return g_object_new (PINOS_TYPE_CLIENT, "daemon", daemon,
"sender", sender,
"object-path", prefix,
"properties", properties,
NULL);
}
/**
* pinos_client_get_sender:
* @client: a #PinosClient
*
* Get the sender of @client.
*
* Returns: the sender of @client
*/
const gchar *
pinos_client_get_sender (PinosClient *client)
{
PinosClientPrivate *priv;
g_return_val_if_fail (PINOS_IS_CLIENT (client), NULL);
priv = client->priv;
return priv->sender;
}
/**
* pinos_client_get_object_path:
* @client: a #PinosClient
*
* Get the object path of @client.
*
* Returns: the object path of @client
*/
const gchar *
pinos_client_get_object_path (PinosClient *client)
{
PinosClientPrivate *priv;
g_return_val_if_fail (PINOS_IS_CLIENT (client), NULL);
priv = client->priv;
return priv->object_path;
}

75
pinos/server/client.h Normal file
View file

@ -0,0 +1,75 @@
/* Pinos
* 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 __PINOS_CLIENT_H__
#define __PINOS_CLIENT_H__
#include <glib-object.h>
#include <pinos/server/daemon.h>
G_BEGIN_DECLS
#define PINOS_TYPE_CLIENT (pinos_client_get_type ())
#define PINOS_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_CLIENT))
#define PINOS_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_CLIENT))
#define PINOS_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_CLIENT, PinosClientClass))
#define PINOS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_CLIENT, PinosClient))
#define PINOS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_CLIENT, PinosClientClass))
#define PINOS_CLIENT_CAST(obj) ((PinosClient*)(obj))
#define PINOS_CLIENT_CLASS_CAST(klass) ((PinosClientClass*)(klass))
typedef struct _PinosClient PinosClient;
typedef struct _PinosClientClass PinosClientClass;
typedef struct _PinosClientPrivate PinosClientPrivate;
/**
* PinosClient:
*
* Pinos client object class.
*/
struct _PinosClient {
GObject object;
PinosClientPrivate *priv;
};
/**
* PinosClientClass:
*
* Pinos client object class.
*/
struct _PinosClientClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pinos_client_get_type (void);
PinosClient * pinos_client_new (PinosDaemon *daemon,
const gchar *sender,
const gchar *prefix,
PinosProperties *properties);
const gchar * pinos_client_get_sender (PinosClient *client);
const gchar * pinos_client_get_object_path (PinosClient *client);
G_END_DECLS
#endif /* __PINOS_CLIENT_H__ */

514
pinos/server/daemon.c Normal file
View file

@ -0,0 +1,514 @@
/* Pinos
* 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 "pinos/client/pinos.h"
#include "pinos/server/daemon.h"
#include "pinos/server/client.h"
#include "pinos/dbus/org-pinos.h"
#define PINOS_DAEMON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_DAEMON, PinosDaemonPrivate))
struct _PinosDaemonPrivate
{
guint id;
GDBusConnection *connection;
GDBusObjectManagerServer *server_manager;
GList *sources;
GHashTable *senders;
PinosProperties *properties;
};
enum
{
PROP_0,
PROP_PROPERTIES,
};
typedef struct {
guint id;
gchar *sender;
PinosDaemon *daemon;
GList *objects;
} SenderData;
static void
client_name_appeared_handler (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
SenderData *data = user_data;
PinosDaemonPrivate *priv = data->daemon->priv;
g_hash_table_insert (priv->senders, data->sender, data);
if (!g_strcmp0 (name, g_dbus_connection_get_unique_name (connection)))
return;
}
static void
client_name_vanished_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
SenderData *data = user_data;
g_bus_unwatch_name (data->id);
}
static void
data_free (SenderData *data)
{
g_list_free_full (data->objects, g_object_unref);
g_hash_table_remove (data->daemon->priv->senders, data->sender);
g_free (data->sender);
g_free (data);
}
static SenderData *
sender_data_new (PinosDaemon *daemon,
const gchar *sender)
{
PinosDaemonPrivate *priv = daemon->priv;
SenderData *data;
data = g_new0 (SenderData, 1);
data->daemon = daemon;
data->sender = g_strdup (sender);
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,
(GDestroyNotify) data_free);
return data;
}
static void
handle_disconnect_client (PinosClient *client,
gpointer user_data)
{
PinosDaemon *daemon = user_data;
PinosDaemonPrivate *priv = daemon->priv;
const gchar *sender;
SenderData *data;
sender = pinos_client_get_sender (client);
data = g_hash_table_lookup (priv->senders, sender);
if (data == NULL)
return;
data->objects = g_list_remove (data->objects, client);
g_object_unref (client);
}
static gboolean
handle_connect_client (PinosDaemon1 *interface,
GDBusMethodInvocation *invocation,
GVariant *arg_properties,
gpointer user_data)
{
PinosDaemon *daemon = user_data;
PinosDaemonPrivate *priv = daemon->priv;
PinosClient *client;
const gchar *sender, *object_path;
SenderData *data;
PinosProperties *props;
sender = g_dbus_method_invocation_get_sender (invocation);
props = pinos_properties_from_variant (arg_properties);
client = pinos_client_new (daemon, sender, PINOS_DBUS_OBJECT_PREFIX, props);
pinos_properties_free (props);
g_signal_connect (client, "disconnect", (GCallback) handle_disconnect_client, daemon);
data = g_hash_table_lookup (priv->senders, sender);
if (data == NULL)
data = sender_data_new (daemon, sender);
data->objects = g_list_prepend (data->objects, client);
object_path = pinos_client_get_object_path (client);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(o)", object_path));
return TRUE;
}
static void
export_server_object (PinosDaemon *daemon,
GDBusObjectManagerServer *manager)
{
PinosDaemonPrivate *priv = daemon->priv;
PinosObjectSkeleton *skel;
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SERVER);
{
PinosDaemon1 *iface;
iface = pinos_daemon1_skeleton_new ();
g_signal_connect (iface, "handle-connect-client", (GCallback) handle_connect_client, daemon);
pinos_daemon1_set_user_name (iface, g_get_user_name ());
pinos_daemon1_set_host_name (iface, g_get_host_name ());
pinos_daemon1_set_version (iface, PACKAGE_VERSION);
pinos_daemon1_set_name (iface, PACKAGE_NAME);
pinos_daemon1_set_cookie (iface, g_random_int());
pinos_daemon1_set_properties (iface, pinos_properties_to_variant (priv->properties));
pinos_object_skeleton_set_daemon1 (skel, iface);
g_object_unref (iface);
}
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
}
static void
bus_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PinosDaemon *daemon = user_data;
PinosDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager = priv->server_manager;
priv->connection = connection;
export_server_object (daemon, manager);
g_dbus_object_manager_server_set_connection (manager, connection);
}
static void
name_acquired_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void
name_lost_handler (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
PinosDaemon *daemon = user_data;
PinosDaemonPrivate *priv = daemon->priv;
GDBusObjectManagerServer *manager = priv->server_manager;
g_dbus_object_manager_server_unexport (manager, PINOS_DBUS_OBJECT_SERVER);
g_dbus_object_manager_server_set_connection (manager, connection);
priv->connection = connection;
}
/**
* pinos_daemon_new:
* @properties: #PinosProperties
*
* Make a new #PinosDaemon object with given @properties
*
* Returns: a new #PinosDaemon
*/
PinosDaemon *
pinos_daemon_new (PinosProperties *properties)
{
return g_object_new (PINOS_TYPE_DAEMON, "properties", properties, NULL);
}
/**
* pinos_daemon_start:
* @daemon: a #PinosDaemon
*
* Start the @daemon.
*/
void
pinos_daemon_start (PinosDaemon *daemon)
{
PinosDaemonPrivate *priv;
g_return_if_fail (PINOS_IS_DAEMON (daemon));
priv = daemon->priv;
g_return_if_fail (priv->id == 0);
priv->id = g_bus_own_name (G_BUS_TYPE_SESSION,
PINOS_DBUS_SERVICE,
G_BUS_NAME_OWNER_FLAGS_REPLACE,
bus_acquired_handler,
name_acquired_handler,
name_lost_handler,
daemon,
NULL);
}
/**
* pinos_daemon_stop:
* @daemon: a #PinosDaemon
*
* Stop the @daemon.
*/
void
pinos_daemon_stop (PinosDaemon *daemon)
{
PinosDaemonPrivate *priv = daemon->priv;
g_return_if_fail (PINOS_IS_DAEMON (daemon));
if (priv->id != 0) {
g_bus_unown_name (priv->id);
priv->id = 0;
}
}
/**
* pinos_daemon_export_uniquely:
* @daemon: a #PinosDaemon
* @skel: a #GDBusObjectSkeleton
*
* Export @skel with @daemon with a unique name
*
* Returns: the unique named used to export @skel.
*/
gchar *
pinos_daemon_export_uniquely (PinosDaemon *daemon,
GDBusObjectSkeleton *skel)
{
g_return_val_if_fail (PINOS_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)));
}
/**
* pinos_daemon_unexport:
* @daemon: a #PinosDaemon
* @object_path: an object path
*
* Unexport the object on @object_path
*/
void
pinos_daemon_unexport (PinosDaemon *daemon,
const gchar *object_path)
{
g_return_if_fail (PINOS_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);
}
/**
* pinos_daemon_add_source:
* @daemon: a #PinosDaemon
* @source: a #PinosSource
*
* Add @source to @daemon.
*/
void
pinos_daemon_add_source (PinosDaemon *daemon,
PinosSource *source)
{
PinosDaemonPrivate *priv;
g_return_if_fail (PINOS_IS_DAEMON (daemon));
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = daemon->priv;
priv->sources = g_list_prepend (priv->sources, source);
}
/**
* pinos_daemon_remove_source:
* @daemon: a #PinosDaemon
* @source: a #PinosSource
*
* Remove @source from @daemon.
*/
void
pinos_daemon_remove_source (PinosDaemon *daemon,
PinosSource *source)
{
PinosDaemonPrivate *priv;
g_return_if_fail (PINOS_IS_DAEMON (daemon));
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = daemon->priv;
priv->sources = g_list_remove (priv->sources, source);
}
/**
* pinos_daemon_find_source:
* @daemon: a #PinosDaemon
* @name: a source name
* @props: source properties
* @format_filter: a format filter
* @error: location for an error
*
* Find the best source in @daemon that matches the given parameters.
*
* Returns: a #PinosSource or %NULL when no source could be found.
*/
PinosSource *
pinos_daemon_find_source (PinosDaemon *daemon,
const gchar *name,
PinosProperties *props,
GBytes *format_filter,
GError **error)
{
PinosDaemonPrivate *priv;
PinosSource *best = NULL;
GList *walk;
g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL);
priv = daemon->priv;
for (walk = priv->sources; walk; walk = g_list_next (walk)) {
PinosSource *s = walk->data;
if (name == NULL) {
best = s;
break;
}
else if (g_str_has_suffix (pinos_source_get_object_path (s), name))
best = s;
}
if (best == NULL) {
if (error)
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_NOT_FOUND,
"Source not found");
}
return best;
}
G_DEFINE_TYPE (PinosDaemon, pinos_daemon, G_TYPE_OBJECT);
static void
pinos_daemon_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PinosDaemon *daemon = PINOS_DAEMON (_object);
PinosDaemonPrivate *priv = daemon->priv;
switch (prop_id) {
case PROP_PROPERTIES:
g_value_set_boxed (value, priv->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (daemon, prop_id, pspec);
break;
}
}
static void
pinos_daemon_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PinosDaemon *daemon = PINOS_DAEMON (_object);
PinosDaemonPrivate *priv = daemon->priv;
switch (prop_id) {
case PROP_PROPERTIES:
if (priv->properties)
pinos_properties_free (priv->properties);
priv->properties = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (daemon, prop_id, pspec);
break;
}
}
static void
pinos_daemon_dispose (GObject * object)
{
PinosDaemon *daemon = PINOS_DAEMON_CAST (object);
pinos_daemon_stop (daemon);
G_OBJECT_CLASS (pinos_daemon_parent_class)->dispose (object);
}
static void
pinos_daemon_finalize (GObject * object)
{
PinosDaemon *daemon = PINOS_DAEMON_CAST (object);
PinosDaemonPrivate *priv = daemon->priv;
g_clear_object (&priv->server_manager);
G_OBJECT_CLASS (pinos_daemon_parent_class)->finalize (object);
}
static void
pinos_daemon_class_init (PinosDaemonClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosDaemonPrivate));
gobject_class->dispose = pinos_daemon_dispose;
gobject_class->finalize = pinos_daemon_finalize;
gobject_class->set_property = pinos_daemon_set_property;
gobject_class->get_property = pinos_daemon_get_property;
g_object_class_install_property (gobject_class,
PROP_PROPERTIES,
g_param_spec_boxed ("properties",
"Properties",
"Client properties",
PINOS_TYPE_PROPERTIES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
}
static void
pinos_daemon_init (PinosDaemon * daemon)
{
PinosDaemonPrivate *priv = daemon->priv = PINOS_DAEMON_GET_PRIVATE (daemon);
priv->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX);
priv->senders = g_hash_table_new (g_str_hash, g_str_equal);
}

84
pinos/server/daemon.h Normal file
View file

@ -0,0 +1,84 @@
/* Pinos
* 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 __PINOS_DAEMON_H__
#define __PINOS_DAEMON_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define PINOS_TYPE_DAEMON (pinos_daemon_get_type ())
#define PINOS_IS_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_DAEMON))
#define PINOS_IS_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_DAEMON))
#define PINOS_DAEMON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_DAEMON, PinosDaemonClass))
#define PINOS_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_DAEMON, PinosDaemon))
#define PINOS_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_DAEMON, PinosDaemonClass))
#define PINOS_DAEMON_CAST(obj) ((PinosDaemon*)(obj))
#define PINOS_DAEMON_CLASS_CAST(klass) ((PinosDaemonClass*)(klass))
typedef struct _PinosDaemon PinosDaemon;
typedef struct _PinosDaemonClass PinosDaemonClass;
typedef struct _PinosDaemonPrivate PinosDaemonPrivate;
#include <pinos/server/source.h>
#include <pinos/client/properties.h>
/**
* PinosDaemon:
*
* Pinos daemon object class.
*/
struct _PinosDaemon {
GObject object;
PinosDaemonPrivate *priv;
};
/**
* PinosDaemonClass:
*
* Pinos daemon object class.
*/
struct _PinosDaemonClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pinos_daemon_get_type (void);
PinosDaemon * pinos_daemon_new (PinosProperties *properties);
void pinos_daemon_start (PinosDaemon *daemon);
void pinos_daemon_stop (PinosDaemon *daemon);
gchar * pinos_daemon_export_uniquely (PinosDaemon *daemon, GDBusObjectSkeleton *skel);
void pinos_daemon_unexport (PinosDaemon *daemon, const gchar *name);
void pinos_daemon_add_source (PinosDaemon *daemon, PinosSource *source);
void pinos_daemon_remove_source (PinosDaemon *daemon, PinosSource *source);
PinosSource * pinos_daemon_find_source (PinosDaemon *daemon,
const gchar *name,
PinosProperties *props,
GBytes *format_filter,
GError **error);
G_END_DECLS
#endif /* __PINOS_DAEMON_H__ */

View file

@ -0,0 +1,508 @@
/* Pinos
* 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 <string.h>
#include <sys/socket.h>
#include <gio/gunixfdlist.h>
#include "pinos/client/enumtypes.h"
#include "pinos/server/daemon.h"
#include "pinos/server/source-output.h"
#include "pinos/dbus/org-pinos.h"
struct _PinosSourceOutputPrivate
{
PinosDaemon *daemon;
PinosSourceOutput1 *iface;
gchar *object_path;
gchar *client_path;
gchar *source_path;
GBytes *possible_formats;
PinosProperties *properties;
GBytes *requested_format;
PinosSourceOutputState state;
GBytes *format;
GSocket *socket;
};
#define PINOS_SOURCE_OUTPUT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SOURCE_OUTPUT, PinosSourceOutputPrivate))
G_DEFINE_TYPE (PinosSourceOutput, pinos_source_output, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH,
PROP_CLIENT_PATH,
PROP_SOURCE_PATH,
PROP_POSSIBLE_FORMATS,
PROP_PROPERTIES,
PROP_REQUESTED_FORMAT,
PROP_FORMAT,
PROP_SOCKET,
PROP_STATE,
};
enum
{
SIGNAL_REMOVE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void
pinos_source_output_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (_object);
PinosSourceOutputPrivate *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_CLIENT_PATH:
g_value_set_string (value, priv->client_path);
break;
case PROP_SOURCE_PATH:
g_value_set_string (value, priv->source_path);
break;
case PROP_POSSIBLE_FORMATS:
g_value_set_boxed (value, priv->possible_formats);
break;
case PROP_PROPERTIES:
g_value_set_boxed (value, priv->properties);
break;
case PROP_REQUESTED_FORMAT:
g_value_set_boxed (value, priv->requested_format);
break;
case PROP_FORMAT:
g_value_set_boxed (value, priv->format);
break;
case PROP_SOCKET:
g_value_set_object (value, priv->socket);
break;
case PROP_STATE:
g_value_set_uint (value, priv->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
break;
}
}
static void
pinos_source_output_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (_object);
PinosSourceOutputPrivate *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;
case PROP_CLIENT_PATH:
priv->client_path = g_value_dup_string (value);
g_object_set (priv->iface, "client", priv->client_path, NULL);
break;
case PROP_SOURCE_PATH:
priv->source_path = g_value_dup_string (value);
g_object_set (priv->iface, "source", priv->source_path, NULL);
break;
case PROP_POSSIBLE_FORMATS:
if (priv->possible_formats)
g_bytes_unref (priv->possible_formats);
priv->possible_formats = g_value_dup_boxed (value);
g_object_set (priv->iface, "possible-formats",
g_bytes_get_data (priv->possible_formats, NULL), NULL);
break;
case PROP_PROPERTIES:
if (priv->properties)
pinos_properties_free (priv->properties);
priv->properties = g_value_dup_boxed (value);
g_object_set (priv->iface, "properties",
pinos_properties_to_variant (priv->properties), NULL);
break;
case PROP_FORMAT:
if (priv->format)
g_bytes_unref (priv->format);
priv->format = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
break;
}
}
static gboolean
handle_start (PinosSourceOutput1 *interface,
GDBusMethodInvocation *invocation,
const gchar *arg_requested_format,
gpointer user_data)
{
PinosSourceOutput *output = user_data;
PinosSourceOutputPrivate *priv = output->priv;
GUnixFDList *fdlist;
gint fd[2];
priv->state = PINOS_SOURCE_OUTPUT_STATE_STARTING;
priv->requested_format = g_bytes_new (arg_requested_format,
strlen (arg_requested_format) + 1);
socketpair (AF_UNIX, SOCK_STREAM, 0, fd);
priv->socket = g_socket_new_from_fd (fd[0], NULL);
g_object_notify (G_OBJECT (output), "socket");
/* the notify of the socket above should configure the format */
if (priv->format == NULL)
goto no_format;
priv->state = PINOS_SOURCE_OUTPUT_STATE_STREAMING;
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 ("(hs@a{sv})",
0,
g_bytes_get_data (priv->format, NULL),
pinos_properties_to_variant (priv->properties)),
fdlist);
g_object_set (priv->iface,
"format", g_bytes_get_data (priv->format, NULL),
"state", priv->state,
NULL);
return TRUE;
/* error */
no_format:
{
g_dbus_method_invocation_return_dbus_error (invocation,
"org.pinos.Error", "No format");
close (fd[0]);
close (fd[1]);
g_clear_pointer (&priv->requested_format, g_bytes_unref);
g_clear_object (&priv->socket);
return TRUE;
}
}
static void
clear_socket (PinosSourceOutput *output)
{
PinosSourceOutputPrivate *priv = output->priv;
g_clear_object (&priv->socket);
g_clear_pointer (&priv->requested_format, g_bytes_unref);
g_clear_pointer (&priv->format, g_bytes_unref);
}
static void
stop_transfer (PinosSourceOutput *output)
{
PinosSourceOutputPrivate *priv = output->priv;
if (priv->socket) {
clear_socket (output);
g_object_notify (G_OBJECT (output), "socket");
}
priv->state = PINOS_SOURCE_OUTPUT_STATE_IDLE;
g_object_set (priv->iface,
"state", priv->state,
NULL);
}
static gboolean
handle_stop (PinosSourceOutput1 *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
PinosSourceOutput *output = user_data;
stop_transfer (output);
g_dbus_method_invocation_return_value (invocation, NULL);
return TRUE;
}
static gboolean
handle_remove (PinosSourceOutput1 *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
PinosSourceOutput *output = user_data;
stop_transfer (output);
g_signal_emit (output, signals[SIGNAL_REMOVE], 0, NULL);
g_dbus_method_invocation_return_value (invocation, NULL);
return TRUE;
}
static void
output_register_object (PinosSourceOutput *output,
const gchar *prefix)
{
PinosSourceOutputPrivate *priv = output->priv;
PinosObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf ("%s/output", prefix);
skel = pinos_object_skeleton_new (name);
g_free (name);
pinos_object_skeleton_set_source_output1 (skel, priv->iface);
g_free (priv->object_path);
priv->object_path = pinos_daemon_export_uniquely (priv->daemon, G_DBUS_OBJECT_SKELETON (skel));
}
static void
output_unregister_object (PinosSourceOutput *output)
{
PinosSourceOutputPrivate *priv = output->priv;
pinos_daemon_unexport (priv->daemon, priv->object_path);
}
static void
pinos_source_output_dispose (GObject * object)
{
PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object);
clear_socket (output);
output_unregister_object (output);
G_OBJECT_CLASS (pinos_source_output_parent_class)->dispose (object);
}
static void
pinos_source_output_finalize (GObject * object)
{
PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object);
PinosSourceOutputPrivate *priv = output->priv;
g_clear_object (&priv->daemon);
g_clear_object (&priv->iface);
g_free (priv->client_path);
g_free (priv->object_path);
g_free (priv->source_path);
G_OBJECT_CLASS (pinos_source_output_parent_class)->finalize (object);
}
static void
pinos_source_output_constructed (GObject * object)
{
PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object);
PinosSourceOutputPrivate *priv = output->priv;
output_register_object (output, priv->object_path);
G_OBJECT_CLASS (pinos_source_output_parent_class)->constructed (object);
}
static void
pinos_source_output_class_init (PinosSourceOutputClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosSourceOutputPrivate));
gobject_class->constructed = pinos_source_output_constructed;
gobject_class->dispose = pinos_source_output_dispose;
gobject_class->finalize = pinos_source_output_finalize;
gobject_class->set_property = pinos_source_output_set_property;
gobject_class->get_property = pinos_source_output_get_property;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The Daemon",
PINOS_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_CLIENT_PATH,
g_param_spec_string ("client-path",
"Client Path",
"The client object path",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SOURCE_PATH,
g_param_spec_string ("source-path",
"Source Path",
"The source object path",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_POSSIBLE_FORMATS,
g_param_spec_boxed ("possible-formats",
"Possible Formats",
"The possbile formats of the stream",
G_TYPE_BYTES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_PROPERTIES,
g_param_spec_boxed ("properties",
"Properties",
"Extra properties of the stream",
PINOS_TYPE_PROPERTIES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_REQUESTED_FORMAT,
g_param_spec_boxed ("requested-format",
"Requested Format",
"The requested format of the stream",
G_TYPE_BYTES,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_FORMAT,
g_param_spec_boxed ("format",
"Format",
"The format of the stream",
G_TYPE_BYTES,
G_PARAM_READWRITE |
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));
signals[SIGNAL_REMOVE] = g_signal_new ("remove",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE,
0,
G_TYPE_NONE);
}
static void
pinos_source_output_init (PinosSourceOutput * output)
{
PinosSourceOutputPrivate *priv = output->priv = PINOS_SOURCE_OUTPUT_GET_PRIVATE (output);
priv->iface = pinos_source_output1_skeleton_new ();
g_signal_connect (priv->iface, "handle-start", (GCallback) handle_start, output);
g_signal_connect (priv->iface, "handle-stop", (GCallback) handle_stop, output);
g_signal_connect (priv->iface, "handle-remove", (GCallback) handle_remove, output);
priv->state = PINOS_SOURCE_OUTPUT_STATE_IDLE;
g_object_set (priv->iface, "state", priv->state, NULL);
}
void
pinos_source_output_remove (PinosSourceOutput *output)
{
stop_transfer (output);
g_signal_emit (output, signals[SIGNAL_REMOVE], 0, NULL);
}
const gchar *
pinos_source_output_get_object_path (PinosSourceOutput *output)
{
PinosSourceOutputPrivate *priv;
g_return_val_if_fail (PINOS_IS_SOURCE_OUTPUT (output), NULL);
priv = output->priv;
return priv->object_path;
}

View file

@ -0,0 +1,69 @@
/* Pinos
* 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 __PINOS_SOURCE_OUTPUT_H__
#define __PINOS_SOURCE_OUTPUT_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define PINOS_TYPE_SOURCE_OUTPUT (pinos_source_output_get_type ())
#define PINOS_IS_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SOURCE_OUTPUT))
#define PINOS_IS_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SOURCE_OUTPUT))
#define PINOS_SOURCE_OUTPUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SOURCE_OUTPUT, PinosSourceOutputClass))
#define PINOS_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SOURCE_OUTPUT, PinosSourceOutput))
#define PINOS_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SOURCE_OUTPUT, PinosSourceOutputClass))
#define PINOS_SOURCE_OUTPUT_CAST(obj) ((PinosSourceOutput*)(obj))
#define PINOS_SOURCE_OUTPUT_CLASS_CAST(klass) ((PinosSourceOutputClass*)(klass))
typedef struct _PinosSourceOutput PinosSourceOutput;
typedef struct _PinosSourceOutputClass PinosSourceOutputClass;
typedef struct _PinosSourceOutputPrivate PinosSourceOutputPrivate;
/**
* PinosSourceOutput:
*
* Pinos source output object class.
*/
struct _PinosSourceOutput {
GObject object;
PinosSourceOutputPrivate *priv;
};
/**
* PinosSourceOutputClass:
*
* Pinos source output object class.
*/
struct _PinosSourceOutputClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pinos_source_output_get_type (void);
void pinos_source_output_remove (PinosSourceOutput *output);
const gchar * pinos_source_output_get_object_path (PinosSourceOutput *output);
G_END_DECLS
#endif /* __PINOS_SOURCE_OUTPUT_H__ */

581
pinos/server/source.c Normal file
View file

@ -0,0 +1,581 @@
/* Pinos
* 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 "pinos/client/pinos.h"
#include "pinos/client/enumtypes.h"
#include "pinos/server/source.h"
#include "pinos/server/daemon.h"
#include "pinos/dbus/org-pinos.h"
#define PINOS_SOURCE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SOURCE, PinosSourcePrivate))
struct _PinosSourcePrivate
{
PinosDaemon *daemon;
PinosSource1 *iface;
gchar *object_path;
gchar *name;
PinosProperties *properties;
PinosSourceState state;
GError *error;
guint idle_timeout;
GList *outputs;
};
G_DEFINE_ABSTRACT_TYPE (PinosSource, pinos_source, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_DAEMON,
PROP_OBJECT_PATH,
PROP_NAME,
PROP_STATE,
PROP_PROPERTIES
};
static void
pinos_source_get_property (GObject *_object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PinosSource *source = PINOS_SOURCE (_object);
PinosSourcePrivate *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;
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_STATE:
g_value_set_enum (value, priv->state);
break;
case PROP_PROPERTIES:
g_value_set_boxed (value, priv->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static void
pinos_source_set_property (GObject *_object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PinosSource *source = PINOS_SOURCE (_object);
PinosSourcePrivate *priv = source->priv;
switch (prop_id) {
case PROP_DAEMON:
priv->daemon = g_value_dup_object (value);
break;
case PROP_OBJECT_PATH:
g_free (priv->object_path);
priv->object_path = g_value_dup_string (value);
break;
case PROP_NAME:
g_free (priv->name);
priv->name = g_value_dup_string (value);
break;
case PROP_PROPERTIES:
if (priv->properties)
pinos_properties_free (priv->properties);
priv->properties = g_value_dup_boxed (value);
if (priv->iface)
g_object_set (priv->iface,
"properties", priv->properties ?
pinos_properties_to_variant (priv->properties) : NULL,
NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
break;
}
}
static void
source_register_object (PinosSource *source)
{
PinosSourcePrivate *priv = source->priv;
PinosDaemon *daemon = priv->daemon;
PinosObjectSkeleton *skel;
GBytes *formats;
GVariant *variant;
formats = pinos_source_get_formats (source, NULL, NULL);
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SOURCE);
if (priv->properties)
variant = pinos_properties_to_variant (priv->properties);
else
variant = NULL;
priv->iface = pinos_source1_skeleton_new ();
g_object_set (priv->iface, "name", priv->name,
"state", priv->state,
"properties", variant,
"possible-formats", g_bytes_get_data (formats, NULL),
NULL);
pinos_object_skeleton_set_source1 (skel, priv->iface);
g_bytes_unref (formats);
g_free (priv->object_path);
priv->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
pinos_daemon_add_source (daemon, source);
return;
}
static void
source_unregister_object (PinosSource *source)
{
PinosSourcePrivate *priv = source->priv;
pinos_daemon_remove_source (priv->daemon, source);
pinos_daemon_unexport (priv->daemon, priv->object_path);
g_clear_object (&priv->iface);
}
static void
pinos_source_constructed (GObject * object)
{
PinosSource *source = PINOS_SOURCE (object);
source_register_object (source);
G_OBJECT_CLASS (pinos_source_parent_class)->constructed (object);
}
static void
do_remove_output (PinosSourceOutput *output,
gpointer user_data)
{
pinos_source_output_remove (output);
}
static void
pinos_source_dispose (GObject * object)
{
PinosSource *source = PINOS_SOURCE (object);
PinosSourcePrivate *priv = source->priv;
g_list_foreach (priv->outputs, (GFunc) do_remove_output, source);
source_unregister_object (source);
G_OBJECT_CLASS (pinos_source_parent_class)->dispose (object);
}
static void
pinos_source_finalize (GObject * object)
{
PinosSource *source = PINOS_SOURCE (object);
PinosSourcePrivate *priv = source->priv;
g_free (priv->object_path);
g_free (priv->name);
if (priv->properties)
pinos_properties_free (priv->properties);
G_OBJECT_CLASS (pinos_source_parent_class)->finalize (object);
}
static gboolean
default_set_state (PinosSource *source,
PinosSourceState state)
{
pinos_source_update_state (source, state);
return TRUE;
}
static void
handle_remove_output (PinosSourceOutput *output,
gpointer user_data)
{
PinosSource *source = user_data;
pinos_source_release_source_output (source, output);
}
static PinosSourceOutput *
default_create_source_output (PinosSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error)
{
PinosSourcePrivate *priv = source->priv;
PinosSourceOutput *output;
GBytes *possible_formats;
possible_formats = pinos_source_get_formats (source, format_filter, error);
if (possible_formats == NULL)
return NULL;
output = g_object_new (PINOS_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon,
"object-path", prefix,
"client-path", client_path,
"source-path", priv->object_path,
"possible-formats", possible_formats,
"properties", props,
NULL);
g_bytes_unref (possible_formats);
if (output == NULL)
goto no_output;
g_signal_connect (output,
"remove",
(GCallback) handle_remove_output,
source);
priv->outputs = g_list_prepend (priv->outputs, output);
return g_object_ref (output);
/* ERRORS */
no_output:
{
if (error)
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_FAILED,
"Could not create a source output");
return NULL;
}
}
static gboolean
default_release_source_output (PinosSource *source,
PinosSourceOutput *output)
{
PinosSourcePrivate *priv = source->priv;
GList *find;
find = g_list_find (priv->outputs, output);
if (find == NULL)
return FALSE;
priv->outputs = g_list_delete_link (priv->outputs, find);
g_object_unref (output);
return TRUE;
}
static void
pinos_source_class_init (PinosSourceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosSourcePrivate));
gobject_class->constructed = pinos_source_constructed;
gobject_class->dispose = pinos_source_dispose;
gobject_class->finalize = pinos_source_finalize;
gobject_class->set_property = pinos_source_set_property;
gobject_class->get_property = pinos_source_get_property;
g_object_class_install_property (gobject_class,
PROP_DAEMON,
g_param_spec_object ("daemon",
"Daemon",
"The Daemon",
PINOS_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 source name",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_STATE,
g_param_spec_enum ("state",
"State",
"The state of the source",
PINOS_TYPE_SOURCE_STATE,
PINOS_SOURCE_STATE_SUSPENDED,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_PROPERTIES,
g_param_spec_boxed ("properties",
"Properties",
"The properties of the source",
PINOS_TYPE_PROPERTIES,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
klass->set_state = default_set_state;
klass->create_source_output = default_create_source_output;
klass->release_source_output = default_release_source_output;
}
static void
pinos_source_init (PinosSource * source)
{
PinosSourcePrivate *priv = source->priv = PINOS_SOURCE_GET_PRIVATE (source);
priv->state = PINOS_SOURCE_STATE_SUSPENDED;
}
GBytes *
pinos_source_get_formats (PinosSource *source,
GBytes *filter,
GError **error)
{
PinosSourceClass *klass;
GBytes *res;
g_return_val_if_fail (PINOS_IS_SOURCE (source), NULL);
klass = PINOS_SOURCE_GET_CLASS (source);
if (klass->get_formats)
res = klass->get_formats (source, filter, error);
else {
res = NULL;
if (error)
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Format query is not supported");
}
return res;
}
static void
remove_idle_timeout (PinosSource *source)
{
PinosSourcePrivate *priv = source->priv;
if (priv->idle_timeout) {
g_source_remove (priv->idle_timeout);
priv->idle_timeout = 0;
}
}
gboolean
pinos_source_set_state (PinosSource *source,
PinosSourceState state)
{
PinosSourceClass *klass;
gboolean res;
g_return_val_if_fail (PINOS_IS_SOURCE (source), FALSE);
klass = PINOS_SOURCE_GET_CLASS (source);
remove_idle_timeout (source);
if (klass->set_state)
res = klass->set_state (source, state);
else
res = FALSE;
return res;
}
void
pinos_source_update_state (PinosSource *source,
PinosSourceState state)
{
PinosSourcePrivate *priv;
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = source->priv;
if (priv->state != state) {
priv->state = state;
pinos_source1_set_state (priv->iface, state);
g_object_notify (G_OBJECT (source), "state");
}
}
void
pinos_source_report_error (PinosSource *source,
GError *error)
{
PinosSourcePrivate *priv;
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = source->priv;
g_clear_error (&priv->error);
remove_idle_timeout (source);
priv->error = error;
priv->state = PINOS_SOURCE_STATE_ERROR;
g_debug ("got error state %s", error->message);
pinos_source1_set_state (priv->iface, priv->state);
g_object_notify (G_OBJECT (source), "state");
}
static gboolean
idle_timeout (PinosSource *source)
{
PinosSourcePrivate *priv = source->priv;
priv->idle_timeout = 0;
pinos_source_set_state (source, PINOS_SOURCE_STATE_SUSPENDED);
return G_SOURCE_REMOVE;
}
void
pinos_source_report_idle (PinosSource *source)
{
PinosSourcePrivate *priv;
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = source->priv;
pinos_source_set_state (source, PINOS_SOURCE_STATE_IDLE);
priv->idle_timeout = g_timeout_add_seconds (3,
(GSourceFunc) idle_timeout,
source);
}
void
pinos_source_report_busy (PinosSource *source)
{
g_return_if_fail (PINOS_IS_SOURCE (source));
pinos_source_set_state (source, PINOS_SOURCE_STATE_RUNNING);
}
void
pinos_source_update_possible_formats (PinosSource *source, GBytes *formats)
{
PinosSourcePrivate *priv;
g_return_if_fail (PINOS_IS_SOURCE (source));
priv = source->priv;
if (priv->iface)
g_object_set (priv->iface, "possible-formats",
g_bytes_get_data (formats, NULL),
NULL);
}
PinosSourceOutput *
pinos_source_create_source_output (PinosSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error)
{
PinosSourceClass *klass;
PinosSourceOutput *res;
g_return_val_if_fail (PINOS_IS_SOURCE (source), NULL);
klass = PINOS_SOURCE_GET_CLASS (source);
if (klass->create_source_output) {
res = klass->create_source_output (source, client_path, format_filter, props, prefix, error);
} else {
if (error) {
*error = g_error_new (G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Create SourceOutput not implemented");
}
res = NULL;
}
return res;
}
gboolean
pinos_source_release_source_output (PinosSource *source,
PinosSourceOutput *output)
{
PinosSourceClass *klass;
gboolean res;
g_return_val_if_fail (PINOS_IS_SOURCE (source), FALSE);
g_return_val_if_fail (PINOS_IS_SOURCE_OUTPUT (output), FALSE);
klass = PINOS_SOURCE_GET_CLASS (source);
if (klass->release_source_output)
res = klass->release_source_output (source, output);
else
res = FALSE;
return res;
}
const gchar *
pinos_source_get_object_path (PinosSource *source)
{
PinosSourcePrivate *priv;
g_return_val_if_fail (PINOS_IS_SOURCE (source), NULL);
priv = source->priv;
return priv->object_path;
}

110
pinos/server/source.h Normal file
View file

@ -0,0 +1,110 @@
/* Pinos
* 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 __PINOS_SOURCE_H__
#define __PINOS_SOURCE_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _PinosSource PinosSource;
typedef struct _PinosSourceClass PinosSourceClass;
typedef struct _PinosSourcePrivate PinosSourcePrivate;
#include <pinos/client/introspect.h>
#include <pinos/server/source-output.h>
#define PINOS_TYPE_SOURCE (pinos_source_get_type ())
#define PINOS_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SOURCE))
#define PINOS_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SOURCE))
#define PINOS_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SOURCE, PinosSourceClass))
#define PINOS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SOURCE, PinosSource))
#define PINOS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SOURCE, PinosSourceClass))
#define PINOS_SOURCE_CAST(obj) ((PinosSource*)(obj))
#define PINOS_SOURCE_CLASS_CAST(klass) ((PinosSourceClass*)(klass))
/**
* PinosSource:
*
* Pinos source object class.
*/
struct _PinosSource {
GObject object;
PinosSourcePrivate *priv;
};
/**
* PinosSourceClass:
* @get_formats: called to get a list of supported formats from the source
* @set_state: called to change the current state of the source
* @create_source_output: called to create a new source-output object
* @release_source_output: called to release a source-output object
*
* Pinos source object class.
*/
struct _PinosSourceClass {
GObjectClass parent_class;
GBytes * (*get_formats) (PinosSource *source,
GBytes *filter,
GError **error);
gboolean (*set_state) (PinosSource *source, PinosSourceState);
PinosSourceOutput * (*create_source_output) (PinosSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error);
gboolean (*release_source_output) (PinosSource *source,
PinosSourceOutput *output);
};
/* normal GObject stuff */
GType pinos_source_get_type (void);
const gchar * pinos_source_get_object_path (PinosSource *source);
GBytes * pinos_source_get_formats (PinosSource *source,
GBytes *filter,
GError **error);
gboolean pinos_source_set_state (PinosSource *source, PinosSourceState state);
void pinos_source_update_state (PinosSource *source, PinosSourceState state);
void pinos_source_report_error (PinosSource *source, GError *error);
void pinos_source_report_idle (PinosSource *source);
void pinos_source_report_busy (PinosSource *source);
void pinos_source_update_possible_formats (PinosSource *source, GBytes *formats);
PinosSourceOutput * pinos_source_create_source_output (PinosSource *source,
const gchar *client_path,
GBytes *format_filter,
PinosProperties *props,
const gchar *prefix,
GError **error);
gboolean pinos_source_release_source_output (PinosSource *source,
PinosSourceOutput *output);
G_END_DECLS
#endif /* __PINOS_SOURCE_H__ */