access.c 36.1 KB
Newer Older
1
/*****************************************************************************
Rocky Bernstein's avatar
Rocky Bernstein committed
2
 * access.c : CD digital audio input module for vlc using libcdio
3
 *****************************************************************************
4
 * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
5
 * $Id$
6
 *
7
 * Authors: Rocky Bernstein <rocky@panix.com>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *          Laurent Aimar <fenrir@via.ecp.fr>
 *          Gildas Bazin <gbazin@netcourrier.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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29 30
#include "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
#include "cdda.h"          /* private structures. Also #includes vlc things */
31
#include "info.h"          /* headers for meta info retrieval */
32
#include "access.h"
33 34
#include <vlc_playlist.h>  /* Has to come *after* cdda.h */
#include "vlc_keys.h"
Clément Stenac's avatar
Round 2  
Clément Stenac committed
35
#include <vlc_interface.h>
36

37
#include <cdio/cdio.h>
38
#include <cdio/logging.h>
39 40
#include <cdio/cd_types.h>

41 42 43 44 45 46 47 48 49 50 51 52
#include <stdio.h>

/* #ifdef variables below are defined via config.h via #include vlc above. */
#ifdef HAVE_STDLIB_H
#endif

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_STRING_H
#endif
53 54 55 56 57 58

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

/* FIXME: This variable is a hack. Would be nice to eliminate. */
59
access_t *p_cdda_input = NULL;
60 61 62 63

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
64
static int      CDDARead( access_t *, uint8_t *, int );
65
static block_t *CDDAReadBlocks( access_t * p_access );
66
static int      CDDASeek( access_t * p_access, int64_t i_pos );
Clément Stenac's avatar
Clément Stenac committed
67 68
static int      CDDAControl( access_t *p_access, int i_query,
                             va_list args );
69

70
static int      CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;
71

72

73 74 75 76
/****************************************************************************
 * Private functions
 ****************************************************************************/

77 78 79
/* process messages that originate from libcdio. 
   called by CDDAOpen
*/
80
static void
Jean-Paul Saman's avatar
Jean-Paul Saman committed
81
cdio_log_handler( cdio_log_level_t level, const char message[] )
82
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
83
    cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
84

Jean-Paul Saman's avatar
Jean-Paul Saman committed
85 86 87 88 89 90 91 92
    if( p_cdda == NULL )
        return;

    switch( level )
    {
        case CDIO_LOG_DEBUG:
        case CDIO_LOG_INFO:
            if (p_cdda->i_debug & INPUT_DBG_CDIO)
93
            msg_Dbg( p_cdda_input, "%s", message);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
94 95
            break;
        case CDIO_LOG_WARN:
96
            msg_Warn( p_cdda_input, "%s", message);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
97 98 99
            break;
        case CDIO_LOG_ERROR:
        case CDIO_LOG_ASSERT:
100
            msg_Err( p_cdda_input, "%s", message);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
101 102
            break;
        default:
103
            msg_Warn( p_cdda_input, "%s\n%s %d", message,
Jean-Paul Saman's avatar
Jean-Paul Saman committed
104 105 106 107 108
                    "the above message had unknown cdio log level",
                    level);
            break;
    }
}
109

110
#ifdef HAVE_LIBCDDB
111
/*! This routine is called by libcddb routines on error.
112
   called by CDDAOpen
113
*/
114
static void
Jean-Paul Saman's avatar
Jean-Paul Saman committed
115
cddb_log_handler( cddb_log_level_t level, const char message[] )
116
{
Clément Stenac's avatar
Clément Stenac committed
117
    cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
118
    switch( level )
Clément Stenac's avatar
Clément Stenac committed
119 120 121
    {
        case CDDB_LOG_DEBUG:
        case CDDB_LOG_INFO:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
122 123
            if( !(p_cdda->i_debug & INPUT_DBG_CDDB) )
                return;
Clément Stenac's avatar
Clément Stenac committed
124 125
        /* Fall through if to warn case */
        default:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
126 127
            cdio_log_handler( level, message );
            break;
Clément Stenac's avatar
Clément Stenac committed
128
    }
129 130 131 132
}
#endif /*HAVE_LIBCDDB*/


