]> git.sesse.net Git - vlc/blobdiff - modules/access/cdda.c
Fix CDDA and a corner-case in playlist handling
[vlc] / modules / access / cdda.c
index e1fa03e0067a6ec9ff058e362242d93b7ac7feac..76cb40991ee98a53429d2088aeed82d5a80c9ba6 100644 (file)
 
 #include <vlc_playlist.h>
 
+#ifdef HAVE_LIBCDDB
+#include <cddb/cddb.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
 /*****************************************************************************
  * Module descriptior
  *****************************************************************************/
@@ -43,8 +51,8 @@ static void Close( vlc_object_t * );
 
 #define CACHING_TEXT N_("Caching value in ms")
 #define CACHING_LONGTEXT N_( \
-    "Allows you to modify the default caching value for cdda streams. This " \
-    "value should be set in milliseconds units." )
+    "Default caching value for Audio CDs. This " \
+    "value should be set in milliseconds." )
 
 vlc_module_begin();
     set_shortname( _("Audio CD"));
@@ -58,7 +66,15 @@ vlc_module_begin();
     add_integer( "cdda-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
                  CACHING_LONGTEXT, VLC_TRUE );
     add_bool( "cdda-separate-tracks", VLC_TRUE, NULL, NULL, NULL, VLC_TRUE );
+        change_internal();
     add_integer( "cdda-track", -1 , NULL, NULL, NULL, VLC_TRUE );
+        change_internal();
+    add_string( "cddb-server", "freedb.freedb.org", NULL,
+                N_( "CDDB Server" ), N_( "Address of the CDDB server to use." ),
+                VLC_TRUE );
+    add_integer( "cddb-port", 8880, NULL,
+                N_( "CDDB port" ), N_( "CDDB Server port to use." ),
+                VLC_TRUE );
     add_shortcut( "cdda" );
     add_shortcut( "cddasimple" );
 vlc_module_end();
@@ -90,6 +106,10 @@ struct access_sys_t
     vlc_bool_t  b_separate_items;
     vlc_bool_t  b_single_track;
     int         i_track;
+
+#ifdef HAVE_LIBCDDB
+    cddb_disc_t *p_disc;
+#endif
 };
 
 static block_t *Block( access_t * );
@@ -99,6 +119,10 @@ static int      Control( access_t *, int, va_list );
 static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
                       playlist_t *p_playlist, playlist_item_t *p_parent );
 
+#ifdef HAVE_LIBCDDB
+static void GetCDDBInfo( access_t *p_access, int i_titles, int *p_sectors );
+#endif
+
 /*****************************************************************************
  * Open: open cdda
  *****************************************************************************/
@@ -132,6 +156,11 @@ static int Open( vlc_object_t *p_this )
     }
     else psz_name = strdup( p_access->psz_path );
 
