From 12b420168c4dcb50c73deed820eb83f30a3e293a Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 11 Mar 2019 15:12:03 +0100 Subject: [PATCH] test: rtpbin_buffer_list: add a test for multiplexed RTP and RTCP RTP and RTCP packets can be muxed together on the same channel (see RFC5761) and can arrive in the same buffer list. The GStreamer rtpsession element support RFC5761, so add a test to cover this case for buffer lists too. --- tests/check/elements/rtpbin_buffer_list.c | 191 ++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/tests/check/elements/rtpbin_buffer_list.c b/tests/check/elements/rtpbin_buffer_list.c index 6561e10357..6aa98d7aa5 100644 --- a/tests/check/elements/rtpbin_buffer_list.c +++ b/tests/check/elements/rtpbin_buffer_list.c @@ -23,6 +23,7 @@ #include #include +#include /* UDP/IP is assumed for bandwidth calculation */ #define UDP_IP_HEADER_OVERHEAD 28 @@ -80,6 +81,16 @@ static const guint payload_len[] = { static GstBuffer *original_buffer = NULL; +static GstStaticPadTemplate sinktemplate_rtcp = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtcp")); + +static GstStaticPadTemplate srctemplate_rtcp = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtcp")); + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -773,6 +784,110 @@ sink_chain_list_different_frames (GstPad * pad, GstObject * parent, } +/* + * RTP and RTCP can be multiplexed in the same channel and end up in the same + * buffer list. + */ +static GstBufferList * +create_buffer_list_muxed_rtcp (void) +{ + GstBufferList *list; + GstBuffer *orig_buffer; + GstBuffer *buffer; + GstRTCPBuffer rtcpbuf = GST_RTCP_BUFFER_INIT; + GstRTCPPacket rtcppacket; + + guint seqnum = 0; + + orig_buffer = create_original_buffer (); + fail_if (orig_buffer == NULL); + + list = gst_buffer_list_new (); + fail_if (list == NULL); + + buffer = + create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0], + orig_buffer, payload_offset[0], payload_len[0], seqnum, 0); + gst_buffer_list_add (list, buffer); + + seqnum++; + + buffer = + create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0], + orig_buffer, payload_offset[0], payload_len[0], seqnum, 0); + gst_buffer_list_add (list, buffer); + + seqnum++; + + buffer = gst_rtcp_buffer_new (1500); + gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcpbuf); + gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SR, &rtcppacket); + gst_rtcp_packet_sr_set_sender_info (&rtcppacket, 0, 0, 0, 0, 0); + gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_RR, &rtcppacket); + gst_rtcp_packet_rr_set_ssrc (&rtcppacket, 1); + gst_rtcp_packet_add_rb (&rtcppacket, 0, 0, 0, 0, 0, 0, 0); + gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SDES, &rtcppacket); + gst_rtcp_packet_sdes_add_item (&rtcppacket, 1); + gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_CNAME, 3, + (guint8 *) "a@a"); + gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_NAME, 2, + (guint8 *) "aa"); + gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_END, 0, + (guint8 *) ""); + gst_rtcp_buffer_unmap (&rtcpbuf); + + gst_buffer_list_add (list, buffer); + + buffer = + create_rtp_buffer_fields (&rtp_header[0], rtp_header_len[0], + orig_buffer, payload_offset[0], payload_len[0], seqnum, 0); + gst_buffer_list_add (list, buffer); + + return list; +} + +/* + * All RTP buffers should have been pushed to recv_rtp_src, the RTCP packet + * should have been pushed to sync_src. + */ +static GstFlowReturn +sink_chain_list_muxed_rtcp (GstPad * pad, GstObject * parent, + GstBufferList * list) +{ + GstBuffer *buffer; + + chain_list_func_called = TRUE; + + fail_unless (GST_IS_BUFFER_LIST (list)); + fail_unless (gst_buffer_list_length (list) == 3); + + /* Verify seqnums of RTP packets. */ + buffer = gst_buffer_list_get (list, 0); + check_seqnum (buffer, 0); + + buffer = gst_buffer_list_get (list, 1); + check_seqnum (buffer, 1); + + buffer = gst_buffer_list_get (list, 2); + check_seqnum (buffer, 2); + + gst_buffer_list_unref (list); + + return GST_FLOW_OK; +} + +/* count multiplexed rtcp packets */ +static guint rtcp_packets; + +static GstFlowReturn +sink_chain_muxed_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + rtcp_packets++; + gst_buffer_unref (buffer); + return GST_FLOW_OK; +} + + /* Get the stats of the **first** source of the given type (get_sender) */ static void get_source_stats (GstElement * rtpsession, @@ -1286,6 +1401,81 @@ GST_START_TEST (test_bufferlist_recv_different_frames) GST_END_TEST; +GST_START_TEST (test_bufferlist_recv_muxed_rtcp) +{ + GstElement *rtpbin; + GstPad *srcpad; + GstPad *sinkpad; + GstPad *srcpad_rtcp; + GstPad *sinkpad_rtcp; + GstCaps *caps; + GstBufferList *list; + + list = create_buffer_list_muxed_rtcp (); + fail_unless (list != NULL); + + rtpbin = gst_check_setup_element ("rtpsession"); + + srcpad = + gst_check_setup_src_pad_by_name (rtpbin, &srctemplate, "recv_rtp_sink"); + fail_if (srcpad == NULL); + + sinkpad = + gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate, "recv_rtp_src"); + fail_if (sinkpad == NULL); + + gst_pad_set_chain_list_function (sinkpad, + GST_DEBUG_FUNCPTR (sink_chain_list_muxed_rtcp)); + + gst_pad_set_active (srcpad, TRUE); + gst_pad_set_active (sinkpad, TRUE); + + caps = gst_caps_from_string (TEST_CAPS); + gst_check_setup_events (srcpad, rtpbin, caps, GST_FORMAT_TIME); + gst_caps_unref (caps); + + /* + * Create supplementary pads after gst_check_setup_events() to avoid + * a failure in gst_pad_create_stream_id(). + */ + srcpad_rtcp = + gst_check_setup_src_pad_by_name (rtpbin, &srctemplate_rtcp, + "recv_rtcp_sink"); + fail_if (srcpad_rtcp == NULL); + + sinkpad_rtcp = + gst_check_setup_sink_pad_by_name (rtpbin, &sinktemplate_rtcp, "sync_src"); + fail_if (sinkpad_rtcp == NULL); + + gst_pad_set_chain_function (sinkpad_rtcp, + GST_DEBUG_FUNCPTR (sink_chain_muxed_rtcp)); + + gst_pad_set_active (srcpad_rtcp, TRUE); + gst_pad_set_active (sinkpad_rtcp, TRUE); + + gst_element_set_state (rtpbin, GST_STATE_PLAYING); + + chain_list_func_called = FALSE; + rtcp_packets = 0; + fail_unless (gst_pad_push_list (srcpad, list) == GST_FLOW_OK); + fail_if (chain_list_func_called == FALSE); + fail_unless (rtcp_packets == 1); + + gst_pad_set_active (sinkpad_rtcp, FALSE); + gst_pad_set_active (srcpad_rtcp, FALSE); + gst_pad_set_active (sinkpad, FALSE); + gst_pad_set_active (srcpad, FALSE); + + gst_check_teardown_pad_by_name (rtpbin, "sync_src"); + gst_check_teardown_pad_by_name (rtpbin, "recv_rtcp_sink"); + gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_src"); + gst_check_teardown_pad_by_name (rtpbin, "recv_rtp_sink"); + gst_check_teardown_element (rtpbin); +} + +GST_END_TEST; + + static Suite * bufferlist_suite (void) { @@ -1306,6 +1496,7 @@ bufferlist_suite (void) tcase_add_test (tc_chain, test_bufferlist_recv_large_jump_recovery); tcase_add_test (tc_chain, test_bufferlist_recv_reordered_packets); tcase_add_test (tc_chain, test_bufferlist_recv_different_frames); + tcase_add_test (tc_chain, test_bufferlist_recv_muxed_rtcp); return s; }