X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fcdda%2Faccess.c;h=cba080a543ec20c32e31b7e23e27f60176cb2ed4;hb=2cb472dba008f7d877ffe6bae9c5575253365282;hp=b7c986f0b430008c84892541fbd335000dc97180;hpb=eb5ef13cf111f583c5b789c30b7636b66503b99d;p=vlc diff --git a/modules/access/cdda/access.c b/modules/access/cdda/access.c index b7c986f0b4..cba080a543 100644 --- a/modules/access/cdda/access.c +++ b/modules/access/cdda/access.c @@ -1,7 +1,7 @@ /***************************************************************************** * access.c : CD digital audio input module for vlc using libcdio ***************************************************************************** - * Copyright (C) 2000, 2003, 2004, 2005 VideoLAN + * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team * $Id$ * * Authors: Rocky Bernstein @@ -20,7 +20,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -61,6 +61,7 @@ access_t *p_cdda_input = NULL; /***************************************************************************** * Local prototypes *****************************************************************************/ +static int CDDARead( access_t *, uint8_t *, int ); static block_t *CDDAReadBlocks( access_t * p_access ); static int CDDASeek( access_t * p_access, int64_t i_pos ); static int CDDAControl( access_t *p_access, int i_query, @@ -73,7 +74,9 @@ static int CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ; * Private functions ****************************************************************************/ -/* process messages that originate from libcdio. */ +/* process messages that originate from libcdio. + called by CDDAOpen +*/ static void cdio_log_handler (cdio_log_level_t level, const char message[]) { @@ -106,7 +109,7 @@ 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. + called by CDDAOpen */ static void cddb_log_handler (cddb_log_level_t level, const char message[]) @@ -126,8 +129,8 @@ cddb_log_handler (cddb_log_level_t level, const char message[]) #endif /*HAVE_LIBCDDB*/ -/*! This routine is when xine is not fully set up (before full initialization) - or is not around (before finalization). +/*! This routine is when vlc 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[]) @@ -163,6 +166,50 @@ uninit_log_handler (cdio_log_level_t level, const char message[]) /* gl_default_cdio_log_handler (level, message); */ } +/* Only used in audio control mode. Gets the current LSN from the + CD-ROM drive. */ +static int64_t +get_audio_position ( access_t *p_access ) +{ + cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; + lsn_t i_offset; + +#if LIBCDIO_VERSION_NUM >= 73 + if (p_cdda->b_audio_ctl) + { + cdio_subchannel_t sub; + CdIo_t *p_cdio = p_cdda->p_cdio; + if (DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub)) { + if (sub.audio_status != CDIO_MMC_READ_SUB_ST_PAUSED && + sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY) + return CDIO_INVALID_LSN; + + if ( ! p_cdda->b_nav_mode ) { + // char *psz = cdio_msf_to_str(&sub.abs_addr); + // fprintf(stderr, "+++disk mode abs msf %s", psz); + // free(psz); + i_offset = cdio_msf_to_lba((&sub.abs_addr)); + // fprintf(stderr, " frame offset %d\n", i_offset); + } else { + // char *psz = cdio_msf_to_str(&sub.rel_addr); + // fprintf(stderr, "+++track abs msf %s", psz); + // free(psz); + i_offset = cdio_msf_to_lba((&sub.rel_addr)); + // fprintf(stderr, " frame offset %d\n", i_offset); + } + } else { + // fprintf(stderr, "+++Error reading current pos\n"); + i_offset = p_cdda->i_lsn; + } + } else + i_offset = p_cdda->i_lsn; +#else + i_offset = p_cdda->i_lsn; + ; +#endif + return i_offset; +} + /***************************************************************************** * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns * an allocated pointer to the data. NULL is returned if no data @@ -176,7 +223,7 @@ static block_t * CDDAReadBlocks( access_t * p_access ) int i_blocks = p_cdda->i_blocks_per_read; dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), - "called %d pos: %lld, size: %lld", + "called i_lsn: %d i_pos: %lld, size: %lld", p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size); /* Check end of file */ @@ -195,13 +242,21 @@ static block_t * CDDAReadBlocks( access_t * p_access ) while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio, p_cdda->i_track) ) { - if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 ) + bool go_on; + + if( p_cdda->b_nav_mode ) + go_on = p_cdda->i_lsn > p_cdda->last_disc_frame; + else + go_on = p_cdda->i_track >= p_cdda->i_first_track+p_cdda->i_titles-1 ; + + if( go_on ) { + dbg_print( (INPUT_DBG_LSN), "EOF"); p_access->info.b_eof = VLC_TRUE; return NULL; } - p_access->info.i_update |= INPUT_UPDATE_TITLE; + p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META; p_access->info.i_title++; p_cdda->i_track++; @@ -292,14 +347,110 @@ static block_t * CDDAReadBlocks( access_t * p_access ) return p_block; } +/***************************************************************************** + * CDDARead: Handler for audio control reads the CD-DA. + *****************************************************************************/ +static int +CDDARead( access_t * p_access, uint8_t *p_buffer, int i_len ) +{ + cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; + + dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), + "called lsn: %d pos: %lld, size: %lld", + p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size); + + /* Check end of file */ + if( p_access->info.b_eof ) return 0; + + { + lsn_t i_lsn = get_audio_position(p_access); + if (CDIO_INVALID_LSN == i_lsn) { + dbg_print((INPUT_DBG_LSN), "invalid lsn"); + memset( p_buffer, 0, i_len ); + return i_len; + } + + p_cdda->i_lsn = i_lsn; + p_access->info.i_pos = p_cdda->i_lsn * CDIO_CD_FRAMESIZE_RAW; + } + + dbg_print((INPUT_DBG_LSN), "updated lsn: %d", p_cdda->i_lsn); + + /* Check end of track */ + while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio, + p_cdda->i_track) ) + { + if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 ) + { + dbg_print( (INPUT_DBG_LSN), "EOF"); + p_access->info.b_eof = VLC_TRUE; + return 0; + } + + p_access->info.i_update |= INPUT_UPDATE_TITLE; + p_access->info.i_title++; + p_cdda->i_track++; + + if ( p_cdda-> b_nav_mode ) { + char *psz_title = CDDAFormatTitle( p_access, p_cdda->i_track ); + input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title ); + free(psz_title); + } else { + p_access->info.i_size = + p_cdda->p_title[p_access->info.i_title]->i_size; + p_access->info.i_pos = 0; + p_access->info.i_update |= INPUT_UPDATE_SIZE; + } + } + + memset( p_buffer, 0, i_len ); + return i_len; +} + +/*! Pause CD playing via audio control */ +static bool +cdda_audio_pause(CdIo_t *p_cdio) +{ + bool b_ok = true; +#if LIBCDIO_VERSION_NUM >= 73 + cdio_subchannel_t sub; + if (DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub)) { + if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) { + b_ok = DRIVER_OP_SUCCESS == cdio_audio_pause(p_cdio); + } + } else + b_ok = false; +#endif + return b_ok; +} + +#if LIBCDIO_VERSION_NUM >= 73 +/*! play CD using audio controls */ +static driver_return_code_t +cdda_audio_play(CdIo_t *p_cdio, lsn_t start_lsn, lsn_t end_lsn) +{ + msf_t start_msf; + msf_t last_msf; + cdio_lsn_to_msf(start_lsn, &start_msf); + cdio_lsn_to_msf(end_lsn, &last_msf); + cdda_audio_pause(p_cdio); + return cdio_audio_play_msf (p_cdio, &start_msf, &last_msf); +} +#endif + /**************************************************************************** * CDDASeek - change position for subsequent reads. For example, this * can happen if the user moves a position slider bar in a GUI. ****************************************************************************/ -static int CDDASeek( access_t * p_access, int64_t i_pos ) +static int +CDDASeek( access_t * p_access, int64_t i_pos ) { cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK), + "lsn %lu, offset: %lld", + (long unsigned int) p_cdda->i_lsn, i_pos ); + p_cdda->i_lsn = (i_pos / CDIO_CD_FRAMESIZE_RAW); #if LIBCDIO_VERSION_NUM >= 72 @@ -307,6 +458,20 @@ static int CDDASeek( access_t * p_access, int64_t i_pos ) cdio_paranoia_seek(p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET); #endif +#if LIBCDIO_VERSION_NUM >= 73 + if ( p_cdda->b_audio_ctl ) { + track_t i_track = cdio_get_track(p_cdda->p_cdio, p_cdda->i_lsn); + lsn_t i_last_lsn; + + if ( p_cdda->b_nav_mode ) + i_last_lsn = p_cdda->last_disc_frame; + else + i_last_lsn = cdio_get_track_last_lsn(p_cdda->p_cdio, i_track); + + cdda_audio_play(p_cdda->p_cdio, p_cdda->i_lsn, i_last_lsn); + } +#endif + if ( ! p_cdda->b_nav_mode ) p_cdda->i_lsn += cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track); @@ -321,7 +486,7 @@ static int CDDASeek( access_t * p_access, int64_t i_pos ) i_track--, p_access->info.i_title-- ) ; p_cdda->i_track = i_track; - p_access->info.i_update |= INPUT_UPDATE_TITLE; + p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META ; psz_title = CDDAFormatTitle( p_access, p_cdda->i_track ); input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title ); @@ -331,12 +496,51 @@ static int CDDASeek( access_t * p_access, int64_t i_pos ) p_access->info.i_pos = i_pos; - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK), - "lsn %lu, offset: %lld", - (long unsigned int) p_cdda->i_lsn, i_pos ); return VLC_SUCCESS; } +/* + Set up internal state so that we play a given track. + If we are using audio-ctl mode we also activate CD-ROM + to play. + */ +static bool +cdda_play_track( access_t *p_access, track_t i_track ) +{ + cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; + + dbg_print((INPUT_DBG_CALL), "called track: %d\n", i_track); + + if (i_track > p_cdda->i_tracks) + { + msg_Err( p_access, "CD has %d tracks, and you requested track %d", + p_cdda->i_tracks, i_track ); + return false; + } + + p_cdda->i_track = i_track; + + /* set up the frame boundaries for this particular track */ + p_cdda->first_frame = p_cdda->i_lsn = + cdio_get_track_lsn(p_cdda->p_cdio, i_track); + + p_cdda->last_frame = cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 1; + +#if LIBCDIO_VERSION_NUM >= 73 + if (p_cdda->b_audio_ctl) + { + lsn_t i_last_lsn; + if ( p_cdda->b_nav_mode ) + i_last_lsn = p_cdda->last_disc_frame; + else + i_last_lsn = cdio_get_track_last_lsn(p_cdda->p_cdio, i_track); + cdda_audio_play(p_cdda->p_cdio, p_cdda->i_lsn, i_last_lsn); + } +#endif + + return true; +} + /**************************************************************************** * Public functions ****************************************************************************/ @@ -398,19 +602,19 @@ CDDAOpen( vlc_object_t *p_this ) if( !psz_source || !*psz_source ) { /* Scan for a CD-ROM drive with a CD-DA in it. */ - char **cd_drives = + char **ppsz_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false); - if (NULL == cd_drives || NULL == cd_drives[0] ) + if (NULL == ppsz_drives || NULL == ppsz_drives[0] ) { msg_Err( p_access, "libcdio couldn't find something with a CD-DA in it" ); - if (cd_drives) cdio_free_device_list(cd_drives); + if (ppsz_drives) cdio_free_device_list(ppsz_drives); return VLC_EGENERIC; } - psz_source = strdup(cd_drives[0]); - cdio_free_device_list(cd_drives); + psz_source = strdup(ppsz_drives[0]); + cdio_free_device_list(ppsz_drives); } } @@ -445,12 +649,16 @@ CDDAOpen( vlc_object_t *p_this ) p_cdda->b_cdtext_prefer = config_GetInt( p_access, MODULE_STRING "-cdtext-prefer" ); +#if LIBCDIO_VERSION_NUM >= 73 + p_cdda->b_audio_ctl = + config_GetInt( p_access, MODULE_STRING "-analog-output" ); +#endif + p_cdda->psz_source = strdup(psz_source); p_cdda->b_header = VLC_FALSE; p_cdda->p_cdio = p_cdio; p_cdda->i_tracks = 0; p_cdda->i_titles = 0; - p_cdda->i_track = i_track; p_cdda->i_debug = config_GetInt(p_this, MODULE_STRING "-debug"); p_cdda->b_nav_mode = config_GetInt(p_this, MODULE_STRING @@ -458,6 +666,9 @@ CDDAOpen( vlc_object_t *p_this ) p_cdda->i_blocks_per_read = config_GetInt(p_this, MODULE_STRING "-blocks-per-read"); + p_cdda->last_disc_frame = + cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); + p_cdda->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT, FIND_PARENT ); @@ -479,8 +690,16 @@ CDDAOpen( vlc_object_t *p_this ) dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source ); /* Set up p_access */ - p_access->pf_read = NULL; - p_access->pf_block = CDDAReadBlocks; + if (p_cdda->b_audio_ctl) + { + p_access->pf_read = CDDARead; + p_access->pf_block = NULL; + } else + { + p_access->pf_read = NULL; + p_access->pf_block = CDDAReadBlocks; + } + p_access->pf_control = CDDAControl; p_access->pf_seek = CDDASeek; @@ -488,7 +707,7 @@ CDDAOpen( vlc_object_t *p_this ) lsn_t i_last_lsn; if (p_cdda->b_nav_mode) - i_last_lsn = cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); + i_last_lsn = p_cdda->last_disc_frame; else i_last_lsn = cdio_get_track_last_lsn(p_cdio, i_track); @@ -509,6 +728,8 @@ CDDAOpen( vlc_object_t *p_this ) i_rc = CDDAInit( p_access, p_cdda ); if ( VLC_SUCCESS != i_rc ) goto error; + cdda_play_track( p_access, i_track ); + CDDAFixupPlaylist( p_access, p_cdda, b_single_track ); #if LIBCDIO_VERSION_NUM >= 72 @@ -601,6 +822,11 @@ CDDAClose (vlc_object_t *p_this ) cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; track_t i; +#if LIBCDIO_VERSION_NUM >= 73 + if (p_cdda->b_audio_ctl) + cdio_audio_stop(p_cdda->p_cdio); +#endif + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" ); /* Remove playlist titles */ @@ -671,13 +897,24 @@ static int CDDAControl( access_t *p_access, int i_query, va_list args ) } case ACCESS_CAN_CONTROL_PACE: + { + vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); + *pb_bool = p_cdda->b_audio_ctl ? VLC_FALSE : VLC_TRUE; + dbg_print( INPUT_DBG_META, "can control pace? %d", *pb_bool); + return VLC_SUCCESS; + } + case ACCESS_CAN_FASTSEEK: + dbg_print( INPUT_DBG_META, "can fast seek?"); + goto common; case ACCESS_CAN_SEEK: + dbg_print( INPUT_DBG_META, "can seek?"); + goto common; case ACCESS_CAN_PAUSE: + dbg_print( INPUT_DBG_META, "can pause?"); + common: { vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* ); - dbg_print( INPUT_DBG_META, - "can seek/fastseek/pause/control pace"); *pb_bool = VLC_TRUE; return VLC_SUCCESS; } @@ -699,11 +936,6 @@ static int CDDAControl( access_t *p_access, int i_query, va_list args ) break; } - /* */ - case ACCESS_SET_PAUSE_STATE: - dbg_print( INPUT_DBG_META, "Set pause state"); - break; - case ACCESS_GET_TITLE_INFO: { input_title_t ***ppp_title = @@ -755,42 +987,50 @@ static int CDDAControl( access_t *p_access, int i_query, va_list args ) dbg_print( INPUT_DBG_EVENT, "set title %d", i ); if( i != p_access->info.i_title ) { + const track_t i_track = p_cdda->i_first_track + i; /* Update info */ p_access->info.i_title = i; if ( p_cdda->b_nav_mode) { lsn_t i_last_lsn; - char *psz_title = - CDDAFormatTitle( p_access, i+1 ); + char *psz_title = CDDAFormatTitle( p_access, i_track ); input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title ); free(psz_title); - p_cdda->i_track = p_cdda->i_first_track+i; + p_cdda->i_track = i_track; i_last_lsn = cdio_get_track_lsn(p_cdda->p_cdio, CDIO_CDROM_LEADOUT_TRACK); if (CDIO_INVALID_LSN != i_last_lsn) p_access->info.i_size = (int64_t) CDIO_CD_FRAMESIZE_RAW * i_last_lsn ; p_access->info.i_pos = (int64_t) - cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track ) + cdio_get_track_lsn( p_cdda->p_cdio, i_track ) * CDIO_CD_FRAMESIZE_RAW; } else { p_access->info.i_size = p_cdda->p_title[i]->i_size; - p_access->info.i_pos = 0; + p_access->info.i_pos = 0; } p_access->info.i_update = INPUT_UPDATE_TITLE | INPUT_UPDATE_SIZE; /* Next sector to read */ - p_cdda->i_lsn = - cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_first_track+i); + p_cdda->i_lsn = cdio_get_track_lsn(p_cdda->p_cdio, i_track); } break; } + case ACCESS_SET_PAUSE_STATE: + dbg_print( INPUT_DBG_META, "Pause"); + if (p_cdda->b_audio_ctl) + cdda_audio_pause(p_cdda->p_cdio); + break; + case ACCESS_SET_SEEKPOINT: + dbg_print( INPUT_DBG_META, "set seekpoint"); + return VLC_EGENERIC; + case ACCESS_SET_PRIVATE_ID_STATE: - dbg_print( INPUT_DBG_META, "set seekpoint/set private id state"); + dbg_print( INPUT_DBG_META, "set private id state"); return VLC_EGENERIC; default: