cdda.c 24.5 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
/*****************************************************************************
 * cdda.c : CD digital audio input module for vlc
 *****************************************************************************
4
 * Copyright (C) 2000, 2003 the VideoLAN team
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * Authors: 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
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
gbazin's avatar
   
gbazin committed
23
24
25
26
27
28
29
30
31
32
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>

#include <vlc/vlc.h>
#include <vlc/input.h>

gbazin's avatar
   
gbazin committed
33
#include "codecs.h"
gbazin's avatar
   
gbazin committed
34
35
#include "vcd/cdrom.h"

36
37
#include <vlc_playlist.h>

38
39
40
41
#ifdef HAVE_LIBCDDB
#include <cddb/cddb.h>
#endif

42
43
44
45
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif

gbazin's avatar
   
gbazin committed
46
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
47
 * Module descriptior
gbazin's avatar
   
gbazin committed
48
 *****************************************************************************/
49
50
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
gbazin's avatar
   
gbazin committed
51
52
53
54

#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
    "Allows you to modify the default caching value for cdda streams. This " \
Sam Hocevar's avatar
Sam Hocevar committed
55
    "value should be set in milliseconds units." )
gbazin's avatar
   
gbazin committed
56
57

vlc_module_begin();
58
    set_shortname( _("Audio CD"));
Sam Hocevar's avatar
Sam Hocevar committed
59
    set_description( _("Audio CD input") );
60
    set_capability( "access2", 10 );
zorglub's avatar
zorglub committed
61
62
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACCESS );
63
    set_callbacks( Open, Close );
gbazin's avatar
   
gbazin committed
64

65
    add_usage_hint( N_("[cdda:][device][@[track]]") );
gbazin's avatar
   
gbazin committed
66
67
    add_integer( "cdda-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
                 CACHING_LONGTEXT, VLC_TRUE );
68
69
    add_bool( "cdda-separate-tracks", VLC_TRUE, NULL, NULL, NULL, VLC_TRUE );
    add_integer( "cdda-track", -1 , NULL, NULL, NULL, VLC_TRUE );
70
71
72
73
74
75
    add_string( "cddb-server", "freedb.freedb.org", NULL,
                N_( "CDDB Server" ), N_( "Adress of the CDDB server to use" ),
                VLC_TRUE );
    add_integer( "cddb-port", 8880, NULL,
                N_( "CDDB port" ), N_( "CDDB Server port to use" ),
                VLC_TRUE );
gbazin's avatar
   
gbazin committed
76
    add_shortcut( "cdda" );
gbazin's avatar
   
gbazin committed
77
    add_shortcut( "cddasimple" );
gbazin's avatar
   
gbazin committed
78
79
vlc_module_end();

Laurent Aimar's avatar
Laurent Aimar committed
80
81
82
83
84
85
86
87
88
89
90

/* how many blocks VCDRead will read in each loop */
#define CDDA_BLOCKS_ONCE 20
#define CDDA_DATA_ONCE   (CDDA_BLOCKS_ONCE * CDDA_DATA_SIZE)

/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
struct access_sys_t
{
    vcddev_t    *vcddev;                            /* vcd device descriptor */
91
92
93
94
95

    /* Title infos */
    int           i_titles;
    input_title_t *title[99];         /* No more that 99 track in a cd-audio */

96
    /* Current position */
Laurent Aimar's avatar
Laurent Aimar committed
97
98
99
    int         i_sector;                                  /* Current Sector */
    int *       p_sectors;                                  /* Track sectors */

100
101
    /* Wave header for the output data */
    WAVEHEADER  waveheader;
102
    vlc_bool_t  b_header;
103
104
105
106

    vlc_bool_t  b_separate_items;
    vlc_bool_t  b_single_track;
    int         i_track;
107
108
109
110

#ifdef HAVE_LIBCDDB
    cddb_disc_t *p_disc;
#endif
Laurent Aimar's avatar
Laurent Aimar committed
111
112
};

113
114
115
static block_t *Block( access_t * );
static int      Seek( access_t *, int64_t );
static int      Control( access_t *, int, va_list );
Laurent Aimar's avatar
Laurent Aimar committed
116

117
118
119
static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
                      playlist_t *p_playlist, playlist_item_t *p_parent );

120
121
122
123
#ifdef HAVE_LIBCDDB
static void GetCDDBInfo( access_t *p_access, int i_titles, int *p_sectors );
#endif