133 134
/*! This routine is when vlc is not fully set up (before full initialization)
  or is not around (before finalization).
135
*/
136
static void
Jean-Paul Saman's avatar
Jean-Paul Saman committed
137
uninit_log_handler( cdio_log_level_t level, const char message[] )
138
{
Clément Stenac's avatar
Clément Stenac committed
139
    cdda_data_t *p_cdda = NULL;
140

Jean-Paul Saman's avatar
Jean-Paul Saman committed
141
    if( p_cdda_input )
Clément Stenac's avatar
Clément Stenac committed
142
        p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
143

Jean-Paul Saman's avatar
Jean-Paul Saman committed
144
     switch( level )
Clément Stenac's avatar
Clément Stenac committed
145 146 147
     {
        case CDIO_LOG_DEBUG:
        case CDIO_LOG_INFO:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
148 149
            if( !p_cdda || !(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)) )
                return;
Clément Stenac's avatar
Clément Stenac committed
150 151
        /* Fall through if to warn case */
        case CDIO_LOG_WARN:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
152
            fprintf( stderr, "WARN: %s\n", message );
Clément Stenac's avatar
Clément Stenac committed
153 154
            break;
        case CDIO_LOG_ERROR:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
155
            fprintf( stderr, "ERROR: %s\n", message );
Clément Stenac's avatar
Clément Stenac committed
156 157
            break;
        case CDIO_LOG_ASSERT:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
158
            fprintf( stderr, "ASSERT ERROR: %s\n", message );
Clément Stenac's avatar
Clément Stenac committed
159 160
            break;
        default:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
161
            fprintf( stderr, "UNKNOWN ERROR: %s\n%s %d\n", message,
Clément Stenac's avatar
Clément Stenac committed
162
                            "The above message had unknown cdio log level",
Jean-Paul Saman's avatar
Jean-Paul Saman committed
163 164
                            level );
        break;
Clément Stenac's avatar
Clément Stenac committed
165 166
    }
    /* gl_default_cdio_log_handler (level, message); */
167 168
}

169 170
/* Only used in audio control mode. Gets the current LSN from the 
   CD-ROM drive. */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
171
static int64_t get_audio_position ( access_t *p_access )
172 173 174 175 176
{
    cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
    lsn_t i_offset;

#if LIBCDIO_VERSION_NUM >= 73
Jean-Paul Saman's avatar
Jean-Paul Saman committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    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 )
            {
                i_offset = cdio_msf_to_lba( (&sub.abs_addr) );
            }
            else
            {
                i_offset = cdio_msf_to_lba( (&sub.rel_addr) );
            }
        }
        else
        {
            i_offset = p_cdda->i_lsn;
        }
    }
    else
    {
        i_offset = p_cdda->i_lsn;
205
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
206 207
#else
        i_offset = p_cdda->i_lsn;
208
#endif
Jean-Paul Saman's avatar
Jean-Paul Saman committed
209
    return i_offset;
210 211
}

212
/*****************************************************************************
213 214 215 216
 * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns
 * an allocated pointer to the data. NULL is returned if no data
 * read. It is also possible if we haven't read a RIFF header in which
 * case one that we creaded during Open/Initialization is returned.
217
 *****************************************************************************/
Clément Stenac's avatar
Clément Stenac committed
218
static block_t * CDDAReadBlocks( access_t * p_access )
219
{
220 221
    block_t     *p_block;
    cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
222
    int          i_blocks = p_cdda->i_blocks_per_read;
223

Jean-Paul Saman's avatar
Jean-Paul Saman committed
224 225 226
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), 
                "called i_lsn: %d i_pos: %lld, size: %lld",
                p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size );
227

228
    /* Check end of file */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
229 230
    if( p_access->info.b_eof )
        return NULL;
231

232 233 234 235 236 237 238
    if( !p_cdda->b_header )
      {
        /* Return only the dummy RIFF header we created in Open/Init */
        p_block = block_New( p_access, sizeof( WAVEHEADER ) );
        memcpy( p_block->p_buffer, &p_cdda->waveheader, sizeof(WAVEHEADER) );
        p_cdda->b_header = VLC_TRUE;
        return p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
239
    }
240

241
    /* Check end of track */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
242 243
    while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio,
           p_cdda->i_track) )
244
    {
245
        bool go_on;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
246 247 248 249 250

        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 ;
251 252

        if( go_on )
253
        {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
254 255
            dbg_print( (INPUT_DBG_LSN), "EOF");
                        p_access->info.b_eof = VLC_TRUE;
256
            return NULL;
257 258
        }

259
        p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META;
260
        p_access->info.i_title++;
Clément Stenac's avatar
Clément Stenac committed
261
        p_cdda->i_track++;
262

Jean-Paul Saman's avatar
Jean-Paul Saman committed
263 264 265 266 267 268 269 270 271 272 273 274 275
        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;
        }
276 277
    }

278
    /* Possibly adjust i_blocks so we don't read past the end of a track. */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
279 280
    if( p_cdda->i_lsn + i_blocks >=
        cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track+1) )
281
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
282 283
        i_blocks = cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track+1 )
                    - p_cdda->i_lsn;
284 285
    }

286 287 288
    /* Do the actual reading */
    p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW );
    if( !p_block)
289
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
290 291
        msg_Err( p_access, "cannot get a new block of size: %i",
                i_blocks * CDIO_CD_FRAMESIZE_RAW );
292 293 294
        intf_UserFatal( p_access, VLC_FALSE, _("CD reading failed"), 
                        _("VLC could not get a new block of size: %i."), 
                        i_blocks * CDIO_CD_FRAMESIZE_RAW );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
295
        return NULL;
296
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
297

