1 /* GStreamer unit tests for the interleave element
2  * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <gst/audio/audio.h>
26 #include <gst/check/gstcheck.h>
27 #include <gst/audio/audio.h>
28 
GST_START_TEST(test_create_and_unref)29 GST_START_TEST (test_create_and_unref)
30 {
31   GstElement *deinterleave;
32 
33   deinterleave = gst_element_factory_make ("deinterleave", NULL);
34   fail_unless (deinterleave != NULL);
35 
36   gst_element_set_state (deinterleave, GST_STATE_NULL);
37   gst_object_unref (deinterleave);
38 }
39 
40 GST_END_TEST;
41 
42 static GstPad *mysrcpad, **mysinkpads;
43 static gint nsinkpads;
44 static GstBus *bus;
45 static GstElement *deinterleave;
46 
47 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
48     GST_PAD_SINK,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS ("audio/x-raw, "
51         "format = (string) " GST_AUDIO_NE (F32) ", "
52         "channels = (int) 1, layout = (string) {interleaved, non-interleaved}, rate = (int) {32000, 48000}"));
53 
54 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
55     GST_PAD_SRC,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("audio/x-raw, "
58         "format = (string) " GST_AUDIO_NE (F32) ", "
59         "channels = (int) { 2, 3 }, layout = (string) interleaved, rate = (int) {32000, 48000}"));
60 
61 #define CAPS_32khz \
62         "audio/x-raw, " \
63         "format = (string) "GST_AUDIO_NE (F32) ", " \
64         "channels = (int) 2, layout = (string) interleaved, " \
65         "rate = (int) 32000"
66 
67 #define CAPS_48khz \
68         "audio/x-raw, " \
69         "format = (string) "GST_AUDIO_NE (F32) ", " \
70         "channels = (int) 2, layout = (string) interleaved, " \
71         "rate = (int) 48000"
72 
73 #define CAPS_48khz_3CH \
74         "audio/x-raw, " \
75         "format = (string) "GST_AUDIO_NE (F32) ", " \
76         "channels = (int) 3, layout = (string) interleaved, " \
77         "rate = (int) 48000"
78 
79 static GstFlowReturn
deinterleave_chain_func(GstPad * pad,GstObject * parent,GstBuffer * buffer)80 deinterleave_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer)
81 {
82   gint i;
83   GstMapInfo map;
84   gfloat *indata;
85 
86   fail_unless (GST_IS_BUFFER (buffer));
87   gst_buffer_map (buffer, &map, GST_MAP_READ);
88   indata = (gfloat *) map.data;
89   fail_unless_equals_int (map.size, 48000 * sizeof (gfloat));
90   fail_unless (indata != NULL);
91 
92   if (strcmp (GST_PAD_NAME (pad), "sink0") == 0) {
93     for (i = 0; i < 48000; i++)
94       fail_unless_equals_float (indata[i], -1.0);
95   } else if (strcmp (GST_PAD_NAME (pad), "sink1") == 0) {
96     for (i = 0; i < 48000; i++)
97       fail_unless_equals_float (indata[i], 1.0);
98   } else {
99     g_assert_not_reached ();
100   }
101   gst_buffer_unmap (buffer, &map);
102   gst_buffer_unref (buffer);
103 
104   return GST_FLOW_OK;
105 }
106 
107 static void
deinterleave_pad_added(GstElement * src,GstPad * pad,gpointer data)108 deinterleave_pad_added (GstElement * src, GstPad * pad, gpointer data)
109 {
110   gchar *name;
111   gint link = GPOINTER_TO_INT (data);
112 
113   if (nsinkpads >= link)
114     return;
115 
116   name = g_strdup_printf ("sink%d", nsinkpads);
117 
118   mysinkpads[nsinkpads] =
119       gst_pad_new_from_static_template (&sinktemplate, name);
120   g_free (name);
121   fail_if (mysinkpads[nsinkpads] == NULL);
122 
123   gst_pad_set_chain_function (mysinkpads[nsinkpads], deinterleave_chain_func);
124   fail_unless (gst_pad_link (pad, mysinkpads[nsinkpads]) == GST_PAD_LINK_OK);
125   gst_pad_set_active (mysinkpads[nsinkpads], TRUE);
126   nsinkpads++;
127 }
128 
GST_START_TEST(test_2_channels)129 GST_START_TEST (test_2_channels)
130 {
131   GstPad *sinkpad;
132   gint i;
133   GstBuffer *inbuf;
134   GstCaps *caps;
135   gfloat *indata;
136   GstMapInfo map;
137   guint64 channel_mask = 0;
138 
139   mysinkpads = g_new0 (GstPad *, 2);
140   nsinkpads = 0;
141 
142   deinterleave = gst_element_factory_make ("deinterleave", NULL);
143   fail_unless (deinterleave != NULL);
144 
145   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
146   fail_unless (mysrcpad != NULL);
147   gst_pad_set_active (mysrcpad, TRUE);
148 
149   caps = gst_caps_from_string (CAPS_48khz);
150   channel_mask |=
151       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
152   channel_mask |=
153       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
154   gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
155       NULL);
156 
157   gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
158 
159   sinkpad = gst_element_get_static_pad (deinterleave, "sink");
160   fail_unless (sinkpad != NULL);
161   fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
162   g_object_unref (sinkpad);
163 
164   g_signal_connect (deinterleave, "pad-added",
165       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
166 
167   bus = gst_bus_new ();
168   gst_element_set_bus (deinterleave, bus);
169 
170   fail_unless (gst_element_set_state (deinterleave,
171           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
172 
173   inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
174   inbuf = gst_buffer_make_writable (inbuf);
175   gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
176   indata = (gfloat *) map.data;
177   for (i = 0; i < 2 * 48000; i += 2) {
178     indata[i] = -1.0;
179     indata[i + 1] = 1.0;
180   }
181   gst_buffer_unmap (inbuf, &map);
182 
183   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
184 
185   fail_unless (gst_element_set_state (deinterleave,
186           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
187 
188   for (i = 0; i < nsinkpads; i++)
189     g_object_unref (mysinkpads[i]);
190   g_free (mysinkpads);
191   mysinkpads = NULL;
192 
193   g_object_unref (deinterleave);
194   gst_bus_set_flushing (bus, TRUE);
195   g_object_unref (bus);
196   gst_caps_unref (caps);
197   gst_object_unref (mysrcpad);
198 }
199 
200 GST_END_TEST;
201 
GST_START_TEST(test_2_channels_1_linked)202 GST_START_TEST (test_2_channels_1_linked)
203 {
204   GstPad *sinkpad;
205   gint i;
206   GstBuffer *inbuf;
207   GstCaps *caps;
208   gfloat *indata;
209   GstMapInfo map;
210   guint64 channel_mask = 0;
211 
212   nsinkpads = 0;
213   mysinkpads = g_new0 (GstPad *, 2);
214 
215   deinterleave = gst_element_factory_make ("deinterleave", NULL);
216   fail_unless (deinterleave != NULL);
217 
218   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
219   fail_unless (mysrcpad != NULL);
220   gst_pad_set_active (mysrcpad, TRUE);
221 
222   caps = gst_caps_from_string (CAPS_48khz);
223   channel_mask |=
224       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
225   channel_mask |=
226       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
227   gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
228       NULL);
229 
230   gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
231 
232   sinkpad = gst_element_get_static_pad (deinterleave, "sink");
233   fail_unless (sinkpad != NULL);
234   fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
235   g_object_unref (sinkpad);
236 
237   g_signal_connect (deinterleave, "pad-added",
238       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (1));
239 
240   bus = gst_bus_new ();
241   gst_element_set_bus (deinterleave, bus);
242 
243   fail_unless (gst_element_set_state (deinterleave,
244           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
245 
246   inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
247   inbuf = gst_buffer_make_writable (inbuf);
248   gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
249   indata = (gfloat *) map.data;
250   for (i = 0; i < 2 * 48000; i += 2) {
251     indata[i] = -1.0;
252     indata[i + 1] = 1.0;
253   }
254   gst_buffer_unmap (inbuf, &map);
255 
256   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
257 
258   fail_unless (gst_element_set_state (deinterleave,
259           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
260 
261   for (i = 0; i < nsinkpads; i++)
262     g_object_unref (mysinkpads[i]);
263   g_free (mysinkpads);
264   mysinkpads = NULL;
265 
266   g_object_unref (deinterleave);
267   gst_bus_set_flushing (bus, TRUE);
268   g_object_unref (bus);
269   gst_caps_unref (caps);
270   gst_object_unref (mysrcpad);
271 }
272 
273 GST_END_TEST;
274 
GST_START_TEST(test_2_channels_caps_change)275 GST_START_TEST (test_2_channels_caps_change)
276 {
277   GstPad *sinkpad;
278   GstCaps *caps, *caps2;
279   GstCaps *ret_caps;
280   gint i;
281   GstBuffer *inbuf;
282   gfloat *indata;
283   GstMapInfo map;
284   guint64 channel_mask;
285 
286   nsinkpads = 0;
287   mysinkpads = g_new0 (GstPad *, 2);
288 
289   deinterleave = gst_element_factory_make ("deinterleave", NULL);
290   fail_unless (deinterleave != NULL);
291 
292   mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src");
293   fail_unless (mysrcpad != NULL);
294 
295   gst_pad_set_active (mysrcpad, TRUE);
296 
297   caps = gst_caps_from_string (CAPS_48khz);
298   channel_mask = 0;
299   channel_mask |=
300       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
301   channel_mask |=
302       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
303   gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
304       NULL);
305 
306   sinkpad = gst_element_get_static_pad (deinterleave, "sink");
307   fail_unless (sinkpad != NULL);
308   fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK);
309   g_object_unref (sinkpad);
310 
311   ret_caps = gst_pad_peer_query_caps (mysrcpad, caps);
312   fail_if (gst_caps_is_empty (ret_caps));
313   fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps));
314   gst_caps_unref (ret_caps);
315   gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
316 
317   g_signal_connect (deinterleave, "pad-added",
318       G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2));
319 
320   bus = gst_bus_new ();
321   gst_element_set_bus (deinterleave, bus);
322 
323   fail_unless (gst_element_set_state (deinterleave,
324           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
325 
326   inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
327   inbuf = gst_buffer_make_writable (inbuf);
328   gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
329   indata = (gfloat *) map.data;
330   for (i = 0; i < 2 * 48000; i += 2) {
331     indata[i] = -1.0;
332     indata[i + 1] = 1.0;
333   }
334   gst_buffer_unmap (inbuf, &map);
335 
336   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
337 
338   caps2 = gst_caps_from_string (CAPS_32khz);
339   channel_mask = 0;
340   channel_mask |=
341       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
342   channel_mask |=
343       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
344   gst_caps_set_simple (caps2, "channel-mask", GST_TYPE_BITMASK, channel_mask,
345       NULL);
346   ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
347   fail_if (gst_caps_is_empty (ret_caps));
348   fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
349   gst_caps_unref (ret_caps);
350   gst_pad_set_caps (mysrcpad, caps2);
351 
352   inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat));
353   inbuf = gst_buffer_make_writable (inbuf);
354   gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
355   indata = (gfloat *) map.data;
356   for (i = 0; i < 2 * 48000; i += 2) {
357     indata[i] = -1.0;
358     indata[i + 1] = 1.0;
359   }
360   gst_buffer_unmap (inbuf, &map);
361 
362   /* Should work fine because the caps changed in a compatible way */
363   fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
364 
365   gst_caps_unref (caps2);
366 
367   caps2 = gst_caps_from_string (CAPS_48khz_3CH);
368   channel_mask = 0;
369   channel_mask |=
370       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
371   channel_mask |=
372       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
373   channel_mask |=
374       G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
375   gst_caps_set_simple (caps2, "channel-mask", GST_TYPE_BITMASK, channel_mask,
376       NULL);
377   ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
378   fail_unless (gst_caps_is_empty (ret_caps));
379   gst_caps_unref (ret_caps);
380   fail_if (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
381   gst_pad_set_caps (mysrcpad, caps2);
382 
383   inbuf = gst_buffer_new_and_alloc (3 * 48000 * sizeof (gfloat));
384   inbuf = gst_buffer_make_writable (inbuf);
385   gst_buffer_map (inbuf, &map, GST_MAP_WRITE);
386   indata = (gfloat *) map.data;
387   for (i = 0; i < 3 * 48000; i += 3) {
388     indata[i] = -1.0;
389     indata[i + 1] = 1.0;
390     indata[i + 2] = 0.0;
391   }
392   gst_buffer_unmap (inbuf, &map);
393 
394   /* Should break because the caps changed in an incompatible way */
395   fail_if (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
396 
397   fail_unless (gst_element_set_state (deinterleave,
398           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
399 
400   for (i = 0; i < nsinkpads; i++)
401     g_object_unref (mysinkpads[i]);
402   g_free (mysinkpads);
403   mysinkpads = NULL;
404 
405   g_object_unref (deinterleave);
406   gst_bus_set_flushing (bus, TRUE);
407   g_object_unref (bus);
408   gst_caps_unref (caps);
409   gst_caps_unref (caps2);
410   gst_object_unref (mysrcpad);
411 }
412 
413 GST_END_TEST;
414 
415 
416 #define SAMPLES_PER_BUFFER  10
417 #define NUM_CHANNELS        8
418 #define SAMPLE_RATE         44100
419 
420 static guint pads_created;
421 
422 static void
set_channel_positions(GstCaps * caps,int channels,GstAudioChannelPosition * channelpositions)423 set_channel_positions (GstCaps * caps, int channels,
424     GstAudioChannelPosition * channelpositions)
425 {
426   int c;
427   guint64 channel_mask = 0;
428 
429   for (c = 0; c < channels; c++)
430     channel_mask |= G_GUINT64_CONSTANT (1) << channelpositions[c];
431 
432   gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
433       NULL);
434 }
435 
436 static void
src_handoff_float32_8ch(GstElement * src,GstBuffer * buf,GstPad * pad,gpointer user_data)437 src_handoff_float32_8ch (GstElement * src, GstBuffer * buf, GstPad * pad,
438     gpointer user_data)
439 {
440   gfloat *data, *p;
441   guint size, i, c;
442 
443   size = sizeof (gfloat) * SAMPLES_PER_BUFFER * NUM_CHANNELS;
444   data = p = (gfloat *) g_malloc (size);
445 
446   for (i = 0; i < SAMPLES_PER_BUFFER; ++i) {
447     for (c = 0; c < NUM_CHANNELS; ++c) {
448       *p = (gfloat) ((i * NUM_CHANNELS) + c);
449       ++p;
450     }
451   }
452 
453   if (gst_buffer_n_memory (buf)) {
454     gst_buffer_replace_memory_range (buf, 0, -1,
455         gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
456   } else {
457     gst_buffer_insert_memory (buf, 0,
458         gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
459   }
460   GST_BUFFER_OFFSET (buf) = 0;
461   GST_BUFFER_TIMESTAMP (buf) = 0;
462 }
463 
464 static GstPadProbeReturn
src_event_probe(GstPad * pad,GstPadProbeInfo * info,gpointer userdata)465 src_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer userdata)
466 {
467   GstAudioChannelPosition layout[NUM_CHANNELS];
468   GstCaps *caps;
469   guint i;
470 
471   if ((info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
472       && GST_EVENT_TYPE (info->data) == GST_EVENT_STREAM_START) {
473     gst_pad_remove_probe (pad, info->id);
474 
475     caps = gst_caps_new_simple ("audio/x-raw",
476         "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
477         "channels", G_TYPE_INT, NUM_CHANNELS,
478         "layout", G_TYPE_STRING, "interleaved",
479         "rate", G_TYPE_INT, SAMPLE_RATE, NULL);
480 
481     for (i = 0; i < NUM_CHANNELS; ++i)
482       layout[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT + i;
483 
484     set_channel_positions (caps, NUM_CHANNELS, layout);
485     gst_pad_set_caps (pad, caps);
486     gst_caps_unref (caps);
487   }
488 
489   return GST_PAD_PROBE_OK;
490 }
491 
492 static GstPadProbeReturn
float_buffer_check_probe(GstPad * pad,GstPadProbeInfo * info,gpointer userdata)493 float_buffer_check_probe (GstPad * pad, GstPadProbeInfo * info,
494     gpointer userdata)
495 {
496   GstMapInfo map;
497   gfloat *data;
498   guint padnum, numpads;
499   guint num, i;
500   GstCaps *caps;
501   GstStructure *s;
502   GstAudioChannelPosition *pos;
503   gint channels;
504   GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
505   GstAudioInfo audio_info;
506   guint pad_id = GPOINTER_TO_UINT (userdata);
507 
508   fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src_%u", &padnum), 1);
509 
510   numpads = pads_created;
511 
512   /* Check caps */
513   caps = gst_pad_get_current_caps (pad);
514   fail_unless (caps != NULL);
515   s = gst_caps_get_structure (caps, 0);
516   fail_unless (gst_structure_get_int (s, "channels", &channels));
517   fail_unless_equals_int (channels, 1);
518 
519   gst_audio_info_init (&audio_info);
520   fail_unless (gst_audio_info_from_caps (&audio_info, caps));
521 
522   pos = audio_info.position;
523   fail_unless (pos != NULL
524       && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT + pad_id);
525   gst_caps_unref (caps);
526 
527   gst_buffer_map (buffer, &map, GST_MAP_READ);
528   data = (gfloat *) map.data;
529   num = map.size / sizeof (gfloat);
530 
531   /* Check buffer content */
532   for (i = 0; i < num; ++i) {
533     guint val, rest;
534 
535     val = (guint) data[i];
536     GST_LOG ("%s[%u]: %8f", GST_PAD_NAME (pad), i, data[i]);
537     /* can't use the modulo operator in the assertion statement, since due to
538      * the way it gets expanded it would be interpreted as a printf operator
539      * in the failure case, which will result in segfaults */
540     rest = val % numpads;
541     /* check that the first channel is on pad src0, the second on src1 etc. */
542     fail_unless_equals_int (rest, padnum);
543   }
544   gst_buffer_unmap (buffer, &map);
545 
546   return GST_PAD_PROBE_OK;      /* don't drop data */
547 }
548 
549 static void
pad_added_setup_data_check_float32_8ch_cb(GstElement * deinterleave,GstPad * pad,GstElement * pipeline)550 pad_added_setup_data_check_float32_8ch_cb (GstElement * deinterleave,
551     GstPad * pad, GstElement * pipeline)
552 {
553   GstElement *queue, *sink;
554   GstPad *sinkpad;
555 
556   queue = gst_element_factory_make ("queue", NULL);
557   fail_unless (queue != NULL);
558 
559   sink = gst_element_factory_make ("fakesink", NULL);
560   fail_unless (sink != NULL);
561 
562   gst_bin_add_many (GST_BIN (pipeline), queue, sink, NULL);
563   gst_element_link_pads_full (queue, "src", sink, "sink",
564       GST_PAD_LINK_CHECK_NOTHING);
565 
566   sinkpad = gst_element_get_static_pad (queue, "sink");
567 
568   fail_unless_equals_int (gst_pad_link (pad, sinkpad), GST_PAD_LINK_OK);
569   gst_object_unref (sinkpad);
570 
571   gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, float_buffer_check_probe,
572       GUINT_TO_POINTER (pads_created), NULL);
573 
574   gst_element_set_state (sink, GST_STATE_PLAYING);
575   gst_element_set_state (queue, GST_STATE_PLAYING);
576 
577   GST_LOG ("new pad: %s", GST_PAD_NAME (pad));
578   ++pads_created;
579 }
580 
581 static GstElement *
make_fake_src_8chans_float32(void)582 make_fake_src_8chans_float32 (void)
583 {
584   GstElement *src;
585   GstPad *pad;
586 
587   src = gst_element_factory_make ("fakesrc", "src");
588   fail_unless (src != NULL, "failed to create fakesrc element");
589 
590   g_object_set (src, "num-buffers", 1, NULL);
591   g_object_set (src, "signal-handoffs", TRUE, NULL);
592 
593   g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_float32_8ch), NULL);
594 
595   pad = gst_element_get_static_pad (src, "src");
596   gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, src_event_probe,
597       NULL, NULL);
598   gst_object_unref (pad);
599 
600   return src;
601 }
602 
GST_START_TEST(test_8_channels_float32)603 GST_START_TEST (test_8_channels_float32)
604 {
605   GstElement *pipeline, *src, *deinterleave;
606   GstMessage *msg;
607 
608   pipeline = (GstElement *) gst_pipeline_new ("pipeline");
609   fail_unless (pipeline != NULL, "failed to create pipeline");
610 
611   src = make_fake_src_8chans_float32 ();
612 
613   deinterleave = gst_element_factory_make ("deinterleave", "deinterleave");
614   fail_unless (deinterleave != NULL, "failed to create deinterleave element");
615   g_object_set (deinterleave, "keep-positions", TRUE, NULL);
616 
617   gst_bin_add_many (GST_BIN (pipeline), src, deinterleave, NULL);
618 
619   fail_unless (gst_element_link (src, deinterleave),
620       "failed to link src <=> deinterleave");
621 
622   g_signal_connect (deinterleave, "pad-added",
623       G_CALLBACK (pad_added_setup_data_check_float32_8ch_cb), pipeline);
624 
625   pads_created = 0;
626 
627   gst_element_set_state (pipeline, GST_STATE_PLAYING);
628 
629   msg = gst_bus_poll (GST_ELEMENT_BUS (pipeline), GST_MESSAGE_EOS, -1);
630   gst_message_unref (msg);
631 
632   fail_unless_equals_int (pads_created, NUM_CHANNELS);
633 
634   gst_element_set_state (pipeline, GST_STATE_NULL);
635   gst_object_unref (pipeline);
636 }
637 
638 GST_END_TEST;
639 
640 static Suite *
deinterleave_suite(void)641 deinterleave_suite (void)
642 {
643   Suite *s = suite_create ("deinterleave");
644   TCase *tc_chain = tcase_create ("general");
645 
646   suite_add_tcase (s, tc_chain);
647   tcase_set_timeout (tc_chain, 180);
648   tcase_add_test (tc_chain, test_create_and_unref);
649   tcase_add_test (tc_chain, test_2_channels);
650   tcase_add_test (tc_chain, test_2_channels_1_linked);
651   tcase_add_test (tc_chain, test_2_channels_caps_change);
652   tcase_add_test (tc_chain, test_8_channels_float32);
653 
654   return s;
655 }
656 
657 GST_CHECK_MAIN (deinterleave);
658