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
dionoea's avatar
dionoea 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 */
hartman's avatar
hartman committed
32
#include "access.h"
33
34
#include <vlc_playlist.h>  /* Has to come *after* cdda.h */
#include "vlc_keys.h"
zorglub's avatar
Round 2    
zorglub 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
53
54
#include <stdio.h>

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

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

#ifdef HAVE_STRING_H
#include <string.h>
#endif
55
56
57
58
59
60

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

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

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
66
static int      CDDARead( access_t *, uint8_t *, int );
67
static block_t *CDDAReadBlocks( access_t * p_access );
68
static int      CDDASeek( access_t * p_access, int64_t i_pos );
zorglub's avatar
zorglub committed
69
70
static int      CDDAControl( access_t *p_access, int i_query,
                             va_list args );
71

72
static int      CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;
73

74

75
76
77
78
/****************************************************************************
 * Private functions
 ****************************************************************************/

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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    if( p_cdda == NULL )
        return;

    switch( level )
    {
        case CDIO_LOG_DEBUG:
        case CDIO_LOG_INFO:
            if (p_cdda->i_debug & INPUT_DBG_CDIO)
            msg_Dbg( p_cdda_input, message);
            break;
        case CDIO_LOG_WARN:
            msg_Warn( p_cdda_input, message);
            break;
        case CDIO_LOG_ERROR:
        case CDIO_LOG_ASSERT:
            msg_Err( p_cdda_input, message);
            break;
        default:
            msg_Warn( p_cdda_input, message,
                    "the above message had unknown cdio log level",
                    level);
            break;
    }
}
111

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


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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
143
    if( p_cdda_input )
zorglub's avatar
zorglub committed
144
        p_cdda = (cdda_data_t *)p_cdda_input->p_sys;
145

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

171
172
/* Only used in audio control mode. Gets the current LSN from the 
   CD-ROM drive. */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
173
static int64_t get_audio_position ( access_t *p_access )
174
175
176
177
178
{
    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
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
205
206
    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;
207
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
208
209
#else
        i_offset = p_cdda->i_lsn;
210
#endif
Jean-Paul Saman's avatar
Jean-Paul Saman committed
211
    return i_offset;
212
213
}

214
/*****************************************************************************
215
216
217
218
 * 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.
219
 *****************************************************************************/
zorglub's avatar
zorglub committed
220
static block_t * CDDAReadBlocks( access_t * p_access )
221
{
222
223
    block_t     *p_block;
    cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
224
    int          i_blocks = p_cdda->i_blocks_per_read;
225

Jean-Paul Saman's avatar
Jean-Paul Saman committed
226
227
228
    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 );
229

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

234
235
236
237
238
239
240
    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;
gbazin's avatar
   
gbazin committed
241
    }
242

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

        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 ;
253
254

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

261
        p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META;
262
        p_access->info.i_title++;
zorglub's avatar
zorglub committed
263
        p_cdda->i_track++;
264

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

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

288
289
290
    /* Do the actual reading */
    p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW );
    if( !p_block)
291
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
292
293
        msg_Err( p_access, "cannot get a new block of size: %i",
                i_blocks * CDIO_CD_FRAMESIZE_RAW );
294
295
296
        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
297
        return NULL;
298
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
299

zorglub's avatar
zorglub committed
300
    {
301
#if LIBCDIO_VERSION_NUM >= 72
Jean-Paul Saman's avatar
Jean-Paul Saman committed
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
331
332
        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 );
333
334
#else
#define DRIVER_OP_SUCCESS 0
Jean-Paul Saman's avatar
Jean-Paul Saman committed
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
            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;
        }
zorglub's avatar
zorglub committed
354
355
    }

356
    p_cdda->i_lsn        += i_blocks;
357
    p_access->info.i_pos += i_blocks * CDIO_CD_FRAMESIZE_RAW;
358

359
    return p_block;
360
361
}

362
363
364
365
366
367
368
369
/*****************************************************************************
 * 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
370
371
372
    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);
373
374

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

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

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

    /* Check end of track */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