Clément Stenac's avatar
Clément Stenac committed
298
    {
299
#if LIBCDIO_VERSION_NUM >= 72
Jean-Paul Saman's avatar
Jean-Paul Saman committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
        driver_return_code_t rc = DRIVER_OP_SUCCESS;

        if( p_cdda->e_paranoia && p_cdda->paranoia )
        {
            int i;
            for( i = 0; i < i_blocks; i++ )
            {
                int16_t *p_readbuf = cdio_paranoia_read( p_cdda->paranoia, NULL );
                char *psz_err = cdio_cddap_errors( p_cdda->paranoia_cd );
                char *psz_mes = cdio_cddap_messages( p_cdda->paranoia_cd );

                if( psz_mes || psz_err )
                    msg_Err( p_access, "%s%s\n", psz_mes ? psz_mes: "",
                             psz_err ? psz_err: "" );

                if( psz_err ) free( psz_err );
                if( psz_mes ) free( psz_mes );
                if( !p_readbuf )
                {
                    msg_Err( p_access, "paranoia read error on frame %i\n",
                    p_cdda->i_lsn+i );
                }
                else
                    memcpy( p_block->p_buffer + i * CDIO_CD_FRAMESIZE_RAW,
                            p_readbuf, CDIO_CD_FRAMESIZE_RAW );
            }
        }
        else
        {
            rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
                                          p_cdda->i_lsn, i_blocks );
331 332
#else
#define DRIVER_OP_SUCCESS 0
Jean-Paul Saman's avatar
Jean-Paul Saman committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
            int rc;
            rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer,
                                          p_cdda->i_lsn, i_blocks);
#endif
        }
        if( rc != DRIVER_OP_SUCCESS )
        {
            msg_Err( p_access, "could not read %d sectors starting from %lu",
                     i_blocks, (long unsigned int) p_cdda->i_lsn );
            block_Release( p_block );

            /* If we had problems above, assume the problem is with
                the first sector of the read and set to skip it.  In
                the future libcdio may have cdparanoia support.
            */
            p_cdda->i_lsn++;
            p_access->info.i_pos += CDIO_CD_FRAMESIZE_RAW;
            return NULL;
        }
Clément Stenac's avatar
Clément Stenac committed
352 353
    }

354
    p_cdda->i_lsn        += i_blocks;
355
    p_access->info.i_pos += i_blocks * CDIO_CD_FRAMESIZE_RAW;
356

357
    return p_block;
358 359
}

360 361 362 363 364 365 366 367
/*****************************************************************************
 * 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;

Jean-Paul Saman's avatar
Jean-Paul Saman committed
368 369 370
    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);
371 372

    /* Check end of file */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
373 374 375
    if( p_access->info.b_eof )
        return 0;

376
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
377 378 379 380 381 382 383 384 385 386
        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;
387
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
388 389

    dbg_print( (INPUT_DBG_LSN), "updated lsn: %d", p_cdda->i_lsn );
390 391

    /* Check end of track */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
392 393
    while( p_cdda->i_lsn > cdio_get_track_last_lsn( p_cdda->p_cdio,
                                                    p_cdda->i_track) )
394 395 396
    {
        if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 )
        {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
397
            dbg_print( (INPUT_DBG_LSN), "EOF");
398 399 400 401 402 403 404
            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++;

Jean-Paul Saman's avatar
Jean-Paul Saman committed
405 406 407 408 409 410 411 412 413 414 415 416 417
        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;
        }
418 419 420 421 422 423
    }
    memset( p_buffer, 0, i_len );
    return i_len;
}

/*! Pause CD playing via audio control */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
424
static bool cdda_audio_pause( CdIo_t *p_cdio )
425
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
426
    bool b_ok = true;
427
#if LIBCDIO_VERSION_NUM >= 73
Jean-Paul Saman's avatar
Jean-Paul Saman committed
428 429 430 431 432 433 434 435
    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);
        }
436
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
437 438
    else
        b_ok = false;
439
#endif
Jean-Paul Saman's avatar
Jean-Paul Saman committed
440
    return b_ok;
441 442
}

443
#if LIBCDIO_VERSION_NUM >= 73
444 445
/*! play CD using audio controls */
static driver_return_code_t
Jean-Paul Saman's avatar
Jean-Paul Saman committed
446
cdda_audio_play( CdIo_t *p_cdio, lsn_t start_lsn, lsn_t end_lsn )
447
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
448 449 450 451 452 453
    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 );
454 455 456
}
#endif

457
/****************************************************************************
458 459
 * CDDASeek - change position for subsequent reads. For example, this
 * can happen if the user moves a position slider bar in a GUI.
460
 ****************************************************************************/
Jean-Paul Saman's avatar
Jean-Paul Saman committed
461
static int CDDASeek( access_t * p_access, int64_t i_pos )
462
{
463
    cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
464

465 466 467 468
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
               "lsn %lu, offset: %lld",
               (long unsigned int) p_cdda->i_lsn, i_pos );

469 470
    p_cdda->i_lsn = (i_pos / CDIO_CD_FRAMESIZE_RAW);

