make separate sockets for data and control

This commit is contained in:
Wim Taymans 2016-10-14 19:23:05 +02:00
parent ee202e13e9
commit 184e0a300a
7 changed files with 419 additions and 92 deletions

View file

@ -90,6 +90,9 @@ struct _PinosStreamPrivate
GSocket *socket;
GSource *socket_source;
int fd;
GSocket *rtsocket;
GSource *rtsocket_source;
int rtfd;
GSource *timeout_source;
@ -700,7 +703,7 @@ send_need_input (PinosStream *stream, uint32_t port_id)
add_need_input (stream, &builder, port_id);
spa_control_builder_end (&builder, &control);
if (spa_control_write (&control, priv->fd) < 0)
if (spa_control_write (&control, priv->rtfd) < 0)
g_warning ("stream %p: error writing control", stream);
spa_control_clear (&control);
@ -763,7 +766,7 @@ send_reuse_buffer (PinosStream *stream, uint32_t port_id, uint32_t buffer_id)
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_EVENT, &cne);
spa_control_builder_end (&builder, &control);
if (spa_control_write (&control, priv->fd) < 0)
if (spa_control_write (&control, priv->rtfd) < 0)
g_warning ("stream %p: error writing control", stream);
spa_control_clear (&control);
@ -795,7 +798,7 @@ send_process_buffer (PinosStream *stream, uint32_t port_id, uint32_t buffer_id)
spa_control_builder_end (&builder, &control);
if (spa_control_write (&control, priv->fd) < 0)
if (spa_control_write (&control, priv->rtfd) < 0)
g_warning ("stream %p: error writing control", stream);
spa_control_clear (&control);
@ -861,13 +864,44 @@ static gboolean
handle_node_event (PinosStream *stream,
SpaNodeEvent *event)
{
PinosStreamPrivate *priv = stream->priv;
switch (event->type) {
case SPA_NODE_EVENT_TYPE_INVALID:
case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT:
case SPA_NODE_EVENT_TYPE_NEED_INPUT:
case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE:
case SPA_NODE_EVENT_TYPE_REUSE_BUFFER:
case SPA_NODE_EVENT_TYPE_DRAINED:
case SPA_NODE_EVENT_TYPE_MARKER:
case SPA_NODE_EVENT_TYPE_ERROR:
case SPA_NODE_EVENT_TYPE_BUFFERING:
case SPA_NODE_EVENT_TYPE_REQUEST_REFRESH:
case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE:
g_warning ("unhandled node event %d", event->type);
break;
}
return TRUE;
}
static gboolean
handle_rtnode_event (PinosStream *stream,
SpaNodeEvent *event)
{
PinosStreamPrivate *priv = stream->priv;
switch (event->type) {
case SPA_NODE_EVENT_TYPE_INVALID:
case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE:
case SPA_NODE_EVENT_TYPE_DRAINED:
case SPA_NODE_EVENT_TYPE_MARKER:
case SPA_NODE_EVENT_TYPE_ERROR:
case SPA_NODE_EVENT_TYPE_BUFFERING:
case SPA_NODE_EVENT_TYPE_REQUEST_REFRESH:
case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE:
g_warning ("unexpected node event %d", event->type);
break;
case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT:
case SPA_NODE_EVENT_TYPE_NEED_INPUT:
g_warning ("unhandled node event %d", event->type);
break;
@ -887,14 +921,6 @@ handle_node_event (PinosStream *stream,
}
break;
}
case SPA_NODE_EVENT_TYPE_DRAINED:
case SPA_NODE_EVENT_TYPE_MARKER:
case SPA_NODE_EVENT_TYPE_ERROR:
case SPA_NODE_EVENT_TYPE_BUFFERING:
case SPA_NODE_EVENT_TYPE_REQUEST_REFRESH:
case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE:
g_warning ("unhandled node event %d", event->type);
break;
}
return TRUE;
}
@ -1003,6 +1029,7 @@ parse_control (PinosStream *stream,
case SPA_CONTROL_CMD_PORT_UPDATE:
case SPA_CONTROL_CMD_PORT_STATUS_CHANGE:
case SPA_CONTROL_CMD_NODE_STATE_CHANGE:
case SPA_CONTROL_CMD_PROCESS_BUFFER:
g_warning ("got unexpected control %d", cmd);
break;
@ -1183,6 +1210,65 @@ parse_control (PinosStream *stream,
spa_control_clear (&control);
break;
}
case SPA_CONTROL_CMD_NODE_EVENT:
{
SpaControlCmdNodeEvent p;
if (spa_control_iter_parse_cmd (&it, &p) < 0)
break;
handle_node_event (stream, p.event);
break;
}
case SPA_CONTROL_CMD_NODE_COMMAND:
{
SpaControlCmdNodeCommand p;
if (spa_control_iter_parse_cmd (&it, &p) < 0)
break;
handle_node_command (stream, p.seq, p.command);
break;
}
case SPA_CONTROL_CMD_INVALID:
g_warning ("unhandled command %d", cmd);
break;
}
}
spa_control_iter_end (&it);
return TRUE;
}
static gboolean
parse_rtcontrol (PinosStream *stream,
SpaControl *ctrl)
{
SpaControlIter it;
PinosStreamPrivate *priv = stream->priv;
spa_control_iter_init (&it, ctrl);
while (spa_control_iter_next (&it) == SPA_RESULT_OK) {
SpaControlCmd cmd = spa_control_iter_get_cmd (&it);
switch (cmd) {
case SPA_CONTROL_CMD_INVALID:
case SPA_CONTROL_CMD_NODE_UPDATE:
case SPA_CONTROL_CMD_PORT_UPDATE:
case SPA_CONTROL_CMD_PORT_STATUS_CHANGE:
case SPA_CONTROL_CMD_NODE_STATE_CHANGE:
case SPA_CONTROL_CMD_ADD_PORT:
case SPA_CONTROL_CMD_REMOVE_PORT:
case SPA_CONTROL_CMD_SET_FORMAT:
case SPA_CONTROL_CMD_SET_PROPERTY:
case SPA_CONTROL_CMD_ADD_MEM:
case SPA_CONTROL_CMD_REMOVE_MEM:
case SPA_CONTROL_CMD_USE_BUFFERS:
case SPA_CONTROL_CMD_NODE_COMMAND:
g_warning ("got unexpected control %d", cmd);
break;
case SPA_CONTROL_CMD_PROCESS_BUFFER:
{
SpaControlCmdProcessBuffer p;
@ -1212,23 +1298,9 @@ parse_control (PinosStream *stream,
if (spa_control_iter_parse_cmd (&it, &p) < 0)
break;
handle_node_event (stream, p.event);
handle_rtnode_event (stream, p.event);
break;
}
case SPA_CONTROL_CMD_NODE_COMMAND:
{
SpaControlCmdNodeCommand p;
if (spa_control_iter_parse_cmd (&it, &p) < 0)
break;
handle_node_command (stream, p.seq, p.command);
break;
}
case SPA_CONTROL_CMD_INVALID:
g_warning ("unhandled command %d", cmd);
break;
}
}
spa_control_iter_end (&it);
@ -1275,6 +1347,46 @@ on_socket_condition (GSocket *socket,
return TRUE;
}
static gboolean
on_rtsocket_condition (GSocket *socket,
GIOCondition condition,
gpointer user_data)
{
PinosStream *stream = user_data;
PinosStreamPrivate *priv = stream->priv;
switch (condition) {
case G_IO_IN:
{
SpaControl *control = &priv->recv_control;
guint8 buffer[4096];
if (spa_control_read (control,
priv->rtfd,
buffer,
sizeof (buffer),
NULL,
0) < 0) {
g_warning ("stream %p: failed to read buffer", stream);
return TRUE;
}
parse_rtcontrol (stream, control);
spa_control_clear (control);
break;
}
case G_IO_OUT:
g_warning ("can do IO\n");
break;
default:
break;
}
return TRUE;
}
static gboolean
on_timeout (gpointer user_data)
{
@ -1296,7 +1408,7 @@ on_timeout (gpointer user_data)
}
static void
handle_socket (PinosStream *stream, gint fd)
handle_socket (PinosStream *stream, gint fd, gint rtfd)
{
PinosStreamPrivate *priv = stream->priv;
GError *error = NULL;
@ -1304,12 +1416,20 @@ handle_socket (PinosStream *stream, gint fd)
priv->socket = g_socket_new_from_fd (fd, &error);
if (priv->socket == NULL)
goto socket_failed;
priv->rtsocket = g_socket_new_from_fd (rtfd, &error);
if (priv->rtsocket == NULL)
goto socket_failed;
priv->fd = g_socket_get_fd (priv->socket);
priv->socket_source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, stream, NULL);
g_source_attach (priv->socket_source, priv->context->priv->context);
priv->rtfd = g_socket_get_fd (priv->rtsocket);
priv->rtsocket_source = g_socket_create_source (priv->rtsocket, G_IO_IN, NULL);
g_source_set_callback (priv->rtsocket_source, (GSourceFunc) on_rtsocket_condition, stream, NULL);
g_source_attach (priv->rtsocket_source, priv->context->priv->context);
priv->timeout_source = g_timeout_source_new (100);
g_source_set_callback (priv->timeout_source, (GSourceFunc) on_timeout, stream, NULL);
g_source_attach (priv->timeout_source, priv->context->priv->context);
@ -1334,6 +1454,10 @@ unhandle_socket (PinosStream *stream)
g_source_destroy (priv->socket_source);
g_clear_pointer (&priv->socket_source, g_source_unref);
}
if (priv->rtsocket_source) {
g_source_destroy (priv->rtsocket_source);
g_clear_pointer (&priv->rtsocket_source, g_source_unref);
}
}
static void
@ -1382,6 +1506,7 @@ on_node_created (GObject *source_object,
const gchar *node_path;
GUnixFDList *fd_list;
gint fd_idx, fd;
gint rtfd_idx, rtfd;
g_assert (context->priv->daemon == G_DBUS_PROXY (source_object));
@ -1391,16 +1516,19 @@ on_node_created (GObject *source_object,
if (ret == NULL)
goto create_failed;
g_variant_get (ret, "(&oh)", &node_path, &fd_idx);
g_variant_get (ret, "(&ohh)", &node_path, &fd_idx, &rtfd_idx);
g_variant_unref (ret);
if ((fd = g_unix_fd_list_get (fd_list, fd_idx, &error)) < 0)
goto fd_failed;
if ((rtfd = g_unix_fd_list_get (fd_list, rtfd_idx, &error)) < 0)
goto fd_failed;
priv->fd = fd;
priv->rtfd = rtfd;
g_object_unref (fd_list);
handle_socket (stream, priv->fd);
handle_socket (stream, priv->fd, priv->rtfd);
pinos_subscribe_get_proxy (context->priv->subscribe,
PINOS_DBUS_SERVICE,
@ -1462,7 +1590,7 @@ on_node_registered (GObject *source_object,
priv->fd = fd;
g_object_unref (fd_list);
handle_socket (stream, priv->fd);
handle_socket (stream, -1, priv->fd);
return;

View file

@ -50,6 +50,7 @@
<arg type='a{sv}' name='properties' direction='in'/>
<arg type='o' name='node' direction='out'/>
<arg type='h' name='fd' direction='out'/>
<arg type='h' name='rtfd' direction='out'/>
</method>
<method name='RegisterClientNode'>

View file

@ -40,7 +40,9 @@
struct _PinosClientNodePrivate
{
int fd;
int rtfd;
GSocket *sockets[2];
GSocket *rtsockets[2];
SpaHandle *handle;
};
@ -104,7 +106,7 @@ pinos_client_node_set_property (GObject *_object,
*/
GSocket *
pinos_client_node_get_socket_pair (PinosClientNode *this,
GError **error)
GError **error)
{
PinosNode *node;
PinosClientNodePrivate *priv;
@ -156,6 +158,70 @@ create_failed:
}
}
/**
* pinos_client_node_get_rtsocket_pair:
* @node: a #PinosClientNode
* @error: a #GError
*
* Create or return a previously create socket pair for @node. The
* Socket for the other end is returned.
*
* Returns: a #GSocket that can be used to send/receive buffers to node.
*/
GSocket *
pinos_client_node_get_rtsocket_pair (PinosClientNode *this,
GError **error)
{
PinosNode *node;
PinosClientNodePrivate *priv;
g_return_val_if_fail (PINOS_IS_CLIENT_NODE (this), FALSE);
node = PINOS_NODE (this);
priv = this->priv;
if (priv->rtsockets[1] == NULL) {
SpaProps *props;
SpaPropValue value;
int fd[2];
if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0)
goto no_sockets;
priv->rtsockets[0] = g_socket_new_from_fd (fd[0], error);
if (priv->rtsockets[0] == NULL)
goto create_failed;
priv->rtsockets[1] = g_socket_new_from_fd (fd[1], error);
if (priv->rtsockets[1] == NULL)
goto create_failed;
priv->rtfd = g_socket_get_fd (priv->rtsockets[0]);
spa_node_get_props (node->node, &props);
value.value = &priv->rtfd;
value.size = sizeof (int);
spa_props_set_value (props, spa_props_index_for_name (props, "rt-socket"), &value);
spa_node_set_props (node->node, props);
}
return g_object_ref (priv->rtsockets[1]);
/* ERRORS */
no_sockets:
{
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errno),
"could not create socketpair: %s", strerror (errno));
return NULL;
}
create_failed:
{
g_clear_object (&priv->rtsockets[0]);
g_clear_object (&priv->rtsockets[1]);
return NULL;
}
}
static void
pinos_client_node_dispose (GObject * object)
{
@ -171,6 +237,7 @@ pinos_client_node_dispose (GObject * object)
value.value = &fd;
value.size = sizeof (int);
spa_props_set_value (props, spa_props_index_for_name (props, "socket"), &value);
spa_props_set_value (props, spa_props_index_for_name (props, "rt-socket"), &value);
spa_node_set_props (node->node, props);
G_OBJECT_CLASS (pinos_client_node_parent_class)->dispose (object);
@ -186,6 +253,8 @@ pinos_client_node_finalize (GObject * object)
g_clear_object (&priv->sockets[0]);
g_clear_object (&priv->sockets[1]);
g_clear_object (&priv->rtsockets[0]);
g_clear_object (&priv->rtsockets[1]);
spa_handle_clear (priv->handle);
g_free (priv->handle);

View file

@ -69,6 +69,8 @@ PinosNode * pinos_client_node_new (PinosDaemon *daem
GSocket * pinos_client_node_get_socket_pair (PinosClientNode *node,
GError **error);
GSocket * pinos_client_node_get_rtsocket_pair (PinosClientNode *node,
GError **error);
G_END_DECLS

View file

@ -378,8 +378,8 @@ handle_create_client_node (PinosDaemon1 *interface,
PinosProperties *props;
GError *error = NULL;
GUnixFDList *fdlist;
GSocket *socket;
gint fdidx;
GSocket *socket, *rtsocket;
gint fdidx, rtfdidx;
sender = g_dbus_method_invocation_get_sender (invocation);
client = sender_get_client (daemon, sender, TRUE);
@ -397,6 +397,10 @@ handle_create_client_node (PinosDaemon1 *interface,
if (socket == NULL)
goto no_socket;
rtsocket = pinos_client_node_get_rtsocket_pair (PINOS_CLIENT_NODE (node), &error);
if (rtsocket == NULL)
goto no_socket;
pinos_client_add_object (client, G_OBJECT (node));
object_path = pinos_node_get_object_path (PINOS_NODE (node));
@ -405,10 +409,12 @@ handle_create_client_node (PinosDaemon1 *interface,
fdlist = g_unix_fd_list_new ();
fdidx = g_unix_fd_list_append (fdlist, g_socket_get_fd (socket), &error);
rtfdidx = g_unix_fd_list_append (fdlist, g_socket_get_fd (rtsocket), &error);
g_object_unref (socket);
g_object_unref (rtsocket);
g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
g_variant_new ("(oh)", object_path, fdidx), fdlist);
g_variant_new ("(ohh)", object_path, fdidx, rtfdidx), fdlist);
g_object_unref (fdlist);
return TRUE;
@ -943,8 +949,11 @@ poll_event (GIOChannel *source,
PollData *data = user_data;
SpaPollNotifyData d;
g_debug ("poll event %d", data->item.fds[0].fd);
d.user_data = data->item.user_data;
d.fds = data->item.fds;
d.fds[0].revents = condition;
d.n_fds = data->item.n_fds;
data->item.after_cb (&d);
@ -960,6 +969,7 @@ do_add_item (SpaPoll *poll,
GSource *source;
PollData data;
g_debug ("add main poll");
channel = g_io_channel_unix_new (item->fds[0].fd);
source = g_io_create_watch (channel, G_IO_IN);
g_io_channel_unref (channel);
@ -987,6 +997,7 @@ do_remove_item (SpaPoll *poll,
{
GSource *source;
g_debug ("remove main poll %d", item->id);
source = g_main_context_find_source_by_id (g_main_context_get_thread_default (), item->id);
g_source_destroy (source);