1 /*****************************************************************************
2 * cddax.c : CD digital audio input module for vlc using libcdio
3 *****************************************************************************
4 * Copyright (C) 2000,2003 VideoLAN
5 * $Id: access.c,v 1.1 2003/11/26 03:35:26 rocky Exp $
7 * Authors: Rocky Bernstein <rocky@panix.com>
8 * Laurent Aimar <fenrir@via.ecp.fr>
9 * Gildas Bazin <gbazin@netcourrier.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 *****************************************************************************/
34 #include <vlc/input.h>
35 #include <sys/types.h>
36 #include <cdio/cdio.h>
37 #include <cdio/cd_types.h>
50 /* how many blocks Open will read in each loop */
51 #define CDDA_BLOCKS_ONCE 1
52 #define CDDA_DATA_ONCE (CDDA_BLOCKS_ONCE * CDIO_CD_FRAMESIZE_RAW)
54 #define DEBUG_TEXT N_("set debug mask for additional debugging.")
55 #define DEBUG_LONGTEXT N_( \
56 "This integer when viewed in binary is a debugging mask\n" \
65 #define DEV_TEXT N_("CD-ROM device name")
66 #define DEV_LONGTEXT N_( \
67 "Specify the name of the CD-ROM device that will be used by default. " \
68 "If you don't specify anything, we'll scan for a suitable CD-ROM device.")
70 /*****************************************************************************
71 * intf_sys_t: description and status of interface
72 *****************************************************************************/
75 input_thread_t * p_input;
77 vlc_bool_t b_click, b_move, b_key_pressed;
80 /* FIXME: This variable is a hack. Would be nice to eliminate. */
81 static input_thread_t *p_cdda_input = NULL;
83 /*****************************************************************************
85 *****************************************************************************/
86 static int CDDARead ( input_thread_t *, byte_t *, size_t );
87 static void CDDASeek ( input_thread_t *, off_t );
88 static int CDDASetArea ( input_thread_t *, input_area_t * );
89 static int CDDASetProgram ( input_thread_t *, pgrm_descriptor_t * );
91 /****************************************************************************
93 ****************************************************************************/
96 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
97 vlc_value_t oldval, vlc_value_t val, void *p_data )
101 if (NULL == p_cdda_input) return VLC_EGENERIC;
103 p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
105 if (p_cdda->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
106 msg_Dbg( p_cdda_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
107 p_cdda->i_debug, p_cdda->i_debug, val.i_int, val.i_int);
109 p_cdda->i_debug = val.i_int;
113 /* process messages that originate from libcdio. */
115 cdio_log_handler (cdio_log_level_t level, const char message[])
117 cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
121 if (p_cdda->i_debug & INPUT_DBG_CDIO)
122 msg_Dbg( p_cdda_input, message);
125 msg_Warn( p_cdda_input, message);
128 case CDIO_LOG_ASSERT:
129 msg_Err( p_cdda_input, message);
132 msg_Warn( p_cdda_input, message,
133 _("The above message had unknown vcdimager log level"),
140 /*****************************************************************************
142 *****************************************************************************/
144 E_(Open)( vlc_object_t *p_this )
146 input_thread_t * p_input = (input_thread_t *)p_this;
150 cdda_data_t * p_cdda;
155 /* Set where to log errors messages from libcdio. */
156 p_cdda_input = (input_thread_t *)p_this;
158 /* parse the options passed in command line : */
159 psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
166 while( *psz_parser && *psz_parser != '@' )
171 if( *psz_parser == '@' )
177 if ('T' == *psz_parser || 't' == *psz_parser )
180 i_title = (int)strtol( psz_parser, NULL, 10 );
181 i_title = i_title ? i_title : 1;
185 /* No source specified, so figure it out. */
186 if( !p_input->psz_access ) {
190 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
192 if( !psz_source || 0==strlen(psz_source) ) {
193 /* Scan for a CD-ROM drive with a CD-DA in it. */
195 cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
196 if (NULL == cd_drives) return -1;
197 if (cd_drives[0] == NULL) {
198 cdio_free_device_list(cd_drives);
201 psz_source = strdup(cd_drives[0]);
202 cdio_free_device_list(cd_drives);
207 cdio_log_set_handler ( cdio_log_handler );
209 if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
211 msg_Warn( p_input, "could not open %s", psz_source );
217 p_cdda = malloc( sizeof(cdda_data_t) );
220 msg_Err( p_input, "out of memory" );
225 p_cdda->p_cddev = p_cddev;
226 p_cdda->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
227 p_input->p_access_data = (void *)p_cdda;
229 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
231 p_input->i_mtu = CDDA_DATA_ONCE;
233 /* We read the Table Of Content information */
234 p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
235 p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
236 if( p_cdda->i_nb_tracks < 0 )
237 msg_Err( p_input, "unable to count tracks" );
238 else if( p_cdda->i_nb_tracks <= 0 )
239 msg_Err( p_input, "no audio tracks found" );
241 if( p_cdda->i_nb_tracks <= 1)
243 ioctl_Close( p_cdda->p_cddev );
248 if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
251 /* Set stream and area data */
252 vlc_mutex_lock( &p_input->stream.stream_lock );
254 /* Initialize ES structures */
255 input_InitStream( p_input, 0 );
257 /* cdda input method */
258 p_input->stream.i_method = INPUT_METHOD_CDDA;
260 p_input->stream.b_pace_control = 1;
261 p_input->stream.b_seekable = 1;
262 p_input->stream.i_mux_rate = 44100 * 4 / 50;
264 #define area p_input->stream.pp_areas
265 for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
267 input_AddArea( p_input, i, 1 );
269 /* Absolute start offset and size */
271 (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
273 (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
274 * (off_t)CDIO_CD_FRAMESIZE_RAW;
278 CDDAPlay( p_input, i_title);
280 vlc_mutex_unlock( &p_input->stream.stream_lock );
282 if( !p_input->psz_demux || !*p_input->psz_demux )
284 p_input->psz_demux = "cdda";
287 p_input->pf_read = CDDARead;
288 p_input->pf_seek = CDDASeek;
289 p_input->pf_set_area = CDDASetArea;
290 p_input->pf_set_program = CDDASetProgram;
292 /* Update default_pts to a suitable value for cdda access */
293 p_input->i_pts_delay = config_GetInt( p_input,
294 MODULE_STRING "-caching" ) * 1000;
296 p_cdda->p_intf = intf_Create( p_input, "cddax" );
297 intf_RunThread( p_cdda->p_intf );
302 /*****************************************************************************
303 * CDDAPlay: Arrange things so we play the specified track.
304 * VLC_TRUE is returned if there was no error.
305 *****************************************************************************/
307 CDDAPlay( input_thread_t *p_input, int i_track )
309 cdda_data_t *p_cdda = (cdda_data_t *) p_input->p_access_data;
311 if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
314 CDDASetArea( p_input, p_input->stream.pp_areas[i_track] );
318 /*****************************************************************************
319 * CDDAClose: closes cdda
320 *****************************************************************************/
322 E_(Close)( vlc_object_t *p_this )
324 input_thread_t * p_input = (input_thread_t *)p_this;
325 cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
327 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
328 ioctl_Close( p_cdda->p_cddev );
333 /*****************************************************************************
334 * CDDARead: reads from the CDDA into PES packets.
335 *****************************************************************************
336 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
338 *****************************************************************************/
339 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
342 cdda_data_t * p_cdda;
347 p_cdda = (cdda_data_t *)p_input->p_access_data;
351 /* Compute the number of blocks we have to read */
353 i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
355 for ( i_index = 0; i_index < i_blocks; i_index++ )
358 if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer,
359 p_cdda->i_sector) != 0)
361 msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
366 if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
368 input_area_t *p_area;
370 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL),
371 "end of track, cur: %u", p_cdda->i_sector );
373 if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
376 vlc_mutex_lock( &p_input->stream.stream_lock );
377 p_area = p_input->stream.pp_areas[
378 p_input->stream.p_selected_area->i_id + 1 ];
381 CDDASetArea( p_input, p_area );
382 vlc_mutex_unlock( &p_input->stream.stream_lock );
384 i_read += CDIO_CD_FRAMESIZE_RAW;
387 if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
389 msg_Err( p_input, "must read full sectors" );
395 /*****************************************************************************
396 * CDDASetProgram: Does nothing since a CDDA is mono_program
397 *****************************************************************************/
398 static int CDDASetProgram( input_thread_t * p_input,
399 pgrm_descriptor_t * p_program)
401 cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
402 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
406 /*****************************************************************************
407 * CDDASetArea: initialize input data for title x.
408 * It should be called for each user navigation request.
409 ****************************************************************************/
410 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
412 cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
415 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
417 /* we can't use the interface slider until initilization is complete */
418 p_input->stream.b_seekable = 0;
420 if( p_area != p_input->stream.p_selected_area )
422 /* Change the default area */
423 p_input->stream.p_selected_area = p_area;
425 /* Change the current track */
426 p_cdda->i_track = p_area->i_id - 1;
427 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
429 /* Update the navigation variables without triggering a callback */
430 val.i_int = p_area->i_id;
431 var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
434 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
436 p_input->stream.p_selected_area->i_tell =
437 (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
438 - p_input->stream.p_selected_area->i_start;
440 /* warn interface that something has changed */
441 p_input->stream.b_seekable = 1;
442 p_input->stream.b_changed = 1;
447 /****************************************************************************
449 ****************************************************************************/
450 static void CDDASeek( input_thread_t * p_input, off_t i_off )
452 cdda_data_t * p_cdda;
454 p_cdda = (cdda_data_t *) p_input->p_access_data;
456 p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
457 + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
459 vlc_mutex_lock( &p_input->stream.stream_lock );
460 p_input->stream.p_selected_area->i_tell =
461 (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
462 - p_input->stream.p_selected_area->i_start;
464 vlc_mutex_unlock( &p_input->stream.stream_lock );
466 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
467 "sector %ud, offset: %lld, i_tell: %lld", p_cdda->i_sector, i_off,
468 p_input->stream.p_selected_area->i_tell );
472 /*****************************************************************************
473 * Demux: local prototypes
474 *****************************************************************************/
481 static int Demux ( input_thread_t * p_input );
483 /****************************************************************************
485 ****************************************************************************/
487 E_(DemuxOpen) ( vlc_object_t * p_this)
489 input_thread_t *p_input = (input_thread_t *)p_this;
494 if( p_input->stream.i_method != INPUT_METHOD_CDDA )
499 p_input->pf_demux = Demux;
500 p_input->pf_rewind = NULL;
501 p_input->pf_demux_control = demux_vaControlDefault;
502 p_input->p_demux_data = p_sys = malloc( sizeof( es_descriptor_t ) );
505 vlc_mutex_lock( &p_input->stream.stream_lock );
506 if( input_InitStream( p_input, 0 ) == -1)
508 vlc_mutex_unlock( &p_input->stream.stream_lock );
509 msg_Err( p_input, "cannot init stream" );
513 p_input->stream.i_mux_rate = 4 * 44100 / 50;
514 vlc_mutex_unlock( &p_input->stream.stream_lock );
516 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', 'r', 'a', 'w' ) );
517 fmt.audio.i_channels = 2;
518 fmt.audio.i_rate = 44100;
519 fmt.audio.i_bitspersample = 16;
520 fmt.audio.i_blockalign = 4;
521 fmt.i_bitrate = 4 * 44100 * 8;
523 p_sys->p_es = es_out_Add( p_input->p_es_out, &fmt );
528 /****************************************************************************
530 ****************************************************************************/
532 E_(DemuxClose)( vlc_object_t * p_this)
534 input_thread_t *p_input = (input_thread_t*)p_this;
535 demux_sys_t *p_sys = (demux_sys_t*)p_input->p_demux_data;
541 /****************************************************************************
543 ****************************************************************************/
544 static int Demux( input_thread_t * p_input )
546 demux_sys_t *p_sys = (demux_sys_t*)p_input->p_demux_data;
550 input_ClockManageRef( p_input,
551 p_input->stream.p_selected_program,
554 if( ( p_block = stream_Block( p_input->s, CDIO_CD_FRAMESIZE_RAW ) ) == NULL )
560 p_block->i_pts = input_ClockGetTS( p_input,
561 p_input->stream.p_selected_program,
563 p_block->i_length = (mtime_t)90000 * (mtime_t)p_block->i_buffer/44100/4;
565 p_sys->i_pts += p_block->i_length;
567 es_out_Send( p_input->p_es_out, p_sys->p_es, p_block );