access.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:20k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * cddax.c : CD digital audio input module for vlc using libcdio
  3.  *****************************************************************************
  4.  * Copyright (C) 2000, 2003, 2004 VideoLAN
  5.  * $Id: access.c 8952 2004-10-07 22:50:44Z rocky $
  6.  *
  7.  * Authors: Rocky Bernstein <rocky@panix.com>
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *          Gildas Bazin <gbazin@netcourrier.com>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
  29. #include "cdda.h"          /* private structures. Also #includes vlc things */
  30. #include "info.h"          /* headers for meta info retrieval */
  31. #include <vlc_playlist.h>  /* Has to come *after* cdda.h */
  32. #include "vlc_keys.h"
  33. #include <cdio/cdio.h>
  34. #include <cdio/logging.h>
  35. #include <cdio/cd_types.h>
  36. #include <stdio.h>
  37. /* #ifdef variables below are defined via config.h via #include vlc above. */
  38. #ifdef HAVE_STDLIB_H
  39. #include <stdlib.h>
  40. #endif
  41. #ifdef HAVE_SYS_TYPES_H
  42. #include <sys/types.h>
  43. #endif
  44. #ifdef HAVE_STRING_H
  45. #include <string.h>
  46. #endif
  47. #ifdef HAVE_UNISTD_H
  48. #   include <unistd.h>
  49. #endif
  50. /* FIXME: This variable is a hack. Would be nice to eliminate. */
  51. access_t *p_cdda_input = NULL;
  52. /*****************************************************************************
  53.  * Local prototypes
  54.  *****************************************************************************/
  55. static block_t *CDDAReadBlocks( access_t * p_access );
  56. static int      CDDASeek( access_t * p_access, int64_t i_pos );
  57. static int      CDDAControl( access_t *p_access, int i_query, 
  58.      va_list args );
  59. static int      CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;
  60. /****************************************************************************
  61.  * Private functions
  62.  ****************************************************************************/
  63. /* process messages that originate from libcdio. */
  64. static void
  65. cdio_log_handler (cdio_log_level_t level, const char message[])
  66. {
  67.   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
  68.   if( p_cdda == NULL )
  69.       return;
  70.   switch (level) {
  71.   case CDIO_LOG_DEBUG:
  72.   case CDIO_LOG_INFO:
  73.     if (p_cdda->i_debug & INPUT_DBG_CDIO)
  74.       msg_Dbg( p_cdda_input, message);
  75.     break;
  76.   case CDIO_LOG_WARN:
  77.     msg_Warn( p_cdda_input, message);
  78.     break;
  79.   case CDIO_LOG_ERROR:
  80.   case CDIO_LOG_ASSERT:
  81.     msg_Err( p_cdda_input, message);
  82.     break;
  83.   default:
  84.     msg_Warn( p_cdda_input, message,
  85.             "The above message had unknown cdio log level",
  86.             level);
  87.   }
  88.   return;
  89. }
  90. #ifdef HAVE_LIBCDDB
  91. /*! This routine is called by libcddb routines on error.
  92.    Setup is done by init_input_plugin.
  93. */
  94. static void
  95. cddb_log_handler (cddb_log_level_t level, const char message[])
  96. {
  97.   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
  98.   switch (level) {
  99.   case CDDB_LOG_DEBUG:
  100.   case CDDB_LOG_INFO:
  101.     if (!(p_cdda->i_debug & INPUT_DBG_CDDB)) return;
  102.     /* Fall through if to warn case */
  103.   default:
  104.     cdio_log_handler (level, message);
  105.   }
  106. }
  107. #endif /*HAVE_LIBCDDB*/
  108. /*! This routine is when xine is not fully set up (before full initialization)
  109.    or is not around (before finalization).
  110. */
  111. static void
  112. uninit_log_handler (cdio_log_level_t level, const char message[])
  113. {
  114.   cdda_data_t *p_cdda = NULL;
  115.   if (p_cdda_input)
  116.     p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
  117.   switch (level) {
  118.   case CDIO_LOG_DEBUG:
  119.   case CDIO_LOG_INFO:
  120.     if (!p_cdda || !(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)))
  121.       return;
  122.     /* Fall through if to warn case */
  123.   case CDIO_LOG_WARN:
  124.     fprintf(stderr, "WARN: %sn", message);
  125.     break;
  126.   case CDIO_LOG_ERROR:
  127.     fprintf(stderr, "ERROR: %sn", message);
  128.     break;
  129.   case CDIO_LOG_ASSERT:
  130.     fprintf(stderr, "ASSERT ERROR: %sn", message);
  131.     break;
  132.   default:
  133.     fprintf(stderr, "UNKNOWN ERROR: %sn%s %dn",
  134.             message,
  135.             "The above message had unknown cdio log level",
  136.             level);
  137.   }
  138.   /* gl_default_cdio_log_handler (level, message); */
  139. }
  140. /*****************************************************************************
  141.  * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns
  142.  * an allocated pointer to the data. NULL is returned if no data
  143.  * read. It is also possible if we haven't read a RIFF header in which
  144.  * case one that we creaded during Open/Initialization is returned.
  145.  *****************************************************************************/
  146. static block_t *
  147. CDDAReadBlocks( access_t * p_access )
  148. {
  149.     block_t     *p_block;
  150.     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
  151.     int          i_blocks = p_cdda->i_blocks_per_read;
  152.     dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), "called %d", 
  153.       p_cdda->i_lsn);
  154.     /* Check end of file */
  155.     if( p_access->info.b_eof ) return NULL;
  156.     if( !p_cdda->b_header )
  157.       {
  158.         /* Return only the dummy RIFF header we created in Open/Init */
  159.         p_block = block_New( p_access, sizeof( WAVEHEADER ) );
  160.         memcpy( p_block->p_buffer, &p_cdda->waveheader, sizeof(WAVEHEADER) );
  161.         p_cdda->b_header = VLC_TRUE;
  162.         return p_block;
  163.     }
  164.     /* Check end of track */
  165.     while( p_cdda->i_lsn >= p_cdda->lsn[p_cdda->i_track+1] )
  166.     {
  167.         if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 )
  168.         {
  169.             p_access->info.b_eof = VLC_TRUE;
  170.             return NULL;
  171.         }
  172.         p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SIZE;
  173.         p_access->info.i_title++;
  174.         p_access->info.i_size = 
  175.   p_cdda->p_title[p_access->info.i_title]->i_size;
  176.         p_access->info.i_pos = 0;
  177. p_cdda->i_track++;
  178.     }
  179.     /* Possibly adjust i_blocks so we don't read past the end of a track. */
  180.     if( p_cdda->i_lsn + i_blocks >= p_cdda->lsn[p_cdda->i_track+1] )
  181.     {
  182.         i_blocks = p_cdda->lsn[p_cdda->i_track+1 ] - p_cdda->i_lsn;
  183.     }
  184.     /* Do the actual reading */
  185.     p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW );
  186.     if( !p_block)
  187.     {
  188.       msg_Err( p_access, "Cannot get a new block of size: %i",
  189.        i_blocks * CDIO_CD_FRAMESIZE_RAW );
  190.       return NULL;
  191.     }
  192.     if( cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
  193.                                  p_cdda->i_lsn, i_blocks) != 0 )
  194.         {
  195.   msg_Err( p_access, "could not read sector %lu",
  196.    (long unsigned int) p_cdda->i_lsn );
  197.   block_Release( p_block );
  198.   /* If we had problems above, assume the problem is with
  199.      the first sector of the read and set to skip it.  In
  200.      the future libcdio may have cdparanoia support.
  201.   */
  202.   p_cdda->i_lsn++;
  203.   p_access->info.i_pos += CDIO_CD_FRAMESIZE_RAW;
  204.   return NULL;
  205.         }
  206.     
  207.     p_cdda->i_lsn        += i_blocks;
  208.     p_access->info.i_pos += p_block->i_buffer;
  209.     return p_block;
  210. }
  211. /****************************************************************************
  212.  * CDDASeek - change position for subsequent reads. For example, this
  213.  * can happen if the user moves a position slider bar in a GUI.
  214.  ****************************************************************************/
  215. static int 
  216. CDDASeek( access_t * p_access, int64_t i_pos )
  217. {
  218.     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
  219.     p_cdda->i_lsn = p_cdda->lsn[p_cdda->i_track]
  220.                   + (i_pos / CDIO_CD_FRAMESIZE_RAW);
  221.     p_access->info.i_pos = i_pos;
  222.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
  223.                "lsn %lu, offset: %lld",  
  224.        (long unsigned int) p_cdda->i_lsn, i_pos );
  225.     return VLC_SUCCESS;
  226. }
  227. /****************************************************************************
  228.  * Public functions
  229.  ****************************************************************************/
  230. /*****************************************************************************
  231.  * Open: open cdda device or image file and initialize structures 
  232.  * for subsequent operations.
  233.  *****************************************************************************/
  234. int
  235. E_(CDDAOpen)( vlc_object_t *p_this )
  236. {
  237.     access_t    *p_access = (access_t*)p_this;
  238.     char *      psz_source = NULL;
  239.     cdda_data_t *p_cdda;
  240.     CdIo        *p_cdio;
  241.     track_t     i_track = 1;
  242.     vlc_bool_t  b_single_track = false;
  243.     int         i_rc = VLC_EGENERIC;
  244.     p_access->p_sys = NULL;
  245.     /* Set where to log errors messages from libcdio. */
  246.     p_cdda_input = p_access;
  247.     /* parse the options passed in command line : */
  248.     if( p_access->psz_path && *p_access->psz_path )
  249.     {
  250.       char *psz_parser = psz_source = strdup( p_access->psz_path );
  251.       while( *psz_parser && *psz_parser != '@' )
  252. {
  253.   psz_parser++;
  254. }
  255.       
  256.       if( *psz_parser == '@' )
  257. {
  258.   /* Found options */
  259.   *psz_parser = '';
  260.   ++psz_parser;
  261.   
  262.   if ('T' == *psz_parser || 't' == *psz_parser )
  263.             ++psz_parser;
  264.   
  265.   i_track = (int)strtol( psz_parser, NULL, 10 );
  266.   i_track = i_track ? i_track : 1;
  267.   b_single_track = true;
  268. }
  269.     } 
  270.     if (!psz_source || !*psz_source)
  271.       {
  272.         /* No device/track given. Continue only when this plugin was 
  273.    selected */
  274.         if( !p_this->b_force ) return VLC_EGENERIC;
  275.         psz_source = var_CreateGetString( p_this, "cd-audio" );
  276. if( !psz_source || !*psz_source ) {
  277.         /* Scan for a CD-ROM drive with a CD-DA in it. */
  278.         char **cd_drives =
  279.           cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
  280.         if (NULL == cd_drives || NULL == cd_drives[0] ) {
  281.   msg_Err( p_access, 
  282.    "libcdio couldn't find something with a CD-DA in it" );
  283.           if (cd_drives) cdio_free_device_list(cd_drives);
  284.   return VLC_EGENERIC;
  285. }
  286.         psz_source = strdup(cd_drives[0]);
  287.         cdio_free_device_list(cd_drives);
  288.       }
  289.     }
  290.     cdio_log_set_handler ( cdio_log_handler );
  291.     /* Open CDDA */
  292.     if( !(p_cdio = cdio_open( psz_source, DRIVER_UNKNOWN )) )
  293.     {
  294.         msg_Warn( p_access, "could not open %s", psz_source );
  295. goto error2;
  296.     }
  297.     p_cdda = malloc( sizeof(cdda_data_t) );
  298.     if( p_cdda == NULL )
  299.     {
  300.         msg_Err( p_access, "out of memory" );
  301.         free( psz_source );
  302.         return VLC_ENOMEM;
  303.     }
  304.     memset( p_cdda, 0, sizeof(cdda_data_t) );
  305. #ifdef HAVE_LIBCDDB
  306.     cddb_log_set_handler ( cddb_log_handler );
  307.     p_cdda->cddb.disc = NULL;
  308.     p_cdda->b_cddb_enabled =
  309.       config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
  310. #endif
  311.     p_cdda->b_cdtext_enabled =
  312.       config_GetInt( p_access, MODULE_STRING "-cdtext-enabled" );
  313.     p_cdda->b_cdtext_prefer =
  314.       config_GetInt( p_access, MODULE_STRING "-cdtext-prefer" );
  315.     p_cdda->b_header = VLC_FALSE;
  316.     p_cdda->p_cdio   = p_cdio;
  317.     p_cdda->i_titles = 0;
  318.     p_cdda->i_track  = i_track;
  319.     p_cdda->i_debug  = config_GetInt(p_this, MODULE_STRING "-debug");
  320.     p_cdda->i_blocks_per_read
  321.                      = config_GetInt(p_this, MODULE_STRING "-blocks-per-read");
  322.     p_cdda->p_input  = vlc_object_find( p_access, VLC_OBJECT_INPUT, 
  323. FIND_PARENT );
  324.     if (0 == p_cdda->i_blocks_per_read)
  325.       p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
  326.     
  327.     if ( p_cdda->i_blocks_per_read < MIN_BLOCKS_PER_READ 
  328.  || p_cdda->i_blocks_per_read > MAX_BLOCKS_PER_READ ) {
  329.       msg_Warn( p_cdda_input, 
  330. "Number of blocks (%d) has to be between %d and %d. "
  331. "Using %d.", 
  332. p_cdda->i_blocks_per_read, 
  333. MIN_BLOCKS_PER_READ, MAX_BLOCKS_PER_READ,
  334. DEFAULT_BLOCKS_PER_READ );
  335.       p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
  336.     }
  337.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
  338.     /* Set up p_access */
  339.     p_access->pf_read    = NULL;
  340.     p_access->pf_block   = CDDAReadBlocks;
  341.     p_access->pf_control = CDDAControl;
  342.     p_access->pf_seek    = CDDASeek;
  343.     p_access->info.i_size      = 0;
  344.     p_access->info.i_update    = 0;
  345.     p_access->info.b_eof       = VLC_FALSE;
  346.     p_access->info.i_title     = 0;
  347.     p_access->info.i_seekpoint = 0;
  348.     p_access->p_sys     = (access_sys_t *) p_cdda;
  349.     /* We read the Table Of Content information */
  350.     i_rc = CDDAInit( p_access, p_cdda );
  351.     if ( VLC_SUCCESS != i_rc ) goto error;
  352.     CDDAFixupPlaylist( p_access, p_cdda, psz_source, b_single_track );
  353.     
  354.     /* Build a WAV header to put in front of the output data. 
  355.        This gets sent back in the Block (read) routine.
  356.      */
  357.     memset( &p_cdda->waveheader, 0, sizeof(WAVEHEADER) );
  358.     SetWLE( &p_cdda->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
  359.     SetWLE( &p_cdda->waveheader.BitsPerSample, 16);
  360.     p_cdda->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
  361.     p_cdda->waveheader.Length = 0;                     /* we just don't know */
  362.     p_cdda->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
  363.     p_cdda->waveheader.SubChunkID  = VLC_FOURCC('f', 'm', 't', ' ');
  364.     SetDWLE( &p_cdda->waveheader.SubChunkLength, 16);
  365.     SetWLE( &p_cdda->waveheader.Modus, 2);
  366.     SetDWLE( &p_cdda->waveheader.SampleFreq, CDDA_FREQUENCY_SAMPLE);
  367.     SetWLE( &p_cdda->waveheader.BytesPerSample,
  368.             2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
  369.     SetDWLE( &p_cdda->waveheader.BytesPerSec,
  370.      2*16/8 /*BytesPerSample*/ * CDDA_FREQUENCY_SAMPLE );
  371.     p_cdda->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
  372.     p_cdda->waveheader.DataLength  = 0;    /* we just don't know */
  373.     /* PTS delay */
  374.     var_Create( p_access, MODULE_STRING "-caching", 
  375. VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
  376.     return VLC_SUCCESS;
  377.  error:
  378.     cdio_destroy( p_cdda->p_cdio );
  379.     free( p_cdda );
  380.  error2:
  381.     free( psz_source );
  382.     return i_rc;
  383. }
  384. /*****************************************************************************
  385.  * CDDAClose: closes cdda and frees any resources associded with it.
  386.  *****************************************************************************/
  387. void
  388. E_(CDDAClose)( vlc_object_t *p_this )
  389. {
  390.     access_t    *p_access = (access_t *) p_this;
  391.     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
  392.     track_t      i;
  393.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
  394.     /* Remove playlist titles */
  395.     for( i = 0; i < p_cdda->i_titles; i++ )
  396.     {
  397.         vlc_input_title_Delete( p_cdda->p_title[i] );
  398.     }
  399.     cdio_destroy( p_cdda->p_cdio );
  400.     cdio_log_set_handler (uninit_log_handler);
  401. #ifdef HAVE_LIBCDDB
  402.     cddb_log_set_handler (uninit_log_handler);
  403.     if (p_cdda->b_cddb_enabled)
  404.       cddb_disc_destroy(p_cdda->cddb.disc);
  405. #endif
  406.     if (p_cdda->psz_mcn) free( p_cdda->psz_mcn );
  407.     free( p_cdda );
  408.     p_cdda_input = NULL;
  409. }
  410. /*****************************************************************************
  411.  * Control: The front-end or vlc engine calls here to ether get
  412.  * information such as meta information or plugin capabilities or to
  413.  * issue miscellaneous "set" requests.
  414.  *****************************************************************************/
  415. static int CDDAControl( access_t *p_access, int i_query, va_list args )
  416. {
  417.     cdda_data_t  *p_cdda = (cdda_data_t *) p_access->p_sys;
  418.     int          *pi_int;
  419.     int i;
  420.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
  421.                "query %d", i_query );
  422.     switch( i_query )
  423.     {
  424.         /* Pass back a copy of meta information that was gathered when we
  425.    during the Open/Initialize call.
  426.  */
  427.         case ACCESS_GET_META:
  428.   { 
  429.     vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
  430.     if ( p_cdda->p_meta ) {
  431.       *pp_meta = vlc_meta_Duplicate( p_cdda->p_meta );
  432.       dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
  433.     } else 
  434.       msg_Warn( p_access, "tried to copy NULL meta info" );
  435.     
  436.     return VLC_SUCCESS;
  437.   }
  438.   return VLC_EGENERIC;
  439.         case ACCESS_CAN_SEEK:
  440.         case ACCESS_CAN_FASTSEEK:
  441.         case ACCESS_CAN_PAUSE:
  442.         case ACCESS_CAN_CONTROL_PACE: 
  443.   {
  444.             vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  445.             *pb_bool = VLC_TRUE;
  446.             break;
  447.   }
  448.         /* */
  449.         case ACCESS_GET_MTU:
  450.             pi_int = (int*)va_arg( args, int * );
  451.             *pi_int = p_cdda-> i_blocks_per_read * CDIO_CD_FRAMESIZE_RAW;
  452.             break;
  453.         case ACCESS_GET_PTS_DELAY:
  454.   { 
  455.     int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
  456.             *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
  457.       * MILLISECONDS_PER_SEC;
  458.             break;
  459.   }
  460.         /* */
  461.         case ACCESS_SET_PAUSE_STATE:
  462.             break;
  463.         case ACCESS_GET_TITLE_INFO:
  464.   { input_title_t ***ppp_title;
  465.             ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
  466.             pi_int    = (int*)va_arg( args, int* );
  467.     *((int*)va_arg( args, int* )) = 1; /* Title offset */
  468.             /* Duplicate title info */
  469.     /*** printf("+++ i_tracks %d, i_titles %dn", 
  470.  p_cdda->i_tracks, p_cdda->i_titles);  ***/
  471.             *pi_int = p_cdda->i_titles;
  472.             *ppp_title = malloc(sizeof( input_title_t **) * p_cdda->i_titles );
  473.     if (!*ppp_title) return VLC_ENOMEM;
  474.             for( i = 0; i < p_cdda->i_titles; i++ )
  475.             {
  476.       if ( p_cdda->p_title[i] )
  477.                 (*ppp_title)[i] = 
  478.   vlc_input_title_Duplicate( p_cdda->p_title[i] );
  479.             }
  480.   }
  481.   break;
  482.         case ACCESS_SET_TITLE:
  483.             i = (int)va_arg( args, int );
  484.             if( i != p_access->info.i_title )
  485.             {
  486.                 /* Update info */
  487.                 p_access->info.i_update |=
  488.                     INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
  489.                 p_access->info.i_title = i;
  490.                 p_access->info.i_size = p_cdda->p_title[i]->i_size;
  491.                 p_access->info.i_pos = 0;
  492.                 /* Next sector to read */
  493.                 p_cdda->i_lsn = p_cdda->lsn[p_cdda->i_first_track+i];
  494.             }
  495.             break;
  496.         case ACCESS_SET_SEEKPOINT:
  497.         case ACCESS_SET_PRIVATE_ID_STATE:
  498.             return VLC_EGENERIC;
  499.         default:
  500.   msg_Warn( p_access, "unimplemented query in control" );
  501.             return VLC_EGENERIC;
  502.     }
  503.     return VLC_SUCCESS;
  504. }
  505. /*****************************************************************************
  506.   CDDAInit: 
  507.  Initialize information pertaining to the CD: the number of tracks,
  508.  first track number, LSNs for each track and the leadout. The leadout
  509.  information is stored after the last track. The LSN array is
  510.  0-origin, same as p_access->info.  Add first_track to get what track
  511.  number this is on the CD. Note: libcdio uses the real track number.
  512.  On input we assume p_cdda->p_cdio and p_cdda->i_track have been set.
  513.  We return the VLC-type status, e.g. VLC_SUCCESS, VLC_ENOMEM, etc.
  514.  *****************************************************************************/
  515. static int
  516. CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) 
  517. {
  518.     track_t i;
  519.     discmode_t  discmode = CDIO_DISC_MODE_NO_INFO;
  520.     p_cdda->i_tracks       = cdio_get_num_tracks(p_cdda->p_cdio);
  521.     p_cdda->i_first_track  = cdio_get_first_track_num(p_cdda->p_cdio);
  522.     discmode = cdio_get_discmode(p_cdda->p_cdio);
  523.     switch(discmode) {
  524.     case CDIO_DISC_MODE_CD_DA:
  525.     case CDIO_DISC_MODE_CD_MIXED:
  526.       /* These are possible for CD-DA */
  527.       break;
  528.     default:
  529.       /* These are not possible for CD-DA */
  530.       msg_Err( p_access, 
  531.        "Disc seems not to be CD-DA. libcdio reports it is %s",
  532.        discmode2str[discmode]
  533.        );
  534.       return VLC_EGENERIC;
  535.     }
  536.     
  537.     /* Fill the lsn array with the track/sector matches.
  538.        Note cdio_get_track_lsn when given num_tracks + 1 will return
  539.        the leadout LSN.
  540.      */
  541.     for( i = 0 ; i <= p_cdda->i_tracks ; i++ )
  542.       {
  543. track_t i_track = p_cdda->i_first_track + i;
  544.         (p_cdda->lsn)[ i_track ] = cdio_get_track_lsn(p_cdda->p_cdio, i_track);
  545.       }
  546.     /* Set reading start LSN. */
  547.     p_cdda->i_lsn = p_cdda->lsn[p_cdda->i_track];
  548.     return VLC_SUCCESS;
  549. }