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., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
31 #include "gstcdparanoiasrc.h"
32 #include "gst/gst-i18n-plugin.h"
51 #define DEFAULT_READ_SPEED -1
52 #define DEFAULT_SEARCH_OVERLAP -1
53 #define DEFAULT_PARANOIA_MODE PARANOIA_MODE_FRAGMENT
54 #define DEFAULT_GENERIC_DEVICE NULL
55 #define DEFAULT_CACHE_SIZE -1
57 GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug);
58 #define GST_CAT_DEFAULT gst_cd_paranoia_src_debug
60 #define gst_cd_paranoia_src_parent_class parent_class
61 G_DEFINE_TYPE (GstCdParanoiaSrc, gst_cd_paranoia_src, GST_TYPE_AUDIO_CD_SRC);
62 GST_ELEMENT_REGISTER_DEFINE (cdparanoiasrc, "cdparanoiasrc", GST_RANK_SECONDARY,
63 GST_TYPE_CD_PARANOIA_SRC);
65 static void gst_cd_paranoia_src_finalize (GObject * obj);
66 static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
67 GValue * value, GParamSpec * pspec);
68 static void gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
69 const GValue * value, GParamSpec * pspec);
70 static GstBuffer *gst_cd_paranoia_src_read_sector (GstAudioCdSrc * src,
72 static gboolean gst_cd_paranoia_src_open (GstAudioCdSrc * src,
73 const gchar * device);
74 static void gst_cd_paranoia_src_close (GstAudioCdSrc * src);
76 /* We use these to serialize calls to paranoia_read() among several
77 * cdparanoiasrc instances. We do this because it's the only reasonably
78 * easy way to find out the calling object from within the paranoia
79 * callback, and we need the object instance in there to emit our signals */
80 static GstCdParanoiaSrc *cur_cb_source;
81 static GMutex cur_cb_mutex;
83 static gint cdpsrc_signals[NUM_SIGNALS]; /* all 0 */
85 #define GST_TYPE_CD_PARANOIA_MODE (gst_cd_paranoia_mode_get_type())
87 gst_cd_paranoia_mode_get_type (void)
89 static const GFlagsValue paranoia_modes[] = {
90 {PARANOIA_MODE_DISABLE, "PARANOIA_MODE_DISABLE", "disable"},
91 {PARANOIA_MODE_FRAGMENT, "PARANOIA_MODE_FRAGMENT", "fragment"},
92 {PARANOIA_MODE_OVERLAP, "PARANOIA_MODE_OVERLAP", "overlap"},
93 {PARANOIA_MODE_SCRATCH, "PARANOIA_MODE_SCRATCH", "scratch"},
94 {PARANOIA_MODE_REPAIR, "PARANOIA_MODE_REPAIR", "repair"},
95 {PARANOIA_MODE_FULL, "PARANOIA_MODE_FULL", "full"},
99 static GType type; /* 0 */
102 type = g_flags_register_static ("GstCdParanoiaMode", paranoia_modes);
109 gst_cd_paranoia_src_init (GstCdParanoiaSrc * src)
113 src->next_sector = -1;
115 src->search_overlap = DEFAULT_SEARCH_OVERLAP;
116 src->paranoia_mode = DEFAULT_PARANOIA_MODE;
117 src->read_speed = DEFAULT_READ_SPEED;
118 src->generic_device = g_strdup (DEFAULT_GENERIC_DEVICE);
119 src->cache_size = DEFAULT_CACHE_SIZE;
123 gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass)
125 GstAudioCdSrcClass *audiocdsrc_class = GST_AUDIO_CD_SRC_CLASS (klass);
126 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
127 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129 gobject_class->set_property = gst_cd_paranoia_src_set_property;
130 gobject_class->get_property = gst_cd_paranoia_src_get_property;
131 gobject_class->finalize = gst_cd_paranoia_src_finalize;
133 gst_element_class_set_static_metadata (element_class,
134 "CD Audio (cdda) Source, Paranoia IV", "Source/File",
135 "Read audio from CD in paranoid mode",
136 "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
138 audiocdsrc_class->open = gst_cd_paranoia_src_open;
139 audiocdsrc_class->close = gst_cd_paranoia_src_close;
140 audiocdsrc_class->read_sector = gst_cd_paranoia_src_read_sector;
142 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GENERIC_DEVICE,
143 g_param_spec_string ("generic-device", "Generic device",
144 "Use specified generic scsi device", DEFAULT_GENERIC_DEVICE,
145 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
146 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_READ_SPEED,
147 g_param_spec_int ("read-speed", "Read speed",
148 "Read from device at specified speed (-1 and 0 = full speed)",
149 -1, G_MAXINT, DEFAULT_READ_SPEED,
150 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
151 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PARANOIA_MODE,
152 g_param_spec_flags ("paranoia-mode", "Paranoia mode",
153 "Type of checking to perform", GST_TYPE_CD_PARANOIA_MODE,
154 DEFAULT_PARANOIA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEARCH_OVERLAP,
156 g_param_spec_int ("search-overlap", "Search overlap",
157 "Force minimum overlap search during verification to n sectors", -1,
158 75, DEFAULT_SEARCH_OVERLAP,
159 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
161 * GstCdParanoiaSrc:cache-size:
163 * Set CD cache size to n sectors (-1 = auto)
165 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CACHE_SIZE,
166 g_param_spec_int ("cache-size", "Cache size",
167 "Set CD cache size to n sectors (-1 = auto)", -1,
168 G_MAXINT, DEFAULT_CACHE_SIZE,
169 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
171 /* FIXME: we don't really want signals for this, but messages on the bus,
172 * but then we can't check any longer whether anyone is interested in them */
174 * GstCdParanoiaSrc::transport-error:
175 * @cdparanoia: The CdParanoia instance
176 * @sector: The sector number at which the error was encountered.
178 * This signal is emitted whenever an error occurs while reading.
179 * CdParanoia will attempt to recover the data.
181 cdpsrc_signals[TRANSPORT_ERROR] =
182 g_signal_new ("transport-error", G_TYPE_FROM_CLASS (klass),
184 G_STRUCT_OFFSET (GstCdParanoiaSrcClass, transport_error),
185 NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
187 * GstCdParanoiaSrc::uncorrected-error:
188 * @cdparanoia: The CdParanoia instance
189 * @sector: The sector number at which the error was encountered.
191 * This signal is emitted whenever an uncorrectable error occurs while
192 * reading. The data could not be read.
194 cdpsrc_signals[UNCORRECTED_ERROR] =
195 g_signal_new ("uncorrected-error", G_TYPE_FROM_CLASS (klass),
197 G_STRUCT_OFFSET (GstCdParanoiaSrcClass, uncorrected_error),
198 NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
200 gst_type_mark_as_plugin_api (GST_TYPE_CD_PARANOIA_MODE, 0);
204 gst_cd_paranoia_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device)
206 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
209 GST_DEBUG_OBJECT (src, "trying to open device %s (generic-device=%s) ...",
210 device, GST_STR_NULL (src->generic_device));
212 /* find the device */
213 if (src->generic_device != NULL) {
214 src->d = cdda_identify_scsi (src->generic_device, device, FALSE, NULL);
216 if (device != NULL) {
217 src->d = cdda_identify (device, FALSE, NULL);
219 src->d = cdda_identify ("/dev/cdrom", FALSE, NULL);
223 /* fail if the device couldn't be found */
227 /* set verbosity mode */
228 cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
231 if (cdda_open (src->d))
234 GST_INFO_OBJECT (src, "set read speed to %d", src->read_speed);
235 cdda_speed_set (src->d, src->read_speed);
237 for (i = 1; i < src->d->tracks + 1; i++) {
238 GstAudioCdSrcTrack track = { 0, };
241 track.is_audio = IS_AUDIO (src->d, i - 1);
242 track.start = cdda_track_firstsector (src->d, i);
243 track.end = cdda_track_lastsector (src->d, i);
246 gst_audio_cd_src_add_track (GST_AUDIO_CD_SRC (src), &track);
249 /* create the paranoia struct and set it up */
250 src->p = paranoia_init (src->d);
254 paranoia_modeset (src->p, src->paranoia_mode);
255 GST_INFO_OBJECT (src, "set paranoia mode to 0x%02x", src->paranoia_mode);
257 if (src->search_overlap != -1) {
258 paranoia_overlapset (src->p, src->search_overlap);
259 GST_INFO_OBJECT (src, "search overlap set to %u", src->search_overlap);
262 cache_size = src->cache_size;
263 if (cache_size == -1) {
264 /* if paranoia mode is low (the default), assume we're doing playback */
265 if (src->paranoia_mode <= PARANOIA_MODE_FRAGMENT)
268 cache_size = paranoia_cachemodel_size (src->p, -1);
270 paranoia_cachemodel_size (src->p, cache_size);
271 GST_INFO_OBJECT (src, "set cachemodel size to %u", cache_size);
273 src->next_sector = -1;
280 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
281 (_("Could not open CD device for reading.")), ("cdda_identify failed"));
286 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
287 (_("Could not open CD device for reading.")), ("cdda_open failed"));
294 GST_ELEMENT_ERROR (src, LIBRARY, INIT,
295 ("failed to initialize paranoia"), ("failed to initialize paranoia"));
301 gst_cd_paranoia_src_close (GstAudioCdSrc * audiocdsrc)
303 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
306 paranoia_free (src->p);
315 src->next_sector = -1;
319 gst_cd_paranoia_dummy_callback (long inpos, int function)
321 /* Used by instanced where no one is interested what's happening here */
325 gst_cd_paranoia_paranoia_callback (long inpos, int function)
327 GstCdParanoiaSrc *src = cur_cb_source;
328 gint sector = (gint) (inpos / CD_FRAMEWORDS);
331 case PARANOIA_CB_SKIP:
332 GST_INFO_OBJECT (src, "Skip at sector %d", sector);
333 g_signal_emit (src, cdpsrc_signals[UNCORRECTED_ERROR], 0, sector);
335 case PARANOIA_CB_READERR:
336 GST_INFO_OBJECT (src, "Transport error at sector %d", sector);
337 g_signal_emit (src, cdpsrc_signals[TRANSPORT_ERROR], 0, sector);
345 gst_cd_paranoia_src_signal_is_being_watched (GstCdParanoiaSrc * src, gint sig)
347 return g_signal_has_handler_pending (src, cdpsrc_signals[sig], 0, FALSE);
351 gst_cd_paranoia_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector)
353 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
355 gboolean do_serialize;
359 /* Do we really need to output this? (tpm) */
360 /* Due to possible autocorrections of start sectors of audio tracks on
361 * multisession cds, we can maybe not compute the correct discid.
362 * So issue a warning.
363 * See cdparanoia/interface/common-interface.c:FixupTOC */
364 if (src->d && src->d->cd_extra) {
366 ("DiscID on multisession discs might be broken. Use at own risk.");
370 if (src->next_sector == -1 || src->next_sector != sector) {
371 if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
374 GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
375 src->next_sector = sector;
379 gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
380 gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);
383 GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
384 g_mutex_lock (&cur_cb_mutex);
385 GST_LOG_OBJECT (src, "Got lock");
388 cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);
390 cur_cb_source = NULL;
391 GST_LOG_OBJECT (src, "Releasing lock");
392 g_mutex_unlock (&cur_cb_mutex);
394 cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
397 if (cdda_buf == NULL)
400 buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
401 gst_buffer_fill (buf, 0, cdda_buf, CD_FRAMESIZE_RAW);
403 /* cdda base class will take care of timestamping etc. */
411 GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
412 GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
413 (_("Could not seek CD.")),
414 ("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
419 GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
420 GST_ELEMENT_ERROR (src, RESOURCE, READ,
421 (_("Could not read CD.")),
422 ("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
428 gst_cd_paranoia_src_finalize (GObject * obj)
430 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (obj);
432 g_free (src->generic_device);
434 G_OBJECT_CLASS (parent_class)->finalize (obj);
438 gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
439 const GValue * value, GParamSpec * pspec)
441 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
443 GST_OBJECT_LOCK (src);
446 case PROP_GENERIC_DEVICE:{
447 g_free (src->generic_device);
448 src->generic_device = g_value_dup_string (value);
449 if (src->generic_device && src->generic_device[0] == '\0') {
450 g_free (src->generic_device);
451 src->generic_device = NULL;
455 case PROP_READ_SPEED:{
456 src->read_speed = g_value_get_int (value);
457 if (src->read_speed == 0)
458 src->read_speed = -1;
461 case PROP_PARANOIA_MODE:{
462 src->paranoia_mode = g_value_get_flags (value) & PARANOIA_MODE_FULL;
465 case PROP_SEARCH_OVERLAP:{
466 src->search_overlap = g_value_get_int (value);
469 case PROP_CACHE_SIZE:{
470 src->cache_size = g_value_get_int (value);
474 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
478 GST_OBJECT_UNLOCK (src);
482 gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
483 GValue * value, GParamSpec * pspec)
485 GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
487 GST_OBJECT_LOCK (src);
490 case PROP_READ_SPEED:
491 g_value_set_int (value, src->read_speed);
493 case PROP_PARANOIA_MODE:
494 g_value_set_flags (value, src->paranoia_mode);
496 case PROP_GENERIC_DEVICE:
497 g_value_set_string (value, src->generic_device);
499 case PROP_SEARCH_OVERLAP:
500 g_value_set_int (value, src->search_overlap);
502 case PROP_CACHE_SIZE:
503 g_value_set_int (value, src->cache_size);
506 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
510 GST_OBJECT_UNLOCK (src);
514 plugin_init (GstPlugin * plugin)
516 gboolean ret = FALSE;
518 GST_DEBUG_CATEGORY_INIT (gst_cd_paranoia_src_debug, "cdparanoiasrc", 0,
519 "CD Paranoia Source");
521 ret |= GST_ELEMENT_REGISTER (cdparanoiasrc, plugin);
524 GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
526 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
527 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
533 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
536 "Read audio from CD in paranoid mode",
537 plugin_init, GST_PLUGINS_BASE_VERSION, "LGPL", GST_PACKAGE_NAME,