gbazin's avatar
   
gbazin committed
124
/*****************************************************************************
125
 * Open: open cdda
gbazin's avatar
   
gbazin committed
126
 *****************************************************************************/
127
static int Open( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
128
{
129
130
131
132
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;

    vcddev_t *vcddev;
133
    char *psz_name;
134
135
136
137
138
139
140
141

    vlc_bool_t b_separate_requested;
    vlc_bool_t b_play = VLC_FALSE;
    input_thread_t *p_input;
    playlist_item_t *p_item = NULL;
    playlist_t *p_playlist  = NULL;
    int i_ret;
    int i_track;
142

143
    if( !p_access->psz_path || !*p_access->psz_path )
gbazin's avatar
   
gbazin committed
144
    {
145
        /* Only when selected */
146
        if( !p_this->b_force ) return VLC_EGENERIC;
147

148
149
        psz_name = var_CreateGetString( p_this, "cd-audio" );
        if( !psz_name || !*psz_name )
gbazin's avatar
   
gbazin committed
150
        {
151
            if( psz_name ) free( psz_name );
Laurent Aimar's avatar
Laurent Aimar committed
152
            return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
153
154
        }
    }
155
    else psz_name = strdup( p_access->psz_path );
gbazin's avatar
   
gbazin committed
156

157
158
159
160
161
#ifdef WIN32
    if( psz_name[0] && psz_name[1] == ':' &&
        psz_name[2] == '\\' && psz_name[3] == '\0' ) psz_name[2] = '\0';
#endif

gbazin's avatar
   
gbazin committed
162
    /* Open CDDA */
163
    if( (vcddev = ioctl_Open( VLC_OBJECT(p_access), psz_name )) == NULL )
gbazin's avatar
   
gbazin committed
164
    {
165
166
        msg_Warn( p_access, "could not open %s", psz_name );
        free( psz_name );
Laurent Aimar's avatar
Laurent Aimar committed
167
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
168
    }
169
    free( psz_name );
170
171
172
173
174
175
176
177
178
179
180
181
182
183

    /* Set up p_access */
    p_access->pf_read = NULL;
    p_access->pf_block = Block;
    p_access->pf_control = Control;
    p_access->pf_seek = Seek;
    p_access->info.i_update = 0;
    p_access->info.i_size = 0;
    p_access->info.i_pos = 0;
    p_access->info.b_eof = VLC_FALSE;
    p_access->info.i_title = 0;
    p_access->info.i_seekpoint = 0;
    p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
    memset( p_sys, 0, sizeof( access_sys_t ) );
Laurent Aimar's avatar
Laurent Aimar committed
184
    p_sys->vcddev = vcddev;
185
186
    p_sys->b_separate_items = VLC_FALSE;
    p_sys->b_single_track = VLC_FALSE;
187
    p_sys->b_header = VLC_FALSE;
gbazin's avatar
   
gbazin committed
188

189
190
191
192
193
194
195
196
197
198
    b_separate_requested = var_CreateGetBool( p_access,
                                              "cdda-separate-tracks" );

    /* We only do separate items if the whole disc is requested -
     *  Dirty hack we access some private data ! */
    p_input = (input_thread_t *)( p_access->p_parent );
    /* Do we play a single track ? */
    i_track = var_CreateGetInteger( p_access, "cdda-track" );
    if( b_separate_requested && p_input->input.i_title_start == -1 &&
        i_track <= 0 )
Laurent Aimar's avatar
Laurent Aimar committed
199
    {
200
        p_sys->b_separate_items = VLC_TRUE;
Laurent Aimar's avatar
Laurent Aimar committed
201
    }
202
    if( i_track > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
203
    {
204
205
        p_sys->b_single_track = VLC_TRUE;
        p_sys->i_track = i_track - 1;
Laurent Aimar's avatar
Laurent Aimar committed
206
    }
gbazin's avatar
   
gbazin committed
207

208
209
210
211
    msg_Dbg( p_access, "Separate items : %i - Single track : %i",
                        p_sys->b_separate_items, p_sys->b_single_track );

    if( p_sys->b_separate_items )
gbazin's avatar
   
gbazin committed
212
    {
213
214
        p_playlist = (playlist_t *) vlc_object_find( p_access,
                                       VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
zorglub's avatar
Grmbl    
zorglub committed
215

216
        if( !p_playlist ) return VLC_EGENERIC;
zorglub's avatar
Grmbl    
zorglub committed
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
        /* Let's check if we need to play */
        if( &p_playlist->status.p_item->input ==
             ((input_thread_t *)p_access->p_parent)->input.p_item )
        {
            p_item = p_playlist->status.p_item;
            b_play = VLC_TRUE;
            msg_Dbg( p_access, "starting Audio CD playback");
        }
        else
        {
            input_item_t *p_current = ( (input_thread_t*)p_access->p_parent)->
                                         input.p_item;
            p_item = playlist_LockItemGetByInput( p_playlist, p_current );
            msg_Dbg( p_access, "not starting Audio CD playback");
zorglub's avatar
Grmbl    
zorglub committed
232

233
234
235
236
237
238
239
            if( !p_item )
            {
                msg_Dbg( p_playlist, "unable to find item in playlist");
               return -1;
            }
            b_play = VLC_FALSE;
        }
gbazin's avatar
   
gbazin committed
240
241
    }

242
    /* We read the Table Of Content information */
zorglub's avatar
zorglub committed
243
    if( 1 )
244
245
246
247
248
249
250
251
    {
        i_ret = GetTracks( p_access, p_sys->b_separate_items,
                           p_playlist, p_item );
        if( i_ret < 0 )
        {
            goto error;
        }
    }
gbazin's avatar
   
gbazin committed
252

gbazin's avatar
   
gbazin committed
253
254
    /* Build a WAV header for the output data */
    memset( &p_sys->waveheader, 0, sizeof(WAVEHEADER) );
gbazin's avatar
   
gbazin committed
255
256
    SetWLE( &p_sys->waveheader.Format, 1 ); /*WAVE_FORMAT_PCM*/
    SetWLE( &p_sys->waveheader.BitsPerSample, 16);
gbazin's avatar
   
gbazin committed
257
258
259
260
    p_sys->waveheader.MainChunkID = VLC_FOURCC('R', 'I', 'F', 'F');
    p_sys->waveheader.Length = 0;                     /* we just don't know */
    p_sys->waveheader.ChunkTypeID = VLC_FOURCC('W', 'A', 'V', 'E');
    p_sys->waveheader.SubChunkID = VLC_FOURCC('f', 'm', 't', ' ');
gbazin's avatar
   
gbazin committed
261
262
263
264
265
266
    SetDWLE( &p_sys->waveheader.SubChunkLength, 16);
    SetWLE( &p_sys->waveheader.Modus, 2);
    SetDWLE( &p_sys->waveheader.SampleFreq, 44100);
    SetWLE( &p_sys->waveheader.BytesPerSample,
            2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
    SetDWLE( &p_sys->waveheader.BytesPerSec,
267
             2*16/8 /*BytesPerSample*/ * 44100 /*SampleFreq*/ );
gbazin's avatar
   
gbazin committed
268
269
270
    p_sys->waveheader.DataChunkID = VLC_FOURCC('d', 'a', 't', 'a');
    p_sys->waveheader.DataLength = 0;                 /* we just don't know */

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    /* Only update META if we are in old mode */
    if( !p_sys->b_separate_items && !p_sys->b_single_track )
    {
        p_access->info.i_update |= INPUT_UPDATE_META;
    }

    /* Position on the right sector and update size */
    if( p_sys->b_single_track )
    {
        p_sys->i_sector = p_sys->p_sectors[ p_sys->i_track ];
        p_access->info.i_size =
            ( p_sys->p_sectors[p_sys->i_track+1] -
              p_sys->p_sectors[p_sys->i_track] ) *
                        (int64_t)CDDA_DATA_SIZE;
    }
286

287
288
    /* PTS delay */
    var_Create( p_access, "cdda-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
289
290
291
292
293
294
295

    if( b_play )
    {
        playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
                          p_playlist->status.i_view, p_playlist->status.p_item,
                          NULL );
    }
zorglub's avatar
zorglub committed
296
297
298

    if( p_playlist ) vlc_object_release( p_playlist );

Laurent Aimar's avatar
Laurent Aimar committed
299
    return VLC_SUCCESS;
300
301
302
303

error:
    ioctl_Close( VLC_OBJECT(p_access), p_sys->vcddev );
    free( p_sys );
zorglub's avatar
zorglub committed
304
    if( p_playlist ) vlc_object_release( p_playlist );
305
    return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
306
307
308
}

/*****************************************************************************
309
 * Close: closes cdda
gbazin's avatar
   
gbazin committed
310
 *****************************************************************************/
311
static void Close( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
312
{
313
314
315
316
317
318
319
320
    access_t     *p_access = (access_t *)p_this;
    access_sys_t *p_sys = p_access->p_sys;
    int          i;

    for( i = 0; i < p_sys->i_titles; i++ )
    {
        vlc_input_title_Delete( p_sys->title[i] );
    }
gbazin's avatar
   
gbazin committed
321

Laurent Aimar's avatar
Laurent Aimar committed
322
323
    ioctl_Close( p_this, p_sys->vcddev );
    free( p_sys );
gbazin's avatar
   
gbazin committed
324
325
326
}

/*****************************************************************************
327
 * Block: read data (CDDA_DATA_ONCE)
gbazin's avatar
   
gbazin committed
328
 *****************************************************************************/
329
static block_t *Block( access_t *p_access )
gbazin's avatar
   
gbazin committed
330
{
331
    access_sys_t *p_sys = p_access->p_sys;
332
333
    int i_blocks = CDDA_BLOCKS_ONCE;
    block_t *p_block;
334

335
336
    if( p_sys->b_separate_items ) p_access->info.b_eof = VLC_TRUE;

337
338
    /* Check end of file */
    if( p_access->info.b_eof ) return NULL;
gbazin's avatar
   
gbazin committed
339

340
    if( !p_sys->b_header )
gbazin's avatar
   
gbazin committed
341
    {
342
343
344
        /* Return only the header */
        p_block = block_New( p_access, sizeof( WAVEHEADER ) );
        memcpy( p_block->p_buffer, &p_sys->waveheader, sizeof(WAVEHEADER) );
345
        p_sys->b_header = VLC_TRUE;
346
        return p_block;
gbazin's avatar
   
gbazin committed
347
    }
gbazin's avatar
   
gbazin committed
348

349
350
    /* Check end of title - Single track */
    if( p_sys->b_single_track )
gbazin's avatar
   
gbazin committed
351
    {
352
        if( p_sys->i_sector >= p_sys->p_sectors[p_sys->i_track + 1] )
353
354
355
356
        {
            p_access->info.b_eof = VLC_TRUE;
            return NULL;
        }
357
358
359
360
361
362
        /* Don't read too far */
        if( p_sys->i_sector + i_blocks >=
            p_sys->p_sectors[p_sys->i_track +1] )
        {
            i_blocks = p_sys->p_sectors[p_sys->i_track+1] - p_sys->i_sector;
        }
gbazin's avatar
   
gbazin committed
363
    }
364
    else
365
    {
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
        /* Check end of title - Normal */
        while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 1] )
        {
            if( p_access->info.i_title + 1 >= p_sys->i_titles )
            {
                p_access->info.b_eof = VLC_TRUE;
                return NULL;
            }

            p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SIZE |
                                       INPUT_UPDATE_META;
            p_access->info.i_title++;
            p_access->info.i_size =
                        p_sys->title[p_access->info.i_title]->i_size;
            p_access->info.i_pos = 0;
        }
        /* Don't read too far */
        if( p_sys->i_sector + i_blocks >=                                                       p_sys->p_sectors[p_access->info.i_title + 1] )
        {
            i_blocks = p_sys->p_sectors[ p_access->info.i_title + 1] -
                         p_sys->i_sector;
        }
388
    }
gbazin's avatar
   
gbazin committed
389

390
391
    /* Do the actual reading */
    if( !( p_block = block_New( p_access, i_blocks * CDDA_DATA_SIZE ) ) )
392
    {
393
        msg_Err( p_access, "cannot get a new block of size: %i",
394
                 i_blocks * CDDA_DATA_SIZE );
395
        return NULL;
gbazin's avatar
   
gbazin committed
396
397
    }

398
399
    if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
            p_sys->i_sector, p_block->p_buffer, i_blocks, CDDA_TYPE ) < 0 )
gbazin's avatar
   
gbazin committed
400
    {
401
        msg_Err( p_access, "cannot read sector %i", p_sys->i_sector );
402
        block_Release( p_block );
403

404
405
406
        /* Try to skip one sector (in case of bad sectors) */
        p_sys->i_sector++;
        p_access->info.i_pos += CDDA_DATA_SIZE;
407
        return NULL;
gbazin's avatar
   
gbazin committed
408
409
    }

410
411
412
    /* Update a few values */
    p_sys->i_sector += i_blocks;
    p_access->info.i_pos += p_block->i_buffer;
413
414

    return p_block;
gbazin's avatar
   
gbazin committed
415
416
}

417
418
/****************************************************************************
 * Seek
gbazin's avatar
   
gbazin committed
419
 ****************************************************************************/
420
static int Seek( access_t *p_access, int64_t i_pos )
gbazin's avatar
   
gbazin committed
421
{
422
    access_sys_t *p_sys = p_access->p_sys;
gbazin's avatar
   
gbazin committed
423

424
    /* Next sector to read */
425
426
427
428
429
430
    p_sys->i_sector = p_sys->p_sectors[
                                        (p_sys->b_single_track ?
                                         p_sys->i_track :
                                         p_access->info.i_title + 1)
                                      ] +
                                i_pos / CDDA_DATA_SIZE;
431
    p_access->info.i_pos = i_pos;
gbazin's avatar
   
gbazin committed
432

433
434
    return VLC_SUCCESS;
}
gbazin's avatar
   
gbazin committed
435

436
437
438
439
440
441
442
443
444
445
446
/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( access_t *p_access, int i_query, va_list args )
{
    access_sys_t *p_sys = p_access->p_sys;
    vlc_bool_t   *pb_bool;
    int          *pi_int;
    int64_t      *pi_64;
    input_title_t ***ppp_title;
    int i;
447
448
    char         *psz_title;
    vlc_meta_t  **pp_meta;
gbazin's avatar
   
gbazin committed
449

450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
    switch( i_query )
    {
        /* */
        case ACCESS_CAN_SEEK:
        case ACCESS_CAN_FASTSEEK:
        case ACCESS_CAN_PAUSE:
        case ACCESS_CAN_CONTROL_PACE:
            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
            *pb_bool = VLC_TRUE;
            break;

        /* */
        case ACCESS_GET_MTU:
            pi_int = (int*)va_arg( args, int * );
            *pi_int = CDDA_DATA_ONCE;
            break;

        case ACCESS_GET_PTS_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
469
            *pi_64 = var_GetInteger( p_access, "cdda-caching" ) * 1000;
470
471
472
473
474
475
476
            break;

        /* */
        case ACCESS_SET_PAUSE_STATE:
            break;

        case ACCESS_GET_TITLE_INFO:
477
478
            if( p_sys->b_single_track )
                return VLC_EGENERIC;
479
480
            ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
            pi_int    = (int*)va_arg( args, int* );
481
            *((int*)va_arg( args, int* )) = 1; /* Title offset */
482
483
484

            /* Duplicate title infos */
            *pi_int = p_sys->i_titles;
485
            *ppp_title = malloc(sizeof( input_title_t **) * p_sys->i_titles );
486
487
488
489
490
            for( i = 0; i < p_sys->i_titles; i++ )
            {
                (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
            }
            break;
gbazin's avatar
   
gbazin committed
491

492
        case ACCESS_SET_TITLE:
493
            if( p_sys->b_single_track ) return VLC_EGENERIC;
494
495
496
497
            i = (int)va_arg( args, int );
            if( i != p_access->info.i_title )
            {
                /* Update info */
498
                p_access->info.i_update |=
499
                    INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE|INPUT_UPDATE_META;
500
501
                p_access->info.i_title = i;
                p_access->info.i_size = p_sys->title[i]->i_size;
502
                p_access->info.i_pos = 0;
503
504
505
506
507

                /* Next sector to read */
                p_sys->i_sector = p_sys->p_sectors[i];
            }
            break;
gbazin's avatar
   
gbazin committed
508

509
        case ACCESS_GET_META:
510
             if( p_sys->b_single_track ) return VLC_EGENERIC;
511
512
513
514
515
             psz_title = malloc( strlen( _("Audio CD - Track ") ) + 5 );
             snprintf( psz_title, 100, _("Audio CD - Track %i" ),
                                        p_access->info.i_title+1 );
             pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
             *pp_meta = vlc_meta_New();
516
             vlc_meta_Add( *pp_meta, _(VLC_META_TITLE), psz_title );
517
518
519
             free( psz_title );
             break;

520
        case ACCESS_SET_SEEKPOINT:
521
        case ACCESS_SET_PRIVATE_ID_STATE:
522
            return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
523

524
        default:
525
            msg_Warn( p_access, "unimplemented query in control" );
526
            return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
527

528
529
    }
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
530
}
531
532
533
534
535
536
537

static int GetTracks( access_t *p_access, vlc_bool_t b_separate,
                      playlist_t *p_playlist, playlist_item_t *p_parent )
{
    access_sys_t *p_sys = p_access->p_sys;
    int i;
    playlist_item_t *p_item;
538
    char *psz_name;
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    p_sys->i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access),
                                          p_sys->vcddev, &p_sys->p_sectors );
    if( p_sys->i_titles < 0 )
    {
        msg_Err( p_access, "unable to count tracks" );
        return VLC_EGENERIC;;
    }
    else if( p_sys->i_titles <= 0 )
    {
        msg_Err( p_access, "no audio tracks found" );
        return VLC_EGENERIC;
    }

    if( b_separate )
    {
        if( p_parent->i_children == -1 )
        {
            playlist_LockItemToNode( p_playlist, p_parent );
        }
558
559
560
561
562
563
564
565
566
567
568
569
        psz_name = strdup( "Audio CD" );
        vlc_mutex_lock( &p_playlist->object_lock );
        playlist_ItemSetName( p_parent, psz_name );
        vlc_mutex_unlock( &p_playlist->object_lock );
        var_SetInteger( p_playlist, "item-change",
                        p_parent->input.i_id );
        free( psz_name );

#ifdef HAVE_LIBCDDB
        GetCDDBInfo( p_access, p_sys->i_titles, p_sys->p_sectors );
        if( p_sys->p_disc )
        {
zorglub's avatar
zorglub committed
570
            if( cddb_disc_get_title( p_sys->p_disc ) )
571
            {
zorglub's avatar
zorglub committed
572
573
                asprintf( &psz_name, "%s", cddb_disc_get_title( p_sys->p_disc )
                         );
574
575
576
577
578
579
580
581
582
                vlc_mutex_lock( &p_playlist->object_lock );
                playlist_ItemSetName( p_parent, psz_name );
                vlc_mutex_unlock( &p_playlist->object_lock );
                var_SetInteger( p_playlist, "item-change",
                                p_parent->input.i_id );
                free( psz_name );
            }
        }
#endif
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
    }

    /* Build title table */
    for( i = 0; i < p_sys->i_titles; i++ )
    {
        msg_Dbg( p_access, "track[%d] start=%d", i, p_sys->p_sectors[i] );
        if( !b_separate )
        {
            input_title_t *t = p_sys->title[i] = vlc_input_title_New();

            asprintf( &t->psz_name, _("Track %i"), i + 1 );
            t->i_size = ( p_sys->p_sectors[i+1] - p_sys->p_sectors[i] ) *
                        (int64_t)CDDA_DATA_SIZE;

            t->i_length = I64C(1000000) * t->i_size / 44100 / 4;
        }
        else
        {
601
            char *psz_uri;
602
603
            int i_path_len = p_access->psz_path ? strlen( p_access->psz_path )
                                                : 0;
604
605
606
607
            char *psz_opt;

            psz_name = malloc( strlen( _("Audio CD - Track ") ) + 5 );
            psz_opt = malloc( strlen( "cdda-track=" ) + 3 );
608
609
610
611

            psz_uri = (char*)malloc( i_path_len + 13 );
            snprintf( psz_uri, i_path_len + 13, "cdda://%s",
                                p_access->psz_path ? p_access->psz_path : "" );
612
613
614
615
616
            sprintf( psz_opt, "cdda-track=%i", i+1 );

            /* Define a "default name" */
            sprintf( psz_name, _("Audio CD - Track %i"), (i+1) );

617
618
619
620
            /* Create playlist items */
            p_item = playlist_ItemNewWithType( VLC_OBJECT( p_playlist ),
                                 psz_uri, psz_name, ITEM_TYPE_DISC );
            playlist_ItemAddOption( p_item, psz_opt );
621
622
623
624
625
626
627
628
#ifdef HAVE_LIBCDDB
            /* If we have CDDB info, change the name */
            if( p_sys->p_disc )
            {
                char *psz_result;
                cddb_track_t *t = cddb_disc_get_track( p_sys->p_disc, i );
                if( t!= NULL )
                {
zorglub's avatar
zorglub committed
629
                    if( cddb_track_get_title( t )  != NULL )
630
631
                    {
                        vlc_input_item_AddInfo( &p_item->input,
632
633
                                            _(VLC_META_INFO_CAT),
                                            _(VLC_META_TITLE),
zorglub's avatar
zorglub committed
634
                                            cddb_track_get_title( t ) );
635
636
                        if( p_item->input.psz_name )
                            free( p_item->input.psz_name );
zorglub's avatar
zorglub committed
637
638
                        asprintf( &p_item->input.psz_name, "%s",
                                  cddb_track_get_title( t ) );
639
640
641
642
643
                    }
                    psz_result = cddb_track_get_artist( t );
                    if( psz_result )
                    {
                        vlc_input_item_AddInfo( &p_item->input,
644
645
                                            _(VLC_META_INFO_CAT),
                                            _(VLC_META_ARTIST), psz_result );
646
647
648
649
                    }
                }
            }
#endif
650
651
652
            playlist_NodeAddItem( p_playlist, p_item,
                                  p_parent->pp_parents[0]->i_view,
                                  p_parent, PLAYLIST_APPEND, PLAYLIST_END );
653
            free( psz_uri ); free( psz_opt ); free( psz_name );
654
655
656
657
658
659
660
661
662
663
664
        }
    }

    p_sys->i_sector = p_sys->p_sectors[0];
    if( p_sys->b_separate_items )
    {
        p_sys->i_titles = 0;
    }

   return VLC_SUCCESS;
}
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

