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:
Sebastian Dröge 2015-05-04 11:42:08 +02:00
parent 8fd3e0e125
commit 3122ef4ae3
6 changed files with 78 additions and 18 deletions

View file

@ -201,6 +201,7 @@ enum
#define DEFAULT_USE_PIPELINE_CLOCK FALSE
#define DEFAULT_RTCP_MIN_INTERVAL (RTP_STATS_MIN_INTERVAL * GST_SECOND)
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
enum
{
@ -216,7 +217,8 @@ enum
PROP_USE_PIPELINE_CLOCK,
PROP_RTCP_MIN_INTERVAL,
PROP_PROBATION,
PROP_STATS
PROP_STATS,
PROP_RTP_PROFILE
};
#define GST_RTP_SESSION_GET_PRIVATE(obj) \
@ -645,6 +647,11 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass)
"Various statistics", GST_TYPE_STRUCTURE,
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 =
GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
gstelement_class->request_new_pad =
@ -776,6 +783,9 @@ gst_rtp_session_set_property (GObject * object, guint prop_id,
case PROP_PROBATION:
g_object_set_property (G_OBJECT (priv->session), "probation", value);
break;
case PROP_RTP_PROFILE:
g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -833,6 +843,9 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
case PROP_STATS:
g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
break;
case PROP_RTP_PROFILE:
g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -68,6 +68,7 @@ enum
#define DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW (2 * GST_SECOND)
#define DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD (3)
#define DEFAULT_PROBATION RTP_DEFAULT_PROBATION
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
enum
{
@ -88,7 +89,8 @@ enum
PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
PROP_PROBATION,
PROP_STATS
PROP_STATS,
PROP_RTP_PROFILE
};
/* 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
* possible within the requested delay.
*
* This sets feedback to %TRUE if not already done before.
*/
rtp_session_signals[SIGNAL_SEND_RTCP] =
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
* 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
* requested delay, FALSE otherwise.
*
@ -494,6 +500,11 @@ rtp_session_class_init (RTPSessionClass * klass)
"Various statistics", GST_TYPE_STRUCTURE,
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 =
GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
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_immediate_feedback_threshold =
DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
sess->rtp_profile = DEFAULT_RTP_PROFILE;
sess->last_keyframe_request = GST_CLOCK_TIME_NONE;
@ -706,6 +718,15 @@ rtp_session_set_property (GObject * object, guint prop_id,
case PROP_PROBATION:
sess->probation = g_value_get_uint (value);
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:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -770,6 +791,9 @@ rtp_session_get_property (GObject * object, guint prop_id,
case PROP_STATS:
g_value_take_boxed (value, rtp_session_create_stats (sess));
break;
case PROP_RTP_PROFILE:
g_value_set_enum (value, sess->rtp_profile);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -2816,9 +2840,12 @@ calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
stats = &sess->bye_stats;
result = rtp_stats_calculate_bye_interval (stats);
} else {
session_update_ptp (sess);
stats = &sess->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",
@ -3561,7 +3588,9 @@ early:
sess->next_rtcp_check_time = current_time + interval;
} else if (interval != GST_CLOCK_TIME_NONE) {
/* 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 =
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);
/* We assume a feedback profile if something is requesting RTCP
* to be sent */
sess->rtp_profile = GST_RTP_PROFILE_AVPF;
/* Check if already requested */
/* RFC 4585 section 3.5.2 step 2 */
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 */
if (sess->allow_early == FALSE) {
if (!sess->allow_early) {
/* Ignore the request a scheduled packet will be in time anyway */
if (current_time + max_delay > sess->next_rtcp_check_time) {
GST_LOG_OBJECT (sess,
@ -3930,7 +3963,7 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
ret = TRUE;
} else {
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_ARGS (current_time), GST_TIME_ARGS (max_delay),
GST_TIME_ARGS (sess->next_rtcp_check_time));

View file

@ -220,6 +220,8 @@ struct _RTPSession {
guint probation;
GstRTPProfile rtp_profile;
/* bandwidths */
gboolean recalc_bandwidth;
guint bandwidth;

View file

@ -21,7 +21,7 @@
#define __RTP_SOURCE_H__
#include <gst/gst.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include <gst/rtp/rtp.h>
#include <gst/net/gstnetaddressmeta.h>
#include <gio/gio.h>

View file

@ -120,6 +120,8 @@ rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw,
* rtp_stats_calculate_rtcp_interval:
* @stats: an #RTPSessionStats struct
* @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
*
* 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
rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send,
gboolean first)
GstRTPProfile profile, gboolean ptp, gboolean first)
{
gdouble members, senders, n;
gdouble avg_rtcp_size, rtcp_bw;
gdouble interval;
gdouble rtcp_min_time;
/* 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;
if (profile == GST_RTP_PROFILE_AVPF || profile == GST_RTP_PROFILE_SAVPF) {
/* RFC 4585 3.4d), 3.5.1 */
if (first && !ptp)
rtcp_min_time = 1.0;
else
rtcp_min_time = 0.0;
} else {
/* 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
* the number of senders is large enough that their share is

View file

@ -22,6 +22,7 @@
#include <gst/gst.h>
#include <gst/net/gstnetaddressmeta.h>
#include <gst/rtp/rtp.h>
#include <gio/gio.h>
/**
@ -222,7 +223,7 @@ void rtp_stats_set_bandwidths (RTPSessionStats *stats,
gdouble rtcp_bw,
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_calculate_bye_interval (RTPSessionStats *stats);
gint64 rtp_stats_get_packets_lost (const RTPSourceStats *stats);