3 * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
24 #include <gst/check/gstcheck.h>
25 #include <gst/dataprotocol/dataprotocol.h>
27 /* For ease of programming we use globals to keep refs for our floating
28 * src and sink pads we create; otherwise we always have to do get_pad,
29 * get_peer, and then remove references in every test function */
30 static GstPad *mysrcpad, *myshsrcpad, *mysinkpad;
32 #define FORMATS "{ S8, "GST_AUDIO_NE(S16)" }"
34 #define AUDIO_CAPS_TEMPLATE_STRING \
36 "format = (string) "FORMATS", " \
37 "rate = (int) [ 1, MAX ], " \
38 "channels = (int) [ 1, 8 ]"
40 #define AUDIO_CAPS_STRING \
42 "format = (string) "GST_AUDIO_NE(S16)", " \
43 "rate = (int) 1000, " \
47 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_STATIC_CAPS ("application/x-gdp")
52 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
55 GST_STATIC_CAPS (AUDIO_CAPS_TEMPLATE_STRING)
58 /* takes over reference for outcaps */
64 GST_DEBUG ("setup_gdppay");
65 gdppay = gst_check_setup_element ("gdppay");
66 mysrcpad = gst_check_setup_src_pad (gdppay, &srctemplate, NULL);
67 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate, NULL);
68 gst_pad_set_active (mysrcpad, TRUE);
69 gst_pad_set_active (mysinkpad, TRUE);
75 cleanup_gdppay (GstElement * gdppay)
77 GST_DEBUG ("cleanup_gdppay");
80 gst_pad_set_active (mysrcpad, FALSE);
82 gst_pad_set_active (myshsrcpad, FALSE);
83 gst_pad_set_active (mysinkpad, FALSE);
84 gst_check_teardown_src_pad (gdppay);
85 gst_check_teardown_sink_pad (gdppay);
86 gst_check_teardown_element (gdppay);
91 GST_START_TEST (test_audio)
95 GstBuffer *inbuffer, *outbuffer;
100 gdppay = setup_gdppay ();
102 fail_unless (gst_element_set_state (gdppay,
103 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
104 "could not set to playing");
106 GST_DEBUG ("new segment");
108 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
109 fail_unless (gst_pad_push_event (mysrcpad, event));
111 /* no buffer should be pushed yet, waiting for caps */
112 fail_unless_equals_int (g_list_length (buffers), 0);
114 GST_DEBUG ("first buffer");
115 inbuffer = gst_buffer_new_and_alloc (4);
116 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
117 gst_buffer_set_caps (inbuffer, caps);
118 caps_string = gst_caps_to_string (caps);
120 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
122 /* pushing gives away my reference */
123 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
125 /* we should have three buffers now */
126 fail_unless_equals_int (g_list_length (buffers), 3);
128 /* first buffer is the serialized new_segment event;
129 * the element also holds a ref to it */
130 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
131 buffers = g_list_remove (buffers, outbuffer);
132 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
133 gst_buffer_unref (outbuffer);
135 /* second buffer is the serialized caps;
136 * the element also holds a ref to it */
137 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
138 buffers = g_list_remove (buffers, outbuffer);
139 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
140 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
141 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
142 gst_buffer_unref (outbuffer);
144 /* the third buffer is the GDP buffer for our pushed buffer */
145 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
146 buffers = g_list_remove (buffers, outbuffer);
147 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
148 length = GST_DP_HEADER_LENGTH + 4;
149 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
150 gst_buffer_unref (outbuffer);
153 GST_DEBUG ("second buffer");
154 inbuffer = gst_buffer_new_and_alloc (4);
155 gst_buffer_set_caps (inbuffer, caps);
157 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
159 /* pushing gives away my reference */
160 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
162 fail_unless_equals_int (g_list_length (buffers), 1);
163 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
164 buffers = g_list_remove (buffers, outbuffer);
165 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
167 /* the third output buffer is data */
168 length = GST_DP_HEADER_LENGTH + 4;
169 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
170 gst_buffer_unref (outbuffer);
172 /* a third buffer without caps set explicitly; should work */
173 GST_DEBUG ("Creating third buffer, no caps set");
174 inbuffer = gst_buffer_new_and_alloc (4);
176 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
178 /* pushing gives away my reference */
179 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
181 fail_unless_equals_int (g_list_length (buffers), 1);
182 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
183 buffers = g_list_remove (buffers, outbuffer);
184 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
186 /* the fourth output buffer is data */
187 length = GST_DP_HEADER_LENGTH + 4;
188 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
189 gst_buffer_unref (outbuffer);
192 fail_unless (gst_element_set_state (gdppay,
193 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
195 gst_caps_unref (caps);
196 g_free (caps_string);
197 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
198 g_list_free (buffers);
200 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
201 cleanup_gdppay (gdppay);
206 static GstStaticPadTemplate shsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
209 GST_STATIC_CAPS ("application/x-gst-test-streamheader")
214 setup_gdppay_streamheader (void)
218 GST_DEBUG ("setup_gdppay");
219 gdppay = gst_check_setup_element ("gdppay");
220 myshsrcpad = gst_check_setup_src_pad (gdppay, &shsrctemplate, NULL);
221 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate, NULL);
222 gst_pad_set_active (myshsrcpad, TRUE);
223 gst_pad_set_active (mysinkpad, TRUE);
228 /* this test serializes a stream that already has a streamheader of its own.
229 * the streamheader should then be serialized and put on the GDP stream's
231 GST_START_TEST (test_streamheader)
233 GstCaps *caps, *sinkcaps;
235 GstBuffer *inbuffer, *outbuffer, *shbuffer;
239 GstStructure *structure;
240 GValue array = { 0 };
241 GValue value = { 0 };
246 gdppay = setup_gdppay_streamheader ();
248 fail_unless (gst_element_set_state (gdppay,
249 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
250 "could not set to playing");
252 GST_DEBUG ("new segment");
254 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
255 fail_unless (gst_pad_push_event (myshsrcpad, event));
257 /* no buffer should be pushed yet, still waiting for caps */
258 fail_unless_equals_int (g_list_length (buffers), 0);
260 GST_DEBUG ("first buffer");
261 inbuffer = gst_buffer_new_and_alloc (4);
262 gst_buffer_fill (inbuffer, 0, "head", 4);
263 caps = gst_caps_from_string ("application/x-gst-test-streamheader");
264 structure = gst_caps_get_structure (caps, 0);
265 GST_BUFFER_FLAG_SET (inbuffer, GST_BUFFER_FLAG_IN_CAPS);
266 g_value_init (&array, GST_TYPE_ARRAY);
267 g_value_init (&value, GST_TYPE_BUFFER);
268 shbuffer = gst_buffer_copy (inbuffer);
269 gst_value_set_buffer (&value, shbuffer);
270 gst_buffer_unref (shbuffer);
271 gst_value_array_append_value (&array, &value);
272 g_value_unset (&value);
273 gst_structure_set_value (structure, "streamheader", &array);
274 g_value_unset (&array);
275 caps_string = gst_caps_to_string (caps);
277 gst_buffer_set_caps (inbuffer, caps);
278 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
280 /* pushing gives away my reference */
281 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
283 /* we should have three buffers now */
284 fail_unless_equals_int (g_list_length (buffers), 3);
286 /* our sink pad should now have GDP caps with a streamheader that includes
287 * GDP wrappings of our streamheader */
288 sinkcaps = gst_pad_get_negotiated_caps (mysinkpad);
289 structure = gst_caps_get_structure (sinkcaps, 0);
290 fail_unless_equals_string ((gchar *) gst_structure_get_name (structure),
291 "application/x-gdp");
292 fail_unless (gst_structure_has_field (structure, "streamheader"));
293 sh = gst_structure_get_value (structure, "streamheader");
294 fail_unless (G_VALUE_TYPE (sh) == GST_TYPE_ARRAY);
295 shbuffers = g_value_peek_pointer (sh);
296 /* a serialized new_segment, a serialized caps, and serialization of our
297 * incoming streamheader */
298 fail_unless_equals_int (shbuffers->len, 3);
300 gst_caps_unref (sinkcaps);
302 /* first buffer is the serialized new_segment event;
303 * the element also holds a ref to it */
304 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
305 buffers = g_list_remove (buffers, outbuffer);
306 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
307 gst_buffer_unref (outbuffer);
309 /* second buffer is the serialized caps;
310 * the element also holds a ref to it */
311 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
312 buffers = g_list_remove (buffers, outbuffer);
313 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
314 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
315 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
316 gst_buffer_unref (outbuffer);
318 /* the third buffer is the GDP buffer for our pushed buffer */
319 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
320 buffers = g_list_remove (buffers, outbuffer);
321 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
322 length = GST_DP_HEADER_LENGTH + 4;
323 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
324 gst_buffer_unref (outbuffer);
327 GST_DEBUG ("second buffer");
328 inbuffer = gst_buffer_new_and_alloc (4);
329 gst_buffer_set_caps (inbuffer, caps);
331 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
333 /* pushing gives away my reference */
334 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
336 fail_unless_equals_int (g_list_length (buffers), 1);
337 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
338 buffers = g_list_remove (buffers, outbuffer);
339 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
341 /* the third output buffer is data */
342 length = GST_DP_HEADER_LENGTH + 4;
343 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
344 gst_buffer_unref (outbuffer);
346 /* a third buffer without caps set explicitly; should work */
347 GST_DEBUG ("Creating third buffer, no caps set");
348 inbuffer = gst_buffer_new_and_alloc (4);
350 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
352 /* pushing gives away my reference */
353 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
355 fail_unless_equals_int (g_list_length (buffers), 1);
356 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
357 buffers = g_list_remove (buffers, outbuffer);
358 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
360 /* the fourth output buffer is data */
361 length = GST_DP_HEADER_LENGTH + 4;
362 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
363 gst_buffer_unref (outbuffer);
366 fail_unless (gst_element_set_state (gdppay,
367 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
369 gst_caps_unref (caps);
370 g_free (caps_string);
371 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
372 g_list_free (buffers);
374 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
375 cleanup_gdppay (gdppay);
381 GST_START_TEST (test_first_no_caps)
386 gdppay = setup_gdppay ();
388 fail_unless (gst_element_set_state (gdppay,
389 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
390 "could not set to playing");
392 GST_DEBUG ("first buffer");
393 inbuffer = gst_buffer_new_and_alloc (4);
394 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
396 /* pushing should trigger an error */
397 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_NOT_NEGOTIATED);
399 fail_unless_equals_int (g_list_length (buffers), 0);
401 fail_unless (gst_element_set_state (gdppay,
402 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
404 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
405 g_list_free (buffers);
407 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
408 cleanup_gdppay (gdppay);
413 /* element should still work if no new_segment is sent before the first
415 GST_START_TEST (test_first_no_new_segment)
421 gdppay = setup_gdppay ();
423 fail_unless (gst_element_set_state (gdppay,
424 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
425 "could not set to playing");
427 GST_DEBUG ("first buffer");
428 inbuffer = gst_buffer_new_and_alloc (4);
429 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
430 gst_buffer_set_caps (inbuffer, caps);
431 gst_caps_unref (caps);
433 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
435 /* pushing gives away my reference */
436 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
438 /* we should have three buffers now;
439 * one for an "invented" new segment, one for GDP caps, and one with our
441 fail_unless_equals_int (g_list_length (buffers), 3);
443 fail_unless (gst_element_set_state (gdppay,
444 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
446 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
447 g_list_free (buffers);
449 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
450 cleanup_gdppay (gdppay);
455 GST_START_TEST (test_crc)
459 GstBuffer *inbuffer, *outbuffer;
465 guint16 crc_calculated, crc_read;
467 gdppay = setup_gdppay ();
468 g_object_set (gdppay, "crc-header", TRUE, NULL);
470 fail_unless (gst_element_set_state (gdppay,
471 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
472 "could not set to playing");
474 GST_DEBUG ("new segment");
476 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, GST_SECOND, 0);
477 fail_unless (gst_pad_push_event (mysrcpad, event));
479 /* no buffer should be pushed yet, waiting for caps */
480 fail_unless_equals_int (g_list_length (buffers), 0);
482 GST_DEBUG ("first buffer");
483 inbuffer = gst_buffer_new_and_alloc (4);
484 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
485 gst_buffer_set_caps (inbuffer, caps);
486 caps_string = gst_caps_to_string (caps);
488 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
490 /* pushing gives away my reference */
491 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
493 /* we should have three buffers now */
494 fail_unless_equals_int (g_list_length (buffers), 3);
496 /* first buffer is the serialized new_segment event;
497 * the element also holds a ref to it */
498 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
499 buffers = g_list_remove (buffers, outbuffer);
500 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
502 /* verify the header checksum */
503 /* CRC's start at 58 in the header */
504 outbuffer = gst_buffer_make_writable (outbuffer);
505 data = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READWRITE);
506 crc_calculated = gst_dp_crc (data, 58);
507 crc_read = GST_READ_UINT16_BE (data + 58);
508 fail_unless_equals_int (crc_calculated, crc_read);
510 /* change a byte in the header and verify that the checksum now fails */
512 crc_calculated = gst_dp_crc (data, 58);
513 fail_if (crc_calculated == crc_read,
514 "Introducing a byte error in the header should make the checksum fail");
516 gst_buffer_unmap (outbuffer, data, size);
517 gst_buffer_unref (outbuffer);
519 /* second buffer is the serialized caps;
520 * the element also holds a ref to it */
521 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
522 buffers = g_list_remove (buffers, outbuffer);
523 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
524 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
525 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
526 gst_buffer_unref (outbuffer);
528 /* the third buffer is the GDP buffer for our pushed buffer */
529 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
530 buffers = g_list_remove (buffers, outbuffer);
531 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
532 length = GST_DP_HEADER_LENGTH + 4;
533 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
534 gst_buffer_unref (outbuffer);
536 fail_unless (gst_element_set_state (gdppay,
537 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
539 gst_caps_unref (caps);
540 g_free (caps_string);
541 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
542 g_list_free (buffers);
544 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
545 cleanup_gdppay (gdppay);
554 Suite *s = suite_create ("gdppay");
555 TCase *tc_chain = tcase_create ("general");
557 suite_add_tcase (s, tc_chain);
558 tcase_add_test (tc_chain, test_audio);
559 tcase_add_test (tc_chain, test_first_no_caps);
560 tcase_add_test (tc_chain, test_first_no_new_segment);
561 tcase_add_test (tc_chain, test_streamheader);
562 tcase_add_test (tc_chain, test_crc);
567 GST_CHECK_MAIN (gdppay);