diff --git a/gst/rtpmanager/rtptwcc.c b/gst/rtpmanager/rtptwcc.c index ad0628abc1..b6ba77c06f 100644 --- a/gst/rtpmanager/rtptwcc.c +++ b/gst/rtpmanager/rtptwcc.c @@ -29,6 +29,9 @@ GST_DEBUG_CATEGORY_EXTERN (rtp_session_debug); #define DELTA_UNIT (250 * GST_USECOND) #define MAX_TS_DELTA (0xff * DELTA_UNIT) +#define STATUS_VECTOR_MAX_CAPACITY 14 +#define STATUS_VECTOR_TWO_BIT_MAX_CAPACITY 7 + typedef enum { RTP_TWCC_CHUNK_TYPE_RUN_LENGTH = 0, @@ -83,6 +86,7 @@ struct _RTPTWCCManager guint64 recv_media_ssrc; guint16 expected_recv_seqnum; + guint16 packet_count_no_marker; gboolean first_fci_parse; guint16 expected_parsed_seqnum; @@ -216,7 +220,7 @@ rtp_twcc_write_run_length_chunk (GArray * packet_chunks, guint16 data = 0; guint len = MIN (run_length - written, 8191); - GST_LOG ("Writing a run-lenght of %u with status %u", len, status); + GST_LOG ("Writing a run-length of %u with status %u", len, status); gst_bit_writer_init_with_data (&writer, (guint8 *) & data, 2, FALSE); gst_bit_writer_put_bits_uint8 (&writer, RTP_TWCC_CHUNK_TYPE_RUN_LENGTH, 1); @@ -276,7 +280,7 @@ chunk_bit_writer_get_available_slots (ChunkBitWriter * writer) static guint chunk_bit_writer_get_total_slots (ChunkBitWriter * writer) { - return 14 / writer->symbol_size; + return STATUS_VECTOR_MAX_CAPACITY / writer->symbol_size; } static void @@ -359,13 +363,43 @@ run_lenght_helper_update (RunLengthHelper * rlh, RecvPacket * pkt) } } +static guint +_get_max_packets_capacity (guint symbol_size) +{ + if (symbol_size == 2) + return STATUS_VECTOR_TWO_BIT_MAX_CAPACITY; + + return STATUS_VECTOR_MAX_CAPACITY; +} + +static gboolean +_pkt_fits_run_length_chunk (RecvPacket * pkt, guint packets_per_chunks, + guint remaining_packets) +{ + if (pkt->missing_run == 0) { + /* we have more or the same equal packets than the ones we can write in to a status chunk */ + if (pkt->equal_run >= packets_per_chunks) + return TRUE; + + /* we have more than one equal and not enough space for the remainings */ + if (pkt->equal_run > 1 && remaining_packets > STATUS_VECTOR_MAX_CAPACITY) + return TRUE; + + /* we have all equal packets for the remaining to write */ + if (pkt->equal_run == remaining_packets) + return TRUE; + } + + return FALSE; +} + static void rtp_twcc_write_chunks (GArray * packet_chunks, GArray * twcc_packets, guint symbol_size) { ChunkBitWriter writer; guint i; - guint bits_per_chunks = 7 * symbol_size; + guint packets_per_chunks = _get_max_packets_capacity (symbol_size); chunk_bit_writer_init (&writer, packet_chunks, symbol_size); @@ -373,21 +407,26 @@ rtp_twcc_write_chunks (GArray * packet_chunks, RecvPacket *pkt = &g_array_index (twcc_packets, RecvPacket, i); guint remaining_packets = twcc_packets->len - i; + GST_LOG + ("About to write pkt: #%u missing_run: %u equal_run: %u status: %u, remaining_packets: %u", + pkt->seqnum, pkt->missing_run, pkt->equal_run, pkt->status, + remaining_packets); + /* we can only start a run-length chunk if the status-chunk is completed */ if (chunk_bit_writer_is_empty (&writer)) { /* first write in any preceeding gaps, we use run-length if it would take up more than one chunk (14/7) */ - if (pkt->missing_run > bits_per_chunks) { + if (pkt->missing_run > packets_per_chunks) { rtp_twcc_write_run_length_chunk (packet_chunks, RTP_TWCC_PACKET_STATUS_NOT_RECV, pkt->missing_run); } /* we have a run of the same status, write a run-length chunk and skip to the next point */ - if (pkt->missing_run == 0 && - (pkt->equal_run > bits_per_chunks || - pkt->equal_run == remaining_packets)) { + if (_pkt_fits_run_length_chunk (pkt, packets_per_chunks, + remaining_packets)) { + rtp_twcc_write_run_length_chunk (packet_chunks, pkt->status, pkt->equal_run); i += pkt->equal_run - 1; @@ -546,24 +585,7 @@ rtp_twcc_manager_create_feedback (RTPTWCCManager * twcc) static gboolean _exceeds_max_packets (RTPTWCCManager * twcc, guint16 seqnum) { - RecvPacket *first, *last; - guint16 packet_count; - - if (twcc->recv_packets->len == 0) - return FALSE; - - /* find the delta betwen first stored packet and this seqnum */ - first = &g_array_index (twcc->recv_packets, RecvPacket, 0); - packet_count = seqnum - first->seqnum + 1; - if (packet_count > twcc->max_packets_per_rtcp) - return TRUE; - - /* then find the delta between last stored packet and this seqnum */ - last = - &g_array_index (twcc->recv_packets, RecvPacket, - twcc->recv_packets->len - 1); - packet_count = seqnum - (last->seqnum + 1); - if (packet_count > twcc->max_packets_per_rtcp) + if (twcc->recv_packets->len + 1 > twcc->max_packets_per_rtcp) return TRUE; return FALSE; @@ -578,13 +600,20 @@ _many_packets_some_lost (RTPTWCCManager * twcc, guint16 seqnum) RecvPacket *first; guint16 packet_count; guint received_packets = twcc->recv_packets->len; + guint lost_packets; if (received_packets == 0) return FALSE; first = &g_array_index (twcc->recv_packets, RecvPacket, 0); packet_count = seqnum - first->seqnum + 1; - /* packet-count larger than recevied-packets means we have lost packets */ - if (packet_count >= 30 && packet_count > received_packets) + + /* check if we lost half of the threshold */ + lost_packets = packet_count - received_packets; + if (received_packets >= 30 && lost_packets >= 60) + return TRUE; + + /* we have lost the marker bit for some and lost some */ + if (twcc->packet_count_no_marker >= 10 && lost_packets >= 60) return TRUE; return FALSE; @@ -621,6 +650,17 @@ rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc, return FALSE; } + if (twcc->recv_packets->len > 0) { + RecvPacket *last = &g_array_index (twcc->recv_packets, RecvPacket, + twcc->recv_packets->len - 1); + + diff = gst_rtp_buffer_compare_seqnum (last->seqnum, seqnum); + if (diff == 0) { + GST_INFO ("Received duplicate packet (%u), dropping", seqnum); + return FALSE; + } + } + /* store the packet for Transport-wide RTCP feedback message */ recv_packet_init (&packet, seqnum, pinfo); g_array_append_val (twcc->recv_packets, packet); @@ -628,6 +668,9 @@ 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) + twcc->packet_count_no_marker++; + /* 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)) @@ -644,6 +687,8 @@ rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc, } else if (pinfo->marker || _many_packets_some_lost (twcc, seqnum)) { rtp_twcc_manager_create_feedback (twcc); send_feedback = TRUE; + + twcc->packet_count_no_marker = 0; } return send_feedback; diff --git a/tests/check/elements/rtpsession.c b/tests/check/elements/rtpsession.c index d18b55bf0f..b03babc37e 100644 --- a/tests/check/elements/rtpsession.c +++ b/tests/check/elements/rtpsession.c @@ -2688,7 +2688,7 @@ typedef struct GstClockTime duration; } TWCCTestData; -static TWCCTestData twcc_header_and_run_lenght_test_data[] = { +static TWCCTestData twcc_header_and_run_length_test_data[] = { {0, 10, 0, 33 * GST_MSECOND}, {65530, 12, 37 * 64 * GST_MSECOND, 10 * GST_MSECOND}, /* seqnum wrap */ {99, 200, 1024 * 64 * GST_MSECOND, 10 * GST_MSECOND}, /* many packets */ @@ -2707,7 +2707,7 @@ GST_START_TEST (test_twcc_header_and_run_length) guint8 *fci_data; guint16 run_length; - TWCCTestData *td = &twcc_header_and_run_lenght_test_data[__i__]; + TWCCTestData *td = &twcc_header_and_run_length_test_data[__i__]; /* enable twcc */ session_harness_set_twcc_recv_ext_id (h, TEST_TWCC_EXT_ID); @@ -2775,6 +2775,16 @@ typedef struct gboolean marker; } TWCCPacket; +#define TWCC_DELTA_UNIT (250 * GST_USECOND) + +static void +fail_unless_equals_twcc_clocktime (GstClockTime twcc_packet_ts, + GstClockTime pkt_ts) +{ + fail_unless_equals_clocktime ( + (twcc_packet_ts / TWCC_DELTA_UNIT) * TWCC_DELTA_UNIT, pkt_ts); +} + #define twcc_push_packets(h, packets) \ G_STMT_START { \ guint i; \ @@ -2806,6 +2816,7 @@ G_STMT_START { \ gst_rtcp_packet_fb_get_type (&packet)); \ fci_data = gst_rtcp_packet_fb_get_fci (&packet); \ fci_length = gst_rtcp_packet_fb_get_fci_length (&packet) * sizeof (guint32); \ + GST_MEMDUMP ("fci:", fci_data, fci_length); \ fail_unless_equals_int (fci_length, sizeof (exp_fci)); \ fail_unless_equals_int (0, memcmp (fci_data, (exp_fci), fci_length)); \ gst_rtcp_buffer_unmap (&rtcp); \ @@ -2840,7 +2851,7 @@ G_STMT_START { \ fail_unless (gst_structure_get_uint (pkt_s, "seqnum", &seqnum)); \ twcc_pkt = &(packets)[j++]; \ fail_unless_equals_int (twcc_pkt->seqnum, seqnum); \ - fail_unless_equals_clocktime (twcc_pkt->timestamp, ts); \ + fail_unless_equals_twcc_clocktime (twcc_pkt->timestamp, ts); \ } \ gst_event_unref (event); \ } G_STMT_END @@ -2903,6 +2914,58 @@ GST_START_TEST (test_twcc_1_bit_status_vector) GST_END_TEST; +GST_START_TEST (test_twcc_status_vector_split_large_delta) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {1, 1 * 60 * GST_MSECOND, FALSE}, + {2, 2 * 60 * GST_MSECOND, FALSE}, + {3, 3 * 60 * GST_MSECOND, FALSE}, + {4, 4 * 60 * GST_MSECOND, FALSE}, + {5, 5 * 60 * GST_MSECOND, FALSE}, + {6, 6 * 60 * GST_MSECOND, FALSE}, + {7, 7 * 60 * GST_MSECOND, FALSE}, + {8, 8 * 60 * GST_MSECOND, FALSE}, + {9, 9 * 60 * GST_MSECOND, FALSE}, + {10, 10 * 60 * GST_MSECOND, FALSE}, + {11, 11 * 60 * GST_MSECOND, FALSE}, + {12, 12 * 60 * GST_MSECOND, FALSE}, + {13, 13 * 60 * GST_MSECOND, FALSE}, + {14, 14 * 60 * GST_MSECOND, FALSE}, + + {15, 60 * 60 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x01, /* base sequence number: 1 */ + 0x00, 0x0f, /* packet status count: 15 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0x20, 0x0e, /* run-length chunk with small delta for #1 to #14: 0 0 1 0 0 0 0 0 | 0 0 0 0 1 1 1 0 */ + 0x40, 0x01, /* rung-length with large delta for #15: 0 1 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ + + /* recv deltas: */ + 0xf0, 0xf0, /* 14 small deltas : +0:00:00.060000000 */ + 0xf0, 0xf0, + 0xf0, 0xf0, + 0xf0, 0xf0, + 0xf0, 0xf0, + 0xf0, 0xf0, + 0xf0, 0xf0, + 0x2b, 0x20, /* large delta: +0:00:02.760000000 */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + GST_START_TEST (test_twcc_2_bit_status_vector) { SessionHarness *h0 = session_harness_new (); @@ -2939,6 +3002,178 @@ GST_START_TEST (test_twcc_2_bit_status_vector) GST_END_TEST; +GST_START_TEST (test_twcc_2_bit_over_capacity) +{ + SessionHarness *h = session_harness_new (); + + TWCCPacket packets[] = { + {0, 0 * GST_MSECOND, FALSE}, + {6, 250 * 250 + 250 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x00, 0x07, /* packet status count: 7 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0xd0, 0x02, /* packet chunk: 1 1 0 1 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x03, 0xe8, /* recv delta: +0:00:00.000000000 */ + 0x00, 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h, packets, exp_fci); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_status_vector_split_with_gap) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {0, 0 * GST_MSECOND, FALSE}, + {7, (250 * 250) + 250 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x00, 0x08, /* packet status count: 8 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0xd0, 0x00, /* packet chunk: 1 1 0 1 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0xe0, 0x00, /* packet chunk: 1 1 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x03, 0xe8, /* recv delta: +0:00:00.250000000 */ + 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_status_vector_split_into_three) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + /* 7 packets with small deltas */ + {0, 0 * 250 * GST_USECOND, FALSE}, + {1, 1 * 250 * GST_USECOND, FALSE}, + {2, 2 * 250 * GST_USECOND, FALSE}, + {3, 3 * 250 * GST_USECOND, FALSE}, + {4, 4 * 250 * GST_USECOND, FALSE}, + {5, 5 * 250 * GST_USECOND, FALSE}, + {6, 6 * 250 * GST_USECOND, FALSE}, + + /* 2 large delta, #8 will present a negative delta */ + {7, 7 * 250 * GST_MSECOND, FALSE}, + {8, 8 * 250 * GST_USECOND, FALSE}, + + /* 13 packets with small deltas */ + {9, 9 * 250 * GST_USECOND, FALSE}, + {10, 10 * 250 * GST_USECOND, FALSE}, + {11, 11 * 250 * GST_USECOND, FALSE}, + {12, 12 * 250 * GST_USECOND, FALSE}, + {13, 13 * 250 * GST_USECOND, FALSE}, + {14, 14 * 250 * GST_USECOND, FALSE}, + {15, 15 * 250 * GST_USECOND, FALSE}, + {16, 16 * 250 * GST_USECOND, FALSE}, + {17, 17 * 250 * GST_USECOND, FALSE}, + {18, 18 * 250 * GST_USECOND, FALSE}, + {19, 19 * 250 * GST_USECOND, FALSE}, + {20, 20 * 250 * GST_USECOND, FALSE}, + {21, 21 * 250 * GST_USECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x00, 0x16, /* packet status count: 22 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0x20, 0x07, /* run-length chunk (small deltas) for #0 to #6: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 1 1 1 */ + 0x40, 0x02, /* run-length chunk (large deltas) for #7 and #8 0 1 0 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x20, 0x0d, /* run-length chunk (small deltas) for #9 and #21 0 1 0 0 0 0 0 0 | 0 0 0 0 1 1 0 1 */ + + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + + 0x1b, 0x52, /* recv delta: +0:00:01.748500000 */ + 0xe4, 0xb0, /* recv delta: -0:00:01.748000000 */ + + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + + 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_2_bit_full_status_vector) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {1, 1 * 64 * GST_MSECOND, FALSE}, + {2, 2 * 64 * GST_MSECOND, FALSE}, + {6, 6 * 64 * GST_MSECOND, FALSE}, + {7, 7 * 64 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x01, /* base sequence number: 1 */ + 0x00, 0x07, /* packet status count: 7 */ + 0x00, 0x00, 0x01, /* reference time: 1 */ + 0x00, /* feedback packet count: 0 */ + 0xd8, 0x0a, /* packet chunk: 1 1 0 1 1 0 0 0 | 0 0 0 0 1 0 1 0 */ + 0x00, 0x01, /* recv delta: +0:00:00.064000000 */ + 0x00, 0x04, /* recv delta: +0:00:00.256000000 */ + 0x00, 0x01, /* recv delta: +0:00:00.064000000 */ + 0x00, 0x00, 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + GST_START_TEST (test_twcc_various_gaps) { SessionHarness *h = session_harness_new (); @@ -3017,7 +3252,6 @@ GST_START_TEST (test_twcc_seqnum_wrap) }; twcc_verify_packets_to_fci (h0, packets, exp_fci); - twcc_verify_packets_to_packets (h1, h1, packets); session_harness_free (h0); @@ -3026,7 +3260,6 @@ GST_START_TEST (test_twcc_seqnum_wrap) GST_END_TEST; - GST_START_TEST (test_twcc_seqnum_wrap_with_loss) { SessionHarness *h = session_harness_new (); @@ -3039,10 +3272,10 @@ GST_START_TEST (test_twcc_seqnum_wrap_with_loss) guint8 exp_fci0[] = { 0xff, 0xfe, /* base sequence number: 65534 */ - 0x00, 0x01, /* packet status count: 2 */ + 0x00, 0x01, /* packet status count: 1 */ 0x00, 0x00, 0x00, /* reference time: 0 */ 0x00, /* feedback packet count: 0 */ - 0x20, 0x01, /* packet chunk */ + 0x20, 0x01, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ 0x00, /* recv delta: +0:00:00.000000000 */ 0x00, /* padding */ }; @@ -3052,7 +3285,7 @@ GST_START_TEST (test_twcc_seqnum_wrap_with_loss) 0x00, 0x01, /* packet status count: 1 */ 0x00, 0x00, 0x00, /* reference time: 0 */ 0x01, /* feedback packet count: 1 */ - 0x20, 0x01, /* packet chunk */ + 0x20, 0x01, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ 0x03, /* recv delta: +0:00:00.000750000 */ 0x00, /* padding */ }; @@ -3072,7 +3305,6 @@ GST_START_TEST (test_twcc_seqnum_wrap_with_loss) GST_END_TEST; - GST_START_TEST (test_twcc_double_packets) { SessionHarness *h = session_harness_new (); @@ -3090,7 +3322,7 @@ GST_START_TEST (test_twcc_double_packets) guint8 exp_fci0[] = { 0x00, 0x0b, /* base sequence number: 11 */ - 0x00, 0x02, /* packet status count: 14 */ + 0x00, 0x02, /* packet status count: 2 */ 0x00, 0x00, 0x00, /* reference time: 0 */ 0x00, /* feedback packet count: 0 */ 0x20, 0x02, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ @@ -3117,8 +3349,8 @@ GST_END_TEST; GST_START_TEST (test_twcc_huge_seqnum_gap) { - SessionHarness *h = session_harness_new (); - GstBuffer *buf; + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); TWCCPacket packets[] = { {9, 4 * 32 * GST_MSECOND, FALSE}, @@ -3128,37 +3360,13 @@ GST_START_TEST (test_twcc_huge_seqnum_gap) {30013, 8 * 32 * GST_MSECOND, TRUE}, }; - guint8 exp_fci0[] = { - 0x00, 0x09, /* base sequence number: 9 */ - 0x00, 0x02, /* packet status count: 2 */ - 0x00, 0x00, 0x02, /* reference time: 2 * 64ms */ - 0x00, /* feedback packet count: 0 */ - /* packet chunks: */ - 0x20, 0x02, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ - 0x00, 0x80, /* recv deltas, +0, +32ms */ - }; - - guint8 exp_fci1[] = { - 0x75, 0x3b, /* base sequence number: 300011 */ - 0x00, 0x03, /* packet status count: 3 */ - 0x00, 0x00, 0x03, /* reference time: 3 * 64ms */ - 0x01, /* feedback packet count: 1 */ - /* packet chunks: */ - 0x20, 0x03, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 1 */ - 0x00, 0x80, 0x80, /* recv deltas, +4, +32ms, +32ms */ - 0x00, 0x00, 0x00, /* padding */ - }; - - /* The sequence-number does a huge leap. Instead of encoding this as - a massive run-lenght sequence, like so */ -#if 0 guint8 exp_fci[] = { 0x00, 0x09, /* base sequence number: 9 */ 0x75, 0x35, /* packet status count: 30005 */ 0x00, 0x00, 0x02, /* reference time: 2 */ 0x00, /* feedback packet count: 0 */ /* packet chunks: */ - 0xb0, 0x00, /* 1 bit 2 there, 12 lost: 1 0 1 1 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0xb0, 0x00, /* run-length: 1 bit 2 there, 12 lost: 1 0 1 1 0 0 0 0 | 0 0 0 0 0 0 0 0 */ 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ @@ -3169,21 +3377,14 @@ GST_START_TEST (test_twcc_huge_seqnum_gap) 0x00, 0x80, 0x80, 0x80, 0x80, /* recv deltas */ 0x00, 0x00, 0x00, /* padding */ }; -#endif - /* ...just send two feedback-packets, with - the second one starting from the new sequence-number. */ - twcc_push_packets (h, packets); + twcc_push_packets (h0, packets); - buf = session_harness_produce_twcc (h); - twcc_verify_fci (buf, exp_fci0); - gst_buffer_unref (buf); + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); - buf = session_harness_produce_twcc (h); - twcc_verify_fci (buf, exp_fci1); - gst_buffer_unref (buf); - - session_harness_free (h); + session_harness_free (h0); + session_harness_free (h1); } GST_END_TEST; @@ -3203,35 +3404,22 @@ GST_START_TEST (test_twcc_duplicate_seqnums) {3, 7 * 32 * GST_MSECOND, TRUE}, }; - guint8 exp_fci0[] = { + guint8 exp_fci[] = { 0x00, 0x01, /* base sequence number: 1 */ - 0x00, 0x02, /* packet status count: 2 */ + 0x00, 0x03, /* packet status count: 2 */ 0x00, 0x00, 0x02, /* reference time: 2 * 64ms */ 0x00, /* feedback packet count: 0 */ /* packet chunks: */ - 0x20, 0x02, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ - 0x00, 0x80, /* recv deltas: +0, +32ms */ - }; - - guint8 exp_fci1[] = { - 0x00, 0x03, /* base sequence number: 3 */ - 0x00, 0x01, /* packet status count: 1 */ - 0x00, 0x00, 0x03, /* reference time: 3 * 64ms */ - 0x01, /* feedback packet count: 1 */ - /* packet chunks: */ - 0x20, 0x01, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ - 0x80, /* recv deltas: +32ms */ - 0x00, /* padding */ + 0xd6, 0x00, /* 1 1 0 1 0 1 1 0 | 0 0 0 0 0 0 0 0 */ + 0x00, 0x80, /* recv deltas: +0, +32ms, + 64ms */ + 0x01, 0x00, + 0x00, 0x00, /* padding */ }; twcc_push_packets (h, packets); buf = session_harness_produce_twcc (h); - twcc_verify_fci (buf, exp_fci0); - gst_buffer_unref (buf); - - buf = session_harness_produce_twcc (h); - twcc_verify_fci (buf, exp_fci1); + twcc_verify_fci (buf, exp_fci); gst_buffer_unref (buf); session_harness_free (h); @@ -3239,6 +3427,7 @@ GST_START_TEST (test_twcc_duplicate_seqnums) GST_END_TEST; + GST_START_TEST (test_twcc_multiple_markers) { SessionHarness *h = session_harness_new (); @@ -3320,7 +3509,7 @@ GST_START_TEST (test_twcc_no_marker_and_gaps) /* Push packets with gaps and no marker bit. This should not prevent the feedback packets from being sent at all. */ - for (i = 0; i < 80; i += 10) { + for (i = 0; i < 100; i += 10) { TWCCPacket packets[] = { {i, i * 250 * GST_USECOND, FALSE} }; twcc_push_packets (h, packets); @@ -3730,7 +3919,6 @@ GST_START_TEST (test_twcc_no_exthdr_in_buffer) GST_END_TEST; - GST_START_TEST (test_twcc_send_and_recv) { SessionHarness *h_send = session_harness_new (); @@ -3949,6 +4137,76 @@ GST_START_TEST (test_twcc_feedback_old_seqnum) GST_END_TEST; +GST_START_TEST (test_twcc_run_length_max) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + /* *INDENT-OFF* */ + {0, 1000 * GST_USECOND, FALSE}, + {8205, 2000 * GST_USECOND, TRUE}, + /* *INDENT-ON* */ + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x20, 0x0e, /* packet status count: 8206 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + + 0xa0, 0x00, /* 1bit status for #0 received: 1 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0x1f, 0xff, /* run-length with max length is reported as not received: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ + 0xa0, 0x00, /* 1bit status for #8205 received: 1 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + + 0x04, /* recv delta: +0:00:00.001000000 */ + 0x04, /* recv delta: +0:00:00.001000000 */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_run_length_min) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + /* *INDENT-OFF* */ + {0, 1000 * GST_USECOND, FALSE}, + {29, 2000 * GST_USECOND, TRUE}, + /* *INDENT-ON* */ + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x00, 0x1e, /* packet status count: 30 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + + 0xa0, 0x00, /* 1bit status for #0 received: 1 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0x00, 0x0f, /* run-length with length of 15, all not received: 0 0 0 0 0 0 0 0 | 0 0 0 0 1 1 1 1 */ + 0xa0, 0x00, /* 1bit status for #29 received: 1 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + + 0x04, /* recv delta: +0:00:00.001000000 */ + 0x04, /* recv delta: +0:00:00.001000000 */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + static Suite * rtpsession_suite (void) @@ -3996,9 +4254,16 @@ rtpsession_suite (void) /* twcc */ tcase_add_loop_test (tc_chain, test_twcc_header_and_run_length, - 0, G_N_ELEMENTS (twcc_header_and_run_lenght_test_data)); + 0, G_N_ELEMENTS (twcc_header_and_run_length_test_data)); + tcase_add_test (tc_chain, test_twcc_run_length_max); + tcase_add_test (tc_chain, test_twcc_run_length_min); tcase_add_test (tc_chain, test_twcc_1_bit_status_vector); tcase_add_test (tc_chain, test_twcc_2_bit_status_vector); + tcase_add_test (tc_chain, test_twcc_2_bit_over_capacity); + tcase_add_test (tc_chain, test_twcc_2_bit_full_status_vector); + tcase_add_test (tc_chain, test_twcc_status_vector_split_large_delta); + tcase_add_test (tc_chain, test_twcc_status_vector_split_with_gap); + tcase_add_test (tc_chain, test_twcc_status_vector_split_into_three); tcase_add_loop_test (tc_chain, test_twcc_various_gaps, 0, 50); tcase_add_test (tc_chain, test_twcc_negative_delta); tcase_add_test (tc_chain, test_twcc_seqnum_wrap); @@ -4021,7 +4286,6 @@ rtpsession_suite (void) tcase_add_test (tc_chain, test_twcc_feedback_count_wrap); tcase_add_test (tc_chain, test_twcc_feedback_old_seqnum); - return s; }