diff --git a/src/client/context.c b/src/client/context.c index ede4bbd1c..2fb51bc50 100644 --- a/src/client/context.c +++ b/src/client/context.c @@ -137,6 +137,8 @@ pinos_context_finalize (GObject * object) PinosContext *context = PINOS_CONTEXT (object); PinosContextPrivate *priv = context->priv; + g_debug ("free context %p", context); + if (priv->id) g_bus_unwatch_name(priv->id); @@ -145,6 +147,9 @@ pinos_context_finalize (GObject * object) if (priv->properties) pinos_properties_free (priv->properties); + g_list_free (priv->sources); + g_list_free (priv->clients); + g_list_free (priv->source_outputs); g_clear_object (&priv->subscribe); g_clear_error (&priv->error); @@ -272,11 +277,22 @@ pinos_context_init (PinosContext * context) { PinosContextPrivate *priv = context->priv = PINOS_CONTEXT_GET_PRIVATE (context); + g_debug ("new context %p", context); + priv->state = PINOS_CONTEXT_STATE_UNCONNECTED; + priv->subscribe = pinos_subscribe_new (); - g_object_set (priv->subscribe, "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, NULL); - g_signal_connect (priv->subscribe, "subscription-event", (GCallback) subscription_cb, context); - g_signal_connect (priv->subscribe, "notify::state", (GCallback) subscription_state, context); + g_object_set (priv->subscribe, + "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, + NULL); + g_signal_connect (priv->subscribe, + "subscription-event", + (GCallback) subscription_cb, + context); + g_signal_connect (priv->subscribe, + "notify::state", + (GCallback) subscription_state, + context); } /** @@ -324,13 +340,21 @@ do_notify_state (PinosContext *context) static void context_set_state (PinosContext *context, - PinosContextState state) + PinosContextState state, + GError *error) { if (context->priv->state != state) { + if (error) { + g_clear_error (&context->priv->error); + context->priv->error = error; + } context->priv->state = state; g_main_context_invoke (context->priv->context, (GSourceFunc) do_notify_state, g_object_ref (context)); + } else { + if (error) + g_error_free (error); } } static void @@ -348,15 +372,14 @@ on_client_proxy (GObject *source_object, if (priv->client == NULL) goto client_failed; - context_set_state (context, PINOS_CONTEXT_STATE_READY); + context_set_state (context, PINOS_CONTEXT_STATE_READY, NULL); return; client_failed: { - priv->error = error; - context_set_state (context, PINOS_STREAM_STATE_ERROR); g_warning ("failed to get client proxy: %s", error->message); + context_set_state (context, PINOS_STREAM_STATE_ERROR, error); return; } } @@ -375,8 +398,7 @@ on_client_connected (GObject *source_object, ret = g_dbus_proxy_call_finish (priv->daemon, res, &error); if (ret == NULL) { g_warning ("failed to connect client: %s", error->message); - priv->error = error; - context_set_state (context, PINOS_CONTEXT_STATE_ERROR); + context_set_state (context, PINOS_CONTEXT_STATE_ERROR, error); return; } @@ -401,7 +423,7 @@ on_daemon_connected (GObject *source_object, PinosContextPrivate *priv = context->priv; GVariant *variant; - context_set_state (context, PINOS_CONTEXT_STATE_REGISTERING); + context_set_state (context, PINOS_CONTEXT_STATE_REGISTERING, NULL); variant = pinos_properties_to_variant (priv->properties); @@ -436,9 +458,12 @@ subscription_cb (PinosSubscribe *subscribe, } else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) { priv->clients = g_list_remove (priv->clients, object); - if (object == priv->client) { - priv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CLOSED, "Client disappeared"); - context_set_state (context, PINOS_CONTEXT_STATE_ERROR); + if (object == priv->client && !priv->disconnecting) { + context_set_state (context, + PINOS_CONTEXT_STATE_ERROR, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_CLOSED, + "Client disappeared")); } } break; @@ -520,10 +545,13 @@ on_name_vanished (GDBusConnection *connection, g_object_set (priv->subscribe, "connection", connection, NULL); if (priv->flags & PINOS_CONTEXT_FLAGS_NOFAIL) { - context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING); + context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL); } else { - priv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CLOSED, "Connection closed"); - context_set_state (context, PINOS_CONTEXT_STATE_ERROR); + context_set_state (context, + PINOS_CONTEXT_STATE_ERROR, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_CLOSED, + "Connection closed")); } } @@ -571,7 +599,7 @@ pinos_context_connect (PinosContext *context, priv->flags = flags; - context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING); + context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL); g_main_context_invoke (priv->context, (GSourceFunc) do_connect, g_object_ref (context)); @@ -591,7 +619,7 @@ finish_client_disconnect (PinosContext *context) priv->id = 0; } - context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED); + context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL); } static void @@ -604,11 +632,12 @@ on_client_disconnected (GObject *source_object, GError *error = NULL; GVariant *ret; + priv->disconnecting = FALSE; + ret = g_dbus_proxy_call_finish (priv->client, res, &error); if (ret == NULL) { g_warning ("failed to disconnect client: %s", error->message); - priv->error = error; - context_set_state (context, PINOS_CONTEXT_STATE_ERROR); + context_set_state (context, PINOS_CONTEXT_STATE_ERROR, error); g_object_unref (context); return; } @@ -651,12 +680,15 @@ pinos_context_disconnect (PinosContext *context) g_return_val_if_fail (PINOS_IS_CONTEXT (context), FALSE); priv = context->priv; + g_return_val_if_fail (!priv->disconnecting, FALSE); if (priv->client == NULL) { finish_client_disconnect (context); return TRUE; } + priv->disconnecting = TRUE; + g_main_context_invoke (priv->context, (GSourceFunc) do_disconnect, g_object_ref (context)); diff --git a/src/client/private.h b/src/client/private.h index cf397ccef..43424e843 100644 --- a/src/client/private.h +++ b/src/client/private.h @@ -34,6 +34,7 @@ struct _PinosContextPrivate GDBusProxy *daemon; GDBusProxy *client; + gboolean disconnecting; PinosSubscriptionFlags subscription_mask; PinosSubscribe *subscribe; @@ -56,8 +57,8 @@ GDBusProxy * pinos_subscribe_get_proxy_finish (PinosSubscribe *subsc typedef struct { - guint32 version; PinosBufferHeader header; + guint32 version; guint32 length; } PinosStackHeader; diff --git a/src/client/stream.c b/src/client/stream.c index f726039ba..907e780ef 100644 --- a/src/client/stream.c +++ b/src/client/stream.c @@ -165,13 +165,21 @@ do_notify_state (PinosStream *stream) static void stream_set_state (PinosStream *stream, - PinosStreamState state) + PinosStreamState state, + GError *error) { if (stream->priv->state != state) { + if (error) { + g_clear_error (&stream->priv->error); + stream->priv->error = error; + } stream->priv->state = state; g_main_context_invoke (stream->priv->context->priv->context, (GSourceFunc) do_notify_state, g_object_ref (stream)); + } else { + if (error) + g_error_free (error); } } @@ -189,8 +197,11 @@ subscription_cb (PinosSubscribe *subscribe, case PINOS_SUBSCRIPTION_FLAG_SOURCE_OUTPUT: if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) { if (object == priv->source_output && !priv->disconnecting) { - priv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CLOSED, "output disappeared"); - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); + stream_set_state (stream, + PINOS_STREAM_STATE_ERROR, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_CLOSED, + "Output disappeared")); } } break; @@ -220,6 +231,9 @@ pinos_stream_finalize (GObject * object) PinosStream *stream = PINOS_STREAM (object); PinosStreamPrivate *priv = stream->priv; + g_debug ("free stream %p", stream); + + g_clear_object (&priv->socket); g_clear_object (&priv->source_output); if (priv->possible_formats) @@ -383,6 +397,8 @@ pinos_stream_init (PinosStream * stream) { PinosStreamPrivate *priv = stream->priv = PINOS_STREAM_GET_PRIVATE (stream); + g_debug ("new stream %p", stream); + priv->state = PINOS_STREAM_STATE_UNCONNECTED; } @@ -495,16 +511,15 @@ on_source_output_proxy (GObject *source_object, g_object_notify (G_OBJECT (stream), "properties"); } - stream_set_state (stream, PINOS_STREAM_STATE_READY); + stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); g_object_unref (stream); return; source_output_failed: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to get source output proxy: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); g_object_unref (stream); return; } @@ -528,7 +543,7 @@ on_source_output_created (GObject *source_object, if (ret == NULL) goto create_failed; - g_variant_get (ret, "(o)", &source_output_path); + g_variant_get (ret, "(&o)", &source_output_path); pinos_subscribe_get_proxy (context->priv->subscribe, PINOS_DBUS_SERVICE, @@ -544,9 +559,8 @@ on_source_output_created (GObject *source_object, /* ERRORS */ create_failed: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to get connect capture: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); g_object_unref (stream); return; } @@ -608,7 +622,7 @@ pinos_stream_connect_capture (PinosStream *stream, priv->accepted_formats = accepted_formats; priv->provide = FALSE; - stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING); + stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING, NULL); g_main_context_invoke (context->priv->context, (GSourceFunc) do_connect_capture, @@ -667,7 +681,7 @@ pinos_stream_connect_provide (PinosStream *stream, priv->possible_formats = possible_formats; priv->provide = TRUE; - stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING); + stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING, NULL); g_main_context_invoke (context->priv->context, (GSourceFunc) do_connect_provide, @@ -695,16 +709,17 @@ on_source_output_removed (GObject *source_object, if (ret == NULL) goto proxy_failed; - stream_set_state (stream, PINOS_STREAM_STATE_UNCONNECTED); + g_variant_unref (ret); + + stream_set_state (stream, PINOS_STREAM_STATE_UNCONNECTED, NULL); g_object_unref (stream); return; /* ERRORS */ proxy_failed: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to disconnect: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); g_object_unref (stream); return; } @@ -887,9 +902,8 @@ handle_socket (PinosStream *stream, gint fd) /* ERRORS */ socket_failed: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to create socket: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); return; } } @@ -960,9 +974,11 @@ on_stream_started (GObject *source_object, if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0) goto fd_failed; + g_object_unref (out_fd_list); + handle_socket (stream, fd); - stream_set_state (stream, PINOS_STREAM_STATE_STREAMING); + stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL); return; @@ -975,12 +991,12 @@ start_failed: fd_failed: { g_warning ("failed to get FD: %s", error->message); + g_object_unref (out_fd_list); goto exit_error; } exit_error: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); return; } } @@ -1034,7 +1050,7 @@ pinos_stream_start (PinosStream *stream, priv->mode = mode; priv->format = format; - stream_set_state (stream, PINOS_STREAM_STATE_STARTING); + stream_set_state (stream, PINOS_STREAM_STATE_STARTING, NULL); g_main_context_invoke (priv->context->priv->context, (GSourceFunc) do_start, stream); @@ -1061,16 +1077,15 @@ on_stream_stopped (GObject *source_object, g_clear_pointer (&priv->format, g_free); g_object_notify (G_OBJECT (stream), "format"); - stream_set_state (stream, PINOS_STREAM_STATE_READY); + stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); return; /* ERRORS */ call_failed: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to release: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); return; } } @@ -1223,11 +1238,6 @@ pinos_stream_provide_buffer (PinosStream *stream, flags, NULL, &error); - if (sb->message) { - g_object_unref (sb->message); - sb->message = NULL; - } - if (len == -1) goto send_error; @@ -1237,9 +1247,8 @@ pinos_stream_provide_buffer (PinosStream *stream, send_error: { - priv->error = error; - stream_set_state (stream, PINOS_STREAM_STATE_ERROR); g_warning ("failed to send_message: %s", error->message); + stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); return FALSE; } } diff --git a/src/gst/gstpinossink.c b/src/gst/gstpinossink.c index ac0b1db2a..a36e92c75 100644 --- a/src/gst/gstpinossink.c +++ b/src/gst/gstpinossink.c @@ -244,7 +244,7 @@ on_stream_notify (GObject *gobject, GstPinosSink *pinossink = user_data; state = pinos_stream_get_state (stream); - GST_DEBUG ("got stream state %d\n", state); + GST_DEBUG ("got stream state %d", state); switch (state) { case PINOS_STREAM_STATE_UNCONNECTED: @@ -394,6 +394,7 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) if (pinos_stream_get_state (pinossink->stream) != PINOS_STREAM_STATE_STREAMING) goto streaming_error; pinos_stream_provide_buffer (pinossink->stream, &pbuf); + pinos_buffer_clear (&pbuf); pinos_main_loop_unlock (pinossink->loop); return GST_FLOW_OK; @@ -452,7 +453,7 @@ on_context_notify (GObject *gobject, PinosContextState state; state = pinos_context_get_state (ctx); - GST_DEBUG ("got context state %d\n", state); + GST_DEBUG ("got context state %d", state); switch (state) { case PINOS_CONTEXT_STATE_UNCONNECTED: @@ -475,7 +476,7 @@ gst_pinos_sink_open (GstPinosSink * pinossink) GError *error = NULL; pinossink->context = g_main_context_new (); - GST_DEBUG ("context %p\n", pinossink->context); + GST_DEBUG ("context %p", pinossink->context); pinossink->loop = pinos_main_loop_new (pinossink->context, "pinos-sink-loop"); if (!pinos_main_loop_start (pinossink->loop, &error))