audiocdsrc.c 15.8 KB
Newer Older
1 2
/* GStreamer
 *
3
 * unit test for the audiocdsrc base class
4
 *
5
 * Copyright (C) <2005> Tim-Philipp Müller <tim centricular net>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

23 24 25 26 27 28
/* TODO:
 *  - test different modes (when seeking to tracks in track mode, buffer
 *    timestamps should start from 0, when seeking to tracks in disc mode,
 *    buffer timestamps should increment, etc.)
 */

29 30 31 32 33 34 35
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <unistd.h>

#include <gst/check/gstcheck.h>
36
#include <gst/check/gstbufferstraw.h>
37

38
#include <gst/audio/gstaudiocdsrc.h>
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include <string.h>

#define CD_FRAMESIZE_RAW 2352

#define GST_TYPE_CD_FOO_SRC            (gst_cd_foo_src_get_type())
#define GST_CD_FOO_SRC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CD_FOO_SRC,GstCdFooSrc))
#define GST_CD_FOO_SRC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CD_FOO_SRC,GstCdFooSrcClass))
#define GST_IS_CD_FOO_SRC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CD_FOO_SRC))
#define GST_IS_CD_FOO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CD_FOO_SRC))
#define GST_CD_FOO_SRC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CDDA_BASAE_SRC, GstCdFooSrcClass))

typedef struct _GstCdFooSrc GstCdFooSrc;
typedef struct _GstCdFooSrcClass GstCdFooSrcClass;


/* Neue Heimat (CD 2) */
55
static GstAudioCdSrcTrack nh_cd2_tracks[] = {
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  {TRUE, 1, 0, 20664, NULL,},
  {TRUE, 2, 20665, 52377, NULL,},
  {TRUE, 3, 52378, 84100, NULL,},
  {TRUE, 4, 84101, 105401, NULL,},
  {TRUE, 5, 105402, 123060, NULL,},
  {TRUE, 6, 123061, 146497, NULL,},
  {TRUE, 7, 146498, 175693, NULL,},
  {TRUE, 8, 175694, 203272, NULL,},
  {TRUE, 9, 203273, 217909, NULL,},
  {TRUE, 10, 217910, 240938, NULL,},
  {TRUE, 11, 240939, 256169, NULL,},
  {TRUE, 12, 256170, 282237, NULL,},
  {TRUE, 13, 282238, 307606, NULL,},
  {TRUE, 14, 307607, 337245, NULL,}
};

/* Offspring - Smash */
73
static GstAudioCdSrcTrack offspring_tracks[] = {
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  {TRUE, 1, 0, 1924, NULL,},
  {TRUE, 2, 1925, 12947, NULL,},
  {TRUE, 3, 12948, 29739, NULL,},
  {TRUE, 4, 29740, 47202, NULL,},
  {TRUE, 5, 47203, 63134, NULL,},
  {TRUE, 6, 63135, 77954, NULL,},
  {TRUE, 7, 77955, 92789, NULL,},
  {TRUE, 8, 92790, 112127, NULL,},
  {TRUE, 9, 112128, 124372, NULL,},
  {TRUE, 10, 124373, 133574, NULL,},
  {TRUE, 11, 133575, 143484, NULL,},
  {TRUE, 12, 143485, 149279, NULL,},
  {TRUE, 13, 149280, 162357, NULL,},
  {TRUE, 14, 162358, 210372, NULL,}
};

/* this matches the sample TOC from the DiscIDCalculation
 * page in the Musicbrainz wiki. It's a tricky one because
 * it's got a data track as well. */
93
static GstAudioCdSrcTrack mb_sample_tracks[] = {
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
  {TRUE, 1, 0, 18640, NULL,},
  {TRUE, 2, 18641, 34666, NULL,},
  {TRUE, 3, 34667, 56349, NULL,},
  {TRUE, 4, 56350, 77005, NULL,},
  {TRUE, 5, 77006, 106093, NULL,},
  {TRUE, 6, 106094, 125728, NULL,},
  {TRUE, 7, 125729, 149784, NULL,},
  {TRUE, 8, 149785, 168884, NULL,},
  {TRUE, 9, 168885, 185909, NULL,},
  {TRUE, 10, 185910, 205828, NULL,},
  {TRUE, 11, 205829, 230141, NULL,},
  {TRUE, 12, 230142, 246658, NULL,},
  {TRUE, 13, 246659, 265613, NULL,},
  {TRUE, 14, 265614, 289478, NULL,},
  {FALSE, 15, 289479, 325731, NULL,}
};

/* Nicola Conte - Other Directions (also
 * tricky due to the extra data track) */
113
static GstAudioCdSrcTrack nconte_odir_tracks[] = {
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  {TRUE, 1, 0, 17852, NULL,},
  {TRUE, 2, 17853, 39956, NULL,},
  {TRUE, 3, 39957, 68449, NULL,},
  {TRUE, 4, 68450, 88725, NULL,},
  {TRUE, 5, 88726, 106413, NULL,},
  {TRUE, 6, 106414, 131966, NULL,},
  {TRUE, 7, 131967, 152372, NULL,},
  {TRUE, 8, 152373, 168602, NULL,},
  {TRUE, 9, 168603, 190348, NULL,},
  {TRUE, 10, 190349, 209044, NULL,},
  {TRUE, 11, 209045, 235586, NULL,},
  {TRUE, 12, 235587, 253830, NULL,},
  {TRUE, 13, 253831, 272213, NULL,},
  {FALSE, 14, 272214, 332849, NULL,}
};

/* Pink Martini - Sympathique (11 track version) */
131
static GstAudioCdSrcTrack pm_symp_tracks[] = {
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
  {TRUE, 1, 0, 21667, NULL,},
  {TRUE, 2, 21668, 49576, NULL,},
  {TRUE, 3, 49577, 62397, NULL,},
  {TRUE, 4, 62398, 81087, NULL,},
  {TRUE, 5, 81088, 106595, NULL,},
  {TRUE, 6, 106596, 122012, NULL,},
  {TRUE, 7, 122013, 138469, NULL,},
  {TRUE, 8, 138470, 157306, NULL,},
  {TRUE, 9, 157307, 179635, NULL,},
  {TRUE, 10, 179636, 203673, NULL,},
  {TRUE, 11, 203674, 213645, NULL,}
};

#define NUM_TEST_DISCS 5

struct _test_disc
{
149
  GstAudioCdSrcTrack *tracks;
150 151 152 153 154 155 156
  guint num_tracks;
  guint32 cddb_discid;
  const gchar *musicbrainz_discid;
};

/* FIXME: now we just need to find out how to treat
 * data tracks for the cddb id calculation .... */
157
static struct _test_disc test_discs[NUM_TEST_DISCS] = {
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  {nh_cd2_tracks, G_N_ELEMENTS (nh_cd2_tracks), 0xae11900e,
      NULL},
  {mb_sample_tracks, G_N_ELEMENTS (mb_sample_tracks), 0x00000000,
      "MUtMmKN402WPj3_VFsgUelxpc8U-"},
  {offspring_tracks, G_N_ELEMENTS (offspring_tracks), 0xc20af40e,
      "ahg7JUcfR3vCYBphSDIogOOWrr0-"},
  {nconte_odir_tracks, G_N_ELEMENTS (nconte_odir_tracks), 0x00000000,
        /* hKx_PejjG47X161ND_Sh0HyqaS0- according to libmusicbrainz, but that's
         * wrong according to the wiki docs (or not?) (neither discid is listed) */
      "fboaOQtfqwENv8WyXa9tRyvyUbQ-"},
  {pm_symp_tracks, G_N_ELEMENTS (pm_symp_tracks), 0xa00b200b,
      "iP0DOLdr4vt_IfKSIXoRUR.q_Wc-"}
};

struct _GstCdFooSrc
{
174
  GstAudioCdSrc audiocdsrc;
175 176 177 178 179 180 181

  struct _test_disc *cur_test;
  guint cur_disc;
};

struct _GstCdFooSrcClass
{
182
  GstAudioCdSrcClass parent_class;
183 184
};

185
GType gst_cd_foo_src_get_type (void);
186
G_DEFINE_TYPE (GstCdFooSrc, gst_cd_foo_src, GST_TYPE_AUDIO_CD_SRC);
187

