mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
rtpsession: Add property for selecting RTP profile (AVP/AVPF/etc)
And modify our RTCP scheduling algorithm accordingly. We now can send more RTCP packets if needed for feedback, but will throttle full RTCP packets by rtcp-min-interval (t-rr-int from RFC4585). In non-feedback mode, rtcp-min-interval is Tmin from RFC3550, which is statically set to 1s or 0s by RFC4585. Tmin defines how often we should send RTCP packets at most. https://bugzilla.gnome.org/show_bug.cgi?id=746543
This commit is contained in:
parent
8fd3e0e125
commit
3122ef4ae3
6 changed files with 78 additions and 18 deletions
|
@ -201,6 +201,7 @@ enum
|
||||||
#define DEFAULT_USE_PIPELINE_CLOCK FALSE
|
#define DEFAULT_USE_PIPELINE_CLOCK FALSE
|
||||||
#define DEFAULT_RTCP_MIN_INTERVAL (RTP_STATS_MIN_INTERVAL * GST_SECOND)
|
#define DEFAULT_RTCP_MIN_INTERVAL (RTP_STATS_MIN_INTERVAL * GST_SECOND)
|
||||||
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
|
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
|
||||||
|
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -216,7 +217,8 @@ enum
|
||||||
PROP_USE_PIPELINE_CLOCK,
|
PROP_USE_PIPELINE_CLOCK,
|
||||||
PROP_RTCP_MIN_INTERVAL,
|
PROP_RTCP_MIN_INTERVAL,
|
||||||
PROP_PROBATION,
|
PROP_PROBATION,
|
||||||
PROP_STATS
|
PROP_STATS,
|
||||||
|
PROP_RTP_PROFILE
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GST_RTP_SESSION_GET_PRIVATE(obj) \
|
#define GST_RTP_SESSION_GET_PRIVATE(obj) \
|
||||||
|
@ -645,6 +647,11 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass)
|
||||||
"Various statistics", GST_TYPE_STRUCTURE,
|
"Various statistics", GST_TYPE_STRUCTURE,
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
|
||||||
|
g_param_spec_enum ("rtp-profile", "RTP Profile",
|
||||||
|
"RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
|
GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
|
@ -776,6 +783,9 @@ gst_rtp_session_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_PROBATION:
|
case PROP_PROBATION:
|
||||||
g_object_set_property (G_OBJECT (priv->session), "probation", value);
|
g_object_set_property (G_OBJECT (priv->session), "probation", value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTP_PROFILE:
|
||||||
|
g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -833,6 +843,9 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_STATS:
|
case PROP_STATS:
|
||||||
g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
|
g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTP_PROFILE:
|
||||||
|
g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -68,6 +68,7 @@ enum
|
||||||
#define DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW (2 * GST_SECOND)
|
#define DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW (2 * GST_SECOND)
|
||||||
#define DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD (3)
|
#define DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD (3)
|
||||||
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
|
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
|
||||||
|
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -88,7 +89,8 @@ enum
|
||||||
PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
|
PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
|
||||||
PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
|
PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
|
||||||
PROP_PROBATION,
|
PROP_PROBATION,
|
||||||
PROP_STATS
|
PROP_STATS,
|
||||||
|
PROP_RTP_PROFILE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* update average packet size */
|
/* update average packet size */
|
||||||
|
@ -313,6 +315,8 @@ rtp_session_class_init (RTPSessionClass * klass)
|
||||||
*
|
*
|
||||||
* Requests that the #RTPSession initiate a new RTCP packet as soon as
|
* Requests that the #RTPSession initiate a new RTCP packet as soon as
|
||||||
* possible within the requested delay.
|
* possible within the requested delay.
|
||||||
|
*
|
||||||
|
* This sets feedback to %TRUE if not already done before.
|
||||||
*/
|
*/
|
||||||
rtp_session_signals[SIGNAL_SEND_RTCP] =
|
rtp_session_signals[SIGNAL_SEND_RTCP] =
|
||||||
g_signal_new ("send-rtcp", G_TYPE_FROM_CLASS (klass),
|
g_signal_new ("send-rtcp", G_TYPE_FROM_CLASS (klass),
|
||||||
|
@ -329,6 +333,8 @@ rtp_session_class_init (RTPSessionClass * klass)
|
||||||
* Requests that the #RTPSession initiate a new RTCP packet as soon as
|
* Requests that the #RTPSession initiate a new RTCP packet as soon as
|
||||||
* possible within the requested delay.
|
* possible within the requested delay.
|
||||||
*
|
*
|
||||||
|
* This sets feedback to %TRUE if not already done before.
|
||||||
|
*
|
||||||
* Returns: TRUE if the new RTCP packet could be scheduled within the
|
* Returns: TRUE if the new RTCP packet could be scheduled within the
|
||||||
* requested delay, FALSE otherwise.
|
* requested delay, FALSE otherwise.
|
||||||
*
|
*
|
||||||
|
@ -494,6 +500,11 @@ rtp_session_class_init (RTPSessionClass * klass)
|
||||||
"Various statistics", GST_TYPE_STRUCTURE,
|
"Various statistics", GST_TYPE_STRUCTURE,
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
|
||||||
|
g_param_spec_enum ("rtp-profile", "RTP Profile",
|
||||||
|
"RTP profile to use for this session", GST_TYPE_RTP_PROFILE,
|
||||||
|
DEFAULT_RTP_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
klass->get_source_by_ssrc =
|
klass->get_source_by_ssrc =
|
||||||
GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
|
GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
|
||||||
klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp);
|
klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp);
|
||||||
|
@ -568,6 +579,7 @@ rtp_session_init (RTPSession * sess)
|
||||||
sess->rtcp_feedback_retention_window = DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW;
|
sess->rtcp_feedback_retention_window = DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW;
|
||||||
sess->rtcp_immediate_feedback_threshold =
|
sess->rtcp_immediate_feedback_threshold =
|
||||||
DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
|
DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
|
||||||
|
sess->rtp_profile = DEFAULT_RTP_PROFILE;
|
||||||
|
|
||||||
sess->last_keyframe_request = GST_CLOCK_TIME_NONE;
|
sess->last_keyframe_request = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
@ -706,6 +718,15 @@ rtp_session_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_PROBATION:
|
case PROP_PROBATION:
|
||||||
sess->probation = g_value_get_uint (value);
|
sess->probation = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTP_PROFILE:
|
||||||
|
sess->rtp_profile = g_value_get_enum (value);
|
||||||
|
/* trigger reconsideration */
|
||||||
|
RTP_SESSION_LOCK (sess);
|
||||||
|
sess->next_rtcp_check_time = 0;
|
||||||
|
RTP_SESSION_UNLOCK (sess);
|
||||||
|
if (sess->callbacks.reconsider)
|
||||||
|
sess->callbacks.reconsider (sess, sess->reconsider_user_data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -770,6 +791,9 @@ rtp_session_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_STATS:
|
case PROP_STATS:
|
||||||
g_value_take_boxed (value, rtp_session_create_stats (sess));
|
g_value_take_boxed (value, rtp_session_create_stats (sess));
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTP_PROFILE:
|
||||||
|
g_value_set_enum (value, sess->rtp_profile);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -2816,9 +2840,12 @@ calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
|
||||||
stats = &sess->bye_stats;
|
stats = &sess->bye_stats;
|
||||||
result = rtp_stats_calculate_bye_interval (stats);
|
result = rtp_stats_calculate_bye_interval (stats);
|
||||||
} else {
|
} else {
|
||||||
|
session_update_ptp (sess);
|
||||||
|
|
||||||
stats = &sess->stats;
|
stats = &sess->stats;
|
||||||
result = rtp_stats_calculate_rtcp_interval (stats,
|
result = rtp_stats_calculate_rtcp_interval (stats,
|
||||||
stats->internal_sender_sources > 0, first);
|
stats->internal_sender_sources > 0, sess->rtp_profile,
|
||||||
|
sess->is_doing_ptp, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG ("next deterministic interval: %" GST_TIME_FORMAT ", first %d",
|
GST_DEBUG ("next deterministic interval: %" GST_TIME_FORMAT ", first %d",
|
||||||
|
@ -3561,7 +3588,9 @@ early:
|
||||||
sess->next_rtcp_check_time = current_time + interval;
|
sess->next_rtcp_check_time = current_time + interval;
|
||||||
} else if (interval != GST_CLOCK_TIME_NONE) {
|
} else if (interval != GST_CLOCK_TIME_NONE) {
|
||||||
/* Apply the rules from RFC 4585 section 3.5.3 */
|
/* Apply the rules from RFC 4585 section 3.5.3 */
|
||||||
if (stats->min_interval != 0 && !sess->first_rtcp) {
|
if ((sess->rtp_profile == GST_RTP_PROFILE_AVPF
|
||||||
|
|| sess->rtp_profile == GST_RTP_PROFILE_SAVPF)
|
||||||
|
&& stats->min_interval != 0 && !sess->first_rtcp) {
|
||||||
GstClockTime T_rr_current_interval =
|
GstClockTime T_rr_current_interval =
|
||||||
g_random_double_range (0.5, 1.5) * stats->min_interval * GST_SECOND;
|
g_random_double_range (0.5, 1.5) * stats->min_interval * GST_SECOND;
|
||||||
|
|
||||||
|
@ -3852,6 +3881,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
|
||||||
|
|
||||||
RTP_SESSION_LOCK (sess);
|
RTP_SESSION_LOCK (sess);
|
||||||
|
|
||||||
|
/* We assume a feedback profile if something is requesting RTCP
|
||||||
|
* to be sent */
|
||||||
|
sess->rtp_profile = GST_RTP_PROFILE_AVPF;
|
||||||
|
|
||||||
/* Check if already requested */
|
/* Check if already requested */
|
||||||
/* RFC 4585 section 3.5.2 step 2 */
|
/* RFC 4585 section 3.5.2 step 2 */
|
||||||
if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
|
if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
|
||||||
|
@ -3919,7 +3952,7 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC 4585 section 3.5.2 step 4a */
|
/* RFC 4585 section 3.5.2 step 4a */
|
||||||
if (sess->allow_early == FALSE) {
|
if (!sess->allow_early) {
|
||||||
/* Ignore the request a scheduled packet will be in time anyway */
|
/* Ignore the request a scheduled packet will be in time anyway */
|
||||||
if (current_time + max_delay > sess->next_rtcp_check_time) {
|
if (current_time + max_delay > sess->next_rtcp_check_time) {
|
||||||
GST_LOG_OBJECT (sess,
|
GST_LOG_OBJECT (sess,
|
||||||
|
@ -3930,7 +3963,7 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
} else {
|
} else {
|
||||||
GST_LOG_OBJECT (sess,
|
GST_LOG_OBJECT (sess,
|
||||||
"can't allow early feedback, next scheduled time is too late %"
|
"can't allow early feedback and next scheduled time is too late %"
|
||||||
GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
|
GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
|
GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
|
||||||
GST_TIME_ARGS (sess->next_rtcp_check_time));
|
GST_TIME_ARGS (sess->next_rtcp_check_time));
|
||||||
|
|
|
@ -220,6 +220,8 @@ struct _RTPSession {
|
||||||
|
|
||||||
guint probation;
|
guint probation;
|
||||||
|
|
||||||
|
GstRTPProfile rtp_profile;
|
||||||
|
|
||||||
/* bandwidths */
|
/* bandwidths */
|
||||||
gboolean recalc_bandwidth;
|
gboolean recalc_bandwidth;
|
||||||
guint bandwidth;
|
guint bandwidth;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define __RTP_SOURCE_H__
|
#define __RTP_SOURCE_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/rtp/gstrtcpbuffer.h>
|
#include <gst/rtp/rtp.h>
|
||||||
#include <gst/net/gstnetaddressmeta.h>
|
#include <gst/net/gstnetaddressmeta.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,8 @@ rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw,
|
||||||
* rtp_stats_calculate_rtcp_interval:
|
* rtp_stats_calculate_rtcp_interval:
|
||||||
* @stats: an #RTPSessionStats struct
|
* @stats: an #RTPSessionStats struct
|
||||||
* @sender: if we are a sender
|
* @sender: if we are a sender
|
||||||
|
* @profile: RTP profile of this session
|
||||||
|
* @ptp: if this session is a point-to-point session
|
||||||
* @first: if this is the first time
|
* @first: if this is the first time
|
||||||
*
|
*
|
||||||
* Calculate the RTCP interval. The result of this function is the amount of
|
* Calculate the RTCP interval. The result of this function is the amount of
|
||||||
|
@ -129,22 +131,31 @@ rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw,
|
||||||
*/
|
*/
|
||||||
GstClockTime
|
GstClockTime
|
||||||
rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
|
rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
|
||||||
gboolean first)
|
GstRTPProfile profile, gboolean ptp, gboolean first)
|
||||||
{
|
{
|
||||||
gdouble members, senders, n;
|
gdouble members, senders, n;
|
||||||
gdouble avg_rtcp_size, rtcp_bw;
|
gdouble avg_rtcp_size, rtcp_bw;
|
||||||
gdouble interval;
|
gdouble interval;
|
||||||
gdouble rtcp_min_time;
|
gdouble rtcp_min_time;
|
||||||
|
|
||||||
/* Very first call at application start-up uses half the min
|
if (profile == GST_RTP_PROFILE_AVPF || profile == GST_RTP_PROFILE_SAVPF) {
|
||||||
* delay for quicker notification while still allowing some time
|
/* RFC 4585 3.4d), 3.5.1 */
|
||||||
* before reporting for randomization and to learn about other
|
|
||||||
* sources so the report interval will converge to the correct
|
if (first && !ptp)
|
||||||
* interval more quickly.
|
rtcp_min_time = 1.0;
|
||||||
*/
|
else
|
||||||
rtcp_min_time = stats->min_interval;
|
rtcp_min_time = 0.0;
|
||||||
if (first)
|
} else {
|
||||||
rtcp_min_time /= 2.0;
|
/* Very first call at application start-up uses half the min
|
||||||
|
* delay for quicker notification while still allowing some time
|
||||||
|
* before reporting for randomization and to learn about other
|
||||||
|
* sources so the report interval will converge to the correct
|
||||||
|
* interval more quickly.
|
||||||
|
*/
|
||||||
|
rtcp_min_time = stats->min_interval;
|
||||||
|
if (first)
|
||||||
|
rtcp_min_time /= 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dedicate a fraction of the RTCP bandwidth to senders unless
|
/* Dedicate a fraction of the RTCP bandwidth to senders unless
|
||||||
* the number of senders is large enough that their share is
|
* the number of senders is large enough that their share is
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/net/gstnetaddressmeta.h>
|
#include <gst/net/gstnetaddressmeta.h>
|
||||||
|
#include <gst/rtp/rtp.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,7 +223,7 @@ void rtp_stats_set_bandwidths (RTPSessionStats *stats,
|
||||||
gdouble rtcp_bw,
|
gdouble rtcp_bw,
|
||||||
guint rs, guint rr);
|
guint rs, guint rr);
|
||||||
|
|
||||||
GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats *stats, gboolean sender, gboolean first);
|
GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats *stats, gboolean sender, GstRTPProfile profile, gboolean ptp, gboolean first);
|
||||||
GstClockTime rtp_stats_add_rtcp_jitter (RTPSessionStats *stats, GstClockTime interval);
|
GstClockTime rtp_stats_add_rtcp_jitter (RTPSessionStats *stats, GstClockTime interval);
|
||||||
GstClockTime rtp_stats_calculate_bye_interval (RTPSessionStats *stats);
|
GstClockTime rtp_stats_calculate_bye_interval (RTPSessionStats *stats);
|
||||||
gint64 rtp_stats_get_packets_lost (const RTPSourceStats *stats);
|
gint64 rtp_stats_get_packets_lost (const RTPSourceStats *stats);
|
||||||
|
|
Loading…
Reference in a new issue