+#ifdef WIN32
+    if( psz_name[0] && psz_name[1] == ':' &&
+        psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0';
+#endif
+
     /* Open CDDA */
     if( (vcddev = ioctl_Open( VLC_OBJECT(p_access), psz_name )) == NULL )
     {
@@ -178,7 +207,7 @@ static int Open( vlc_object_t *p_this )
         p_sys->i_track = i_track - 1;
     }
 
-    msg_Dbg( p_access, "Separate items : %i - Single track : %i",
+    msg_Dbg( p_access, "separate items : %i - single track : %i",
                         p_sys->b_separate_items, p_sys->b_single_track );
 
     if( p_sys->b_separate_items )
@@ -189,7 +218,7 @@ static int Open( vlc_object_t *p_this )
         if( !p_playlist ) return VLC_EGENERIC;
 
         /* Let's check if we need to play */
-        if( &p_playlist->status.p_item->input ==
+        if( p_playlist->status.p_item->p_input ==
              ((input_thread_t *)p_access->p_parent)->input.p_item )
         {
             p_item = p_playlist->status.p_item;
@@ -206,7 +235,7 @@ static int Open( vlc_object_t *p_this )
             if( !p_item )
             {
                 msg_Dbg( p_playlist, "unable to find item in playlist");
-               return -1;
+                return -1;
             }
             b_play = VLC_FALSE;
         }
@@ -262,9 +291,9 @@ static int Open( vlc_object_t *p_this )
 
     if( b_play )
     {
-        playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
-                          p_playlist->status.i_view, p_playlist->status.p_item,
-                          NULL );
+          playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, 1242,
+                            p_playlist->request.p_node, NULL );
+//        playlist_Play( p_playlist );
     }
 
     if( p_playlist ) vlc_object_release( p_playlist );
@@ -418,7 +447,7 @@ static int Control( access_t *p_access, int i_query, va_list args )
     input_title_t ***ppp_title;
     int i;
     char         *psz_title;
-    vlc_meta_t  **pp_meta;
+    vlc_meta_t  *p_meta;
 
     switch( i_query )
     {
@@ -484,9 +513,8 @@ static int Control( access_t *p_access, int i_query, va_list args )
              psz_title = malloc( strlen( _("Audio CD - Track ") ) + 5 );
              snprintf( psz_title, 100, _("Audio CD - Track %i" ),
                                         p_access->info.i_title+1 );
-             pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
-             *pp_meta = vlc_meta_New();
-             vlc_meta_Add( *pp_meta, VLC_META_TITLE, psz_title );
+             p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
+             vlc_meta_SetTitle( p_meta, psz_title );
              free( psz_title );
              break;
 
@@ -507,7 +535,9 @@ static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
 {
     access_sys_t *p_sys = p_access->p_sys;
     int i;
-    playlist_item_t *p_item;
+    input_item_t *p_input_item;
+    playlist_item_t *p_item_in_category;
+    char *psz_name;
     p_sys->i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access),
                                           p_sys->vcddev, &p_sys->p_sectors );
     if( p_sys->i_titles < 0 )
@@ -523,10 +553,32 @@ static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
 
     if( b_separate )
     {
-        if( p_parent->i_children == -1 )
+        p_item_in_category = playlist_LockItemToNode( p_playlist, p_parent );
+        psz_name = strdup( "Audio CD" );
+        vlc_mutex_lock( &p_playlist->object_lock );
+        playlist_ItemSetName( p_parent, psz_name );
+        vlc_mutex_unlock( &p_playlist->object_lock );
+        var_SetInteger( p_playlist, "item-change",
+                        p_parent->p_input->i_id );
+        free( psz_name );
+
+#ifdef HAVE_LIBCDDB
+        GetCDDBInfo( p_access, p_sys->i_titles, p_sys->p_sectors );
+        if( p_sys->p_disc )
         {
-            playlist_LockItemToNode( p_playlist, p_parent );
+            if( cddb_disc_get_title( p_sys->p_disc ) )
+            {
+                asprintf( &psz_name, "%s", cddb_disc_get_title( p_sys->p_disc )
+                         );
+                vlc_mutex_lock( &p_playlist->object_lock );
+                playlist_ItemSetName( p_parent, psz_name );
+                vlc_mutex_unlock( &p_playlist->object_lock );
+                var_SetInteger( p_playlist, "item-change",
+                                p_parent->p_input->i_id );
+                free( psz_name );
+            }
         }
+#endif
     }
 
     /* Build title table */
@@ -548,23 +600,56 @@ static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
             char *psz_uri;
             int i_path_len = p_access->psz_path ? strlen( p_access->psz_path )
                                                 : 0;
-            char *psz_name = malloc( strlen( _("Audio CD - Track ") ) + 5 );
-            char *psz_opt = (char*)malloc( 14 );
+            char *psz_opt;
+
+            psz_name = malloc( strlen( _("Audio CD - Track ") ) + 5 );
+            psz_opt = malloc( strlen( "cdda-track=" ) + 3 );
 
             psz_uri = (char*)malloc( i_path_len + 13 );
             snprintf( psz_uri, i_path_len + 13, "cdda://%s",
                                 p_access->psz_path ? p_access->psz_path : "" );
-            snprintf( psz_name, 100, _("Audio CD - Track %i" ),
-                                     (i+1) );
-            snprintf( psz_opt, 14, "cdda-track=%i", i+1 );
+            sprintf( psz_opt, "cdda-track=%i", i+1 );
+
+            /* Define a "default name" */
+            sprintf( psz_name, _("Audio CD - Track %i"), (i+1) );
+
             /* Create playlist items */
-            p_item = playlist_ItemNewWithType( VLC_OBJECT( p_playlist ),
-                                 psz_uri, psz_name, ITEM_TYPE_DISC );
-            playlist_ItemAddOption( p_item, psz_opt );
-            playlist_NodeAddItem( p_playlist, p_item,
-                                  p_parent->pp_parents[0]->i_view,
-                                  p_parent, PLAYLIST_APPEND, PLAYLIST_END );
-            free( psz_uri ); free( psz_opt );
+            p_input_item = input_ItemNewWithType( VLC_OBJECT( p_playlist ),
+                                psz_uri, psz_name, 0, NULL, -1,
+                                ITEM_TYPE_DISC );
+            vlc_input_item_AddOption( p_input_item, psz_opt );
+#ifdef HAVE_LIBCDDB
+            /* If we have CDDB info, change the name */
+            if( p_sys->p_disc )
+            {
+                char *psz_result;
+                cddb_track_t *t = cddb_disc_get_track( p_sys->p_disc, i );
+                if( t!= NULL )
+                {
+                    if( cddb_track_get_title( t )  != NULL )
+                    {
+                        vlc_input_item_AddInfo( p_input_item,
+                                            _(VLC_META_INFO_CAT),
+                                            _(VLC_META_TITLE),
+                                            cddb_track_get_title( t ) );
+                        if( p_input_item->psz_name )
+                            free( p_input_item->psz_name );
+                        asprintf( &p_input_item->psz_name, "%s",
+                                  cddb_track_get_title( t ) );
+                    }
+                    psz_result = cddb_track_get_artist( t );
+                    if( psz_result )
+                    {
+                        vlc_input_item_AddInfo( p_input_item,
+                                            _(VLC_META_INFO_CAT),
+                                            _(VLC_META_ARTIST), psz_result );
+                    }
+                }
+            }
+#endif
+            playlist_AddWhereverNeeded( p_playlist, p_input_item, p_parent,
+                               p_item_in_category, VLC_FALSE, PLAYLIST_APPEND );
+            free( psz_uri ); free( psz_opt ); free( psz_name );
         }
     }
 
