1 /* GStreamer
2  *
3  * unit test for spectrum
4  *
5  * Copyright (C) <2007> Stefan Kost <ensonic@users.sf.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include <gst/audio/audio.h>
24 #include <gst/check/gstcheck.h>
25 
26 gboolean have_eos = FALSE;
27 
28 /* For ease of programming we use globals to keep refs for our floating
29  * src and sink pads we create; otherwise we always have to do get_pad,
30  * get_peer, and then remove references in every test function */
31 GstPad *mysrcpad, *mysinkpad;
32 
33 #define SPECT_CAPS_TEMPLATE_STRING \
34     "audio/x-raw, "                                                   \
35     " rate = (int) [ 1, MAX ], "                                      \
36     " channels = (int) [ 1, MAX ], "                                  \
37     " layout = (string) interleaved, "                                \
38     " format = (string) { "                                           \
39     GST_AUDIO_NE(S16) ", "                                            \
40     GST_AUDIO_NE(S32) ", "                                            \
41     GST_AUDIO_NE(F32) ", "                                            \
42     GST_AUDIO_NE(F64) " }"
43 
44 #define SPECT_CAPS_STRING_S16 \
45   "audio/x-raw, " \
46     "rate = (int) 44100, " \
47     "channels = (int) 1, " \
48     "layout = (string) interleaved, " \
49     "format = (string) " GST_AUDIO_NE(S16)
50 
51 #define SPECT_CAPS_STRING_S32 \
52   "audio/x-raw, " \
53     "rate = (int) 44100, " \
54     "channels = (int) 1, " \
55     "layout = (string) interleaved, " \
56     "format = (string) " GST_AUDIO_NE(S32)
57 
58 #define SPECT_CAPS_STRING_F32 \
59     "audio/x-raw, "                                                   \
60     " rate = (int) 44100, "                                           \
61     " channels = (int) 1, "                                           \
62     " layout = (string) interleaved, " \
63     " format = (string) " GST_AUDIO_NE(F32)
64 
65 #define SPECT_CAPS_STRING_F64 \
66     "audio/x-raw, "                                                   \
67     " rate = (int) 44100, "                                           \
68     " channels = (int) 1, "                                           \
69     " layout = (string) interleaved, " \
70     " format = (string) " GST_AUDIO_NE(F64)
71 
72 #define SPECT_BANDS 256
73 
74 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
75     GST_PAD_SINK,
76     GST_PAD_ALWAYS,
77     GST_STATIC_CAPS (SPECT_CAPS_TEMPLATE_STRING)
78     );
79 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
80     GST_PAD_SRC,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS (SPECT_CAPS_TEMPLATE_STRING)
83     );
84 
85 /* takes over reference for outcaps */
86 static GstElement *
setup_spectrum(const gchar * caps_str)87 setup_spectrum (const gchar * caps_str)
88 {
89   GstElement *spectrum;
90   GstCaps *caps;
91 
92   GST_DEBUG ("setup_spectrum");
93   spectrum = gst_check_setup_element ("spectrum");
94   mysrcpad = gst_check_setup_src_pad (spectrum, &srctemplate);
95   mysinkpad = gst_check_setup_sink_pad (spectrum, &sinktemplate);
96   gst_pad_set_active (mysrcpad, TRUE);
97   gst_pad_set_active (mysinkpad, TRUE);
98 
99   caps = gst_caps_from_string (caps_str);
100   gst_check_setup_events (mysrcpad, spectrum, caps, GST_FORMAT_TIME);
101   gst_caps_unref (caps);
102 
103   return spectrum;
104 }
105 
106 static void
cleanup_spectrum(GstElement * spectrum)107 cleanup_spectrum (GstElement * spectrum)
108 {
109   GST_DEBUG ("cleanup_spectrum");
110 
111   gst_pad_set_active (mysrcpad, FALSE);
112   gst_pad_set_active (mysinkpad, FALSE);
113   gst_check_teardown_src_pad (spectrum);
114   gst_check_teardown_sink_pad (spectrum);
115   gst_check_teardown_element (spectrum);
116 
117   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
118   g_list_free (buffers);
119   buffers = NULL;
120 }
121 
122 
GST_START_TEST(test_int16)123 GST_START_TEST (test_int16)
124 {
125   GstElement *spectrum;
126   GstBuffer *inbuffer, *outbuffer;
127   GstBus *bus;
128   GstMessage *message;
129   const GstStructure *structure;
130   int i, j;
131   gint16 *data;
132   GstMapInfo map;
133   const GValue *list, *value;
134   GstClockTime endtime;
135   gfloat level;
136 
137   spectrum = setup_spectrum (SPECT_CAPS_STRING_S16);
138   g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
139       "bands", SPECT_BANDS, "threshold", -80, NULL);
140 
141   fail_unless (gst_element_set_state (spectrum,
142           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
143       "could not set to playing");
144 
145   /* create a 1 sec buffer with an 11025 Hz sine wave */
146   inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gint16), 0);
147   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
148   data = (gint16 *) map.data;
149   for (j = 0; j < 44100; j += 4) {
150     *data = 0;
151     ++data;
152     *data = 32767;
153     ++data;
154     *data = 0;
155     ++data;
156     *data = -32767;
157     ++data;
158   }
159   gst_buffer_unmap (inbuffer, &map);
160   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
161 
162   /* create a bus to get the spectrum message on */
163   bus = gst_bus_new ();
164   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
165   gst_element_set_bus (spectrum, bus);
166   ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
167 
168   /* pushing gives away my reference ... */
169   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
170   /* ... but it ends up being collected on the global buffer list */
171   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
172   fail_unless_equals_int (g_list_length (buffers), 1);
173   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
174   fail_unless (inbuffer == outbuffer);
175 
176   message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
177   ASSERT_OBJECT_REFCOUNT (message, "message", 1);
178 
179   fail_unless (message != NULL);
180   fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
181   fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
182   structure = gst_message_get_structure (message);
183   fail_if (structure == NULL);
184   fail_unless_equals_string ((char *) gst_structure_get_name (structure),
185       "spectrum");
186   fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
187 
188   list = gst_structure_get_value (structure, "magnitude");
189   for (i = 0; i < SPECT_BANDS; ++i) {
190     value = gst_value_list_get_value (list, i);
191     level = g_value_get_float (value);
192     GST_DEBUG ("band[%3d] is %.2f", i, level);
193     /* Only the bands in the middle should have a level above 60 */
194     fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
195         && level < -20.0);
196     fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
197         && level > -20.0);
198   }
199   fail_unless_equals_int (g_list_length (buffers), 1);
200   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
201   fail_unless (inbuffer == outbuffer);
202 
203   /* clean up */
204   /* flush current messages,and future state change messages */
205   gst_bus_set_flushing (bus, TRUE);
206 
207   /* message has a ref to the element */
208   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
209   gst_message_unref (message);
210   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
211 
212   gst_element_set_bus (spectrum, NULL);
213   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
214   gst_object_unref (bus);
215   fail_unless (gst_element_set_state (spectrum,
216           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
217   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
218   cleanup_spectrum (spectrum);
219 }
220 
221 GST_END_TEST;
222 
GST_START_TEST(test_int32)223 GST_START_TEST (test_int32)
224 {
225   GstElement *spectrum;
226   GstBuffer *inbuffer, *outbuffer;
227   GstBus *bus;
228   GstMessage *message;
229   const GstStructure *structure;
230   int i, j;
231   gint32 *data;
232   GstMapInfo map;
233   const GValue *list, *value;
234   GstClockTime endtime;
235   gfloat level;
236 
237   spectrum = setup_spectrum (SPECT_CAPS_STRING_S32);
238   g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
239       "bands", SPECT_BANDS, "threshold", -80, NULL);
240 
241   fail_unless (gst_element_set_state (spectrum,
242           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
243       "could not set to playing");
244 
245   /* create a 1 sec buffer with an 11025 Hz sine wave */
246   inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gint32), 0);
247   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
248   data = (gint32 *) map.data;
249   for (j = 0; j < 44100; j += 4) {
250     *data = 0;
251     ++data;
252     *data = 2147483647;
253     ++data;
254     *data = 0;
255     ++data;
256     *data = -2147483647;
257     ++data;
258   }
259   gst_buffer_unmap (inbuffer, &map);
260   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
261 
262   /* create a bus to get the spectrum message on */
263   bus = gst_bus_new ();
264   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
265   gst_element_set_bus (spectrum, bus);
266   ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
267 
268   /* pushing gives away my reference ... */
269   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
270   /* ... but it ends up being collected on the global buffer list */
271   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
272   fail_unless_equals_int (g_list_length (buffers), 1);
273   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
274   fail_unless (inbuffer == outbuffer);
275 
276   message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
277   ASSERT_OBJECT_REFCOUNT (message, "message", 1);
278 
279   fail_unless (message != NULL);
280   fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
281   fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
282   structure = gst_message_get_structure (message);
283   fail_if (structure == NULL);
284   fail_unless_equals_string ((char *) gst_structure_get_name (structure),
285       "spectrum");
286   fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
287 
288   list = gst_structure_get_value (structure, "magnitude");
289   for (i = 0; i < SPECT_BANDS; ++i) {
290     value = gst_value_list_get_value (list, i);
291     level = g_value_get_float (value);
292     GST_DEBUG ("band[%3d] is %.2f", i, level);
293     /* Only the bands in the middle should have a level above 60 */
294     fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
295         && level < -20.0);
296     fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
297         && level > -20.0);
298   }
299   fail_unless_equals_int (g_list_length (buffers), 1);
300   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
301   fail_unless (inbuffer == outbuffer);
302 
303   /* clean up */
304   /* flush current messages,and future state change messages */
305   gst_bus_set_flushing (bus, TRUE);
306 
307   /* message has a ref to the element */
308   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
309   gst_message_unref (message);
310   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
311 
312   gst_element_set_bus (spectrum, NULL);
313   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
314   gst_object_unref (bus);
315   fail_unless (gst_element_set_state (spectrum,
316           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
317   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
318   cleanup_spectrum (spectrum);
319 }
320 
321 GST_END_TEST;
322 
GST_START_TEST(test_float32)323 GST_START_TEST (test_float32)
324 {
325   GstElement *spectrum;
326   GstBuffer *inbuffer, *outbuffer;
327   GstBus *bus;
328   GstMessage *message;
329   const GstStructure *structure;
330   int i, j;
331   gfloat *data;
332   GstMapInfo map;
333   const GValue *list, *value;
334   GstClockTime endtime;
335   gfloat level;
336 
337   spectrum = setup_spectrum (SPECT_CAPS_STRING_F32);
338   g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
339       "bands", SPECT_BANDS, "threshold", -80, NULL);
340 
341   fail_unless (gst_element_set_state (spectrum,
342           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
343       "could not set to playing");
344 
345   /* create a 1 sec buffer with an 11025 Hz sine wave */
346   inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gfloat), 0);
347   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
348   data = (gfloat *) map.data;
349   for (j = 0; j < 44100; j += 4) {
350     *data = 0.0;
351     ++data;
352     *data = 1.0;
353     ++data;
354     *data = 0.0;
355     ++data;
356     *data = -1.0;
357     ++data;
358   }
359   gst_buffer_unmap (inbuffer, &map);
360   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
361 
362   /* create a bus to get the spectrum message on */
363   bus = gst_bus_new ();
364   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
365   gst_element_set_bus (spectrum, bus);
366   ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
367 
368   /* pushing gives away my reference ... */
369   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
370   /* ... but it ends up being collected on the global buffer list */
371   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
372   fail_unless_equals_int (g_list_length (buffers), 1);
373   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
374   fail_unless (inbuffer == outbuffer);
375 
376   message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
377   ASSERT_OBJECT_REFCOUNT (message, "message", 1);
378 
379   fail_unless (message != NULL);
380   fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
381   fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
382   structure = gst_message_get_structure (message);
383   fail_if (structure == NULL);
384   fail_unless_equals_string ((char *) gst_structure_get_name (structure),
385       "spectrum");
386   fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
387 
388   list = gst_structure_get_value (structure, "magnitude");
389   for (i = 0; i < SPECT_BANDS; ++i) {
390     value = gst_value_list_get_value (list, i);
391     level = g_value_get_float (value);
392     GST_DEBUG ("band[%3d] is %.2f", i, level);
393     /* Only the bands in the middle should have a level above 60 */
394     fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
395         && level < -20.0);
396     fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
397         && level > -20.0);
398   }
399   fail_unless_equals_int (g_list_length (buffers), 1);
400   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
401   fail_unless (inbuffer == outbuffer);
402 
403   /* clean up */
404   /* flush current messages,and future state change messages */
405   gst_bus_set_flushing (bus, TRUE);
406 
407   /* message has a ref to the element */
408   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
409   gst_message_unref (message);
410   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
411 
412   gst_element_set_bus (spectrum, NULL);
413   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
414   gst_object_unref (bus);
415   fail_unless (gst_element_set_state (spectrum,
416           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
417   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
418   cleanup_spectrum (spectrum);
419 }
420 
421 GST_END_TEST;
422 
GST_START_TEST(test_float64)423 GST_START_TEST (test_float64)
424 {
425   GstElement *spectrum;
426   GstBuffer *inbuffer, *outbuffer;
427   GstBus *bus;
428   GstMessage *message;
429   const GstStructure *structure;
430   int i, j;
431   gdouble *data;
432   GstMapInfo map;
433   const GValue *list, *value;
434   GstClockTime endtime;
435   gfloat level;
436 
437   spectrum = setup_spectrum (SPECT_CAPS_STRING_F64);
438   g_object_set (spectrum, "post-messages", TRUE, "interval", GST_SECOND / 100,
439       "bands", SPECT_BANDS, "threshold", -80, NULL);
440 
441   fail_unless (gst_element_set_state (spectrum,
442           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
443       "could not set to playing");
444 
445   /* create a 1 sec buffer with an 11025 Hz sine wave */
446   inbuffer = gst_buffer_new_allocate (NULL, 44100 * sizeof (gdouble), 0);
447   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
448   data = (gdouble *) map.data;
449   for (j = 0; j < 44100; j += 4) {
450     *data = 0.0;
451     ++data;
452     *data = 1.0;
453     ++data;
454     *data = 0.0;
455     ++data;
456     *data = -1.0;
457     ++data;
458   }
459   gst_buffer_unmap (inbuffer, &map);
460   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
461 
462   /* create a bus to get the spectrum message on */
463   bus = gst_bus_new ();
464   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
465   gst_element_set_bus (spectrum, bus);
466   ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
467 
468   /* pushing gives away my reference ... */
469   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
470   /* ... but it ends up being collected on the global buffer list */
471   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
472   fail_unless_equals_int (g_list_length (buffers), 1);
473   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
474   fail_unless (inbuffer == outbuffer);
475 
476   message = gst_bus_poll (bus, GST_MESSAGE_ELEMENT, -1);
477   ASSERT_OBJECT_REFCOUNT (message, "message", 1);
478 
479   fail_unless (message != NULL);
480   fail_unless (GST_MESSAGE_SRC (message) == GST_OBJECT (spectrum));
481   fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT);
482   structure = gst_message_get_structure (message);
483   fail_if (structure == NULL);
484   fail_unless_equals_string ((char *) gst_structure_get_name (structure),
485       "spectrum");
486   fail_unless (gst_structure_get_clock_time (structure, "endtime", &endtime));
487 
488   list = gst_structure_get_value (structure, "magnitude");
489   for (i = 0; i < SPECT_BANDS; ++i) {
490     value = gst_value_list_get_value (list, i);
491     level = g_value_get_float (value);
492     GST_DEBUG ("band[%3d] is %.2f", i, level);
493     /* Only the bands in the middle should have a level above 60 */
494     fail_if ((i == SPECT_BANDS / 2 || i == SPECT_BANDS / 2 - 1)
495         && level < -20.0);
496     fail_if ((i != SPECT_BANDS / 2 && i != SPECT_BANDS / 2 - 1)
497         && level > -20.0);
498   }
499   fail_unless_equals_int (g_list_length (buffers), 1);
500   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
501   fail_unless (inbuffer == outbuffer);
502 
503   /* clean up */
504   /* flush current messages,and future state change messages */
505   gst_bus_set_flushing (bus, TRUE);
506 
507   /* message has a ref to the element */
508   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 2);
509   gst_message_unref (message);
510   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
511 
512   gst_element_set_bus (spectrum, NULL);
513   ASSERT_OBJECT_REFCOUNT (bus, "bus", 1);
514   gst_object_unref (bus);
515   fail_unless (gst_element_set_state (spectrum,
516           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
517   ASSERT_OBJECT_REFCOUNT (spectrum, "spectrum", 1);
518   cleanup_spectrum (spectrum);
519 }
520 
521 GST_END_TEST;
522 
523 
524 static Suite *
spectrum_suite(void)525 spectrum_suite (void)
526 {
527   Suite *s = suite_create ("spectrum");
528   TCase *tc_chain = tcase_create ("general");
529 
530   suite_add_tcase (s, tc_chain);
531   tcase_add_test (tc_chain, test_int16);
532   tcase_add_test (tc_chain, test_int32);
533   tcase_add_test (tc_chain, test_float32);
534   tcase_add_test (tc_chain, test_float64);
535 
536   return s;
537 }
538 
539 GST_CHECK_MAIN (spectrum);
540