]> git.sesse.net Git - vlc/blob - modules/access/cdda/access.c
* modules/demux/mkv.cpp: compilation fixes.
[vlc] / modules / access / cdda / access.c
1 /*****************************************************************************
2  * access.c : CD digital audio input module for vlc using libcdio
3  *****************************************************************************
4  * Copyright (C) 2000, 2003, 2004, 2005 VideoLAN
5  * $Id$
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 "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
30 #include "cdda.h"          /* private structures. Also #includes vlc things */
31 #include "info.h"          /* headers for meta info retrieval */
32 #include <vlc_playlist.h>  /* Has to come *after* cdda.h */
33 #include "vlc_keys.h"
34
35 #include <cdio/cdio.h>
36 #include <cdio/logging.h>
37 #include <cdio/cd_types.h>
38
39 #include <stdio.h>
40
41 /* #ifdef variables below are defined via config.h via #include vlc above. */
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45
46 #ifdef HAVE_SYS_TYPES_H
47 #include <sys/types.h>
48 #endif
49
50 #ifdef HAVE_STRING_H
51 #include <string.h>
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 #   include <unistd.h>
56 #endif
57
58 /* FIXME: This variable is a hack. Would be nice to eliminate. */
59 access_t *p_cdda_input = NULL;
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static block_t *CDDAReadBlocks( access_t * p_access );
65 static int      CDDASeek( access_t * p_access, int64_t i_pos );
66 static int      CDDAControl( access_t *p_access, int i_query,
67                              va_list args );
68
69 static int      CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;
70
71
72 /****************************************************************************
73  * Private functions
74  ****************************************************************************/
75
76 /* process messages that originate from libcdio. */
77 static void
78 cdio_log_handler (cdio_log_level_t level, const char message[])
79 {
80   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
81
82   if( p_cdda == NULL )
83       return;
84
85   switch (level) {
86   case CDIO_LOG_DEBUG:
87   case CDIO_LOG_INFO:
88     if (p_cdda->i_debug & INPUT_DBG_CDIO)
89       msg_Dbg( p_cdda_input, message);
90     break;
91   case CDIO_LOG_WARN:
92     msg_Warn( p_cdda_input, message);
93     break;
94   case CDIO_LOG_ERROR:
95   case CDIO_LOG_ASSERT:
96     msg_Err( p_cdda_input, message);
97     break;
98   default:
99     msg_Warn( p_cdda_input, message,
100             "The above message had unknown cdio log level",
101             level);
102   }
103   return;
104 }
105
106
107 #ifdef HAVE_LIBCDDB
108 /*! This routine is called by libcddb routines on error.
109    Setup is done by init_input_plugin.
110 */
111 static void
112 cddb_log_handler (cddb_log_level_t level, const char message[])
113 {
114     cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
115     switch (level)
116     {
117         case CDDB_LOG_DEBUG:
118         case CDDB_LOG_INFO:
119         if (!(p_cdda->i_debug & INPUT_DBG_CDDB)) return;
120
121         /* Fall through if to warn case */
122         default:
123             cdio_log_handler (level, message);
124     }
125 }
126 #endif /*HAVE_LIBCDDB*/
127
128
129 /*! This routine is when xine is not fully set up (before full initialization)
130    or is not around (before finalization).
131 */
132 static void
133 uninit_log_handler (cdio_log_level_t level, const char message[])
134 {
135     cdda_data_t *p_cdda = NULL;
136
137     if (p_cdda_input)
138         p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
139
140      switch (level)
141      {
142         case CDIO_LOG_DEBUG:
143         case CDIO_LOG_INFO:
144         if (!p_cdda || !(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)))
145             return;
146
147         /* Fall through if to warn case */
148         case CDIO_LOG_WARN:
149             fprintf(stderr, "WARN: %s\n", message);
150             break;
151         case CDIO_LOG_ERROR:
152             fprintf(stderr, "ERROR: %s\n", message);
153             break;
154         case CDIO_LOG_ASSERT:
155             fprintf(stderr, "ASSERT ERROR: %s\n", message);
156             break;
157         default:
158             fprintf(stderr, "UNKNOWN ERROR: %s\n%s %d\n", message,
159                             "The above message had unknown cdio log level",
160                             level);
161     }
162
163     /* gl_default_cdio_log_handler (level, message); */
164 }
165
166 /*****************************************************************************
167  * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns
168  * an allocated pointer to the data. NULL is returned if no data
169  * read. It is also possible if we haven't read a RIFF header in which
170  * case one that we creaded during Open/Initialization is returned.
171  *****************************************************************************/
172 static block_t * CDDAReadBlocks( access_t * p_access )
173 {
174     block_t     *p_block;
175     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
176     int          i_blocks = p_cdda->i_blocks_per_read;
177
178     dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), "called %d",
179               p_cdda->i_lsn);
180
181     /* Check end of file */
182     if( p_access->info.b_eof ) return NULL;
183
184     if( !p_cdda->b_header )
185       {
186         /* Return only the dummy RIFF header we created in Open/Init */
187         p_block = block_New( p_access, sizeof( WAVEHEADER ) );
188         memcpy( p_block->p_buffer, &p_cdda->waveheader, sizeof(WAVEHEADER) );
189         p_cdda->b_header = VLC_TRUE;
190         return p_block;
191     }
192
193     /* Check end of track */
194     while( p_cdda->i_lsn >= cdio_get_track_lsn(p_cdda->p_cdio, 
195                                                p_cdda->i_track+1) )
196     {
197         if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 )
198         {
199             p_access->info.b_eof = VLC_TRUE;
200             return NULL;
201         }
202
203         p_access->info.i_update |= INPUT_UPDATE_TITLE;
204         p_access->info.i_title++;
205         p_cdda->i_track++;
206
207         if ( p_cdda-> b_nav_mode ) {
208           char *psz_title = CDDAFormatTitle( p_access, p_cdda->i_track );
209           input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title );
210           free(psz_title);
211         } else {
212           p_access->info.i_size =
213             p_cdda->p_title[p_access->info.i_title]->i_size;
214           p_access->info.i_pos = 0;
215           p_access->info.i_update |= INPUT_UPDATE_SIZE;
216         }
217     }
218
219     /* Possibly adjust i_blocks so we don't read past the end of a track. */
220     if( p_cdda->i_lsn + i_blocks >= 
221         cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track+1) )
222     {
223       i_blocks = cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track+1 ) 
224         - p_cdda->i_lsn;
225     }
226
227     /* Do the actual reading */
228     p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW );
229     if( !p_block)
230     {
231       msg_Err( p_access, "Cannot get a new block of size: %i",
232                i_blocks * CDIO_CD_FRAMESIZE_RAW );
233       return NULL;
234     }
235     
236     {
237 #if LIBCDIO_VERSION_NUM >= 72
238       driver_return_code_t rc = DRIVER_OP_SUCCESS;
239
240       if ( p_cdda->b_paranoia_enabled ) 
241         {
242           int i;
243           for( i = 0; i < i_blocks; i++ )
244             {
245               int16_t *p_readbuf = cdio_paranoia_read(p_cdda->paranoia, NULL);
246               char *psz_err=cdio_cddap_errors(p_cdda->paranoia_cd);
247               char *psz_mes=cdio_cddap_messages(p_cdda->paranoia_cd);
248
249               if (psz_mes || psz_err)
250                 msg_Err( p_access, "%s%s\n", psz_mes ? psz_mes: "", 
251                         psz_err ? psz_err: "" );
252               
253               if (psz_err) free(psz_err);
254               if (psz_mes) free(psz_mes);
255               if( !p_readbuf ) {
256                 msg_Err( p_access, "paranoia read error on frame %i\n", 
257                          p_cdda->i_lsn+i );
258               } else 
259                 memcpy(p_block + i * CDIO_CD_FRAMESIZE_RAW, p_readbuf, 
260                        CDIO_CD_FRAMESIZE_RAW);
261             }
262         }
263       else 
264         rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
265                                       p_cdda->i_lsn, i_blocks);
266 #else
267 #define DRIVER_OP_SUCCESS 0
268       int rc;
269       rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
270                                     p_cdda->i_lsn, i_blocks);
271 #endif    
272       if( rc != DRIVER_OP_SUCCESS )
273         {
274           msg_Err( p_access, "could not read %d sectors starting from %lu",
275                    i_blocks, (long unsigned int) p_cdda->i_lsn );
276           block_Release( p_block );
277           
278           /* If we had problems above, assume the problem is with
279              the first sector of the read and set to skip it.  In
280              the future libcdio may have cdparanoia support.
281           */
282           p_cdda->i_lsn++;
283           p_access->info.i_pos += CDIO_CD_FRAMESIZE_RAW;
284           return NULL;
285         }
286     }
287
288     p_cdda->i_lsn        += i_blocks;
289     p_access->info.i_pos += p_block->i_buffer;
290
291     return p_block;
292 }
293
294 /****************************************************************************
295  * CDDASeek - change position for subsequent reads. For example, this
296  * can happen if the user moves a position slider bar in a GUI.
297  ****************************************************************************/
298 static int CDDASeek( access_t * p_access, int64_t i_pos )
299 {
300     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
301
302     p_cdda->i_lsn = (i_pos / CDIO_CD_FRAMESIZE_RAW);
303
304 #if LIBCDIO_VERSION_NUM >= 72
305     if ( p_cdda->b_paranoia_enabled ) 
306       cdio_paranoia_seek(p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET);
307 #endif
308
309     if ( ! p_cdda->b_nav_mode ) 
310       p_cdda->i_lsn += cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track);
311
312     /* Seeked backwards and we are doing disc mode. */
313     if ( p_cdda->b_nav_mode && p_access->info.i_pos > i_pos ) {
314       track_t i_track;
315       char *psz_title;
316       
317       for( i_track = p_cdda->i_track; 
318            i_track > 1 && 
319              p_cdda->i_lsn < cdio_get_track_lsn(p_cdda->p_cdio, i_track);
320            i_track--, p_access->info.i_title-- ) ;
321
322       p_cdda->i_track = i_track;
323       p_access->info.i_update |= INPUT_UPDATE_TITLE;
324       psz_title  = CDDAFormatTitle( p_access, p_cdda->i_track );
325       input_Control( p_cdda->p_input, INPUT_SET_NAME, 
326                      psz_title );
327       free(psz_title);
328
329     }
330     
331     p_access->info.i_pos = i_pos;
332
333     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
334                "lsn %lu, offset: %lld",
335                (long unsigned int) p_cdda->i_lsn, i_pos );
336     return VLC_SUCCESS;
337 }
338
339 /****************************************************************************
340  * Public functions
341  ****************************************************************************/
342
343 /*****************************************************************************
344  * Open: open cdda device or image file and initialize structures
345  *       for subsequent operations.
346  *****************************************************************************/
347 int 
348 CDDAOpen( vlc_object_t *p_this )
349 {
350     access_t    *p_access = (access_t*)p_this;
351     char *      psz_source = NULL;
352     cdda_data_t *p_cdda    = NULL;
353     CdIo_t      *p_cdio;
354     track_t     i_track = 1;
355     vlc_bool_t  b_single_track = false;
356     int         i_rc = VLC_EGENERIC;
357
358     p_access->p_sys = NULL;
359
360     /* Set where to log errors messages from libcdio. */
361     p_cdda_input = p_access;
362
363     /* parse the options passed in command line : */
364
365     if( p_access->psz_path && *p_access->psz_path )
366     {
367         char *psz_parser = psz_source = strdup( p_access->psz_path );
368
369         while( *psz_parser && *psz_parser != '@' )
370         {
371             psz_parser++;
372         }
373
374         if( *psz_parser == '@' )
375         {
376             /* Found options */
377             *psz_parser = '\0';
378             ++psz_parser;
379
380             if ('T' == *psz_parser || 't' == *psz_parser )
381             ++psz_parser;
382
383             i_track = (int)strtol( psz_parser, NULL, 10 );
384             i_track = i_track ? i_track : 1;
385             b_single_track = true;
386         }
387     }
388
389     if (!psz_source || !*psz_source)
390     {
391         /* No device/track given. Continue only when this plugin was
392            selected */
393         if( !p_this->b_force ) return VLC_EGENERIC;
394
395         psz_source = var_CreateGetString( p_this, "cd-audio" );
396
397         if( !psz_source || !*psz_source )
398         {
399             /* Scan for a CD-ROM drive with a CD-DA in it. */
400             char **cd_drives =
401               cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
402
403             if (NULL == cd_drives || NULL == cd_drives[0] )
404             {
405                 msg_Err( p_access,
406                      "libcdio couldn't find something with a CD-DA in it" );
407                 if (cd_drives) cdio_free_device_list(cd_drives);
408                 return VLC_EGENERIC;
409             }
410
411             psz_source = strdup(cd_drives[0]);
412             cdio_free_device_list(cd_drives);
413         }
414     }
415
416     cdio_log_set_handler ( cdio_log_handler );
417
418     /* Open CDDA */
419     if( !(p_cdio = cdio_open( psz_source, DRIVER_UNKNOWN )) )
420     {
421         msg_Warn( p_access, "could not open %s", psz_source );
422         if (psz_source) free( psz_source );
423         return VLC_EGENERIC;
424     }
425
426     p_cdda = calloc( 1, sizeof(cdda_data_t) );
427     if( p_cdda == NULL )
428     {
429         msg_Err( p_access, "out of memory" );
430         free( psz_source );
431         return VLC_ENOMEM;
432     }
433
434 #ifdef HAVE_LIBCDDB
435     cddb_log_set_handler ( cddb_log_handler );
436     p_cdda->cddb.disc = NULL;
437     p_cdda->b_cddb_enabled =
438       config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
439 #endif
440
441     p_cdda->b_cdtext_enabled =
442       config_GetInt( p_access, MODULE_STRING "-cdtext-enabled" );
443
444     p_cdda->b_cdtext_prefer =
445       config_GetInt( p_access, MODULE_STRING "-cdtext-prefer" );
446
447     p_cdda->psz_source = strdup(psz_source);
448     p_cdda->b_header   = VLC_FALSE;
449     p_cdda->p_cdio     = p_cdio;
450     p_cdda->i_tracks   = 0;
451     p_cdda->i_titles   = 0;
452     p_cdda->i_track    = i_track;
453     p_cdda->i_debug    = config_GetInt(p_this, MODULE_STRING 
454                                        "-debug");
455     p_cdda->b_nav_mode = config_GetInt(p_this, MODULE_STRING 
456                                        "-navigation-mode" );
457     p_cdda->i_blocks_per_read
458       = config_GetInt(p_this, MODULE_STRING "-blocks-per-read");
459
460     p_cdda->p_input  = vlc_object_find( p_access, VLC_OBJECT_INPUT,
461                                         FIND_PARENT );
462
463     if (0 == p_cdda->i_blocks_per_read)
464         p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
465
466     if ( p_cdda->i_blocks_per_read < MIN_BLOCKS_PER_READ
467          || p_cdda->i_blocks_per_read > MAX_BLOCKS_PER_READ )
468     {
469         msg_Warn( p_cdda_input,
470                 "Number of blocks (%d) has to be between %d and %d. "
471                 "Using %d.",
472                 p_cdda->i_blocks_per_read,
473                 MIN_BLOCKS_PER_READ, MAX_BLOCKS_PER_READ,
474                 DEFAULT_BLOCKS_PER_READ );
475         p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
476     }
477
478     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
479
480     /* Set up p_access */
481     p_access->pf_read    = NULL;
482     p_access->pf_block   = CDDAReadBlocks;
483     p_access->pf_control = CDDAControl;
484     p_access->pf_seek    = CDDASeek;
485
486     p_access->info.i_size      = 0;
487
488     p_access->info.i_update    = 0;
489     p_access->info.b_eof       = VLC_FALSE;
490     p_access->info.i_title     = 0;
491     p_access->info.i_seekpoint = 0;
492
493     p_access->p_sys     = (access_sys_t *) p_cdda;
494
495     /* We read the Table Of Content information */
496     i_rc = CDDAInit( p_access, p_cdda );
497     if ( VLC_SUCCESS != i_rc ) goto error;
498
499     CDDAFixupPlaylist( p_access, p_cdda, b_single_track );
500
501 #if LIBCDIO_VERSION_NUM >= 72
502     p_cdda->b_paranoia_enabled =
503       config_GetInt( p_access, MODULE_STRING "-paranoia-enabled" );
504
505     /* Use CD Paranoia? */
506     if ( p_cdda->b_paranoia_enabled ) {
507       p_cdda->paranoia_cd = cdio_cddap_identify_cdio(p_cdio, 1, NULL);
508       /* We'll set for verbose paranoia messages. */
509       cdio_cddap_verbose_set(p_cdda->paranoia_cd, CDDA_MESSAGE_PRINTIT, 
510                             CDDA_MESSAGE_PRINTIT);
511       if ( 0 != cdio_cddap_open(p_cdda->paranoia_cd) ) {
512         msg_Warn( p_cdda_input, "Unable to get paranoia support - "
513                   "continuing without it." );
514         p_cdda->b_paranoia_enabled = VLC_FALSE;
515       } else {
516         p_cdda->paranoia = cdio_paranoia_init(p_cdda->paranoia_cd);
517         cdio_paranoia_seek(p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET);
518
519         /* Set reading mode for full paranoia, but allow skipping sectors. */
520         cdio_paranoia_modeset(p_cdda->paranoia, 
521                               PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
522       }
523       
524     }
525 #endif    
526
527     /* Build a WAV header to put in front of the output data.
528        This gets sent back in the Block (read) routine.
529      */
530     memset( &p_cdda->waveheader, 0, sizeof(WAVEHEADER) );
531     SetWLE( &p_cdda->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
532     SetWLE( &p_cdda->waveheader.BitsPerSample, 16);
533     p_cdda->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
534     p_cdda->waveheader.Length = 0;                     /* we just don't know */
535     p_cdda->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
536     p_cdda->waveheader.SubChunkID  = VLC_FOURCC('f', 'm', 't', ' ');
537     SetDWLE( &p_cdda->waveheader.SubChunkLength, 16);
538     SetWLE( &p_cdda->waveheader.Modus, 2);
539     SetDWLE( &p_cdda->waveheader.SampleFreq, CDDA_FREQUENCY_SAMPLE);
540     SetWLE( &p_cdda->waveheader.BytesPerSample,
541             2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
542     SetDWLE( &p_cdda->waveheader.BytesPerSec,
543              2*16/8 /*BytesPerSample*/ * CDDA_FREQUENCY_SAMPLE );
544     p_cdda->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
545     p_cdda->waveheader.DataLength  = 0;    /* we just don't know */
546
547     /* PTS delay */
548     var_Create( p_access, MODULE_STRING "-caching",
549                 VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
550     vlc_object_release( p_cdda->p_input );
551     return VLC_SUCCESS;
552
553  error:
554     cdio_destroy( p_cdda->p_cdio );
555     if( psz_source) free( psz_source );
556     if( p_cdda ) {
557       if ( p_cdda->p_input )
558         vlc_object_release( p_cdda->p_input );
559       free(p_cdda);
560     }
561     
562     return i_rc;
563
564 }
565
566 /*****************************************************************************
567  * CDDAClose: closes cdda and frees any resources associded with it.
568  *****************************************************************************/
569 void 
570 CDDAClose (vlc_object_t *p_this )
571 {
572     access_t    *p_access = (access_t *) p_this;
573     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
574     track_t      i;
575
576     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
577
578     /* Remove playlist titles */
579     for( i = 0; i < p_cdda->i_titles; i++ )
580     {
581         vlc_input_title_Delete( p_cdda->p_title[i] );
582     }
583
584 #ifdef HAVE_LIBCDDB
585     cddb_log_set_handler ((cddb_log_handler_t) uninit_log_handler);
586     if (p_cdda->b_cddb_enabled)
587       cddb_disc_destroy(p_cdda->cddb.disc);
588 #endif
589
590     cdio_destroy( p_cdda->p_cdio );
591     cdio_log_set_handler (uninit_log_handler);
592
593 #if LIBCDIO_VERSION_NUM >= 72
594     if (p_cdda->paranoia)
595       cdio_paranoia_free(p_cdda->paranoia);
596     if (p_cdda->paranoia_cd) 
597       cdio_cddap_close_no_free_cdio(p_cdda->paranoia_cd);
598 #endif
599
600     if (p_cdda->psz_mcn)    free( p_cdda->psz_mcn );
601     if (p_cdda->psz_source) free( p_cdda->psz_source );
602     free( p_cdda );
603     p_cdda = NULL;
604     p_cdda_input = NULL;
605 }
606
607 /*****************************************************************************
608  * Control: The front-end or vlc engine calls here to ether get
609  * information such as meta information or plugin capabilities or to
610  * issue miscellaneous "set" requests.
611  *****************************************************************************/
612 static int CDDAControl( access_t *p_access, int i_query, va_list args )
613 {
614     cdda_data_t  *p_cdda = (cdda_data_t *) p_access->p_sys;
615     int          *pi_int;
616     int i;
617
618     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
619                "query %d", i_query );
620
621     switch( i_query )
622     {
623         /* Pass back a copy of meta information that was gathered when we
624            during the Open/Initialize call.
625          */
626         case ACCESS_GET_META:
627         {
628             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
629             if ( p_cdda->p_meta )
630             {
631                 *pp_meta = vlc_meta_Duplicate( p_cdda->p_meta );
632                 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
633                 return VLC_SUCCESS;
634             }
635             else {
636                 msg_Warn( p_access, "tried to copy NULL meta info" );
637                 return VLC_EGENERIC;
638             }
639         }
640
641         case ACCESS_CAN_SEEK:
642         case ACCESS_CAN_FASTSEEK:
643         case ACCESS_CAN_PAUSE:
644         case ACCESS_CAN_CONTROL_PACE:
645         {
646             vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
647             *pb_bool = VLC_TRUE;
648             return VLC_SUCCESS;;
649         }
650
651         /* */
652         case ACCESS_GET_MTU:
653         {
654             pi_int = (int*)va_arg( args, int * );
655             *pi_int = p_cdda-> i_blocks_per_read * CDIO_CD_FRAMESIZE_RAW;
656             break;
657         }
658
659         case ACCESS_GET_PTS_DELAY:
660         {
661             int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
662             *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
663               * MILLISECONDS_PER_SEC;
664             break;
665         }
666
667         /* */
668         case ACCESS_SET_PAUSE_STATE:
669             break;
670
671         case ACCESS_GET_TITLE_INFO:
672         {
673             input_title_t ***ppp_title = 
674               (input_title_t***)va_arg( args, input_title_t*** );
675
676             pi_int    = (int*)va_arg( args, int* );
677             *((int*)va_arg( args, int* )) = 1; /* Title offset */
678
679             dbg_print ( INPUT_DBG_EVENT,
680                         "GET TITLE: i_tracks %d, i_tracks %d",
681                         p_cdda->i_tracks, p_cdda->i_tracks );
682
683             CDDAMetaInfo( p_access, CDIO_INVALID_TRACK );
684
685             if ( p_cdda->b_nav_mode) {
686                 char *psz_title = 
687                   CDDAFormatTitle( p_access, p_cdda->i_track );
688                 input_Control( p_cdda->p_input, INPUT_SET_NAME, 
689                                psz_title );
690                 free(psz_title);
691             }
692
693             /* Duplicate title info */
694             if( p_cdda->i_titles == 0 )
695             {
696                 *pi_int = 0; ppp_title = NULL;
697                 return VLC_SUCCESS;
698             }
699             *pi_int = p_cdda->i_titles;
700             *ppp_title = calloc(1, 
701                                 sizeof( input_title_t **) * p_cdda->i_titles );
702
703             if (!*ppp_title) return VLC_ENOMEM;
704
705             for( i = 0; i < p_cdda->i_titles; i++ )
706             {
707               if ( p_cdda->p_title[i] ) {
708                    (*ppp_title)[i] =
709                      vlc_input_title_Duplicate( p_cdda->p_title[i] );
710               }
711             }
712             break;
713         }
714
715         case ACCESS_SET_TITLE:
716         {
717             i = (int)va_arg( args, int );
718
719             dbg_print( INPUT_DBG_EVENT, "set title %d", i );
720             if( i != p_access->info.i_title )
721             {
722                 /* Update info */
723                 p_access->info.i_update |= INPUT_UPDATE_TITLE;
724                 p_access->info.i_title = i;
725                 if ( p_cdda->b_nav_mode) {
726                     char *psz_title = 
727                       CDDAFormatTitle( p_access, i+1 );
728                     input_Control( p_cdda->p_input, INPUT_SET_NAME, 
729                                    psz_title );
730                     free(psz_title);
731                     p_cdda->i_track = i+1;
732                     p_access->info.i_pos = 
733                       cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track ) 
734                       * CDIO_CD_FRAMESIZE_RAW;
735                 } else {
736                    p_access->info.i_update |= INPUT_UPDATE_SIZE;
737                    p_access->info.i_size = p_cdda->p_title[i]->i_size;
738                    p_access->info.i_pos = 0;
739                 }
740
741                 /* Next sector to read */
742                 p_cdda->i_lsn = 
743                   cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_first_track+i);
744             }
745             break;
746         }
747
748         case ACCESS_SET_SEEKPOINT:
749         case ACCESS_SET_PRIVATE_ID_STATE:
750             return VLC_EGENERIC;
751
752         default:
753             msg_Warn( p_access, "unimplemented query in control" );
754             return VLC_EGENERIC;
755
756     }
757     return VLC_SUCCESS;
758 }
759
760 /*****************************************************************************
761   CDDAInit:
762
763  Initialize information pertaining to the CD: the number of tracks,
764  first track number, LSNs for each track and the leadout. The leadout
765  information is stored after the last track. The LSN array is
766  0-origin, same as p_access->info.  Add first_track to get what track
767  number this is on the CD. Note: libcdio uses the real track number.
768
769  On input we assume p_cdda->p_cdio and p_cdda->i_track have been set.
770
771  We return the VLC-type status, e.g. VLC_SUCCESS, VLC_ENOMEM, etc.
772  *****************************************************************************/
773 static int CDDAInit( access_t *p_access, cdda_data_t *p_cdda )
774 {
775     discmode_t  discmode = CDIO_DISC_MODE_NO_INFO;
776
777     p_cdda->i_tracks       = cdio_get_num_tracks(p_cdda->p_cdio);
778     p_cdda->i_first_track  = cdio_get_first_track_num(p_cdda->p_cdio);
779
780     discmode = cdio_get_discmode(p_cdda->p_cdio);
781     switch(discmode) {
782     case CDIO_DISC_MODE_CD_DA:
783     case CDIO_DISC_MODE_CD_MIXED:
784         /* These are possible for CD-DA */
785         break;
786     default:
787         /* These are not possible for CD-DA */
788         msg_Err( p_access,
789                "Disc seems not to be CD-DA. libcdio reports it is %s",
790                discmode2str[discmode]
791                );
792         return VLC_EGENERIC;
793     }
794
795     /* Set reading start LSN. */
796     p_cdda->i_lsn = cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track);
797
798     return VLC_SUCCESS;
799 }
800
801 /* 
802  * Local variables:
803  *  mode: C
804  *  style: gnu
805  * End:
806  */