Commit 78ba4b7e authored by Rocky Bernstein's avatar Rocky Bernstein

Add CD-DA CDDB support via libcddb.

parent f54c0f61
dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.124 2003/11/30 14:28:07 fenrir Exp $
dnl $Id: configure.ac,v 1.125 2003/11/30 18:14:20 rocky Exp $
AC_INIT(vlc,0.7.0-test1)
......@@ -295,7 +295,7 @@ fi
AC_CHECK_FUNCS(connect,,[
AC_CHECK_LIB(socket,connect,[
AX_ADD_LDFLAGS([vlc ipv4],-lsocket)
AX_ADD_LDFLAGS([vlc ipv4 cddax],-lsocket)
])
])
......@@ -307,7 +307,7 @@ AC_CHECK_FUNCS(send,,[
AC_CHECK_FUNCS(gethostbyname,,[
AC_CHECK_LIB(nsl,gethostbyname,[
AX_ADD_LDFLAGS([ipv4 httpd vlc],[-lnsl])
AX_ADD_LDFLAGS([cddax ipv4 httpd vlc],[-lnsl])
],[
AC_CHECK_LIB(bind,gethostbyname,[
AX_ADD_LDFLAGS([ipv4 access_mms httpd],[-lbind])
......@@ -1474,6 +1474,56 @@ then
AX_ADD_PLUGINS([pvr])
fi
dnl
dnl VCDX and CDDAX modules
dnl
AC_ARG_ENABLE(libcdio,
[ --enable-libcdio CDDA support via libcdio (default enabled)])
AC_ARG_ENABLE(libcddb,
[ --enable-libcddb CDDB support for CDDAX (default enabled)])
AC_ARG_ENABLE(vcdx,
[ --enable-vcdx VCD support with Navigation (default enabled)])
if test "${enable_cddax}" != "no"
then
PKG_CHECK_MODULES(LIBCDIO, libcdio >= 0.65,
[enable_cddax="no"
AX_ADD_LDFLAGS([cddax],[$LIBCDIO_LIBS])
AX_ADD_CFLAGS([cddax],[$LIBCDIO_CFLAGS])
AX_ADD_PLUGINS([cddax])],
[AC_MSG_WARN(libcdio library not found)])
if test x$enable_cddb != no; then
PKG_CHECK_MODULES(LIBCDDB, libcddb >= 0.9.4, [
HAVE_LIBCDDB=yes
AC_DEFINE(HAVE_LIBCDDB, [], [Define this if you have libcddb installed])
AX_ADD_LDFLAGS([cddax],[$LIBCDDB_LIBS])
AX_ADD_CFLAGS([cddax],[$LIBCDDB_CFLAGS])
],
[AC_MSG_WARN(new enough libcddb not found. CDDB access disabled)
HAVE_LIBCDDB=no])
fi
PKG_CHECK_MODULES(LIBCDIO, libcdio >= 0.65,
[enable_cddax="no"
AX_ADD_LDFLAGS([cddax],[$LIBCDIO_LIBS])
AX_ADD_CFLAGS([cddax],[$LIBCDIO_CFLAGS])
AX_ADD_PLUGINS([cddax])],
[AC_MSG_WARN(libcdio library not found)])
if test "${enable_vcdx}" != "no"
then
PKG_CHECK_MODULES(VCDINFO, libvcdinfo >= 0.7.20-cdio,
[enable_vcd="no"
AX_ADD_LDFLAGS([vcdx],[$VCDINFO_LIBS])
AX_ADD_CFLAGS([vcdx],[$VCDINFO_CFLAGS])
AX_ADD_PLUGINS([vcdx])],
[AC_MSG_WARN(vcdinfo library not found)])
fi
fi
dnl
dnl VCD module
dnl
......@@ -1520,29 +1570,6 @@ then
fi
fi
dnl
dnl VCDX and CDX modules
dnl
AC_ARG_ENABLE(vcdx,
[ --enable-vcdx VCD support with Navigation for Linux and Win32 (default enabled)])
if test "${enable_vcdx}" != "no"
then
PKG_CHECK_MODULES(LIBCDIO, libcdio >= 0.65,
[enable_cdda="no"
AX_ADD_LDFLAGS([cddax],[$LIBCDIO_LIBS])
AX_ADD_CFLAGS([cddax],[$LIBCDIO_CFLAGS])
AX_ADD_PLUGINS([cddax])],
[AC_MSG_WARN(libcdio library not found)])
PKG_CHECK_MODULES(VCDINFO, libvcdinfo >= 0.7.20-cdio,
[enable_vcd="no"
AX_ADD_LDFLAGS([vcdx],[$VCDINFO_LIBS])
AX_ADD_CFLAGS([vcdx],[$VCDINFO_CFLAGS])
AX_ADD_PLUGINS([vcdx])],
[AC_MSG_WARN(vcdinfo library not found)])
fi
dnl
dnl Satellite input module
dnl
......
......@@ -2,7 +2,7 @@
* cddax.c : CD digital audio input module for vlc using libcdio
*****************************************************************************
* Copyright (C) 2000,2003 VideoLAN
* $Id: access.c,v 1.3 2003/11/30 02:41:00 rocky Exp $
* $Id: access.c,v 1.4 2003/11/30 18:14:20 rocky Exp $
*
* Authors: Rocky Bernstein <rocky@panix.com>
* Laurent Aimar <fenrir@via.ecp.fr>
......@@ -31,6 +31,7 @@
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include <sys/types.h>
#include <cdio/cdio.h>
#include <cdio/cd_types.h>
......@@ -50,6 +51,8 @@
#define CDDA_BLOCKS_ONCE 1
#define CDDA_DATA_ONCE (CDDA_BLOCKS_ONCE * CDIO_CD_FRAMESIZE_RAW)
#define CDDA_MRL_PREFIX "cddax://"
/* FIXME: This variable is a hack. Would be nice to eliminate. */
static input_thread_t *p_cdda_input = NULL;
......@@ -61,6 +64,10 @@ static void CDDASeek ( input_thread_t *, off_t );
static int CDDASetArea ( input_thread_t *, input_area_t * );
static int CDDASetProgram ( input_thread_t *, pgrm_descriptor_t * );
static int CDDAFixupPlayList(const input_thread_t *p_input,
cdda_data_t *p_cdda, const char *psz_source,
bool play_single_track, unsigned int i_track);
/****************************************************************************
* Private functions
****************************************************************************/
......@@ -110,6 +117,58 @@ cdio_log_handler (cdio_log_level_t level, const char message[])
}
#ifdef HAVE_LIBCDDB
/*! This routine is called by libcddb routines on error.
Setup is done by init_input_plugin.
*/
static void
cddb_log_handler (cddb_log_level_t level, const char message[])
{
cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
switch (level) {
case CDDB_LOG_DEBUG:
case CDDB_LOG_INFO:
if (!(p_cdda->i_debug & INPUT_DBG_CDDB)) return;
/* Fall through if to warn case */
default:
cdio_log_handler (level, message);
}
}
#endif /*HAVE_LIBCDDB*/
/*! This routine is when xine is not fully set up (before full initialization)
or is not around (before finalization).
*/
static void
uninit_log_handler (cdio_log_level_t level, const char message[])
{
cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
switch (level) {
case CDIO_LOG_DEBUG:
case CDIO_LOG_INFO:
if (!(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)))
return;
/* Fall through if to warn case */
case CDIO_LOG_WARN:
fprintf(stderr, "WARN: %s\n", message);
break;
case CDIO_LOG_ERROR:
fprintf(stderr, "ERROR: %s\n", message);
break;
case CDIO_LOG_ASSERT:
fprintf(stderr, "ASSERT ERROR: %s\n", message);
break;
default:
fprintf(stderr, "UNKNOWN ERROR: %s\n%s %d\n",
message,
_("The above message had unknown cdio log level"),
level);
}
/* gl_default_cdio_log_handler (level, message); */
}
/*****************************************************************************
* Open: open cdda
*****************************************************************************/
......@@ -122,8 +181,9 @@ E_(Open)( vlc_object_t *p_this )
char * psz_source;
cdda_data_t * p_cdda;
int i;
int i_title = 1;
int i_track = 1;
cddev_t *p_cddev;
bool play_single_track = false;
/* Set where to log errors messages from libcdio. */
p_cdda_input = (input_thread_t *)p_this;
......@@ -150,8 +210,9 @@ E_(Open)( vlc_object_t *p_this )
if ('T' == *psz_parser || 't' == *psz_parser )
++psz_parser;
i_title = (int)strtol( psz_parser, NULL, 10 );
i_title = i_title ? i_title : 1;
i_track = (int)strtol( psz_parser, NULL, 10 );
i_track = i_track ? i_track : 1;
play_single_track = true;
}
if( !*psz_source ) {
......@@ -178,6 +239,9 @@ E_(Open)( vlc_object_t *p_this )
/* Open CDDA */
cdio_log_set_handler ( cdio_log_handler );
#ifdef HAVE_LIBCDDB
cddb_log_set_handler ( cddb_log_handler );
#endif
if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
{
......@@ -185,7 +249,6 @@ E_(Open)( vlc_object_t *p_this )
free( psz_source );
return -1;
}
free( psz_source );
p_cdda = malloc( sizeof(cdda_data_t) );
if( p_cdda == NULL )
......@@ -215,11 +278,12 @@ E_(Open)( vlc_object_t *p_this )
{
ioctl_Close( p_cdda->p_cddev );
free( p_cdda );
free( psz_source );
return -1;
}
if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
i_title = 1;
if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
i_track = 1;
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
......@@ -248,7 +312,9 @@ E_(Open)( vlc_object_t *p_this )
}
#undef area
CDDAPlay( p_input, i_title);
CDDAFixupPlayList(p_input, p_cdda, psz_source, play_single_track, i_track);
CDDAPlay( p_input, i_track);
vlc_mutex_unlock( &p_input->stream.stream_lock );
......@@ -268,6 +334,7 @@ E_(Open)( vlc_object_t *p_this )
p_cdda->p_intf = intf_Create( p_input, "cddax" );
intf_RunThread( p_cdda->p_intf );
free( psz_source );
return 0;
}
......@@ -299,6 +366,14 @@ E_(Close)( vlc_object_t *p_this )
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
ioctl_Close( p_cdda->p_cddev );
cdio_log_set_handler (uninit_log_handler);
#ifdef HAVE_LIBCDDB
cddb_log_set_handler (uninit_log_handler);
cddb_disc_destroy(p_cdda->cddb.disc);
#endif
free( p_cdda );
p_cdda_input = NULL;
}
......@@ -441,3 +516,194 @@ static void CDDASeek( input_thread_t * p_input, off_t i_off )
p_input->stream.p_selected_area->i_tell );
}
#ifdef HAVE_LIBCDDB
static void
GetCDDBInfo( const input_thread_t *p_input, cdda_data_t *p_cdda )
{
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
if (config_GetInt( p_input, MODULE_STRING "-cddb-enabled" )) {
int i, i_matches;
cddb_conn_t *conn = cddb_new();
const CdIo *cdio = p_cdda->p_cddev->cdio;
cddb_log_set_handler (uninit_log_handler);
if (!conn) {
msg_Warn( p_input, "unable to initialize libcddb" );
goto cddb_destroy;
}
cddb_set_email_address( conn,
config_GetPsz( p_input,
MODULE_STRING "-cddb-email") );
cddb_set_server_name( conn,
config_GetPsz( p_input,
MODULE_STRING "-cddb-server") );
cddb_set_server_port(conn,
config_GetInt( p_input,
MODULE_STRING "-cddb-port") );
/* Set the location of the local CDDB cache directory.
The default location of this directory is */
if (!config_GetInt( p_input, MODULE_STRING "-cddb-enable-cache" ))
cddb_cache_disable(conn);
cddb_cache_set_dir(conn,
config_GetPsz( p_input,
MODULE_STRING "-cddb-cachedir") );
cddb_set_timeout(conn,
config_GetInt( p_input, MODULE_STRING "-cddb-timeout") );
if (config_GetInt( p_input, MODULE_STRING "-cddb-httpd" )) {
cddb_http_enable(conn);
} else
cddb_http_disable(conn);
p_cdda->cddb.disc = cddb_disc_new();
if (!p_cdda->cddb.disc) {
msg_Err( p_input, "Unable to create CDDB disc structure." );
goto cddb_end;
}
for(i = 1; i <= p_cdda->i_nb_tracks; i++) {
cddb_track_t *t = cddb_track_new();
t->frame_offset = cdio_get_track_lba(cdio, i);
cddb_disc_add_track(p_cdda->cddb.disc, t);
}
p_cdda->cddb.disc->length =
cdio_get_track_lba(cdio, CDIO_CDROM_LEADOUT_TRACK)
/ CDIO_CD_FRAMES_PER_SEC;
if (!cddb_disc_calc_discid(p_cdda->cddb.disc)) {
msg_Err( p_input, "CDDB disc calc failed" );
goto cddb_destroy;
}
i_matches = cddb_query(conn, p_cdda->cddb.disc);
if (i_matches > 0) {
if (i_matches > 1)
msg_Warn( p_input, "Found %d matches in CDDB. Using first one.",
i_matches);
cddb_read(conn, p_cdda->cddb.disc);
if (p_cdda->i_debug & INPUT_DBG_CDDB)
cddb_disc_print(p_cdda->cddb.disc);
#if FIXED
if ((_cdda_is_cd_changed(this) == 1))
#endif
/**** _cdda_cddb_set_info(this, this->cddb.disc); ***/
} else {
msg_Warn( p_input, "CDDB error: %s", cddb_error_str(errno));
}
cddb_destroy:
cddb_destroy(conn);
}
cddb_end: ;
}
#endif /*HAVE_LIBCDDB*/
static void
CDDACreatePlayListItem(const input_thread_t *p_input, cdda_data_t *p_cdda,
playlist_t *p_playlist, unsigned int i_track,
char *psz_mrl, int psz_mrl_max,
const char *psz_source, int i_cddb_enabled,
int playlist_operation, unsigned int i_pos)
{
mtime_t i_duration =
(p_cdda->p_sectors[i_track] - p_cdda->p_sectors[i_track-1])
* 1000 / CDIO_CD_FRAMES_PER_SEC;
char *p_title = psz_mrl;
snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
CDDA_MRL_PREFIX, psz_source, i_track);
if (i_cddb_enabled) {
cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i_track-1);
if (t != NULL && t->title != NULL)
p_title = t->title;
}
playlist_AddExt( p_playlist, psz_mrl, p_title, i_duration,
0, 0, playlist_operation, i_pos );
}
static int
CDDAFixupPlayList(const input_thread_t *p_input, cdda_data_t *p_cdda,
const char *psz_source, bool play_single_track,
unsigned int i_track)
{
int i;
playlist_t * p_playlist;
char * psz_mrl;
unsigned int psz_mrl_max = strlen(CDDA_MRL_PREFIX) + strlen(psz_source) +
strlen("@T") + strlen("100") + 1;
int i_cddb_enabled =
#ifdef HAVE_LIBCDDB
config_GetInt( p_input, MODULE_STRING "-cddb-enabled" );
#else
0
#endif
if (play_single_track && !i_cddb_enabled) return 0;
psz_mrl = malloc( psz_mrl_max );
if( psz_mrl == NULL )
{
msg_Warn( p_input, "out of memory" );
return -1;
}
p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( !p_playlist )
{
msg_Warn( p_input, "can't find playlist" );
free(psz_mrl);
return -1;
}
#ifdef HAVE_LIBCDDB
if (i_cddb_enabled)
GetCDDBInfo(p_input, p_cdda);
#endif
if (play_single_track) {
/* May fill out more information when the playlist user interface becomes
more mature.
*/
CDDACreatePlayListItem(p_input, p_cdda, p_playlist, i_track,
psz_mrl, psz_mrl_max,
psz_source, i_cddb_enabled,
PLAYLIST_REPLACE, p_playlist->i_index);
} else {
playlist_Delete( p_playlist, p_playlist->i_index);
for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
{
CDDACreatePlayListItem(p_input, p_cdda, p_playlist, i, psz_mrl,
psz_mrl_max, psz_source, i_cddb_enabled,
PLAYLIST_APPEND, PLAYLIST_END);
}
playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
}
vlc_object_release( p_playlist );
free(psz_mrl);
return 0;
}
......@@ -2,11 +2,11 @@
* cddax.c : CD digital audio input module for vlc using libcdio
*****************************************************************************
* Copyright (C) 2000,2003 VideoLAN
* $Id: cdda.c,v 1.2 2003/11/26 03:35:26 rocky Exp $
* $Id: cdda.c,v 1.3 2003/11/30 18:14:20 rocky Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Authors: Rocky Bernstein <rocky@panix.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
* Rocky Bernstein <rocky@panix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -53,23 +53,22 @@ int E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
* Option help text
*****************************************************************************/
#define DEBUG_TEXT N_("set debug mask for additional debugging.")
#define DEBUG_LONGTEXT N_( \
"This integer when viewed in binary is a debugging mask\n" \
"MRL 1\n" \
"events 2\n" \
"external call 4\n" \
"all calls 8\n" \
"LSN (10) 16\n" \
"libcdio (20) 32\n" \
"seeks (40) 64\n" )
#define DEV_TEXT N_("CD-ROM device name")
"meta info 1\n" \
"events 2\n" \
"MRL 4\n" \
"external call 8\n" \
"all calls (10) 16\n" \
"LSN (20) 32\n" \
"seek (40) 64\n" \
"libcdio (80) 128\n" \
"libcddb (100) 256\n" )
#define DEV_LONGTEXT N_( \
"Specify the name of the CD-ROM device that will be used by default. " \
"If you don't specify anything, we'll scan for a suitable CD-ROM device.")
#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 millisecond units." )
......@@ -79,7 +78,7 @@ int E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
*****************************************************************************/
vlc_module_begin();
add_usage_hint( N_("cddax://[device-or-file][@num]") );
add_usage_hint( N_("cddax://[device-or-file][@[T]num]") );
set_description( _("Compact Disc Digital Audio (CD-DA) input") );
set_capability( "access", 75 /* slightly higher than cdda */ );
set_callbacks( E_(Open), E_(Close) );
......@@ -89,15 +88,64 @@ vlc_module_begin();
/* Configuration options */
add_category_hint( N_("CDX"), NULL, VLC_TRUE );
add_integer ( MODULE_STRING "-debug", 0, E_(DebugCallback), DEBUG_TEXT,
add_integer ( MODULE_STRING "-debug", 0, E_(DebugCallback),
N_("set debug mask for additional debugging."),
DEBUG_LONGTEXT, VLC_TRUE );
add_integer( MODULE_STRING "-caching",
DEFAULT_PTS_DELAY / 1000, NULL,
CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
add_string( MODULE_STRING "-device", "", NULL, DEV_TEXT,
DEV_LONGTEXT, VLC_TRUE );
N_("Caching value in ms"),
CACHING_LONGTEXT, VLC_TRUE );
add_string( MODULE_STRING "-device", "", NULL,
N_("CD-ROM device name"),
DEV_LONGTEXT, VLC_FALSE );
#ifdef HAVE_LIBCDDB
add_bool( MODULE_STRING "-cddb-enabled", 1, NULL,
N_("Do CDDB lookups?"),
N_("If set, lookup CD-DA track information using the CDDB "
"protocol"),
VLC_FALSE );
add_string( MODULE_STRING "-cddb-server", "freedb.freedb.org", NULL,
N_("CDDB server"),
N_( "Contact this CDDB server look up CD-DA information"),
VLC_TRUE );
add_integer( MODULE_STRING "-cddb-port", 8880, NULL,
N_("CDDB server port"),
N_("CDDB server uses this port number to communicate on"),
VLC_TRUE );
add_string( MODULE_STRING "-cddb-email", "me@home", NULL,
N_("email address reported to CDDB server"),
N_("email address reported to CDDB server"),
VLC_TRUE );
add_bool( MODULE_STRING "-cddb-enable-cache", 1, NULL,
N_("Cache CDDB lookups?"),
N_("If set cache CDDB information about this CD"),
VLC_FALSE );
add_bool( MODULE_STRING "-cddb-httpd", 0, NULL,
N_("Contact CDDB via the HTTP protocol?"),
N_("If set, the CDDB server get information via the CDDB HTTP "
"protocol"),
VLC_TRUE );
add_integer( MODULE_STRING "-cddb-timeout", 10, NULL,
N_("CDDB server timeout"),
N_("Time (in seconds) to wait for a response from the "
"CDDB server"),
VLC_FALSE );
add_string( MODULE_STRING "-cddb-cachedir", "~/.cddbslave", NULL,
N_("Directory to cache CDDB requests"),
N_("Directory to cache CDDB requests"),
VLC_TRUE );
#endif
add_submodule();
set_description( _("CD Audio demux") );
......
......@@ -3,7 +3,7 @@
* using libcdio, libvcd and libvcdinfo
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* $Id: cdda.h,v 1.1 2003/11/26 03:35:26 rocky Exp $
* $Id: cdda.h,v 1.2 2003/11/30 18:14:20 rocky Exp $
*
* Authors: Rocky Bernstein <rocky@panix.com>
*
......@@ -24,16 +24,22 @@
#include "../vcdx/cdrom.h"
#ifdef HAVE_LIBCDDB
#include <cddb/cddb.h>
#endif
/*****************************************************************************
* Debugging
*****************************************************************************/
#define INPUT_DBG_MRL 1
#define INPUT_DBG_META 1 /* Meta information */
#define INPUT_DBG_EVENT 2 /* Trace keyboard events */
#define INPUT_DBG_EXT 4 /* Calls from external routines */
#define INPUT_DBG_CALL 8 /* all calls */
#define INPUT_DBG_LSN 16 /* LSN changes */
#define INPUT_DBG_CDIO 32 /* Debugging from CDIO */
#define INPUT_DBG_MRL 4 /* MRL debugging */
#define INPUT_DBG_EXT 8 /* Calls from external routines */
#define INPUT_DBG_CALL 16 /* all calls */
#define INPUT_DBG_LSN 32 /* LSN changes */
#define INPUT_DBG_SEEK 64 /* Seeks to set location */
#define INPUT_DBG_CDIO 128 /* Debugging from CDIO */
#define INPUT_DBG_CDDB 256 /* CDDB debugging */
#define INPUT_DEBUG 1
#if INPUT_DEBUG
......@@ -58,6 +64,30 @@ typedef struct cdda_data_s
int i_debug; /* Debugging mask */
intf_thread_t *p_intf;
#ifdef HAVE_LIBCDDB
struct {
bool have_info; /* True if we have any info */
cddb_disc_t *disc; /* libcdio uses this to get disc info */
char *cdiscid;
char *disc_title;
char disc_year[5]; /* Year. Probably 19XX or 20XX */
char *disc_artist;
char *disc_genre;
cddb_cat_t disc_category; /* CDDB category */
int disc_seconds; /* Length in seconds listed in CDDB