From 347caecbe958dbe374046fbf15cf34ab6fc34778 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Thu, 22 Oct 2009 13:39:58 +0300 Subject: [PATCH] tests: also include the new test for prev commit --- tests/check/elements/rtpjitterbuffer.c | 286 +++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 tests/check/elements/rtpjitterbuffer.c diff --git a/tests/check/elements/rtpjitterbuffer.c b/tests/check/elements/rtpjitterbuffer.c new file mode 100644 index 0000000..12fad5f --- /dev/null +++ b/tests/check/elements/rtpjitterbuffer.c @@ -0,0 +1,286 @@ +/* GStreamer + * + * Copyright (C) 2009 Nokia Corporation and its subsidary(-ies) + * contact: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +/* For ease of programming we use globals to keep refs for our floating + * src and sink pads we create; otherwise we always have to do get_pad, + * get_peer, and then remove references in every test function */ +static GstPad *mysrcpad, *mysinkpad; +/* we also have a list of src buffers */ +static GList *inbuffers = NULL; + +#define RTP_CAPS_STRING \ + "application/x-rtp, " \ + "media = (string)audio, " \ + "payload = (int) 0, " \ + "clock-rate = (int) 8000, " \ + "encoding-name = (string)PCMU" + +#define RTP_FRAME_SIZE 20 + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "clock-rate = (int) [ 1, 2147483647 ]") + ); + +static GstElement * +setup_jitterbuffer (gint num_buffers) +{ + GstElement *jitterbuffer; + GstClock *clock; + GstBuffer *buffer; + GstCaps *caps; + /* generated with + * gst-launch audiotestsrc wave=silence blocksize=40 num-buffers=3 ! + * "audio/x-raw-int,channels=1,rate=8000" ! mulawenc ! rtppcmupay ! + * fakesink dump=1 + */ + guint8 in[] = { /* first 4 bytes are rtp-header, next 4 bytes are timestamp */ + 0x80, 0x80, 0x1c, 0x24, 0x46, 0xcd, 0xb7, 0x11, 0x3c, 0x3a, 0x7c, 0x5b, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + GstClockTime ts = G_GUINT64_CONSTANT (0); + GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000); + /*guint latency = GST_TIME_AS_MSECONDS (num_buffers*tso); */ + gint i; + + GST_DEBUG ("setup_jitterbuffer"); + jitterbuffer = gst_check_setup_element ("gstrtpjitterbuffer"); + /* we need a clock here */ + clock = gst_system_clock_obtain (); + gst_element_set_clock (jitterbuffer, clock); + gst_object_unref (clock); + /* setup latency */ + /* latency would be 7 for 3 buffers here, default is 200 + g_object_set (G_OBJECT (jitterbuffer), "latency", latency, NULL); + GST_INFO_OBJECT (jitterbuffer, "set latency to %u ms", latency); + */ + + mysrcpad = gst_check_setup_src_pad (jitterbuffer, &srctemplate, NULL); + mysinkpad = gst_check_setup_sink_pad (jitterbuffer, &sinktemplate, NULL); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + /* create n buffers */ + caps = gst_caps_from_string (RTP_CAPS_STRING); + for (i = 0; i < num_buffers; i++) { + buffer = gst_buffer_new_and_alloc (sizeof (in)); + memcpy (GST_BUFFER_DATA (buffer), in, sizeof (in)); + gst_buffer_set_caps (buffer, caps); + GST_BUFFER_TIMESTAMP (buffer) = ts; + GST_BUFFER_DURATION (buffer) = tso; + + if (!i) + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); + + inbuffers = g_list_append (inbuffers, buffer); + + /* hackish way to update the rtp header */ + in[1] = 0x00; + in[3]++; /* seqnumber */ + in[7] += RTP_FRAME_SIZE; /* inc. timestamp with framesize */ + ts += tso; + } + gst_caps_unref (caps); + + return jitterbuffer; +} + +static void +cleanup_jitterbuffer (GstElement * jitterbuffer) +{ + GST_DEBUG ("cleanup_jitterbuffer"); + + g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL); + g_list_free (buffers); + buffers = NULL; + + g_list_free (inbuffers); + inbuffers = NULL; + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (jitterbuffer); + gst_check_teardown_sink_pad (jitterbuffer); + gst_check_teardown_element (jitterbuffer); +} + +static void +check_jitterbuffer_results (GstElement * jitterbuffer, gint num_buffers) +{ + GstBuffer *buffer; + GList *node; + GstClockTime ts = G_GUINT64_CONSTANT (0); + GstClockTime tso = gst_util_uint64_scale (RTP_FRAME_SIZE, GST_SECOND, 8000); + guint8 *data; + guint16 prev_sn = 0, cur_sn; + guint32 prev_ts = 0, cur_ts; + + /* check the buffer list */ + fail_unless_equals_int (g_list_length (buffers), num_buffers); + for (node = buffers; node; node = g_list_next (node)) { + fail_if ((buffer = (GstBuffer *) node->data) == NULL); + fail_if (GST_BUFFER_TIMESTAMP (buffer) != ts); + data = GST_BUFFER_DATA (buffer); + cur_sn = ((guint16) data[2] << 8) | data[3]; + cur_ts = ((guint32) data[4] << 24) | ((guint32) data[5] << 16) | + ((guint32) data[6] << 8) | data[7]; + + if (node != buffers) { + fail_unless (cur_sn > prev_sn); + fail_unless (cur_ts > prev_ts); + + prev_sn = cur_sn; + prev_ts = cur_ts; + } + ts += tso; + } +} + +GST_START_TEST (test_push_forward_seq) +{ + GstElement *jitterbuffer; + const guint num_buffers = 3; + GstBuffer *buffer; + GList *node; + + jitterbuffer = setup_jitterbuffer (num_buffers); + fail_unless (gst_element_set_state (jitterbuffer, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* push buffers: 0,1,2, */ + for (node = inbuffers; node; node = g_list_next (node)) { + buffer = (GstBuffer *) node->data; + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + } + + /* check the buffer list */ + check_jitterbuffer_results (jitterbuffer, num_buffers); + + /* cleanup */ + cleanup_jitterbuffer (jitterbuffer); +} + +GST_END_TEST; + +#if 0 +GST_START_TEST (test_push_backward_seq) +{ + GstElement *jitterbuffer; + const guint num_buffers = 3; + GstBuffer *buffer; + GList *node; + + jitterbuffer = setup_jitterbuffer (num_buffers); + fail_unless (gst_element_set_state (jitterbuffer, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* push buffers: 2,1,0 */ + for (node = g_list_last (inbuffers); node; node = g_list_previous (node)) { + buffer = (GstBuffer *) node->data; + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + } + + /* attempt to flush the jitterbuffer */ +#if 0 + gst_pad_push_event (mysrcpad, gst_event_new_eos ()); + gst_element_set_state (jitterbuffer, GST_STATE_READY); + gst_element_get_state (jitterbuffer, NULL, NULL, GST_CLOCK_TIME_NONE); +#endif + + /* check the buffer list */ + check_jitterbuffer_results (jitterbuffer, num_buffers); + + /* cleanup */ + cleanup_jitterbuffer (jitterbuffer); +} + +GST_END_TEST; + + +GST_START_TEST (test_push_unordered) +{ + GstElement *jitterbuffer; + const guint num_buffers = 3; + GstBuffer *buffer; + + jitterbuffer = setup_jitterbuffer (num_buffers); + fail_unless (gst_element_set_state (jitterbuffer, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + /* push buffers; 0,2,1 */ + buffer = (GstBuffer *) inbuffers->data; + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + buffer = g_list_nth_data (inbuffers, 2); + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + buffer = g_list_nth_data (inbuffers, 1); + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + + /* attempt to flush the jitterbuffer */ +#if 0 + gst_pad_push_event (mysrcpad, gst_event_new_eos ()); + gst_element_set_state (jitterbuffer, GST_STATE_READY); + gst_element_get_state (jitterbuffer, NULL, NULL, GST_CLOCK_TIME_NONE); +#endif + + /* check the buffer list */ + check_jitterbuffer_results (jitterbuffer, num_buffers); + + /* cleanup */ + cleanup_jitterbuffer (jitterbuffer); +} + +GST_END_TEST; +#endif + +static Suite * +rtpjitterbuffer_suite (void) +{ + Suite *s = suite_create ("rtpjitterbuffer"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_push_forward_seq); +#if 0 + /* these don't work yet, buffers get dropped or never arrive in the buffers + * list */ + tcase_add_test (tc_chain, test_push_backward_seq); + tcase_add_test (tc_chain, test_push_unordered); +#endif + + /* FIXME: test buffer lists */ + + return s; +} + +GST_CHECK_MAIN (rtpjitterbuffer); -- 2.7.4