static void test_rtxsender_packet_retention (gboolean test_with_time) { guint master_ssrc = 1234567; guint master_pt = 96; guint rtx_ssrc = 7654321; guint rtx_pt = 99; gint num_buffers = test_with_time ? 30 : 10; gint half_buffers = num_buffers / 2; guint timestamp_delta = 90000 / 30; guint timestamp = G_MAXUINT32 - half_buffers * timestamp_delta; GstHarness *h; GstStructure *pt_map = gst_structure_new ("application/x-rtp-pt-map", "96", G_TYPE_UINT, rtx_pt, NULL); GstStructure *ssrc_map = gst_structure_new ("application/x-rtp-ssrc-map", "1234567", G_TYPE_UINT, rtx_ssrc, NULL); h = gst_harness_new ("rtprtxsend"); /* In both cases we want the rtxsend queue to store 'half_buffers' amount of buffers at most. In max-size-packets mode, it's trivial. In max-size-time mode, we specify almost half a second, which is the equivalent of 15 frames in a 30fps video stream. */ g_object_set (h->element, "max-size-packets", test_with_time ? 0 : half_buffers, "max-size-time", test_with_time ? 499 : 0, "payload-type-map", pt_map, "ssrc-map", ssrc_map, NULL); gst_harness_set_src_caps_str (h, "application/x-rtp, " "media = (string)video, payload = (int)96, " "ssrc = (uint)1234567, clock-rate = (int)90000, " "encoding-name = (string)RAW"); /* Now push all buffers and request retransmission every time for all of them */ for (gint i = 0; i < num_buffers; ++i, timestamp += timestamp_delta) { /* Request to retransmit all the previous ones */ for (gint j = 0; j < i; ++j) { guint rtx_seqnum = 0x100 + j; gst_harness_push_upstream_event (h, create_rtx_event (master_ssrc, master_pt, rtx_seqnum)); /* Pull only the ones supposed to be retransmited */ if (j >= i - half_buffers) pull_and_verify (h, TRUE, rtx_ssrc, rtx_pt, rtx_seqnum); } /* Check there no extra buffers in the harness queue */ fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0); /* We create RTP buffers with timestamps that will eventualy wrap around 0 to be sure, rtprtxsend can handle it properly */ push_pull_and_verify (h, create_rtp_buffer_with_timestamp (master_ssrc, master_pt, 0x100 + i, timestamp), FALSE, master_ssrc, master_pt, 0x100 + i); } gst_structure_free (pt_map); gst_structure_free (ssrc_map); gst_harness_teardown (h); }
static void create_destroy_element_harness (gpointer data, gpointer user_data) { GstElement *element = user_data; GstHarness *h = gst_harness_new_with_element (element, NULL, NULL); gst_harness_teardown (h); }
static void session_harness_free (SessionHarness * h) { gst_system_clock_set_default (NULL); gst_caps_unref (h->caps); gst_object_unref (h->testclock); gst_harness_teardown (h->rtcp_h); gst_harness_teardown (h->recv_rtp_h); gst_harness_teardown (h->send_rtp_h); g_object_unref (h->internal_session); gst_object_unref (h->session); g_free (h); }
static void rtp_jpeg_do_packet_loss (gdouble prob, gint num_expected) { GstHarness *h; gboolean eos = FALSE; gchar *s; guint i, buffer_count; s = g_strdup_printf ("videotestsrc pattern=ball num-buffers=100 ! " "jpegenc quality=50 ! rtpjpegpay ! identity drop-probability=%g ! " "rtpjpegdepay", prob); GST_INFO ("running pipeline %s", s); h = gst_harness_new_parse (s); g_free (s); gst_harness_play (h); do { GstEvent *event; event = gst_harness_pull_event (h); eos = (GST_EVENT_TYPE (event) == GST_EVENT_EOS); gst_event_unref (event); } while (!eos); buffer_count = gst_harness_buffers_received (h); GST_INFO ("Got %u buffers", buffer_count); if (num_expected >= 0) { fail_unless_equals_int (num_expected, buffer_count); } for (i = 0; i < buffer_count; ++i) { GstBuffer *buf; GstMapInfo map; guint16 soi, eoi; buf = gst_harness_pull (h); fail_unless (buf != NULL); fail_unless (gst_buffer_map (buf, &map, GST_MAP_READ)); GST_MEMDUMP ("jpeg frame", map.data, map.size); fail_unless (map.size > 4); soi = GST_READ_UINT16_BE (map.data); fail_unless (soi == 0xffd8, "expected JPEG frame start FFD8 not %02X", soi); eoi = GST_READ_UINT16_BE (map.data + map.size - 2); fail_unless (eoi == 0xffd9, "expected JPEG frame end FFD9 not %02X", eoi); gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); } gst_harness_teardown (h); }
static guint check_rtxsenders_stats_and_teardown (RtxSender * senders, guint senders_num) { guint total_pakets_num = 0; for (gint i = 0; i < senders_num; ++i) { guint rtx_requests; guint rtx_packets; g_object_get (G_OBJECT (senders[i].h->element), "num-rtx-requests", &rtx_requests, "num-rtx-packets", &rtx_packets, NULL); fail_unless_equals_int (rtx_packets, senders[i].expected_rtx_packets); fail_unless_equals_int (rtx_requests, senders[i].expected_rtx_packets); total_pakets_num += rtx_packets; gst_harness_teardown (senders[i].h); } return total_pakets_num; }
static void _recovered_from_fec_base (guint32 ssrc, guint8 fec_pt, guint8 lost_pt, guint16 lost_seq, gconstpointer fec_packet, gsize fec_packet_size, gconstpointer lost_packet, gsize lost_packet_size) { GstHarness *h = harness_rtpulpfecdec (ssrc, lost_pt, 123); RecoveredPacketInfo info = {.pt = lost_pt,.ssrc = ssrc,.seq = lost_seq }; GList *expected = expect_recovered_packets (h, &info, 1); push_data (h, fec_packet, fec_packet_size); lose_and_recover_test (h, lost_seq, lost_packet, lost_packet_size); check_rtpulpfecdec_stats (h, 1, 0); g_list_free (expected); gst_harness_teardown (h); }