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.
25 #include <gst/check/gstcheck.h>
26 #include <gst/audio/audio.h>
27 #include "../../gst/gdp/dataprotocol.c"
29 /* For ease of programming we use globals to keep refs for our floating
30 * src and sink pads we create; otherwise we always have to do get_pad,
31 * get_peer, and then remove references in every test function */
32 static GstPad *mysrcpad, *myshsrcpad, *mysinkpad;
34 #define FORMATS "{ S8, "GST_AUDIO_NE(S16)" }"
36 #define AUDIO_CAPS_TEMPLATE_STRING \
38 "format = (string) "FORMATS", " \
39 "rate = (int) [ 1, MAX ], " \
40 "channels = (int) [ 1, 8 ]"
42 #define AUDIO_CAPS_STRING \
44 "format = (string) "GST_AUDIO_NE(S16)", " \
45 "rate = (int) 1000, " \
49 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS ("application/x-gdp")
54 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
57 GST_STATIC_CAPS (AUDIO_CAPS_TEMPLATE_STRING)
60 /* takes over reference for outcaps */
66 GST_DEBUG ("setup_gdppay");
67 gdppay = gst_check_setup_element ("gdppay");
68 mysrcpad = gst_check_setup_src_pad (gdppay, &srctemplate);
69 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate);
70 gst_pad_set_active (mysrcpad, TRUE);
71 gst_pad_set_active (mysinkpad, TRUE);
77 cleanup_gdppay (GstElement * gdppay)
79 GST_DEBUG ("cleanup_gdppay");
82 gst_pad_set_active (mysrcpad, FALSE);
84 gst_pad_set_active (myshsrcpad, FALSE);
85 gst_pad_set_active (mysinkpad, FALSE);
86 gst_check_teardown_src_pad (gdppay);
87 gst_check_teardown_sink_pad (gdppay);
88 gst_check_teardown_element (gdppay);
93 GST_START_TEST (test_audio)
97 GstBuffer *inbuffer, *outbuffer;
103 gdppay = setup_gdppay ();
105 fail_unless (gst_element_set_state (gdppay,
106 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
107 "could not set to playing");
109 GST_DEBUG ("new segment");
110 gst_segment_init (&segment, GST_FORMAT_TIME);
111 segment.stop = GST_SECOND;
112 event = gst_event_new_segment (&segment);
113 fail_unless (gst_pad_push_event (mysrcpad, event));
115 /* no buffer should be pushed yet, waiting for caps */
116 fail_unless_equals_int (g_list_length (buffers), 0);
118 GST_DEBUG ("first buffer");
119 inbuffer = gst_buffer_new_and_alloc (4);
120 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
121 gst_pad_set_caps (mysrcpad, caps);
122 caps_string = gst_caps_to_string (caps);
124 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
126 /* pushing gives away my reference */
127 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
129 /* we should have three buffers now */
130 fail_unless_equals_int (g_list_length (buffers), 3);
132 /* first buffer is the serialized new_segment event;
133 * the element also holds a ref to it */
134 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
135 buffers = g_list_remove (buffers, outbuffer);
136 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
137 gst_buffer_unref (outbuffer);
139 /* second buffer is the serialized caps;
140 * the element also holds a ref to it */
141 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
142 buffers = g_list_remove (buffers, outbuffer);
143 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
144 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
145 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
146 gst_buffer_unref (outbuffer);
148 /* the third buffer is the GDP buffer for our pushed buffer */
149 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
150 buffers = g_list_remove (buffers, outbuffer);
151 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
152 length = GST_DP_HEADER_LENGTH + 4;
153 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
154 gst_buffer_unref (outbuffer);
157 GST_DEBUG ("second buffer");
158 inbuffer = gst_buffer_new_and_alloc (4);
160 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
162 /* pushing gives away my reference */
163 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
165 fail_unless_equals_int (g_list_length (buffers), 1);
166 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
167 buffers = g_list_remove (buffers, outbuffer);
168 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
170 /* the third output buffer is data */
171 length = GST_DP_HEADER_LENGTH + 4;
172 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
173 gst_buffer_unref (outbuffer);
175 /* a third buffer without caps set explicitly; should work */
176 GST_DEBUG ("Creating third buffer, no caps set");
177 inbuffer = gst_buffer_new_and_alloc (4);
179 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
181 /* pushing gives away my reference */
182 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
184 fail_unless_equals_int (g_list_length (buffers), 1);
185 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
186 buffers = g_list_remove (buffers, outbuffer);
187 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
189 /* the fourth output buffer is data */
190 length = GST_DP_HEADER_LENGTH + 4;
191 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
192 gst_buffer_unref (outbuffer);
195 fail_unless (gst_element_set_state (gdppay,
196 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
198 gst_caps_unref (caps);
199 g_free (caps_string);
200 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
201 g_list_free (buffers);
203 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
204 cleanup_gdppay (gdppay);
209 static GstStaticPadTemplate shsrctemplate = GST_STATIC_PAD_TEMPLATE ("src",
212 GST_STATIC_CAPS ("application/x-gst-test-streamheader")
217 setup_gdppay_streamheader (void)
221 GST_DEBUG ("setup_gdppay");
222 gdppay = gst_check_setup_element ("gdppay");
223 myshsrcpad = gst_check_setup_src_pad (gdppay, &shsrctemplate);
224 mysinkpad = gst_check_setup_sink_pad (gdppay, &sinktemplate);
225 gst_pad_set_active (myshsrcpad, TRUE);
226 gst_pad_set_active (mysinkpad, TRUE);
231 /* this test serializes a stream that already has a streamheader of its own.
232 * the streamheader should then be serialized and put on the GDP stream's
234 GST_START_TEST (test_streamheader)
236 GstCaps *caps, *sinkcaps;
238 GstBuffer *inbuffer, *outbuffer, *shbuffer;
243 GstStructure *structure;
244 GValue array = { 0 };
245 GValue value = { 0 };
250 gdppay = setup_gdppay_streamheader ();
252 fail_unless (gst_element_set_state (gdppay,
253 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
254 "could not set to playing");
256 GST_DEBUG ("new segment");
257 gst_segment_init (&segment, GST_FORMAT_TIME);
258 segment.stop = GST_SECOND;
259 event = gst_event_new_segment (&segment);
260 fail_unless (gst_pad_push_event (myshsrcpad, event));
262 /* no buffer should be pushed yet, still waiting for caps */
263 fail_unless_equals_int (g_list_length (buffers), 0);
265 GST_DEBUG ("first buffer");
266 inbuffer = gst_buffer_new_and_alloc (4);
267 gst_buffer_fill (inbuffer, 0, "head", 4);
268 caps = gst_caps_from_string ("application/x-gst-test-streamheader");
269 structure = gst_caps_get_structure (caps, 0);
270 GST_BUFFER_FLAG_SET (inbuffer, GST_BUFFER_FLAG_HEADER);
271 g_value_init (&array, GST_TYPE_ARRAY);
272 g_value_init (&value, GST_TYPE_BUFFER);
273 shbuffer = gst_buffer_copy (inbuffer);
274 gst_value_set_buffer (&value, shbuffer);
275 gst_buffer_unref (shbuffer);
276 gst_value_array_append_value (&array, &value);
277 g_value_unset (&value);
278 gst_structure_set_value (structure, "streamheader", &array);
279 g_value_unset (&array);
280 caps_string = gst_caps_to_string (caps);
282 gst_pad_set_caps (myshsrcpad, caps);
283 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
285 /* pushing gives away my reference */
286 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
288 /* we should have three buffers now */
289 fail_unless_equals_int (g_list_length (buffers), 3);
291 /* our sink pad should now have GDP caps with a streamheader that includes
292 * GDP wrappings of our streamheader */
293 sinkcaps = gst_pad_get_current_caps (mysinkpad);
294 structure = gst_caps_get_structure (sinkcaps, 0);
295 fail_unless_equals_string ((gchar *) gst_structure_get_name (structure),
296 "application/x-gdp");
297 fail_unless (gst_structure_has_field (structure, "streamheader"));
298 sh = gst_structure_get_value (structure, "streamheader");
299 fail_unless (G_VALUE_TYPE (sh) == GST_TYPE_ARRAY);
300 shbuffers = g_value_peek_pointer (sh);
301 /* a serialized new_segment, a serialized caps, and serialization of our
302 * incoming streamheader */
303 fail_unless_equals_int (shbuffers->len, 3);
305 gst_caps_unref (sinkcaps);
307 /* first buffer is the serialized new_segment event;
308 * the element also holds a ref to it */
309 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
310 buffers = g_list_remove (buffers, outbuffer);
311 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
312 gst_buffer_unref (outbuffer);
314 /* second buffer is the serialized caps;
315 * the element also holds a ref to it */
316 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
317 buffers = g_list_remove (buffers, outbuffer);
318 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
319 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
320 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
321 gst_buffer_unref (outbuffer);
323 /* the third buffer is the GDP buffer for our pushed buffer */
324 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
325 buffers = g_list_remove (buffers, outbuffer);
326 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
327 length = GST_DP_HEADER_LENGTH + 4;
328 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
329 gst_buffer_unref (outbuffer);
332 GST_DEBUG ("second buffer");
333 inbuffer = gst_buffer_new_and_alloc (4);
335 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
337 /* pushing gives away my reference */
338 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
340 fail_unless_equals_int (g_list_length (buffers), 1);
341 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
342 buffers = g_list_remove (buffers, outbuffer);
343 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
345 /* the third output buffer is data */
346 length = GST_DP_HEADER_LENGTH + 4;
347 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
348 gst_buffer_unref (outbuffer);
350 /* a third buffer without caps set explicitly; should work */
351 GST_DEBUG ("Creating third buffer, no caps set");
352 inbuffer = gst_buffer_new_and_alloc (4);
354 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
356 /* pushing gives away my reference */
357 fail_unless (gst_pad_push (myshsrcpad, inbuffer) == GST_FLOW_OK);
359 fail_unless_equals_int (g_list_length (buffers), 1);
360 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
361 buffers = g_list_remove (buffers, outbuffer);
362 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
364 /* the fourth output buffer is data */
365 length = GST_DP_HEADER_LENGTH + 4;
366 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
367 gst_buffer_unref (outbuffer);
370 fail_unless (gst_element_set_state (gdppay,
371 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
373 gst_caps_unref (caps);
374 g_free (caps_string);
375 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
376 g_list_free (buffers);
378 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
379 cleanup_gdppay (gdppay);
385 GST_START_TEST (test_first_no_caps)
390 gdppay = setup_gdppay ();
392 fail_unless (gst_element_set_state (gdppay,
393 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
394 "could not set to playing");
396 GST_DEBUG ("first buffer");
397 inbuffer = gst_buffer_new_and_alloc (4);
398 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
400 /* pushing should trigger an error */
401 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_NOT_NEGOTIATED);
403 fail_unless_equals_int (g_list_length (buffers), 0);
405 fail_unless (gst_element_set_state (gdppay,
406 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
408 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
409 g_list_free (buffers);
411 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
412 cleanup_gdppay (gdppay);
417 /* element should still work if no new_segment is sent before the first
419 GST_START_TEST (test_first_no_new_segment)
425 gdppay = setup_gdppay ();
427 fail_unless (gst_element_set_state (gdppay,
428 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
429 "could not set to playing");
431 GST_DEBUG ("first buffer");
432 inbuffer = gst_buffer_new_and_alloc (4);
433 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
434 gst_pad_set_caps (mysrcpad, caps);
435 gst_caps_unref (caps);
437 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
439 /* pushing gives away my reference */
440 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
442 /* we should have three buffers now;
443 * one for an "invented" new segment, one for GDP caps, and one with our
445 fail_unless_equals_int (g_list_length (buffers), 3);
447 fail_unless (gst_element_set_state (gdppay,
448 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
450 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
451 g_list_free (buffers);
453 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
454 cleanup_gdppay (gdppay);
459 GST_START_TEST (test_crc)
463 GstBuffer *inbuffer, *outbuffer;
469 guint16 crc_calculated, crc_read;
471 gdppay = setup_gdppay ();
472 g_object_set (gdppay, "crc-header", TRUE, NULL);
474 fail_unless (gst_element_set_state (gdppay,
475 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
476 "could not set to playing");
478 GST_DEBUG ("new segment");
479 gst_segment_init (&segment, GST_FORMAT_TIME);
480 event = gst_event_new_segment (&segment);
481 fail_unless (gst_pad_push_event (mysrcpad, event));
483 /* no buffer should be pushed yet, waiting for caps */
484 fail_unless_equals_int (g_list_length (buffers), 0);
486 GST_DEBUG ("first buffer");
487 inbuffer = gst_buffer_new_and_alloc (4);
488 caps = gst_caps_from_string (AUDIO_CAPS_STRING);
489 gst_pad_set_caps (mysrcpad, caps);
490 caps_string = gst_caps_to_string (caps);
492 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
494 /* pushing gives away my reference */
495 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
497 /* we should have three buffers now */
498 fail_unless_equals_int (g_list_length (buffers), 3);
500 /* first buffer is the serialized new_segment event;
501 * the element also holds a ref to it */
502 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
503 buffers = g_list_remove (buffers, outbuffer);
504 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
506 /* verify the header checksum */
507 /* CRC's start at 58 in the header */
508 outbuffer = gst_buffer_make_writable (outbuffer);
509 gst_buffer_map (outbuffer, &map, GST_MAP_READWRITE);
510 crc_calculated = gst_dp_crc (map.data, 58);
511 crc_read = GST_READ_UINT16_BE (map.data + 58);
512 fail_unless_equals_int (crc_calculated, crc_read);
514 /* change a byte in the header and verify that the checksum now fails */
516 crc_calculated = gst_dp_crc (map.data, 58);
517 fail_if (crc_calculated == crc_read,
518 "Introducing a byte error in the header should make the checksum fail");
520 gst_buffer_unmap (outbuffer, &map);
521 gst_buffer_unref (outbuffer);
523 /* second buffer is the serialized caps;
524 * the element also holds a ref to it */
525 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
526 buffers = g_list_remove (buffers, outbuffer);
527 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
528 length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
529 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
530 gst_buffer_unref (outbuffer);
532 /* the third buffer is the GDP buffer for our pushed buffer */
533 fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
534 buffers = g_list_remove (buffers, outbuffer);
535 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
536 length = GST_DP_HEADER_LENGTH + 4;
537 fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
538 gst_buffer_unref (outbuffer);
540 fail_unless (gst_element_set_state (gdppay,
541 GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
543 gst_caps_unref (caps);
544 g_free (caps_string);
545 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
546 g_list_free (buffers);
548 ASSERT_OBJECT_REFCOUNT (gdppay, "gdppay", 1);
549 cleanup_gdppay (gdppay);
558 Suite *s = suite_create ("gdppay");
559 TCase *tc_chain = tcase_create ("general");
561 suite_add_tcase (s, tc_chain);
562 tcase_add_test (tc_chain, test_audio);
563 tcase_add_test (tc_chain, test_first_no_caps);
564 tcase_add_test (tc_chain, test_first_no_new_segment);
565 tcase_add_test (tc_chain, test_streamheader);
566 tcase_add_test (tc_chain, test_crc);
571 GST_CHECK_MAIN (gdppay);