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