394
395
    while( p_cdda->i_lsn > cdio_get_track_last_lsn( p_cdda->p_cdio,
                                                    p_cdda->i_track) )
396
397
398
    {
        if( p_cdda->i_track >= p_cdda->i_first_track + p_cdda->i_titles - 1 )
        {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
399
            dbg_print( (INPUT_DBG_LSN), "EOF");
400
401
402
403
404
405
406
            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
407
408
409
410
411
412
413
414
415
416
417
418
419
        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;
        }
420
421
422
423
424
425
    }
    memset( p_buffer, 0, i_len );
    return i_len;
}

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

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

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

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

471
472
    p_cdda->i_lsn = (i_pos / CDIO_CD_FRAMESIZE_RAW);

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

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

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

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

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

    /* Seeked backwards and we are doing disc mode. */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
    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 );
513
    }
514

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

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

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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
531
532
533
534
535
536
    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;
    }
537
538
539
540
    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
541
    cdio_get_track_lsn( p_cdda->p_cdio, i_track );
542

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

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

559
560
561
562
563
/****************************************************************************
 * Public functions
 ****************************************************************************/

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

hartman's avatar
hartman committed
577
578
    p_access->p_sys = NULL;

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

582
583
    /* parse the options passed in command line : */
    if( p_access->psz_path && *p_access->psz_path )
584
    {
zorglub's avatar
zorglub committed
585
586
587
588
589
590
591
592
593
594
595
596
597
598
        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 )
599
            ++psz_parser;
zorglub's avatar
zorglub committed
600
601
602
603
604
605

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

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

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

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

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

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

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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
667
    p_cdda->psz_source = strdup( psz_source );
668
669
670
671
    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
672
673
674
675
676
677
678
679
680
681
    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 )
zorglub's avatar
zorglub committed
682
        p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
683

Jean-Paul Saman's avatar
Jean-Paul Saman committed
684
685
    if( (p_cdda->i_blocks_per_read < MIN_BLOCKS_PER_READ)
         || (p_cdda->i_blocks_per_read > MAX_BLOCKS_PER_READ) )
zorglub's avatar
zorglub committed
686
687
    {
        msg_Warn( p_cdda_input,
Jean-Paul Saman's avatar
Jean-Paul Saman committed
688
689
690
691
692
                  "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 );
zorglub's avatar
zorglub committed
693
694
        p_cdda->i_blocks_per_read = DEFAULT_BLOCKS_PER_READ;
    }
695

696
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
697

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

710
711
712
    p_access->pf_control = CDDAControl;
    p_access->pf_seek    = CDDASeek;

713
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
714
715
716
717
718
719
720
721
722
723
724
        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;
725
    }
726
727

    p_access->info.i_update    = 0;
728
729
730
731
732
733
    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;

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

739
    cdda_play_track( p_access, i_track );
740
    CDDAFixupPlaylist( p_access, p_cdda, b_single_track );
zorglub's avatar
zorglub committed
741

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

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

Jean-Paul Saman's avatar
Jean-Paul Saman committed
755
756
757
758
759
760
761
762
763
764
765
766
767
            /* 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." );
768
                    p_cdda->e_paranoia = PARANOIA_MODE_DISABLE;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
769
770
771
772
773
774
775
776
777
778
                }
                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,
779
                            PARANOIA_MODE_FULL == p_cdda->e_paranoia ?
Jean-Paul Saman's avatar
Jean-Paul Saman committed
780
781
782
783
784
                            PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP :
                            PARANOIA_MODE_OVERLAP^PARANOIA_MODE_NEVERSKIP );
                }
            }
        }
785
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
786
#endif
787

zorglub's avatar
zorglub committed
788
    /* Build a WAV header to put in front of the output data.
789
790
       This gets sent back in the Block (read) routine.
     */
gbazin's avatar
   
