Rework how clients connect.

Add buffer flags. The idea is to make it possible to easily check when a
buffer contains control information that we need to parse to update the
port fields.
Make the client create remote nodes and ports and set up proxies for
them.
Make a port base class implementing most of the logic to pass buffers
locally and remotely.
Remove most code from stream.c, it's now in the port.
Make a portsink and portsrc that can write and read to/from any port. We
use these in the server to send and receive data.
Rework format negotiation. The final format is now sent in-line before
the data. The server will select a format on output ports.
This commit is contained in:
Wim Taymans 2016-05-17 09:38:30 +02:00
parent e85c3002f7
commit 4a5ed1e1f5
35 changed files with 3111 additions and 761 deletions

View file

@ -115,24 +115,23 @@ setup_pipeline (PinosGstSink *sink, GError **error)
{
PinosGstSinkPrivate *priv = sink->priv;
GstBus *bus;
GstCaps *caps;
g_debug ("gst-sink %p: setup pipeline", sink);
priv->pipeline = gst_pipeline_new (NULL);
priv->src = gst_element_factory_make ("socketsrc", NULL);
caps = gst_caps_new_empty_simple ("application/x-pinos");
g_object_set (priv->src, "send-messages", TRUE,
"caps", caps, NULL);
gst_caps_unref (caps);
priv->src = gst_element_factory_make ("pinosportsrc", NULL);
g_object_set (priv->src, "port", priv->input,
NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->src);
priv->depay = gst_element_factory_make ("pinosdepay", NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->depay);
gst_element_link (priv->src, priv->depay);
// priv->depay = gst_element_factory_make ("pinosdepay", NULL);
// gst_bin_add (GST_BIN (priv->pipeline), priv->depay);
// gst_element_link (priv->src, priv->depay);
g_object_set (priv->element, "sync", FALSE, NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->element);
gst_element_link (priv->depay, priv->element);
gst_element_link (priv->src, priv->element);
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
gst_bus_add_watch (bus, bus_handler, sink);
@ -240,80 +239,6 @@ set_state (PinosNode *node,
return TRUE;
}
#if 0
static void
on_socket_notify (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
PinosNode *node = user_data;
PinosGstSink *sink = user_data;
PinosGstSinkPrivate *priv = sink->priv;
GSocket *socket;
guint num_handles;
GstCaps *caps;
GBytes *requested_format, *format = NULL;
gchar *str;
gpointer state = NULL;
const gchar *key, *val;
PinosProperties *props;
g_object_get (gobject, "socket", &socket, NULL);
GST_DEBUG ("got socket %p", socket);
if (socket == NULL) {
g_object_set (priv->src, "socket", NULL, NULL);
num_handles = 0;
} else {
g_object_set (priv->src, "socket", socket, NULL);
num_handles = 1;
}
if (num_handles == 0) {
pinos_node_report_idle (node);
g_object_set (priv->depay, "caps", NULL, NULL);
str = gst_caps_to_string (priv->possible_formats);
format = g_bytes_new_take (str, strlen (str) + 1);
} else if (socket) {
/* what client requested */
g_object_get (gobject, "requested-format", &requested_format, NULL);
g_assert (requested_format != NULL);
if (num_handles == 1) {
/* first client, we set the requested format as the format */
format = requested_format;
/* set on the filter */
caps = gst_caps_from_string (g_bytes_get_data (format, NULL));
g_assert (caps != NULL);
g_object_set (priv->depay, "caps", caps, NULL);
gst_caps_unref (caps);
} else {
/* we already have a client, format is whatever is configured already */
g_bytes_unref (requested_format);
g_object_get (priv->depay, "caps", &caps, NULL);
str = gst_caps_to_string (caps);
format = g_bytes_new_take (str, strlen (str) + 1);
gst_caps_unref (caps);
}
/* this is what we use as the final format for the output */
g_object_set (gobject, "format", format, NULL);
pinos_node_report_busy (node);
g_object_unref (socket);
}
g_object_get (gobject, "properties", &props, NULL);
while ((key = pinos_properties_iterate (priv->props, &state))) {
val = pinos_properties_get (priv->props, key);
pinos_properties_set (props, key, val);
}
g_object_set (gobject, "properties", props, NULL);
pinos_properties_free (props);
}
#endif
static void
get_property (GObject *object,
guint prop_id,
@ -362,19 +287,48 @@ set_property (GObject *object,
}
}
static void
on_linked (PinosPort *port, PinosPort *peer, gpointer user_data)
{
PinosNode *node = user_data;
gint n_peers;
g_debug ("port %p: linked", port);
n_peers = pinos_port_get_n_links (port);
if (n_peers == 1)
pinos_node_report_busy (node);
}
static void
on_unlinked (PinosPort *port, PinosPort *peer, gpointer user_data)
{
PinosNode *node = user_data;
gint n_peers;
g_debug ("port %p: unlinked", port);
n_peers = pinos_port_get_n_links (port);
if (n_peers == 0)
pinos_node_report_idle (node);
}
static void
on_input_port_created (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PinosNode *node = PINOS_NODE (source_object);
PinosGstSinkPrivate *priv = PINOS_GST_SINK (node)->priv;
PinosGstSink *sink = PINOS_GST_SINK (node);
PinosGstSinkPrivate *priv = sink->priv;
priv->input = pinos_node_create_port_finish (node, res, NULL);
g_signal_connect (priv->input, "linked", (GCallback) on_linked, node);
g_signal_connect (priv->input, "unlinked", (GCallback) on_unlinked, node);
setup_pipeline (sink, NULL);
}
static void
sink_constructed (GObject * object)
{
@ -382,32 +336,32 @@ sink_constructed (GObject * object)
PinosGstSink *sink = PINOS_GST_SINK (object);
PinosGstSinkPrivate *priv = sink->priv;
gchar *str;
GBytes *format;
GBytes *possible_formats;
G_OBJECT_CLASS (pinos_gst_sink_parent_class)->constructed (object);
str = gst_caps_to_string (priv->possible_formats);
format = g_bytes_new_take (str, strlen (str) + 1);
possible_formats = g_bytes_new_take (str, strlen (str) + 1);
pinos_node_create_port (PINOS_NODE (node),
PINOS_DIRECTION_INPUT,
"input",
format,
possible_formats,
NULL,
NULL,
on_input_port_created,
node);
g_bytes_unref (format);
setup_pipeline (sink, NULL);
g_bytes_unref (possible_formats);
}
static void
sink_finalize (GObject * object)
{
PinosServerNode *node = PINOS_SERVER_NODE (object);
PinosGstSink *sink = PINOS_GST_SINK (object);
PinosGstSinkPrivate *priv = sink->priv;
pinos_node_remove_port (PINOS_NODE (node), priv->input);
destroy_pipeline (sink);
g_clear_pointer (&priv->possible_formats, gst_caps_unref);
pinos_properties_free (priv->props);

View file

@ -32,7 +32,7 @@ struct _PinosGstSourcePrivate
{
GstElement *pipeline;
GstElement *element;
GstElement *filter;
GstElement *pay;
GstElement *sink;
PinosPort *output;
@ -122,18 +122,21 @@ setup_pipeline (PinosGstSource *source, GError **error)
gst_bin_add (GST_BIN (priv->pipeline), priv->element);
priv->filter = gst_element_factory_make ("capsfilter", NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->filter);
gst_element_link (priv->element, priv->filter);
#if 0
priv->pay = gst_element_factory_make ("pinospay", NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->pay);
gst_element_link (priv->element, priv->pay);
#endif
priv->sink = gst_element_factory_make ("pinossocketsink", NULL);
priv->sink = gst_element_factory_make ("pinosportsink", NULL);
g_object_set (priv->sink, "sync", TRUE,
"enable-last-sample", FALSE,
"qos", FALSE,
"port", priv->output,
NULL);
gst_bin_add (GST_BIN (priv->pipeline), priv->sink);
gst_element_link (priv->filter, priv->sink);
gst_element_link (priv->element, priv->sink);
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
gst_bus_add_watch (bus, bus_handler, source);
@ -286,86 +289,6 @@ set_state (PinosNode *node,
return TRUE;
}
#if 0
static void
on_socket_notify (GObject *gobject,
GParamSpec *pspec,
gpointer user_data)
{
PinosGstSource *source = user_data;
PinosGstSourcePrivate *priv = source->priv;
GSocket *socket;
guint num_handles;
GstCaps *caps;
GBytes *requested_format, *format = NULL;
gchar *str;
gpointer state = NULL;
const gchar *key, *val;
PinosProperties *props;
g_object_get (gobject, "socket", &socket, NULL);
GST_DEBUG ("got socket %p", socket);
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) {
pinos_node_report_idle (PINOS_NODE (source));
g_object_set (priv->filter, "caps", NULL, NULL);
str = gst_caps_to_string (priv->possible_formats);
format = g_bytes_new_take (str, strlen (str) + 1);
} else if (socket) {
/* what client requested */
g_object_get (gobject, "requested-format", &requested_format, NULL);
g_assert (requested_format != NULL);
if (num_handles == 1) {
/* first client, we set the requested format as the format */
format = requested_format;
/* set on the filter */
caps = gst_caps_from_string (g_bytes_get_data (format, NULL));
g_assert (caps != NULL);
g_object_set (priv->filter, "caps", caps, NULL);
gst_caps_unref (caps);
} else {
/* we already have a client, format is whatever is configured already */
g_bytes_unref (requested_format);
g_object_get (priv->filter, "caps", &caps, NULL);
str = gst_caps_to_string (caps);
format = g_bytes_new_take (str, strlen (str) + 1);
gst_caps_unref (caps);
}
/* this is what we use as the final format for the output */
g_object_set (gobject, "format", format, NULL);
pinos_node_report_busy (PINOS_NODE (source));
}
if (format) {
g_object_set (priv->output, "possible-formats", format, NULL);
g_bytes_unref (format);
}
g_object_get (gobject, "properties", &props, NULL);
while ((key = pinos_properties_iterate (priv->props, &state))) {
val = pinos_properties_get (priv->props, key);
pinos_properties_set (props, key, val);
}
g_object_set (gobject, "properties", props, NULL);
pinos_properties_free (props);
}
#endif
static void
get_property (GObject *object,
guint prop_id,
@ -414,15 +337,43 @@ set_property (GObject *object,
}
}
static void
on_linked (PinosPort *port, PinosPort *peer, gpointer user_data)
{
PinosNode *node = user_data;
gint n_peers;
n_peers = pinos_port_get_n_links (port);
if (n_peers == 1)
pinos_node_report_busy (node);
}
static void
on_unlinked (PinosPort *port, PinosPort *peer, gpointer user_data)
{
PinosNode *node = user_data;
gint n_peers;
n_peers = pinos_port_get_n_links (port);
if (n_peers == 0)
pinos_node_report_idle (node);
}
static void
on_output_port_created (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
PinosNode *node = PINOS_NODE (source_object);
PinosGstSourcePrivate *priv = PINOS_GST_SOURCE (node)->priv;
PinosGstSource *source = PINOS_GST_SOURCE (node);
PinosGstSourcePrivate *priv = source->priv;
priv->output = pinos_node_create_port_finish (node, res, NULL);
g_signal_connect (priv->output, "linked", (GCallback) on_linked, node);
g_signal_connect (priv->output, "unlinked", (GCallback) on_unlinked, node);
setup_pipeline (source, NULL);
}
static void
@ -432,24 +383,22 @@ source_constructed (GObject * object)
PinosGstSource *source = PINOS_GST_SOURCE (object);
PinosGstSourcePrivate *priv = source->priv;
gchar *str;
GBytes *format;
GBytes *possible_formats;
G_OBJECT_CLASS (pinos_gst_source_parent_class)->constructed (object);
str = gst_caps_to_string (priv->possible_formats);
format = g_bytes_new_take (str, strlen (str) + 1);
possible_formats = g_bytes_new_take (str, strlen (str) + 1);
pinos_node_create_port (PINOS_NODE (node),
PINOS_DIRECTION_OUTPUT,
"output",
format,
possible_formats,
NULL,
NULL,
on_output_port_created,
node);
g_bytes_unref (format);
setup_pipeline (source, NULL);
g_bytes_unref (possible_formats);
}
static void
@ -459,8 +408,9 @@ source_finalize (GObject * object)
PinosGstSource *source = PINOS_GST_SOURCE (object);
PinosGstSourcePrivate *priv = source->priv;
pinos_node_remove_port (PINOS_NODE (node), priv->output);
g_debug ("gst-source %p: dispose", node);
destroy_pipeline (source);
pinos_node_remove_port (PINOS_NODE (node), priv->output);
g_clear_pointer (&priv->possible_formats, gst_caps_unref);
pinos_properties_free (priv->props);