1 /*****************************************************************************
2 * cddax.c : CD digital audio input module for vlc using libcdio
3 *****************************************************************************
4 * Copyright (C) 2000 VideoLAN
5 * $Id: cddax.c,v 1.3 2003/10/05 14:51:47 rocky Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Gildas Bazin <gbazin@netcourrier.com>
9 * Rocky Bernstein <rocky@panix.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
33 #include <vlc/input.h>
34 #include <sys/types.h>
35 #include <cdio/cdio.h>
36 #include <cdio/cd_types.h>
46 #include "vcdx/cdrom.h"
48 /* how many blocks CDDAOpen will read in each loop */
49 #define CDDA_BLOCKS_ONCE 1
50 #define CDDA_DATA_ONCE (CDDA_BLOCKS_ONCE * CDIO_CD_FRAMESIZE_RAW)
52 /*****************************************************************************
53 * cdda_data_t: CD audio information
54 *****************************************************************************/
55 typedef struct cdda_data_s
57 cddev_t *p_cddev; /* CD device descriptor */
58 int i_nb_tracks; /* Nb of tracks (titles) */
59 int i_track; /* Current track */
60 lsn_t i_sector; /* Current Sector */
61 lsn_t * p_sectors; /* Track sectors */
62 vlc_bool_t b_end_of_track; /* If the end of track was reached */
63 int i_debug; /* Debugging mask */
69 es_descriptor_t *p_es;
73 /*****************************************************************************
75 *****************************************************************************/
76 #define INPUT_DBG_MRL 1
77 #define INPUT_DBG_EXT 2 /* Calls from external routines */
78 #define INPUT_DBG_CALL 4 /* all calls */
79 #define INPUT_DBG_LSN 8 /* LSN changes */
80 #define INPUT_DBG_CDIO 16 /* Debugging from CDIO */
81 #define INPUT_DBG_SEEK 32 /* Seeks to set location */
83 #define DEBUG_TEXT N_("set debug mask for additional debugging.")
84 #define DEBUG_LONGTEXT N_( \
85 "This integer when viewed in binary is a debugging mask\n" \
95 #define dbg_print(mask, s, args...) \
96 if (p_cdda->i_debug & mask) \
97 msg_Dbg(p_input, "%s: "s, __func__ , ##args)
99 #define dbg_print(mask, s, args...)
102 /*****************************************************************************
104 *****************************************************************************/
105 static int CDDAOpen ( vlc_object_t * );
106 static void CDDAClose ( vlc_object_t * );
107 static int CDDARead ( input_thread_t *, byte_t *, size_t );
108 static void CDDASeek ( input_thread_t *, off_t );
109 static int CDDASetArea ( input_thread_t *, input_area_t * );
110 static int CDDASetProgram ( input_thread_t *, pgrm_descriptor_t * );
112 static int CDDAOpenDemux ( vlc_object_t * );
113 static void CDDACloseDemux ( vlc_object_t * );
114 static int CDDADemux ( input_thread_t * p_input );
116 /*****************************************************************************
118 *****************************************************************************/
120 /* FIXME: This variable is a hack. Would be nice to eliminate. */
121 static input_thread_t *p_cdda_input = NULL;
123 static int debug_callback ( vlc_object_t *p_this, const char *psz_name,
124 vlc_value_t oldval, vlc_value_t val,
127 /*****************************************************************************
129 *****************************************************************************/
130 #define CACHING_TEXT N_("Caching value in ms")
131 #define CACHING_LONGTEXT N_( \
132 "Allows you to modify the default caching value for cdda streams. This " \
133 "value should be set in miliseconds units." )
136 set_description( _("CD Audio input") );
137 set_capability( "access", 75 /* slightly higher than cdda */ );
138 add_integer( "cddax-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
139 set_callbacks( CDDAOpen, CDDAClose );
140 add_shortcut( "cdda" );
142 /* Configuration options */
143 add_category_hint( N_("CDX"), NULL, VLC_TRUE );
144 add_integer ( MODULE_STRING "-debug", 0, debug_callback, DEBUG_TEXT,
145 DEBUG_LONGTEXT, VLC_TRUE );
148 set_description( _("CD Audio demux") );
149 set_capability( "demux", 0 );
150 set_callbacks( CDDAOpenDemux, CDDACloseDemux );
151 add_shortcut( "cdda" );
154 /****************************************************************************
156 ****************************************************************************/
159 debug_callback ( vlc_object_t *p_this, const char *psz_name,
160 vlc_value_t oldval, vlc_value_t val, void *p_data )
164 if (NULL == p_cdda_input) return VLC_EGENERIC;
166 p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
168 if (p_cdda->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
169 msg_Dbg( p_cdda_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
170 p_cdda->i_debug, p_cdda->i_debug, val.i_int, val.i_int);
172 p_cdda->i_debug = val.i_int;
176 /* process messages that originate from libcdio. */
178 cdio_log_handler (cdio_log_level_t level, const char message[])
180 cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
184 if (p_cdda->i_debug & INPUT_DBG_CDIO)
185 msg_Dbg( p_cdda_input, message);
188 msg_Warn( p_cdda_input, message);
191 case CDIO_LOG_ASSERT:
192 msg_Err( p_cdda_input, message);
195 msg_Warn( p_cdda_input, message,
196 _("The above message had unknown vcdimager log level"),
203 /*****************************************************************************
204 * CDDAOpen: open cdda
205 *****************************************************************************/
206 static int CDDAOpen( vlc_object_t *p_this )
208 input_thread_t * p_input = (input_thread_t *)p_this;
212 cdda_data_t * p_cdda;
214 input_area_t * p_area;
218 /* Set where to log errors messages from libcdio. */
219 p_cdda_input = (input_thread_t *)p_this;
221 /* parse the options passed in command line : */
222 psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
229 while( *psz_parser && *psz_parser != '@' )
234 if( *psz_parser == '@' )
240 if ('T' == *psz_parser || 't' == *psz_parser )
243 i_title = (int)strtol( psz_parser, NULL, 10 );
244 i_title = i_title ? i_title : 1;
248 /* No source specified, so figure it out. */
249 if( !p_input->psz_access ) {
253 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
256 /* Scan for a CD with a CD-DA in it. */
258 cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
259 if (NULL == cd_drives) return -1;
260 if (cd_drives[0] == NULL) {
261 cdio_free_device_list(cd_drives);
264 psz_source = strdup(cd_drives[0]);
265 cdio_free_device_list(cd_drives);
270 if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
272 msg_Warn( p_input, "could not open %s", psz_source );
278 p_cdda = malloc( sizeof(cdda_data_t) );
281 msg_Err( p_input, "out of memory" );
286 p_cdda->p_cddev = p_cddev;
287 p_cdda->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
288 p_input->p_access_data = (void *)p_cdda;
290 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
292 p_input->i_mtu = CDDA_DATA_ONCE;
294 /* We read the Table Of Content information */
295 p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
296 p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
297 if( p_cdda->i_nb_tracks < 0 )
298 msg_Err( p_input, "unable to count tracks" );
299 else if( p_cdda->i_nb_tracks <= 0 )
300 msg_Err( p_input, "no audio tracks found" );
302 if( p_cdda->i_nb_tracks <= 1)
304 ioctl_Close( p_cdda->p_cddev );
309 if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
312 /* Set stream and area data */
313 vlc_mutex_lock( &p_input->stream.stream_lock );
315 /* Initialize ES structures */
316 input_InitStream( p_input, 0 );
318 /* cdda input method */
319 p_input->stream.i_method = INPUT_METHOD_CDDA;
321 p_input->stream.b_pace_control = 1;
322 p_input->stream.b_seekable = 1;
323 p_input->stream.i_mux_rate = 44100 * 4 / 50;
325 #define area p_input->stream.pp_areas
326 for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
328 input_AddArea( p_input, i, 1 );
330 /* Absolute start offset and size */
332 (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
334 (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
335 * (off_t)CDIO_CD_FRAMESIZE_RAW;
339 p_area = p_input->stream.pp_areas[i_title];
341 CDDASetArea( p_input, p_area );
343 vlc_mutex_unlock( &p_input->stream.stream_lock );
345 if( !p_input->psz_demux || !*p_input->psz_demux )
347 p_input->psz_demux = "cdda";
350 p_input->pf_read = CDDARead;
351 p_input->pf_seek = CDDASeek;
352 p_input->pf_set_area = CDDASetArea;
353 p_input->pf_set_program = CDDASetProgram;
355 /* Update default_pts to a suitable value for cdda access */
356 p_input->i_pts_delay = config_GetInt( p_input,
357 MODULE_STRING "-caching" ) * 1000;
362 /*****************************************************************************
363 * CDDAClose: closes cdda
364 *****************************************************************************/
365 static void CDDAClose( vlc_object_t *p_this )
367 input_thread_t * p_input = (input_thread_t *)p_this;
368 cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
370 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
371 ioctl_Close( p_cdda->p_cddev );
376 /*****************************************************************************
377 * CDDARead: reads from the CDDA into PES packets.
378 *****************************************************************************
379 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
381 *****************************************************************************/
382 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
385 cdda_data_t * p_cdda;
390 p_cdda = (cdda_data_t *)p_input->p_access_data;
394 /* Compute the number of blocks we have to read */
396 i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
398 for ( i_index = 0; i_index < i_blocks; i_index++ )
401 if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer,
402 p_cdda->i_sector) != 0)
404 msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
409 if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
411 input_area_t *p_area;
413 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL),
414 "end of track, cur: %u", p_cdda->i_sector );
416 if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
419 vlc_mutex_lock( &p_input->stream.stream_lock );
420 p_area = p_input->stream.pp_areas[
421 p_input->stream.p_selected_area->i_id + 1 ];
424 CDDASetArea( p_input, p_area );
425 vlc_mutex_unlock( &p_input->stream.stream_lock );
427 i_read += CDIO_CD_FRAMESIZE_RAW;
430 if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
432 msg_Err( p_input, "must read full sectors" );
438 /*****************************************************************************
439 * CDDASetProgram: Does nothing since a CDDA is mono_program
440 *****************************************************************************/
441 static int CDDASetProgram( input_thread_t * p_input,
442 pgrm_descriptor_t * p_program)
444 cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
445 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
449 /*****************************************************************************
450 * CDDASetArea: initialize input data for title x.
451 * It should be called for each user navigation request.
452 ****************************************************************************/
453 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
455 cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
458 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
460 /* we can't use the interface slider until initilization is complete */
461 p_input->stream.b_seekable = 0;
463 if( p_area != p_input->stream.p_selected_area )
465 /* Change the default area */
466 p_input->stream.p_selected_area = p_area;
468 /* Change the current track */
469 p_cdda->i_track = p_area->i_id - 1;
470 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
472 /* Update the navigation variables without triggering a callback */
473 val.i_int = p_area->i_id;
474 var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
477 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
479 p_input->stream.p_selected_area->i_tell =
480 (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
481 - p_input->stream.p_selected_area->i_start;
483 /* warn interface that something has changed */
484 p_input->stream.b_seekable = 1;
485 p_input->stream.b_changed = 1;
490 /****************************************************************************
492 ****************************************************************************/
493 static void CDDASeek( input_thread_t * p_input, off_t i_off )
495 cdda_data_t * p_cdda;
497 p_cdda = (cdda_data_t *) p_input->p_access_data;
499 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
500 + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
502 vlc_mutex_lock( &p_input->stream.stream_lock );
503 p_input->stream.p_selected_area->i_tell =
504 (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
505 - p_input->stream.p_selected_area->i_start;
507 vlc_mutex_unlock( &p_input->stream.stream_lock );
509 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
510 "sector %ud, offset: %lld, i_tell: %lld", p_cdda->i_sector, i_off,
511 p_input->stream.p_selected_area->i_tell );
515 /****************************************************************************
517 ****************************************************************************/
518 static int CDDAOpenDemux ( vlc_object_t * p_this)
520 input_thread_t *p_input = (input_thread_t *)p_this;
521 demux_sys_t *p_demux;
524 if( p_input->stream.i_method != INPUT_METHOD_CDDA )
529 p_demux = malloc( sizeof( es_descriptor_t ) );
531 p_demux->p_es = NULL;
533 p_input->pf_demux = CDDADemux;
534 p_input->pf_demux_control = demux_vaControlDefault;
535 p_input->pf_rewind = NULL;
536 p_input->p_demux_data = p_demux;
538 vlc_mutex_lock( &p_input->stream.stream_lock );
539 if( input_AddProgram( p_input, 0, 0) == NULL )
541 msg_Err( p_input, "cannot add program" );
542 free( p_input->p_demux_data );
545 p_input->stream.pp_programs[0]->b_is_ok = 0;
546 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
549 p_demux->p_es = input_AddES( p_input,
550 p_input->stream.p_selected_program,
551 1 /* id */, AUDIO_ES, NULL, 0 );
554 vlc_mutex_unlock( &p_input->stream.stream_lock );
555 msg_Err( p_input, "out of memory" );
556 free( p_input->p_demux_data );
559 p_demux->p_es->i_stream_id = 1;
560 p_demux->p_es->i_fourcc = VLC_FOURCC('a','r','a','w');
562 p_demux->p_es->p_waveformatex = p_wf = malloc( sizeof( WAVEFORMATEX ) );
563 p_wf->wFormatTag = WAVE_FORMAT_PCM;
565 p_wf->nSamplesPerSec = 44100;
566 p_wf->nAvgBytesPerSec = 2 * 44100 * 2;
567 p_wf->nBlockAlign = 4;
568 p_wf->wBitsPerSample = 16;
571 input_SelectES( p_input, p_demux->p_es );
573 p_input->stream.p_selected_program->b_is_ok = 1;
574 vlc_mutex_unlock( &p_input->stream.stream_lock );
579 static void CDDACloseDemux( vlc_object_t * p_this)
581 input_thread_t *p_input = (input_thread_t*)p_this;
582 demux_sys_t *p_demux = (demux_sys_t*)p_input->p_demux_data;
585 p_input->p_demux_data = NULL;
589 static int CDDADemux( input_thread_t * p_input )
591 demux_sys_t *p_demux = (demux_sys_t*)p_input->p_demux_data;
593 data_packet_t * p_data;
594 pes_packet_t * p_pes;
596 input_ClockManageRef( p_input,
597 p_input->stream.p_selected_program,
600 i_read = input_SplitBuffer( p_input, &p_data, CDIO_CD_FRAMESIZE_RAW );
606 p_pes = input_NewPES( p_input->p_method_data );
610 msg_Err( p_input, "out of memory" );
611 input_DeletePacket( p_input->p_method_data, p_data );
615 p_pes->i_rate = p_input->stream.control.i_rate;
616 p_pes->p_first = p_pes->p_last = p_data;
617 p_pes->i_nb_data = 1;
618 p_pes->i_pes_size = i_read;
621 p_pes->i_pts = input_ClockGetTS( p_input,
622 p_input->stream.p_selected_program,
625 if( p_demux->p_es->p_decoder_fifo )
627 input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
631 input_DeletePES( p_input->p_method_data, p_pes );
634 p_demux->i_pts += ((mtime_t)90000) * i_read
635 / (mtime_t)44100 / 4 /* stereo 16 bits */;