gstcdparanoia.c 20.9 KB
Newer Older
Andy Wingo's avatar
Andy Wingo committed
1
/* GStreamer
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * 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.
 */

20
/* #define GST_DEBUG_ENABLED */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

#include "gstcdparanoia.h"


static GstElementDetails cdparanoia_details = {
  "CD Audio (cdda) Source, Paranoia IV",
40
  "Source/File",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
41
42
43
44
45
46
  "Read audio from CD in paranoid mode",
  VERSION,
  "Erik Walthinsen <omega@cse.ogi.edu>",
  "(C) 2000",
};

47
GST_PAD_TEMPLATE_FACTORY (cdparanoia_src_factory,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  "src",
  GST_PAD_SRC,
  GST_PAD_ALWAYS,
  GST_CAPS_NEW (
    "cdparanoia_src",
    "audio/raw",
      "format",   GST_PROPS_STRING ("int"),
        "law",        GST_PROPS_INT (0),
        "endianness", GST_PROPS_INT (G_BYTE_ORDER),
        "signed",     GST_PROPS_BOOLEAN (TRUE),
        "width",      GST_PROPS_INT (16),
        "depth",      GST_PROPS_INT (16),
        "rate",       GST_PROPS_INT (44100),
        "channels",   GST_PROPS_INT (2),
        "chunksize",  GST_PROPS_INT (CD_FRAMESIZE_RAW)
  )
);


/********** Define useful types for non-programmatic interfaces **********/
Wim Taymans's avatar
Wim Taymans committed
68
#define GST_TYPE_PARANOIA_MODE (gst_paranoia_mode_get_type())
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
69
static GType
Wim Taymans's avatar
Wim Taymans committed
70
gst_paranoia_mode_get_type (void)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
{
  static GType paranoia_mode_type = 0;
  static GEnumValue paranoia_modes[] = {
    { 0, "0", "Disable paranoid checking" },
    { 1, "1", "cdda2wav-style overlap checking" },
    { 2, "2", "Full paranoia" },
    { 0, NULL, NULL },
  };
  if (!paranoia_mode_type) {
    paranoia_mode_type = g_enum_register_static ("GstParanoiaMode", paranoia_modes);
  }
  return paranoia_mode_type;
}


/********** Standard stuff for signals and arguments **********/
/* CDParanoia signals and args */
enum {
  SMILIE_CHANGE,
  TRANSPORT_ERROR,
  UNCORRECTED_ERROR,
  LAST_SIGNAL
};

enum {
  ARG_0,
  ARG_LOCATION,
  ARG_GENERIC_DEVICE,
  ARG_START_TRACK,
  ARG_END_TRACK,
  ARG_LAST_TRACK,
  ARG_CUR_TRACK,
  ARG_START_SECTOR,
  ARG_END_SECTOR,
  ARG_CUR_SECTOR,
  ARG_DEFAULT_SECTORS,
  ARG_SEARCH_OVERLAP,
  ARG_ENDIAN,
  ARG_READ_SPEED,
  ARG_TOC_OFFSET,
  ARG_TOC_BIAS,
  ARG_NEVER_SKIP,
  ARG_ABORT_ON_SKIP,
  ARG_PARANOIA_MODE,
  ARG_SMILIE,
};


static void			cdparanoia_class_init		(CDParanoiaClass *klass);
static void			cdparanoia_init			(CDParanoia *cdparanoia);

static void			cdparanoia_set_property		(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void			cdparanoia_get_property		(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);

static GstBuffer*		cdparanoia_get			(GstPad *pad);

static GstElementStateReturn	cdparanoia_change_state		(GstElement *element);


static GstElementClass *parent_class = NULL;
static guint cdparanoia_signals[LAST_SIGNAL] = { 0 };

GType
cdparanoia_get_type (void)
{
  static GType cdparanoia_type = 0;

  if (!cdparanoia_type) {
    static const GTypeInfo cdparanoia_info = {
      sizeof(CDParanoiaClass),      NULL,
      NULL,
      (GClassInitFunc)cdparanoia_class_init,
      NULL,
      NULL,
      sizeof(CDParanoia),
      0,
      (GInstanceInitFunc)cdparanoia_init,
    };
    cdparanoia_type = g_type_register_static (GST_TYPE_ELEMENT, "CDParanoia", &cdparanoia_info, 0);
  }
  return cdparanoia_type;
}

static void
cdparanoia_class_init (CDParanoiaClass *klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
159
160
  char *success = strerror_tr[0];
  success = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

  gobject_class = (GObjectClass*)klass;
  gstelement_class = (GstElementClass*)klass;

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);

  cdparanoia_signals[SMILIE_CHANGE] =
    g_signal_new ("smilie_change", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (CDParanoiaClass, smilie_change), NULL, NULL,
                   g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
  cdparanoia_signals[TRANSPORT_ERROR] =
    g_signal_new ("transport_error", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (CDParanoiaClass, transport_error), NULL, NULL,
                   g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
  cdparanoia_signals[UNCORRECTED_ERROR] =
    g_signal_new ("uncorrected_error", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (CDParanoiaClass, uncorrected_error), NULL, NULL,
                   g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);

  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LOCATION,
    g_param_spec_string("location","location","location",
182
                        NULL, G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
183
184
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_GENERIC_DEVICE,
    g_param_spec_string("generic_device","generic_device","generic_device",
185
                        NULL, G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
186
187
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_START_TRACK,
    g_param_spec_int("start_track","start_track","start_track",
188
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
189
190
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_END_TRACK,
    g_param_spec_int("end_track","end_track","end_track",
191
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
192
193
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LAST_TRACK,
    g_param_spec_int("last_track","last_track","last_track",
194
                     G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
195
196
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CUR_TRACK,
    g_param_spec_int("cur_track","cur_track","cur_track",
197
                     G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
198
199
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_START_SECTOR,
    g_param_spec_int("start_sector","start_sector","start_sector",
200
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
201
202
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_END_SECTOR,
    g_param_spec_int("end_sector","end_sector","end_sector",
203
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
204
205
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CUR_SECTOR,
    g_param_spec_int("cur_sector","cur_sector","cur_sector",
206
                     G_MININT,G_MAXINT,0,G_PARAM_READABLE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
207
208
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEFAULT_SECTORS,
    g_param_spec_int("default_sectors","default_sectors","default_sectors",
209
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
210
211
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SEARCH_OVERLAP,
    g_param_spec_int("search_overlap","search_overlap","search_overlap",
212
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
213
214
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ENDIAN,
    g_param_spec_int("endian","endian","endian",
215
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
216
217
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_READ_SPEED,
    g_param_spec_int("read_speed","read_speed","read_speed",
218
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
219
220
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOC_OFFSET,
    g_param_spec_int("toc_offset","toc_offset","toc_offset",
221
                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
222
223
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOC_BIAS,
    g_param_spec_boolean("toc_bias","toc_bias","toc_bias",
224
                         TRUE,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
225
226
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NEVER_SKIP,
    g_param_spec_boolean("never_skip","never_skip","never_skip",
227
                         TRUE,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
228
229
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ABORT_ON_SKIP,
    g_param_spec_boolean("abort_on_skip","abort_on_skip","abort_on_skip",
230
                         TRUE,G_PARAM_READWRITE)); /* CHECKME */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
231
232
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PARANOIA_MODE,
    g_param_spec_enum("paranoia_mode","paranoia_mode","paranoia_mode",
233
                      GST_TYPE_PARANOIA_MODE,0,G_PARAM_READWRITE)); /* CHECKME! */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
234
235
236
237
238
239
240
241
242
243
244

  gobject_class->set_property = cdparanoia_set_property;
  gobject_class->get_property = cdparanoia_get_property;

  gstelement_class->change_state = cdparanoia_change_state;
}

static void
cdparanoia_init (CDParanoia *cdparanoia)
{
  cdparanoia->srcpad = gst_pad_new_from_template (
245
		  GST_PAD_TEMPLATE_GET (cdparanoia_src_factory), "src");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
246
247
248
  gst_pad_set_get_function (cdparanoia->srcpad, cdparanoia_get);
  gst_element_add_pad (GST_ELEMENT (cdparanoia), cdparanoia->srcpad);

249
  cdparanoia->device = g_strdup ("/dev/cdrom");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  cdparanoia->generic_device = NULL;
  cdparanoia->start_sector = -1;
  cdparanoia->end_sector = -1;
  cdparanoia->cur_sector = -1;
  cdparanoia->start_track = -1;
  cdparanoia->cur_track = -1;
  cdparanoia->end_track = -1;
  cdparanoia->last_track = -1;
  cdparanoia->default_sectors = -1;
  cdparanoia->search_overlap = -1;
  cdparanoia->endian = -1;
  cdparanoia->read_speed = -1;
  cdparanoia->toc_offset = 0;
  cdparanoia->toc_bias = FALSE;
  cdparanoia->never_skip = FALSE;
  cdparanoia->paranoia_mode = 2;
  cdparanoia->abort_on_skip = FALSE;

  cdparanoia->cur_sector = 0;
  cdparanoia->seq = 0;
}


static void
cdparanoia_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
  CDParanoia *src;

  /* it's not null if we got it, but it might not be ours */
  g_return_if_fail (GST_IS_CDPARANOIA (object));

  src = CDPARANOIA (object);

  switch (prop_id) {
    case ARG_LOCATION:
      /* the element must be stopped in order to do this */
286
/*      g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
287
288
289
290
291
292
293
294
295
296
297

      if (src->device) g_free (src->device);
      /* clear the filename if we get a NULL (is that possible?) */
      if (g_value_get_string (value) == NULL)
        src->device = NULL;
      /* otherwise set the new filename */
      else
        src->device = g_strdup (g_value_get_string (value));
      break;
    case ARG_GENERIC_DEVICE:
      /* the element must be stopped in order to do this */
298
/*      g_return_if_fail(!GST_FLAG_IS_SET(src,GST_STATE_RUNNING)); */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

      if (src->generic_device) g_free (src->generic_device);
      /* reset the device if we get a NULL (is that possible?) */
      if (g_value_get_string (value) == NULL)
        src->generic_device = NULL;
      /* otherwise set the new filename */
      else
        src->generic_device = g_strdup (g_value_get_string (value));
      break;
    case ARG_START_SECTOR:
      src->start_sector = g_value_get_int (value);
      break;
    case ARG_END_SECTOR:
      src->end_sector = g_value_get_int (value);
      break;
    case ARG_START_TRACK:
      src->start_track = g_value_get_int (value);
      break;
    case ARG_END_TRACK:
      src->end_track = g_value_get_int (value);
      break;  
    case ARG_DEFAULT_SECTORS:
      src->default_sectors = g_value_get_int (value);
      break;
    case ARG_SEARCH_OVERLAP:
      src->search_overlap = g_value_get_int (value);
      break;
    case ARG_ENDIAN:
      src->endian = g_value_get_int (value);
      break;
    case ARG_READ_SPEED:
      src->read_speed = g_value_get_int (value);
      break;
    case ARG_TOC_OFFSET:
      src->toc_offset = g_value_get_int (value);
      break;
    case ARG_TOC_BIAS:
      src->toc_bias = g_value_get_boolean (value);
      break;
    case ARG_NEVER_SKIP:
      src->never_skip = g_value_get_boolean (value);
      break;
    case ARG_ABORT_ON_SKIP:
      src->abort_on_skip = g_value_get_boolean (value);
      break;
    case ARG_PARANOIA_MODE:
Wim Taymans's avatar
Wim Taymans committed
345
      src->paranoia_mode = g_value_get_enum (value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
      break;
    default:
      break;
  }

}

static void
cdparanoia_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
  CDParanoia *src;

  /* it's not null if we got it, but it might not be ours */
  g_return_if_fail (GST_IS_CDPARANOIA (object));

  src = CDPARANOIA (object);

  switch (prop_id) {
    case ARG_LOCATION:
      g_value_set_string (value, src->device);
      break;
    case ARG_GENERIC_DEVICE:
      g_value_set_string (value, src->generic_device);
      break;
    case ARG_START_SECTOR:
      g_value_set_int (value, src->start_sector);
      break;
    case ARG_END_SECTOR:
      g_value_set_int (value, src->end_sector);
      break;
    case ARG_CUR_SECTOR:
      g_value_set_int (value, src->cur_sector);
      break;
    case ARG_START_TRACK:
      g_value_set_int (value, src->start_track);
      break;
    case ARG_END_TRACK:
      g_value_set_int (value, src->end_track);
      break;
    case ARG_CUR_TRACK:
      g_value_set_int (value, src->cur_track);
      break;
    case ARG_LAST_TRACK:
      g_value_set_int (value, src->last_track);
      break;
    case ARG_DEFAULT_SECTORS:
      g_value_set_int (value, src->default_sectors);
      break;
    case ARG_SEARCH_OVERLAP:
      g_value_set_int (value, src->search_overlap);
      break;
    case ARG_ENDIAN:
      g_value_set_int (value, src->endian);
      break;
    case ARG_READ_SPEED:
      g_value_set_int (value, src->read_speed);
      break;
    case ARG_TOC_OFFSET:
      g_value_set_int (value, src->toc_offset);
      break;
    case ARG_TOC_BIAS:
      g_value_set_boolean (value, src->toc_bias);
      break;
    case ARG_NEVER_SKIP:
      g_value_set_boolean (value, src->never_skip);
      break;
    case ARG_ABORT_ON_SKIP:
      g_value_set_boolean (value, src->abort_on_skip);
      break;
    case ARG_PARANOIA_MODE:
Wim Taymans's avatar
Wim Taymans committed
416
      g_value_set_enum (value, src->paranoia_mode);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void cdparanoia_callback(long inpos, int function) {
}

static GstBuffer*
cdparanoia_get (GstPad *pad)
{
  CDParanoia *src;
  GstBuffer *buf;
  static gint16 *cdda_buf;

  g_return_val_if_fail (pad != NULL, NULL);
  src = CDPARANOIA (gst_pad_get_parent (pad));
  g_return_val_if_fail (GST_FLAG_IS_SET (src, CDPARANOIA_OPEN), NULL);

438
  /* create a new buffer */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
439
440
441
  buf = gst_buffer_new ();
  g_return_val_if_fail (buf, NULL);

442
443
  /* read a sector */
/* NOTE: if you have a patched cdparanoia, set this to 1 to save cycles */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
444
445
446
447
448
449
#if 0
  cdda_buf = paranoia_read (src->p, NULL);
#else
  cdda_buf = paranoia_read (src->p, cdparanoia_callback);
#endif

450
  /* update current sector and stop things if appropriate */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
451
452
453
  src->cur_sector++;

  if (src->cur_sector == src->end_sector) {
454
    GST_DEBUG (0,"setting EOS");
Wim Taymans's avatar
Wim Taymans committed
455
    gst_element_set_eos(GST_ELEMENT(src));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
456

Wim Taymans's avatar
Wim Taymans committed
457
458
459
460
461
    buf = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
  }
  else {
    src->cur_track = cdda_sector_gettrack( src->d, src->cur_sector );

462
463
    /* have to copy the buffer for now since we don't own it... */
    /* FIXME must ask monty about allowing ownership transfer */
Wim Taymans's avatar
Wim Taymans committed
464
465
466
467
    GST_BUFFER_DATA (buf) = g_malloc(CD_FRAMESIZE_RAW);
    memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW);
    GST_BUFFER_SIZE (buf) = CD_FRAMESIZE_RAW;
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

  /* we're done, push the buffer off now */
  return buf;
}

/* open the file, necessary to go to RUNNING state */
static gboolean
cdparanoia_open (CDParanoia *src)
{
  gint i;
  gint paranoia_mode;

  g_return_val_if_fail (!GST_FLAG_IS_SET (src, CDPARANOIA_OPEN), FALSE);

  GST_DEBUG_ENTER("(\"%s\",...)", gst_element_get_name (GST_ELEMENT (src)));

484
  /* find the device */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
485
486
487
488
489
490
491
492
493
494
  if (src->generic_device != NULL) {
    src->d = cdda_identify_scsi (src->generic_device, src->device, FALSE, NULL);
  } else {
    if (src->device != NULL) {
      src->d = cdda_identify (src->device, FALSE, NULL);
    } else {
      src->d = cdda_identify ("/dev/cdrom", FALSE, NULL);
    }
  }

495
  /* fail if the device couldn't be found */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
496
  if (src->d == NULL) {
497
    GST_DEBUG (0,"couldn't open device");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
498
499
500
    return FALSE;
  }

501
  /* set verbosity mode */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
502
503
  cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);

504
  /* set various other parameters */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
505
506
  if (src->default_sectors != -1) {
    if ((src->default_sectors < 0) || (src->default_sectors > 100)) {
507
      GST_DEBUG (0,"default sector read size must be 1 <= n <= 100");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
508
509
510
511
512
513
514
515
516
517
      cdda_close (src->d);
      src->d = NULL;
      return FALSE;
    } else {
      src->d->nsectors = src->default_sectors;
      src->d->bigbuff = src->default_sectors * CD_FRAMESIZE_RAW;
    }
  }
  if (src->search_overlap != -1) {
    if ((src->search_overlap < 0) || (src->search_overlap > 75)) {
518
      GST_DEBUG (0,"search overlap must be 0 <= n <= 75");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
519
520
521
522
523
524
      cdda_close (src->d);
      src->d = NULL;
      return FALSE;
    }
  }

525
  /* open the disc */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
526
  if (cdda_open (src->d)) {
527
    GST_DEBUG (0,"couldn't open disc");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
528
529
530
531
532
    cdda_close (src->d);
    src->d = NULL;
    return FALSE;
  }

533
  /* set up some more stuff */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
534
535
536
537
538
539
540
541
542
543
544
  if (src->toc_bias) {
    src->toc_offset -= cdda_track_firstsector (src->d, 1);
  }
  for (i=0;i<src->d->tracks + 1;i++) {
    src->d->disc_toc[i].dwStartSector += src->toc_offset;
  }

  if (src->read_speed != -1) {
    cdda_speed_set (src->d, src->read_speed);
  }

545
  /* if the start_track is set, override the start_sector */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
546
547
  if (src->start_track != -1) {
    src->start_sector = cdda_track_firstsector (src->d, src->start_track);
548
  /* if neither start_track nor start_sector is set, */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
549
550
551
  } else if (src->start_sector == -1) {
    src->start_sector = cdda_disc_firstsector (src->d);
  }
552
  /* if the end_track is set, override the end_sector */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
553
554
  if (src->end_track != -1) {
    src->end_sector = cdda_track_lastsector (src->d, src->end_track);
555
  /* if neither end_track nor end_sector is set, */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
556
557
558
559
  } else if (src->end_sector == -1) {
    src->end_sector = cdda_disc_lastsector (src->d);
  }

560
  /* set last_track */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
561
562
  src->last_track = cdda_tracks (src->d);

563
  /* create the paranoia struct and set it up */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
564
565
  src->p = paranoia_init (src->d);
  if (src->p == NULL) {
566
    GST_DEBUG (0,"couldn't create paranoia struct");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
    return FALSE;
  }

  if (src->paranoia_mode == 0) paranoia_mode = PARANOIA_MODE_DISABLE;
  else if (src->paranoia_mode == 1) paranoia_mode = PARANOIA_MODE_OVERLAP;
  else paranoia_mode = PARANOIA_MODE_FULL;
  if (src->never_skip) paranoia_mode |= PARANOIA_MODE_NEVERSKIP;
  paranoia_modeset (src->p, paranoia_mode);

  if (src->search_overlap != -1) {
    paranoia_overlapset (src->p, src->search_overlap);
  }

  src->cur_sector = src->start_sector;
  paranoia_seek (src->p, src->cur_sector, SEEK_SET);
582
  GST_DEBUG (0,"successfully seek'd to beginning of disk");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
583
584
585
586
587
588
589
590
591
592
593
594
595
596

  GST_FLAG_SET (src, CDPARANOIA_OPEN);

  GST_DEBUG_LEAVE("");

  return TRUE;
}

/* close the file */
static void
cdparanoia_close (CDParanoia *src)
{
  g_return_if_fail (GST_FLAG_IS_SET (src, CDPARANOIA_OPEN));

597
  /* kill the paranoia state */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
598
599
600
  paranoia_free (src->p);
  src->p = NULL;

601
  /* close the disc */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  cdda_close (src->d);
  src->d = NULL;

  GST_FLAG_UNSET (src, CDPARANOIA_OPEN);
}

static GstElementStateReturn
cdparanoia_change_state (GstElement *element)
{
  g_return_val_if_fail (GST_IS_CDPARANOIA (element), GST_STATE_FAILURE);

  /* if going down into NULL state, close the file if it's open */
  if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
    if (GST_FLAG_IS_SET (element, CDPARANOIA_OPEN))
      cdparanoia_close (CDPARANOIA (element));
  /* otherwise (READY or higher) we need to open the file */
  } else {
    if (!GST_FLAG_IS_SET (element, CDPARANOIA_OPEN)) {
      if (!cdparanoia_open (CDPARANOIA (element))) {
        g_print("failed opening cd\n");
        return GST_STATE_FAILURE;
      }
    }
  }

  /* if we haven't failed already, give the parent class a chance too ;-) */
  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);

  return GST_STATE_SUCCESS;
}

static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
  GstElementFactory *factory;

  /* create an elementfactory for the cdparanoia element */
640
  factory = gst_element_factory_new ("cdparanoia", GST_TYPE_CDPARANOIA,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
641
642
643
644
                                    &cdparanoia_details);
  g_return_val_if_fail (factory != NULL, FALSE);

  /* register the source's caps */
645
  gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (cdparanoia_src_factory));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
646
647
648
649
650
651
652
653
654
655
656
657
658

  /* and add the cdparanoia element factory to the plugin */
  gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));

  return TRUE;
}

GstPluginDesc plugin_desc = {
  GST_VERSION_MAJOR,
  GST_VERSION_MINOR,
  "cdparanoia",
  plugin_init
};