rtpsession: expose timeout-inactive-sources property

In some situations it is not desirable to time out when no data is
received any longer, users can opt in to this behavior via a new
property.

The property is also exposed on rtpbin and sdpdemux

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4880>
This commit is contained in:
Mathieu Duponchelle 2023-06-16 21:53:11 +02:00 committed by GStreamer Marge Bot
parent 170dcd58db
commit 7445b73e76
9 changed files with 188 additions and 21 deletions

View file

@ -229820,6 +229820,18 @@
"readable": true,
"type": "guint64",
"writable": true
},
"timeout-inactive-rtp-sources": {
"blurb": "Whether RTP sources that don't receive RTP or RTCP packets for longer than 5x RTCP interval should be removed",
"conditionally-available": false,
"construct": true,
"construct-only": false,
"controllable": false,
"default": "true",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
}
},
"rank": "none",

View file

@ -79,6 +79,7 @@ enum
#define DEFAULT_REDIRECT TRUE
#define DEFAULT_RTCP_MODE GST_SDP_DEMUX_RTCP_MODE_SENDRECV
#define DEFAULT_MEDIA NULL
#define DEFAULT_TIMEOUT_INACTIVE_RTP_SOURCES TRUE
enum
{
@ -89,6 +90,7 @@ enum
PROP_REDIRECT,
PROP_RTCP_MODE,
PROP_MEDIA,
PROP_TIMEOUT_INACTIVE_RTP_SOURCES,
};
static void gst_sdp_demux_finalize (GObject * object);
@ -202,6 +204,23 @@ gst_sdp_demux_class_init (GstSDPDemuxClass * klass)
"Media to use, e.g. audio or video (NULL = all)", DEFAULT_MEDIA,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstSDPDemux:timeout-inactive-rtp-sources:
*
* Whether inactive RTP sources in the underlying RTP session
* should be timed out.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class,
PROP_TIMEOUT_INACTIVE_RTP_SOURCES,
g_param_spec_boolean ("timeout-inactive-rtp-sources",
"Time out inactive sources",
"Whether RTP sources that don't receive RTP or RTCP packets for longer "
"than 5x RTCP interval should be removed",
DEFAULT_TIMEOUT_INACTIVE_RTP_SOURCES,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
gst_element_class_add_static_pad_template (gstelement_class, &rtptemplate);
@ -284,6 +303,9 @@ gst_sdp_demux_set_property (GObject * object, guint prop_id,
demux->media = g_intern_string (g_value_get_string (value));
GST_OBJECT_UNLOCK (demux);
break;
case PROP_TIMEOUT_INACTIVE_RTP_SOURCES:
demux->timeout_inactive_rtp_sources = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -319,6 +341,9 @@ gst_sdp_demux_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_string (value, demux->media);
GST_OBJECT_UNLOCK (demux);
break;
case PROP_TIMEOUT_INACTIVE_RTP_SOURCES:
g_value_set_boolean (value, demux->timeout_inactive_rtp_sources);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1021,6 +1046,9 @@ gst_sdp_demux_configure_manager (GstSDPDemux * demux, char *rtsp_sdp)
demux);
g_signal_connect (demux->session, "on-timeout", (GCallback) on_timeout,
demux);
g_object_set (demux->session, "timeout-inactive-sources",
demux->timeout_inactive_rtp_sources, NULL);
}
g_object_set (demux->session, "latency", demux->latency, NULL);

View file