471
#if LIBCDIO_VERSION_NUM >= 72
Jean-Paul Saman's avatar
Jean-Paul Saman committed
472 473
    if( p_cdda->e_paranoia && p_cdda->paranoia )
         cdio_paranoia_seek( p_cdda->paranoia, p_cdda->i_lsn, SEEK_SET );
474 475
#endif

476
#if LIBCDIO_VERSION_NUM >= 73
Jean-Paul Saman's avatar
Jean-Paul Saman committed
477 478 479 480
    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;
481

Jean-Paul Saman's avatar
Jean-Paul Saman committed
482 483 484 485
        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 );
486

Jean-Paul Saman's avatar
Jean-Paul Saman committed
487
        cdda_audio_play( p_cdda->p_cdio, p_cdda->i_lsn, i_last_lsn );
488
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
489
#endif
490

Jean-Paul Saman's avatar
Jean-Paul Saman committed
491 492
    if( ! p_cdda->b_nav_mode )
        p_cdda->i_lsn += cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track );
493 494

    /* Seeked backwards and we are doing disc mode. */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    if( p_cdda->b_nav_mode && p_access->info.i_pos > i_pos )
    {
        track_t i_track;
        char *psz_title;

        for( i_track = p_cdda->i_track; i_track > 1 &&
             p_cdda->i_lsn < cdio_get_track_lsn( p_cdda->p_cdio, i_track );
             i_track--, p_access->info.i_title-- )
            ;

        p_cdda->i_track = i_track;
        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 );
        free( psz_title );
511
    }
512

Jean-Paul Saman's avatar
Jean-Paul Saman committed
513
    p_access->info.i_pos = i_pos;
514
    p_access->info.b_eof = VLC_FALSE;
515
    return VLC_SUCCESS;
516 517
}

518 519
/*
  Set up internal state so that we play a given track.
520 521
  If we are using audio-ctl mode we also activate CD-ROM
  to play.
522
 */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
523
static bool cdda_play_track( access_t *p_access, track_t i_track )
524 525 526
{
    cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;

Jean-Paul Saman's avatar
Jean-Paul Saman committed
527
    dbg_print( (INPUT_DBG_CALL), "called track: %d\n", i_track );
528

Jean-Paul Saman's avatar
Jean-Paul Saman committed
529 530 531 532 533 534
    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;
    }
535 536 537 538
    p_cdda->i_track = i_track;

    /* set up the frame boundaries for this particular track */
    p_cdda->first_frame = p_cdda->i_lsn = 
Jean-Paul Saman's avatar
Jean-Paul Saman committed
539
    cdio_get_track_lsn( p_cdda->p_cdio, i_track );
540

Jean-Paul Saman's avatar
Jean-Paul Saman committed
541
    p_cdda->last_frame  = cdio_get_track_lsn( p_cdda->p_cdio, i_track+1 ) - 1;
542 543

#if LIBCDIO_VERSION_NUM >= 73
Jean-Paul Saman's avatar
Jean-Paul Saman committed
544 545 546 547 548 549 550 551 552
    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 );
    }
553
#endif
Jean-Paul Saman's avatar
Jean-Paul Saman committed
554
    return true;
555 556
}

557 558 559 560 561
/****************************************************************************
 * Public functions
 ****************************************************************************/

/*****************************************************************************
Clément Stenac's avatar
Clément Stenac committed
562 563
 * Open: open cdda device or image file and initialize structures
 *       for subsequent operations.
564
 *****************************************************************************/
