Introduce the concept of a Port

A port is an input or output on a Node.
Channels are created from the ports and inherit the direction of the
port.
do automatic port selection based on the direction and caps and
node/port name.
Simplify stream_connect by passing the direction.
Fix pinossink to connect in setcaps so that we know the format and can
select a good sink to connect to.
This commit is contained in:
Wim Taymans 2016-05-06 13:01:52 +02:00
parent b885d40390
commit ba4ef9b5d9
35 changed files with 1939 additions and 2120 deletions

View file

@ -23,7 +23,6 @@
#include "pinos/client/enumtypes.h"
#include "pinos/server/node.h"
#include "pinos/server/source.h"
#include "pinos/server/daemon.h"
#include "pinos/dbus/org-pinos.h"
@ -35,10 +34,18 @@
struct _PinosNodePrivate
{
PinosDaemon *daemon;
PinosObjectSkeleton *skeleton;
PinosNode1 *iface;
gchar *object_path;
PinosSource *source;
PinosSink *sink;
gchar *name;
PinosNodeState state;
GError *error;
guint idle_timeout;
PinosProperties *properties;
GList *ports;
};
G_DEFINE_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT);
@ -47,8 +54,10 @@ enum
{
PROP_0,
PROP_DAEMON,
PROP_SKELETON,
PROP_OBJECT_PATH,
PROP_NAME,
PROP_STATE,
PROP_PROPERTIES,
};
static void
@ -65,14 +74,22 @@ pinos_node_get_property (GObject *_object,
g_value_set_object (value, priv->daemon);
break;
case PROP_SKELETON:
g_value_set_object (value, priv->skeleton);
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 (node, prop_id, pspec);
break;
@ -93,6 +110,19 @@ pinos_node_set_property (GObject *_object,
priv->daemon = g_value_dup_object (value);
break;
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);
if (priv->iface)
pinos_node1_set_properties (priv->iface,
priv->properties ? pinos_properties_to_variant (priv->properties) : NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (node, prop_id, pspec);
break;
@ -104,11 +134,20 @@ node_register_object (PinosNode *node)
{
PinosNodePrivate *priv = node->priv;
PinosDaemon *daemon = priv->daemon;
PinosObjectSkeleton *skel;
priv->skeleton = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_NODE);
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_NODE);
priv->iface = pinos_node1_skeleton_new ();
pinos_node1_set_name (priv->iface, priv->name);
if (priv->properties)
pinos_node1_set_properties (priv->iface, pinos_properties_to_variant (priv->properties));
pinos_node1_set_state (priv->iface, priv->state);
pinos_object_skeleton_set_node1 (skel, priv->iface);
g_free (priv->object_path);
priv->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (priv->skeleton));
priv->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
pinos_daemon_add_node (daemon, node);
@ -122,7 +161,7 @@ node_unregister_object (PinosNode *node)
pinos_daemon_unexport (priv->daemon, priv->object_path);
pinos_daemon_remove_node (priv->daemon, node);
g_clear_object (&priv->skeleton);
g_clear_object (&priv->iface);
}
static void
@ -187,6 +226,37 @@ pinos_node_class_init (PinosNodeClass * klass)
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
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));
}
static void
@ -234,96 +304,210 @@ pinos_node_get_object_path (PinosNode *node)
}
/**
* pinos_node_set_source:
* pinos_node_add_port:
* @node: a #PinosNode
* @source: a #PinosSource
* @port: a #PinosPort
*
* Set the #PinosSource of @node
* Add the #PinosPort to @node
*/
void
pinos_node_set_source (PinosNode *node, PinosSource *source, GObject *iface)
pinos_node_add_port (PinosNode *node, PinosPort *port)
{
PinosNodePrivate *priv;
g_return_if_fail (PINOS_IS_NODE (node));
g_return_if_fail (source == NULL || PINOS_IS_SOURCE (source));
g_return_if_fail (iface == NULL || PINOS_IS_SOURCE1 (iface));
g_return_if_fail (PINOS_IS_PORT (port));
priv = node->priv;
if (source) {
pinos_object_skeleton_set_source1 (priv->skeleton, PINOS_SOURCE1 (iface));
priv->source = source;
} else {
pinos_object_skeleton_set_source1 (priv->skeleton, NULL);
priv->source = NULL;
}
priv->ports = g_list_append (priv->ports, port);
}
/**
* pinos_node_get_source:
* pinos_node_remove_port:
* @node: a #PinosNode
* @port: a #PinosPort
*
* Remove the #PinosPort from @node
*/
void
pinos_node_remove_port (PinosNode *node, PinosPort *port)
{
PinosNodePrivate *priv;
g_return_if_fail (PINOS_IS_NODE (node));
g_return_if_fail (PINOS_IS_PORT (port));
priv = node->priv;
priv->ports = g_list_remove (priv->ports, port);
}
/**
* pinos_node_get_ports:
* @node: a #PinosNode
*
* Get the #PinosSource of @node
* Get the list of ports in @node.
*
* Returns: the #PinosSource of @node or %NULL
* Returns: a #GList of nodes owned by @node.
*/
PinosSource *
pinos_node_get_source (PinosNode *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->source;
return priv->ports;
}
/**
* pinos_node_set_sink:
* @node: a #PinosNode
* @sink: a #PinosSink
*
* Set the #PinosSink of @node
*/
void
pinos_node_set_sink (PinosNode *node, PinosSink *sink, GObject *iface)
static void
remove_idle_timeout (PinosNode *node)
{
PinosNodePrivate *priv;
PinosNodePrivate *priv = node->priv;
g_return_if_fail (PINOS_IS_NODE (node));
g_return_if_fail (sink == NULL || PINOS_IS_SINK (sink));
g_return_if_fail (iface == NULL || PINOS_IS_SINK1 (iface));
priv = node->priv;
if (sink) {
pinos_object_skeleton_set_sink1 (priv->skeleton, PINOS_SINK1 (iface));
priv->sink = sink;
} else {
pinos_object_skeleton_set_sink1 (priv->skeleton, NULL);
priv->sink = NULL;
if (priv->idle_timeout) {
g_source_remove (priv->idle_timeout);
priv->idle_timeout = 0;
}
}
/**
* pinos_node_get_sink:
* pinos_node_set_state:
* @node: a #PinosNode
* @state: a #PinosNodeState
*
* Get the #PinosSink of @node
* Set the state of @node to @state.
*
* Returns: the #PinosSink of @node or %NULL
* Returns: %TRUE on success.
*/
PinosSink *
pinos_node_get_sink (PinosNode *node)
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_val_if_fail (PINOS_IS_NODE (node), NULL);
g_return_if_fail (PINOS_IS_NODE (node));
priv = node->priv;
return priv->sink;
if (priv->state != state) {
priv->state = state;
pinos_node1_set_state (priv->iface, 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);
pinos_node1_set_state (priv->iface, priv->state);
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);
}
/**
* pinos_node_new:
* @daemon: a #PinosDaemon
*
* Make a new node
*
* Returns: a new #PinosNode
*/
PinosNode *
pinos_node_new (PinosDaemon *daemon)
{