diff --git a/pinos/client/client-node.c b/pinos/client/client-node.c new file mode 100644 index 000000000..8c3156362 --- /dev/null +++ b/pinos/client/client-node.c @@ -0,0 +1,224 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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 + +#include "pinos/client/pinos.h" +#include "pinos/client/enumtypes.h" + +#include "pinos/client/context.h" +#include "pinos/client/client-node.h" +#include "pinos/client/client-port.h" + +#define PINOS_CLIENT_NODE_GET_PRIVATE(node) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((node), PINOS_TYPE_CLIENT_NODE, PinosClientNodePrivate)) + +struct _PinosClientNodePrivate +{ + PinosContext *context; + GDBusProxy *proxy; +}; + +G_DEFINE_TYPE (PinosClientNode, pinos_client_node, PINOS_TYPE_NODE); + +enum +{ + PROP_0, + PROP_CONTEXT, + PROP_PROXY, +}; + +static gboolean +client_node_set_state (PinosNode *node, + PinosNodeState state) +{ + return FALSE; +} + +static void +client_node_create_port (PinosNode *node, + PinosDirection direction, + const gchar *name, + GBytes *possible_formats, + PinosProperties *props, + GTask *task) +{ + PinosPort *port; + + port = g_object_new (PINOS_TYPE_CLIENT_PORT, + "node", node, + "direction", direction, + "name", name, + "possible-formats", possible_formats, + "properties", props, + NULL); + + g_task_return_pointer (task, port, (GDestroyNotify) g_object_unref); +} + +static void +client_node_remove_port (PinosNode *node, + PinosPort *port) +{ +} + +static void +pinos_client_node_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PinosClientNode *node = PINOS_CLIENT_NODE (_object); + PinosClientNodePrivate *priv = node->priv; + + switch (prop_id) { + case PROP_CONTEXT: + g_value_set_object (value, priv->context); + break; + + case PROP_PROXY: + g_value_set_object (value, priv->proxy); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec); + break; + } +} + +static void +pinos_client_node_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PinosClientNode *node = PINOS_CLIENT_NODE (_object); + PinosClientNodePrivate *priv = node->priv; + + switch (prop_id) { + case PROP_CONTEXT: + priv->context = g_value_dup_object (value); + break; + + case PROP_PROXY: + priv->proxy = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec); + break; + } +} + +static void +pinos_client_node_constructed (GObject * obj) +{ + PinosClientNode *node = PINOS_CLIENT_NODE (obj); + + g_debug ("client-node %p: constructed", node); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->constructed (obj); +} + +static void +pinos_client_node_dispose (GObject * obj) +{ + PinosClientNode *node = PINOS_CLIENT_NODE (obj); + + g_debug ("client-node %p: dispose", node); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->dispose (obj); +} + +static void +pinos_client_node_finalize (GObject * obj) +{ + PinosClientNode *node = PINOS_CLIENT_NODE (obj); + PinosClientNodePrivate *priv = node->priv; + + g_debug ("client-node %p: finalize", node); + g_clear_object (&priv->context); + g_clear_object (&priv->proxy); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->finalize (obj); +} + +static void +pinos_client_node_class_init (PinosClientNodeClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + PinosNodeClass *node_class = PINOS_NODE_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosClientNodePrivate)); + + gobject_class->constructed = pinos_client_node_constructed; + gobject_class->dispose = pinos_client_node_dispose; + gobject_class->finalize = pinos_client_node_finalize; + gobject_class->set_property = pinos_client_node_set_property; + gobject_class->get_property = pinos_client_node_get_property; + + g_object_class_install_property (gobject_class, + PROP_CONTEXT, + g_param_spec_object ("context", + "Context", + "The Context", + PINOS_TYPE_CONTEXT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_PROXY, + g_param_spec_object ("proxy", + "Proxy", + "The Proxy", + G_TYPE_DBUS_PROXY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + node_class->set_state = client_node_set_state; + node_class->create_port = client_node_create_port; + node_class->remove_port = client_node_remove_port; +} + +static void +pinos_client_node_init (PinosClientNode * node) +{ + node->priv = PINOS_CLIENT_NODE_GET_PRIVATE (node); + + g_debug ("client-node %p: new", node); +} + +/** + * pinos_client_node_get_context: + * @node: a #PinosClientNode + * + * Get the context of @node. + * + * Returns: the context of @node. + */ +PinosContext * +pinos_client_node_get_context (PinosClientNode *node) +{ + PinosClientNodePrivate *priv; + + g_return_val_if_fail (PINOS_IS_CLIENT_NODE (node), NULL); + priv = node->priv; + + return priv->context; +} diff --git a/pinos/client/client-node.h b/pinos/client/client-node.h new file mode 100644 index 000000000..d18172341 --- /dev/null +++ b/pinos/client/client-node.h @@ -0,0 +1,71 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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_NODE_H__ +#define __PINOS_CLIENT_NODE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PinosClientNode PinosClientNode; +typedef struct _PinosClientNodeClass PinosClientNodeClass; +typedef struct _PinosClientNodePrivate PinosClientNodePrivate; + +#include +#include + +#define PINOS_TYPE_CLIENT_NODE (pinos_client_node_get_type ()) +#define PINOS_IS_CLIENT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_CLIENT_NODE)) +#define PINOS_IS_CLIENT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_CLIENT_NODE)) +#define PINOS_CLIENT_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_CLIENT_NODE, PinosClientNodeClass)) +#define PINOS_CLIENT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_CLIENT_NODE, PinosClientNode)) +#define PINOS_CLIENT_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_CLIENT_NODE, PinosClientNodeClass)) +#define PINOS_CLIENT_NODE_CAST(obj) ((PinosClientNode*)(obj)) +#define PINOS_CLIENT_NODE_CLASS_CAST(klass) ((PinosClientNodeClass*)(klass)) + +/** + * PinosClientNode: + * + * Pinos client node class. + */ +struct _PinosClientNode { + PinosNodeClass object; + + PinosClientNodePrivate *priv; +}; + +/** + * PinosClientNodeClass: + * @set_state: called to change the current state of the client node + * + * Pinos client node class. + */ +struct _PinosClientNodeClass { + PinosNodeClass parent_class; +}; + +/* normal GObject stuff */ +GType pinos_client_node_get_type (void); + +PinosContext * pinos_client_node_get_context (PinosClientNode *node); + +G_END_DECLS + +#endif /* __PINOS_CLIENT_NODE_H__ */ diff --git a/pinos/client/client-port.c b/pinos/client/client-port.c new file mode 100644 index 000000000..f5701f861 --- /dev/null +++ b/pinos/client/client-port.c @@ -0,0 +1,123 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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 + +#include +#include + +#include "pinos/client/pinos.h" +#include "pinos/client/enumtypes.h" + +#include "pinos/client/client-port.h" + +#define PINOS_CLIENT_PORT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_CLIENT_PORT, PinosClientPortPrivate)) + +struct _PinosClientPortPrivate +{ + gint foo; +}; + +G_DEFINE_TYPE (PinosClientPort, pinos_client_port, PINOS_TYPE_PORT); + +enum +{ + PROP_0, +}; + +static void +pinos_client_port_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PinosClientPort *port = PINOS_CLIENT_PORT (_object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (port, prop_id, pspec); + break; + } +} + +static void +pinos_client_port_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PinosClientPort *port = PINOS_CLIENT_PORT (_object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (port, prop_id, pspec); + break; + } +} + +static void +pinos_client_port_constructed (GObject * object) +{ + PinosClientPort *port = PINOS_CLIENT_PORT (object); + + g_debug ("client-port %p: constructed", port); + + G_OBJECT_CLASS (pinos_client_port_parent_class)->constructed (object); +} + +static void +pinos_client_port_dispose (GObject * object) +{ + PinosClientPort *port = PINOS_CLIENT_PORT (object); + + g_debug ("client-port %p: dispose", port); + + G_OBJECT_CLASS (pinos_client_port_parent_class)->dispose (object); +} + +static void +pinos_client_port_finalize (GObject * object) +{ + PinosClientPort *port = PINOS_CLIENT_PORT (object); + + g_debug ("client-port %p: finalize", port); + + G_OBJECT_CLASS (pinos_client_port_parent_class)->finalize (object); +} + +static void +pinos_client_port_class_init (PinosClientPortClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosClientPortPrivate)); + + gobject_class->constructed = pinos_client_port_constructed; + gobject_class->dispose = pinos_client_port_dispose; + gobject_class->finalize = pinos_client_port_finalize; + gobject_class->set_property = pinos_client_port_set_property; + gobject_class->get_property = pinos_client_port_get_property; +} + +static void +pinos_client_port_init (PinosClientPort * port) +{ + port->priv = PINOS_CLIENT_PORT_GET_PRIVATE (port); +} diff --git a/pinos/client/client-port.h b/pinos/client/client-port.h new file mode 100644 index 000000000..84ceade7e --- /dev/null +++ b/pinos/client/client-port.h @@ -0,0 +1,75 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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_PORT_H__ +#define __PINOS_CLIENT_PORT_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PinosClientPort PinosClientPort; +typedef struct _PinosClientPortClass PinosClientPortClass; +typedef struct _PinosClientPortPrivate PinosClientPortPrivate; + +#include +#include + +#define PINOS_TYPE_CLIENT_PORT (pinos_client_port_get_type ()) +#define PINOS_IS_CLIENT_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_CLIENT_PORT)) +#define PINOS_IS_CLIENT_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_CLIENT_PORT)) +#define PINOS_CLIENT_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_CLIENT_PORT, PinosClientPortClass)) +#define PINOS_CLIENT_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_CLIENT_PORT, PinosClientPort)) +#define PINOS_CLIENT_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_CLIENT_PORT, PinosClientPortClass)) +#define PINOS_CLIENT_PORT_CAST(obj) ((PinosClientPort*)(obj)) +#define PINOS_CLIENT_PORT_CLASS_CAST(klass) ((PinosClientPortClass*)(klass)) + +/** + * PinosClientPort: + * + * Pinos client port object class. + */ +struct _PinosClientPort { + PinosPort object; + + PinosClientPortPrivate *priv; +}; + +/** + * PinosClientPortClass: + * @get_formats: called to get a list of supported formats from the port + * @create_channel: called to create a new channel object + * @release_channel: called to release a channel object + * + * Pinos client port object class. + */ +struct _PinosClientPortClass { + PinosPortClass parent_class; +}; + +/* normal GObject stuff */ +GType pinos_client_port_get_type (void); + +GBytes * pinos_client_port_get_formats (PinosClientPort *port, + GBytes *filter, + GError **error); + +G_END_DECLS + +#endif /* __PINOS_CLIENT_PORT_H__ */ diff --git a/pinos/client/node.c b/pinos/client/node.c new file mode 100644 index 000000000..dc9261add --- /dev/null +++ b/pinos/client/node.c @@ -0,0 +1,478 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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 + +#include "pinos/client/pinos.h" +#include "pinos/client/enumtypes.h" + +#include "pinos/client/node.h" + + +#define PINOS_NODE_GET_PRIVATE(node) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((node), PINOS_TYPE_NODE, PinosNodePrivate)) + +struct _PinosNodePrivate +{ + gchar *name; + + PinosNodeState state; + GError *error; + guint idle_timeout; + + PinosProperties *properties; + + GList *ports; +}; + +G_DEFINE_ABSTRACT_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT); + +enum +{ + PROP_0, + PROP_NAME, + PROP_STATE, + PROP_PROPERTIES, +}; + +enum +{ + SIGNAL_REMOVE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +pinos_node_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PinosNode *node = PINOS_NODE (_object); + PinosNodePrivate *priv = node->priv; + + switch (prop_id) { + 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 (node, prop_id, pspec); + break; + } +} + +static void +pinos_node_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PinosNode *node = PINOS_NODE (_object); + PinosNodePrivate *priv = node->priv; + + switch (prop_id) { + case PROP_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); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec); + break; + } +} + +static void +pinos_node_constructed (GObject * obj) +{ + PinosNode *node = PINOS_NODE (obj); + + g_debug ("node %p: constructed", node); + + G_OBJECT_CLASS (pinos_node_parent_class)->constructed (obj); +} + +static void +pinos_node_dispose (GObject * obj) +{ + PinosNode *node = PINOS_NODE (obj); + PinosNodePrivate *priv = node->priv; + + g_debug ("node %p: dispose", node); + g_list_free_full (priv->ports, (GDestroyNotify) g_object_unref); + priv->ports = NULL; + + G_OBJECT_CLASS (pinos_node_parent_class)->dispose (obj); +} + +static void +pinos_node_finalize (GObject * obj) +{ + PinosNode *node = PINOS_NODE (obj); + PinosNodePrivate *priv = node->priv; + + g_debug ("node %p: finalize", node); + g_free (priv->name); + g_clear_error (&priv->error); + if (priv->properties) + pinos_properties_free (priv->properties); + + G_OBJECT_CLASS (pinos_node_parent_class)->finalize (obj); +} + +static void +pinos_node_class_init (PinosNodeClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosNodePrivate)); + + gobject_class->constructed = pinos_node_constructed; + gobject_class->dispose = pinos_node_dispose; + gobject_class->finalize = pinos_node_finalize; + gobject_class->set_property = pinos_node_set_property; + gobject_class->get_property = pinos_node_get_property; + + g_object_class_install_property (gobject_class, + PROP_NAME, + g_param_spec_string ("name", + "Name", + "The node 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 node", + PINOS_TYPE_NODE_STATE, + PINOS_NODE_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 node", + PINOS_TYPE_PROPERTIES, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + 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_node_init (PinosNode * node) +{ + PinosNodePrivate *priv = node->priv = PINOS_NODE_GET_PRIVATE (node); + + g_debug ("node %p: new", node); + priv->state = PINOS_NODE_STATE_SUSPENDED; +} + +/** + * pinos_node_remove: + * @node: a #PinosNode + * + * Remove @node. This will stop the transfer on the node and + * free the resources allocated by @node. + */ +void +pinos_node_remove (PinosNode *node) +{ + g_return_if_fail (PINOS_IS_NODE (node)); + + g_debug ("node %p: remove", node); + g_signal_emit (node, signals[SIGNAL_REMOVE], 0, NULL); +} + +static void +handle_remove_port (PinosPort *port, PinosNode *node) +{ + pinos_node_remove_port (node, port); +} + +/** + * pinos_node_create_port: + * @node: a #PinosNode + * @direction: the direction of the port + * @name: the name of the port + * @possible_formats: possible media formats for the port + * @props: extra properties for the port + * + * Create a new #PinosPort from @node. + * + * Returns: a new #PinosPort that should be freed with + * pinos_node_remove_port(). + */ +void +pinos_node_create_port (PinosNode *node, + PinosDirection direction, + const gchar *name, + GBytes *possible_formats, + PinosProperties *props, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PinosNodeClass *klass; + GTask *task; + + g_return_if_fail (PINOS_IS_NODE (node)); + + klass = PINOS_NODE_GET_CLASS (node); + if (!klass->create_port) + return; + + task = g_task_new (node, cancellable, callback, user_data); + klass->create_port (node, direction, name, possible_formats, props, task); +} + +PinosPort * +pinos_node_create_port_finish (PinosNode *node, + GAsyncResult *res, + GError **error) +{ + PinosPort *port; + PinosNodePrivate *priv; + + g_return_val_if_fail (PINOS_IS_NODE (node), NULL); + priv = node->priv; + + port = g_task_propagate_pointer (G_TASK (res), error); + if (port) { + priv->ports = g_list_append (priv->ports, port); + g_signal_connect (port, "remove", (GCallback) handle_remove_port, node); + } + return port; +} + +/** + * pinos_node_remove_port: + * @node: a #PinosNode + * @port: (transfer full): a #PinosPort + * + * Remove the #PinosPort from @node + */ +void +pinos_node_remove_port (PinosNode *node, PinosPort *port) +{ + PinosNodePrivate *priv; + PinosNodeClass *klass; + GList *find; + + g_return_if_fail (PINOS_IS_NODE (node)); + g_return_if_fail (PINOS_IS_PORT (port)); + priv = node->priv; + + find = g_list_find (priv->ports, port); + if (find) { + klass = PINOS_NODE_GET_CLASS (node); + + if (klass->remove_port) + klass->remove_port (node, port); + + priv->ports = g_list_delete_link (priv->ports, find); + g_object_unref (port); + } +} + +/** + * pinos_node_get_ports: + * @node: a #PinosNode + * + * Get the list of ports in @node. + * + * Returns: a #GList of nodes owned by @node. + */ +GList * +pinos_node_get_ports (PinosNode *node) +{ + PinosNodePrivate *priv; + + g_return_val_if_fail (PINOS_IS_NODE (node), NULL); + priv = node->priv; + + return priv->ports; +} + +static void +remove_idle_timeout (PinosNode *node) +{ + PinosNodePrivate *priv = node->priv; + + if (priv->idle_timeout) { + g_source_remove (priv->idle_timeout); + priv->idle_timeout = 0; + } +} + +/** + * pinos_node_set_state: + * @node: a #PinosNode + * @state: a #PinosNodeState + * + * Set the state of @node to @state. + * + * Returns: %TRUE on success. + */ +gboolean +pinos_node_set_state (PinosNode *node, + PinosNodeState state) +{ + PinosNodeClass *klass; + gboolean res; + + g_return_val_if_fail (PINOS_IS_NODE (node), FALSE); + + klass = PINOS_NODE_GET_CLASS (node); + + remove_idle_timeout (node); + + if (klass->set_state) + res = klass->set_state (node, state); + else + res = FALSE; + + return res; +} + +/** + * pinos_node_update_state: + * @node: a #PinosNode + * @state: a #PinosNodeState + * + * Update the state of a node. This method is used from + * inside @node itself. + */ +void +pinos_node_update_state (PinosNode *node, + PinosNodeState state) +{ + PinosNodePrivate *priv; + + g_return_if_fail (PINOS_IS_NODE (node)); + priv = node->priv; + + if (priv->state != state) { + priv->state = state; + g_object_notify (G_OBJECT (node), "state"); + } +} + +/** + * pinos_node_report_error: + * @node: a #PinosNode + * @error: a #GError + * + * Report an error from within @node. + */ +void +pinos_node_report_error (PinosNode *node, + GError *error) +{ + PinosNodePrivate *priv; + + g_return_if_fail (PINOS_IS_NODE (node)); + priv = node->priv; + + g_clear_error (&priv->error); + remove_idle_timeout (node); + priv->error = error; + priv->state = PINOS_NODE_STATE_ERROR; + g_debug ("got error state %s", error->message); + g_object_notify (G_OBJECT (node), "state"); +} + +static gboolean +idle_timeout (PinosNode *node) +{ + PinosNodePrivate *priv = node->priv; + + priv->idle_timeout = 0; + pinos_node_set_state (node, PINOS_NODE_STATE_SUSPENDED); + + return G_SOURCE_REMOVE; +} + +/** + * pinos_node_report_idle: + * @node: a #PinosNode + * + * Mark @node as being idle. This will start a timeout that will + * set the node to SUSPENDED. + */ +void +pinos_node_report_idle (PinosNode *node) +{ + PinosNodePrivate *priv; + + g_return_if_fail (PINOS_IS_NODE (node)); + priv = node->priv; + + pinos_node_set_state (node, PINOS_NODE_STATE_IDLE); + + priv->idle_timeout = g_timeout_add_seconds (3, + (GSourceFunc) idle_timeout, + node); +} + +/** + * pinos_node_report_busy: + * @node: a #PinosNode + * + * Mark @node as being busy. This will set the state of the node + * to the RUNNING state. + */ +void +pinos_node_report_busy (PinosNode *node) +{ + g_return_if_fail (PINOS_IS_NODE (node)); + + pinos_node_set_state (node, PINOS_NODE_STATE_RUNNING); +} diff --git a/pinos/client/node.h b/pinos/client/node.h new file mode 100644 index 000000000..ff899e2be --- /dev/null +++ b/pinos/client/node.h @@ -0,0 +1,109 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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_NODE_H__ +#define __PINOS_NODE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PinosNode PinosNode; +typedef struct _PinosNodeClass PinosNodeClass; +typedef struct _PinosNodePrivate PinosNodePrivate; + +#include +#include + +#define PINOS_TYPE_NODE (pinos_node_get_type ()) +#define PINOS_IS_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_NODE)) +#define PINOS_IS_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_NODE)) +#define PINOS_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_NODE, PinosNodeClass)) +#define PINOS_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_NODE, PinosNode)) +#define PINOS_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_NODE, PinosNodeClass)) +#define PINOS_NODE_CAST(obj) ((PinosNode*)(obj)) +#define PINOS_NODE_CLASS_CAST(klass) ((PinosNodeClass*)(klass)) + +/** + * PinosNode: + * + * Pinos node class. + */ +struct _PinosNode { + GObject object; + + PinosNodePrivate *priv; +}; + +/** + * PinosNodeClass: + * @set_state: called to change the current state of the node + * @create_node: make a new port + * @remove_node: remove a port + * + * Pinos node class. + */ +struct _PinosNodeClass { + GObjectClass parent_class; + + gboolean (*set_state) (PinosNode *node, + PinosNodeState state); + + void (*create_port) (PinosNode *node, + PinosDirection direction, + const gchar *name, + GBytes *possible_formats, + PinosProperties *props, + GTask *task); + void (*remove_port) (PinosNode *node, + PinosPort *port); + +}; + +/* normal GObject stuff */ +GType pinos_node_get_type (void); + +void pinos_node_remove (PinosNode *node); + +void pinos_node_create_port (PinosNode *node, + PinosDirection direction, + const gchar *name, + GBytes *possible_formats, + PinosProperties *props, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +PinosPort * pinos_node_create_port_finish (PinosNode *node, + GAsyncResult *res, + GError **error); + +void pinos_node_remove_port (PinosNode *node, + PinosPort *port); +GList * pinos_node_get_ports (PinosNode *node); + +gboolean pinos_node_set_state (PinosNode *node, PinosNodeState state); +void pinos_node_update_state (PinosNode *node, PinosNodeState state); + +void pinos_node_report_error (PinosNode *node, GError *error); +void pinos_node_report_idle (PinosNode *node); +void pinos_node_report_busy (PinosNode *node); + +G_END_DECLS + +#endif /* __PINOS_NODE_H__ */ diff --git a/pinos/client/port.c b/pinos/client/port.c new file mode 100644 index 000000000..cf7609cc1 --- /dev/null +++ b/pinos/client/port.c @@ -0,0 +1,382 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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 + +#include +#include + +#include "pinos/client/pinos.h" +#include "pinos/client/enumtypes.h" + +#include "pinos/client/port.h" +#include "pinos/client/node.h" + +#define PINOS_PORT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_PORT, PinosPortPrivate)) + +struct _PinosPortPrivate +{ + PinosNode *node; + + gchar *name; + PinosDirection direction; + GBytes *possible_formats; + PinosProperties *properties; +}; + +G_DEFINE_ABSTRACT_TYPE (PinosPort, pinos_port, G_TYPE_OBJECT); + +enum +{ + PROP_0, + PROP_NODE, + PROP_NAME, + PROP_DIRECTION, + PROP_POSSIBLE_FORMATS, + PROP_PROPERTIES +}; + +enum +{ + SIGNAL_FORMAT_REQUEST, + SIGNAL_REMOVE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +pinos_port_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PinosPort *port = PINOS_PORT (_object); + PinosPortPrivate *priv = port->priv; + + switch (prop_id) { + case PROP_NODE: + g_value_set_object (value, priv->node); + break; + + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + + case PROP_DIRECTION: + g_value_set_enum (value, priv->direction); + 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; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (port, prop_id, pspec); + break; + } +} + +static void +pinos_port_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PinosPort *port = PINOS_PORT (_object); + PinosPortPrivate *priv = port->priv; + + switch (prop_id) { + case PROP_NODE: + priv->node = g_value_get_object (value); + break; + + case PROP_NAME: + priv->name = g_value_dup_string (value); + break; + + case PROP_DIRECTION: + priv->direction = g_value_get_enum (value); + break; + + case PROP_POSSIBLE_FORMATS: + { + if (priv->possible_formats) + g_bytes_unref (priv->possible_formats); + priv->possible_formats = g_value_dup_boxed (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 (port, prop_id, pspec); + break; + } +} + +static void +pinos_port_constructed (GObject * object) +{ + PinosPort *port = PINOS_PORT (object); + + g_debug ("port %p: constructed", port); + + G_OBJECT_CLASS (pinos_port_parent_class)->constructed (object); +} + +static void +pinos_port_dispose (GObject * object) +{ + PinosPort *port = PINOS_PORT (object); + + g_debug ("port %p: dispose", port); + + G_OBJECT_CLASS (pinos_port_parent_class)->dispose (object); +} + +static void +pinos_port_finalize (GObject * object) +{ + PinosPort *port = PINOS_PORT (object); + PinosPortPrivate *priv = port->priv; + + g_debug ("port %p: finalize", port); + + g_free (priv->name); + if (priv->possible_formats) + g_bytes_unref (priv->possible_formats); + if (priv->properties) + pinos_properties_free (priv->properties); + + G_OBJECT_CLASS (pinos_port_parent_class)->finalize (object); +} + +static void +pinos_port_class_init (PinosPortClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosPortPrivate)); + + gobject_class->constructed = pinos_port_constructed; + gobject_class->dispose = pinos_port_dispose; + gobject_class->finalize = pinos_port_finalize; + gobject_class->set_property = pinos_port_set_property; + gobject_class->get_property = pinos_port_get_property; + + g_object_class_install_property (gobject_class, + PROP_NODE, + g_param_spec_object ("node", + "Node", + "The Node", + PINOS_TYPE_NODE, + 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 port name", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, + PROP_DIRECTION, + g_param_spec_enum ("direction", + "Direction", + "The direction of the port", + PINOS_TYPE_DIRECTION, + PINOS_DIRECTION_INVALID, + 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 port", + 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", + "The properties of the port", + PINOS_TYPE_PROPERTIES, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + + signals[SIGNAL_FORMAT_REQUEST] = g_signal_new ("format-request", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 0, + G_TYPE_NONE); + + 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_port_init (PinosPort * port) +{ + PinosPortPrivate *priv = port->priv = PINOS_PORT_GET_PRIVATE (port); + + priv->direction = PINOS_DIRECTION_INVALID; +} + +/** + * pinos_port_remove: + * @port: a #PinosPort + * + * Trigger removal of @port + */ +void +pinos_port_remove (PinosPort *port) +{ + g_return_if_fail (PINOS_IS_PORT (port)); + + g_debug ("port %p: remove", port); + g_signal_emit (port, signals[SIGNAL_REMOVE], 0, NULL); +} + +/** + * pinos_port_get_node: + * @port: a #PinosPort + * + * Get the parent #PinosNode of @port + * + * Returns: the parent node or %NULL + */ +PinosNode * +pinos_port_get_node (PinosPort *port) +{ + PinosPortPrivate *priv; + + g_return_val_if_fail (PINOS_IS_PORT (port), NULL); + priv = port->priv; + + return priv->node; +} + +/** + * pinos_port_get_formats: + * @port: a #PinosPort + * @filter: a #GBytes + * @error: a #GError or %NULL + * + * Get all the currently supported formats for @port and filter the + * results with @filter. + * + * Returns: the list of supported format. If %NULL is returned, @error will + * be set. + */ +GBytes * +pinos_port_get_formats (PinosPort *port, + GBytes *filter, + GError **error) +{ + GstCaps *tmp, *caps, *cfilter; + gchar *str; + PinosPortPrivate *priv; + + g_return_val_if_fail (PINOS_IS_PORT (port), NULL); + priv = port->priv; + + if (filter) { + cfilter = gst_caps_from_string (g_bytes_get_data (filter, NULL)); + if (cfilter == NULL) + goto invalid_filter; + } else { + cfilter = NULL; + } + + g_signal_emit (port, signals[SIGNAL_FORMAT_REQUEST], 0, NULL); + + if (priv->possible_formats) + caps = gst_caps_from_string (g_bytes_get_data (priv->possible_formats, NULL)); + else + caps = gst_caps_new_any (); + + if (caps && cfilter) { + tmp = gst_caps_intersect_full (caps, cfilter, GST_CAPS_INTERSECT_FIRST); + g_clear_pointer (&cfilter, gst_caps_unref); + gst_caps_take (&caps, tmp); + } + if (caps == NULL || gst_caps_is_empty (caps)) + goto no_format; + + str = gst_caps_to_string (caps); + gst_caps_unref (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"); + if (cfilter) + gst_caps_unref (cfilter); + if (caps) + gst_caps_unref (caps); + return NULL; + } +} diff --git a/pinos/client/port.h b/pinos/client/port.h new file mode 100644 index 000000000..736f785ad --- /dev/null +++ b/pinos/client/port.h @@ -0,0 +1,74 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * 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_PORT_H__ +#define __PINOS_PORT_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PinosPort PinosPort; +typedef struct _PinosPortClass PinosPortClass; +typedef struct _PinosPortPrivate PinosPortPrivate; + +#include + +#define PINOS_TYPE_PORT (pinos_port_get_type ()) +#define PINOS_IS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_PORT)) +#define PINOS_IS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_PORT)) +#define PINOS_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_PORT, PinosPortClass)) +#define PINOS_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_PORT, PinosPort)) +#define PINOS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_PORT, PinosPortClass)) +#define PINOS_PORT_CAST(obj) ((PinosPort*)(obj)) +#define PINOS_PORT_CLASS_CAST(klass) ((PinosPortClass*)(klass)) + +/** + * PinosPort: + * + * Pinos port object class. + */ +struct _PinosPort { + GObject object; + + PinosPortPrivate *priv; +}; + +/** + * PinosPortClass: + * + * Pinos port object class. + */ +struct _PinosPortClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType pinos_port_get_type (void); + +void pinos_port_remove (PinosPort *port); + +PinosNode * pinos_port_get_node (PinosPort *port); +GBytes * pinos_port_get_formats (PinosPort *port, + GBytes *filter, + GError **error); + +G_END_DECLS + +#endif /* __PINOS_PORT_H__ */