Jean-Paul Saman's avatar
Jean-Paul Saman committed
565
int CDDAOpen( vlc_object_t *p_this )
566
{
567 568
    access_t    *p_access = (access_t*)p_this;
    char *      psz_source = NULL;
569
    cdda_data_t *p_cdda    = NULL;
570
    CdIo_t      *p_cdio;
571 572 573
    track_t     i_track = 1;
    vlc_bool_t  b_single_track = false;
    int         i_rc = VLC_EGENERIC;
574

575 576
    p_access->p_sys = NULL;

577
    /* Set where to log errors messages from libcdio. */
578
    p_cdda_input = p_access;
579

580 581
    /* parse the options passed in command line : */
    if( p_access->psz_path && *p_access->psz_path )
582
    {
Clément Stenac's avatar
Clément Stenac committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596
        char *psz_parser = psz_source = strdup( p_access->psz_path );

        while( *psz_parser && *psz_parser != '@' )
        {
            psz_parser++;
        }

        if( *psz_parser == '@' )
        {
            /* Found options */
            *psz_parser = '\0';
            ++psz_parser;

            if ('T' == *psz_parser || 't' == *psz_parser )
597
            ++psz_parser;
Clément Stenac's avatar
Clément Stenac committed
598 599 600 601 602 603

            i_track = (int)strtol( psz_parser, NULL, 10 );
            i_track = i_track ? i_track : 1;
            b_single_track = true;
        }
    }
604

Jean-Paul Saman's avatar
Jean-Paul Saman committed
605
    if( !psz_source || !*psz_source )
Clément Stenac's avatar
Clément Stenac committed
606 607 608
    {
        /* No device/track given. Continue only when this plugin was
           selected */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
609 610
        if( !p_this->b_force )
            return VLC_EGENERIC;
611

612
        psz_source = var_CreateGetString( p_this, "cd-audio" );
Clément Stenac's avatar
Clément Stenac committed
613 614 615
        if( !psz_source || !*psz_source )
        {
            /* Scan for a CD-ROM drive with a CD-DA in it. */
616
            char **ppsz_drives =
Jean-Paul Saman's avatar
Jean-Paul Saman committed
617
                    cdio_get_devices_with_cap( NULL,  CDIO_FS_AUDIO, false );
Clément Stenac's avatar
Clément Stenac committed
618

Jean-Paul Saman's avatar
Jean-Paul Saman committed
619
            if( (NULL == ppsz_drives) || (NULL == ppsz_drives[0]) )
Clément Stenac's avatar
Clément Stenac committed
620 621
            {
                msg_Err( p_access,
Jean-Paul Saman's avatar
Jean-Paul Saman committed
622 623 624
                         "libcdio couldn't find something with a CD-DA in it" );
                if( ppsz_drives )
                    cdio_free_device_list( ppsz_drives );
Clément Stenac's avatar
Clément Stenac committed
625 626
                return VLC_EGENERIC;
            }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
627 628
            psz_source = strdup( ppsz_drives[0] );
            cdio_free_device_list( ppsz_drives );
Clément Stenac's avatar
Clément Stenac committed
629
        }
630
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
631
    cdio_log_set_handler( cdio_log_handler );
632

633
    /* Open CDDA */
634
    if( !(p_cdio = cdio_open( psz_source, DRIVER_UNKNOWN )) )
635
    {
636
        msg_Warn( p_access, "could not open %s", psz_source );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
637 638 639
        if ( psz_source )
            free( psz_source );
        return VLC_EGENERIC;
640 641
    }

642
    p_cdda = calloc( 1, sizeof(cdda_data_t) );
643 644
    if( p_cdda == NULL )
    {
645
        msg_Err( p_access, "out of memory" );
646
        free( psz_source );
647
        return VLC_ENOMEM;
648 649
    }

650 651 652
#ifdef HAVE_LIBCDDB
    cddb_log_set_handler ( cddb_log_handler );
    p_cdda->cddb.disc = NULL;
653
    p_cdda->b_cddb_enabled =
Jean-Paul Saman's avatar
Jean-Paul Saman committed
654
        config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
655
#endif
656
    p_cdda->b_cdtext =
Jean-Paul Saman's avatar
Jean-Paul Saman committed
657
        config_GetInt( p_access, MODULE_STRING "-cdtext-enabled" );
658
    p_cdda->b_cdtext_prefer =
Jean-Paul Saman's avatar
Jean-Paul Saman committed
659
        config_GetInt( p_access, MODULE_STRING "-cdtext-prefer" );
660 661
#if LIBCDIO_VERSION_NUM >= 73
    p_cdda->b_audio_ctl =
Jean-Paul Saman's avatar
Jean-Paul Saman committed
662
        config_GetInt( p_access, MODULE_STRING "-analog-output" );
663 664
#endif

Jean-Paul Saman's avatar
Jean-Paul Saman committed
665
    p_cdda->psz_source = strdup( psz_source );
666 667 668 669
    p_cdda->b_header   = VLC_FALSE;
    p_cdda->p_cdio     = p_cdio;
    p_cdda->i_tracks   = 0;
    p_cdda->i_titles   = 0;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
670 671 672 673 674 675 676 677 678 679
    p_cdda->i_debug    = config_GetInt( p_this, MODULE_STRING "-debug" );
    p_cdda->b_nav_mode = config_GetInt(p_this, MODULE_STRING "-navigation-mode" );
    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 );

    if( 0 == p_cdda->i_blocks_per_read )
Clément Stenac's avatar
Clément Stenac committed
680
        p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
681

Jean-Paul Saman's avatar
Jean-Paul Saman committed
682 683
    if( (p_cdda->i_blocks_per_read < MIN_BLOCKS_PER_READ)
         || (p_cdda->i_blocks_per_read > MAX_BLOCKS_PER_READ) )
Clément Stenac's avatar
Clément Stenac committed
684 685
    {
        msg_Warn( p_cdda_input,
Jean-Paul Saman's avatar
Jean-Paul Saman committed
686 687 688 689 690
                  "number of blocks (%d) has to be between %d and %d. "
                  "Using %d.",
                  p_cdda->i_blocks_per_read,
                  MIN_BLOCKS_PER_READ, MAX_BLOCKS_PER_READ,
                  DEFAULT_BLOCKS_PER_READ );
Clément Stenac's avatar
Clément Stenac committed
691 692
        p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
    }
693

694
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
695

696
    /* Set up p_access */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
697 698 699 700 701 702 703 704 705 706 707
    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;
    }

708 709 710
    p_access->pf_control = CDDAControl;
    p_access->pf_seek    = CDDASeek;

