1 /* GStreamer
2  *
3  * unit test for volume
4  *
5  * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <gst/base/gstbasetransform.h>
28 #include <gst/check/gstcheck.h>
29 #include <gst/audio/streamvolume.h>
30 #include <gst/controller/gstinterpolationcontrolsource.h>
31 #include <gst/controller/gstdirectcontrolbinding.h>
32 
33 /* For ease of programming we use globals to keep refs for our floating
34  * src and sink pads we create; otherwise we always have to do get_pad,
35  * get_peer, and then remove references in every test function */
36 static GstPad *mysrcpad, *mysinkpad;
37 
38 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
39 #define FORMATS1 "{ S8, S16LE, S24LE, S32LE, F32LE, F64LE }"
40 #define FORMATS2 "S8"
41 #define FORMATS3 "S16LE"
42 #define FORMATS4 "S24LE"
43 #define FORMATS5 "S32LE"
44 #define FORMATS6 "F32LE"
45 #define FORMATS7 "F64LE"
46 #define FORMATS8 "U16LE"
47 #else
48 #define FORMATS1 "{ S8, S16BE, S24BE, S32BE, F32BE, F64BE }"
49 #define FORMATS2 "S8"
50 #define FORMATS3 "S16BE"
51 #define FORMATS4 "S24BE"
52 #define FORMATS5 "S32BE"
53 #define FORMATS6 "F32BE"
54 #define FORMATS7 "F64BE"
55 #define FORMATS8 "U16BE"
56 #endif
57 
58 #define VOLUME_CAPS_TEMPLATE_STRING     \
59     "audio/x-raw, "                     \
60     "format = (string) "FORMATS1", "    \
61     "channels = (int) [ 1, MAX ], "     \
62     "rate = (int) [ 1,  MAX ], "        \
63     "layout = (string) interleaved"
64 
65 #define VOLUME_CAPS_STRING_S8           \
66     "audio/x-raw, "                     \
67     "format = (string) "FORMATS2", "   \
68     "channels = (int) 1, "              \
69     "rate = (int) 44100,"               \
70     "layout = (string) interleaved"
71 
72 #define VOLUME_CAPS_STRING_S16          \
73     "audio/x-raw, "                     \
74     "format = (string) "FORMATS3", "   \
75     "channels = (int) 1, "              \
76     "rate = (int) 44100,"               \
77     "layout = (string) interleaved"
78 
79 #define VOLUME_CAPS_STRING_S24          \
80     "audio/x-raw, "                     \
81     "format = (string) "FORMATS4", "   \
82     "channels = (int) 1, "              \
83     "rate = (int) 44100,"               \
84     "layout = (string) interleaved"
85 
86 #define VOLUME_CAPS_STRING_S32          \
87     "audio/x-raw, "                     \
88     "format = (string) "FORMATS5", "   \
89     "channels = (int) 1, "              \
90     "rate = (int) 44100,"               \
91     "layout = (string) interleaved"
92 
93 #define VOLUME_CAPS_STRING_F32          \
94     "audio/x-raw, "                     \
95     "format = (string) "FORMATS6", "   \
96     "channels = (int) 1, "              \
97     "rate = (int) 44100,"               \
98     "layout = (string) interleaved"
99 
100 #define VOLUME_CAPS_STRING_F64          \
101     "audio/x-raw, "                     \
102     "format = (string) "FORMATS7", "   \
103     "channels = (int) 1, "              \
104     "rate = (int) 44100,"               \
105     "layout = (string) interleaved"
106 
107 #define VOLUME_WRONG_CAPS_STRING        \
108     "audio/x-raw, "                     \
109     "format = (string) "FORMATS8", "   \
110     "channels = (int) 1, "              \
111     "rate = (int) 44100,"               \
112     "layout = (string) interleaved"
113 
114 
115 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
116     GST_PAD_SINK,
117     GST_PAD_ALWAYS,
118     GST_STATIC_CAPS (VOLUME_CAPS_TEMPLATE_STRING)
119     );
120 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
121     GST_PAD_SRC,
122     GST_PAD_ALWAYS,
123     GST_STATIC_CAPS (VOLUME_CAPS_TEMPLATE_STRING)
124     );
125 
126 static GstElement *
setup_volume(void)127 setup_volume (void)
128 {
129   GstElement *volume;
130 
131   GST_DEBUG ("setup_volume");
132   volume = gst_check_setup_element ("volume");
133   mysrcpad = gst_check_setup_src_pad (volume, &srctemplate);
134   mysinkpad = gst_check_setup_sink_pad (volume, &sinktemplate);
135   gst_pad_set_active (mysrcpad, TRUE);
136   gst_pad_set_active (mysinkpad, TRUE);
137 
138   return volume;
139 }
140 
141 static void
cleanup_volume(GstElement * volume)142 cleanup_volume (GstElement * volume)
143 {
144   GST_DEBUG ("cleanup_volume");
145 
146   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
147   g_list_free (buffers);
148   buffers = NULL;
149 
150   gst_pad_set_active (mysrcpad, FALSE);
151   gst_pad_set_active (mysinkpad, FALSE);
152   gst_check_teardown_src_pad (volume);
153   gst_check_teardown_sink_pad (volume);
154   gst_check_teardown_element (volume);
155 }
156 
GST_START_TEST(test_get_set)157 GST_START_TEST (test_get_set)
158 {
159   GstElement *volume = gst_element_factory_make ("volume", NULL);
160   gdouble val;
161 
162   fail_unless (volume != NULL);
163   g_object_get (G_OBJECT (volume), "volume", &val, NULL);
164   fail_unless (val == 1.0);
165   fail_unless (val == gst_stream_volume_get_volume (GST_STREAM_VOLUME (volume),
166           GST_STREAM_VOLUME_FORMAT_LINEAR));
167 
168   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
169   g_object_get (G_OBJECT (volume), "volume", &val, NULL);
170   fail_unless (val == 0.5);
171   fail_unless (val == gst_stream_volume_get_volume (GST_STREAM_VOLUME (volume),
172           GST_STREAM_VOLUME_FORMAT_LINEAR));
173 
174   gst_stream_volume_set_volume (GST_STREAM_VOLUME (volume),
175       GST_STREAM_VOLUME_FORMAT_LINEAR, 1.0);
176   g_object_get (G_OBJECT (volume), "volume", &val, NULL);
177   fail_unless (val == 1.0);
178   fail_unless (val == gst_stream_volume_get_volume (GST_STREAM_VOLUME (volume),
179           GST_STREAM_VOLUME_FORMAT_LINEAR));
180 
181   gst_object_unref (volume);
182 }
183 
184 GST_END_TEST;
185 
GST_START_TEST(test_unity_s8)186 GST_START_TEST (test_unity_s8)
187 {
188   GstElement *volume;
189   GstBuffer *inbuffer, *outbuffer;
190   GstCaps *caps;
191   gint8 in[2] = { 64, -16 };
192   gint8 *res;
193   GstMapInfo map;
194 
195   volume = setup_volume ();
196   fail_unless (gst_element_set_state (volume,
197           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
198       "could not set to playing");
199 
200   inbuffer = gst_buffer_new_and_alloc (2);
201   gst_buffer_fill (inbuffer, 0, in, 2);
202   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
203   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
204   gst_caps_unref (caps);
205   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
206 
207   /* pushing gives away my reference ... */
208   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
209   /* ... but it ends up being collected on the global buffer list */
210   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
211   fail_unless_equals_int (g_list_length (buffers), 1);
212   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
213   fail_unless (inbuffer == outbuffer);
214   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
215   res = (gint8 *) map.data;
216   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in[0], in[1], res[0], res[1]);
217   fail_unless (memcmp (res, in, 2) == 0);
218   gst_buffer_unmap (outbuffer, &map);
219 
220   /* cleanup */
221   cleanup_volume (volume);
222 }
223 
224 GST_END_TEST;
225 
GST_START_TEST(test_half_s8)226 GST_START_TEST (test_half_s8)
227 {
228   GstElement *volume;
229   GstBuffer *inbuffer;
230   GstBuffer *outbuffer;
231   GstCaps *caps;
232   gint8 in[2] = { 64, -16 };
233   gint8 out[2] = { 32, -8 };
234   gint8 *res;
235   GstMapInfo map;
236 
237   volume = setup_volume ();
238   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
239   fail_unless (gst_element_set_state (volume,
240           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
241       "could not set to playing");
242 
243   inbuffer = gst_buffer_new_and_alloc (2);
244   gst_buffer_fill (inbuffer, 0, in, 2);
245   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
246   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
247   gst_caps_unref (caps);
248   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
249   /* FIXME: reffing the inbuffer should make the transformation not be
250    * inplace
251    gst_buffer_ref (inbuffer);
252    */
253 
254   /* pushing gives away my reference ... */
255   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
256   /* ... but it ends up being modified inplace and
257    * collected on the global buffer list */
258   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
259   fail_unless_equals_int (g_list_length (buffers), 1);
260   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
261   fail_unless (inbuffer == outbuffer);
262   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
263   res = (gint8 *) map.data;
264   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], res[0],
265       res[1]);
266   fail_unless (memcmp (res, out, 2) == 0);
267   gst_buffer_unmap (outbuffer, &map);
268 
269   /* cleanup */
270   cleanup_volume (volume);
271 }
272 
273 GST_END_TEST;
274 
GST_START_TEST(test_double_s8)275 GST_START_TEST (test_double_s8)
276 {
277   GstElement *volume;
278   GstBuffer *inbuffer;
279   GstBuffer *outbuffer;
280   GstCaps *caps;
281   gint8 in[2] = { 64, -16 };
282   gint8 out[2] = { 127, -32 };  /* notice the clamped sample */
283   gint8 *res;
284   GstMapInfo map;
285 
286   volume = setup_volume ();
287   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
288   fail_unless (gst_element_set_state (volume,
289           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
290       "could not set to playing");
291 
292   inbuffer = gst_buffer_new_and_alloc (2);
293   gst_buffer_fill (inbuffer, 0, in, 2);
294   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
295   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
296   gst_caps_unref (caps);
297   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
298   /* FIXME: reffing the inbuffer should make the transformation not be
299    * inplace
300    gst_buffer_ref (inbuffer);
301    */
302 
303   /* pushing gives away my reference ... */
304   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
305   /* ... but it ends up being modified inplace and
306    * collected on the global buffer list */
307   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
308   fail_unless_equals_int (g_list_length (buffers), 1);
309   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
310   fail_unless (inbuffer == outbuffer);
311   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
312   res = (gint8 *) map.data;
313   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], res[0],
314       res[1]);
315   fail_unless (memcmp (res, out, 2) == 0);
316   gst_buffer_unmap (outbuffer, &map);
317 
318   /* cleanup */
319   cleanup_volume (volume);
320 }
321 
322 GST_END_TEST;
323 
GST_START_TEST(test_ten_s8)324 GST_START_TEST (test_ten_s8)
325 {
326   GstElement *volume;
327   GstBuffer *inbuffer;
328   GstBuffer *outbuffer;
329   GstCaps *caps;
330   gint8 in[2] = { 64, -10 };
331   gint8 out[2] = { 127, -100 }; /* notice the clamped sample */
332   gint8 *res;
333   GstMapInfo map;
334 
335   volume = setup_volume ();
336   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
337   fail_unless (gst_element_set_state (volume,
338           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
339       "could not set to playing");
340 
341   inbuffer = gst_buffer_new_and_alloc (2);
342   gst_buffer_fill (inbuffer, 0, in, 2);
343   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 2) == 0);
344   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
345   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
346   gst_caps_unref (caps);
347   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
348   /* FIXME: reffing the inbuffer should make the transformation not be
349    * inplace
350    gst_buffer_ref (inbuffer);
351    */
352 
353   /* pushing gives away my reference ... */
354   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
355   /* ... but it ends up being modified inplace and
356    * collected on the global buffer list */
357   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
358   fail_unless_equals_int (g_list_length (buffers), 1);
359   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
360   fail_unless (inbuffer == outbuffer);
361   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
362   res = (gint8 *) map.data;
363   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], res[0],
364       res[1]);
365   fail_unless (memcmp (res, out, 2) == 0);
366   gst_buffer_unmap (outbuffer, &map);
367 
368   /* cleanup */
369   cleanup_volume (volume);
370 }
371 
372 GST_END_TEST;
373 
GST_START_TEST(test_mute_s8)374 GST_START_TEST (test_mute_s8)
375 {
376   GstElement *volume;
377   GstBuffer *inbuffer;
378   GstBuffer *outbuffer;
379   GstCaps *caps;
380   gint8 in[2] = { 64, -16 };
381   gint8 out[2] = { 0, 0 };
382   GstMapInfo map;
383 
384   volume = setup_volume ();
385   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
386   fail_unless (gst_element_set_state (volume,
387           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
388       "could not set to playing");
389 
390   inbuffer = gst_buffer_new_and_alloc (2);
391   gst_buffer_fill (inbuffer, 0, in, 2);
392   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
393   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
394   gst_caps_unref (caps);
395   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
396   /* FIXME: reffing the inbuffer should make the transformation not be
397    * inplace
398    gst_buffer_ref (inbuffer);
399    */
400 
401   /* pushing gives away my reference ... */
402   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
403   /* ... but it ends up being modified inplace and
404    * collected on the global buffer list */
405   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
406   fail_unless_equals_int (g_list_length (buffers), 1);
407   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
408   fail_unless (inbuffer == outbuffer);
409   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
410   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
411       map.data[1]);
412   fail_unless (memcmp (map.data, out, 2) == 0);
413   gst_buffer_unmap (outbuffer, &map);
414 
415   /* cleanup */
416   cleanup_volume (volume);
417 }
418 
419 GST_END_TEST;
420 
GST_START_TEST(test_unity_s16)421 GST_START_TEST (test_unity_s16)
422 {
423   GstElement *volume;
424   GstBuffer *inbuffer, *outbuffer;
425   GstCaps *caps;
426   gint16 in[2] = { 16384, -256 };
427   GstMapInfo map;
428 
429   volume = setup_volume ();
430   fail_unless (gst_element_set_state (volume,
431           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
432       "could not set to playing");
433 
434   inbuffer = gst_buffer_new_and_alloc (4);
435   gst_buffer_fill (inbuffer, 0, in, 4);
436   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
437   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
438   gst_caps_unref (caps);
439   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
440 
441   /* pushing gives away my reference ... */
442   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
443   /* ... but it ends up being collected on the global buffer list */
444   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
445   fail_unless_equals_int (g_list_length (buffers), 1);
446   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
447   fail_unless (inbuffer == outbuffer);
448   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
449   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in[0], in[1], map.data[0],
450       map.data[1]);
451   fail_unless (memcmp (map.data, in, 4) == 0);
452   gst_buffer_unmap (outbuffer, &map);
453 
454   /* cleanup */
455   cleanup_volume (volume);
456 }
457 
458 GST_END_TEST;
459 
GST_START_TEST(test_half_s16)460 GST_START_TEST (test_half_s16)
461 {
462   GstElement *volume;
463   GstBuffer *inbuffer;
464   GstBuffer *outbuffer;
465   GstCaps *caps;
466   gint16 in[2] = { 16384, -256 };
467   gint16 out[2] = { 8192, -128 };
468   GstMapInfo map;
469 
470   volume = setup_volume ();
471   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
472   fail_unless (gst_element_set_state (volume,
473           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
474       "could not set to playing");
475 
476   inbuffer = gst_buffer_new_and_alloc (4);
477   gst_buffer_fill (inbuffer, 0, in, 4);
478   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
479   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
480   gst_caps_unref (caps);
481   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
482   /* FIXME: reffing the inbuffer should make the transformation not be
483    * inplace
484    gst_buffer_ref (inbuffer);
485    */
486 
487   /* pushing gives away my reference ... */
488   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
489   /* ... but it ends up being modified inplace and
490    * collected on the global buffer list */
491   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
492   fail_unless_equals_int (g_list_length (buffers), 1);
493   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
494   fail_unless (inbuffer == outbuffer);
495   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
496   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
497       map.data[1]);
498   fail_unless (memcmp (map.data, out, 4) == 0);
499   gst_buffer_unmap (outbuffer, &map);
500 
501   /* cleanup */
502   cleanup_volume (volume);
503 }
504 
505 GST_END_TEST;
506 
GST_START_TEST(test_double_s16)507 GST_START_TEST (test_double_s16)
508 {
509   GstElement *volume;
510   GstBuffer *inbuffer;
511   GstBuffer *outbuffer;
512   GstCaps *caps;
513   gint16 in[2] = { 16384, -256 };
514   gint16 out[2] = { 32767, -512 };      /* notice the clamped sample */
515   GstMapInfo map;
516 
517   volume = setup_volume ();
518   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
519   fail_unless (gst_element_set_state (volume,
520           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
521       "could not set to playing");
522 
523   inbuffer = gst_buffer_new_and_alloc (4);
524   gst_buffer_fill (inbuffer, 0, in, 4);
525   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
526   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
527   gst_caps_unref (caps);
528   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
529   /* FIXME: reffing the inbuffer should make the transformation not be
530    * inplace
531    gst_buffer_ref (inbuffer);
532    */
533 
534   /* pushing gives away my reference ... */
535   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
536   /* ... but it ends up being modified inplace and
537    * collected on the global buffer list */
538   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
539   fail_unless_equals_int (g_list_length (buffers), 1);
540   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
541   fail_unless (inbuffer == outbuffer);
542   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
543   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
544       map.data[1]);
545   fail_unless (memcmp (map.data, out, 4) == 0);
546   gst_buffer_unmap (outbuffer, &map);
547 
548   /* cleanup */
549   cleanup_volume (volume);
550 }
551 
552 GST_END_TEST;
553 
GST_START_TEST(test_ten_s16)554 GST_START_TEST (test_ten_s16)
555 {
556   GstElement *volume;
557   GstBuffer *inbuffer;
558   GstBuffer *outbuffer;
559   GstCaps *caps;
560   gint16 in[2] = { 16384, -10 };
561   gint16 out[2] = { 32767, -100 };      /* notice the clamped sample */
562   GstMapInfo map;
563 
564   volume = setup_volume ();
565   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
566   fail_unless (gst_element_set_state (volume,
567           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
568       "could not set to playing");
569 
570   inbuffer = gst_buffer_new_and_alloc (4);
571   gst_buffer_fill (inbuffer, 0, in, 4);
572   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 4) == 0);
573   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
574   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
575   gst_caps_unref (caps);
576   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
577   /* FIXME: reffing the inbuffer should make the transformation not be
578    * inplace
579    gst_buffer_ref (inbuffer);
580    */
581 
582   /* pushing gives away my reference ... */
583   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
584   /* ... but it ends up being modified inplace and
585    * collected on the global buffer list */
586   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
587   fail_unless_equals_int (g_list_length (buffers), 1);
588   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
589   fail_unless (inbuffer == outbuffer);
590   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
591   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
592       map.data[1]);
593   fail_unless (memcmp (map.data, out, 4) == 0);
594   gst_buffer_unmap (outbuffer, &map);
595 
596   /* cleanup */
597   cleanup_volume (volume);
598 }
599 
600 GST_END_TEST;
601 
602 
GST_START_TEST(test_mute_s16)603 GST_START_TEST (test_mute_s16)
604 {
605   GstElement *volume;
606   GstBuffer *inbuffer;
607   GstBuffer *outbuffer;
608   GstCaps *caps;
609   gint16 in[2] = { 16384, -256 };
610   gint16 out[2] = { 0, 0 };
611   GstMapInfo map;
612 
613   volume = setup_volume ();
614   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
615   fail_unless (gst_element_set_state (volume,
616           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
617       "could not set to playing");
618 
619   inbuffer = gst_buffer_new_and_alloc (4);
620   gst_buffer_fill (inbuffer, 0, in, 4);
621   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
622   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
623   gst_caps_unref (caps);
624   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
625   /* FIXME: reffing the inbuffer should make the transformation not be
626    * inplace
627    gst_buffer_ref (inbuffer);
628    */
629 
630   /* pushing gives away my reference ... */
631   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
632   /* ... but it ends up being modified inplace and
633    * collected on the global buffer list */
634   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
635   fail_unless_equals_int (g_list_length (buffers), 1);
636   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
637   fail_unless (inbuffer == outbuffer);
638   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
639   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
640       map.data[1]);
641   fail_unless (memcmp (map.data, out, 4) == 0);
642   gst_buffer_unmap (outbuffer, &map);
643 
644   /* cleanup */
645   cleanup_volume (volume);
646 }
647 
648 GST_END_TEST;
649 
650 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
651 #define get_unaligned_i24(_x) ( (((guint8*)_x)[0]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[2]) << 16) )
652 #define write_unaligned_u24(_x,samp) do { (((guint8*)_x)[0]) = samp & 0xFF; (((guint8*)_x)[1]) = (samp >> 8) & 0xFF; (((guint8*)_x)[2]) = (samp >> 16) & 0xFF; } while (0)
653 #else /* BIG ENDIAN */
654 #define get_unaligned_i24(_x) ( (((guint8*)_x)[2]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[0]) << 16) )
655 #define write_unaligned_u24(_x,samp) do { (((guint8*)_x)[0]) = (samp >> 16) & 0xFF; (((guint8*)_x)[1]) = (samp >> 8) & 0xFF; (((guint8*)_x)[2]) = samp & 0xFF; } while (0)
656 #endif
657 
GST_START_TEST(test_unity_s24)658 GST_START_TEST (test_unity_s24)
659 {
660   GstElement *volume;
661   GstBuffer *inbuffer, *outbuffer;
662   GstCaps *caps;
663   gint32 in_32[2] = { 4194304, -4096 };
664   guint8 in[6];
665   GstMapInfo map;
666   gint32 res_32[2];
667 
668   write_unaligned_u24 (in, in_32[0]);
669   write_unaligned_u24 (in + 3, in_32[1]);
670 
671   volume = setup_volume ();
672   fail_unless (gst_element_set_state (volume,
673           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
674       "could not set to playing");
675 
676   inbuffer = gst_buffer_new_and_alloc (6);
677   gst_buffer_fill (inbuffer, 0, in, 6);
678   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
679   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
680   gst_caps_unref (caps);
681   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
682 
683   /* pushing gives away my reference ... */
684   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
685   /* ... but it ends up being collected on the global buffer list */
686   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
687   fail_unless_equals_int (g_list_length (buffers), 1);
688   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
689   fail_unless (inbuffer == outbuffer);
690   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
691 
692   res_32[0] = get_unaligned_i24 (map.data);
693   res_32[1] = get_unaligned_i24 ((map.data + 3));
694 
695   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in_32[0], in_32[1], res_32[0],
696       res_32[1]);
697   fail_unless (memcmp (map.data, in, 6) == 0);
698   gst_buffer_unmap (outbuffer, &map);
699 
700   /* cleanup */
701   cleanup_volume (volume);
702 }
703 
704 GST_END_TEST;
705 
GST_START_TEST(test_half_s24)706 GST_START_TEST (test_half_s24)
707 {
708   GstElement *volume;
709   GstBuffer *inbuffer;
710   GstBuffer *outbuffer;
711   GstCaps *caps;
712   gint32 in_32[2] = { 4194304, -4096 };
713   guint8 in[6];
714   GstMapInfo map;
715   gint32 res_32[2];
716   gint32 out_32[2] = { 2097152, -2048 };
717 
718   write_unaligned_u24 (in, in_32[0]);
719   write_unaligned_u24 (in + 3, in_32[1]);
720 
721   volume = setup_volume ();
722   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
723   fail_unless (gst_element_set_state (volume,
724           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
725       "could not set to playing");
726 
727   inbuffer = gst_buffer_new_and_alloc (6);
728   gst_buffer_fill (inbuffer, 0, in, 6);
729   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
730   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
731   gst_caps_unref (caps);
732   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
733   /* FIXME: reffing the inbuffer should make the transformation not be
734    * inplace
735    gst_buffer_ref (inbuffer);
736    */
737 
738   /* pushing gives away my reference ... */
739   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
740   /* ... but it ends up being modified inplace and
741    * collected on the global buffer list */
742   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
743   fail_unless_equals_int (g_list_length (buffers), 1);
744   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
745   fail_unless (inbuffer == outbuffer);
746   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
747 
748   res_32[0] = get_unaligned_i24 (map.data);
749   res_32[1] = get_unaligned_i24 ((map.data + 3));
750 
751   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out_32[0], out_32[1],
752       res_32[0], res_32[1]);
753   fail_unless (memcmp (res_32, out_32, 8) == 0);
754   gst_buffer_unmap (outbuffer, &map);
755 
756   /* cleanup */
757   cleanup_volume (volume);
758 }
759 
760 GST_END_TEST;
761 
GST_START_TEST(test_double_s24)762 GST_START_TEST (test_double_s24)
763 {
764   GstElement *volume;
765   GstBuffer *inbuffer;
766   GstBuffer *outbuffer;
767   GstCaps *caps;
768   gint32 in_32[2] = { 4194304, -4096 };
769   guint8 in[6];
770   GstMapInfo map;
771   gint32 res_32[2];
772   gint32 out_32[2] = { 8388607, -8192 };        /* notice the clamped sample */
773 
774   write_unaligned_u24 (in, in_32[0]);
775   write_unaligned_u24 (in + 3, in_32[1]);
776 
777   volume = setup_volume ();
778   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
779   fail_unless (gst_element_set_state (volume,
780           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
781       "could not set to playing");
782 
783   inbuffer = gst_buffer_new_and_alloc (6);
784   gst_buffer_fill (inbuffer, 0, in, 6);
785   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
786   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
787   gst_caps_unref (caps);
788   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
789   /* FIXME: reffing the inbuffer should make the transformation not be
790    * inplace
791    gst_buffer_ref (inbuffer);
792    */
793 
794   /* pushing gives away my reference ... */
795   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
796   /* ... but it ends up being modified inplace and
797    * collected on the global buffer list */
798   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
799   fail_unless_equals_int (g_list_length (buffers), 1);
800   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
801   fail_unless (inbuffer == outbuffer);
802   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
803 
804   res_32[0] = get_unaligned_i24 (map.data);
805   res_32[1] = get_unaligned_i24 ((map.data + 3));
806 
807   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out_32[0], out_32[1],
808       res_32[0], res_32[1]);
809   fail_unless (memcmp (res_32, out_32, 8) == 0);
810   gst_buffer_unmap (outbuffer, &map);
811 
812   /* cleanup */
813   cleanup_volume (volume);
814 }
815 
816 GST_END_TEST;
817 
GST_START_TEST(test_ten_s24)818 GST_START_TEST (test_ten_s24)
819 {
820   GstElement *volume;
821   GstBuffer *inbuffer;
822   GstBuffer *outbuffer;
823   GstCaps *caps;
824   gint32 in_32[2] = { 4194304, -10 };
825   guint8 in[6];
826   GstMapInfo map;
827   gint32 res_32[2];
828   gint32 out_32[2] = { 8388607, -100 }; /* notice the clamped sample */
829 
830   write_unaligned_u24 (in, in_32[0]);
831   write_unaligned_u24 (in + 3, in_32[1]);
832 
833   volume = setup_volume ();
834   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
835   fail_unless (gst_element_set_state (volume,
836           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
837       "could not set to playing");
838 
839   inbuffer = gst_buffer_new_and_alloc (6);
840   gst_buffer_fill (inbuffer, 0, in, 6);
841   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 6) == 0);
842   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
843   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
844   gst_caps_unref (caps);
845   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
846   /* FIXME: reffing the inbuffer should make the transformation not be
847    * inplace
848    gst_buffer_ref (inbuffer);
849    */
850 
851   /* pushing gives away my reference ... */
852   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
853   /* ... but it ends up being modified inplace and
854    * collected on the global buffer list */
855   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
856   fail_unless_equals_int (g_list_length (buffers), 1);
857   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
858   fail_unless (inbuffer == outbuffer);
859   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
860 
861   res_32[0] = get_unaligned_i24 (map.data);
862   res_32[1] = get_unaligned_i24 ((map.data + 3));
863 
864   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out_32[0], out_32[1],
865       res_32[0], res_32[1]);
866   fail_unless (memcmp (res_32, out_32, 8) == 0);
867   gst_buffer_unmap (outbuffer, &map);
868 
869   /* cleanup */
870   cleanup_volume (volume);
871 }
872 
873 GST_END_TEST;
874 
GST_START_TEST(test_mute_s24)875 GST_START_TEST (test_mute_s24)
876 {
877   GstElement *volume;
878   GstBuffer *inbuffer;
879   GstBuffer *outbuffer;
880   GstCaps *caps;
881   gint32 in_32[2] = { 4194304, -4096 };
882   guint8 in[6];
883   GstMapInfo map;
884   gint32 res_32[2];
885   gint32 out_32[2] = { 0, 0 };  /* notice the clamped sample */
886 
887   write_unaligned_u24 (in, in_32[0]);
888   write_unaligned_u24 (in + 3, in_32[1]);
889 
890   volume = setup_volume ();
891   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
892   fail_unless (gst_element_set_state (volume,
893           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
894       "could not set to playing");
895 
896   inbuffer = gst_buffer_new_and_alloc (6);
897   gst_buffer_fill (inbuffer, 0, in, 6);
898   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
899   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
900   gst_caps_unref (caps);
901   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
902   /* FIXME: reffing the inbuffer should make the transformation not be
903    * inplace
904    gst_buffer_ref (inbuffer);
905    */
906 
907   /* pushing gives away my reference ... */
908   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
909   /* ... but it ends up being modified inplace and
910    * collected on the global buffer list */
911   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
912   fail_unless_equals_int (g_list_length (buffers), 1);
913   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
914   fail_unless (inbuffer == outbuffer);
915 
916   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
917 
918   res_32[0] = get_unaligned_i24 (map.data);
919   res_32[1] = get_unaligned_i24 ((map.data + 3));
920 
921   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out_32[0], out_32[1],
922       res_32[0], res_32[1]);
923   fail_unless (memcmp (res_32, out_32, 8) == 0);
924   gst_buffer_unmap (outbuffer, &map);
925 
926   /* cleanup */
927   cleanup_volume (volume);
928 }
929 
930 GST_END_TEST;
931 
GST_START_TEST(test_unity_s32)932 GST_START_TEST (test_unity_s32)
933 {
934   GstElement *volume;
935   GstBuffer *inbuffer, *outbuffer;
936   GstCaps *caps;
937   gint32 in[2] = { 1073741824, -65536 };
938   GstMapInfo map;
939 
940   volume = setup_volume ();
941   fail_unless (gst_element_set_state (volume,
942           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
943       "could not set to playing");
944 
945   inbuffer = gst_buffer_new_and_alloc (8);
946   gst_buffer_fill (inbuffer, 0, in, 8);
947   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
948   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
949   gst_caps_unref (caps);
950   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
951 
952   /* pushing gives away my reference ... */
953   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
954   /* ... but it ends up being collected on the global buffer list */
955   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
956   fail_unless_equals_int (g_list_length (buffers), 1);
957   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
958   fail_unless (inbuffer == outbuffer);
959   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
960   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in[0], in[1], map.data[0],
961       map.data[1]);
962   fail_unless (memcmp (map.data, in, 8) == 0);
963   gst_buffer_unmap (outbuffer, &map);
964 
965   /* cleanup */
966   cleanup_volume (volume);
967 }
968 
969 GST_END_TEST;
970 
GST_START_TEST(test_half_s32)971 GST_START_TEST (test_half_s32)
972 {
973   GstElement *volume;
974   GstBuffer *inbuffer;
975   GstBuffer *outbuffer;
976   GstCaps *caps;
977   gint32 in[2] = { 1073741824, -65536 };
978   gint32 out[2] = { 536870912, -32768 };
979   GstMapInfo map;
980 
981   volume = setup_volume ();
982   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
983   fail_unless (gst_element_set_state (volume,
984           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
985       "could not set to playing");
986 
987   inbuffer = gst_buffer_new_and_alloc (8);
988   gst_buffer_fill (inbuffer, 0, in, 8);
989   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
990   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
991   gst_caps_unref (caps);
992   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
993   /* FIXME: reffing the inbuffer should make the transformation not be
994    * inplace
995    gst_buffer_ref (inbuffer);
996    */
997 
998   /* pushing gives away my reference ... */
999   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1000   /* ... but it ends up being modified inplace and
1001    * collected on the global buffer list */
1002   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1003   fail_unless_equals_int (g_list_length (buffers), 1);
1004   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1005   fail_unless (inbuffer == outbuffer);
1006   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1007   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
1008       map.data[1]);
1009   fail_unless (memcmp (map.data, out, 8) == 0);
1010   gst_buffer_unmap (outbuffer, &map);
1011 
1012   /* cleanup */
1013   cleanup_volume (volume);
1014 }
1015 
1016 GST_END_TEST;
1017 
GST_START_TEST(test_double_s32)1018 GST_START_TEST (test_double_s32)
1019 {
1020   GstElement *volume;
1021   GstBuffer *inbuffer;
1022   GstBuffer *outbuffer;
1023   GstCaps *caps;
1024   gint32 in[2] = { 1073741824, -65536 };
1025   gint32 out[2] = { 2147483647, -131072 };      /* notice the clamped sample */
1026   GstMapInfo map;
1027 
1028   volume = setup_volume ();
1029   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
1030   fail_unless (gst_element_set_state (volume,
1031           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1032       "could not set to playing");
1033 
1034   inbuffer = gst_buffer_new_and_alloc (8);
1035   gst_buffer_fill (inbuffer, 0, in, 8);
1036   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
1037   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1038   gst_caps_unref (caps);
1039   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1040   /* FIXME: reffing the inbuffer should make the transformation not be
1041    * inplace
1042    gst_buffer_ref (inbuffer);
1043    */
1044 
1045   /* pushing gives away my reference ... */
1046   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1047   /* ... but it ends up being modified inplace and
1048    * collected on the global buffer list */
1049   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1050   fail_unless_equals_int (g_list_length (buffers), 1);
1051   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1052   fail_unless (inbuffer == outbuffer);
1053   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1054   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
1055       map.data[1]);
1056   fail_unless (memcmp (map.data, out, 8) == 0);
1057   gst_buffer_unmap (outbuffer, &map);
1058 
1059   /* cleanup */
1060   cleanup_volume (volume);
1061 }
1062 
1063 GST_END_TEST;
1064 
GST_START_TEST(test_ten_s32)1065 GST_START_TEST (test_ten_s32)
1066 {
1067   GstElement *volume;
1068   GstBuffer *inbuffer;
1069   GstBuffer *outbuffer;
1070   GstCaps *caps;
1071   gint32 in[2] = { 1073741824, -10 };
1072   gint32 out[2] = { 2147483647, -100 }; /* notice the clamped sample */
1073   GstMapInfo map;
1074 
1075   volume = setup_volume ();
1076   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
1077   fail_unless (gst_element_set_state (volume,
1078           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1079       "could not set to playing");
1080 
1081   inbuffer = gst_buffer_new_and_alloc (8);
1082   gst_buffer_fill (inbuffer, 0, in, 8);
1083   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
1084   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
1085   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1086   gst_caps_unref (caps);
1087   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1088   /* FIXME: reffing the inbuffer should make the transformation not be
1089    * inplace
1090    gst_buffer_ref (inbuffer);
1091    */
1092 
1093   /* pushing gives away my reference ... */
1094   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1095   /* ... but it ends up being modified inplace and
1096    * collected on the global buffer list */
1097   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1098   fail_unless_equals_int (g_list_length (buffers), 1);
1099   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1100   fail_unless (inbuffer == outbuffer);
1101   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1102   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
1103       map.data[1]);
1104   fail_unless (memcmp (map.data, out, 8) == 0);
1105   gst_buffer_unmap (outbuffer, &map);
1106 
1107   /* cleanup */
1108   cleanup_volume (volume);
1109 }
1110 
1111 GST_END_TEST;
1112 
GST_START_TEST(test_mute_s32)1113 GST_START_TEST (test_mute_s32)
1114 {
1115   GstElement *volume;
1116   GstBuffer *inbuffer;
1117   GstBuffer *outbuffer;
1118   GstCaps *caps;
1119   gint32 in[2] = { 1073741824, -65536 };
1120   gint32 out[2] = { 0, 0 };
1121   GstMapInfo map;
1122 
1123   volume = setup_volume ();
1124   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
1125   fail_unless (gst_element_set_state (volume,
1126           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1127       "could not set to playing");
1128 
1129   inbuffer = gst_buffer_new_and_alloc (8);
1130   gst_buffer_fill (inbuffer, 0, in, 8);
1131   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
1132   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1133   gst_caps_unref (caps);
1134   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1135   /* FIXME: reffing the inbuffer should make the transformation not be
1136    * inplace
1137    gst_buffer_ref (inbuffer);
1138    */
1139 
1140   /* pushing gives away my reference ... */
1141   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1142   /* ... but it ends up being modified inplace and
1143    * collected on the global buffer list */
1144   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1145   fail_unless_equals_int (g_list_length (buffers), 1);
1146   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1147   fail_unless (inbuffer == outbuffer);
1148   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1149   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", out[0], out[1], map.data[0],
1150       map.data[1]);
1151   fail_unless (memcmp (map.data, out, 8) == 0);
1152   gst_buffer_unmap (outbuffer, &map);
1153 
1154   /* cleanup */
1155   cleanup_volume (volume);
1156 }
1157 
1158 GST_END_TEST;
1159 
GST_START_TEST(test_unity_f32)1160 GST_START_TEST (test_unity_f32)
1161 {
1162   GstElement *volume;
1163   GstBuffer *inbuffer, *outbuffer;
1164   GstCaps *caps;
1165   gfloat in[2] = { 0.75, -0.25 }, *res;
1166   GstMapInfo map;
1167 
1168   volume = setup_volume ();
1169   fail_unless (gst_element_set_state (volume,
1170           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1171       "could not set to playing");
1172 
1173   inbuffer = gst_buffer_new_and_alloc (8);
1174   gst_buffer_fill (inbuffer, 0, in, sizeof (in));
1175   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
1176   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1177   gst_caps_unref (caps);
1178   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1179 
1180   /* pushing gives away my reference ... */
1181   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1182   /* ... but it ends up being collected on the global buffer list */
1183   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1184   fail_unless_equals_int (g_list_length (buffers), 1);
1185   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1186   fail_unless (inbuffer == outbuffer);
1187   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1188   res = (gfloat *) map.data;
1189   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", in[0], in[1],
1190       res[0], res[1]);
1191   fail_unless_equals_float (res[0], in[0]);
1192   fail_unless_equals_float (res[1], in[1]);
1193   gst_buffer_unmap (outbuffer, &map);
1194 
1195   /* cleanup */
1196   cleanup_volume (volume);
1197 }
1198 
1199 GST_END_TEST;
1200 
GST_START_TEST(test_half_f32)1201 GST_START_TEST (test_half_f32)
1202 {
1203   GstElement *volume;
1204   GstBuffer *inbuffer;
1205   GstBuffer *outbuffer;
1206   GstCaps *caps;
1207   gfloat in[2] = { 0.75, -0.25 };
1208   gfloat out[2] = { 0.375, -0.125 };
1209   gfloat *res;
1210   GstMapInfo map;
1211 
1212   volume = setup_volume ();
1213   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
1214   fail_unless (gst_element_set_state (volume,
1215           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1216       "could not set to playing");
1217 
1218   inbuffer = gst_buffer_new_and_alloc (8);
1219   gst_buffer_fill (inbuffer, 0, in, 8);
1220   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
1221   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1222   gst_caps_unref (caps);
1223   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1224   /* FIXME: reffing the inbuffer should make the transformation not be
1225    * inplace
1226    gst_buffer_ref (inbuffer);
1227    */
1228 
1229   /* pushing gives away my reference ... */
1230   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1231   /* ... but it ends up being modified inplace and
1232    * collected on the global buffer list */
1233   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1234   fail_unless_equals_int (g_list_length (buffers), 1);
1235   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1236   fail_unless (inbuffer == outbuffer);
1237   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1238   res = (gfloat *) map.data;
1239   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1240       res[0], res[1]);
1241   fail_unless_equals_float (res[0], out[0]);
1242   fail_unless_equals_float (res[1], out[1]);
1243   gst_buffer_unmap (outbuffer, &map);
1244 
1245   /* cleanup */
1246   cleanup_volume (volume);
1247 }
1248 
1249 GST_END_TEST;
1250 
GST_START_TEST(test_double_f32)1251 GST_START_TEST (test_double_f32)
1252 {
1253   GstElement *volume;
1254   GstBuffer *inbuffer;
1255   GstBuffer *outbuffer;
1256   GstCaps *caps;
1257   gfloat in[2] = { 0.75, -0.25 };
1258   gfloat out[2] = { 1.5, -0.5 };        /* nothing is clamped */
1259   gfloat *res;
1260   GstMapInfo map;
1261 
1262   volume = setup_volume ();
1263   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
1264   fail_unless (gst_element_set_state (volume,
1265           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1266       "could not set to playing");
1267 
1268   inbuffer = gst_buffer_new_and_alloc (8);
1269   gst_buffer_fill (inbuffer, 0, in, 8);
1270   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
1271   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1272   gst_caps_unref (caps);
1273   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1274   /* FIXME: reffing the inbuffer should make the transformation not be
1275    * inplace
1276    gst_buffer_ref (inbuffer);
1277    */
1278 
1279   /* pushing gives away my reference ... */
1280   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1281   /* ... but it ends up being modified inplace and
1282    * collected on the global buffer list */
1283   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1284   fail_unless_equals_int (g_list_length (buffers), 1);
1285   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1286   fail_unless (inbuffer == outbuffer);
1287   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1288   res = (gfloat *) map.data;
1289   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1290       res[0], res[1]);
1291   fail_unless_equals_float (res[0], out[0]);
1292   fail_unless_equals_float (res[1], out[1]);
1293   gst_buffer_unmap (outbuffer, &map);
1294 
1295   /* cleanup */
1296   cleanup_volume (volume);
1297 }
1298 
1299 GST_END_TEST;
1300 
GST_START_TEST(test_ten_f32)1301 GST_START_TEST (test_ten_f32)
1302 {
1303   GstElement *volume;
1304   GstBuffer *inbuffer;
1305   GstBuffer *outbuffer;
1306   GstCaps *caps;
1307   gfloat in[2] = { 0.75, -0.25 };
1308   gfloat out[2] = { 7.5, -2.5 };        /* nothing is clamped */
1309   gfloat *res;
1310   GstMapInfo map;
1311 
1312   volume = setup_volume ();
1313   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
1314   fail_unless (gst_element_set_state (volume,
1315           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1316       "could not set to playing");
1317 
1318   inbuffer = gst_buffer_new_and_alloc (8);
1319   gst_buffer_fill (inbuffer, 0, in, 8);
1320   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 8) == 0);
1321   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
1322   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1323   gst_caps_unref (caps);
1324   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1325   /* FIXME: reffing the inbuffer should make the transformation not be
1326    * inplace
1327    gst_buffer_ref (inbuffer);
1328    */
1329 
1330   /* pushing gives away my reference ... */
1331   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1332   /* ... but it ends up being modified inplace and
1333    * collected on the global buffer list */
1334   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1335   fail_unless_equals_int (g_list_length (buffers), 1);
1336   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1337   fail_unless (inbuffer == outbuffer);
1338   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1339   res = (gfloat *) map.data;
1340   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1341       res[0], res[1]);
1342   fail_unless_equals_float (res[0], out[0]);
1343   fail_unless_equals_float (res[1], out[1]);
1344   gst_buffer_unmap (outbuffer, &map);
1345 
1346   /* cleanup */
1347   cleanup_volume (volume);
1348 }
1349 
1350 GST_END_TEST;
1351 
1352 
GST_START_TEST(test_mute_f32)1353 GST_START_TEST (test_mute_f32)
1354 {
1355   GstElement *volume;
1356   GstBuffer *inbuffer;
1357   GstBuffer *outbuffer;
1358   GstCaps *caps;
1359   gfloat in[2] = { 0.75, -0.25 };
1360   gfloat out[2] = { 0, 0 };
1361   gfloat *res;
1362   GstMapInfo map;
1363 
1364   volume = setup_volume ();
1365   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
1366   fail_unless (gst_element_set_state (volume,
1367           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1368       "could not set to playing");
1369 
1370   inbuffer = gst_buffer_new_and_alloc (8);
1371   gst_buffer_fill (inbuffer, 0, in, 8);
1372   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
1373   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1374   gst_caps_unref (caps);
1375   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1376   /* FIXME: reffing the inbuffer should make the transformation not be
1377    * inplace
1378    gst_buffer_ref (inbuffer);
1379    */
1380 
1381   /* pushing gives away my reference ... */
1382   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1383   /* ... but it ends up being modified inplace and
1384    * collected on the global buffer list */
1385   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1386   fail_unless_equals_int (g_list_length (buffers), 1);
1387   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1388   fail_unless (inbuffer == outbuffer);
1389   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1390   res = (gfloat *) map.data;
1391   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1392       res[0], res[1]);
1393   fail_unless_equals_float (res[0], out[0]);
1394   fail_unless_equals_float (res[1], out[1]);
1395   gst_buffer_unmap (outbuffer, &map);
1396 
1397   /* cleanup */
1398   cleanup_volume (volume);
1399 }
1400 
1401 GST_END_TEST;
1402 
GST_START_TEST(test_unity_f64)1403 GST_START_TEST (test_unity_f64)
1404 {
1405   GstElement *volume;
1406   GstBuffer *inbuffer, *outbuffer;
1407   GstCaps *caps;
1408   gdouble in[2] = { 0.75, -0.25 };
1409   gdouble *res;
1410   GstMapInfo map;
1411 
1412   volume = setup_volume ();
1413   fail_unless (gst_element_set_state (volume,
1414           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1415       "could not set to playing");
1416 
1417   inbuffer = gst_buffer_new_and_alloc (16);
1418   gst_buffer_fill (inbuffer, 0, in, 16);
1419   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
1420   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1421   gst_caps_unref (caps);
1422   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1423 
1424   /* pushing gives away my reference ... */
1425   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1426   /* ... but it ends up being collected on the global buffer list */
1427   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1428   fail_unless_equals_int (g_list_length (buffers), 1);
1429   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1430   fail_unless (inbuffer == outbuffer);
1431   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1432   res = (gdouble *) map.data;
1433   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", in[0], in[1],
1434       res[0], res[1]);
1435   fail_unless_equals_float (res[0], in[0]);
1436   fail_unless_equals_float (res[1], in[1]);
1437   gst_buffer_unmap (outbuffer, &map);
1438 
1439   /* cleanup */
1440   cleanup_volume (volume);
1441 }
1442 
1443 GST_END_TEST;
1444 
GST_START_TEST(test_half_f64)1445 GST_START_TEST (test_half_f64)
1446 {
1447   GstElement *volume;
1448   GstBuffer *inbuffer;
1449   GstBuffer *outbuffer;
1450   GstCaps *caps;
1451   gdouble in[2] = { 0.75, -0.25 };
1452   gdouble out[2] = { 0.375, -0.125 };
1453   gdouble *res;
1454   GstMapInfo map;
1455 
1456   volume = setup_volume ();
1457   g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
1458   fail_unless (gst_element_set_state (volume,
1459           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1460       "could not set to playing");
1461 
1462   inbuffer = gst_buffer_new_and_alloc (16);
1463   gst_buffer_fill (inbuffer, 0, in, 16);
1464   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
1465   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1466   gst_caps_unref (caps);
1467   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1468   /* FIXME: reffing the inbuffer should make the transformation not be
1469    * inplace
1470    gst_buffer_ref (inbuffer);
1471    */
1472 
1473   /* pushing gives away my reference ... */
1474   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1475   /* ... but it ends up being modified inplace and
1476    * collected on the global buffer list */
1477   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1478   fail_unless_equals_int (g_list_length (buffers), 1);
1479   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1480   fail_unless (inbuffer == outbuffer);
1481   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1482   res = (gdouble *) map.data;
1483   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1484       res[0], res[1]);
1485   fail_unless_equals_float (res[0], out[0]);
1486   fail_unless_equals_float (res[1], out[1]);
1487   gst_buffer_unmap (outbuffer, &map);
1488 
1489   /* cleanup */
1490   cleanup_volume (volume);
1491 }
1492 
1493 GST_END_TEST;
1494 
GST_START_TEST(test_double_f64)1495 GST_START_TEST (test_double_f64)
1496 {
1497   GstElement *volume;
1498   GstBuffer *inbuffer;
1499   GstBuffer *outbuffer;
1500   GstCaps *caps;
1501   gdouble in[2] = { 0.75, -0.25 };
1502   gdouble out[2] = { 1.5, -0.5 };       /* nothing is clamped */
1503   gdouble *res;
1504   GstMapInfo map;
1505 
1506   volume = setup_volume ();
1507   g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
1508   fail_unless (gst_element_set_state (volume,
1509           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1510       "could not set to playing");
1511 
1512   inbuffer = gst_buffer_new_and_alloc (16);
1513   gst_buffer_fill (inbuffer, 0, in, 16);
1514   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
1515   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1516   gst_caps_unref (caps);
1517   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1518   /* FIXME: reffing the inbuffer should make the transformation not be
1519    * inplace
1520    gst_buffer_ref (inbuffer);
1521    */
1522 
1523   /* pushing gives away my reference ... */
1524   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1525   /* ... but it ends up being modified inplace and
1526    * collected on the global buffer list */
1527   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1528   fail_unless_equals_int (g_list_length (buffers), 1);
1529   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1530   fail_unless (inbuffer == outbuffer);
1531   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1532   res = (gdouble *) map.data;
1533   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1534       res[0], res[1]);
1535   fail_unless_equals_float (res[0], out[0]);
1536   fail_unless_equals_float (res[1], out[1]);
1537   gst_buffer_unmap (outbuffer, &map);
1538 
1539   /* cleanup */
1540   cleanup_volume (volume);
1541 }
1542 
1543 GST_END_TEST;
1544 
GST_START_TEST(test_ten_f64)1545 GST_START_TEST (test_ten_f64)
1546 {
1547   GstElement *volume;
1548   GstBuffer *inbuffer;
1549   GstBuffer *outbuffer;
1550   GstCaps *caps;
1551   gdouble in[2] = { 0.75, -0.25 };
1552   gdouble out[2] = { 7.5, -2.5 };       /* nothing is clamped */
1553   gdouble *res;
1554   GstMapInfo map;
1555 
1556   volume = setup_volume ();
1557   g_object_set (G_OBJECT (volume), "volume", 10.0, NULL);
1558   fail_unless (gst_element_set_state (volume,
1559           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1560       "could not set to playing");
1561 
1562   inbuffer = gst_buffer_new_and_alloc (16);
1563   gst_buffer_fill (inbuffer, 0, in, 16);
1564   fail_unless (gst_buffer_memcmp (inbuffer, 0, in, 16) == 0);
1565   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
1566   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1567   gst_caps_unref (caps);
1568   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1569   /* FIXME: reffing the inbuffer should make the transformation not be
1570    * inplace
1571    gst_buffer_ref (inbuffer);
1572    */
1573 
1574   /* pushing gives away my reference ... */
1575   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1576   /* ... but it ends up being modified inplace and
1577    * collected on the global buffer list */
1578   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1579   fail_unless_equals_int (g_list_length (buffers), 1);
1580   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1581   fail_unless (inbuffer == outbuffer);
1582   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1583   res = (gdouble *) map.data;
1584   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1585       res[0], res[1]);
1586   fail_unless_equals_float (res[0], out[0]);
1587   fail_unless_equals_float (res[1], out[1]);
1588   gst_buffer_unmap (outbuffer, &map);
1589 
1590   /* cleanup */
1591   cleanup_volume (volume);
1592 }
1593 
1594 GST_END_TEST;
1595 
1596 
GST_START_TEST(test_mute_f64)1597 GST_START_TEST (test_mute_f64)
1598 {
1599   GstElement *volume;
1600   GstBuffer *inbuffer;
1601   GstBuffer *outbuffer;
1602   GstCaps *caps;
1603   gdouble in[2] = { 0.75, -0.25 };
1604   gdouble out[2] = { 0, 0 };
1605   gdouble *res;
1606   GstMapInfo map;
1607 
1608   volume = setup_volume ();
1609   g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
1610   fail_unless (gst_element_set_state (volume,
1611           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1612       "could not set to playing");
1613 
1614   inbuffer = gst_buffer_new_and_alloc (16);
1615   gst_buffer_fill (inbuffer, 0, in, 16);
1616   caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
1617   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1618   gst_caps_unref (caps);
1619   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1620   /* FIXME: reffing the inbuffer should make the transformation not be
1621    * inplace
1622    gst_buffer_ref (inbuffer);
1623    */
1624 
1625   /* pushing gives away my reference ... */
1626   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1627   /* ... but it ends up being modified inplace and
1628    * collected on the global buffer list */
1629   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1630   fail_unless_equals_int (g_list_length (buffers), 1);
1631   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1632   fail_unless (inbuffer == outbuffer);
1633   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1634   res = (gdouble *) map.data;
1635   GST_INFO ("expected %+1.4f %+1.4f  real %+1.4f %+1.4f", out[0], out[1],
1636       res[0], res[1]);
1637   fail_unless_equals_float (res[0], out[0]);
1638   fail_unless_equals_float (res[1], out[1]);
1639   gst_buffer_unmap (outbuffer, &map);
1640 
1641   /* cleanup */
1642   cleanup_volume (volume);
1643 }
1644 
1645 GST_END_TEST;
1646 
GST_START_TEST(test_wrong_caps)1647 GST_START_TEST (test_wrong_caps)
1648 {
1649   GstElement *volume;
1650   GstBuffer *inbuffer;
1651   gint16 in[2] = { 16384, -256 };
1652   GstBus *bus;
1653   GstMessage *message;
1654   GstCaps *caps;
1655 
1656   volume = setup_volume ();
1657   bus = gst_bus_new ();
1658 
1659   fail_unless (gst_element_set_state (volume,
1660           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1661       "could not set to playing");
1662 
1663   inbuffer = gst_buffer_new_and_alloc (4);
1664   gst_buffer_fill (inbuffer, 0, in, 4);
1665   caps = gst_caps_from_string (VOLUME_WRONG_CAPS_STRING);
1666   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1667   gst_caps_unref (caps);
1668   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1669   gst_buffer_ref (inbuffer);
1670 
1671   /* set a bus here so we avoid getting state change messages */
1672   gst_element_set_bus (volume, bus);
1673 
1674   /* pushing gives an error because it can't negotiate with wrong caps */
1675   fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer),
1676       GST_FLOW_NOT_NEGOTIATED);
1677   /* ... and the buffer would have been lost if we didn't ref it ourselves */
1678   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1679   gst_buffer_unref (inbuffer);
1680   fail_unless_equals_int (g_list_length (buffers), 0);
1681 
1682   /* volume_set_caps should not have been called since basetransform caught
1683    * the negotiation problem */
1684   fail_if ((message = gst_bus_pop (bus)) != NULL);
1685 
1686   /* cleanup */
1687   gst_element_set_bus (volume, NULL);
1688   gst_object_unref (GST_OBJECT (bus));
1689   cleanup_volume (volume);
1690 }
1691 
1692 GST_END_TEST;
1693 
GST_START_TEST(test_passthrough)1694 GST_START_TEST (test_passthrough)
1695 {
1696   GstElement *volume;
1697   GstBuffer *inbuffer, *outbuffer;
1698   GstCaps *caps;
1699   gint16 *out, in[2] = { 16384, -256 };
1700   GstMapInfo map;
1701 
1702   volume = setup_volume ();
1703   g_object_set (G_OBJECT (volume), "volume", 1.0, NULL);
1704   fail_unless (gst_element_set_state (volume,
1705           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1706       "could not set to playing");
1707 
1708   inbuffer = gst_buffer_new_and_alloc (4);
1709   gst_buffer_fill (inbuffer, 0, in, 4);
1710   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
1711   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1712   gst_caps_unref (caps);
1713   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1714 
1715   /* pushing gives away my reference ... */
1716   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1717   /* ... but it ends up being collected on the global buffer list */
1718   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1719   fail_unless_equals_int (g_list_length (buffers), 1);
1720   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1721   fail_unless (inbuffer == outbuffer);
1722   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1723   out = (gint16 *) map.data;
1724   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in[0], in[1], out[0], out[1]);
1725   fail_unless (memcmp (map.data, in, 4) == 0);
1726   gst_buffer_unmap (outbuffer, &map);
1727 
1728   /* cleanup */
1729   cleanup_volume (volume);
1730 }
1731 
1732 GST_END_TEST;
1733 
GST_START_TEST(test_controller_usability)1734 GST_START_TEST (test_controller_usability)
1735 {
1736   GstControlSource *cs;
1737   GstTimedValueControlSource *tvcs;
1738   GstControlBinding *cb;
1739   GstElement *volume;
1740 
1741   volume = setup_volume ();
1742 
1743   /* this shouldn't crash, whether this mode is implemented or not */
1744   cs = gst_interpolation_control_source_new ();
1745   g_object_set (cs, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL);
1746   cb = gst_direct_control_binding_new (GST_OBJECT_CAST (volume), "volume", cs);
1747   gst_object_add_control_binding (GST_OBJECT_CAST (volume), cb);
1748 
1749   tvcs = (GstTimedValueControlSource *) cs;
1750   gst_timed_value_control_source_set (tvcs, 0 * GST_SECOND, 0.0);
1751   gst_timed_value_control_source_set (tvcs, 5 * GST_SECOND, 1.0);
1752   gst_timed_value_control_source_set (tvcs, 10 * GST_SECOND, 0.0);
1753 
1754   gst_object_unref (cs);
1755   gst_object_remove_control_binding (GST_OBJECT_CAST (volume), cb);
1756 
1757   cleanup_volume (volume);
1758 }
1759 
1760 GST_END_TEST;
1761 
GST_START_TEST(test_controller_processing)1762 GST_START_TEST (test_controller_processing)
1763 {
1764   GstControlSource *cs;
1765   GstTimedValueControlSource *tvcs;
1766   GstElement *volume;
1767   GstBuffer *inbuffer, *outbuffer;
1768   GstCaps *caps;
1769   gint16 *out, in[2] = { 16384, -256 };
1770   GstMapInfo map;
1771   GstSegment seg;
1772 
1773   volume = setup_volume ();
1774 
1775   cs = gst_interpolation_control_source_new ();
1776   g_object_set (cs, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL);
1777   gst_object_add_control_binding (GST_OBJECT_CAST (volume),
1778       gst_direct_control_binding_new (GST_OBJECT_CAST (volume), "volume", cs));
1779 
1780   /* the value range for volume is 0.0 ... 10.0 */
1781   tvcs = (GstTimedValueControlSource *) cs;
1782   gst_timed_value_control_source_set (tvcs, 0 * GST_SECOND, 0.1);
1783 
1784   fail_unless (gst_element_set_state (volume,
1785           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1786       "could not set to playing");
1787 
1788   inbuffer = gst_buffer_new_and_alloc (4);
1789   gst_buffer_fill (inbuffer, 0, in, 4);
1790   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
1791   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1792   GST_BUFFER_TIMESTAMP (inbuffer) = 0;
1793   gst_caps_unref (caps);
1794   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1795 
1796   gst_segment_init (&seg, GST_FORMAT_TIME);
1797   fail_unless (gst_pad_push_event (mysrcpad,
1798           gst_event_new_segment (&seg)) == TRUE);
1799 
1800   /* pushing gives away my reference ... */
1801   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1802   /* ... but it ends up being collected on the global buffer list */
1803   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
1804   fail_unless_equals_int (g_list_length (buffers), 1);
1805   fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
1806   fail_unless (inbuffer == outbuffer);
1807   gst_buffer_map (outbuffer, &map, GST_MAP_READ);
1808   out = (gint16 *) map.data;
1809   GST_INFO ("expected %+5d %+5d  real %+5d %+5d", in[0], in[1], out[0], out[1]);
1810   fail_unless (memcmp (map.data, in, 4) == 0);
1811   gst_buffer_unmap (outbuffer, &map);
1812 
1813   gst_object_unref (cs);
1814   cleanup_volume (volume);
1815 }
1816 
1817 GST_END_TEST;
1818 
GST_START_TEST(test_controller_defaults_at_ts0)1819 GST_START_TEST (test_controller_defaults_at_ts0)
1820 {
1821   GstControlSource *cs;
1822   GstTimedValueControlSource *tvcs;
1823   GstElement *volume;
1824   GstBuffer *inbuffer;
1825   GstCaps *caps;
1826   GstSegment seg;
1827 
1828   volume = setup_volume ();
1829 
1830   cs = gst_interpolation_control_source_new ();
1831   g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
1832   gst_object_add_control_binding (GST_OBJECT_CAST (volume),
1833       gst_direct_control_binding_new (GST_OBJECT_CAST (volume), "volume", cs));
1834 
1835   /* make a control curve that does not start at ts=0, the element will use
1836    * the current property value (default) until the control curve starts
1837    */
1838   tvcs = (GstTimedValueControlSource *) cs;
1839   gst_timed_value_control_source_set (tvcs, GST_SECOND / 100, 0.1);
1840   gst_timed_value_control_source_set (tvcs, GST_SECOND, 1.0);
1841 
1842   fail_unless (gst_element_set_state (volume,
1843           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1844       "could not set to playing");
1845 
1846   /* controller curve starts at sample: 441 */
1847   inbuffer = gst_buffer_new_and_alloc (1000 * sizeof (gint16));
1848   gst_buffer_memset (inbuffer, 0, 0, 1000 * sizeof (gint16));
1849   caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
1850   gst_check_setup_events (mysrcpad, volume, caps, GST_FORMAT_TIME);
1851   GST_BUFFER_TIMESTAMP (inbuffer) = 0;
1852   gst_caps_unref (caps);
1853 
1854   gst_segment_init (&seg, GST_FORMAT_TIME);
1855   fail_unless (gst_pad_push_event (mysrcpad,
1856           gst_event_new_segment (&seg)) == TRUE);
1857 
1858   /* pushing gives away my reference ... */
1859   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
1860 
1861   gst_object_unref (cs);
1862   cleanup_volume (volume);
1863 }
1864 
1865 GST_END_TEST;
1866 
1867 
1868 static Suite *
volume_suite(void)1869 volume_suite (void)
1870 {
1871   Suite *s = suite_create ("volume");
1872   TCase *tc_chain = tcase_create ("general");
1873 
1874   suite_add_tcase (s, tc_chain);
1875   tcase_add_test (tc_chain, test_get_set);
1876   tcase_add_test (tc_chain, test_unity_s8);
1877   tcase_add_test (tc_chain, test_half_s8);
1878   tcase_add_test (tc_chain, test_double_s8);
1879   tcase_add_test (tc_chain, test_ten_s8);
1880   tcase_add_test (tc_chain, test_mute_s8);
1881   tcase_add_test (tc_chain, test_unity_s16);
1882   tcase_add_test (tc_chain, test_half_s16);
1883   tcase_add_test (tc_chain, test_double_s16);
1884   tcase_add_test (tc_chain, test_ten_s16);
1885   tcase_add_test (tc_chain, test_mute_s16);
1886   tcase_add_test (tc_chain, test_unity_s24);
1887   tcase_add_test (tc_chain, test_half_s24);
1888   tcase_add_test (tc_chain, test_double_s24);
1889   tcase_add_test (tc_chain, test_ten_s24);
1890   tcase_add_test (tc_chain, test_mute_s24);
1891   tcase_add_test (tc_chain, test_unity_s32);
1892   tcase_add_test (tc_chain, test_half_s32);
1893   tcase_add_test (tc_chain, test_double_s32);
1894   tcase_add_test (tc_chain, test_ten_s32);
1895   tcase_add_test (tc_chain, test_mute_s32);
1896   tcase_add_test (tc_chain, test_unity_f32);
1897   tcase_add_test (tc_chain, test_half_f32);
1898   tcase_add_test (tc_chain, test_double_f32);
1899   tcase_add_test (tc_chain, test_ten_f32);
1900   tcase_add_test (tc_chain, test_mute_f32);
1901   tcase_add_test (tc_chain, test_unity_f64);
1902   tcase_add_test (tc_chain, test_half_f64);
1903   tcase_add_test (tc_chain, test_double_f64);
1904   tcase_add_test (tc_chain, test_ten_f64);
1905   tcase_add_test (tc_chain, test_mute_f64);
1906   tcase_add_test (tc_chain, test_wrong_caps);
1907   tcase_add_test (tc_chain, test_passthrough);
1908   tcase_add_test (tc_chain, test_controller_usability);
1909   tcase_add_test (tc_chain, test_controller_processing);
1910   tcase_add_test (tc_chain, test_controller_defaults_at_ts0);
1911 
1912   return s;
1913 }
1914 
1915 GST_CHECK_MAIN (volume)
1916