]> git.sesse.net Git - vlc/blob - modules/access/cdda/access.c
Split out cdda to facilitate later changes.
[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.1 2003/11/26 03:35:26 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 #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" \
57     "MRL             1\n" \
58     "events          2\n" \
59     "external call   4\n" \
60     "all calls       8\n" \
61     "LSN      (10)  16\n" \
62     "libcdio  (20)  32\n" \
63     "seeks    (40)  64\n" )
64
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.")
69
70 /*****************************************************************************
71  * intf_sys_t: description and status of interface
72  *****************************************************************************/
73 struct intf_sys_t
74 {
75     input_thread_t    * p_input;
76     cdda_data_t       * p_cdda;
77     vlc_bool_t          b_click, b_move, b_key_pressed;
78 };
79
80 /* FIXME: This variable is a hack. Would be nice to eliminate. */
81 static input_thread_t *p_cdda_input = NULL;
82
83 /*****************************************************************************
84  * Local prototypes
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 * );
90
91 /****************************************************************************
92  * Private functions
93  ****************************************************************************/
94
95 int
96 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
97                       vlc_value_t oldval, vlc_value_t val, void *p_data )
98 {
99   cdda_data_t *p_cdda;
100
101   if (NULL == p_cdda_input) return VLC_EGENERIC;
102   
103   p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
104
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);
108   }
109   p_cdda->i_debug = val.i_int;
110   return VLC_SUCCESS;
111 }
112
113 /* process messages that originate from libcdio. */
114 static void
115 cdio_log_handler (cdio_log_level_t level, const char message[])
116 {
117   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
118   switch (level) {
119   case CDIO_LOG_DEBUG:
120   case CDIO_LOG_INFO:
121     if (p_cdda->i_debug & INPUT_DBG_CDIO) 
122       msg_Dbg( p_cdda_input, message);
123     break;
124   case CDIO_LOG_WARN:
125     msg_Warn( p_cdda_input, message);
126     break;
127   case CDIO_LOG_ERROR:
128   case CDIO_LOG_ASSERT:
129     msg_Err( p_cdda_input, message);
130     break;
131   default:
132     msg_Warn( p_cdda_input, message,
133             _("The above message had unknown vcdimager log level"), 
134             level);
135   }
136   return;
137 }
138
139
140 /*****************************************************************************
141  * Open: open cdda
142  *****************************************************************************/
143 int 
144 E_(Open)( vlc_object_t *p_this )
145 {
146     input_thread_t *        p_input = (input_thread_t *)p_this;
147     char *                  psz_orig;
148     char *                  psz_parser;
149     char *                  psz_source;
150     cdda_data_t *           p_cdda;
151     int                     i;
152     int                     i_title = 1;
153     cddev_t                 *p_cddev;
154
155     /* Set where to log errors messages from libcdio. */
156     p_cdda_input = (input_thread_t *)p_this;
157
158     /* parse the options passed in command line : */
159     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
160
161     if( !psz_orig )
162     {
163         return( -1 );
164     }
165
166     while( *psz_parser && *psz_parser != '@' )
167     {
168         psz_parser++;
169     }
170
171     if( *psz_parser == '@' )
172     {
173         /* Found options */
174         *psz_parser = '\0';
175         ++psz_parser;
176
177         if ('T' == *psz_parser || 't' == *psz_parser ) 
178             ++psz_parser;
179           
180         i_title = (int)strtol( psz_parser, NULL, 10 );
181         i_title = i_title ? i_title : 1;
182     }
183
184     if( !*psz_source ) {
185       /* No source specified, so figure it out. */
186       if( !p_input->psz_access ) {
187         free( psz_orig );
188         return -1;
189       }
190       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
191       
192       if( !psz_source || 0==strlen(psz_source) ) {
193         /* Scan for a CD-ROM drive with a CD-DA in it. */
194         char **cd_drives = 
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);
199           return -1;
200         }
201         psz_source = strdup(cd_drives[0]);
202         cdio_free_device_list(cd_drives);
203       }
204     }
205
206     /* Open CDDA */
207     cdio_log_set_handler ( cdio_log_handler );
208
209     if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
210     {
211         msg_Warn( p_input, "could not open %s", psz_source );
212         free( psz_source );
213         return -1;
214     }
215     free( psz_source );
216
217     p_cdda = malloc( sizeof(cdda_data_t) );
218     if( p_cdda == NULL )
219     {
220         msg_Err( p_input, "out of memory" );
221         free( psz_source );
222         return -1;
223     }
224
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;
228
229     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
230
231     p_input->i_mtu = CDDA_DATA_ONCE;
232
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" );
240
241     if( p_cdda->i_nb_tracks <= 1)
242     {
243         ioctl_Close( p_cdda->p_cddev );
244         free( p_cdda );
245         return -1;
246     }
247
248     if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
249         i_title = 1;
250
251     /* Set stream and area data */
252     vlc_mutex_lock( &p_input->stream.stream_lock );
253
254     /* Initialize ES structures */
255     input_InitStream( p_input, 0 );
256
257     /* cdda input method */
258     p_input->stream.i_method = INPUT_METHOD_CDDA;
259
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;
263
264 #define area p_input->stream.pp_areas
265     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
266     {
267         input_AddArea( p_input, i, 1 );
268
269         /* Absolute start offset and size */
270         area[i]->i_start =
271             (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
272         area[i]->i_size =
273             (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
274             * (off_t)CDIO_CD_FRAMESIZE_RAW;
275     }
276 #undef area
277
278     CDDAPlay( p_input, i_title);
279
280     vlc_mutex_unlock( &p_input->stream.stream_lock );
281
282     if( !p_input->psz_demux || !*p_input->psz_demux )
283     {
284         p_input->psz_demux = "cdda";
285     }
286
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;
291
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;
295
296     p_cdda->p_intf = intf_Create( p_input, "cddax" );
297     intf_RunThread( p_cdda->p_intf );
298
299     return 0;
300 }
301
302 /*****************************************************************************
303  * CDDAPlay: Arrange things so we play the specified track.
304  * VLC_TRUE is returned if there was no error.
305  *****************************************************************************/
306 vlc_bool_t
307 CDDAPlay( input_thread_t *p_input, int i_track )
308 {
309   cdda_data_t *p_cdda = (cdda_data_t *) p_input->p_access_data;
310
311   if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
312     return VLC_FALSE;
313
314   CDDASetArea( p_input, p_input->stream.pp_areas[i_track] );
315   return VLC_TRUE;
316 }
317
318 /*****************************************************************************
319  * CDDAClose: closes cdda
320  *****************************************************************************/
321 void 
322 E_(Close)( vlc_object_t *p_this )
323 {
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;
326
327     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
328     ioctl_Close( p_cdda->p_cddev );
329     free( p_cdda );
330     p_cdda_input = NULL;
331 }
332
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
337  * bytes.
338  *****************************************************************************/
339 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
340                      size_t i_len )
341 {
342     cdda_data_t *           p_cdda;
343     int                     i_blocks;
344     int                     i_index;
345     int                     i_read;
346
347     p_cdda = (cdda_data_t *)p_input->p_access_data;
348
349     i_read = 0;
350
351     /* Compute the number of blocks we have to read */
352
353     i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
354
355     for ( i_index = 0; i_index < i_blocks; i_index++ )
356     {
357
358       if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer, 
359                                  p_cdda->i_sector) != 0)
360         {
361           msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
362           return -1;
363         }
364
365         p_cdda->i_sector ++;
366         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
367         {
368             input_area_t *p_area;
369
370             dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL), 
371                        "end of track, cur: %u", p_cdda->i_sector );
372
373             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
374                 return 0; /* EOF */
375
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 ];
379
380             p_area->i_part = 1;
381             CDDASetArea( p_input, p_area );
382             vlc_mutex_unlock( &p_input->stream.stream_lock );
383         }
384         i_read += CDIO_CD_FRAMESIZE_RAW;
385     }
386
387     if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
388     {
389         msg_Err( p_input, "must read full sectors" );
390     }
391
392     return i_read;
393 }
394
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)
400 {
401     cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
402     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
403     return 0;
404 }
405
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 )
411 {
412     cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
413     vlc_value_t val;
414
415     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
416
417     /* we can't use the interface slider until initilization is complete */
418     p_input->stream.b_seekable = 0;
419
420     if( p_area != p_input->stream.p_selected_area )
421     {
422         /* Change the default area */
423         p_input->stream.p_selected_area = p_area;
424
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];
428
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 );
432     }
433
434     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
435
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;
439
440     /* warn interface that something has changed */
441     p_input->stream.b_seekable = 1;
442     p_input->stream.b_changed = 1;
443
444     return 0;
445 }
446
447 /****************************************************************************
448  * CDDASeek
449  ****************************************************************************/
450 static void CDDASeek( input_thread_t * p_input, off_t i_off )
451 {
452     cdda_data_t * p_cdda;
453
454     p_cdda = (cdda_data_t *) p_input->p_access_data;
455
456     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
457                        + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
458
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;
463
464     vlc_mutex_unlock( &p_input->stream.stream_lock );
465
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 );
469
470 }
471
472 /*****************************************************************************
473  * Demux: local prototypes
474  *****************************************************************************/
475 struct demux_sys_t
476 {
477     es_out_id_t *p_es;
478     mtime_t     i_pts;
479 };
480
481 static int  Demux     ( input_thread_t * p_input );
482
483 /****************************************************************************
484  * DemuxOpen:
485  ****************************************************************************/
486 int  
487 E_(DemuxOpen)    ( vlc_object_t * p_this)
488 {
489     input_thread_t *p_input = (input_thread_t *)p_this;
490     demux_sys_t    *p_sys;
491
492     es_format_t    fmt;
493
494     if( p_input->stream.i_method != INPUT_METHOD_CDDA )
495     {
496         return VLC_EGENERIC;
497     }
498
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 ) );
503     p_sys->i_pts = 0;
504
505     vlc_mutex_lock( &p_input->stream.stream_lock );
506     if( input_InitStream( p_input, 0 ) == -1)
507     {
508         vlc_mutex_unlock( &p_input->stream.stream_lock );
509         msg_Err( p_input, "cannot init stream" );
510         free( p_sys );
511         return VLC_EGENERIC;
512     }
513     p_input->stream.i_mux_rate = 4 * 44100 / 50;
514     vlc_mutex_unlock( &p_input->stream.stream_lock );
515
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;
522
523     p_sys->p_es =  es_out_Add( p_input->p_es_out, &fmt );
524
525     return VLC_SUCCESS;
526 }
527
528 /****************************************************************************
529  * DemuxClose:
530  ****************************************************************************/
531 void 
532 E_(DemuxClose)( vlc_object_t * p_this)
533 {
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;
536
537     free( p_sys );
538     return;
539 }
540
541 /****************************************************************************
542  * Demux:
543  ****************************************************************************/
544 static int  Demux( input_thread_t * p_input )
545 {
546     demux_sys_t    *p_sys = (demux_sys_t*)p_input->p_demux_data;
547     block_t        *p_block;
548
549
550     input_ClockManageRef( p_input,
551                           p_input->stream.p_selected_program,
552                           p_sys->i_pts );
553
554     if( ( p_block = stream_Block( p_input->s, CDIO_CD_FRAMESIZE_RAW ) ) == NULL )
555     {
556         /* eof */
557         return 0;
558     }
559     p_block->i_dts =
560     p_block->i_pts = input_ClockGetTS( p_input,
561                                        p_input->stream.p_selected_program,
562                                        p_sys->i_pts );
563     p_block->i_length = (mtime_t)90000 * (mtime_t)p_block->i_buffer/44100/4;
564
565     p_sys->i_pts += p_block->i_length;
566
567     es_out_Send( p_input->p_es_out, p_sys->p_es, p_block );
568
569     return 1;
570 }
571