Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

access.c

00001 /*****************************************************************************
00002  * access.c : CD digital audio input module for vlc using libcdio
00003  *****************************************************************************
00004  * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
00005  * $Id: access.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Rocky Bernstein <[email protected]>
00008  *          Laurent Aimar <[email protected]>
00009  *          Gildas Bazin <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027  * Preamble
00028  *****************************************************************************/
00029 #include "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
00030 #include "cdda.h"          /* private structures. Also #includes vlc things */
00031 #include "info.h"          /* headers for meta info retrieval */
00032 #include <vlc_playlist.h>  /* Has to come *after* cdda.h */
00033 #include "vlc_keys.h"
00034 
00035 #include <cdio/cdio.h>
00036 #include <cdio/logging.h>
00037 #include <cdio/cd_types.h>
00038 
00039 #include <stdio.h>
00040 
00041 /* #ifdef variables below are defined via config.h via #include vlc above. */
00042 #ifdef HAVE_STDLIB_H
00043 #include <stdlib.h>
00044 #endif
00045 
00046 #ifdef HAVE_SYS_TYPES_H
00047 #include <sys/types.h>
00048 #endif
00049 
00050 #ifdef HAVE_STRING_H
00051 #include <string.h>
00052 #endif
00053 
00054 #ifdef HAVE_UNISTD_H
00055 #   include <unistd.h>
00056 #endif
00057 
00058 /* FIXME: This variable is a hack. Would be nice to eliminate. */
00059 access_t *p_cdda_input = NULL;
00060 
00061 /*****************************************************************************
00062  * Local prototypes
00063  *****************************************************************************/
00064 static int      CDDARead( access_t *, uint8_t *, int );
00065 static block_t *CDDAReadBlocks( access_t * p_access );
00066 static int      CDDASeek( access_t * p_access, int64_t i_pos );
00067 static int      CDDAControl( access_t *p_access, int i_query,
00068                              va_list args );
00069 
00070 static int      CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;
00071 
00072 
00073 /****************************************************************************
00074  * Private functions
00075  ****************************************************************************/
00076 
00077 /* process messages that originate from libcdio. 
00078    called by CDDAOpen
00079 */
00080 static void
00081 cdio_log_handler (cdio_log_level_t level, const char message[])
00082 {
00083   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
00084 
00085   if( p_cdda == NULL )
00086       return;
00087 
00088   switch (level) {
00089   case CDIO_LOG_DEBUG:
00090   case CDIO_LOG_INFO:
00091     if (p_cdda->i_debug & INPUT_DBG_CDIO)
00092       msg_Dbg( p_cdda_input, message);
00093     break;
00094   case CDIO_LOG_WARN:
00095     msg_Warn( p_cdda_input, message);
00096     break;
00097   case CDIO_LOG_ERROR:
00098   case CDIO_LOG_ASSERT:
00099     msg_Err( p_cdda_input, message);
00100     break;
00101   default:
00102     msg_Warn( p_cdda_input, message,
00103             "The above message had unknown cdio log level",
00104             level);
00105   }
00106   return;
00107 }
00108 
00109 
00110 #ifdef HAVE_LIBCDDB
00111 
00114 static void
00115 cddb_log_handler (cddb_log_level_t level, const char message[])
00116 {
00117     cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
00118     switch (level)
00119     {
00120         case CDDB_LOG_DEBUG:
00121         case CDDB_LOG_INFO:
00122         if (!(p_cdda->i_debug & INPUT_DBG_CDDB)) return;
00123 
00124         /* Fall through if to warn case */
00125         default:
00126             cdio_log_handler (level, message);
00127     }
00128 }
00129 #endif /*HAVE_LIBCDDB*/
00130 
00131 
00135 static void
00136 uninit_log_handler (cdio_log_level_t level, const char message[])
00137 {
00138     cdda_data_t *p_cdda = NULL;
00139 
00140     if (p_cdda_input)
00141         p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
00142 
00143      switch (level)
00144      {
00145         case CDIO_LOG_DEBUG:
00146         case CDIO_LOG_INFO:
00147         if (!p_cdda || !(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)))
00148             return;
00149 
00150         /* Fall through if to warn case */
00151         case CDIO_LOG_WARN:
00152             fprintf(stderr, "WARN: %s\n", message);
00153             break;
00154         case CDIO_LOG_ERROR:
00155             fprintf(stderr, "ERROR: %s\n", message);
00156             break;
00157         case CDIO_LOG_ASSERT:
00158             fprintf(stderr, "ASSERT ERROR: %s\n", message);
00159             break;
00160         default:
00161             fprintf(stderr, "UNKNOWN ERROR: %s\n%s %d\n", message,
00162                             "The above message had unknown cdio log level",
00163                             level);
00164     }
00165 
00166     /* gl_default_cdio_log_handler (level, message); */
00167 }
00168 
00169 /* Only used in audio control mode. Gets the current LSN from the 
00170    CD-ROM drive. */
00171 static int64_t
00172 get_audio_position ( access_t *p_access ) 
00173 {
00174     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
00175     lsn_t i_offset;
00176 
00177 #if LIBCDIO_VERSION_NUM >= 73
00178     if (p_cdda->b_audio_ctl) 
00179       {
00180         cdio_subchannel_t sub;
00181         CdIo_t *p_cdio = p_cdda->p_cdio;
00182         if (DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub)) {
00183           if (sub.audio_status != CDIO_MMC_READ_SUB_ST_PAUSED &&
00184               sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY) 
00185             return CDIO_INVALID_LSN;
00186           
00187           if ( ! p_cdda->b_nav_mode ) {
00188             // char *psz = cdio_msf_to_str(&sub.abs_addr);
00189             // fprintf(stderr, "+++disk mode abs msf %s", psz);
00190             // free(psz);
00191             i_offset = cdio_msf_to_lba((&sub.abs_addr));
00192             // fprintf(stderr, " frame offset %d\n", i_offset);
00193           } else {
00194             // char *psz = cdio_msf_to_str(&sub.rel_addr);
00195             // fprintf(stderr, "+++track abs msf %s", psz);
00196             // free(psz);
00197             i_offset = cdio_msf_to_lba((&sub.rel_addr));
00198             // fprintf(stderr, " frame offset %d\n", i_offset);
00199           }
00200         } else {
00201           // fprintf(stderr, "+++Error reading current pos\n");
00202           i_offset = p_cdda->i_lsn;
00203         }
00204       } else
00205         i_offset = p_cdda->i_lsn;
00206 #else 
00207     i_offset = p_cdda->i_lsn;
00208   ;
00209 #endif
00210   return i_offset;
00211 }
00212 
00213 /*****************************************************************************
00214  * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns
00215  * an allocated pointer to the data. NULL is returned if no data
00216  * read. It is also possible if we haven't read a RIFF header in which
00217  * case one that we creaded during Open/Initialization is returned.
00218  *****************************************************************************/
00219 static block_t * CDDAReadBlocks( access_t * p_access )
00220 {
00221     block_t     *p_block;
00222     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
00223     int          i_blocks = p_cdda->i_blocks_per_read;
00224 
00225     dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), 
00226               "called i_lsn: %d i_pos: %lld, size: %lld",
00227               p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size);
00228 
00229     /* Check end of file */
00230     if( p_access->info.b_eof ) return NULL;
00231 
00232     if( !p_cdda->b_header )
00233       {
00234         /* Return only the dummy RIFF header we created in Open/Init */
00235         p_block = block_New( p_access, sizeof( WAVEHEADER ) );
00236         memcpy( p_block->p_buffer, &p_cdda->waveheader, sizeof(WAVEHEADER) );
00237         p_cdda->b_header = VLC_TRUE;
00238         return p_block;
00239     }
00240 
00241     /* Check end of track */
00242     while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio, 
00243                                                    p_cdda->i_track) )
00244     {
00245         bool go_on;
00246       
00247         if( p_cdda->b_nav_mode )
00248           go_on = p_cdda->i_lsn > p_cdda->last_disc_frame;
00249         else
00250           go_on = p_cdda->i_track >= p_cdda->i_first_track+p_cdda->i_titles-1 ;
00251 
00252         if( go_on )
00253         {
00254             dbg_print( (INPUT_DBG_LSN), "EOF");
00255             p_access->info.b_eof = VLC_TRUE;
00256             return NULL;
00257         }
00258 
00259         p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META;
00260         p_access->info.i_title++;
00261         p_cdda->i_track++;
00262 
00263         if ( p_cdda-> b_nav_mode ) {
00264           char *psz_title = CDDAFormatTitle( p_access, p_cdda->i_track );
00265           input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title );
00266           free(psz_title);
00267         } else {
00268           p_access->info.i_size =
00269             p_cdda->p_title[p_access->info.i_title]->i_size;
00270           p_access->info.i_pos = 0;
00271           p_access->info.i_update |= INPUT_UPDATE_SIZE;
00272         }
00273     }
00274 
00275     /* Possibly adjust i_blocks so we don't read past the end of a track. */
00276     if( p_cdda->i_lsn + i_blocks >= 
00277         cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track+1) )
00278     {
00279       i_blocks = cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track+1 ) 
00280         - p_cdda->i_lsn;
00281     }
00282 
00283     /* Do the actual reading */
00284     p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW );
00285     if( !p_block)
00286     {
00287       msg_Err( p_access, "Cannot get a new block of size: %i",
00288                i_blocks * CDIO_CD_FRAMESIZE_RAW );
00289       return NULL;
00290     }
00291     
00292     {
00293 #if LIBCDIO_VERSION_NUM >= 72
00294       driver_return_code_t rc = DRIVER_OP_SUCCESS;
00295 
00296       if ( p_cdda->e_paranoia && p_cdda->paranoia ) 
00297         {
00298           int i;
00299           for( i = 0; i < i_blocks; i++ )
00300             {
00301               int16_t *p_readbuf = cdio_paranoia_read(p_cdda->paranoia, NULL);
00302               char *psz_err=cdio_cddap_errors(p_cdda->paranoia_cd);
00303               char *psz_mes=cdio_cddap_messages(p_cdda->paranoia_cd);
00304 
00305               if (psz_mes || psz_err)
00306                 msg_Err( p_access, "%s%s\n", psz_mes ? psz_mes: "", 
00307                         psz_err ? psz_err: "" );
00308               
00309               if (psz_err) free(psz_err);
00310               if (psz_mes) free(psz_mes);
00311               if( !p_readbuf ) {
00312                 msg_Err( p_access, "paranoia read error on frame %i\n", 
00313                          p_cdda->i_lsn+i );
00314               } else 
00315                 memcpy(p_block->p_buffer + i * CDIO_CD_FRAMESIZE_RAW, 
00316                        p_readbuf, CDIO_CD_FRAMESIZE_RAW);
00317             }
00318         }
00319       else 
00320         rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
00321                                       p_cdda->i_lsn, i_blocks);
00322 #else
00323 #define DRIVER_OP_SUCCESS 0
00324       int rc;
00325       rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
00326                                     p_cdda->i_lsn, i_blocks);
00327 #endif    
00328       if( rc != DRIVER_OP_SUCCESS )
00329         {
00330           msg_Err( p_access, "could not read %d sectors starting from %lu",
00331                    i_blocks, (long unsigned int) p_cdda->i_lsn );
00332           block_Release( p_block );
00333           
00334           /* If we had problems above, assume the problem is with
00335              the first sector of the read and set to skip it.  In
00336              the future libcdio may have cdparanoia support.
00337           */
00338           p_cdda->i_lsn++;
00339           p_access->info.i_pos += CDIO_CD_FRAMESIZE_RAW;
00340           return NULL;
00341         }
00342     }
00343 
00344     p_cdda->i_lsn        += i_blocks;
00345     p_access->info.i_pos += i_blocks * CDIO_CD_FRAMESIZE_RAW;
00346 
00347     return p_block;
00348 }
00349 
00350 /*****************************************************************************
00351  * CDDARead: Handler for audio control reads the CD-DA.
00352  *****************************************************************************/
00353 static int
00354 CDDARead( access_t * p_access, uint8_t *p_buffer, int i_len )
00355 {
00356     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
00357 
00358     dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), 
00359               "called lsn: %d pos: %lld, size: %lld",
00360               p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size);
00361 
00362     /* Check end of file */
00363     if( p_access->info.b_eof ) return 0;
00364     
00365     {
00366       lsn_t i_lsn = get_audio_position(p_access);
00367       if (CDIO_INVALID_LSN == i_lsn) {
00368         dbg_print((INPUT_DBG_LSN), "invalid lsn");
00369         memset( p_buffer, 0, i_len );
00370         return i_len;
00371       }
00372     
00373       p_cdda->i_lsn = i_lsn;
00374       p_access->info.i_pos = p_cdda->i_lsn * CDIO_CD_FRAMESIZE_RAW;
00375     }
00376     
00377     dbg_print((INPUT_DBG_LSN), "updated lsn: %d", p_cdda->i_lsn);
00378 
00379     /* Check end of track */
00380     while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio, 
00381                                                    p_cdda->i_track) )
00382     {
00383         if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 )
00384         {
00385             dbg_print( (INPUT_DBG_LSN), "EOF");
00386             p_access->info.b_eof = VLC_TRUE;
00387             return 0;
00388         }
00389 
00390         p_access->info.i_update |= INPUT_UPDATE_TITLE;
00391         p_access->info.i_title++;
00392         p_cdda->i_track++;
00393 
00394         if ( p_cdda-> b_nav_mode ) {
00395           char *psz_title = CDDAFormatTitle( p_access, p_cdda->i_track );
00396           input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title );
00397           free(psz_title);
00398         } else {
00399           p_access->info.i_size =
00400             p_cdda->p_title[p_access->info.i_title]->i_size;
00401           p_access->info.i_pos = 0;
00402           p_access->info.i_update |= INPUT_UPDATE_SIZE;
00403         }
00404     }
00405 
00406     memset( p_buffer, 0, i_len );
00407     return i_len;
00408 }
00409 
00411 static bool
00412 cdda_audio_pause(CdIo_t *p_cdio)
00413 {
00414   bool b_ok = true;
00415 #if LIBCDIO_VERSION_NUM >= 73
00416   cdio_subchannel_t sub;
00417   if (DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub)) {
00418     if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
00419       b_ok = DRIVER_OP_SUCCESS == cdio_audio_pause(p_cdio);
00420     }
00421   } else
00422     b_ok = false;
00423 #endif
00424   return b_ok;
00425 }
00426 
00427 #if LIBCDIO_VERSION_NUM >= 73
00428 
00429 static driver_return_code_t
00430 cdda_audio_play(CdIo_t *p_cdio, lsn_t start_lsn, lsn_t end_lsn)
00431 {
00432   msf_t start_msf;
00433   msf_t last_msf;
00434   cdio_lsn_to_msf(start_lsn, &start_msf);
00435   cdio_lsn_to_msf(end_lsn, &last_msf);
00436   cdda_audio_pause(p_cdio);
00437   return cdio_audio_play_msf (p_cdio, &start_msf, &last_msf);
00438 }
00439 #endif
00440 
00441 /****************************************************************************
00442  * CDDASeek - change position for subsequent reads. For example, this
00443  * can happen if the user moves a position slider bar in a GUI.
00444  ****************************************************************************/
00445 static int 
00446 CDDASeek( access_t * p_access, int64_t i_pos )
00447 {
00448     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
00449 
00450     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
00451                "lsn %lu, offset: %lld",
00452                (long unsigned int) p_cdda->i_lsn, i_pos );
00453 
00454     p_cdda->i_lsn = (i_pos / CDIO_CD_FRAMESIZE_RAW);
00455 
00456 #if LIBCDIO_VERSION_NUM >= 72
00457     if ( p_cdda->e_paranoia && p_cdda->paranoia ) 
00458       cdio_paranoia_seek(p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET);
00459 #endif
00460 
00461 #if LIBCDIO_VERSION_NUM >= 73
00462     if ( p_cdda->b_audio_ctl ) {
00463       track_t i_track = cdio_get_track(p_cdda->p_cdio, p_cdda->i_lsn);
00464       lsn_t i_last_lsn;
00465 
00466       if ( p_cdda->b_nav_mode )
00467         i_last_lsn = p_cdda->last_disc_frame;
00468       else 
00469         i_last_lsn = cdio_get_track_last_lsn(p_cdda->p_cdio, i_track);
00470 
00471       cdda_audio_play(p_cdda->p_cdio, p_cdda->i_lsn, i_last_lsn);
00472     }
00473 #endif 
00474 
00475     if ( ! p_cdda->b_nav_mode ) 
00476       p_cdda->i_lsn += cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track);
00477 
00478     /* Seeked backwards and we are doing disc mode. */
00479     if ( p_cdda->b_nav_mode && p_access->info.i_pos > i_pos ) {
00480       track_t i_track;
00481       char *psz_title;
00482       
00483       for( i_track = p_cdda->i_track; 
00484            i_track > 1 && 
00485              p_cdda->i_lsn < cdio_get_track_lsn(p_cdda->p_cdio, i_track);
00486            i_track--, p_access->info.i_title-- ) ;
00487 
00488       p_cdda->i_track = i_track;
00489       p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META ;
00490       psz_title  = CDDAFormatTitle( p_access, p_cdda->i_track );
00491       input_Control( p_cdda->p_input, INPUT_SET_NAME, 
00492                      psz_title );
00493       free(psz_title);
00494 
00495     }
00496     
00497     p_access->info.i_pos = i_pos;
00498 
00499     return VLC_SUCCESS;
00500 }
00501 
00502 /*
00503   Set up internal state so that we play a given track.
00504   If we are using audio-ctl mode we also activate CD-ROM
00505   to play.
00506  */
00507 static bool
00508 cdda_play_track( access_t *p_access, track_t i_track ) 
00509 {
00510     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
00511 
00512     dbg_print((INPUT_DBG_CALL), "called track: %d\n", i_track);
00513 
00514     if (i_track > p_cdda->i_tracks) 
00515       {
00516         msg_Err( p_access, "CD has %d tracks, and you requested track %d", 
00517                  p_cdda->i_tracks, i_track );
00518         return false;
00519       }
00520 
00521     p_cdda->i_track = i_track;
00522 
00523     /* set up the frame boundaries for this particular track */
00524     p_cdda->first_frame = p_cdda->i_lsn = 
00525     cdio_get_track_lsn(p_cdda->p_cdio, i_track);
00526 
00527     p_cdda->last_frame  = cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 1;
00528 
00529 #if LIBCDIO_VERSION_NUM >= 73
00530     if (p_cdda->b_audio_ctl) 
00531       {
00532         lsn_t i_last_lsn;
00533         if ( p_cdda->b_nav_mode )
00534           i_last_lsn = p_cdda->last_disc_frame;
00535         else 
00536           i_last_lsn = cdio_get_track_last_lsn(p_cdda->p_cdio, i_track);
00537         cdda_audio_play(p_cdda->p_cdio, p_cdda->i_lsn, i_last_lsn);
00538       }
00539 #endif
00540   
00541   return true;
00542 }
00543 
00544 /****************************************************************************
00545  * Public functions
00546  ****************************************************************************/
00547 
00548 /*****************************************************************************
00549  * Open: open cdda device or image file and initialize structures
00550  *       for subsequent operations.
00551  *****************************************************************************/
00552 int 
00553 CDDAOpen( vlc_object_t *p_this )
00554 {
00555     access_t    *p_access = (access_t*)p_this;
00556     char *      psz_source = NULL;
00557     cdda_data_t *p_cdda    = NULL;
00558     CdIo_t      *p_cdio;
00559     track_t     i_track = 1;
00560     vlc_bool_t  b_single_track = false;
00561     int         i_rc = VLC_EGENERIC;
00562 
00563     p_access->p_sys = NULL;
00564 
00565     /* Set where to log errors messages from libcdio. */
00566     p_cdda_input = p_access;
00567 
00568     /* parse the options passed in command line : */
00569 
00570     if( p_access->psz_path && *p_access->psz_path )
00571     {
00572         char *psz_parser = psz_source = strdup( p_access->psz_path );
00573 
00574         while( *psz_parser && *psz_parser != '@' )
00575         {
00576             psz_parser++;
00577         }
00578 
00579         if( *psz_parser == '@' )
00580         {
00581             /* Found options */
00582             *psz_parser = '\0';
00583             ++psz_parser;
00584 
00585             if ('T' == *psz_parser || 't' == *psz_parser )
00586             ++psz_parser;
00587 
00588             i_track = (int)strtol( psz_parser, NULL, 10 );
00589             i_track = i_track ? i_track : 1;
00590             b_single_track = true;
00591         }
00592     }
00593 
00594     if (!psz_source || !*psz_source)
00595     {
00596         /* No device/track given. Continue only when this plugin was
00597            selected */
00598         if( !p_this->b_force ) return VLC_EGENERIC;
00599 
00600         psz_source = var_CreateGetString( p_this, "cd-audio" );
00601 
00602         if( !psz_source || !*psz_source )
00603         {
00604             /* Scan for a CD-ROM drive with a CD-DA in it. */
00605             char **ppsz_drives =
00606               cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
00607 
00608             if (NULL == ppsz_drives || NULL == ppsz_drives[0] )
00609             {
00610                 msg_Err( p_access,
00611                      "libcdio couldn't find something with a CD-DA in it" );
00612                 if (ppsz_drives) cdio_free_device_list(ppsz_drives);
00613                 return VLC_EGENERIC;
00614             }
00615 
00616             psz_source = strdup(ppsz_drives[0]);
00617             cdio_free_device_list(ppsz_drives);
00618         }
00619     }
00620 
00621     cdio_log_set_handler ( cdio_log_handler );
00622 
00623     /* Open CDDA */
00624     if( !(p_cdio = cdio_open( psz_source, DRIVER_UNKNOWN )) )
00625     {
00626         msg_Warn( p_access, "could not open %s", psz_source );
00627         if (psz_source) free( psz_source );
00628         return VLC_EGENERIC;
00629     }
00630 
00631     p_cdda = calloc( 1, sizeof(cdda_data_t) );
00632     if( p_cdda == NULL )
00633     {
00634         msg_Err( p_access, "out of memory" );
00635         free( psz_source );
00636         return VLC_ENOMEM;
00637     }
00638 
00639 #ifdef HAVE_LIBCDDB
00640     cddb_log_set_handler ( cddb_log_handler );
00641     p_cdda->cddb.disc = NULL;
00642     p_cdda->b_cddb_enabled =
00643       config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
00644 #endif
00645 
00646     p_cdda->b_cdtext =
00647       config_GetInt( p_access, MODULE_STRING "-cdtext-enabled" );
00648 
00649     p_cdda->b_cdtext_prefer =
00650       config_GetInt( p_access, MODULE_STRING "-cdtext-prefer" );
00651 
00652 #if LIBCDIO_VERSION_NUM >= 73
00653     p_cdda->b_audio_ctl =
00654       config_GetInt( p_access, MODULE_STRING "-analog-output" );
00655 #endif
00656 
00657     p_cdda->psz_source = strdup(psz_source);
00658     p_cdda->b_header   = VLC_FALSE;
00659     p_cdda->p_cdio     = p_cdio;
00660     p_cdda->i_tracks   = 0;
00661     p_cdda->i_titles   = 0;
00662     p_cdda->i_debug    = config_GetInt(p_this, MODULE_STRING 
00663                                        "-debug");
00664     p_cdda->b_nav_mode = config_GetInt(p_this, MODULE_STRING 
00665                                        "-navigation-mode" );
00666     p_cdda->i_blocks_per_read
00667       = config_GetInt(p_this, MODULE_STRING "-blocks-per-read");
00668 
00669     p_cdda->last_disc_frame = 
00670       cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK);
00671 
00672     p_cdda->p_input  = vlc_object_find( p_access, VLC_OBJECT_INPUT,
00673                                         FIND_PARENT );
00674 
00675     if (0 == p_cdda->i_blocks_per_read)
00676         p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
00677 
00678     if ( p_cdda->i_blocks_per_read < MIN_BLOCKS_PER_READ
00679          || p_cdda->i_blocks_per_read > MAX_BLOCKS_PER_READ )
00680     {
00681         msg_Warn( p_cdda_input,
00682                 "Number of blocks (%d) has to be between %d and %d. "
00683                 "Using %d.",
00684                 p_cdda->i_blocks_per_read,
00685                 MIN_BLOCKS_PER_READ, MAX_BLOCKS_PER_READ,
00686                 DEFAULT_BLOCKS_PER_READ );
00687         p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
00688     }
00689 
00690     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
00691 
00692     /* Set up p_access */
00693     if (p_cdda->b_audio_ctl) 
00694       {
00695         p_access->pf_read  = CDDARead;
00696         p_access->pf_block = NULL;
00697       } else 
00698       {
00699         p_access->pf_read  = NULL;
00700         p_access->pf_block = CDDAReadBlocks;
00701       }
00702     
00703     p_access->pf_control = CDDAControl;
00704     p_access->pf_seek    = CDDASeek;
00705 
00706     {
00707       lsn_t i_last_lsn;
00708       
00709       if (p_cdda->b_nav_mode)
00710           i_last_lsn = p_cdda->last_disc_frame;
00711       else 
00712           i_last_lsn = cdio_get_track_last_lsn(p_cdio, i_track);
00713       
00714       if (CDIO_INVALID_LSN != i_last_lsn)
00715         p_access->info.i_size = i_last_lsn * (uint64_t) CDIO_CD_FRAMESIZE_RAW;
00716       else 
00717         p_access->info.i_size = 0;
00718     }
00719 
00720     p_access->info.i_update    = 0;
00721     p_access->info.b_eof       = VLC_FALSE;
00722     p_access->info.i_title     = 0;
00723     p_access->info.i_seekpoint = 0;
00724 
00725     p_access->p_sys     = (access_sys_t *) p_cdda;
00726 
00727     /* We read the Table Of Content information */
00728     i_rc = CDDAInit( p_access, p_cdda );
00729     if ( VLC_SUCCESS != i_rc ) goto error;
00730 
00731     cdda_play_track( p_access, i_track );
00732 
00733     CDDAFixupPlaylist( p_access, p_cdda, b_single_track );
00734 
00735 #if LIBCDIO_VERSION_NUM >= 72
00736     {
00737    
00738       char *psz_paranoia = config_GetPsz( p_access, 
00739                                           MODULE_STRING "-paranoia" );
00740       p_cdda->e_paranoia = paranoia_none;
00741       if( psz_paranoia && *psz_paranoia )
00742       {
00743 
00744         if( !strncmp( psz_paranoia, "full", strlen("full") )  )
00745           p_cdda->e_paranoia = paranoia_full;
00746         else if( !strncmp( psz_paranoia, "overlap", strlen("overlap") )  )
00747           p_cdda->e_paranoia = paranoia_overlap;
00748         
00749         /* Use CD Paranoia? */
00750         if ( p_cdda->e_paranoia ) {
00751           p_cdda->paranoia_cd = cdio_cddap_identify_cdio(p_cdio, 1, NULL);
00752           /* We'll set for verbose paranoia messages. */
00753           cdio_cddap_verbose_set(p_cdda->paranoia_cd, CDDA_MESSAGE_PRINTIT, 
00754                                  CDDA_MESSAGE_PRINTIT);
00755           if ( 0 != cdio_cddap_open(p_cdda->paranoia_cd) ) {
00756             msg_Warn( p_cdda_input, "Unable to get paranoia support - "
00757                       "continuing without it." );
00758             p_cdda->e_paranoia = paranoia_none;
00759           } else {
00760             p_cdda->paranoia = cdio_paranoia_init(p_cdda->paranoia_cd);
00761             cdio_paranoia_seek(p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET);
00762             
00763             /* Set reading mode for full or overlap paranoia, 
00764                but allow skipping sectors. */
00765             cdio_paranoia_modeset(p_cdda->paranoia,
00766                                   paranoia_full == p_cdda->e_paranoia ?
00767                                   PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP :
00768                                   PARANOIA_MODE_OVERLAP^PARANOIA_MODE_NEVERSKIP
00769                                   );
00770           }
00771         }
00772       }
00773     }
00774 #endif    
00775 
00776     /* Build a WAV header to put in front of the output data.
00777        This gets sent back in the Block (read) routine.
00778      */
00779     memset( &p_cdda->waveheader, 0, sizeof(WAVEHEADER) );
00780     SetWLE( &p_cdda->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
00781     SetWLE( &p_cdda->waveheader.BitsPerSample, 16);
00782     p_cdda->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
00783     p_cdda->waveheader.Length = 0;                     /* we just don't know */
00784     p_cdda->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
00785     p_cdda->waveheader.SubChunkID  = VLC_FOURCC('f', 'm', 't', ' ');
00786     SetDWLE( &p_cdda->waveheader.SubChunkLength, 16);
00787     SetWLE( &p_cdda->waveheader.Modus, 2);
00788     SetDWLE( &p_cdda->waveheader.SampleFreq, CDDA_FREQUENCY_SAMPLE);
00789     SetWLE( &p_cdda->waveheader.BytesPerSample,
00790             2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
00791     SetDWLE( &p_cdda->waveheader.BytesPerSec,
00792              2*16/8 /*BytesPerSample*/ * CDDA_FREQUENCY_SAMPLE );
00793     p_cdda->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
00794     p_cdda->waveheader.DataLength  = 0;    /* we just don't know */
00795 
00796     /* PTS delay */
00797     var_Create( p_access, MODULE_STRING "-caching",
00798                 VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00799     vlc_object_release( p_cdda->p_input );
00800     return VLC_SUCCESS;
00801 
00802  error:
00803     cdio_destroy( p_cdda->p_cdio );
00804     if( psz_source) free( psz_source );
00805     if( p_cdda ) {
00806       if ( p_cdda->p_input )
00807         vlc_object_release( p_cdda->p_input );
00808       free(p_cdda);
00809     }
00810     
00811     return i_rc;
00812 
00813 }
00814 
00815 /*****************************************************************************
00816  * CDDAClose: closes cdda and frees any resources associded with it.
00817  *****************************************************************************/
00818 void 
00819 CDDAClose (vlc_object_t *p_this )
00820 {
00821     access_t    *p_access = (access_t *) p_this;
00822     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
00823     track_t      i;
00824 
00825 #if LIBCDIO_VERSION_NUM >= 73
00826     if (p_cdda->b_audio_ctl)
00827       cdio_audio_stop(p_cdda->p_cdio);
00828 #endif
00829 
00830     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
00831 
00832     /* Remove playlist titles */
00833     for( i = 0; i < p_cdda->i_titles; i++ )
00834     {
00835         vlc_input_title_Delete( p_cdda->p_title[i] );
00836     }
00837 
00838 #ifdef HAVE_LIBCDDB
00839     cddb_log_set_handler ((cddb_log_handler_t) uninit_log_handler);
00840     if (p_cdda->b_cddb_enabled)
00841       cddb_disc_destroy(p_cdda->cddb.disc);
00842 #endif
00843 
00844     cdio_destroy( p_cdda->p_cdio );
00845     cdio_log_set_handler (uninit_log_handler);
00846 
00847 #if LIBCDIO_VERSION_NUM >= 72
00848     if (p_cdda->paranoia)
00849       cdio_paranoia_free(p_cdda->paranoia);
00850     if (p_cdda->paranoia_cd) 
00851       cdio_cddap_close_no_free_cdio(p_cdda->paranoia_cd);
00852 #endif
00853 
00854     if (p_cdda->psz_mcn)    free( p_cdda->psz_mcn );
00855     if (p_cdda->psz_source) free( p_cdda->psz_source );
00856 
00857 #if LIBCDDB_VERSION_NUM >= 1
00858     libcddb_shutdown();
00859 #endif
00860     free( p_cdda );
00861     p_cdda = NULL;
00862     p_cdda_input = NULL;
00863 }
00864 
00865 /*****************************************************************************
00866  * Control: The front-end or vlc engine calls here to ether get
00867  * information such as meta information or plugin capabilities or to
00868  * issue miscellaneous "set" requests.
00869  *****************************************************************************/
00870 static int CDDAControl( access_t *p_access, int i_query, va_list args )
00871 {
00872     cdda_data_t  *p_cdda = (cdda_data_t *) p_access->p_sys;
00873     int          *pi_int;
00874     int i;
00875 
00876     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
00877                "query %d", i_query );
00878 
00879     switch( i_query )
00880     {
00881         /* Pass back a copy of meta information that was gathered when we
00882            during the Open/Initialize call.
00883          */
00884         case ACCESS_GET_META:
00885         {
00886             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
00887             if ( p_cdda->p_meta )
00888             {
00889                 *pp_meta = vlc_meta_Duplicate( p_cdda->p_meta );
00890                 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
00891                 return VLC_SUCCESS;
00892             }
00893             else {
00894                 msg_Warn( p_access, "tried to copy NULL meta info" );
00895                 return VLC_EGENERIC;
00896             }
00897         }
00898 
00899         case ACCESS_CAN_CONTROL_PACE:
00900           {
00901             vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00902             *pb_bool = p_cdda->b_audio_ctl ? VLC_FALSE : VLC_TRUE;
00903             dbg_print( INPUT_DBG_META, "can control pace? %d", *pb_bool);
00904             return VLC_SUCCESS;
00905           }
00906             
00907         case ACCESS_CAN_FASTSEEK:
00908             dbg_print( INPUT_DBG_META, "can fast seek?");
00909             goto common;
00910         case ACCESS_CAN_SEEK:
00911             dbg_print( INPUT_DBG_META, "can seek?");
00912             goto common;
00913         case ACCESS_CAN_PAUSE:
00914             dbg_print( INPUT_DBG_META, "can pause?");
00915     common:
00916         {
00917             vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00918             *pb_bool = VLC_TRUE;
00919             return VLC_SUCCESS;
00920         }
00921 
00922         /* */
00923         case ACCESS_GET_MTU:
00924         {
00925             pi_int = (int*)va_arg( args, int * );
00926             *pi_int = p_cdda-> i_blocks_per_read * CDIO_CD_FRAMESIZE_RAW;
00927             dbg_print( INPUT_DBG_META, "Get MTU %d", *pi_int);
00928             break;
00929         }
00930 
00931         case ACCESS_GET_PTS_DELAY:
00932         {
00933             int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
00934             *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
00935               * MILLISECONDS_PER_SEC;
00936             break;
00937         }
00938 
00939         case ACCESS_GET_TITLE_INFO:
00940         {
00941             input_title_t ***ppp_title = 
00942               (input_title_t***)va_arg( args, input_title_t*** );
00943 
00944             pi_int    = (int*)va_arg( args, int* );
00945             *((int*)va_arg( args, int* )) = 1; /* Title offset */
00946 
00947             dbg_print ( INPUT_DBG_EVENT,
00948                         "GET TITLE: i_tracks %d, i_tracks %d",
00949                         p_cdda->i_tracks, p_cdda->i_tracks );
00950 
00951             CDDAMetaInfo( p_access, CDIO_INVALID_TRACK );
00952 
00953             if ( p_cdda->b_nav_mode) {
00954                 char *psz_title = 
00955                   CDDAFormatTitle( p_access, p_cdda->i_track );
00956                 input_Control( p_cdda->p_input, INPUT_SET_NAME, 
00957                                psz_title );
00958                 free(psz_title);
00959             }
00960 
00961             /* Duplicate title info */
00962             if( p_cdda->i_titles == 0 )
00963             {
00964                 *pi_int = 0; ppp_title = NULL;
00965                 return VLC_SUCCESS;
00966             }
00967             *pi_int = p_cdda->i_titles;
00968             *ppp_title = calloc(1, 
00969                                 sizeof( input_title_t **) * p_cdda->i_titles );
00970 
00971             if (!*ppp_title) return VLC_ENOMEM;
00972 
00973             for( i = 0; i < p_cdda->i_titles; i++ )
00974             {
00975               if ( p_cdda->p_title[i] ) {
00976                    (*ppp_title)[i] =
00977                      vlc_input_title_Duplicate( p_cdda->p_title[i] );
00978               }
00979             }
00980             break;
00981         }
00982 
00983         case ACCESS_SET_TITLE:
00984         {
00985             i = (int)va_arg( args, int );
00986 
00987             dbg_print( INPUT_DBG_EVENT, "set title %d", i );
00988             if( i != p_access->info.i_title )
00989             {
00990                 const track_t i_track = p_cdda->i_first_track + i;
00991                 /* Update info */
00992                 p_access->info.i_title = i;
00993                 if ( p_cdda->b_nav_mode) 
00994                 {
00995                     lsn_t i_last_lsn;
00996                     char *psz_title = CDDAFormatTitle( p_access, i_track );
00997                     input_Control( p_cdda->p_input, INPUT_SET_NAME, 
00998                                    psz_title );
00999                     free(psz_title);
01000                     p_cdda->i_track = i_track;
01001                     i_last_lsn = cdio_get_track_lsn(p_cdda->p_cdio, 
01002                                                     CDIO_CDROM_LEADOUT_TRACK);
01003                     if (CDIO_INVALID_LSN != i_last_lsn)
01004                       p_access->info.i_size = (int64_t) CDIO_CD_FRAMESIZE_RAW 
01005                         * i_last_lsn ;
01006                     p_access->info.i_pos = (int64_t)
01007                       cdio_get_track_lsn( p_cdda->p_cdio, i_track ) 
01008                       * CDIO_CD_FRAMESIZE_RAW;
01009                 } else {
01010                    p_access->info.i_size = p_cdda->p_title[i]->i_size;
01011                    p_access->info.i_pos  = 0;
01012                 }
01013                 p_access->info.i_update = 
01014                   INPUT_UPDATE_TITLE | INPUT_UPDATE_SIZE;
01015 
01016                 /* Next sector to read */
01017                 p_cdda->i_lsn = cdio_get_track_lsn(p_cdda->p_cdio, i_track);
01018             }
01019             break;
01020         }
01021 
01022         case ACCESS_SET_PAUSE_STATE:
01023           dbg_print( INPUT_DBG_META, "Pause");
01024           if (p_cdda->b_audio_ctl)
01025             cdda_audio_pause(p_cdda->p_cdio);
01026           break;
01027 
01028         case ACCESS_SET_SEEKPOINT:
01029             dbg_print( INPUT_DBG_META, "set seekpoint");
01030             return VLC_EGENERIC;
01031 
01032         case ACCESS_SET_PRIVATE_ID_STATE:
01033             dbg_print( INPUT_DBG_META, "set private id state");
01034             return VLC_EGENERIC;
01035 
01036         default:
01037             msg_Warn( p_access, "unimplemented query in control" );
01038             return VLC_EGENERIC;
01039 
01040     }
01041     return VLC_SUCCESS;
01042 }
01043 
01044 /*****************************************************************************
01045   CDDAInit:
01046 
01047  Initialize information pertaining to the CD: the number of tracks,
01048  first track number, LSNs for each track and the leadout. The leadout
01049  information is stored after the last track. The LSN array is
01050  0-origin, same as p_access->info.  Add first_track to get what track
01051  number this is on the CD. Note: libcdio uses the real track number.
01052 
01053  On input we assume p_cdda->p_cdio and p_cdda->i_track have been set.
01054 
01055  We return the VLC-type status, e.g. VLC_SUCCESS, VLC_ENOMEM, etc.
01056  *****************************************************************************/
01057 static int CDDAInit( access_t *p_access, cdda_data_t *p_cdda )
01058 {
01059     discmode_t  discmode = CDIO_DISC_MODE_NO_INFO;
01060 
01061     p_cdda->i_tracks       = cdio_get_num_tracks(p_cdda->p_cdio);
01062     p_cdda->i_first_track  = cdio_get_first_track_num(p_cdda->p_cdio);
01063 
01064     discmode = cdio_get_discmode(p_cdda->p_cdio);
01065     switch(discmode) {
01066     case CDIO_DISC_MODE_CD_DA:
01067     case CDIO_DISC_MODE_CD_MIXED:
01068         /* These are possible for CD-DA */
01069         break;
01070     default:
01071         /* These are not possible for CD-DA */
01072         msg_Err( p_access,
01073                "Disc seems not to be CD-DA. libcdio reports it is %s",
01074                discmode2str[discmode]
01075                );
01076         return VLC_EGENERIC;
01077     }
01078 
01079     /* Set reading start LSN. */
01080     p_cdda->i_lsn = cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track);
01081 
01082     return VLC_SUCCESS;
01083 }
01084 
01085 /* 
01086  * Local variables:
01087  *  mode: C
01088  *  style: gnu
01089  * End:
01090  */

Generated on Tue Dec 20 10:14:23 2005 for vlc-0.8.4a by  doxygen 1.4.2