mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
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:
parent
e85c3002f7
commit
4a5ed1e1f5
35 changed files with 3111 additions and 761 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue