1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
3 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * <2005> Wim Taymans <wim@fluendo.com>
5 * <2005> Tim-Philipp Müller <tim centricular net>
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.
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.
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
30 #include "gstcdparanoiasrc.h"
31 #include "gst/gst-i18n-plugin.h"
50 #define DEFAULT_READ_SPEED -1
51 #define DEFAULT_SEARCH_OVERLAP -1
52 #define DEFAULT_PARANOIA_MODE PARANOIA_MODE_FRAGMENT
53 #define DEFAULT_GENERIC_DEVICE NULL
54 #define DEFAULT_CACHE_SIZE -1
56 GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug);
57 #define GST_CAT_DEFAULT gst_cd_paranoia_src_debug
59 GST_BOILERPLATE (GstCdParanoiaSrc, gst_cd_paranoia_src, GstCddaBaseSrc,
60 GST_TYPE_CDDA_BASE_SRC);
62 static void gst_cd_paranoia_src_finalize (GObject * obj);
63 static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
64 GValue * value, GParamSpec * pspec);
65 static void gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
66 const GValue * value, GParamSpec * pspec);
67 static GstBuffer *gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * src,
69 static gboolean gst_cd_paranoia_src_open (GstCddaBaseSrc * src,
70 const gchar * device);
71 static void gst_cd_paranoia_src_close (GstCddaBaseSrc * src);
73 /* We use these to serialize calls to paranoia_read() among several
74 * cdparanoiasrc instances. We do this because it's the only reasonably
75 * easy way to find out the calling object from within the paranoia
76 * callback, and we need the object instance in there to emit our signals */
77 static GstCdParanoiaSrc *cur_cb_source;
78 static GStaticMutex cur_cb_mutex = G_STATIC_MUTEX_INIT;
80 static gint cdpsrc_signals[NUM_SIGNALS]; /* all 0 */
82 #define GST_TYPE_CD_PARANOIA_MODE (gst_cd_paranoia_mode_get_type())
84 gst_cd_paranoia_mode_get_type (void)
86 static const GFlagsValue paranoia_modes[] = {
87 {PARANOIA_MODE_DISABLE, "PARANOIA_MODE_DISABLE", "disable"},
88 {PARANOIA_MODE_FRAGMENT, "PARANOIA_MODE_FRAGMENT", "fragment"},
89 {PARANOIA_MODE_OVERLAP, "PARANOIA_MODE_OVERLAP", "overlap"},
90 {PARANOIA_MODE_SCRATCH, "PARANOIA_MODE_SCRATCH", "scratch"},
91 {PARANOIA_MODE_REPAIR, "PARANOIA_MODE_REPAIR", "repair"},
92 {PARANOIA_MODE_FULL, "PARANOIA_MODE_FULL", "full"},
96 static GType type; /* 0 */
99 type = g_flags_register_static ("GstCdParanoiaMode", paranoia_modes);
106 gst_cd_paranoia_src_base_init (gpointer g_class)
108 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
110 gst_element_class_set_details_simple (element_class,
111 "CD Audio (cdda) Source, Paranoia IV", "Source/File",
112 "Read audio from CD in paranoid mode",
113 "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
117 gst_cd_paranoia_src_init (GstCdParanoiaSrc * src, GstCdParanoiaSrcClass * klass)
121 src->next_sector = -1;
123 src->search_overlap = DEFAULT_SEARCH_OVERLAP;
124 src->paranoia_mode = DEFAULT_PARANOIA_MODE;
125 src->read_speed = DEFAULT_READ_SPEED;
126 src->generic_device = g_strdup (DEFAULT_GENERIC_DEVICE);
127 src->cache_size = DEFAULT_CACHE_SIZE;
131 gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass)
133 GstCddaBaseSrcClass *cddabasesrc_class = GST_CDDA_BASE_SRC_CLASS (klass);
134 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
136 gobject_class->set_property = gst_cd_paranoia_src_set_property;
137 gobject_class->get_property = gst_cd_paranoia_src_get_property;
138 gobject_class->finalize = gst_cd_paranoia_src_finalize;
140 cddabasesrc_class->open = gst_cd_paranoia_src_open;
141 cddabasesrc_class->close = gst_cd_paranoia_src_close;
142 cddabasesrc_class->read_sector = gst_cd_paranoia_src_read_sector;
144 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GENERIC_DEVICE,
145 g_param_spec_string ("generic-device", "Generic device",
146 "Use specified generic scsi device", DEFAULT_GENERIC_DEVICE,
147 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
148 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_READ_SPEED,
149 g_param_spec_int ("read-speed", "Read speed",
150 "Read from device at specified speed", -1, G_MAXINT,
151 DEFAULT_READ_SPEED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PARANOIA_MODE,
153 g_param_spec_flags ("paranoia-mode", "Paranoia mode",
154 "Type of checking to perform", GST_TYPE_CD_PARANOIA_MODE,
155 DEFAULT_PARANOIA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEARCH_OVERLAP,
157 g_param_spec_int ("search-overlap", "Search overlap",
158 "Force minimum overlap search during verification to n sectors", -1,
159 75, DEFAULT_SEARCH_OVERLAP,
160 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
162 * GstCdParanoiaSrc:cache-size
164 * Set CD cache size to n sectors (-1 = auto)
168 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CACHE_SIZE,
169 g_param_spec_int ("cache-size", "Cache size",
170 "Set CD cache size to n sectors (-1 = auto)", -1,
171 G_MAXINT, DEFAULT_CACHE_SIZE,
172 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174 /* FIXME: we don't really want signals for this, but messages on the bus,
175 * but then we can't check any longer whether anyone is interested in them */
177 * GstCdParanoiaSrc::transport-error
178 * @cdparanoia: The CdParanoia instance
179 * @sector: The sector number at which the error was encountered.
181 * This signal is emitted whenever an error occurs while reading.
182 * CdParanoia will attempt to recover the data.
184 cdpsrc_signals[TRANSPORT_ERROR] =
185 g_signal_new ("transport-error", G_TYPE_FROM_CLASS (klass),
187 G_STRUCT_OFFSET (GstCdParanoiaSrcClass, transport_error),
188 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
190 * GstCdParanoiaSrc::uncorrected-error
191 * @cdparanoia: The CdParanoia instance
192 * @sector: The sector number at which the error was encountered.
194 * This signal is emitted whenever an uncorrectable error occurs while
195 * reading. The data could not be read.
197 cdpsrc_signals[UNCORRECTED_ERROR] =
198 g_signal_new ("uncorrected-error", G_TYPE_FROM_CLASS (klass),
200 G_STRUCT_OFFSET (GstCdParanoiaSrcClass, uncorrected_error),
201 NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
205 gst_cd_paranoia_src_open (GstCddaBaseSrc * cddabasesrc, const gchar * device)
207 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
210 GST_DEBUG_OBJECT (src, "trying to open device %s (generic-device=%s) ...",
211 device, GST_STR_NULL (src->generic_device));
213 /* find the device */
214 if (src->generic_device != NULL) {
215 src->d = cdda_identify_scsi (src->generic_device, device, FALSE, NULL);
217 if (device != NULL) {
218 src->d = cdda_identify (device, FALSE, NULL);
220 src->d = cdda_identify ("/dev/cdrom", FALSE, NULL);
224 /* fail if the device couldn't be found */
228 /* set verbosity mode */
229 cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
232 if (cdda_open (src->d))
235 if (src->read_speed != -1) {
236 cdda_speed_set (src->d, src->read_speed);
239 for (i = 1; i < src->d->tracks + 1; i++) {
240 GstCddaBaseSrcTrack track = { 0, };
243 track.is_audio = IS_AUDIO (src->d, i - 1);
244 track.start = cdda_track_firstsector (src->d, i);
245 track.end = cdda_track_lastsector (src->d, i);
248 gst_cdda_base_src_add_track (GST_CDDA_BASE_SRC (src), &track);
251 /* create the paranoia struct and set it up */
252 src->p = paranoia_init (src->d);
256 paranoia_modeset (src->p, src->paranoia_mode);
257 GST_INFO_OBJECT (src, "set paranoia mode to 0x%02x", src->paranoia_mode);
259 if (src->search_overlap != -1) {
260 paranoia_overlapset (src->p, src->search_overlap);
261 GST_INFO_OBJECT (src, "search overlap set to %u", src->search_overlap);
264 cache_size = src->cache_size;
265 if (cache_size == -1) {
266 /* if paranoia mode is low (the default), assume we're doing playback */
267 if (src->paranoia_mode <= PARANOIA_MODE_FRAGMENT)
270 cache_size = paranoia_cachemodel_size (src->p, -1);
272 paranoia_cachemodel_size (src->p, cache_size);
273 GST_INFO_OBJECT (src, "set cachemodel size to %u", cache_size);
275 src->next_sector = -1;
282 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
283 (_("Could not open CD device for reading.")), ("cdda_identify failed"));
288 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
289 (_("Could not open CD device for reading.")), ("cdda_open failed"));
296 GST_ELEMENT_ERROR (src, LIBRARY, INIT,
297 ("failed to initialize paranoia"), ("failed to initialize paranoia"));
303 gst_cd_paranoia_src_close (GstCddaBaseSrc * cddabasesrc)
305 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
308 paranoia_free (src->p);
317 src->next_sector = -1;
321 gst_cd_paranoia_dummy_callback (long inpos, int function)
323 /* Used by instanced where no one is interested what's happening here */
327 gst_cd_paranoia_paranoia_callback (long inpos, int function)
329 GstCdParanoiaSrc *src = cur_cb_source;
330 gint sector = (gint) (inpos / CD_FRAMEWORDS);
333 case PARANOIA_CB_SKIP:
334 GST_INFO_OBJECT (src, "Skip at sector %d", sector);
335 g_signal_emit (src, cdpsrc_signals[UNCORRECTED_ERROR], 0, sector);
337 case PARANOIA_CB_READERR:
338 GST_INFO_OBJECT (src, "Transport error at sector %d", sector);
339 g_signal_emit (src, cdpsrc_signals[TRANSPORT_ERROR], 0, sector);
347 gst_cd_paranoia_src_signal_is_being_watched (GstCdParanoiaSrc * src, gint sig)
349 return g_signal_has_handler_pending (src, cdpsrc_signals[sig], 0, FALSE);
353 gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * cddabasesrc, gint sector)
355 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
357 gboolean do_serialize;
361 /* Do we really need to output this? (tpm) */
362 /* Due to possible autocorrections of start sectors of audio tracks on
363 * multisession cds, we can maybe not compute the correct discid.
364 * So issue a warning.
365 * See cdparanoia/interface/common-interface.c:FixupTOC */
366 if (src->d && src->d->cd_extra) {
368 ("DiscID on multisession discs might be broken. Use at own risk.");
372 if (src->next_sector == -1 || src->next_sector != sector) {
373 if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
376 GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
377 src->next_sector = sector;
381 gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
382 gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);
385 GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
386 g_static_mutex_lock (&cur_cb_mutex);
387 GST_LOG_OBJECT (src, "Got lock");
390 cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);
392 cur_cb_source = NULL;
393 GST_LOG_OBJECT (src, "Releasing lock");
394 g_static_mutex_unlock (&cur_cb_mutex);
396 cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
399 if (cdda_buf == NULL)
402 buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
403 memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW);
405 /* cdda base class will take care of timestamping etc. */
413 GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
414 GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
415 (_("Could not seek CD.")),
416 ("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
421 GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
422 GST_ELEMENT_ERROR (src, RESOURCE, READ,
423 (_("Could not read CD.")),
424 ("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
430 gst_cd_paranoia_src_finalize (GObject * obj)
432 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (obj);
434 g_free (src->generic_device);
436 G_OBJECT_CLASS (parent_class)->finalize (obj);
440 gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
441 const GValue * value, GParamSpec * pspec)
443 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
445 GST_OBJECT_LOCK (src);
448 case PROP_GENERIC_DEVICE:{
449 g_free (src->generic_device);
450 src->generic_device = g_value_dup_string (value);
451 if (src->generic_device && src->generic_device[0] == '\0') {
452 g_free (src->generic_device);
453 src->generic_device = NULL;
457 case PROP_READ_SPEED:{
458 src->read_speed = g_value_get_int (value);
459 if (src->read_speed == 0)
460 src->read_speed = -1;
463 case PROP_PARANOIA_MODE:{
464 src->paranoia_mode = g_value_get_flags (value) & PARANOIA_MODE_FULL;
467 case PROP_SEARCH_OVERLAP:{
468 src->search_overlap = g_value_get_int (value);
471 case PROP_CACHE_SIZE:{
472 src->cache_size = g_value_get_int (value);
476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
480 GST_OBJECT_UNLOCK (src);
484 gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
485 GValue * value, GParamSpec * pspec)
487 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
489 GST_OBJECT_LOCK (src);
492 case PROP_READ_SPEED:
493 g_value_set_int (value, src->read_speed);
495 case PROP_PARANOIA_MODE:
496 g_value_set_flags (value, src->paranoia_mode);
498 case PROP_GENERIC_DEVICE:
499 g_value_set_string (value, src->generic_device);
501 case PROP_SEARCH_OVERLAP:
502 g_value_set_int (value, src->search_overlap);
504 case PROP_CACHE_SIZE:
505 g_value_set_int (value, src->cache_size);
508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
512 GST_OBJECT_UNLOCK (src);
516 plugin_init (GstPlugin * plugin)
518 GST_DEBUG_CATEGORY_INIT (gst_cd_paranoia_src_debug, "cdparanoiasrc", 0,
519 "CD Paranoia Source");
521 if (!gst_element_register (plugin, "cdparanoiasrc", GST_RANK_SECONDARY,
522 GST_TYPE_CD_PARANOIA_SRC))
526 GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
528 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
529 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
535 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
538 "Read audio from CD in paranoid mode",
539 plugin_init, GST_PLUGINS_BASE_VERSION, "LGPL", GST_PACKAGE_NAME,