1 /* GStreamer
2  *
3  * unit test for audiotestsrc
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/check/gstcheck.h>
28 #include <gst/check/gstharness.h>
29 #include <gst/audio/audio.h>
30 
31 /* For ease of programming we use globals to keep refs for our floating
32  * src and sink pads we create; otherwise we always have to do get_pad,
33  * get_peer, and then remove references in every test function */
34 static GstPad *mysinkpad;
35 
36 
37 #define CAPS_TEMPLATE_STRING            \
38     "audio/x-raw, "                     \
39     "format = (string) "GST_AUDIO_NE(S16)", "   \
40     "channels = (int) 1, "              \
41     "rate = (int) [ 1,  MAX ]"
42 
43 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS (CAPS_TEMPLATE_STRING)
47     );
48 
49 static GstElement *
setup_audiotestsrc(void)50 setup_audiotestsrc (void)
51 {
52   GstElement *audiotestsrc;
53 
54   GST_DEBUG ("setup_audiotestsrc");
55   audiotestsrc = gst_check_setup_element ("audiotestsrc");
56   mysinkpad = gst_check_setup_sink_pad (audiotestsrc, &sinktemplate);
57   gst_pad_set_active (mysinkpad, TRUE);
58 
59   return audiotestsrc;
60 }
61 
62 static void
cleanup_audiotestsrc(GstElement * audiotestsrc)63 cleanup_audiotestsrc (GstElement * audiotestsrc)
64 {
65   GST_DEBUG ("cleanup_audiotestsrc");
66 
67   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
68   g_list_free (buffers);
69   buffers = NULL;
70 
71   gst_pad_set_active (mysinkpad, FALSE);
72   gst_check_teardown_sink_pad (audiotestsrc);
73   gst_check_teardown_element (audiotestsrc);
74 }
75 
GST_START_TEST(test_all_waves)76 GST_START_TEST (test_all_waves)
77 {
78   GstElement *audiotestsrc;
79   GObjectClass *oclass;
80   GParamSpec *property;
81   GEnumValue *values;
82   guint j = 0;
83 
84   audiotestsrc = setup_audiotestsrc ();
85   oclass = G_OBJECT_GET_CLASS (audiotestsrc);
86   property = g_object_class_find_property (oclass, "wave");
87   fail_unless (G_IS_PARAM_SPEC_ENUM (property));
88   values = G_ENUM_CLASS (g_type_class_ref (property->value_type))->values;
89 
90 
91   while (values[j].value_name) {
92     GST_DEBUG_OBJECT (audiotestsrc, "testing wave %s", values[j].value_name);
93     g_object_set (audiotestsrc, "wave", values[j].value, NULL);
94 
95     fail_unless (gst_element_set_state (audiotestsrc,
96             GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
97         "could not set to playing");
98 
99     g_mutex_lock (&check_mutex);
100     while (g_list_length (buffers) < 10)
101       g_cond_wait (&check_cond, &check_mutex);
102     g_mutex_unlock (&check_mutex);
103 
104     gst_element_set_state (audiotestsrc, GST_STATE_READY);
105 
106     g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
107     g_list_free (buffers);
108     buffers = NULL;
109     ++j;
110   }
111 
112   /* cleanup */
113   cleanup_audiotestsrc (audiotestsrc);
114 }
115 
116 GST_END_TEST;
117 
118 
119 #define TEST_LAYOUT_CHANNELS 6
120 
121 static GstStaticPadTemplate sinktemplate_interleaved =
122 GST_STATIC_PAD_TEMPLATE ("sink",
123     GST_PAD_SINK,
124     GST_PAD_ALWAYS,
125     GST_STATIC_CAPS ("audio/x-raw, "
126         "format = (string) " GST_AUDIO_NE (S16) ", "
127         "channels = (int) " G_STRINGIFY (TEST_LAYOUT_CHANNELS) ", "
128         "rate = (int) [ 1,  MAX ], layout = (string) interleaved")
129     );
130 
131 static GstStaticPadTemplate sinktemplate_planar =
132 GST_STATIC_PAD_TEMPLATE ("sink",
133     GST_PAD_SINK,
134     GST_PAD_ALWAYS,
135     GST_STATIC_CAPS ("audio/x-raw, "
136         "format = (string) " GST_AUDIO_NE (S16) ", "
137         "channels = (int) " G_STRINGIFY (TEST_LAYOUT_CHANNELS) ", "
138         "rate = (int) [ 1,  MAX ], layout = (string) non-interleaved")
139     );
140 
141 typedef enum
142 {
143   GST_AUDIO_TEST_SRC_WAVE_SINE,
144   GST_AUDIO_TEST_SRC_WAVE_SQUARE,
145   GST_AUDIO_TEST_SRC_WAVE_SAW,
146   GST_AUDIO_TEST_SRC_WAVE_TRIANGLE,
147   GST_AUDIO_TEST_SRC_WAVE_SILENCE,
148   GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE,
149   GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE,
150   GST_AUDIO_TEST_SRC_WAVE_SINE_TAB,
151   GST_AUDIO_TEST_SRC_WAVE_TICKS,
152   GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE,
153   GST_AUDIO_TEST_SRC_WAVE_RED_NOISE,
154   GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE,
155   GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE,
156 
157   _GST_AUDIO_TEST_SRC_WAVE_LAST
158 } GstAudioTestSrcWave;
159 
GST_START_TEST(test_layout)160 GST_START_TEST (test_layout)
161 {
162   GstHarness *interleavedsrc, *plannarsrc;
163   GObjectClass *oclass;
164   GParamSpec *property;
165   GEnumValue *values;
166   guint i, j;
167 
168   interleavedsrc = gst_harness_new_with_templates ("audiotestsrc", NULL,
169       &sinktemplate_interleaved);
170   plannarsrc = gst_harness_new_with_templates ("audiotestsrc", NULL,
171       &sinktemplate_planar);
172 
173   gst_harness_use_testclock (interleavedsrc);
174   gst_harness_use_testclock (plannarsrc);
175   g_object_set (interleavedsrc->element, "is-live", TRUE, NULL);
176   g_object_set (plannarsrc->element, "is-live", TRUE, NULL);
177 
178   oclass = G_OBJECT_GET_CLASS (interleavedsrc->element);
179   property = g_object_class_find_property (oclass, "wave");
180   fail_unless (G_IS_PARAM_SPEC_ENUM (property));
181   values = G_ENUM_CLASS (g_type_class_ref (property->value_type))->values;
182 
183   for (j = 0; values[j].value_name; j++) {
184     /* these produce random values by definition,
185      * so we can't compare channels */
186     switch (j) {
187       case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE:
188       case GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE:
189       case GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE:
190       case GST_AUDIO_TEST_SRC_WAVE_RED_NOISE:
191       case GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE:
192       case GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE:
193         continue;
194       default:
195         break;
196     }
197 
198     GST_DEBUG ("layout test with wave %s", values[j].value_name);
199     g_object_set (interleavedsrc->element, "wave", values[j].value, NULL);
200     g_object_set (plannarsrc->element, "wave", values[j].value, NULL);
201 
202     if (j == 0) {
203       GST_DEBUG ("gst_harness_play");
204       gst_harness_play (interleavedsrc);
205       gst_harness_play (plannarsrc);
206     } else {
207       GST_DEBUG ("discarding buffers with old wave");
208       fail_unless (gst_harness_crank_single_clock_wait (interleavedsrc));
209       fail_unless (gst_harness_crank_single_clock_wait (plannarsrc));
210       gst_buffer_unref (gst_harness_pull (interleavedsrc));
211       gst_buffer_unref (gst_harness_pull (plannarsrc));
212     }
213 
214     for (i = 0; i < 10; i++) {
215       GstBuffer *ibuf, *pbuf;
216       GstMapInfo imap, pmap;
217       GstAudioMeta *meta;
218       GstAudioBuffer pabuf;
219       gint16 *iptr, *pptr;
220       guint isamples, psamples, s, c;
221 
222       GST_DEBUG ("waiting on clock");
223       fail_unless (gst_harness_crank_single_clock_wait (interleavedsrc));
224       fail_unless (gst_harness_crank_single_clock_wait (plannarsrc));
225 
226       ibuf = gst_harness_pull (interleavedsrc);
227       pbuf = gst_harness_pull (plannarsrc);
228 
229       gst_buffer_map (ibuf, &imap, GST_MAP_READ);
230       gst_buffer_map (pbuf, &pmap, GST_MAP_READ);
231 
232       /* buffers should have the same size in bytes and in samples */
233       fail_unless_equals_int (imap.size, pmap.size);
234       isamples = imap.size / TEST_LAYOUT_CHANNELS;
235       isamples /= 2;            /* S16 -> 2 bytes per sample */
236       fail_unless_equals_int (imap.size % TEST_LAYOUT_CHANNELS, 0);
237       psamples = pmap.size / TEST_LAYOUT_CHANNELS;
238       psamples /= 2;            /* S16 -> 2 bytes per sample */
239       fail_unless_equals_int (pmap.size % TEST_LAYOUT_CHANNELS, 0);
240       fail_unless_equals_int (isamples, psamples);
241 
242       iptr = (gint16 *) imap.data;
243       pptr = (gint16 *) pmap.data;
244 
245       GST_DEBUG ("verifying contents of buffers; samples=%d, channels=%d",
246           isamples, TEST_LAYOUT_CHANNELS);
247 
248       for (s = 0; s < isamples; s++) {
249         for (c = 0; c < TEST_LAYOUT_CHANNELS; c++) {
250           guint iidx = s * TEST_LAYOUT_CHANNELS + c;
251           guint pidx = c * isamples + s;
252 
253           GST_TRACE ("s = %u | c = %u | iidx (s * channels + c) = %u | "
254               "pidx (c * samples + s) = %u", s, c, iidx, pidx);
255 
256           fail_unless (iidx < imap.size / 2);
257           fail_unless (pidx < pmap.size / 2);
258           fail_unless_equals_int (iptr[iidx], pptr[pidx]);
259         }
260       }
261 
262       gst_buffer_unmap (pbuf, &pmap);
263 
264       GST_DEBUG ("verify that mapping through GstAudioBuffer works the same");
265 
266       meta = gst_buffer_get_audio_meta (pbuf);
267       fail_unless (meta);
268 
269       gst_audio_buffer_map (&pabuf, &meta->info, pbuf, GST_MAP_READ);
270 
271       for (s = 0; s < isamples; s++) {
272         for (c = 0; c < TEST_LAYOUT_CHANNELS; c++) {
273           guint iidx = s * TEST_LAYOUT_CHANNELS + c;
274 
275           fail_unless_equals_int (iptr[iidx], ((gint16 *) pabuf.planes[c])[s]);
276         }
277       }
278 
279       gst_audio_buffer_unmap (&pabuf);
280       gst_buffer_unmap (ibuf, &imap);
281 
282       gst_buffer_unref (ibuf);
283       gst_buffer_unref (pbuf);
284     }
285 
286     /* ensure the audiotestsrcs are not in fill() while we change the wave */
287     fail_unless (gst_harness_wait_for_clock_id_waits (interleavedsrc, 1, 1));
288     fail_unless (gst_harness_wait_for_clock_id_waits (plannarsrc, 1, 1));
289   }
290 
291   /* make sure we ran the test */
292   fail_unless_equals_int (j, _GST_AUDIO_TEST_SRC_WAVE_LAST);
293 
294   gst_harness_teardown (interleavedsrc);
295   gst_harness_teardown (plannarsrc);
296 }
297 
298 GST_END_TEST;
299 
300 static Suite *
audiotestsrc_suite(void)301 audiotestsrc_suite (void)
302 {
303   Suite *s = suite_create ("audiotestsrc");
304   TCase *tc_chain = tcase_create ("general");
305 
306   suite_add_tcase (s, tc_chain);
307   tcase_add_test (tc_chain, test_all_waves);
308   tcase_add_test (tc_chain, test_layout);
309 
310   return s;
311 }
312 
313 GST_CHECK_MAIN (audiotestsrc);
314