gbazin committed
791
    memset( &p_cdda->waveheader, 0, sizeof(WAVEHEADER) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
792

gbazin's avatar
   
gbazin committed
793
794
    SetWLE( &p_cdda->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
    SetWLE( &p_cdda->waveheader.BitsPerSample, 16);
Jean-Paul Saman's avatar
Jean-Paul Saman committed
795

gbazin's avatar
   
gbazin committed
796
797
798
    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');
799
    p_cdda->waveheader.SubChunkID  = VLC_FOURCC('f', 'm', 't', ' ');
Jean-Paul Saman's avatar
Jean-Paul Saman committed
800

gbazin's avatar
   
gbazin committed
801
802
    SetDWLE( &p_cdda->waveheader.SubChunkLength, 16);
    SetWLE( &p_cdda->waveheader.Modus, 2);
803
    SetDWLE( &p_cdda->waveheader.SampleFreq, CDDA_FREQUENCY_SAMPLE);
gbazin's avatar
   
gbazin committed
804
805
806
    SetWLE( &p_cdda->waveheader.BytesPerSample,
            2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
    SetDWLE( &p_cdda->waveheader.BytesPerSec,
zorglub's avatar
zorglub committed
807
             2*16/8 /*BytesPerSample*/ * CDDA_FREQUENCY_SAMPLE );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
808

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

812
    /* PTS delay */
zorglub's avatar
zorglub committed
813
814
815
    var_Create( p_access, MODULE_STRING "-caching",
                VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    vlc_object_release( p_cdda->p_input );
816
    return VLC_SUCCESS;
817
818

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

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

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

844
    dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
845
846

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

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

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

#if LIBCDIO_VERSION_NUM >= 72
Jean-Paul Saman's avatar
Jean-Paul Saman committed
862
863
864
865
    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 );
866
867
#endif

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

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

/*****************************************************************************
 * 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
zorglub's avatar
zorglub committed
896
897
           during the Open/Initialize call.
         */
898
        case ACCESS_GET_META:
zorglub's avatar
zorglub committed
899
900
        {
            vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
901
902
#if 0
            if( p_cdda->p_meta )
zorglub's avatar
zorglub committed
903
904
905
            {
                *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
906
                return VLC_SUCCESS;
zorglub's avatar
zorglub committed
907
            }
908
909
910
            else
#endif
            {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
911
912
913
                msg_Warn( p_access, "tried to copy NULL meta info" );
                return VLC_EGENERIC;
            }
zorglub's avatar
zorglub committed
914
        }
915

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

924
        case ACCESS_CAN_FASTSEEK:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
925
926
            dbg_print( INPUT_DBG_META, "can fast seek?");
            goto common;
927
        case ACCESS_CAN_SEEK:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
928
929
            dbg_print( INPUT_DBG_META, "can seek?");
            goto common;
930
        case ACCESS_CAN_PAUSE:
Jean-Paul Saman's avatar
Jean-Paul Saman committed
931
932
933
934
935
936
937
            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;
            }
938
939
940

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

        case ACCESS_GET_PTS_DELAY:
zorglub's avatar
zorglub committed
949
950
        {
            int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
951
            *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
zorglub's avatar
zorglub committed
952
              * MILLISECONDS_PER_SEC;
953
            break;
zorglub's avatar
zorglub committed
954
        }
955
956

        case ACCESS_GET_TITLE_INFO:
zorglub's avatar
zorglub committed
957
        {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
958
959
            input_title_t ***ppp_title =
             (input_title_t***)va_arg( args, input_title_t*** );
960

961
            pi_int    = (int*)va_arg( args, int* );
zorglub's avatar
zorglub committed
962
            *((int*)va_arg( args, int* )) = 1; /* Title offset */
963

zorglub's avatar
zorglub committed
964
            dbg_print ( INPUT_DBG_EVENT,
Rocky Bernstein's avatar
Rocky Bernstein committed
965
966
967
                        "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
968
            CDDAMetaInfo( p_access, CDIO_INVALID_TRACK );
969

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

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

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

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

        case ACCESS_SET_TITLE:
zorglub's avatar
zorglub committed
1002
        {