188 189 190
static GstBuffer *gst_cd_foo_src_read_sector (GstAudioCdSrc * src, gint sector);
static gboolean gst_cd_foo_src_open (GstAudioCdSrc * src, const gchar * device);
static void gst_cd_foo_src_close (GstAudioCdSrc * src);
191 192

static void
193
gst_cd_foo_src_init (GstCdFooSrc * src)
194 195 196 197 198 199 200
{
  src->cur_disc = 0;
}

static void
gst_cd_foo_src_class_init (GstCdFooSrcClass * klass)
{
201
  GstAudioCdSrcClass *audiocdsrc_class = GST_AUDIO_CD_SRC_CLASS (klass);
202 203
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

204
  gst_element_class_set_metadata (element_class,
205 206
      "CD Audio (cdda) Source, FooBar", "Source/File",
      "Read audio from CD", "Foo Bar <foo@bar.com>");
207

208 209 210
  audiocdsrc_class->open = gst_cd_foo_src_open;
  audiocdsrc_class->close = gst_cd_foo_src_close;
  audiocdsrc_class->read_sector = gst_cd_foo_src_read_sector;
211 212 213
}

static gboolean
214
gst_cd_foo_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device)
215
{
216
  GstAudioCdSrcTrack *tracks;
217 218 219
  GstCdFooSrc *src;
  gint i;

220
  src = GST_CD_FOO_SRC (audiocdsrc);
221 222 223 224 225 226 227 228 229

  /* if this fails, the test is wrong */
  g_assert (src->cur_disc < NUM_TEST_DISCS);

  src->cur_test = &test_discs[src->cur_disc];

  /* add tracks */
  tracks = src->cur_test->tracks;
  for (i = 0; i < src->cur_test->num_tracks; ++i) {
230
    gst_audio_cd_src_add_track (GST_AUDIO_CD_SRC (src), &tracks[i]);
231 232 233 234 235 236
  }

  return TRUE;
}

static void
237
gst_cd_foo_src_close (GstAudioCdSrc * audiocdsrc)
238
{
239
  GstCdFooSrc *src = GST_CD_FOO_SRC (audiocdsrc);
240 241

  if (src->cur_test->cddb_discid != 0) {
242 243
    GST_FIXME ("Fix DISCID comparison: extract discid");
#if 0
244
    g_assert (audiocdsrc->discid == src->cur_test->cddb_discid);
245
#endif
246 247 248
  }

  if (src->cur_test->musicbrainz_discid != NULL) {
249 250
    GST_FIXME ("Fix MB DISCID comparison: extract musicbrainz discid");
#if 0
251
    g_assert (g_str_equal (audiocdsrc->mb_discid,
252
            src->cur_test->musicbrainz_discid));
253
#endif
254 255 256 257
  }
}

static GstBuffer *
258
gst_cd_foo_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector)
259 260 261 262
{
  GstBuffer *buf;

  buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
Wim Taymans's avatar
Wim Taymans committed
263
  gst_buffer_memset (buf, 0, 0, CD_FRAMESIZE_RAW);
264 265 266 267

  return buf;
}

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
static inline gboolean
tag_list_has_tag (GstTagList * list, const gchar * tag, GType type)
{
  const GValue *val = gst_tag_list_get_value_index (list, tag, 0);

  if (val == NULL) {
    GST_LOG ("no tag '%s' in taglist %" GST_PTR_FORMAT, tag, list);
    return FALSE;
  }

  if (!G_VALUE_HOLDS (val, type)) {
    GST_LOG ("tag '%s' in taglist %" GST_PTR_FORMAT " is not of type %s",
        tag, list, g_type_name (type));
    return FALSE;
  }

  return TRUE;
}

287
static void
288
test_uri_parse (const gchar * uri, const gchar * device, gint track)
289 290
{
  GstElement *foosrc;
291 292
  gchar *set_device = NULL;
  gint set_track = 0;
293 294

  foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
295
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc), uri, NULL),
296 297
      "couldn't set uri %s", uri);
  g_object_get (foosrc, "device", &set_device, "track", &set_track, NULL);
298
  fail_unless (set_device != NULL);
299 300 301 302
  fail_unless (strcmp (set_device, device) == 0,
      "device set was %s, expected %s", set_device, device);
  fail_unless (set_track == track, "track set was %d, expected %d", set_track,
      track);
