1 /* GStreamer
2  *
3  * unit test for the audiocdsrc base class
4  *
5  * Copyright (C) <2005> Tim-Philipp Müller <tim centricular net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /* TODO:
24  *  - test different modes (when seeking to tracks in track mode, buffer
25  *    timestamps should start from 0, when seeking to tracks in disc mode,
26  *    buffer timestamps should increment, etc.)
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <gst/check/gstcheck.h>
34 #include <gst/check/gstbufferstraw.h>
35 
36 #include <gst/audio/gstaudiocdsrc.h>
37 #include <string.h>
38 
39 #define CD_FRAMESIZE_RAW 2352
40 
41 #define GST_TYPE_CD_FOO_SRC            (gst_cd_foo_src_get_type())
42 #define GST_CD_FOO_SRC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CD_FOO_SRC,GstCdFooSrc))
43 #define GST_CD_FOO_SRC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CD_FOO_SRC,GstCdFooSrcClass))
44 #define GST_IS_CD_FOO_SRC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CD_FOO_SRC))
45 #define GST_IS_CD_FOO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CD_FOO_SRC))
46 #define GST_CD_FOO_SRC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CDDA_BASAE_SRC, GstCdFooSrcClass))
47 
48 typedef struct _GstCdFooSrc GstCdFooSrc;
49 typedef struct _GstCdFooSrcClass GstCdFooSrcClass;
50 
51 
52 /* Neue Heimat (CD 2) */
53 static GstAudioCdSrcTrack nh_cd2_tracks[] = {
54   {TRUE, 1, 0, 20664, NULL,},
55   {TRUE, 2, 20665, 52377, NULL,},
56   {TRUE, 3, 52378, 84100, NULL,},
57   {TRUE, 4, 84101, 105401, NULL,},
58   {TRUE, 5, 105402, 123060, NULL,},
59   {TRUE, 6, 123061, 146497, NULL,},
60   {TRUE, 7, 146498, 175693, NULL,},
61   {TRUE, 8, 175694, 203272, NULL,},
62   {TRUE, 9, 203273, 217909, NULL,},
63   {TRUE, 10, 217910, 240938, NULL,},
64   {TRUE, 11, 240939, 256169, NULL,},
65   {TRUE, 12, 256170, 282237, NULL,},
66   {TRUE, 13, 282238, 307606, NULL,},
67   {TRUE, 14, 307607, 337245, NULL,}
68 };
69 
70 /* Offspring - Smash */
71 static GstAudioCdSrcTrack offspring_tracks[] = {
72   {TRUE, 1, 0, 1924, NULL,},
73   {TRUE, 2, 1925, 12947, NULL,},
74   {TRUE, 3, 12948, 29739, NULL,},
75   {TRUE, 4, 29740, 47202, NULL,},
76   {TRUE, 5, 47203, 63134, NULL,},
77   {TRUE, 6, 63135, 77954, NULL,},
78   {TRUE, 7, 77955, 92789, NULL,},
79   {TRUE, 8, 92790, 112127, NULL,},
80   {TRUE, 9, 112128, 124372, NULL,},
81   {TRUE, 10, 124373, 133574, NULL,},
82   {TRUE, 11, 133575, 143484, NULL,},
83   {TRUE, 12, 143485, 149279, NULL,},
84   {TRUE, 13, 149280, 162357, NULL,},
85   {TRUE, 14, 162358, 210372, NULL,}
86 };
87 
88 /* this matches the sample TOC from the DiscIDCalculation
89  * page in the Musicbrainz wiki. It's a tricky one because
90  * it's got a data track as well. */
91 static GstAudioCdSrcTrack mb_sample_tracks[] = {
92   {TRUE, 1, 0, 18640, NULL,},
93   {TRUE, 2, 18641, 34666, NULL,},
94   {TRUE, 3, 34667, 56349, NULL,},
95   {TRUE, 4, 56350, 77005, NULL,},
96   {TRUE, 5, 77006, 106093, NULL,},
97   {TRUE, 6, 106094, 125728, NULL,},
98   {TRUE, 7, 125729, 149784, NULL,},
99   {TRUE, 8, 149785, 168884, NULL,},
100   {TRUE, 9, 168885, 185909, NULL,},
101   {TRUE, 10, 185910, 205828, NULL,},
102   {TRUE, 11, 205829, 230141, NULL,},
103   {TRUE, 12, 230142, 246658, NULL,},
104   {TRUE, 13, 246659, 265613, NULL,},
105   {TRUE, 14, 265614, 289478, NULL,},
106   {FALSE, 15, 289479, 325731, NULL,}
107 };
108 
109 /* Nicola Conte - Other Directions (also
110  * tricky due to the extra data track) */
111 static GstAudioCdSrcTrack nconte_odir_tracks[] = {
112   {TRUE, 1, 0, 17852, NULL,},
113   {TRUE, 2, 17853, 39956, NULL,},
114   {TRUE, 3, 39957, 68449, NULL,},
115   {TRUE, 4, 68450, 88725, NULL,},
116   {TRUE, 5, 88726, 106413, NULL,},
117   {TRUE, 6, 106414, 131966, NULL,},
118   {TRUE, 7, 131967, 152372, NULL,},
119   {TRUE, 8, 152373, 168602, NULL,},
120   {TRUE, 9, 168603, 190348, NULL,},
121   {TRUE, 10, 190349, 209044, NULL,},
122   {TRUE, 11, 209045, 235586, NULL,},
123   {TRUE, 12, 235587, 253830, NULL,},
124   {TRUE, 13, 253831, 272213, NULL,},
125   {FALSE, 14, 272214, 332849, NULL,}
126 };
127 
128 /* Pink Martini - Sympathique (11 track version) */
129 static GstAudioCdSrcTrack pm_symp_tracks[] = {
130   {TRUE, 1, 0, 21667, NULL,},
131   {TRUE, 2, 21668, 49576, NULL,},
132   {TRUE, 3, 49577, 62397, NULL,},
133   {TRUE, 4, 62398, 81087, NULL,},
134   {TRUE, 5, 81088, 106595, NULL,},
135   {TRUE, 6, 106596, 122012, NULL,},
136   {TRUE, 7, 122013, 138469, NULL,},
137   {TRUE, 8, 138470, 157306, NULL,},
138   {TRUE, 9, 157307, 179635, NULL,},
139   {TRUE, 10, 179636, 203673, NULL,},
140   {TRUE, 11, 203674, 213645, NULL,}
141 };
142 
143 #define NUM_TEST_DISCS 5
144 
145 struct _test_disc
146 {
147   GstAudioCdSrcTrack *tracks;
148   guint num_tracks;
149   guint32 cddb_discid;
150   const gchar *musicbrainz_discid;
151 };
152 
153 /* FIXME: now we just need to find out how to treat
154  * data tracks for the cddb id calculation .... */
155 static struct _test_disc test_discs[NUM_TEST_DISCS] = {
156   {nh_cd2_tracks, G_N_ELEMENTS (nh_cd2_tracks), 0xae11900e,
157       NULL},
158   {mb_sample_tracks, G_N_ELEMENTS (mb_sample_tracks), 0x00000000,
159       "MUtMmKN402WPj3_VFsgUelxpc8U-"},
160   {offspring_tracks, G_N_ELEMENTS (offspring_tracks), 0xc20af40e,
161       "ahg7JUcfR3vCYBphSDIogOOWrr0-"},
162   {nconte_odir_tracks, G_N_ELEMENTS (nconte_odir_tracks), 0x00000000,
163         /* hKx_PejjG47X161ND_Sh0HyqaS0- according to libmusicbrainz, but that's
164          * wrong according to the wiki docs (or not?) (neither discid is listed) */
165       "fboaOQtfqwENv8WyXa9tRyvyUbQ-"},
166   {pm_symp_tracks, G_N_ELEMENTS (pm_symp_tracks), 0xa00b200b,
167       "iP0DOLdr4vt_IfKSIXoRUR.q_Wc-"}
168 };
169 
170 struct _GstCdFooSrc
171 {
172   GstAudioCdSrc audiocdsrc;
173 
174   struct _test_disc *cur_test;
175   guint cur_disc;
176 };
177 
178 struct _GstCdFooSrcClass
179 {
180   GstAudioCdSrcClass parent_class;
181 };
182 
183 GType gst_cd_foo_src_get_type (void);
184 G_DEFINE_TYPE (GstCdFooSrc, gst_cd_foo_src, GST_TYPE_AUDIO_CD_SRC);
185 
186 static GstBuffer *gst_cd_foo_src_read_sector (GstAudioCdSrc * src, gint sector);
187 static gboolean gst_cd_foo_src_open (GstAudioCdSrc * src, const gchar * device);
188 static void gst_cd_foo_src_close (GstAudioCdSrc * src);
189 
190 static void
gst_cd_foo_src_init(GstCdFooSrc * src)191 gst_cd_foo_src_init (GstCdFooSrc * src)
192 {
193   src->cur_disc = 0;
194 }
195 
196 static void
gst_cd_foo_src_class_init(GstCdFooSrcClass * klass)197 gst_cd_foo_src_class_init (GstCdFooSrcClass * klass)
198 {
199   GstAudioCdSrcClass *audiocdsrc_class = GST_AUDIO_CD_SRC_CLASS (klass);
200   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
201 
202   gst_element_class_set_metadata (element_class,
203       "CD Audio (cdda) Source, FooBar", "Source/File",
204       "Read audio from CD", "Foo Bar <foo@bar.com>");
205 
206   audiocdsrc_class->open = gst_cd_foo_src_open;
207   audiocdsrc_class->close = gst_cd_foo_src_close;
208   audiocdsrc_class->read_sector = gst_cd_foo_src_read_sector;
209 }
210 
211 static gboolean
gst_cd_foo_src_open(GstAudioCdSrc * audiocdsrc,const gchar * device)212 gst_cd_foo_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device)
213 {
214   GstAudioCdSrcTrack *tracks;
215   GstCdFooSrc *src;
216   gint i;
217 
218   src = GST_CD_FOO_SRC (audiocdsrc);
219 
220   /* if this fails, the test is wrong */
221   g_assert (src->cur_disc < NUM_TEST_DISCS);
222 
223   src->cur_test = &test_discs[src->cur_disc];
224 
225   /* add tracks */
226   tracks = src->cur_test->tracks;
227   for (i = 0; i < src->cur_test->num_tracks; ++i) {
228     gst_audio_cd_src_add_track (GST_AUDIO_CD_SRC (src), &tracks[i]);
229   }
230 
231   return TRUE;
232 }
233 
234 static void
gst_cd_foo_src_close(GstAudioCdSrc * audiocdsrc)235 gst_cd_foo_src_close (GstAudioCdSrc * audiocdsrc)
236 {
237   GstCdFooSrc *src = GST_CD_FOO_SRC (audiocdsrc);
238 
239   if (src->cur_test->cddb_discid != 0) {
240     GST_FIXME ("Fix DISCID comparison: extract discid");
241 #if 0
242     g_assert (audiocdsrc->discid == src->cur_test->cddb_discid);
243 #endif
244   }
245 
246   if (src->cur_test->musicbrainz_discid != NULL) {
247     GST_FIXME ("Fix MB DISCID comparison: extract musicbrainz discid");
248 #if 0
249     g_assert (g_str_equal (audiocdsrc->mb_discid,
250             src->cur_test->musicbrainz_discid));
251 #endif
252   }
253 }
254 
255 static GstBuffer *
gst_cd_foo_src_read_sector(GstAudioCdSrc * audiocdsrc,gint sector)256 gst_cd_foo_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector)
257 {
258   GstBuffer *buf;
259 
260   buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
261   gst_buffer_memset (buf, 0, 0, CD_FRAMESIZE_RAW);
262 
263   return buf;
264 }
265 
266 static inline gboolean
tag_list_has_tag(GstTagList * list,const gchar * tag,GType type)267 tag_list_has_tag (GstTagList * list, const gchar * tag, GType type)
268 {
269   const GValue *val = gst_tag_list_get_value_index (list, tag, 0);
270 
271   if (val == NULL) {
272     GST_LOG ("no tag '%s' in taglist %" GST_PTR_FORMAT, tag, list);
273     return FALSE;
274   }
275 
276   if (!G_VALUE_HOLDS (val, type)) {
277     GST_LOG ("tag '%s' in taglist %" GST_PTR_FORMAT " is not of type %s",
278         tag, list, g_type_name (type));
279     return FALSE;
280   }
281 
282   return TRUE;
283 }
284 
285 static void
test_uri_parse(const gchar * uri,const gchar * device,gint track)286 test_uri_parse (const gchar * uri, const gchar * device, gint track)
287 {
288   GstElement *foosrc;
289   gchar *set_device = NULL;
290   gint set_track = 0;
291 
292   foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
293   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc), uri, NULL),
294       "couldn't set uri %s", uri);
295   g_object_get (foosrc, "device", &set_device, "track", &set_track, NULL);
296   fail_unless (set_device != NULL);
297   fail_unless (strcmp (set_device, device) == 0,
298       "device set was %s, expected %s", set_device, device);
299   fail_unless (set_track == track, "track set was %d, expected %d", set_track,
300       track);
301   g_free (set_device);
302   gst_object_unref (foosrc);
303 }
304 
GST_START_TEST(test_discid_calculations)305 GST_START_TEST (test_discid_calculations)
306 {
307   GstElement *foosrc, *pipeline, *sink;
308   gint i;
309 
310   fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
311           GST_TYPE_CD_FOO_SRC));
312 
313   pipeline = gst_pipeline_new ("pipeline");
314 
315   sink = gst_element_factory_make ("fakesink", "sink");
316   fail_unless (sink != NULL, "couldn't create fakesink");
317 
318   foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
319   fail_unless (foosrc != NULL, "couldn't create cdfoosrc");
320 
321   gst_bin_add (GST_BIN (pipeline), foosrc);
322   gst_bin_add (GST_BIN (pipeline), sink);
323   fail_unless (gst_element_link (foosrc, sink));
324 
325   for (i = 0; i < G_N_ELEMENTS (test_discs); ++i) {
326     GstTagList *tags = NULL;
327     GstMessage *msg;
328 
329     GST_LOG ("Testing disc layout %u ...", i);
330     GST_CD_FOO_SRC (foosrc)->cur_disc = i;
331     gst_element_set_state (pipeline, GST_STATE_PLAYING);
332 
333     msg =
334         gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
335         GST_CLOCK_TIME_NONE, GST_MESSAGE_TAG);
336     gst_message_parse_tag (msg, &tags);
337     fail_unless (tags != NULL);
338     fail_unless (tag_list_has_tag (tags, "track-count", G_TYPE_UINT));
339     fail_unless (tag_list_has_tag (tags, "track-number", G_TYPE_UINT));
340     fail_unless (tag_list_has_tag (tags, "duration", G_TYPE_UINT64));
341     fail_unless (tag_list_has_tag (tags, "discid", G_TYPE_STRING));
342     fail_unless (tag_list_has_tag (tags, "discid-full", G_TYPE_STRING));
343     fail_unless (tag_list_has_tag (tags, "musicbrainz-discid", G_TYPE_STRING));
344     fail_unless (tag_list_has_tag (tags, "musicbrainz-discid-full",
345             G_TYPE_STRING));
346     gst_tag_list_unref (tags);
347     gst_message_unref (msg);
348 
349     msg =
350         gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
351         GST_CLOCK_TIME_NONE, GST_MESSAGE_ASYNC_DONE);
352     gst_message_unref (msg);
353 
354     gst_element_set_state (pipeline, GST_STATE_NULL);
355   }
356 
357   gst_object_unref (pipeline);
358 
359   gst_task_cleanup_all ();
360 }
361 
362 GST_END_TEST;
363 
GST_START_TEST(test_buffer_timestamps)364 GST_START_TEST (test_buffer_timestamps)
365 {
366   GstElement *foosrc, *pipeline, *fakesink;
367   GstClockTime prev_ts, prev_duration, ts;
368   GstPad *sinkpad;
369   gint i;
370 
371   fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
372           GST_TYPE_CD_FOO_SRC));
373 
374   pipeline = gst_pipeline_new ("pipeline");
375   foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
376   fakesink = gst_element_factory_make ("fakesink", "fakesink");
377   gst_bin_add_many (GST_BIN (pipeline), foosrc, fakesink, NULL);
378   fail_unless (gst_element_link (foosrc, fakesink));
379   sinkpad = gst_element_get_static_pad (fakesink, "sink");
380 
381   GST_CD_FOO_SRC (foosrc)->cur_disc = 0;
382 
383   gst_buffer_straw_start_pipeline (pipeline, sinkpad);
384 
385   prev_ts = GST_CLOCK_TIME_NONE;
386   prev_duration = GST_CLOCK_TIME_NONE;
387 
388   for (i = 0; i < 100; ++i) {
389     GstBuffer *buf;
390 
391     buf = gst_buffer_straw_get_buffer (pipeline, sinkpad);
392     GST_LOG ("buffer, ts=%" GST_TIME_FORMAT ", dur=%" GST_TIME_FORMAT,
393         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
394         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
395     ts = GST_BUFFER_TIMESTAMP (buf);
396     fail_unless (GST_CLOCK_TIME_IS_VALID (ts));
397     fail_unless (GST_BUFFER_DURATION_IS_VALID (buf));
398     if (i > 0) {
399       fail_unless (GST_CLOCK_TIME_IS_VALID (prev_ts));
400       fail_unless (GST_CLOCK_TIME_IS_VALID (prev_duration));
401       fail_unless ((prev_ts + prev_duration) == ts);
402     }
403     prev_ts = ts;
404     prev_duration = GST_BUFFER_DURATION (buf);
405     gst_buffer_unref (buf);
406   }
407 
408   gst_buffer_straw_stop_pipeline (pipeline, sinkpad);
409 
410   gst_task_cleanup_all ();
411   gst_object_unref (pipeline);
412   gst_object_unref (sinkpad);
413 }
414 
415 GST_END_TEST;
416 
GST_START_TEST(test_uri_parsing)417 GST_START_TEST (test_uri_parsing)
418 {
419   GstElement *foosrc;
420 
421   fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
422           GST_TYPE_CD_FOO_SRC));
423 
424   /* wrong protocol */
425   foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
426   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
427           "xyz://", NULL) == FALSE);
428   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
429           "cddaq://", NULL) == FALSE);
430 
431   /* cdda://track */
432   test_uri_parse ("cdda://", "/dev/cdrom", 1);
433   test_uri_parse ("cdda://2", "/dev/cdrom", 2);
434   test_uri_parse ("cdda://47", "/dev/cdrom", 47);
435   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
436           "cdda://-1", NULL) == FALSE);
437   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
438           "cdda://what", NULL) == FALSE);
439 
440   /* cdda://device#track */
441   test_uri_parse ("cdda:///dev/hdb#1", "/dev/hdb", 1);
442   test_uri_parse ("cdda://anything#8", "anything", 8);
443   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
444           "cdda:///dev/hdb#nonsense", NULL) == FALSE);
445   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
446           "cdda:///dev/hdb#-2", NULL) == FALSE);
447 
448   /* cdda://track#device (device should be ignored - FIXME 0.11) */
449   test_uri_parse ("cdda://8#/dev/hdb", "/dev/cdrom", 8);
450 
451   gst_object_unref (foosrc);
452 }
453 
454 GST_END_TEST;
455 
GST_START_TEST(test_properties)456 GST_START_TEST (test_properties)
457 {
458   GstElement *foosrc;
459   gchar *device;
460   guint track;
461 
462   fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
463           GST_TYPE_CD_FOO_SRC));
464 
465   foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
466 
467   g_object_set (foosrc, "device", "/dev/cdrom", NULL);
468   g_object_get (foosrc, "device", &device, "track", &track, NULL);
469   fail_unless (g_str_equal (device, "/dev/cdrom"));
470   fail_unless_equals_int (track, 1);
471   g_free (device);
472 
473   g_object_set (foosrc, "device", "/dev/cdrom1", "track", 17, NULL);
474   g_object_get (foosrc, "device", &device, "track", &track, NULL);
475   fail_unless (g_str_equal (device, "/dev/cdrom1"));
476   fail_unless_equals_int (track, 17);
477   g_free (device);
478 
479   g_object_set (foosrc, "track", 17, "device", "/dev/cdrom1", NULL);
480   g_object_get (foosrc, "device", &device, "track", &track, NULL);
481   fail_unless (g_str_equal (device, "/dev/cdrom1"));
482   fail_unless_equals_int (track, 17);
483   g_free (device);
484 
485   g_object_set (foosrc, "track", 12, NULL);
486   g_object_get (foosrc, "device", &device, "track", &track, NULL);
487   fail_unless (g_str_equal (device, "/dev/cdrom1"));
488   fail_unless_equals_int (track, 12);
489   g_free (device);
490 
491   gst_object_unref (foosrc);
492 }
493 
494 GST_END_TEST;
495 
496 static Suite *
audiocdsrc_suite(void)497 audiocdsrc_suite (void)
498 {
499   Suite *s = suite_create ("audiocdsrc");
500   TCase *tc_chain = tcase_create ("general");
501 
502   suite_add_tcase (s, tc_chain);
503   tcase_add_test (tc_chain, test_discid_calculations);
504   tcase_add_test (tc_chain, test_buffer_timestamps);
505   tcase_add_test (tc_chain, test_uri_parsing);
506   tcase_add_test (tc_chain, test_properties);
507 
508   return s;
509 }
510 
511 GST_CHECK_MAIN (audiocdsrc)
512