711
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
712 713 714 715 716 717 718 719 720 721 722
        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_cdio, i_track );

        if( CDIO_INVALID_LSN != i_last_lsn )
            p_access->info.i_size = i_last_lsn * (uint64_t) CDIO_CD_FRAMESIZE_RAW;
        else
            p_access->info.i_size = 0;
723
    }
724 725

    p_access->info.i_update    = 0;
726 727 728 729 730 731
    p_access->info.b_eof       = VLC_FALSE;
    p_access->info.i_title     = 0;
    p_access->info.i_seekpoint = 0;

    p_access->p_sys     = (access_sys_t *) p_cdda;

732
    /* We read the Table Of Content information */
733
    i_rc = CDDAInit( p_access, p_cdda );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
734 735
    if( VLC_SUCCESS != i_rc )
        goto error;
736

737
    cdda_play_track( p_access, i_track );
738
    CDDAFixupPlaylist( p_access, p_cdda, b_single_track );
Clément Stenac's avatar
Clément Stenac committed
739

740
#if LIBCDIO_VERSION_NUM >= 72
741
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
742 743 744
        char *psz_paranoia = config_GetPsz( p_access,
                                MODULE_STRING "-paranoia" );

745
        p_cdda->e_paranoia = PARANOIA_MODE_DISABLE;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
746 747 748
        if( psz_paranoia && *psz_paranoia )
        {
            if( !strncmp( psz_paranoia, "full", strlen("full") ) )
749
                p_cdda->e_paranoia = PARANOIA_MODE_FULL;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
750
            else if( !strncmp(psz_paranoia, "overlap", strlen("overlap")) )
751
                p_cdda->e_paranoia = PARANOIA_MODE_OVERLAP;
752

Jean-Paul Saman's avatar
Jean-Paul Saman committed
753 754 755 756 757 758 759 760 761 762 763 764 765
            /* Use CD Paranoia? */
            if( p_cdda->e_paranoia )
            {
                p_cdda->paranoia_cd =
                            cdio_cddap_identify_cdio( p_cdio, 1, NULL );
                /* We'll set for verbose paranoia messages. */
                cdio_cddap_verbose_set( p_cdda->paranoia_cd,
                                        CDDA_MESSAGE_PRINTIT,
                                        CDDA_MESSAGE_PRINTIT );
                if ( 0 != cdio_cddap_open(p_cdda->paranoia_cd) )
                {
                    msg_Warn( p_cdda_input, "unable to get paranoia support - "
                                "continuing without it." );
766
                    p_cdda->e_paranoia = PARANOIA_MODE_DISABLE;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
767 768 769 770 771 772 773 774 775 776
                }
                else
                {
                    p_cdda->paranoia = cdio_paranoia_init(p_cdda->paranoia_cd);
                    cdio_paranoia_seek( p_cdda->paranoia, p_cdda->i_lsn,
                                        SEEK_SET);

                    /* Set reading mode for full or overlap paranoia,
                     * but allow skipping sectors. */
                    cdio_paranoia_modeset( p_cdda->paranoia,
777
                            PARANOIA_MODE_FULL == p_cdda->e_paranoia ?
Jean-Paul Saman's avatar
Jean-Paul Saman committed
778 779 780 781 782
                            PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP :
                            PARANOIA_MODE_OVERLAP^PARANOIA_MODE_NEVERSKIP );
                }
            }
        }
783
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
784
#endif
785

Clément Stenac's avatar
Clément Stenac committed
786
    /* Build a WAV header to put in front of the output data.
787 788
       This gets sent back in the Block (read) routine.
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
789
    memset( &p_cdda->waveheader, 0, sizeof(WAVEHEADER) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
790

Gildas Bazin's avatar
 
Gildas Bazin committed
791 792
    SetWLE( &p_cdda->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
    SetWLE( &p_cdda->waveheader.BitsPerSample, 16);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
793

Gildas Bazin's avatar
 
Gildas Bazin committed
794 795 796
    p_cdda->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
    p_cdda->waveheader.Length = 0;                     /* we just don't know */
    p_cdda->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
797
    p_cdda->waveheader.SubChunkID  = VLC_FOURCC('f', 'm', 't', ' ');
Jean-Paul Saman's avatar
Jean-Paul Saman committed
798

Gildas Bazin's avatar
 
Gildas Bazin committed
799 800
    SetDWLE( &p_cdda->waveheader.SubChunkLength, 16);
    SetWLE( &p_cdda->waveheader.Modus, 2);
801
    SetDWLE( &p_cdda->waveheader.SampleFreq, CDDA_FREQUENCY_SAMPLE);
Gildas Bazin's avatar
 
