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:
parent
ddcde96efe
commit
be5fab15e0
@ -78,6 +78,7 @@ enum
|
|||||||
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
|
#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP
|
||||||
#define DEFAULT_RTCP_REDUCED_SIZE FALSE
|
#define DEFAULT_RTCP_REDUCED_SIZE FALSE
|
||||||
#define DEFAULT_RTCP_DISABLE_SR_TIMESTAMP FALSE
|
#define DEFAULT_RTCP_DISABLE_SR_TIMESTAMP FALSE
|
||||||
|
#define DEFAULT_TWCC_FEEDBACK_INTERVAL GST_CLOCK_TIME_NONE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -103,7 +104,8 @@ enum
|
|||||||
PROP_STATS,
|
PROP_STATS,
|
||||||
PROP_RTP_PROFILE,
|
PROP_RTP_PROFILE,
|
||||||
PROP_RTCP_REDUCED_SIZE,
|
PROP_RTCP_REDUCED_SIZE,
|
||||||
PROP_RTCP_DISABLE_SR_TIMESTAMP
|
PROP_RTCP_DISABLE_SR_TIMESTAMP,
|
||||||
|
PROP_TWCC_FEEDBACK_INTERVAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* update average packet size */
|
/* update average packet size */
|
||||||
@ -629,6 +631,23 @@ rtp_session_class_init (RTPSessionClass * klass)
|
|||||||
DEFAULT_RTCP_DISABLE_SR_TIMESTAMP,
|
DEFAULT_RTCP_DISABLE_SR_TIMESTAMP,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
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 =
|
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);
|
||||||
@ -907,6 +926,10 @@ rtp_session_set_property (GObject * object, guint prop_id,
|
|||||||
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
|
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
|
||||||
sess->timestamp_sender_reports = !g_value_get_boolean (value);
|
sess->timestamp_sender_reports = !g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TWCC_FEEDBACK_INTERVAL:
|
||||||
|
rtp_twcc_manager_set_feedback_interval (sess->twcc,
|
||||||
|
g_value_get_uint64 (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;
|
||||||
@ -989,6 +1012,10 @@ rtp_session_get_property (GObject * object, guint prop_id,
|
|||||||
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
|
case PROP_RTCP_DISABLE_SR_TIMESTAMP:
|
||||||
g_value_set_boolean (value, !sess->timestamp_sender_reports);
|
g_value_set_boolean (value, !sess->timestamp_sender_reports);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TWCC_FEEDBACK_INTERVAL:
|
||||||
|
g_value_set_uint64 (value,
|
||||||
|
rtp_twcc_manager_get_feedback_interval (sess->twcc));
|
||||||
|
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;
|
||||||
|
@ -87,6 +87,9 @@ struct _RTPTWCCManager
|
|||||||
gboolean first_fci_parse;
|
gboolean first_fci_parse;
|
||||||
guint16 expected_parsed_seqnum;
|
guint16 expected_parsed_seqnum;
|
||||||
guint8 expected_parsed_fb_pkt_count;
|
guint8 expected_parsed_fb_pkt_count;
|
||||||
|
|
||||||
|
GstClockTime next_feedback_send_time;
|
||||||
|
GstClockTime feedback_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (RTPTWCCManager, rtp_twcc_manager, G_TYPE_OBJECT);
|
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->recv_sender_ssrc = -1;
|
||||||
|
|
||||||
twcc->first_fci_parse = TRUE;
|
twcc->first_fci_parse = TRUE;
|
||||||
|
|
||||||
|
twcc->feedback_interval = GST_CLOCK_TIME_NONE;
|
||||||
|
twcc->next_feedback_send_time = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
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
|
static gint
|
||||||
_twcc_seqnum_sort (gconstpointer a, gconstpointer b)
|
_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,
|
GST_LOG ("Receive: twcc-seqnum: %u, marker: %d, ts: %" GST_TIME_FORMAT,
|
||||||
seqnum, pinfo->marker, GST_TIME_ARGS (pinfo->running_time));
|
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);
|
rtp_twcc_manager_create_feedback (twcc);
|
||||||
send_feedback = TRUE;
|
send_feedback = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,9 @@ struct _RTPTWCCPacket
|
|||||||
RTPTWCCManager * rtp_twcc_manager_new (guint mtu);
|
RTPTWCCManager * rtp_twcc_manager_new (guint mtu);
|
||||||
|
|
||||||
void rtp_twcc_manager_set_mtu (RTPTWCCManager * twcc, 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,
|
gboolean rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc,
|
||||||
guint16 seqnum, RTPPacketInfo * pinfo);
|
guint16 seqnum, RTPPacketInfo * pinfo);
|
||||||
|
@ -3685,6 +3685,48 @@ GST_START_TEST (test_twcc_send_and_recv)
|
|||||||
|
|
||||||
GST_END_TEST;
|
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 *
|
static Suite *
|
||||||
rtpsession_suite (void)
|
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_recv_rtcp_reordered);
|
||||||
tcase_add_test (tc_chain, test_twcc_no_exthdr_in_buffer);
|
tcase_add_test (tc_chain, test_twcc_no_exthdr_in_buffer);
|
||||||
tcase_add_test (tc_chain, test_twcc_send_and_recv);
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user