mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +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_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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -220,6 +220,8 @@ struct _RTPSession {
|
|||
|
||||
guint probation;
|
||||
|
||||
GstRTPProfile rtp_profile;
|
||||
|
||||
/* bandwidths */
|
||||
gboolean recalc_bandwidth;
|
||||
guint bandwidth;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue