mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
screen-cast-src: Notify about the stream being closed after dispatch
We're iterating inside the PipeWire loop when detecting PipeWire errors,
and shouldn't destroy the PipeWire objects mid-iteration. Avoid this by
first disabling the stream src (effectively stopping the recording),
then notifying about it being closed in an idle callback. The
notification eventually makes the rest of the screen cast code clean up
the objects, including the src and the associated PipeWire objects, but
will do so outside the PipeWire loop iteration.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1251
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit c8e12ead08
)
This commit is contained in:
parent
31307720bf
commit
63fc71f05b
@ -68,6 +68,7 @@ typedef struct _MetaPipeWireSource
|
|||||||
{
|
{
|
||||||
GSource base;
|
GSource base;
|
||||||
|
|
||||||
|
MetaScreenCastStreamSrc *src;
|
||||||
struct pw_loop *pipewire_loop;
|
struct pw_loop *pipewire_loop;
|
||||||
} MetaPipeWireSource;
|
} MetaPipeWireSource;
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ typedef struct _MetaScreenCastStreamSrcPrivate
|
|||||||
struct spa_hook pipewire_core_listener;
|
struct spa_hook pipewire_core_listener;
|
||||||
|
|
||||||
gboolean is_enabled;
|
gboolean is_enabled;
|
||||||
|
gboolean emit_closed_after_dispatch;
|
||||||
|
|
||||||
struct pw_stream *pipewire_stream;
|
struct pw_stream *pipewire_stream;
|
||||||
struct spa_hook pipewire_stream_listener;
|
struct spa_hook pipewire_stream_listener;
|
||||||
@ -540,12 +542,6 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src)
|
|||||||
priv->is_enabled = FALSE;
|
priv->is_enabled = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
meta_screen_cast_stream_src_notify_closed (MetaScreenCastStreamSrc *src)
|
|
||||||
{
|
|
||||||
g_signal_emit (src, signals[CLOSED], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_stream_state_changed (void *data,
|
on_stream_state_changed (void *data,
|
||||||
enum pw_stream_state old,
|
enum pw_stream_state old,
|
||||||
@ -560,7 +556,9 @@ on_stream_state_changed (void *data,
|
|||||||
{
|
{
|
||||||
case PW_STREAM_STATE_ERROR:
|
case PW_STREAM_STATE_ERROR:
|
||||||
g_warning ("pipewire stream error: %s", error_message);
|
g_warning ("pipewire stream error: %s", error_message);
|
||||||
meta_screen_cast_stream_src_notify_closed (src);
|
if (meta_screen_cast_stream_src_is_enabled (src))
|
||||||
|
meta_screen_cast_stream_src_disable (src);
|
||||||
|
priv->emit_closed_after_dispatch = TRUE;
|
||||||
break;
|
break;
|
||||||
case PW_STREAM_STATE_PAUSED:
|
case PW_STREAM_STATE_PAUSED:
|
||||||
if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream)
|
if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream)
|
||||||
@ -828,11 +826,17 @@ on_core_error (void *data,
|
|||||||
const char *message)
|
const char *message)
|
||||||
{
|
{
|
||||||
MetaScreenCastStreamSrc *src = data;
|
MetaScreenCastStreamSrc *src = data;
|
||||||
|
MetaScreenCastStreamSrcPrivate *priv =
|
||||||
|
meta_screen_cast_stream_src_get_instance_private (src);
|
||||||
|
|
||||||
g_warning ("pipewire remote error: id:%u %s", id, message);
|
g_warning ("pipewire remote error: id:%u %s", id, message);
|
||||||
|
|
||||||
if (id == PW_ID_CORE && res == -EPIPE)
|
if (id == PW_ID_CORE && res == -EPIPE)
|
||||||
meta_screen_cast_stream_src_notify_closed (src);
|
{
|
||||||
|
if (meta_screen_cast_stream_src_is_enabled (src))
|
||||||
|
meta_screen_cast_stream_src_disable (src);
|
||||||
|
priv->emit_closed_after_dispatch = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -849,12 +853,18 @@ pipewire_loop_source_dispatch (GSource *source,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
|
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
|
||||||
|
MetaScreenCastStreamSrc *src = pipewire_source->src;
|
||||||
|
MetaScreenCastStreamSrcPrivate *priv =
|
||||||
|
meta_screen_cast_stream_src_get_instance_private (src);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = pw_loop_iterate (pipewire_source->pipewire_loop, 0);
|
result = pw_loop_iterate (pipewire_source->pipewire_loop, 0);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
|
g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
|
||||||
|
|
||||||
|
if (priv->emit_closed_after_dispatch)
|
||||||
|
g_signal_emit (src, signals[CLOSED], 0);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,13 +886,14 @@ static GSourceFuncs pipewire_source_funcs =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static MetaPipeWireSource *
|
static MetaPipeWireSource *
|
||||||
create_pipewire_source (void)
|
create_pipewire_source (MetaScreenCastStreamSrc *src)
|
||||||
{
|
{
|
||||||
MetaPipeWireSource *pipewire_source;
|
MetaPipeWireSource *pipewire_source;
|
||||||
|
|
||||||
pipewire_source =
|
pipewire_source =
|
||||||
(MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
|
(MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
|
||||||
sizeof (MetaPipeWireSource));
|
sizeof (MetaPipeWireSource));
|
||||||
|
pipewire_source->src = src;
|
||||||
pipewire_source->pipewire_loop = pw_loop_new (NULL);
|
pipewire_source->pipewire_loop = pw_loop_new (NULL);
|
||||||
if (!pipewire_source->pipewire_loop)
|
if (!pipewire_source->pipewire_loop)
|
||||||
{
|
{
|
||||||
@ -914,7 +925,7 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
|
|||||||
MetaScreenCastStreamSrcPrivate *priv =
|
MetaScreenCastStreamSrcPrivate *priv =
|
||||||
meta_screen_cast_stream_src_get_instance_private (src);
|
meta_screen_cast_stream_src_get_instance_private (src);
|
||||||
|
|
||||||
priv->pipewire_source = create_pipewire_source ();
|
priv->pipewire_source = create_pipewire_source (src);
|
||||||
if (!priv->pipewire_source)
|
if (!priv->pipewire_source)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
Loading…
Reference in New Issue
Block a user