]> git.sesse.net Git - vlc/blob - modules/access/cdda/access.c
Remove unused code accidentially duplicated in split.
[vlc] / modules / access / cdda / access.c
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.2 2003/11/26 03:40:31 rocky Exp $
6  *
7  * Authors: Rocky Bernstein <rocky@panix.com> 
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34 #include <vlc/input.h>
35 #include <sys/types.h>
36 #include <cdio/cdio.h>
37 #include <cdio/cd_types.h>
38
39 #include "codecs.h"
40 #include "vlc_keys.h"
41
42 #ifdef HAVE_UNISTD_H
43 #   include <unistd.h>
44 #endif
45
46 #include <string.h>
47
48 #include "cdda.h"
49
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)
53
54 /* FIXME: This variable is a hack. Would be nice to eliminate. */
55 static input_thread_t *p_cdda_input = NULL;
56
57 /*****************************************************************************
58  * Local prototypes
59  *****************************************************************************/
60 static int  CDDARead         ( input_thread_t *, byte_t *, size_t );
61 static void CDDASeek         ( input_thread_t *, off_t );
62 static int  CDDASetArea      ( input_thread_t *, input_area_t * );
63 static int  CDDASetProgram   ( input_thread_t *, pgrm_descriptor_t * );
64
65 /****************************************************************************
66  * Private functions
67  ****************************************************************************/
68
69 int
70 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
71                       vlc_value_t oldval, vlc_value_t val, void *p_data )
72 {
73   cdda_data_t *p_cdda;
74
75   if (NULL == p_cdda_input) return VLC_EGENERIC;
76   
77   p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
78
79   if (p_cdda->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
80     msg_Dbg( p_cdda_input, "Old debug (x%0x) %d, new debug (x%0x) %d", 
81              p_cdda->i_debug, p_cdda->i_debug, val.i_int, val.i_int);
82   }
83   p_cdda->i_debug = val.i_int;
84   return VLC_SUCCESS;
85 }
86
87 /* process messages that originate from libcdio. */
88 static void
89 cdio_log_handler (cdio_log_level_t level, const char message[])
90 {
91   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
92   switch (level) {
93   case CDIO_LOG_DEBUG:
94   case CDIO_LOG_INFO:
95     if (p_cdda->i_debug & INPUT_DBG_CDIO) 
96       msg_Dbg( p_cdda_input, message);
97     break;
98   case CDIO_LOG_WARN:
99     msg_Warn( p_cdda_input, message);
100     break;
101   case CDIO_LOG_ERROR:
102   case CDIO_LOG_ASSERT:
103     msg_Err( p_cdda_input, message);
104     break;
105   default:
106     msg_Warn( p_cdda_input, message,
107             _("The above message had unknown vcdimager log level"), 
108             level);
109   }
110   return;
111 }
112
113
114 /*****************************************************************************
115  * Open: open cdda
116  *****************************************************************************/
117 int 
118 E_(Open)( vlc_object_t *p_this )
119 {
120     input_thread_t *        p_input = (input_thread_t *)p_this;
121     char *                  psz_orig;
122     char *                  psz_parser;
123     char *                  psz_source;
124     cdda_data_t *           p_cdda;
125     int                     i;
126     int                     i_title = 1;
127     cddev_t                 *p_cddev;
128
129     /* Set where to log errors messages from libcdio. */
130     p_cdda_input = (input_thread_t *)p_this;
131
132     /* parse the options passed in command line : */
133     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
134
135     if( !psz_orig )
136     {
137         return( -1 );
138     }
139
140     while( *psz_parser && *psz_parser != '@' )
141     {
142         psz_parser++;
143     }
144
145     if( *psz_parser == '@' )
146     {
147         /* Found options */
148         *psz_parser = '\0';
149         ++psz_parser;
150
151         if ('T' == *psz_parser || 't' == *psz_parser ) 
152             ++psz_parser;
153           
154         i_title = (int)strtol( psz_parser, NULL, 10 );
155         i_title = i_title ? i_title : 1;
156     }
157
158     if( !*psz_source ) {
159       /* No source specified, so figure it out. */
160       if( !p_input->psz_access ) {
161         free( psz_orig );
162         return -1;
163       }
164       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
165       
166       if( !psz_source || 0==strlen(psz_source) ) {
167         /* Scan for a CD-ROM drive with a CD-DA in it. */
168         char **cd_drives = 
169           cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
170         if (NULL == cd_drives) return -1;
171         if (cd_drives[0] == NULL) {
172           cdio_free_device_list(cd_drives);
173           return -1;
174         }
175         psz_source = strdup(cd_drives[0]);
176         cdio_free_device_list(cd_drives);
177       }
178     }
179
180     /* Open CDDA */
181     cdio_log_set_handler ( cdio_log_handler );
182
183     if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
184     {
185         msg_Warn( p_input, "could not open %s", psz_source );
186         free( psz_source );
187         return -1;
188     }
189     free( psz_source );
190
191     p_cdda = malloc( sizeof(cdda_data_t) );
192     if( p_cdda == NULL )
193     {
194         msg_Err( p_input, "out of memory" );
195         free( psz_source );
196         return -1;
197     }
198
199     p_cdda->p_cddev        = p_cddev;
200     p_cdda->i_debug        = config_GetInt( p_this, MODULE_STRING "-debug" );
201     p_input->p_access_data = (void *)p_cdda;
202
203     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
204
205     p_input->i_mtu = CDDA_DATA_ONCE;
206
207     /* We read the Table Of Content information */
208     p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
209                               p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
210     if( p_cdda->i_nb_tracks < 0 )
211         msg_Err( p_input, "unable to count tracks" );
212     else if( p_cdda->i_nb_tracks <= 0 )
213         msg_Err( p_input, "no audio tracks found" );
214
215     if( p_cdda->i_nb_tracks <= 1)
216     {
217         ioctl_Close( p_cdda->p_cddev );
218         free( p_cdda );
219         return -1;
220     }
221
222     if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
223         i_title = 1;
224
225     /* Set stream and area data */
226     vlc_mutex_lock( &p_input->stream.stream_lock );
227
228     /* Initialize ES structures */
229     input_InitStream( p_input, 0 );
230
231     /* cdda input method */
232     p_input->stream.i_method = INPUT_METHOD_CDDA;
233
234     p_input->stream.b_pace_control = 1;
235     p_input->stream.b_seekable = 1;
236     p_input->stream.i_mux_rate = 44100 * 4 / 50;
237
238 #define area p_input->stream.pp_areas
239     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
240     {
241         input_AddArea( p_input, i, 1 );
242
243         /* Absolute start offset and size */
244         area[i]->i_start =
245             (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
246         area[i]->i_size =
247             (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
248             * (off_t)CDIO_CD_FRAMESIZE_RAW;
249     }
250 #undef area
251
252     CDDAPlay( p_input, i_title);
253
254     vlc_mutex_unlock( &p_input->stream.stream_lock );
255
256     if( !p_input->psz_demux || !*p_input->psz_demux )
257     {
258         p_input->psz_demux = "cdda";
259     }
260
261     p_input->pf_read = CDDARead;
262     p_input->pf_seek = CDDASeek;
263     p_input->pf_set_area = CDDASetArea;
264     p_input->pf_set_program = CDDASetProgram;
265
266     /* Update default_pts to a suitable value for cdda access */
267     p_input->i_pts_delay = config_GetInt( p_input, 
268                                           MODULE_STRING "-caching" ) * 1000;
269
270     p_cdda->p_intf = intf_Create( p_input, "cddax" );
271     intf_RunThread( p_cdda->p_intf );
272
273     return 0;
274 }
275
276 /*****************************************************************************
277  * CDDAPlay: Arrange things so we play the specified track.
278  * VLC_TRUE is returned if there was no error.
279  *****************************************************************************/
280 vlc_bool_t
281 CDDAPlay( input_thread_t *p_input, int i_track )
282 {
283   cdda_data_t *p_cdda = (cdda_data_t *) p_input->p_access_data;
284
285   if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
286     return VLC_FALSE;
287
288   CDDASetArea( p_input, p_input->stream.pp_areas[i_track] );
289   return VLC_TRUE;
290 }
291
292 /*****************************************************************************
293  * CDDAClose: closes cdda
294  *****************************************************************************/
295 void 
296 E_(Close)( vlc_object_t *p_this )
297 {
298     input_thread_t *   p_input = (input_thread_t *)p_this;
299     cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
300
301     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
302     ioctl_Close( p_cdda->p_cddev );
303     free( p_cdda );
304     p_cdda_input = NULL;
305 }
306
307 /*****************************************************************************
308  * CDDARead: reads from the CDDA into PES packets.
309  *****************************************************************************
310  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
311  * bytes.
312  *****************************************************************************/
313 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
314                      size_t i_len )
315 {
316     cdda_data_t *           p_cdda;
317     int                     i_blocks;
318     int                     i_index;
319     int                     i_read;
320
321     p_cdda = (cdda_data_t *)p_input->p_access_data;
322
323     i_read = 0;
324
325     /* Compute the number of blocks we have to read */
326
327     i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
328
329     for ( i_index = 0; i_index < i_blocks; i_index++ )
330     {
331
332       if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer, 
333                                  p_cdda->i_sector) != 0)
334         {
335           msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
336           return -1;
337         }
338
339         p_cdda->i_sector ++;
340         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
341         {
342             input_area_t *p_area;
343
344             dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL), 
345                        "end of track, cur: %u", p_cdda->i_sector );
346
347             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
348                 return 0; /* EOF */
349
350             vlc_mutex_lock( &p_input->stream.stream_lock );
351             p_area = p_input->stream.pp_areas[
352                     p_input->stream.p_selected_area->i_id + 1 ];
353
354             p_area->i_part = 1;
355             CDDASetArea( p_input, p_area );
356             vlc_mutex_unlock( &p_input->stream.stream_lock );
357         }
358         i_read += CDIO_CD_FRAMESIZE_RAW;
359     }
360
361     if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
362     {
363         msg_Err( p_input, "must read full sectors" );
364     }
365
366     return i_read;
367 }
368
369 /*****************************************************************************
370  * CDDASetProgram: Does nothing since a CDDA is mono_program
371  *****************************************************************************/
372 static int CDDASetProgram( input_thread_t * p_input,
373                            pgrm_descriptor_t * p_program)
374 {
375     cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
376     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
377     return 0;
378 }
379
380 /*****************************************************************************
381  * CDDASetArea: initialize input data for title x.
382  * It should be called for each user navigation request.
383  ****************************************************************************/
384 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
385 {
386     cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
387     vlc_value_t val;
388
389     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
390
391     /* we can't use the interface slider until initilization is complete */
392     p_input->stream.b_seekable = 0;
393
394     if( p_area != p_input->stream.p_selected_area )
395     {
396         /* Change the default area */
397         p_input->stream.p_selected_area = p_area;
398
399         /* Change the current track */
400         p_cdda->i_track = p_area->i_id - 1;
401         p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
402
403         /* Update the navigation variables without triggering a callback */
404         val.i_int = p_area->i_id;
405         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
406     }
407
408     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
409
410     p_input->stream.p_selected_area->i_tell =
411         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
412          - p_input->stream.p_selected_area->i_start;
413
414     /* warn interface that something has changed */
415     p_input->stream.b_seekable = 1;
416     p_input->stream.b_changed = 1;
417
418     return 0;
419 }
420
421 /****************************************************************************
422  * CDDASeek
423  ****************************************************************************/
424 static void CDDASeek( input_thread_t * p_input, off_t i_off )
425 {
426     cdda_data_t * p_cdda;
427
428     p_cdda = (cdda_data_t *) p_input->p_access_data;
429
430     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
431                        + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
432
433     vlc_mutex_lock( &p_input->stream.stream_lock );
434     p_input->stream.p_selected_area->i_tell =
435         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
436          - p_input->stream.p_selected_area->i_start;
437
438     vlc_mutex_unlock( &p_input->stream.stream_lock );
439
440     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
441     "sector %ud, offset: %lld, i_tell: %lld",  p_cdda->i_sector, i_off, 
442                p_input->stream.p_selected_area->i_tell );
443
444 }
445
446 /*****************************************************************************
447  * Demux: local prototypes
448  *****************************************************************************/
449 struct demux_sys_t
450 {
451     es_out_id_t *p_es;
452     mtime_t     i_pts;
453 };
454
455 static int  Demux     ( input_thread_t * p_input );
456
457 /****************************************************************************
458  * DemuxOpen:
459  ****************************************************************************/
460 int  
461 E_(DemuxOpen)    ( vlc_object_t * p_this)
462 {
463     input_thread_t *p_input = (input_thread_t *)p_this;
464     demux_sys_t    *p_sys;
465
466     es_format_t    fmt;
467
468     if( p_input->stream.i_method != INPUT_METHOD_CDDA )
469     {
470         return VLC_EGENERIC;
471     }
472
473     p_input->pf_demux  = Demux;
474     p_input->pf_rewind = NULL;
475     p_input->pf_demux_control = demux_vaControlDefault;
476     p_input->p_demux_data = p_sys = malloc( sizeof( es_descriptor_t ) );
477     p_sys->i_pts = 0;
478
479     vlc_mutex_lock( &p_input->stream.stream_lock );
480     if( input_InitStream( p_input, 0 ) == -1)
481     {
482         vlc_mutex_unlock( &p_input->stream.stream_lock );
483         msg_Err( p_input, "cannot init stream" );
484         free( p_sys );
485         return VLC_EGENERIC;
486     }
487     p_input->stream.i_mux_rate = 4 * 44100 / 50;
488     vlc_mutex_unlock( &p_input->stream.stream_lock );
489
490     es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'a', 'r', 'a', 'w' ) );
491     fmt.audio.i_channels = 2;
492     fmt.audio.i_rate = 44100;
493     fmt.audio.i_bitspersample = 16;
494     fmt.audio.i_blockalign = 4;
495     fmt.i_bitrate = 4 * 44100 * 8;
496
497     p_sys->p_es =  es_out_Add( p_input->p_es_out, &fmt );
498
499     return VLC_SUCCESS;
500 }
501
502 /****************************************************************************
503  * DemuxClose:
504  ****************************************************************************/
505 void 
506 E_(DemuxClose)( vlc_object_t * p_this)
507 {
508     input_thread_t *p_input = (input_thread_t*)p_this;
509     demux_sys_t    *p_sys = (demux_sys_t*)p_input->p_demux_data;
510
511     free( p_sys );
512     return;
513 }
514
515 /****************************************************************************
516  * Demux:
517  ****************************************************************************/
518 static int  Demux( input_thread_t * p_input )
519 {
520     demux_sys_t    *p_sys = (demux_sys_t*)p_input->p_demux_data;
521     block_t        *p_block;
522
523
524     input_ClockManageRef( p_input,
525                           p_input->stream.p_selected_program,
526                           p_sys->i_pts );
527
528     if( ( p_block = stream_Block( p_input->s, CDIO_CD_FRAMESIZE_RAW ) ) == NULL )
529     {
530         /* eof */
531         return 0;
532     }
533     p_block->i_dts =
534     p_block->i_pts = input_ClockGetTS( p_input,
535                                        p_input->stream.p_selected_program,
536                                        p_sys->i_pts );
537     p_block->i_length = (mtime_t)90000 * (mtime_t)p_block->i_buffer/44100/4;
538
539     p_sys->i_pts += p_block->i_length;
540
541     es_out_Send( p_input->p_es_out, p_sys->p_es, p_block );
542
543     return 1;
544 }
545