#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
{
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 */
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);
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;
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;
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);
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
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)
{
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;
}
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);
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)
{
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;
}