Gildas Bazin committed
802 803 804
    SetWLE( &p_cdda->waveheader.BytesPerSample,
            2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
    SetDWLE( &p_cdda->waveheader.BytesPerSec,
Clément Stenac's avatar
Clément Stenac committed
805
             2*16/8 /*BytesPerSample*/ * CDDA_FREQUENCY_SAMPLE );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
806

Gildas Bazin's avatar
 
Gildas Bazin committed
807
    p_cdda->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
808
    p_cdda->waveheader.DataLength  = 0;    /* we just don't know */
Gildas Bazin's avatar
 
Gildas Bazin committed
809

810
    /* PTS delay */
Clément Stenac's avatar
Clément Stenac committed
811 812 813
    var_Create( p_access, MODULE_STRING "-caching",
                VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    vlc_object_release( p_cdda->p_input );
814
    return VLC_SUCCESS;
815 816

 error:
817
    cdio_destroy( p_cdda->p_cdio );
818
    if( psz_source) free( psz_source );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
819 820 821 822 823
    if( p_cdda )
    {
        if ( p_cdda->p_input )
            vlc_object_release( p_cdda->p_input );
        free(p_cdda);
Clément Stenac's avatar
Clément Stenac committed
824
    }
825
    return i_rc;
826 827 828
}

/*****************************************************************************
829
 * CDDAClose: closes cdda and frees any resources associded with it.
830
 *****************************************************************************/
Jean-Paul Saman's avatar
Jean-Paul Saman committed
831
void CDDAClose (vlc_object_t *p_this )
832
{
833 834 835
    access_t    *p_access = (access_t *) p_this;
    cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
    track_t      i;
836

837
#if LIBCDIO_VERSION_NUM >= 73
Jean-Paul Saman's avatar
Jean-Paul Saman committed
838 839
    if( p_cdda->b_audio_ctl )
        cdio_audio_stop(p_cdda->p_cdio);
840 841
#endif

842
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
843 844

    /* Remove playlist titles */
845
    for( i = 0; i < p_cdda->i_titles; i++ )
846 847 848 849
    {
        vlc_input_title_Delete( p_cdda->p_title[i] );
    }

850
#ifdef HAVE_LIBCDDB
Jean-Paul Saman's avatar
Jean-Paul Saman committed
851 852 853
    cddb_log_set_handler( (cddb_log_handler_t) uninit_log_handler );
    if( p_cdda->b_cddb_enabled )
        cddb_disc_destroy( p_cdda->cddb.disc );
854 855
#endif

856
    cdio_destroy( p_cdda->p_cdio );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
857
    cdio_log_set_handler( uninit_log_handler );
858 859

#if LIBCDIO_VERSION_NUM >= 72
Jean-Paul Saman's avatar
Jean-Paul Saman committed
860 861 862 863
    if( p_cdda->paranoia )
        cdio_paranoia_free(p_cdda->paranoia);
    if( p_cdda->paranoia_cd )
        cdio_cddap_close_no_free_cdio( p_cdda->paranoia_cd );
864 865
#endif

Jean-Paul Saman's avatar
Jean-Paul Saman committed
866 867
    if( p_cdda->psz_mcn )    free( p_cdda->psz_mcn );
    if( p_cdda->psz_source ) free( p_cdda->psz_source );
868 869 870 871

#if LIBCDDB_VERSION_NUM >= 1
    libcddb_shutdown();
#endif
872
    free( p_cdda );
873
    p_cdda = NULL;
874 875
    p_cdda_input = NULL;
}
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893

/*****************************************************************************
 * Control: The front-end or vlc engine calls here to ether get
 * information such as meta information or plugin capabilities or to
 * issue miscellaneous "set" requests.
 *****************************************************************************/
static int CDDAControl( access_t *p_access, int i_query, va_list args )
{
    cdda_data_t  *p_cdda = (cdda_data_t *) p_access->p_sys;
    int          *pi_int;
    int i;

    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
               "query %d", i_query );

    switch( i_query )
    {
        /* Pass back a copy of meta information that was gathered when we
Clément Stenac's avatar
Clément Stenac committed
894 895
           during the Open/Initialize call.
         */
896
        case ACCESS_GET_META:
Clément Stenac's avatar
Clément Stenac committed
897
        {
898
#if 0
899
            vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
900
            if( p_cdda->p_meta )
Clément Stenac's avatar
Clément Stenac committed
901 902 903
            {
                *pp_meta = vlc_meta_Duplicate( p_cdda->p_meta );
                dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
904
                return VLC_SUCCESS;
Clément Stenac's avatar
Clément Stenac committed
905
            }
906 907 908
            else
#endif
            {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
909 910 911
                msg_Warn( p_access, "tried to copy NULL meta info" );
                return VLC_EGENERIC;
            }
Clément Stenac's avatar
Clément Stenac committed
912
        }
913

914
        case ACCESS_CAN_CONTROL_PACE:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
915
        {
916 917
            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;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
918
            dbg_print( INPUT_DBG_META, "can control pace? %d", *pb_bool);
919
            return VLC_SUCCESS;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
920 921
        }

922
        case ACCESS_CAN_FASTSEEK:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
923 924
            dbg_print( INPUT_DBG_META, "can fast seek?");
            goto common;
925
        case ACCESS_CAN_SEEK:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
926 927
            dbg_print( INPUT_DBG_META, "can seek?");
            goto common;
928
        case ACCESS_CAN_PAUSE:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
929 930 931 932 933 934 935
            dbg_print( INPUT_DBG_META, "can pause?");
 common:
            {
                vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
                *pb_bool = VLC_TRUE;
                return VLC_SUCCESS;
            }
936 937 938

        /* */
        case ACCESS_GET_MTU:
Clément Stenac's avatar
Clément Stenac committed
939
        {
940
            pi_int = (int*)va_arg( args, int * );
941
            *pi_int = p_cdda-> i_blocks_per_read * CDIO_CD_FRAMESIZE_RAW;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
942
            dbg_print( INPUT_DBG_META, "Get MTU %d", *pi_int);
943
            break;
Clément Stenac's avatar
Clément Stenac committed
944
        }
945 946

        case ACCESS_GET_PTS_DELAY:
Clément Stenac's avatar
Clément Stenac committed
947 948
        {
            int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
949
            *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
Clément Stenac's avatar
Clément Stenac committed
950
              * MILLISECONDS_PER_SEC;
951
            break;
Clément Stenac's avatar
Clément Stenac committed
952
        }
953 954

        case ACCESS_GET_TITLE_INFO:
Clément Stenac's avatar
Clément Stenac committed
955
        {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
956 957
            input_title_t ***ppp_title =
             (input_title_t***)va_arg( args, input_title_t*** );
958

959
            pi_int    = (int*)va_arg( args, int* );
Clément Stenac's avatar
Clément Stenac committed
960
            *((int*)va_arg( args, int* )) = 1; /* Title offset */
961

Clément Stenac's avatar
Clément Stenac committed
962
            dbg_print ( INPUT_DBG_EVENT,
Rocky Bernstein's avatar
Rocky Bernstein committed
963 964 965
                        "GET TITLE: i_tracks %d, i_tracks %d",
                        p_cdda->i_tracks, p_cdda->i_tracks );

Jean-Paul Saman's avatar
Jean-Paul Saman committed
966
            CDDAMetaInfo( p_access, CDIO_INVALID_TRACK );
967

Jean-Paul Saman's avatar
Jean-Paul Saman committed
968 969 970 971 972 973
            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);
            }
974

Rocky Bernstein's avatar
Rocky Bernstein committed
975
            /* Duplicate title info */
Clément Stenac's avatar
Clément Stenac committed
976 977 978 979 980
            if( p_cdda->i_titles == 0 )
            {
                *pi_int = 0; ppp_title = NULL;
                return VLC_SUCCESS;
            }
981
            *pi_int = p_cdda->i_titles;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
982 983
            *ppp_title = calloc(1, sizeof( input_title_t **)
                                           * p_cdda->i_titles );
984

Jean-Paul Saman's avatar
Jean-Paul Saman committed
985 986
            if (!*ppp_title)
                return VLC_ENOMEM;
987

988
            for( i = 0; i < p_cdda->i_titles; i++ )
989
            {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
990 991 992 993 994
                if ( p_cdda->p_title[i] )
                {
                    (*ppp_title)[i] =
                        vlc_input_title_Duplicate( p_cdda->p_title[i] );
                }
995
            }
Clément Stenac's avatar
Clément Stenac committed
996 997
            break;
        }
