]> git.sesse.net Git - vlc/blob - modules/access/cdda/info.c
* Fixes for CDDB courtesy of Alexander Gall <gall at switch dot ch>.
[vlc] / modules / access / cdda / info.c
1 /*****************************************************************************
2  * info.c : CD digital audio input information routines
3  *****************************************************************************
4  * Copyright (C) 2004, 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Rocky Bernstein <rocky@panix.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
28 #include "cdda.h"          /* private structures. Also #includes vlc things */
29 #include <vlc_playlist.h>  /* Has to come *after* cdda.h */
30
31 #include <cdio/cdio.h>
32 #include <cdio/cdtext.h>
33 #include <cdio/logging.h>
34 #include <cdio/cd_types.h>
35 #include "info.h"
36
37 #ifdef HAVE_ERRNO_H
38 #   include <errno.h>
39 #endif
40
41 static char *CDDAFormatStr( const access_t *p_access, cdda_data_t *p_cdda,
42                             const char format_str[], const char *psz_mrl, 
43                             track_t i_track);
44
45 static char *CDDAFormatMRL( const access_t *p_access, track_t i_track );
46
47 #ifdef HAVE_LIBCDDB
48
49 #define free_and_dup(var, val) \
50   if (var) free(var);          \
51   if (val) var=strdup(val);
52
53
54 /* Saves CDDB information about CD-DA via libcddb. */
55 static void 
56 GetCDDBInfo( access_t *p_access, cdda_data_t *p_cdda )
57 {
58     int i, i_matches;
59     cddb_conn_t  *conn = cddb_new();
60     const CdIo_t *p_cdio = p_cdda->p_cdio;
61
62     dbg_print( (INPUT_DBG_CALL), "" );
63
64 #ifdef FIXME_NOW
65     cddb_log_set_handler (uninit_log_handler);
66 #endif
67
68     if (!conn)
69     {
70         msg_Warn( p_access, "Unable to initialize libcddb" );
71         goto cddb_destroy;
72     }
73
74     cddb_set_email_address( conn,
75                             config_GetPsz( p_access,
76                                            MODULE_STRING "-cddb-email") );
77     cddb_set_server_name( conn,
78                           config_GetPsz( p_access,
79                                          MODULE_STRING "-cddb-server") );
80     cddb_set_server_port(conn,
81                          config_GetInt( p_access,
82                                         MODULE_STRING "-cddb-port") );
83
84   /* Set the location of the local CDDB cache directory.
85      The default location of this directory is */
86
87     if (!config_GetInt( p_access, MODULE_STRING "-cddb-enable-cache" ))
88         cddb_cache_disable(conn);
89
90     cddb_cache_set_dir(conn,
91                      config_GetPsz( p_access,
92                                     MODULE_STRING "-cddb-cachedir") );
93
94     cddb_set_timeout(conn,
95                    config_GetInt( p_access, MODULE_STRING "-cddb-timeout") );
96
97
98     if (config_GetInt( p_access, MODULE_STRING "-cddb-httpd" ) )
99     {
100         cddb_http_enable(conn);
101     }
102     else
103     {
104         cddb_http_disable(conn);
105     }
106
107     p_cdda->cddb.disc = cddb_disc_new();
108
109     if (!p_cdda->cddb.disc)
110     {
111         msg_Err( p_access, "Unable to create CDDB disc structure." );
112         goto cddb_end;
113     }
114
115     for(i = 0; i < p_cdda->i_tracks; i++)
116     {
117         track_t i_track =  p_cdda->i_first_track + i;
118         cddb_track_t *t = cddb_track_new();
119         cddb_track_set_frame_offset(t, 
120                                     cdio_get_track_lba(p_cdio, i_track));
121         cddb_disc_add_track(p_cdda->cddb.disc, t);
122     }
123
124     cddb_disc_set_length(p_cdda->cddb.disc,
125                          cdio_get_track_lba(p_cdio, CDIO_CDROM_LEADOUT_TRACK)
126                          / CDIO_CD_FRAMES_PER_SEC);
127
128     if (!cddb_disc_calc_discid(p_cdda->cddb.disc))
129     {
130         msg_Err( p_access, "CDDB disc ID calculation failed" );
131         goto cddb_destroy;
132     }
133
134     i_matches = cddb_query(conn, p_cdda->cddb.disc);
135
136     if (i_matches > 0)
137     {
138         if (i_matches > 1)
139              msg_Warn( p_access, "Found %d matches in CDDB. Using first one.",
140                                  i_matches);
141         cddb_read(conn, p_cdda->cddb.disc);
142
143         if (p_cdda->i_debug & INPUT_DBG_CDDB)
144             cddb_disc_print(p_cdda->cddb.disc);
145
146     }
147     else
148     {
149         msg_Warn( p_access, "CDDB error: %s", cddb_error_str(errno));
150     }
151
152 cddb_destroy:
153     cddb_destroy(conn);
154
155 cddb_end: ;
156 }
157 #endif /*HAVE_LIBCDDB*/
158
159 #define add_meta_val(VLC_META, VAL)                                     \
160   if ( p_cdda->p_meta && VAL) {                                         \
161     vlc_meta_Add( p_cdda->p_meta, VLC_META, VAL );                      \
162     dbg_print( INPUT_DBG_META, "field %s: %s\n", VLC_META, VAL );       \
163   }                                                                     \
164
165 #define add_cddb_meta(FIELD, VLC_META)                                  \
166   add_meta_val(VLC_META, cddb_disc_get_##FIELD(p_cdda->cddb.disc));
167
168 #define add_cddb_meta_fmt(FIELD, FORMAT_SPEC, VLC_META)                 \
169   {                                                                     \
170     char psz_buf[100];                                                  \
171     snprintf( psz_buf, sizeof(psz_buf)-1, FORMAT_SPEC,                  \
172               cddb_disc_get_##FIELD(p_cdda->cddb.disc));                               \
173     psz_buf[sizeof(psz_buf)-1] = '\0';                                  \
174     add_meta_val(VLC_META, psz_buf);                                    \
175   }
176
177 /* Adds a string-valued entry to the stream and media information if
178    the string is not null or the null string.
179  */
180 #define add_info_str(CATEGORY, TITLE, FIELD)                      \
181   if (FIELD && strlen(FIELD)) {                                   \
182     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
183                    _(TITLE), "%s", FIELD );                       \
184   }
185
186 /* Adds a numeric-valued entry to the stream and media information
187    if the number is not zero. */
188 #define add_info_val(CATEGORY, TITLE, FMT, FIELD)                 \
189   if (FIELD) {                                                    \
190     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
191                    _(TITLE), FMT, FIELD );                        \
192   }
193
194 /* Adds a CDDB string-valued entry to the stream and media information
195    under category "Disc" if the string is not null or the null string.
196  */
197 #define add_cddb_disc_info_str(TITLE, FIELD)                    \
198   add_info_str("Disc", TITLE, cddb_disc_get_##FIELD(p_cdda->cddb.disc))
199
200 /* Adds a CDDB numeric-valued entry to the stream and media information
201    under category "Disc" if the string is not null or the null string.
202  */
203 #define add_cddb_disc_info_val(TITLE, FMT, FIELD)               \
204   add_info_val("Disc", TITLE, FMT, cddb_disc_get_##FIELD(p_cdda->cddb.disc))
205
206 /* Adds a CD-Text string-valued entry to the stream and media information
207    under category "Disc" if the string is not null or the null string.
208  */
209 #define add_cdtext_info_str(CATEGORY, TITLE, INDEX, FIELD)              \
210     add_info_str(CATEGORY, TITLE, p_cdda->p_cdtext[INDEX]->field[FIELD])
211
212 /* Adds a CD-Text string-valued entry to the stream and media information
213    under category "Disc" if the string is not null or the null string.
214  */
215 #define add_cdtext_disc_info_str(TITLE, FIELD) \
216   add_cdtext_info_str("Disc", TITLE, 0, FIELD)
217
218
219 /*
220   Saves Meta Information about the CD-DA.
221
222   Meta information used in "stream and media info" or in playlist
223   info. The intialization of CD-Text or CDDB is done here though.
224   Therefore, this should be called before CDDAMetaInfo is called.
225
226  */
227 void 
228 CDDAMetaInfoInit( access_t *p_access )
229 {
230     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
231     
232     if ( ! p_cdda ) return;
233
234     dbg_print( (INPUT_DBG_CALL), "p_cdda->i_tracks %d", 
235                p_cdda->i_tracks );
236
237     p_cdda->psz_mcn = cdio_get_mcn(p_cdda->p_cdio);
238     p_cdda->p_meta = vlc_meta_New();
239
240 #ifdef HAVE_LIBCDDB
241     if ( p_cdda->b_cddb_enabled )
242     {
243         GetCDDBInfo(p_access, p_cdda);
244     }
245
246 #endif /*HAVE_LIBCDDB*/
247     
248 #define TITLE_MAX 30
249     {
250         track_t i_track;
251
252         for( i_track = 0 ; i_track < p_cdda->i_tracks ; i_track++ )
253         {
254             p_cdda->p_cdtext[i_track] =
255               cdio_get_cdtext(p_cdda->p_cdio, i_track);
256         }
257     }
258 }
259
260 /*
261  In the Control routine, we handle Meta Information requests and
262  basically copy what was saved in CDDAMetaInfoInit.
263
264  If i_track is CDIO_INVALID_TRACK we are probably asking about the entire
265  CD.
266  */
267 void 
268 CDDAMetaInfo( access_t *p_access, track_t i_track )
269 {
270     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
271     char *psz_meta_title = CDDAFormatMRL( p_access, i_track );
272     char *psz_meta_artist = NULL;
273     
274     if ( ! p_cdda ) return;
275
276     dbg_print( (INPUT_DBG_CALL), "i_track %d", i_track );
277
278 #ifdef HAVE_LIBCDDB
279
280     /* Set up for Meta and name for CDDB access. */
281     if ( p_cdda->b_cddb_enabled &&  p_cdda->cddb.disc )
282     {
283         if( CDIO_INVALID_TRACK == i_track )
284         {
285
286             psz_meta_title  = (char *)cddb_disc_get_title(p_cdda->cddb.disc);
287             psz_meta_artist = (char *)cddb_disc_get_artist(p_cdda->cddb.disc);
288             if ( cddb_disc_get_genre(p_cdda->cddb.disc) && 
289                      strlen(cddb_disc_get_genre(p_cdda->cddb.disc)) )
290                 add_cddb_meta(genre, VLC_META_GENRE);
291             if ( 0 != cddb_disc_get_year(p_cdda->cddb.disc))
292                 add_cddb_meta_fmt(year, "%d", VLC_META_DATE );
293         }
294         else
295         {
296           cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i_track-1);
297           if (t != NULL )
298           {
299               if( cddb_track_get_title(t) != NULL && ! p_cdda->b_nav_mode )
300               {
301                   add_meta_val( VLC_META_TITLE, cddb_track_get_title(t) );
302               }
303               if( cddb_track_get_artist(t) != NULL )
304               {
305                 add_meta_val( VLC_META_ARTIST, cddb_track_get_artist(t) );
306               }
307           }
308         }
309     }
310
311 #endif /*HAVE_LIBCDDB*/
312     
313 #define TITLE_MAX 30
314     {
315         track_t i = p_cdda->i_tracks;
316         const int i_first_track = p_cdda->i_first_track;
317         char psz_buffer[MSTRTIME_MAX_SIZE];
318         unsigned int i_track_frames = 
319           cdio_get_track_lba(p_cdda->p_cdio, CDIO_CDROM_LEADOUT_TRACK);
320           
321         mtime_t i_duration = i_track_frames / CDIO_CD_FRAMES_PER_SEC;
322
323         dbg_print( INPUT_DBG_META, "Duration %ld, tracks %d", 
324                    (long int) i_duration, p_cdda->i_tracks );
325         input_Control( p_cdda->p_input, INPUT_ADD_INFO,
326                        _("Disc"), _("Duration"), "%s",
327                        secstotimestr( psz_buffer, i_duration ) );
328
329         if (p_cdda->psz_mcn) {
330             input_Control( p_cdda->p_input, INPUT_ADD_INFO,
331                            _("Disc"), _("Media Catalog Number (MCN)"), "%s", 
332                            p_cdda->psz_mcn );
333             
334             input_Control( p_cdda->p_input, INPUT_ADD_INFO,
335                            _("Disc"), _("Tracks"), "%d", p_cdda->i_tracks );
336         }
337         
338
339 #ifdef HAVE_LIBCDDB
340         if (p_cdda->b_cddb_enabled && p_cdda->cddb.disc)
341         {
342           add_cddb_disc_info_str("Artist (CDDB)", artist);
343           if ( CDDB_CAT_INVALID != cddb_disc_get_category(p_cdda->cddb.disc) )
344             add_info_str("Disc", "Category (CDDB)",
345                          CDDB_CATEGORY[cddb_disc_get_category(p_cdda->cddb.disc)]);
346           add_cddb_disc_info_val("Disc ID (CDDB)", "%x", discid);
347           add_cddb_disc_info_str("Extended Data (CDDB)", ext_data);
348           add_cddb_disc_info_str("Genre (CDDB)",  genre);
349           add_cddb_disc_info_str("Title (CDDB)",  title);
350           if ( 0 != cddb_disc_get_year(p_cdda->cddb.disc) ) 
351             add_cddb_disc_info_val("Year (CDDB)", "%d", year);
352
353         }
354 #endif /*HAVE_LIBCDDB*/
355
356         if (p_cdda->p_cdtext[0])
357         {
358             char *psz_field;
359           
360             add_cdtext_disc_info_str("Arranger (CD-Text)",    CDTEXT_ARRANGER);
361             add_cdtext_disc_info_str("Composer (CD-Text)",    CDTEXT_COMPOSER);
362             add_cdtext_disc_info_str("Disc ID (CD-Text)",     CDTEXT_DISCID);
363             add_cdtext_disc_info_str("Genre (CD-Text)",       CDTEXT_GENRE);
364             add_cdtext_disc_info_str("Message (CD-Text)",     CDTEXT_MESSAGE);
365             add_cdtext_disc_info_str("Performer (CD-Text)",   CDTEXT_PERFORMER);
366             add_cdtext_disc_info_str("Songwriter (CD-Text)",  CDTEXT_SONGWRITER);
367             add_cdtext_disc_info_str("Title (CD-Text)",       CDTEXT_TITLE);
368
369             psz_field = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
370             if (psz_field && strlen(psz_field)) {   
371               psz_meta_title = psz_field;
372             }
373             psz_field = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
374             if (psz_field && strlen(psz_field)) {   
375               psz_meta_artist = psz_field;
376             }
377             
378         }
379
380         for( i = 0 ; i < p_cdda->i_tracks ; i++ )
381         {
382           char psz_track[TITLE_MAX];
383           const track_t i_track = i_first_track + i;
384           unsigned int i_track_frames = 
385             cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 
386             cdio_get_track_lsn(p_cdda->p_cdio, i_track);
387
388           mtime_t i_duration = i_track_frames / CDIO_CD_FRAMES_PER_SEC;
389           char *psz_mrl = CDDAFormatMRL( p_access, i_track );
390           
391           snprintf(psz_track, TITLE_MAX, "%s %02d", _("Track"), i_track);
392
393           input_Control( p_cdda->p_input, INPUT_ADD_INFO, psz_track,
394                          _("Duration"), "%s",
395                          secstotimestr( psz_buffer, i_duration ) );
396           
397           input_Control( p_cdda->p_input, INPUT_ADD_INFO, psz_track,
398                          _("MRL"), "%s", psz_mrl );
399           free(psz_mrl);
400           
401           if (p_cdda->p_cdtext[i_track])
402             {
403               add_cdtext_info_str( psz_track, "Arranger (CD-Text)",
404                                    i_track, CDTEXT_ARRANGER);
405               add_cdtext_info_str( psz_track, "Composer (CD-Text)",
406                                    i_track, CDTEXT_COMPOSER);
407               add_cdtext_info_str( psz_track, "Disc ID (CD-Text)",
408                                    i_track, CDTEXT_DISCID);
409               add_cdtext_info_str( psz_track, "Genre (CD-Text)",
410                                    i_track, CDTEXT_GENRE);
411               add_cdtext_info_str( psz_track, "Message (CD-Text)",
412                                    i_track, CDTEXT_MESSAGE);
413               add_cdtext_info_str( psz_track, "Performer (CD-Text)",
414                                    i_track, CDTEXT_PERFORMER);
415               add_cdtext_info_str( psz_track, "Songwriter (CD-Text)",
416                                    i_track, CDTEXT_SONGWRITER);
417               add_cdtext_info_str( psz_track, "Title (CD-Text)",
418                                    i_track, CDTEXT_TITLE);
419             }
420           
421 #ifdef HAVE_LIBCDDB
422           if (p_cdda->b_cddb_enabled)
423             {
424               cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i);
425               if (t != NULL)
426                 {
427                   add_info_str(psz_track, "Artist (CDDB)", 
428                                cddb_track_get_artist(t));
429                   add_info_str(psz_track, "Title (CDDB)",  
430                                cddb_track_get_title(t));
431                   add_info_str(psz_track, "Extended Data (CDDB)",
432                                cddb_track_get_ext_data(t));
433                 }
434             }
435 #endif /*HAVE_LIBCDDB*/
436         }
437
438         /* Above we should have set psz_meta_title and psz_meta_artist
439            to CDDB or CD-Text values or the default value depending on
440            availablity and user preferences.
441
442            So now add the title and artist to VLC's meta, and the name
443            as shown in the status bar and playlist entry.
444
445            For playlist mode, the meta title is what's seen at the
446            bottom and in the playlist. For nav-mode playing, it is
447            done by input_control. I don't understand why they do
448            different things. In either case, we may have customized to
449            put in the track name.
450          */
451         if ( CDIO_INVALID_TRACK != i_track ) 
452         {
453             char *psz_name = CDDAFormatTitle( p_access, i_track ) ;
454             if ( !p_cdda->b_nav_mode ) {
455                 add_meta_val( VLC_META_TITLE, psz_name );
456             } else 
457             { 
458                 input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_name );
459                 free(psz_name);
460             }
461             if (psz_meta_artist) 
462               add_meta_val( VLC_META_ARTIST, psz_meta_artist );
463         }
464         
465     }
466 }
467
468 #define add_format_str_info(val)                         \
469   {                                                      \
470     const char *str = val;                               \
471     unsigned int len;                                    \
472     if (val != NULL) {                                   \
473       len=strlen(str);                                   \
474       if (len != 0) {                                    \
475         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));    \
476         tp += len;                                       \
477       }                                                  \
478       saw_control_prefix = false;                        \
479     }                                                    \
480   }
481
482 #define add_format_num_info(val, fmt)                    \
483   {                                                      \
484     char num_str[10];                                    \
485     unsigned int len;                                    \
486     sprintf(num_str, fmt, val);                          \
487     len=strlen(num_str);                                 \
488     if (len != 0) {                                      \
489       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));  \
490       tp += len;                                         \
491     }                                                    \
492     saw_control_prefix = false;                          \
493   }
494
495 static inline bool
496 want_cddb_info(
497 cdda_data_t *p_cdda, char *psz_cdtext) 
498 {
499   /* We either don't have CD-Text info, or we do but we prefer to get CDDB
500      which means CDDB has been enabled and we were able to retrieve the info.*/
501 #ifdef HAVE_LIBCDDB
502   return !psz_cdtext || 
503     (!p_cdda->b_cdtext_prefer && p_cdda->b_cddb_enabled && p_cdda->cddb.disc);
504 #else
505   return false;
506 #endif
507 }
508
509
510 /*!
511    Take a format string and expand escape sequences, that is sequences that
512    begin with %, with information from the current CD.
513    The expanded string is returned. Here is a list of escape sequences:
514
515    %a : The album artist **
516    %A : The album information **
517    %C : Category **
518    %e : The extended track data
519    %I : CDDB disk ID **
520    %G : Genre **
521    %M : The current MRL
522    %m : The CD-DA Media Catalog Number (MCN)
523    %n : The number of tracks on the CD
524    %p : The artist/performer/composer in the track **
525    %T : The track number **
526    %s : Number of seconds in this track, or seconds in CD if invalid track
527    %S : Number of seconds on the CD
528    %t : The track name or MRL if no name 
529    %Y : The year 19xx or 20xx **
530    %% : a %
531 */
532 char *
533 CDDAFormatStr( const access_t *p_access, cdda_data_t *p_cdda,
534                const char format_str[], const char *psz_mrl, track_t i_track)
535 {
536 #define TEMP_STR_SIZE 256
537 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
538     static char temp_str[TEMP_STR_SIZE];
539     size_t i;
540     char * tp = temp_str;
541     vlc_bool_t saw_control_prefix = false;
542     size_t format_len = strlen(format_str);
543
544     memset(temp_str, 0, TEMP_STR_SIZE);
545
546     for (i=0; i<format_len; i++)
547     {
548         char *psz = NULL;
549
550         if (!saw_control_prefix && format_str[i] != '%')
551         {
552             *tp++ = format_str[i];
553             saw_control_prefix = false;
554             continue;
555         }
556
557         switch(format_str[i])
558         {
559             case '%':
560               if (saw_control_prefix)
561               {
562                   *tp++ = '%';
563               }
564               saw_control_prefix = !saw_control_prefix;
565               break;
566 #ifdef HAVE_LIBCDDB
567             case 'a':
568                 if (p_cdda->p_cdtext[0]
569                     && p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER])
570                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
571                 if (want_cddb_info(p_cdda, psz))
572                   psz = (char *)cddb_disc_get_artist(p_cdda->cddb.disc);
573                 goto format_str;
574             case 'A':
575                 if (p_cdda->p_cdtext[0]
576                     && p_cdda->p_cdtext[0]->field[CDTEXT_TITLE])
577                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
578                 if (want_cddb_info(p_cdda, psz))
579                   psz =  (char *)cddb_disc_get_title(p_cdda->cddb.disc);
580                 goto format_str;
581             case 'C':
582                 if (!p_cdda->b_cddb_enabled) goto not_special;
583                 if (p_cdda->cddb.disc)
584                     add_format_str_info(CDDB_CATEGORY[cddb_disc_get_category(p_cdda->cddb.disc)]);
585                 break;
586             case 'G':
587                 if (p_cdda->p_cdtext[0]
588                     && p_cdda->p_cdtext[0]->field[CDTEXT_GENRE])
589                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_GENRE];
590                 if (want_cddb_info(p_cdda, psz))
591                   psz = (char *)cddb_disc_get_genre(p_cdda->cddb.disc);
592                 goto format_str;
593             case 'I':
594                 if (p_cdda->p_cdtext[0]
595                     && p_cdda->p_cdtext[0]->field[CDTEXT_DISCID])
596                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_DISCID];
597                 if (want_cddb_info(p_cdda, psz)) {
598                      add_format_num_info(cddb_disc_get_discid(p_cdda->cddb.disc), "%x");
599                 } else if (psz)
600                      add_format_str_info(psz);
601                 break;
602             case 'Y':
603                 if (!p_cdda->b_cddb_enabled) goto not_special;
604                 if (p_cdda->cddb.disc)
605                     add_format_num_info(cddb_disc_get_year(p_cdda->cddb.disc), 
606                                         "%5d");
607                 break;
608             case 't':
609                 if ( CDIO_INVALID_TRACK == i_track ) break;
610                 if (p_cdda && p_cdda->b_cddb_enabled && p_cdda->cddb.disc)
611                 {
612                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
613                                                         i_track-1);
614                     if (t != NULL && cddb_track_get_title(t) != NULL) {
615                       add_format_str_info(cddb_track_get_title(t));
616                     } else {
617                       add_format_str_info(psz_mrl);
618                     }
619                 } else {
620                   if (p_cdda->p_cdtext[i_track]
621                       && p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE]) {
622                     add_format_str_info(p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE]);
623                   
624                   } else 
625                     add_format_str_info(psz_mrl);
626                 }
627                 break;
628             case 'p':
629                 if ( CDIO_INVALID_TRACK == i_track ) break;
630                 if (p_cdda->p_cdtext[i_track] 
631                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER])
632                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER];
633                 if (want_cddb_info(p_cdda, psz))
634                   {
635                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
636                                                         i_track-1);
637                     if (t != NULL && cddb_track_get_artist(t) != NULL)
638                       psz = (char *)cddb_track_get_artist(t);
639                   }
640                 goto format_str;
641             case 'e':
642                 if ( CDIO_INVALID_TRACK == i_track ) break;
643                 if (p_cdda->p_cdtext[i_track] 
644                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE])
645                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE];
646                 if (want_cddb_info(p_cdda, psz))
647                 {
648                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
649                                                         i_track-1);
650                     if (t != NULL && cddb_track_get_ext_data(t) != NULL)
651                         psz = (char *)cddb_track_get_ext_data(t);
652                 } 
653                 goto format_str;
654                 break;
655 #else
656             case 'a':
657                 if (p_cdda->p_cdtext[0] 
658                     && p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER])
659                     psz = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
660                 goto format_str;
661             case 'A':
662                 if (p_cdda->p_cdtext[0] 
663                     && p_cdda->p_cdtext[0]->field[CDTEXT_TITLE])
664                     psz = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
665                 goto format_str;
666             case 'G':
667                 if (p_cdda->p_cdtext[0] 
668                     && p_cdda->p_cdtext[0]->field[CDTEXT_GENRE])
669                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_GENRE];
670                 goto format_str;
671             case 'I':
672                 if (p_cdda->p_cdtext[0] 
673                     && p_cdda->p_cdtext[0]->field[CDTEXT_DISCID])
674                   add_format_str_info(p_cdda->p_cdtext[0]->field[CDTEXT_DISCID]);
675                 break;
676             case 'p':
677                 if ( CDIO_INVALID_TRACK == i_track ) break;
678                 if (p_cdda->p_cdtext[i_track] 
679                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER])
680                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER];
681                 goto format_str;
682             case 't':
683                 if ( CDIO_INVALID_TRACK == i_track ) break;
684                 if (p_cdda->p_cdtext[i_track] 
685                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE])
686                     psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE];
687                 else 
688                     psz = psz_mrl;
689                 goto format_str;
690             case 'e':
691                 if ( CDIO_INVALID_TRACK == i_track ) break;
692                 if (p_cdda->p_cdtext[i_track] 
693                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE])
694                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE];
695                 goto format_str;
696                 break;
697 #endif /*HAVE_LIBCDDB*/
698
699             case 's':
700                 if ( CDIO_INVALID_TRACK != i_track )
701                 {
702                     char psz_buffer[MSTRTIME_MAX_SIZE];
703                     unsigned int i_track_frames = 
704                       cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
705                     mtime_t i_duration = 
706                       i_track_frames / CDIO_CD_FRAMES_PER_SEC;
707                     add_format_str_info( secstotimestr( psz_buffer, 
708                                                         i_duration ) );
709                     break;
710                 }
711
712                 /* Fall through to disc duration if CDIO_INVALID_TRACK  */
713             case 'S':
714                 {
715                     char psz_buffer[MSTRTIME_MAX_SIZE];
716                     unsigned int i_track_frames = 
717                       cdio_get_track_lba(p_cdda->p_cdio, 
718                                          CDIO_CDROM_LEADOUT_TRACK);
719                     mtime_t i_duration = 
720                       i_track_frames / CDIO_CD_FRAMES_PER_SEC;
721                     add_format_str_info( secstotimestr( psz_buffer, 
722                                                         i_duration ) );
723                     break;
724                 }
725
726             case 'M':
727               add_format_str_info(psz_mrl);
728               break;
729
730             case 'm':
731               add_format_str_info(p_cdda->psz_mcn);
732               break;
733
734             case 'n':
735               add_format_num_info(p_cdda->i_tracks, "%d");
736               break;
737
738             case 'T':
739               add_format_num_info(i_track, "%02d");
740               break;
741             format_str:
742               if (psz)
743                 add_format_str_info(psz);
744               break;
745 #ifdef HAVE_LIBCDDB
746             not_special:
747 #endif
748             default:
749                 *tp++ = '%';
750                 *tp++ = format_str[i];
751                 saw_control_prefix = false;
752         }
753     }
754     return strdup(temp_str);
755 }
756
757 /* Return a MRL for the given track. The caller must free the 
758    allocated string. */
759 static char *
760 CDDAFormatMRL( const access_t *p_access, track_t i_track )
761 {
762     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
763     const unsigned int psz_mrl_max = strlen(CDDA_MRL_PREFIX) 
764       + strlen(p_cdda->psz_source) +
765       + strlen("@T") + strlen("100") + 1;
766     char *psz_mrl = calloc( 1, psz_mrl_max );
767     
768     if (CDIO_INVALID_TRACK == i_track)
769       snprintf(psz_mrl, psz_mrl_max, "%s%s",
770                CDDA_MRL_PREFIX, p_cdda->psz_source);
771     else 
772       snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
773                CDDA_MRL_PREFIX, p_cdda->psz_source, i_track);
774     return psz_mrl;
775 }
776
777
778 /* Return a title string as specified by the titel format string for the 
779    given track. The caller must free the allocated string. */
780 char *
781 CDDAFormatTitle( const access_t *p_access, track_t i_track )
782
783
784     char *config_varname = MODULE_STRING "-title-format";
785     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
786     char *psz_mrl = CDDAFormatMRL( p_access, i_track );
787
788     if( psz_mrl ) 
789     {
790         char *psz_name;
791 #ifdef HAVE_LIBCDDB
792         if (p_cdda->b_cddb_enabled)
793         {
794             config_varname = MODULE_STRING "-cddb-title-format";
795         }
796 #endif /*HAVE_LIBCDDB*/
797         psz_name = 
798           CDDAFormatStr( p_access, p_cdda,
799                          config_GetPsz( p_access, config_varname ),
800                          psz_mrl, i_track );
801         free(psz_mrl);
802         return psz_name;
803     }
804     return(NULL);
805 }
806
807 /* Adds a string-valued entry to the playlist information under "Track"
808    if the string is not null or the null string.
809  */
810 #define add_playlist_track_info_str(TITLE, FIELD)                        \
811     if (FIELD && strlen(FIELD))                                          \
812     {                                                                    \
813         vlc_input_item_AddInfo( &p_item->input, _("Track"), _(TITLE),    \
814                               "%s", FIELD);                              \
815     }
816
817 static playlist_item_t *
818 CDDACreatePlaylistItem( const access_t *p_access, cdda_data_t *p_cdda,
819                         playlist_t *p_playlist, playlist_item_t *p_item, 
820                         track_t i_track )
821 {
822   unsigned int i_track_frames = 
823     cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 
824     cdio_get_track_lsn(p_cdda->p_cdio, i_track);
825     mtime_t i_mduration = 
826       i_track_frames * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC) ;
827     char *psz_title = NULL;
828     char *psz_mrl   = NULL;
829
830     playlist_item_t *p_child = NULL;
831
832     if( !p_item ) return NULL;
833
834     psz_title = CDDAFormatTitle( p_access, i_track ) ;
835     psz_mrl = CDDAFormatMRL( p_access, i_track  ) ;
836
837     dbg_print( INPUT_DBG_META, "mrl: %s, title: %s, duration, %ld",
838                psz_mrl, psz_title, (long int) i_mduration / 1000000 );
839
840     p_child = playlist_ItemNew( p_playlist, psz_mrl, psz_title );
841     p_child->input.i_duration   = i_mduration;
842     free(psz_mrl);
843     free(psz_title);
844
845     if( !p_child ) return NULL;
846
847     playlist_NodeAddItem( p_playlist, p_child,
848                           p_item->pp_parents[0]->i_view,
849                           p_item, PLAYLIST_APPEND, PLAYLIST_END );
850     playlist_CopyParents( p_item, p_child );
851
852     return p_child;
853 }
854
855 int CDDAAddMetaToItem( access_t *p_access, cdda_data_t *p_cdda,
856                        playlist_item_t *p_item, int i_track,
857                        vlc_bool_t b_single )
858 {
859     add_playlist_track_info_str("Source",  p_cdda->psz_source);
860     vlc_input_item_AddInfo( &p_item->input, _("Track"), _("Track Number"),
861                            "%d", i_track );
862
863     if (p_cdda->p_cdtext[i_track])
864     {
865         const cdtext_t *p = p_cdda->p_cdtext[i_track];
866         add_playlist_track_info_str("Arranger (CD-Text)",
867                                     p->field[CDTEXT_ARRANGER]);
868         add_playlist_track_info_str("Composer (CD-Text)",
869                                     p->field[CDTEXT_COMPOSER]);
870         add_playlist_track_info_str("Genre (CD-Text)",
871                                     p->field[CDTEXT_GENRE]);
872         add_playlist_track_info_str("Message (CD-Text)",
873                                     p->field[CDTEXT_MESSAGE]);
874         add_playlist_track_info_str("Performer (CD-Text)",
875                                     p->field[CDTEXT_PERFORMER]);
876         add_playlist_track_info_str("Songwriter (CD-Text)",
877                                     p->field[CDTEXT_SONGWRITER]);
878         add_playlist_track_info_str("Title (CD-Text)",
879                                     p->field[CDTEXT_TITLE]);
880     }
881
882 #ifdef HAVE_LIBCDDB
883     if (p_cdda->b_cddb_enabled)
884     {
885         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
886                                             i_track-p_cdda->i_first_track);
887
888         if (t)
889         {
890             if (cddb_track_get_artist(t))
891                 add_playlist_track_info_str("Artist (CDDB)",
892                                              cddb_track_get_artist(t));
893             if (cddb_track_get_title(t))
894                 add_playlist_track_info_str("Title (CDDB)",
895                                             cddb_track_get_title(t));
896             if (cddb_track_get_ext_data(t))
897                 add_playlist_track_info_str("Extended information (CDDB)",
898                                             cddb_track_get_ext_data(t));
899         }
900     }
901 #endif /*HAVE_LIBCDDB*/
902
903     return VLC_SUCCESS;
904 }
905
906 /* 
907    Fixes up playlist. 
908 */
909 int
910 CDDAFixupPlaylist( access_t *p_access, cdda_data_t *p_cdda, 
911                    vlc_bool_t b_single_track )
912 {
913     int i;
914     playlist_t * p_playlist = NULL;
915     const track_t i_first_track = p_cdda->i_first_track;
916     playlist_item_t *p_item = NULL;
917     vlc_bool_t b_play = VLC_FALSE;
918     track_t    i_track;
919
920 #ifdef HAVE_LIBCDDB
921     p_cdda->b_cddb_enabled =
922         config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
923     if( b_single_track && !p_cdda->b_cddb_enabled )
924         return VLC_SUCCESS;
925 #else
926     if( b_single_track )
927         return VLC_SUCCESS;
928 #endif
929
930     if (! p_cdda->b_nav_mode ) {
931         p_playlist = (playlist_t *) vlc_object_find( p_access, 
932                                                      VLC_OBJECT_PLAYLIST,
933                                                      FIND_ANYWHERE );
934         if( !p_playlist )
935           {
936               msg_Warn( p_access, "can't find playlist" );
937               return VLC_EGENERIC;
938           }
939     }
940
941     if( b_single_track || p_cdda->b_nav_mode ) {
942         i_track = p_cdda->i_track;
943     }
944     else
945     {
946         i_track = CDIO_INVALID_TRACK;
947     }
948     CDDAMetaInfoInit( p_access );
949     CDDAMetaInfo( p_access, p_cdda->i_track );
950
951     if (p_playlist) {
952
953       p_item = playlist_LockItemGetByInput( p_playlist,
954                         ((input_thread_t *)p_access->p_parent)->input.p_item );
955
956       if( p_item == p_playlist->status.p_item && !b_single_track )
957         {
958           b_play = VLC_TRUE;
959         }
960       else
961         {
962           b_play = VLC_FALSE;
963         }
964     }
965
966     if( b_single_track && !p_cdda->b_nav_mode )
967     {
968         /*May fill out more information when the playlist user interface becomes
969            more mature.
970          */
971         track_t i_track = p_cdda->i_track;
972         unsigned int i_track_frames = 
973           cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
974         
975         input_title_t *t = p_cdda->p_title[0] = //i_track-i_first_track] =
976         vlc_input_title_New();
977
978         asprintf( &t->psz_name, _("Track %i"), i_track );
979         t->i_size = i_track_frames * (int64_t) CDIO_CD_FRAMESIZE_RAW;
980
981         t->i_length = I64C(1000000) * t->i_size / CDDA_FREQUENCY_SAMPLE / 4;
982
983
984         if (p_item) 
985         {
986             CDDAAddMetaToItem( p_access, p_cdda, p_item, i_track, VLC_FALSE );
987             p_item->input.i_duration = i_track_frames 
988               * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC);
989             p_item->input.psz_uri    = CDDAFormatMRL(p_access, i_track);
990         }
991         
992         p_cdda->i_titles = 1;
993         p_access->info.i_update = INPUT_UPDATE_TITLE;
994     }
995     else
996     {
997         input_title_t *t;
998
999         if ( !p_cdda->b_nav_mode )
1000           playlist_ItemToNode( p_playlist, p_item );
1001
1002         for( i = 0 ; i < p_cdda->i_tracks ; i++ )
1003         {
1004             playlist_item_t *p_child;
1005             const track_t i_track = i_first_track + i;
1006             unsigned int i_track_frames = 
1007               cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
1008
1009             t = p_cdda->p_title[i] = vlc_input_title_New();
1010
1011             asprintf( &t->psz_name, _("Track %i"), i_track );
1012             t->i_size = i_track_frames * (int64_t) CDIO_CD_FRAMESIZE_RAW;
1013
1014             t->i_length = I64C(1000000) * t->i_size 
1015               / CDDA_FREQUENCY_SAMPLE / 4;
1016
1017             if ( ! p_cdda->b_nav_mode ) {
1018               p_child = CDDACreatePlaylistItem( p_access, p_cdda, p_playlist,
1019                                                 p_item,
1020                                                 i_track );
1021               CDDAAddMetaToItem( p_access, p_cdda, p_child, i_track, 
1022                                  VLC_TRUE );
1023             }
1024         }
1025
1026         p_cdda->i_titles = p_cdda->i_tracks;
1027         p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
1028         if (p_item) {
1029             p_item->input.i_duration = 
1030               p_access->info.i_size * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC) ;
1031             p_item->input.psz_uri    = CDDAFormatMRL(p_access, 
1032                                                      p_cdda->i_track);
1033         }
1034     }
1035     
1036
1037     if( b_play )
1038     {
1039         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
1040                           p_playlist->status.i_view,
1041                           p_playlist->status.p_item, NULL );
1042     }
1043
1044     if (p_playlist) vlc_object_release( p_playlist );
1045     return VLC_SUCCESS;
1046 }
1047
1048
1049 /* 
1050  * Local variables:
1051  *  mode: C
1052  *  style: gnu
1053  * End:
1054  */