]> git.sesse.net Git - vlc/blob - modules/access/cdda/access.c
Customizable playlist title.
[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.5 2003/11/30 22:26:48 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
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 CDDA_MRL_PREFIX "cddax://"
55
56 /* FIXME: This variable is a hack. Would be nice to eliminate. */
57 static input_thread_t *p_cdda_input = NULL;
58
59 /*****************************************************************************
60  * Local prototypes
61  *****************************************************************************/
62 static int  CDDARead         ( input_thread_t *, byte_t *, size_t );
63 static void CDDASeek         ( input_thread_t *, off_t );
64 static int  CDDASetArea      ( input_thread_t *, input_area_t * );
65 static int  CDDASetProgram   ( input_thread_t *, pgrm_descriptor_t * );
66
67 static int  CDDAFixupPlayList(const input_thread_t *p_input, 
68                               cdda_data_t *p_cdda, const char *psz_source, 
69                               bool play_single_track);
70
71 /****************************************************************************
72  * Private functions
73  ****************************************************************************/
74
75 int
76 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
77                       vlc_value_t oldval, vlc_value_t val, void *p_data )
78 {
79   cdda_data_t *p_cdda;
80
81   if (NULL == p_cdda_input) return VLC_EGENERIC;
82   
83   p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
84
85   if (p_cdda->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
86     msg_Dbg( p_cdda_input, "Old debug (x%0x) %d, new debug (x%0x) %d", 
87              p_cdda->i_debug, p_cdda->i_debug, val.i_int, val.i_int);
88   }
89   p_cdda->i_debug = val.i_int;
90   return VLC_SUCCESS;
91 }
92
93 /* process messages that originate from libcdio. */
94 static void
95 cdio_log_handler (cdio_log_level_t level, const char message[])
96 {
97   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
98   switch (level) {
99   case CDIO_LOG_DEBUG:
100   case CDIO_LOG_INFO:
101     if (p_cdda->i_debug & INPUT_DBG_CDIO) 
102       msg_Dbg( p_cdda_input, message);
103     break;
104   case CDIO_LOG_WARN:
105     msg_Warn( p_cdda_input, message);
106     break;
107   case CDIO_LOG_ERROR:
108   case CDIO_LOG_ASSERT:
109     msg_Err( p_cdda_input, message);
110     break;
111   default:
112     msg_Warn( p_cdda_input, message,
113             _("The above message had unknown vcdimager log level"), 
114             level);
115   }
116   return;
117 }
118
119
120 #ifdef HAVE_LIBCDDB
121 /*! This routine is called by libcddb routines on error. 
122    Setup is done by init_input_plugin.
123 */
124 static void 
125 cddb_log_handler (cddb_log_level_t level, const char message[])
126 {
127   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
128   switch (level) {
129   case CDDB_LOG_DEBUG:
130   case CDDB_LOG_INFO:
131     if (!(p_cdda->i_debug & INPUT_DBG_CDDB)) return;
132     /* Fall through if to warn case */
133   default:
134     cdio_log_handler (level, message);
135   }
136 }
137 #endif /*HAVE_LIBCDDB*/
138
139
140 /*! This routine is when xine is not fully set up (before full initialization)
141    or is not around (before finalization). 
142 */
143 static void 
144 uninit_log_handler (cdio_log_level_t level, const char message[])
145 {
146   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
147   switch (level) {
148   case CDIO_LOG_DEBUG:
149   case CDIO_LOG_INFO:
150     if (!(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)))
151       return;
152     /* Fall through if to warn case */
153   case CDIO_LOG_WARN:
154     fprintf(stderr, "WARN: %s\n", message);
155     break;
156   case CDIO_LOG_ERROR:
157     fprintf(stderr, "ERROR: %s\n", message);
158     break;
159   case CDIO_LOG_ASSERT:
160     fprintf(stderr, "ASSERT ERROR: %s\n", message);
161     break;
162   default:
163     fprintf(stderr, "UNKNOWN ERROR: %s\n%s %d\n",
164             message, 
165             _("The above message had unknown cdio log level"), 
166             level);
167   }
168   
169   /* gl_default_cdio_log_handler (level, message); */
170 }
171
172 /*****************************************************************************
173  * Open: open cdda
174  *****************************************************************************/
175 int 
176 E_(Open)( vlc_object_t *p_this )
177 {
178     input_thread_t *        p_input = (input_thread_t *)p_this;
179     char *                  psz_orig;
180     char *                  psz_parser;
181     char *                  psz_source;
182     cdda_data_t *           p_cdda;
183     int                     i;
184     int                     i_track = 1;
185     cddev_t                 *p_cddev;
186     bool                    play_single_track = false;
187
188     /* Set where to log errors messages from libcdio. */
189     p_cdda_input = (input_thread_t *)p_this;
190
191     /* parse the options passed in command line : */
192     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
193
194     if( !psz_orig )
195     {
196         return( -1 );
197     }
198
199     while( *psz_parser && *psz_parser != '@' )
200     {
201         psz_parser++;
202     }
203
204     if( *psz_parser == '@' )
205     {
206         /* Found options */
207         *psz_parser = '\0';
208         ++psz_parser;
209
210         if ('T' == *psz_parser || 't' == *psz_parser ) 
211             ++psz_parser;
212           
213         i_track = (int)strtol( psz_parser, NULL, 10 );
214         i_track = i_track ? i_track : 1;
215         play_single_track = true;
216     }
217
218     if( !*psz_source ) {
219       /* No source specified, so figure it out. */
220       if( !p_input->psz_access ) {
221         free( psz_orig );
222         return -1;
223       }
224       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
225       
226       if( !psz_source || 0==strlen(psz_source) ) {
227         /* Scan for a CD-ROM drive with a CD-DA in it. */
228         char **cd_drives = 
229           cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
230         if (NULL == cd_drives) return -1;
231         if (cd_drives[0] == NULL) {
232           cdio_free_device_list(cd_drives);
233           return -1;
234         }
235         psz_source = strdup(cd_drives[0]);
236         cdio_free_device_list(cd_drives);
237       }
238     }
239
240     /* Open CDDA */
241     cdio_log_set_handler ( cdio_log_handler );
242 #ifdef HAVE_LIBCDDB
243     cddb_log_set_handler ( cddb_log_handler );
244 #endif
245
246     if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
247     {
248         msg_Warn( p_input, "could not open %s", psz_source );
249         free( psz_source );
250         return -1;
251     }
252
253     p_cdda = malloc( sizeof(cdda_data_t) );
254     if( p_cdda == NULL )
255     {
256         msg_Err( p_input, "out of memory" );
257         free( psz_source );
258         return -1;
259     }
260
261     p_cdda->p_cddev        = p_cddev;
262     p_cdda->i_debug        = config_GetInt( p_this, MODULE_STRING "-debug" );
263     p_input->p_access_data = (void *)p_cdda;
264
265     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
266
267     p_input->i_mtu = CDDA_DATA_ONCE;
268
269     /* We read the Table Of Content information */
270     p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
271                               p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
272     if( p_cdda->i_nb_tracks < 0 )
273         msg_Err( p_input, "unable to count tracks" );
274     else if( p_cdda->i_nb_tracks <= 0 )
275         msg_Err( p_input, "no audio tracks found" );
276
277     if( p_cdda->i_nb_tracks <= 1)
278     {
279         ioctl_Close( p_cdda->p_cddev );
280         free( p_cdda );
281         free( psz_source );
282         return -1;
283     }
284
285     if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
286         i_track = 1;
287
288     /* Set stream and area data */
289     vlc_mutex_lock( &p_input->stream.stream_lock );
290
291     /* Initialize ES structures */
292     input_InitStream( p_input, 0 );
293
294     /* cdda input method */
295     p_input->stream.i_method = INPUT_METHOD_CDDA;
296
297     p_input->stream.b_pace_control = 1;
298     p_input->stream.b_seekable = 1;
299     p_input->stream.i_mux_rate = 44100 * 4 / 50;
300
301 #define area p_input->stream.pp_areas
302     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
303     {
304         input_AddArea( p_input, i, 1 );
305
306         /* Absolute start offset and size */
307         area[i]->i_start =
308             (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
309         area[i]->i_size =
310             (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
311             * (off_t)CDIO_CD_FRAMESIZE_RAW;
312     }
313 #undef area
314
315     CDDAPlay( p_input, i_track);
316
317     CDDAFixupPlayList(p_input, p_cdda, psz_source, play_single_track);
318
319     vlc_mutex_unlock( &p_input->stream.stream_lock );
320
321     if( !p_input->psz_demux || !*p_input->psz_demux )
322     {
323         p_input->psz_demux = "cdda";
324     }
325
326     p_input->pf_read = CDDARead;
327     p_input->pf_seek = CDDASeek;
328     p_input->pf_set_area = CDDASetArea;
329     p_input->pf_set_program = CDDASetProgram;
330
331     /* Update default_pts to a suitable value for cdda access */
332     p_input->i_pts_delay = config_GetInt( p_input, 
333                                           MODULE_STRING "-caching" ) * 1000;
334
335     p_cdda->p_intf = intf_Create( p_input, "cddax" );
336     intf_RunThread( p_cdda->p_intf );
337     free( psz_source );
338
339     return 0;
340 }
341
342 /*****************************************************************************
343  * CDDAPlay: Arrange things so we play the specified track.
344  * VLC_TRUE is returned if there was no error.
345  *****************************************************************************/
346 vlc_bool_t
347 CDDAPlay( input_thread_t *p_input, int i_track )
348 {
349   cdda_data_t *p_cdda = (cdda_data_t *) p_input->p_access_data;
350
351   if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
352     return VLC_FALSE;
353
354   CDDASetArea( p_input, p_input->stream.pp_areas[i_track] );
355   return VLC_TRUE;
356 }
357
358 /*****************************************************************************
359  * CDDAClose: closes cdda
360  *****************************************************************************/
361 void 
362 E_(Close)( vlc_object_t *p_this )
363 {
364     input_thread_t *   p_input = (input_thread_t *)p_this;
365     cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
366
367     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
368     ioctl_Close( p_cdda->p_cddev );
369
370     cdio_log_set_handler (uninit_log_handler);
371
372 #ifdef HAVE_LIBCDDB
373     cddb_log_set_handler (uninit_log_handler);
374     cddb_disc_destroy(p_cdda->cddb.disc);
375 #endif
376
377     free( p_cdda );
378     p_cdda_input = NULL;
379 }
380
381 /*****************************************************************************
382  * CDDARead: reads from the CDDA into PES packets.
383  *****************************************************************************
384  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
385  * bytes.
386  *****************************************************************************/
387 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
388                      size_t i_len )
389 {
390     cdda_data_t *           p_cdda;
391     int                     i_blocks;
392     int                     i_index;
393     int                     i_read;
394
395     p_cdda = (cdda_data_t *)p_input->p_access_data;
396
397     i_read = 0;
398
399     /* Compute the number of blocks we have to read */
400
401     i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
402
403     for ( i_index = 0; i_index < i_blocks; i_index++ )
404     {
405
406       if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer, 
407                                  p_cdda->i_sector) != 0)
408         {
409           msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
410           return -1;
411         }
412
413         p_cdda->i_sector ++;
414         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
415         {
416             input_area_t *p_area;
417
418             dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL), 
419                        "end of track, cur: %u", p_cdda->i_sector );
420
421             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
422                 return 0; /* EOF */
423
424             vlc_mutex_lock( &p_input->stream.stream_lock );
425             p_area = p_input->stream.pp_areas[
426                     p_input->stream.p_selected_area->i_id + 1 ];
427
428             p_area->i_part = 1;
429             CDDASetArea( p_input, p_area );
430             vlc_mutex_unlock( &p_input->stream.stream_lock );
431         }
432         i_read += CDIO_CD_FRAMESIZE_RAW;
433     }
434
435     if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
436     {
437         msg_Err( p_input, "must read full sectors" );
438     }
439
440     return i_read;
441 }
442
443 /*****************************************************************************
444  * CDDASetProgram: Does nothing since a CDDA is mono_program
445  *****************************************************************************/
446 static int CDDASetProgram( input_thread_t * p_input,
447                            pgrm_descriptor_t * p_program)
448 {
449     cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
450     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
451     return 0;
452 }
453
454 /*****************************************************************************
455  * CDDASetArea: initialize input data for title x.
456  * It should be called for each user navigation request.
457  ****************************************************************************/
458 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
459 {
460     cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
461     vlc_value_t val;
462
463     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
464
465     /* we can't use the interface slider until initilization is complete */
466     p_input->stream.b_seekable = 0;
467
468     if( p_area != p_input->stream.p_selected_area )
469     {
470         /* Change the default area */
471         p_input->stream.p_selected_area = p_area;
472
473         /* Change the current track */
474         p_cdda->i_track = p_area->i_id - 1;
475         p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
476
477         /* Update the navigation variables without triggering a callback */
478         val.i_int = p_area->i_id;
479         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
480     }
481
482     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
483
484     p_input->stream.p_selected_area->i_tell =
485         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
486          - p_input->stream.p_selected_area->i_start;
487
488     /* warn interface that something has changed */
489     p_input->stream.b_seekable = 1;
490     p_input->stream.b_changed = 1;
491
492     return 0;
493 }
494
495 /****************************************************************************
496  * CDDASeek
497  ****************************************************************************/
498 static void CDDASeek( input_thread_t * p_input, off_t i_off )
499 {
500     cdda_data_t * p_cdda;
501
502     p_cdda = (cdda_data_t *) p_input->p_access_data;
503
504     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
505                        + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
506
507     vlc_mutex_lock( &p_input->stream.stream_lock );
508     p_input->stream.p_selected_area->i_tell =
509         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
510          - p_input->stream.p_selected_area->i_start;
511
512     vlc_mutex_unlock( &p_input->stream.stream_lock );
513
514     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
515     "sector %ud, offset: %lld, i_tell: %lld",  p_cdda->i_sector, i_off, 
516                p_input->stream.p_selected_area->i_tell );
517
518 }
519
520 #ifdef HAVE_LIBCDDB
521
522 #define free_and_dup(var, val) \
523   if (var) free(var);          \
524   if (val) var=strdup(val);            
525   
526
527 static void
528 GetCDDBInfo( const input_thread_t *p_input, cdda_data_t *p_cdda )
529 {
530
531   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
532
533   if (config_GetInt( p_input, MODULE_STRING "-cddb-enabled" )) {
534     int i, i_matches;
535     cddb_conn_t  *conn = cddb_new();
536     const CdIo *cdio = p_cdda->p_cddev->cdio;
537     
538     
539     cddb_log_set_handler (uninit_log_handler);
540
541     if (!conn) {
542       msg_Warn( p_input, "unable to initialize libcddb" );
543       goto cddb_destroy;
544     }
545     
546     cddb_set_email_address( conn, 
547                             config_GetPsz( p_input, 
548                                            MODULE_STRING "-cddb-email") );
549     
550     cddb_set_server_name( conn, 
551                           config_GetPsz( p_input, 
552                                          MODULE_STRING "-cddb-server") );
553
554     cddb_set_server_port(conn, 
555                           config_GetInt( p_input, 
556                                          MODULE_STRING "-cddb-port") );
557
558     /* Set the location of the local CDDB cache directory.
559        The default location of this directory is */
560
561     if (!config_GetInt( p_input, MODULE_STRING "-cddb-enable-cache" )) 
562       cddb_cache_disable(conn);
563
564     cddb_cache_set_dir(conn, 
565                        config_GetPsz( p_input, 
566                                       MODULE_STRING "-cddb-cachedir") );
567
568     cddb_set_timeout(conn, 
569                      config_GetInt( p_input, MODULE_STRING "-cddb-timeout") );
570
571
572     if (config_GetInt( p_input, MODULE_STRING "-cddb-httpd" )) {
573       cddb_http_enable(conn);
574     } else
575       cddb_http_disable(conn);
576     
577     p_cdda->cddb.disc = cddb_disc_new();
578     if (!p_cdda->cddb.disc) {
579       msg_Err( p_input, "Unable to create CDDB disc structure." );
580       goto cddb_end;
581     }
582
583     for(i = 1; i <= p_cdda->i_nb_tracks; i++) {
584       cddb_track_t *t = cddb_track_new(); 
585       t->frame_offset = cdio_get_track_lba(cdio, i);
586       cddb_disc_add_track(p_cdda->cddb.disc, t);
587     }
588     
589     p_cdda->cddb.disc->length = 
590       cdio_get_track_lba(cdio, CDIO_CDROM_LEADOUT_TRACK) 
591       / CDIO_CD_FRAMES_PER_SEC;
592
593
594     if (!cddb_disc_calc_discid(p_cdda->cddb.disc)) {
595       msg_Err( p_input, "CDDB disc calc failed" );
596       goto cddb_destroy;
597     }
598
599     i_matches = cddb_query(conn, p_cdda->cddb.disc);
600     if (i_matches > 0) {
601       if (i_matches > 1)
602         msg_Warn( p_input, "Found %d matches in CDDB. Using first one.", 
603                   i_matches);
604       cddb_read(conn, p_cdda->cddb.disc);
605
606       if (p_cdda->i_debug & INPUT_DBG_CDDB) 
607         cddb_disc_print(p_cdda->cddb.disc);
608
609     } else {
610       msg_Warn( p_input, "CDDB error: %s", cddb_error_str(errno));
611     }
612
613   cddb_destroy:
614     cddb_destroy(conn);
615   }
616   cddb_end: ;
617 }
618 #endif /*HAVE_LIBCDDB*/
619
620 #define add_format_str_info(val)                        \
621   {                                                     \
622     const char *str = val;                              \
623     unsigned int len;                                   \
624     if (val != NULL) {                                  \
625       len=strlen(str);                                  \
626       if (len != 0) {                                   \
627         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));   \
628         tp += len;                                      \
629       }                                                 \
630       saw_control_prefix = false;                       \
631     }                                                   \
632   }
633
634 #define add_format_num_info(val, fmt)                   \
635   {                                                     \
636     char num_str[10];                                   \
637     unsigned int len;                                   \
638     sprintf(num_str, fmt, val);                         \
639     len=strlen(num_str);                                \
640     if (len != 0) {                                     \
641       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
642       tp += len;                                        \
643     }                                                   \
644     saw_control_prefix = false;                         \
645   }
646
647 /*!
648    Take a format string and expand escape sequences, that is sequences that
649    begin with %, with information from the current CD. 
650    The expanded string is returned. Here is a list of escape sequences:
651
652    %a : The artist
653    %A : The album information 
654    %C : Category
655    %I : CDDB disk ID
656    %G : Genre
657    %M : The current MRL
658    %m : The CD-DA Media Catalog Number (MCN)
659    %T : The track number
660    %t : The name
661    %Y : The year 19xx or 20xx
662    %% : a %
663 */
664 static char *
665 CDDAFormatStr(const input_thread_t *p_input, cdda_data_t *p_cdda,
666               const char format_str[], const char *mrl, int i_track)
667 {
668 #define TEMP_STR_SIZE 256
669 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
670   static char    temp_str[TEMP_STR_SIZE];
671   size_t i;
672   char * tp = temp_str;
673   bool saw_control_prefix = false;
674   size_t format_len = strlen(format_str);
675
676   bzero(temp_str, TEMP_STR_SIZE);
677
678   for (i=0; i<format_len; i++) {
679
680     if (!saw_control_prefix && format_str[i] != '%') {
681       *tp++ = format_str[i];
682       saw_control_prefix = false;
683       continue;
684     }
685
686     switch(format_str[i]) {
687     case '%':
688       if (saw_control_prefix) {
689         *tp++ = '%';
690       }
691       saw_control_prefix = !saw_control_prefix;
692       break;
693 #ifdef HAVE_LIBCDDB      
694     case 'a':
695       if (!p_cdda->i_cddb_enabled) goto not_special;
696       add_format_str_info(p_cdda->cddb.disc->artist);
697       break;
698     case 'A':
699       if (!p_cdda->i_cddb_enabled) goto not_special;
700       add_format_str_info(p_cdda->cddb.disc->title);
701       break;
702     case 'C':
703       if (!p_cdda->i_cddb_enabled) goto not_special;
704       add_format_str_info(CDDB_CATEGORY[p_cdda->cddb.disc->category]);
705       break;
706     case 'G':
707       if (!p_cdda->i_cddb_enabled) goto not_special;
708       add_format_str_info(p_cdda->cddb.disc->genre);
709       break;
710     case 'I':
711       if (!p_cdda->i_cddb_enabled) goto not_special;
712       add_format_num_info(p_cdda->cddb.disc->discid, "%x");
713       break;
714     case 'Y':
715       if (!p_cdda->i_cddb_enabled) goto not_special;
716       add_format_num_info(p_cdda->cddb.disc->year, "%5d");
717       break;
718     case 't':
719       if (p_cdda->i_cddb_enabled) {
720         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, 
721                                             i_track-1);
722         if (t != NULL && t->title != NULL) 
723           add_format_str_info(t->title);
724       } else goto not_special;
725       break;
726
727 #endif
728
729     case 'M':
730       add_format_str_info(mrl);
731       break;
732 #if FINISHED
733     case 'm':
734       add_format_str_info(p_cdda->mcn);
735       break;
736 #endif
737     case 'T':
738       add_format_num_info(i_track, "%d");
739       break;
740 #ifdef HAVE_LIBCDDB      
741     not_special:
742 #endif
743     default:
744       *tp++ = '%'; 
745       *tp++ = format_str[i];
746       saw_control_prefix = false;
747     }
748   }
749   return strdup(temp_str);
750 }
751
752 static void
753 CDDACreatePlayListItem(const input_thread_t *p_input, cdda_data_t *p_cdda, 
754                        playlist_t *p_playlist, unsigned int i_track, 
755                        char *psz_mrl, int psz_mrl_max, 
756                        const char *psz_source, int playlist_operation, 
757                        unsigned int i_pos)
758 {
759   mtime_t i_duration = 
760     (p_cdda->p_sectors[i_track] - p_cdda->p_sectors[i_track-1]) 
761     * 1000 / CDIO_CD_FRAMES_PER_SEC;
762   char *p_title;
763   
764   snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u", 
765            CDDA_MRL_PREFIX, psz_source, i_track);
766
767   p_title = CDDAFormatStr(p_input, p_cdda, 
768                           config_GetPsz( p_input, 
769                                          MODULE_STRING "-title-format" ),
770                           psz_mrl, i_track);
771
772   playlist_AddExt( p_playlist, psz_mrl, p_title, i_duration, 
773                    0, 0, playlist_operation, i_pos );
774 }
775
776 static int
777 CDDAFixupPlayList(const input_thread_t *p_input, cdda_data_t *p_cdda, 
778                   const char *psz_source, bool play_single_track) 
779 {
780   int i;
781   playlist_t * p_playlist;
782   char       * psz_mrl;
783   unsigned int psz_mrl_max = strlen(CDDA_MRL_PREFIX) + strlen(psz_source) + 
784     strlen("@T") + strlen("100") + 1;
785
786 #ifdef HAVE_LIBCDDB
787   p_cdda->i_cddb_enabled = 
788     config_GetInt( p_input, MODULE_STRING "-cddb-enabled" );
789 #endif
790   
791   if (play_single_track && !p_cdda->i_cddb_enabled) return 0;
792
793   psz_mrl = malloc( psz_mrl_max );
794
795   if( psz_mrl == NULL )
796     {
797       msg_Warn( p_input, "out of memory" );
798       return -1;
799     }
800
801   p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
802                                                FIND_ANYWHERE );
803   if( !p_playlist )
804     {
805       msg_Warn( p_input, "can't find playlist" );
806       free(psz_mrl);
807       return -1;
808     }
809
810 #ifdef HAVE_LIBCDDB
811   if (p_cdda->i_cddb_enabled)
812     GetCDDBInfo(p_input, p_cdda);
813 #endif
814   
815   if (play_single_track) {
816     /* May fill out more information when the playlist user interface becomes
817        more mature.
818      */
819     CDDACreatePlayListItem(p_input, p_cdda, p_playlist, p_cdda->i_track+1, 
820                            psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE, 
821                            p_playlist->i_index);
822   } else {
823   
824     playlist_Delete( p_playlist, p_playlist->i_index);
825
826     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
827       {
828         CDDACreatePlayListItem(p_input, p_cdda, p_playlist, i, psz_mrl, 
829                                psz_mrl_max, psz_source, PLAYLIST_APPEND, 
830                                PLAYLIST_END);
831
832       }
833
834     playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
835
836   }
837     
838   vlc_object_release( p_playlist );
839   free(psz_mrl);
840   return 0;
841 }