998 999

        case ACCESS_SET_TITLE:
Clément Stenac's avatar
Clément Stenac committed
1000
        {
1001
            i = (int)va_arg( args, int );
Rocky Bernstein's avatar
Rocky Bernstein committed
1002

Jean-Paul Saman's avatar
Jean-Paul Saman committed
1003
            dbg_print( INPUT_DBG_EVENT, "set title %d", i );
1004 1005
            if( i != p_access->info.i_title )
            {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1006
                const track_t i_track = p_cdda->i_first_track + i;
1007 1008
                /* Update info */
                p_access->info.i_title = i;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
                if( p_cdda->b_nav_mode)
                {
                    lsn_t i_last_lsn;
                    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 = 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, i_track )
                                                        * CDIO_CD_FRAMESIZE_RAW;
                }
                else
1027
                {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1028 1029 1030 1031
                    p_access->info.i_size = p_cdda->p_title[i]->i_size;
                    p_access->info.i_pos  = 0;
                }
                p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
1032 1033

                /* Next sector to read */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1034
                p_cdda->i_lsn = cdio_get_track_lsn( p_cdda->p_cdio, i_track );
1035 1036
            }
            break;
Clément Stenac's avatar
Clément Stenac committed
1037
        }
1038

1039
        case ACCESS_SET_PAUSE_STATE:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1040 1041 1042 1043
            dbg_print( INPUT_DBG_META, "Pause");
            if( p_cdda->b_audio_ctl )
                cdda_audio_pause( p_cdda->p_cdio );
            break;
1044

1045
        case ACCESS_SET_SEEKPOINT:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1046
            dbg_print( INPUT_DBG_META, "set seekpoint");
1047 1048
            return VLC_EGENERIC;

1049
        case ACCESS_SET_PRIVATE_ID_STATE:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1050