303
  g_free (set_device);
304 305 306
  gst_object_unref (foosrc);
}

307
GST_START_TEST (test_discid_calculations)
308
{
309
  GstElement *foosrc, *pipeline, *sink;
310 311
  gint i;

312 313 314
  fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
          GST_TYPE_CD_FOO_SRC));

315 316 317 318 319
  pipeline = gst_pipeline_new ("pipeline");

  sink = gst_element_factory_make ("fakesink", "sink");
  fail_unless (sink != NULL, "couldn't create fakesink");

320
  foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
321 322 323 324 325
  fail_unless (foosrc != NULL, "couldn't create cdfoosrc");

  gst_bin_add (GST_BIN (pipeline), foosrc);
  gst_bin_add (GST_BIN (pipeline), sink);
  fail_unless (gst_element_link (foosrc, sink));
326 327

  for (i = 0; i < G_N_ELEMENTS (test_discs); ++i) {
328 329 330
    GstTagList *tags = NULL;
    GstMessage *msg;

331
    GST_LOG ("Testing disc layout %u ...", i);
332
    GST_CD_FOO_SRC (foosrc)->cur_disc = i;
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    msg =
        gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
        GST_CLOCK_TIME_NONE, GST_MESSAGE_TAG);
    gst_message_parse_tag (msg, &tags);
    fail_unless (tags != NULL);
    fail_unless (tag_list_has_tag (tags, "track-count", G_TYPE_UINT));
    fail_unless (tag_list_has_tag (tags, "track-number", G_TYPE_UINT));
    fail_unless (tag_list_has_tag (tags, "duration", G_TYPE_UINT64));
    fail_unless (tag_list_has_tag (tags, "discid", G_TYPE_STRING));
    fail_unless (tag_list_has_tag (tags, "discid-full", G_TYPE_STRING));
    fail_unless (tag_list_has_tag (tags, "musicbrainz-discid", G_TYPE_STRING));
    fail_unless (tag_list_has_tag (tags, "musicbrainz-discid-full",
            G_TYPE_STRING));
348
    gst_tag_list_unref (tags);
349 350
    gst_message_unref (msg);

351 352 353 354 355
    msg =
        gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
        GST_CLOCK_TIME_NONE, GST_MESSAGE_ASYNC_DONE);
    gst_message_unref (msg);

356
    gst_element_set_state (pipeline, GST_STATE_NULL);
357 358
  }

359
  gst_object_unref (pipeline);
360 361

  gst_task_cleanup_all ();
362 363 364 365
}

GST_END_TEST;

366 367 368 369 370 371 372
GST_START_TEST (test_buffer_timestamps)
{
  GstElement *foosrc, *pipeline, *fakesink;
  GstClockTime prev_ts, prev_duration, ts;
  GstPad *sinkpad;
  gint i;

373 374 375
  fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
          GST_TYPE_CD_FOO_SRC));

376 377 378 379 380
  pipeline = gst_pipeline_new ("pipeline");
  foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
  fakesink = gst_element_factory_make ("fakesink", "fakesink");
  gst_bin_add_many (GST_BIN (pipeline), foosrc, fakesink, NULL);
  fail_unless (gst_element_link (foosrc, fakesink));
381
  sinkpad = gst_element_get_static_pad (fakesink, "sink");
382 383 384 385 386

  GST_CD_FOO_SRC (foosrc)->cur_disc = 0;

  gst_buffer_straw_start_pipeline (pipeline, sinkpad);

387 388 389
  prev_ts = GST_CLOCK_TIME_NONE;
  prev_duration = GST_CLOCK_TIME_NONE;

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
  for (i = 0; i < 100; ++i) {
    GstBuffer *buf;

    buf = gst_buffer_straw_get_buffer (pipeline, sinkpad);
    GST_LOG ("buffer, ts=%" GST_TIME_FORMAT ", dur=%" GST_TIME_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
    ts = GST_BUFFER_TIMESTAMP (buf);
    fail_unless (GST_CLOCK_TIME_IS_VALID (ts));
    fail_unless (GST_BUFFER_DURATION_IS_VALID (buf));
    if (i > 0) {
      fail_unless (GST_CLOCK_TIME_IS_VALID (prev_ts));
      fail_unless (GST_CLOCK_TIME_IS_VALID (prev_duration));
      fail_unless ((prev_ts + prev_duration) == ts);
    }
    prev_ts = ts;
    prev_duration = GST_BUFFER_DURATION (buf);
    gst_buffer_unref (buf);
  }

  gst_buffer_straw_stop_pipeline (pipeline, sinkpad);

412
  gst_task_cleanup_all ();
413 414 415 416 417 418
  gst_object_unref (pipeline);
  gst_object_unref (sinkpad);
}