@ -124,6 +124,7 @@ struct _GstSDPDemux {
gboolean redirect;
const gchar *media; /* if non-NULL only hook up these kinds of media (video/audio) */ /* interned string */
GstSDPDemuxRTCPMode rtcp_mode;
gboolean timeout_inactive_rtp_sources;
/* session management */
GstElement *session;

View file

@ -17679,6 +17679,18 @@
"type": "GstStructure",
"writable": true
},
"timeout-inactive-sources": {
"blurb": "Whether sources that don't receive RTP or RTCP packets for longer than 5x RTCP interval should be removed",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "true",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"ts-offset-smoothing-factor": {
"blurb": "Sets a smoothing factor for the timestamp offset in number of values for a calculated running moving average. (0 = no smoothing factor)",
"conditionally-available": false,
@ -19611,6 +19623,18 @@
"type": "GstStructure",
"writable": false
},
"timeout-inactive-sources": {
"blurb": "Whether sources that don't receive RTP or RTCP packets for longer than 5x RTCP interval should be removed",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "true",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"twcc-stats": {
"blurb": "Various statistics from TWCC",
"conditionally-available": false,
@ -20454,6 +20478,18 @@
"type": "GstStructure",
"writable": false
},
"timeout-inactive-sources": {
"blurb": "Whether sources that don't receive RTP or RTCP packets for longer than 5x RTCP interval should be removed",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "true",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"twcc-feedback-interval": {
"blurb": "The interval to send TWCC reports on",
"conditionally-available": false,

View file

@ -358,6 +358,7 @@ enum
#define DEFAULT_MIN_TS_OFFSET MIN_TS_OFFSET_ROUND_OFF_COMP
#define DEFAULT_TS_OFFSET_SMOOTHING_FACTOR 0
#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE
#define DEFAULT_TIMEOUT_INACTIVE_SOURCES TRUE
enum
{
@ -391,6 +392,7 @@ enum
PROP_FEC_DECODERS,
PROP_FEC_ENCODERS,
PROP_UPDATE_NTP64_HEADER_EXT,
PROP_TIMEOUT_INACTIVE_SOURCES,
};
#define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type())
@ -783,6 +785,9 @@ create_session (GstRtpBin * rtpbin, gint id)
g_object_set (session, "update-ntp64-header-ext",
rtpbin->update_ntp64_header_ext, NULL);
g_object_set (session, "timeout-inactive-sources",
rtpbin->timeout_inactive_sources, NULL);
GST_OBJECT_UNLOCK (rtpbin);
/* provide clock_rate to the session manager when needed */
@ -3002,6 +3007,22 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
DEFAULT_UPDATE_NTP64_HEADER_EXT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRtpBin:timeout-inactive-sources:
*
* Whether inactive sources should be timed out
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class,
PROP_TIMEOUT_INACTIVE_SOURCES,
g_param_spec_boolean ("timeout-inactive-sources",
"Time out inactive sources",
"Whether sources that don't receive RTP or RTCP packets for longer "
"than 5x RTCP interval should be removed",
DEFAULT_TIMEOUT_INACTIVE_SOURCES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
@ -3093,6 +3114,7 @@ gst_rtp_bin_init (GstRtpBin * rtpbin)
rtpbin->min_ts_offset_is_set = FALSE;
rtpbin->ts_offset_smoothing_factor = DEFAULT_TS_OFFSET_SMOOTHING_FACTOR;
rtpbin->update_ntp64_header_ext = DEFAULT_UPDATE_NTP64_HEADER_EXT;
rtpbin->timeout_inactive_sources = DEFAULT_TIMEOUT_INACTIVE_SOURCES;
/* some default SDES entries */
cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
@ -3439,6 +3461,13 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id,
gst_rtp_bin_propagate_property_to_session (rtpbin,
"update-ntp64-header-ext", value);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
GST_RTP_BIN_LOCK (rtpbin);
rtpbin->timeout_inactive_sources = g_value_get_boolean (value);
GST_RTP_BIN_UNLOCK (rtpbin);
gst_rtp_bin_propagate_property_to_session (rtpbin,
"timeout-inactive-sources", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -3551,6 +3580,9 @@ gst_rtp_bin_get_property (GObject * object, guint prop_id,
case PROP_UPDATE_NTP64_HEADER_EXT:
g_value_set_boolean (value, rtpbin->update_ntp64_header_ext);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
g_value_set_boolean (value, rtpbin->timeout_inactive_sources);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -100,6 +100,8 @@ struct _GstRtpBin {
gboolean update_ntp64_header_ext;
gboolean timeout_inactive_sources;
/*< private >*/
GstRtpBinPrivate *priv;
};

View file

@ -224,6 +224,7 @@ enum
#define DEFAULT_NTP_TIME_SOURCE GST_RTP_NTP_TIME_SOURCE_NTP
#define DEFAULT_RTCP_SYNC_SEND_TIME TRUE
#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE
#define DEFAULT_TIMEOUT_INACTIVE_SOURCES TRUE
enum
{
@ -246,7 +247,8 @@ enum
PROP_RTP_PROFILE,
PROP_NTP_TIME_SOURCE,
PROP_RTCP_SYNC_SEND_TIME,
PROP_UPDATE_NTP64_HEADER_EXT
PROP_UPDATE_NTP64_HEADER_EXT,
PROP_TIMEOUT_INACTIVE_SOURCES,
};
#define GST_RTP_SESSION_LOCK(sess) g_mutex_lock (&(sess)->priv->lock)
@ -830,6 +832,22 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass)
DEFAULT_UPDATE_NTP64_HEADER_EXT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRtpSession:timeout-inactive-sources:
*
* Whether inactive sources should be timed out
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class,
PROP_TIMEOUT_INACTIVE_SOURCES,
g_param_spec_boolean ("timeout-inactive-sources",
"Time out inactive sources",
"Whether sources that don't receive RTP or RTCP packets for longer "
"than 5x RTCP interval should be removed",
DEFAULT_TIMEOUT_INACTIVE_SOURCES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
gstelement_class->request_new_pad =
@ -1008,6 +1026,10 @@ gst_rtp_session_set_property (GObject * object, guint prop_id,
g_object_set_property (G_OBJECT (priv->session),
"update-ntp64-header-ext", value);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
g_object_set_property (G_OBJECT (priv->session),
"timeout-inactive-sources", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1091,6 +1113,10 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
g_object_get_property (G_OBJECT (priv->session),
"update-ntp64-header-ext", value);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
g_object_get_property (G_OBJECT (priv->session),
"timeout-inactive-sources", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -82,6 +82,7 @@ enum
#define DEFAULT_FAVOR_NEW FALSE
#define DEFAULT_TWCC_FEEDBACK_INTERVAL GST_CLOCK_TIME_NONE
#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE
#define DEFAULT_TIMEOUT_INACTIVE_SOURCES TRUE
enum
{
@ -110,6 +111,7 @@ enum
PROP_RTCP_DISABLE_SR_TIMESTAMP,
PROP_TWCC_FEEDBACK_INTERVAL,
PROP_UPDATE_NTP64_HEADER_EXT,
PROP_TIMEOUT_INACTIVE_SOURCES,
PROP_LAST,
};
@ -660,6 +662,21 @@ rtp_session_class_init (RTPSessionClass * klass)
DEFAULT_UPDATE_NTP64_HEADER_EXT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
* RTPSession:timeout-inactive-sources:
*
* Whether inactive sources should be timed out
*
* Since: 1.24
*/
properties[PROP_TIMEOUT_INACTIVE_SOURCES] =
g_param_spec_boolean ("timeout-inactive-sources",
"Time out inactive sources",
"Whether sources that don't receive RTP or RTCP packets for longer "
"than 5x RTCP interval should be removed",
DEFAULT_TIMEOUT_INACTIVE_SOURCES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, properties);
klass->get_source_by_ssrc =
@ -706,6 +723,7 @@ rtp_session_init (RTPSession * sess)
sess->mtu = DEFAULT_RTCP_MTU;
sess->update_ntp64_header_ext = DEFAULT_UPDATE_NTP64_HEADER_EXT;
sess->timeout_inactive_sources = DEFAULT_TIMEOUT_INACTIVE_SOURCES;
sess->probation = DEFAULT_PROBATION;
sess->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
@ -950,6 +968,9 @@ rtp_session_set_property (GObject * object, guint prop_id,
case PROP_UPDATE_NTP64_HEADER_EXT:
sess->update_ntp64_header_ext = g_value_get_boolean (value);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
sess->timeout_inactive_sources = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1039,6 +1060,9 @@ rtp_session_get_property (GObject * object, guint prop_id,
case PROP_UPDATE_NTP64_HEADER_EXT:
g_value_set_boolean (value, sess->update_ntp64_header_ext);
break;
case PROP_TIMEOUT_INACTIVE_SOURCES:
g_value_set_boolean (value, sess->timeout_inactive_sources);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -3793,6 +3817,7 @@ typedef struct
gboolean may_suppress;
GQueue output;
guint nacked_seqnums;
gboolean timeout_inactive_sources;
} ReportData;
static void
@ -4186,27 +4211,29 @@ session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
remove = TRUE;
}
/* sources that were inactive for more than 5 times the deterministic reporting
* interval get timed out. the min timeout is 5 seconds. */
/* mind old time that might pre-date last time going to PLAYING */
btime = MAX (source->last_activity, sess->start_time);
if (data->current_time > btime) {
interval = MAX (binterval * 5, 5 * GST_SECOND);
if (data->current_time - btime > interval) {
GST_DEBUG ("removing timeout source %08x, last %" GST_TIME_FORMAT,
source->ssrc, GST_TIME_ARGS (btime));
if (source->internal) {
/* this is an internal source that is not using our suggested ssrc.
* since there must be another source using this ssrc, we can remove
* this one instead of making it a receiver forever */
if (source->ssrc != sess->suggested_ssrc
&& source->media_ssrc != sess->suggested_ssrc) {
rtp_source_mark_bye (source, "timed out");
/* do not schedule bye here, since we are inside the RTCP timeout
* processing and scheduling bye will interfere with SR/RR sending */
if (data->timeout_inactive_sources) {
/* sources that were inactive for more than 5 times the deterministic reporting
* interval get timed out. the min timeout is 5 seconds. */
/* mind old time that might pre-date last time going to PLAYING */
btime = MAX (source->last_activity, sess->start_time);
if (data->current_time > btime) {
interval = MAX (binterval * 5, 5 * GST_SECOND);
if (data->current_time - btime > interval) {
GST_DEBUG ("removing timeout source %08x, last %" GST_TIME_FORMAT,
source->ssrc, GST_TIME_ARGS (btime));
if (source->internal) {
/* this is an internal source that is not using our suggested ssrc.
* since there must be another source using this ssrc, we can remove
* this one instead of making it a receiver forever */
if (source->ssrc != sess->suggested_ssrc
&& source->media_ssrc != sess->suggested_ssrc) {
rtp_source_mark_bye (source, "timed out");
/* do not schedule bye here, since we are inside the RTCP timeout
* processing and scheduling bye will interfere with SR/RR sending */
}
} else {
remove = TRUE;
}
} else {
remove = TRUE;
}
}
}
@ -4660,6 +4687,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
data.num_to_report = 0;
data.may_suppress = FALSE;
data.nacked_seqnums = 0;
data.timeout_inactive_sources = sess->timeout_inactive_sources;
g_queue_init (&data.output);
RTP_SESSION_LOCK (sess);

View file

@ -315,6 +315,8 @@ struct _RTPSession {
gboolean update_ntp64_header_ext;
gboolean timeout_inactive_sources;
/* Transport-wide cc-extension */
RTPTWCCManager *twcc;
RTPTWCCStats *twcc_stats;