#ifdef HAVE_LIBCDDB
static void GetCDDBInfo( access_t *p_access, int i_titles, int *p_sectors )
{
    int i, i_matches;
    int64_t  i_length = 0, i_size = 0;
    cddb_conn_t  *p_cddb = cddb_new();

//    cddb_log_set_handler( CDDBLogHandler );

    if( !p_cddb )
    {
        msg_Warn( p_access, "unable to use CDDB" );
        goto cddb_destroy;
    }

    cddb_set_email_address( p_cddb, "vlc@videolan.org" );
    cddb_set_server_name( p_cddb, config_GetPsz( p_access, "cddb-server" ) );
    cddb_set_server_port( p_cddb, config_GetInt( p_access, "cddb-port" ) );

    /// \todo
    cddb_cache_disable( p_cddb );

//    cddb_cache_set_dir( p_cddb,
//                     config_GetPsz( p_access,
//                                    MODULE_STRING "-cddb-cachedir") );

    cddb_set_timeout( p_cddb, 10 );

    /// \todo
    cddb_http_disable( p_cddb);

    p_access->p_sys->p_disc = cddb_disc_new();

    if(! p_access->p_sys->p_disc )
    {
        msg_Err( p_access, "Unable to create CDDB disc structure." );
        goto cddb_end;
    }

    for(i = 0; i < i_titles ; i++ )
    {
        cddb_track_t *t = cddb_track_new();
        cddb_track_set_frame_offset(t, p_sectors[i] );
        cddb_disc_add_track( p_access->p_sys->p_disc, t );
        i_size = ( p_sectors[i+1] - p_sectors[i] ) *
                   (int64_t)CDDA_DATA_SIZE;
        i_length += I64C(1000000) * i_size / 44100 / 4  ;
    }

    cddb_disc_set_length( p_access->p_sys->p_disc, (int)(i_length/1000000) );

    if (!cddb_disc_calc_discid(p_access->p_sys->p_disc ))
    {
        msg_Err( p_access, "CDDB disc ID calculation failed" );
        goto cddb_destroy;
    }

    i_matches = cddb_query( p_cddb, p_access->p_sys->p_disc);

    if (i_matches > 0)
    {
        if (i_matches > 1)
             msg_Warn( p_access, "Found %d matches in CDDB. Using first one.",
                                 i_matches);
        cddb_read( p_cddb, p_access->p_sys->p_disc );

//        cddb_disc_print( p_access->p_sys->p_disc );
    }
    else
    {
        msg_Warn( p_access, "CDDB error: %s", cddb_error_str(errno));
    }

cddb_destroy:
    cddb_destroy( p_cddb);

cddb_end: ;
}
#endif /*HAVE_LIBCDDB*/