GST_END_TEST;

419 420 421 422 423 424 425 426 427 428
GST_START_TEST (test_uri_parsing)
{
  GstElement *foosrc;

  fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
          GST_TYPE_CD_FOO_SRC));

  /* wrong protocol */
  foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
429
          "xyz://", NULL) == FALSE);
430
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
431
          "cddaq://", NULL) == FALSE);
432 433 434 435 436 437

  /* cdda://track */
  test_uri_parse ("cdda://", "/dev/cdrom", 1);
  test_uri_parse ("cdda://2", "/dev/cdrom", 2);
  test_uri_parse ("cdda://47", "/dev/cdrom", 47);
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
438
          "cdda://-1", NULL) == FALSE);
439
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
440
          "cdda://what", NULL) == FALSE);
441 442 443 444 445

  /* cdda://device#track */
  test_uri_parse ("cdda:///dev/hdb#1", "/dev/hdb", 1);
  test_uri_parse ("cdda://anything#8", "anything", 8);
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
446
          "cdda:///dev/hdb#nonsense", NULL) == FALSE);
447
  fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (foosrc),
448
          "cdda:///dev/hdb#-2", NULL) == FALSE);
449 450 451 452 453 454 455 456 457

  /* cdda://track#device (device should be ignored - FIXME 0.11) */
  test_uri_parse ("cdda://8#/dev/hdb", "/dev/cdrom", 8);

  gst_object_unref (foosrc);
}

GST_END_TEST;

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
GST_START_TEST (test_properties)
{
  GstElement *foosrc;
  gchar *device;
  guint track;

  fail_unless (gst_element_register (NULL, "cdfoosrc", GST_RANK_SECONDARY,
          GST_TYPE_CD_FOO_SRC));

  foosrc = gst_element_factory_make ("cdfoosrc", "cdfoosrc");

  g_object_set (foosrc, "device", "/dev/cdrom", NULL);
  g_object_get (foosrc, "device", &device, "track", &track, NULL);
  fail_unless (g_str_equal (device, "/dev/cdrom"));
  fail_unless_equals_int (track, 1);
  g_free (device);

  g_object_set (foosrc, "device", "/dev/cdrom1", "track", 17, NULL);
  g_object_get (foosrc, "device", &device, "track", &track, NULL);
  fail_unless (g_str_equal (device, "/dev/cdrom1"));
  fail_unless_equals_int (track, 17);
  g_free (device);

  g_object_set (foosrc, "track", 17, "device", "/dev/cdrom1", NULL);
  g_object_get (foosrc, "device", &device, "track", &track, NULL);
  fail_unless (g_str_equal (device, "/dev/cdrom1"));
  fail_unless_equals_int (track, 17);
  g_free (device);

  g_object_set (foosrc, "track", 12, NULL);
  g_object_get (foosrc, "device", &device, "track", &track, NULL);
  fail_unless (g_str_equal (device, "/dev/cdrom1"));
  fail_unless_equals_int (track, 12);
  g_free (device);

  gst_object_unref (foosrc);
}

GST_END_TEST;

498
static Suite *
499
audiocdsrc_suite (void)
500
{
501
  Suite *s = suite_create ("audiocdsrc");
502 503 504 505
  TCase *tc_chain = tcase_create ("general");

  suite_add_tcase (s, tc_chain);
  tcase_add_test (tc_chain, test_discid_calculations);
506
  tcase_add_test (tc_chain, test_buffer_timestamps);
507
  tcase_add_test (tc_chain, test_uri_parsing);
508
  tcase_add_test (tc_chain, test_properties);
509 510 511 512

  return s;
}

513
GST_CHECK_MAIN (audiocdsrc)