@@ -576,3 +661,83 @@ static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
 
    return VLC_SUCCESS;
 }
+
+#ifdef HAVE_LIBCDDB
+static void GetCDDBInfo( access_t *p_access, int i_titles, int *p_sectors )
+{
+    int i, i_matches;
+    int64_t  i_length = 0, i_size = 0;
+    cddb_conn_t  *p_cddb = cddb_new();
+
+//    cddb_log_set_handler( CDDBLogHandler );
+
+    if( !p_cddb )
+    {
+        msg_Warn( p_access, "unable to use CDDB" );
+        goto cddb_destroy;
+    }
+
+    cddb_set_email_address( p_cddb, "vlc@videolan.org" );
+    cddb_set_server_name( p_cddb, config_GetPsz( p_access, "cddb-server" ) );
+    cddb_set_server_port( p_cddb, config_GetInt( p_access, "cddb-port" ) );
+
+    /// \todo
+    cddb_cache_disable( p_cddb );
+
+//    cddb_cache_set_dir( p_cddb,
+//                     config_GetPsz( p_access,
+//                                    MODULE_STRING "-cddb-cachedir") );
+
+    cddb_set_timeout( p_cddb, 10 );
+
+    /// \todo
+    cddb_http_disable( p_cddb);
+
+    p_access->p_sys->p_disc = cddb_disc_new();
+
+    if(! p_access->p_sys->p_disc )
+    {
+        msg_Err( p_access, "unable to create CDDB disc structure." );
+        goto cddb_end;
+    }
+
+    for(i = 0; i < i_titles ; i++ )
+    {
+        cddb_track_t *t = cddb_track_new();
+        cddb_track_set_frame_offset(t, p_sectors[i] );
+        cddb_disc_add_track( p_access->p_sys->p_disc, t );
+        i_size = ( p_sectors[i+1] - p_sectors[i] ) *
+                   (int64_t)CDDA_DATA_SIZE;
+        i_length += I64C(1000000) * i_size / 44100 / 4  ;
+    }
+
+    cddb_disc_set_length( p_access->p_sys->p_disc, (int)(i_length/1000000) );
+
+    if (!cddb_disc_calc_discid(p_access->p_sys->p_disc ))
+    {
+        msg_Err( p_access, "CDDB disc ID calculation failed" );
+        goto cddb_destroy;
+    }
+
+    i_matches = cddb_query( p_cddb, p_access->p_sys->p_disc);
+
+    if (i_matches > 0)
+    {
+        if (i_matches > 1)
+             msg_Warn( p_access, "found %d matches in CDDB. Using first one.",
+                                 i_matches);
+        cddb_read( p_cddb, p_access->p_sys->p_disc );
+
+//        cddb_disc_print( p_access->p_sys->p_disc );
+    }
+    else
+    {
+        msg_Warn( p_access, "CDDB error: %s", cddb_error_str(errno));
+    }
+
+cddb_destroy:
+    cddb_destroy( p_cddb);
+
+cddb_end: ;
+}
+#endif /*HAVE_LIBCDDB*/