set rtspclientsink state to "NULL" will block
my app is runs on android with gstreamer 1.16.2.
the pipline has two branch as follow:
rtspsrc -> rtph264depay -> tee -> queue -> amcviddec -> queue -> autovideosink
|
.--> queue -> rtspclientsink
link these two branches dynamically.
rtspsrc and rtspclientsink are useing different network.
when network unavailable for rtspclientsink, i get an error message from it.
and then set rtspclientsink state to NULL. the func gst_element_set_state will been blocked,
if i destroy the branch directly, the app will crash.
the func gst_element_set_state is blocked because RECORD CMD cannot be canncelled.
the rtspclientsink element thread will block in the following two lines (3603,4366):
gst/rtsp-sink/gstrtspclientsink.c:
3601 while (!context->prerolled && !sink->conninfo.flushing) {
3602 GST_DEBUG_OBJECT (sink, "Waiting for caps on stream %d", context->index);
3603 g_cond_wait (&sink->preroll_cond, &sink->preroll_lock);
3604 }
4363 /* Wait for streams to be blocked */
4364 while (sink->n_streams_blocked < g_list_length (sink->contexts)) {
4365 GST_DEBUG_OBJECT (sink, "waiting for streams to be blocked");
4366 g_cond_wait (&sink->block_streams_cond, &sink->block_streams_lock);
4367 }
my solution is as follows,clumsy but temporarily effective:
diff --git a/gst/rtsp-sink/gstrtspclientsink.c b/gst/rtsp-sink/gstrtspclientsink.c
index 9b87ea3..4712c86 100644
--- a/gst/rtsp-sink/gstrtspclientsink.c
+++ b/gst/rtsp-sink/gstrtspclientsink.c
@@ -2081,6 +2081,7 @@ gst_rtsp_client_sink_connection_flush (GstRTSPClientSink * sink, gboolean flush)
stream->conninfo.flushing = flush;
}
}
+ sink->conninfo.flushing = flush;
g_cond_broadcast (&sink->preroll_cond);
g_mutex_unlock (&sink->preroll_lock);
}
@@ -3571,6 +3572,7 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink)
GstRTSPStreamContext *context;
GList *walk;
const gchar *base;
+ gint64 end_time;
gboolean has_slash;
GST_DEBUG_OBJECT (sink, "Collecting stream information");
@@ -3600,7 +3602,8 @@ gst_rtsp_client_sink_collect_streams (GstRTSPClientSink * sink)
g_mutex_lock (&sink->preroll_lock);
while (!context->prerolled && !sink->conninfo.flushing) {
GST_DEBUG_OBJECT (sink, "Waiting for caps on stream %d", context->index);
- g_cond_wait (&sink->preroll_cond, &sink->preroll_lock);
+ end_time = g_get_monotonic_time () + G_TIME_SPAN_MILLISECOND * 500;
+ g_cond_wait_until (&sink->preroll_cond, &sink->preroll_lock, end_time);
}
if (sink->conninfo.flushing) {
g_mutex_unlock (&sink->preroll_lock);
@@ -4343,6 +4346,7 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async)
GInetAddress *ia;
GSocket *conn_socket;
GList *walk;
+ gint64 end_time;
g_mutex_lock (&sink->preroll_lock);
if (sink->state == GST_RTSP_STATE_PLAYING) {
@@ -4361,11 +4365,14 @@ gst_rtsp_client_sink_record (GstRTSPClientSink * sink, gboolean async)
g_mutex_lock (&sink->block_streams_lock);
/* Wait for streams to be blocked */
- while (sink->n_streams_blocked < g_list_length (sink->contexts)) {
+ while ((sink->n_streams_blocked < g_list_length (sink->contexts)) && ! sink->conninfo.flushing) {
GST_DEBUG_OBJECT (sink, "waiting for streams to be blocked");
- g_cond_wait (&sink->block_streams_cond, &sink->block_streams_lock);
+ end_time = g_get_monotonic_time () + G_TIME_SPAN_MILLISECOND * 500;
+ g_cond_wait_until (&sink->block_streams_cond, &sink->block_streams_lock, end_time);
}
g_mutex_unlock (&sink->block_streams_lock);
+ if (sink->conninfo.flushing)
+ return GST_RTSP_EINTR;
/* Send announce, then setup for all streams */
gst_sdp_message_init (&sink->cursdp);
any good ideas?