diff --git a/doc/design.txt b/doc/design.txt index 30bbbcf27..bc0c0d8ba 100644 --- a/doc/design.txt +++ b/doc/design.txt @@ -86,13 +86,13 @@ make buffer |--------->| | (2) multisocketsink sends the buffer to N Pinos clients (3) for each client that is sent a buffer, multisocketsink sends an event with the client object and buffer in it. -(4) pinospay maps the fd-index that was sent, to the buffer in a - hashtable for each client. It refs the buffer so that it remains +(4) pinospay uses the fdmanager object to map the fd-index that was + sent, to the buffer and client. The buffer is reffed and kept alive for as long as the client is using the buffer. (5) when a message is received from a client, multisocketsink sends an event upstream. -(6) pinospay parses the message and removes all fd-index entries from - the client hashtable. When all clients release the fd, the buffer +(6) pinospay parses the message and instructs the fdmanager to release + the fd-index again. When all clients release the fd, the buffer will be unreffed and v4l2src can reuse the memory. * client consumer @@ -157,16 +157,24 @@ make buffer |--------->| | freed. (3) multisocketsink sends the buffer to the clients (4) for each buffer that is sent, an event is sent to the payloader -(5) the payloader remembers the fd-index and buffer in a per-client - hashtable. it keeps a ref on the buffer +(5) the payloader uses the fdmanager to map the fd-index to a buffer + and a client. it keeps a ref on the buffer (6) release-fd is received from a client -(7) pinospay removes the fd-index from the client hashtable. If all +(7) pinospay removes the fd-index from the fdmanager. If all clients released the fd, the buffer will be freeds, triggering the DestroyNotify. This will then trigger an event with a release-fd message to the source. (8) the source sends the release-fd message to Pinos +* client remove + +When a client disconnects from pinos, it must have released all fd-indexes +that it received. Pinos will force a release and will reuse the fd-indexes +when the client disconnects. + + + Wire ---- diff --git a/pinos/gst/gstpinospay.c b/pinos/gst/gstpinospay.c index 95ffbae98..c7bbf03b8 100644 --- a/pinos/gst/gstpinospay.c +++ b/pinos/gst/gstpinospay.c @@ -322,7 +322,7 @@ release_fds (GstPinosPay *pay, GstBuffer *buffer) for (i = 0; i < fdids->len; i++) { r.id = g_array_index (fdids, guint32, i); - GST_LOG ("release fd %d", r.id); + GST_LOG ("release fd index %d", r.id); pinos_buffer_builder_add_release_fd_payload (&b, &r); } pinos_buffer_builder_end (&b, &pbuf); diff --git a/pinos/server/client-source.c b/pinos/server/client-source.c index 5faec6364..ec8ca0ec6 100644 --- a/pinos/server/client-source.c +++ b/pinos/server/client-source.c @@ -149,6 +149,8 @@ setup_pipeline (PinosClientSource *source) bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); priv->id = gst_bus_add_watch (bus, bus_handler, source); gst_object_unref (bus); + + g_debug ("client-source %p: setup pipeline", source); } static GstCaps * @@ -254,6 +256,8 @@ on_socket_notify (GObject *gobject, g_object_get (gobject, "socket", &socket, NULL); + g_debug ("client-source %p: output socket notify %p", source, socket); + if (socket == NULL) { GSocket *prev_socket = g_object_steal_data (gobject, "last-socket"); if (prev_socket) { @@ -302,6 +306,8 @@ client_create_source_output (PinosSource *source, if (output == NULL) return NULL; + g_debug ("client-source %p: create output %p", source, output); + g_signal_connect (output, "notify::socket", (GCallback) on_socket_notify, source); return output; @@ -311,6 +317,7 @@ static gboolean client_release_source_output (PinosSource *source, PinosSourceOutput *output) { + g_debug ("client-source %p: release output %p", source, output); return PINOS_SOURCE_CLASS (pinos_client_source_parent_class)->release_source_output (source, output); } @@ -319,6 +326,8 @@ client_source_dispose (GObject * object) { PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (object)->priv; + g_debug ("client-source %p: dispose", object); + g_source_remove (priv->id); gst_element_set_state (priv->pipeline, GST_STATE_NULL); @@ -330,6 +339,8 @@ client_source_finalize (GObject * object) { PinosClientSourcePrivate *priv = PINOS_CLIENT_SOURCE (object)->priv; + g_debug ("client-source %p: finalize", object); + g_clear_object (&priv->input); g_clear_object (&priv->sink); g_clear_object (&priv->src); @@ -355,6 +366,7 @@ on_input_socket_notify (GObject *gobject, GstCaps *caps; g_object_get (gobject, "socket", &socket, NULL); + g_debug ("client-source %p: input socket notify %p", source, socket); if (socket) { /* requested format is final format */ @@ -373,9 +385,11 @@ on_input_socket_notify (GObject *gobject, g_object_set (priv->src, "socket", socket, NULL); if (socket) { + g_debug ("client-source %p: set pipeline to PLAYING", source); gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); g_object_unref (socket); } else { + g_debug ("client-source %p: set pipeline to READY", source); gst_element_set_state (priv->pipeline, GST_STATE_READY); } } @@ -384,8 +398,10 @@ static void handle_remove_source_input (PinosSourceOutput *output, gpointer user_data) { - PinosClientSourcePrivate *priv = user_data; + PinosClientSource *source = user_data; + PinosClientSourcePrivate *priv = source->priv; + g_debug ("client-source %p: remove source input %p", source, priv->input); g_clear_pointer (&priv->input, g_object_unref); } @@ -420,8 +436,9 @@ pinos_client_source_get_source_input (PinosClientSource *source, g_signal_connect (priv->input, "remove", (GCallback) handle_remove_source_input, - priv); + source); + g_debug ("client-source %p: get source input %p", source, priv->input); g_signal_connect (priv->input, "notify::socket", (GCallback) on_input_socket_notify, source); } return g_object_ref (priv->input); @@ -462,6 +479,7 @@ pinos_client_source_init (PinosClientSource * source) { source->priv = PINOS_CLIENT_SOURCE_GET_PRIVATE (source); + g_debug ("client-source %p: new", source); setup_pipeline (source); } diff --git a/pinos/server/client.c b/pinos/server/client.c index 6fb39e37f..a5c14f266 100644 --- a/pinos/server/client.c +++ b/pinos/server/client.c @@ -133,6 +133,7 @@ handle_remove_source_output (PinosSourceOutput *output, PinosClient *client = user_data; PinosClientPrivate *priv = client->priv; + g_debug ("client %p: remove source output %p", client, output); priv->outputs = g_list_remove (priv->outputs, output); g_object_unref (output); } @@ -189,6 +190,7 @@ handle_create_source_output (PinosClient1 *interface, client); object_path = pinos_source_output_get_object_path (output); + g_debug ("client %p: add source output %p, %s", client, output, object_path); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", object_path)); @@ -203,6 +205,7 @@ not_allowed: } no_source: { + g_debug ("client %p: could not find source %s, %s", client, arg_source, error->message); g_dbus_method_invocation_return_gerror (invocation, error); pinos_properties_free (props); g_bytes_unref (formats); @@ -211,6 +214,7 @@ no_source: } no_output: { + g_debug ("client %p: could not create output %s", client, error->message); g_dbus_method_invocation_return_gerror (invocation, error); g_clear_error (&error); return TRUE; @@ -263,7 +267,7 @@ handle_create_source_input (PinosClient1 *interface, g_object_unref); source_input_path = pinos_source_output_get_object_path (input); - + g_debug ("client %p: add source input %p, %s", client, input, source_input_path); priv->outputs = g_list_prepend (priv->outputs, input); g_signal_connect (input, @@ -286,6 +290,7 @@ not_allowed: } no_source: { + g_debug ("client %p: could not create source", client); g_dbus_method_invocation_return_dbus_error (invocation, "org.pinos.Error", "Can't create source"); g_bytes_unref (formats); @@ -293,6 +298,7 @@ no_source: } no_input: { + g_debug ("client %p: could not create input %s", client, error->message); g_dbus_method_invocation_return_gerror (invocation, error); g_object_unref (source); g_clear_error (&error); @@ -307,6 +313,7 @@ handle_disconnect (PinosClient1 *interface, { PinosClient *client = user_data; + g_debug ("client %p: disconnect", client); g_signal_emit (client, signals[SIGNAL_DISCONNECT], 0, NULL); g_dbus_method_invocation_return_value (invocation, @@ -343,6 +350,7 @@ client_register_object (PinosClient *client, g_free (priv->object_path); priv->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel)); + g_debug ("client %p: register %s", client, priv->object_path); } static void @@ -351,6 +359,7 @@ client_unregister_object (PinosClient *client) PinosClientPrivate *priv = client->priv; PinosDaemon *daemon = priv->daemon; + g_debug ("client %p: unregister", client); g_clear_object (&priv->client1); pinos_daemon_unexport (daemon, priv->object_path); @@ -361,6 +370,7 @@ static void do_remove_output (PinosSourceOutput *output, PinosClient *client) { + g_debug ("client %p: remove output %p", client, output); pinos_source_output_remove (output); } @@ -370,6 +380,7 @@ pinos_client_dispose (GObject * object) PinosClient *client = PINOS_CLIENT (object); PinosClientPrivate *priv = client->priv; + g_debug ("client %p: dispose", client); if (priv->object_path) pinos_fd_manager_remove_all (priv->fdmanager, priv->object_path); @@ -379,12 +390,14 @@ pinos_client_dispose (GObject * object) G_OBJECT_CLASS (pinos_client_parent_class)->dispose (object); } + static void pinos_client_finalize (GObject * object) { PinosClient *client = PINOS_CLIENT (object); PinosClientPrivate *priv = client->priv; + g_debug ("client %p: finalize", client); g_free (priv->sender); if (priv->properties) pinos_properties_free (priv->properties); @@ -399,6 +412,8 @@ pinos_client_constructed (GObject * object) PinosClient *client = PINOS_CLIENT (object); PinosClientPrivate *priv = client->priv; + g_debug ("client %p: constructed", client); + client_register_object (client, priv->object_path); G_OBJECT_CLASS (pinos_client_parent_class)->constructed (object); @@ -474,6 +489,7 @@ pinos_client_init (PinosClient * client) { PinosClientPrivate *priv = client->priv = PINOS_CLIENT_GET_PRIVATE (client); + g_debug ("client %p: new", client); priv->fdmanager = pinos_fd_manager_get (PINOS_FD_MANAGER_DEFAULT); } diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index 7307c523f..ec092de25 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -66,10 +66,9 @@ client_name_appeared_handler (GDBusConnection *connection, SenderData *data = user_data; PinosDaemonPrivate *priv = data->daemon->priv; - g_hash_table_insert (priv->senders, data->sender, data); + g_debug ("daemon %p: appeared %s %s", data->daemon, name, name_owner); - if (!g_strcmp0 (name, g_dbus_connection_get_unique_name (connection))) - return; + g_hash_table_insert (priv->senders, data->sender, data); } static void @@ -79,12 +78,15 @@ client_name_vanished_handler (GDBusConnection *connection, { SenderData *data = user_data; + g_debug ("daemon %p: vanished %s", data->daemon, name); + g_bus_unwatch_name (data->id); } static void data_free (SenderData *data) { + g_debug ("daemon %p: free sender data %p for %s", data->daemon, data, data->sender); g_list_free_full (data->objects, g_object_unref); g_hash_table_remove (data->daemon->priv->senders, data->sender); g_free (data->sender); @@ -102,6 +104,8 @@ sender_data_new (PinosDaemon *daemon, data->daemon = daemon; data->sender = g_strdup (sender); + g_debug ("daemon %p: new sender data %p for %s", daemon, data, sender); + data->id = g_bus_watch_name_on_connection (priv->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, @@ -109,8 +113,6 @@ sender_data_new (PinosDaemon *daemon, client_name_vanished_handler, data, (GDestroyNotify) data_free); - - return data; } @@ -125,10 +127,13 @@ handle_disconnect_client (PinosClient *client, sender = pinos_client_get_sender (client); + g_debug ("daemon %p: client %p disconnect %s", daemon, client, sender); + data = g_hash_table_lookup (priv->senders, sender); if (data == NULL) return; + g_debug ("daemon %p: client %p unref", daemon, client); data->objects = g_list_remove (data->objects, client); g_object_unref (client); } @@ -148,6 +153,8 @@ handle_connect_client (PinosDaemon1 *interface, sender = g_dbus_method_invocation_get_sender (invocation); + g_debug ("daemon %p: connect client: %s", daemon, sender); + props = pinos_properties_from_variant (arg_properties); client = pinos_client_new (daemon, sender, PINOS_DBUS_OBJECT_PREFIX, props); pinos_properties_free (props); @@ -161,6 +168,7 @@ handle_connect_client (PinosDaemon1 *interface, data->objects = g_list_prepend (data->objects, client); object_path = pinos_client_get_object_path (client); + g_debug ("daemon %p: added client %p with path %s", daemon, client, object_path); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", object_path)); @@ -260,6 +268,8 @@ pinos_daemon_start (PinosDaemon *daemon) priv = daemon->priv; g_return_if_fail (priv->id == 0); + g_debug ("daemon %p: start", daemon); + priv->id = g_bus_own_name (G_BUS_TYPE_SESSION, PINOS_DBUS_SERVICE, G_BUS_NAME_OWNER_FLAGS_REPLACE, @@ -283,6 +293,8 @@ pinos_daemon_stop (PinosDaemon *daemon) g_return_if_fail (PINOS_IS_DAEMON (daemon)); + g_debug ("daemon %p: stop", daemon); + if (priv->id != 0) { g_bus_unown_name (priv->id); priv->id = 0; @@ -463,6 +475,8 @@ pinos_daemon_dispose (GObject * object) { PinosDaemon *daemon = PINOS_DAEMON_CAST (object); + g_debug ("daemon %p: dispose", object); + pinos_daemon_stop (daemon); G_OBJECT_CLASS (pinos_daemon_parent_class)->dispose (object); @@ -474,6 +488,7 @@ pinos_daemon_finalize (GObject * object) PinosDaemon *daemon = PINOS_DAEMON_CAST (object); PinosDaemonPrivate *priv = daemon->priv; + g_debug ("daemon %p: finalize", object); g_clear_object (&priv->server_manager); G_OBJECT_CLASS (pinos_daemon_parent_class)->finalize (object); @@ -509,6 +524,8 @@ pinos_daemon_init (PinosDaemon * daemon) { PinosDaemonPrivate *priv = daemon->priv = PINOS_DAEMON_GET_PRIVATE (daemon); + g_debug ("daemon %p: new", daemon); + priv->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX); priv->senders = g_hash_table_new (g_str_hash, g_str_equal); } diff --git a/pinos/server/source-output.c b/pinos/server/source-output.c index aa9a5ed7b..21c188b83 100644 --- a/pinos/server/source-output.c +++ b/pinos/server/source-output.c @@ -192,6 +192,8 @@ clear_formats (PinosSourceOutput *output) { PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: clear format", output); + g_clear_pointer (&priv->requested_format, g_bytes_unref); g_clear_pointer (&priv->format, g_bytes_unref); } @@ -201,6 +203,8 @@ stop_transfer (PinosSourceOutput *output) { PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: stop transfer", output); + if (priv->socket) { g_clear_object (&priv->socket); g_object_notify (G_OBJECT (output), "socket"); @@ -222,6 +226,7 @@ handle_start (PinosSourceOutput1 *interface, PinosSourceOutputPrivate *priv = output->priv; GUnixFDList *fdlist; gint fd[2]; + const gchar *format; priv->state = PINOS_SOURCE_OUTPUT_STATE_STARTING; @@ -230,16 +235,23 @@ handle_start (PinosSourceOutput1 *interface, socketpair (AF_UNIX, SOCK_STREAM, 0, fd); + g_debug ("source-output %p: handle start, fd[%d,%d]", output, fd[0], fd[1]); + g_clear_object (&priv->socket); priv->socket = g_socket_new_from_fd (fd[0], NULL); - g_object_set_data (priv->socket, "pinos-client-path", priv->client_path); + g_object_set_data (G_OBJECT (priv->socket), "pinos-client-path", priv->client_path); + + g_debug ("source-output %p: notify socket %p, path %s", output, priv->socket, priv->client_path); g_object_notify (G_OBJECT (output), "socket"); /* the notify of the socket above should configure the format */ if (priv->format == NULL) goto no_format; + format = g_bytes_get_data (priv->format, NULL); + priv->state = PINOS_SOURCE_OUTPUT_STATE_STREAMING; + g_debug ("source-output %p: we are now streaming in format \"%s\"", output, format); fdlist = g_unix_fd_list_new (); g_unix_fd_list_append (fdlist, fd[1], NULL); @@ -247,14 +259,14 @@ handle_start (PinosSourceOutput1 *interface, g_dbus_method_invocation_return_value_with_unix_fd_list (invocation, g_variant_new ("(hs@a{sv})", 0, - g_bytes_get_data (priv->format, NULL), + format, pinos_properties_to_variant (priv->properties)), fdlist); g_object_unref (fdlist); close (fd[1]); g_object_set (priv->iface, - "format", g_bytes_get_data (priv->format, NULL), + "format", format, "state", priv->state, NULL); @@ -263,6 +275,7 @@ handle_start (PinosSourceOutput1 *interface, /* error */ no_format: { + g_debug ("source-output %p: no format configured", output); g_dbus_method_invocation_return_dbus_error (invocation, "org.pinos.Error", "No format"); close (fd[0]); @@ -280,6 +293,7 @@ handle_stop (PinosSourceOutput1 *interface, { PinosSourceOutput *output = user_data; + g_debug ("source-output %p: handle stop", output); stop_transfer (output); g_dbus_method_invocation_return_value (invocation, NULL); @@ -294,6 +308,7 @@ handle_remove (PinosSourceOutput1 *interface, { PinosSourceOutput *output = user_data; + g_debug ("source-output %p: handle remove", output); stop_transfer (output); g_signal_emit (output, signals[SIGNAL_REMOVE], 0, NULL); @@ -319,6 +334,7 @@ output_register_object (PinosSourceOutput *output, g_free (priv->object_path); priv->object_path = pinos_daemon_export_uniquely (priv->daemon, G_DBUS_OBJECT_SKELETON (skel)); + g_debug ("source-output %p: register object %s", output, priv->object_path); } static void @@ -326,6 +342,7 @@ output_unregister_object (PinosSourceOutput *output) { PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: unregister object", output); pinos_daemon_unexport (priv->daemon, priv->object_path); } @@ -335,6 +352,7 @@ pinos_source_output_dispose (GObject * object) PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object); PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: dispose", output); clear_formats (output); g_clear_object (&priv->socket); output_unregister_object (output); @@ -348,6 +366,7 @@ pinos_source_output_finalize (GObject * object) PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object); PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: finalize", output); if (priv->possible_formats) g_bytes_unref (priv->possible_formats); if (priv->properties) @@ -367,6 +386,7 @@ pinos_source_output_constructed (GObject * object) PinosSourceOutput *output = PINOS_SOURCE_OUTPUT (object); PinosSourceOutputPrivate *priv = output->priv; + g_debug ("source-output %p: constructed", output); output_register_object (output, priv->object_path); G_OBJECT_CLASS (pinos_source_output_parent_class)->constructed (object); @@ -496,11 +516,14 @@ pinos_source_output_init (PinosSourceOutput * output) priv->state = PINOS_SOURCE_OUTPUT_STATE_IDLE; g_object_set (priv->iface, "state", priv->state, NULL); + + g_debug ("source-output %p: new", output); } void pinos_source_output_remove (PinosSourceOutput *output) { + g_debug ("source-output %p: remove", output); stop_transfer (output); g_signal_emit (output, signals[SIGNAL_REMOVE], 0, NULL);