rtptwcc: add feedback-interval

To allow RTCP TWCC reports to be scheduled on a timer instead of per
marker-bit.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/927>
This commit is contained in:
Havard Graff 2020-11-19 23:50:23 +01:00 committed by GStreamer Marge Bot
parent ddcde96efe
commit be5fab15e0
4 changed files with 109 additions and 2 deletions

View file

@ -78,6 +78,7 @@ enum
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
#define DEFAULT_RTCP_REDUCED_SIZE FALSE
#define DEFAULT_RTCP_DISABLE_SR_TIMESTAMP FALSE
#define DEFAULT_TWCC_FEEDBACK_INTERVAL GST_CLOCK_TIME_NONE
enum
{
@ -103,7 +104,8 @@ enum
PROP_STATS,
PROP_RTP_PROFILE,
PROP_RTCP_REDUCED_SIZE,
PROP_RTCP_DISABLE_SR_TIMESTAMP
PROP_RTCP_DISABLE_SR_TIMESTAMP,
PROP_TWCC_FEEDBACK_INTERVAL,
};
/* update average packet size */
@ -629,6 +631,23 @@ rtp_session_class_init (RTPSessionClass * klass)
DEFAULT_RTCP_DISABLE_SR_TIMESTAMP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* RTPSession::twcc-feedback-interval:
*
* The interval to send TWCC reports on.
* This overrides the default behavior of sending reports
* based on marker-bits.
*
* Since: 1.20
*/
g_object_class_install_property (gobject_class,
PROP_TWCC_FEEDBACK_INTERVAL,
g_param_spec_uint64 ("twcc-feedback-interval",
"TWCC Feedback Interval",
"The interval to send TWCC reports on",
0, G_MAXUINT64, DEFAULT_TWCC_FEEDBACK_INTERVAL,
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);
@ -907,6 +926,10 @@ rtp_session_set_property (GObject * object, guint prop_id,
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
sess->timestamp_sender_reports = !g_value_get_boolean (value);
break;
case PROP_TWCC_FEEDBACK_INTERVAL:
rtp_twcc_manager_set_feedback_interval (sess->twcc,
g_value_get_uint64 (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -989,6 +1012,10 @@ rtp_session_get_property (GObject * object, guint prop_id,
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
g_value_set_boolean (value, !sess->timestamp_sender_reports);
break;
case PROP_TWCC_FEEDBACK_INTERVAL:
g_value_set_uint64 (value,
rtp_twcc_manager_get_feedback_interval (sess->twcc));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -87,6 +87,9 @@ struct _RTPTWCCManager
gboolean first_fci_parse;
guint16 expected_parsed_seqnum;
guint8 expected_parsed_fb_pkt_count;
GstClockTime next_feedback_send_time;
GstClockTime feedback_interval;
};
G_DEFINE_TYPE (RTPTWCCManager, rtp_twcc_manager, G_TYPE_OBJECT);
@ -105,6 +108,9 @@ rtp_twcc_manager_init (RTPTWCCManager * twcc)
twcc->recv_sender_ssrc = -1;
twcc->first_fci_parse = TRUE;
twcc->feedback_interval = GST_CLOCK_TIME_NONE;
twcc->next_feedback_send_time = GST_CLOCK_TIME_NONE;
}
static void
@ -157,6 +163,19 @@ rtp_twcc_manager_set_mtu (RTPTWCCManager * twcc, guint mtu)
twcc->max_packets_per_rtcp = ((twcc->mtu - 32) * 7) / (2 + 14);
}
void
rtp_twcc_manager_set_feedback_interval (RTPTWCCManager * twcc,
GstClockTime feedback_interval)
{
twcc->feedback_interval = feedback_interval;
}
GstClockTime
rtp_twcc_manager_get_feedback_interval (RTPTWCCManager * twcc)
{
return twcc->feedback_interval;
}
static gint
_twcc_seqnum_sort (gconstpointer a, gconstpointer b)
{
@ -609,7 +628,20 @@ rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc,
GST_LOG ("Receive: twcc-seqnum: %u, marker: %d, ts: %" GST_TIME_FORMAT,
seqnum, pinfo->marker, GST_TIME_ARGS (pinfo->running_time));
if (pinfo->marker || _many_packets_some_lost (twcc, seqnum)) {
/* are we sending on an interval, or based on marker bit */
if (GST_CLOCK_TIME_IS_VALID (twcc->feedback_interval)) {
if (!GST_CLOCK_TIME_IS_VALID (twcc->next_feedback_send_time))
twcc->next_feedback_send_time =
pinfo->running_time + twcc->feedback_interval;
if (pinfo->running_time >= twcc->next_feedback_send_time) {
rtp_twcc_manager_create_feedback (twcc);
send_feedback = TRUE;
while (pinfo->running_time >= twcc->next_feedback_send_time)
twcc->next_feedback_send_time += twcc->feedback_interval;
}
} else if (pinfo->marker || _many_packets_some_lost (twcc, seqnum)) {
rtp_twcc_manager_create_feedback (twcc);
send_feedback = TRUE;
}

View file

@ -54,6 +54,9 @@ struct _RTPTWCCPacket
RTPTWCCManager * rtp_twcc_manager_new (guint mtu);
void rtp_twcc_manager_set_mtu (RTPTWCCManager * twcc, guint mtu);
void rtp_twcc_manager_set_feedback_interval (RTPTWCCManager * twcc,
GstClockTime feedback_interval);
GstClockTime rtp_twcc_manager_get_feedback_interval (RTPTWCCManager * twcc);
gboolean rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc,
guint16 seqnum, RTPPacketInfo * pinfo);

View file

@ -3685,6 +3685,48 @@ GST_START_TEST (test_twcc_send_and_recv)
GST_END_TEST;
typedef struct
{
GstClockTime interval;
guint num_packets;
GstClockTime ts_delta;
guint num_feedback;
} TWCCFeedbackIntervalCtx;
static TWCCFeedbackIntervalCtx test_twcc_feedback_interval_ctx[] = {
{50 * GST_MSECOND, 21, 10 * GST_MSECOND, 4},
{50 * GST_MSECOND, 16, 7 * GST_MSECOND, 2},
{50 * GST_MSECOND, 16, 66 * GST_MSECOND, 15},
{50 * GST_MSECOND, 15, 33 * GST_MSECOND, 9},
};
GST_START_TEST (test_twcc_feedback_interval)
{
SessionHarness *h = session_harness_new ();
GstBuffer *buf;
TWCCFeedbackIntervalCtx *ctx = &test_twcc_feedback_interval_ctx[__i__];
session_harness_set_twcc_recv_ext_id (h, TEST_TWCC_EXT_ID);
g_object_set (h->internal_session, "twcc-feedback-interval", ctx->interval,
NULL);
for (guint i = 0; i < ctx->num_packets; i++) {
GstClockTime ts = i * ctx->ts_delta;
gst_test_clock_set_time ((h->testclock), ts);
fail_unless_equals_int (GST_FLOW_OK,
session_harness_recv_rtp (h, generate_twcc_recv_buffer (i, ts, FALSE)));
}
for (guint i = 0; i < ctx->num_feedback; i++) {
buf = session_harness_produce_twcc (h);
gst_buffer_unref (buf);
}
session_harness_free (h);
}
GST_END_TEST;
static Suite *
rtpsession_suite (void)
{
@ -3749,6 +3791,9 @@ rtpsession_suite (void)
tcase_add_test (tc_chain, test_twcc_recv_rtcp_reordered);
tcase_add_test (tc_chain, test_twcc_no_exthdr_in_buffer);
tcase_add_test (tc_chain, test_twcc_send_and_recv);
tcase_add_loop_test (tc_chain, test_twcc_feedback_interval, 0,
G_N_ELEMENTS (test_twcc_feedback_interval_ctx));
return s;
}