cdda.c 21 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * cdda.c : CD digital audio input module for vlc
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2000, 2003-2006, 2008-2009 VLC authors and VideoLAN
5
 * $Id$
Gildas Bazin's avatar
 
Gildas Bazin committed
6 7 8 9
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Gildas Bazin <gbazin@netcourrier.com>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Gildas Bazin's avatar
 
Gildas Bazin committed
13 14 15 16
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Gildas Bazin's avatar
 
Gildas Bazin committed
19
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
 
Gildas Bazin committed
23 24
 *****************************************************************************/

25 26
/**
 * Todo:
27
 *   - Improve CDDB support (non-blocking, ...)
28 29 30
 *   - Fix tracknumber in MRL
 */

Gildas Bazin's avatar
 
Gildas Bazin committed
31 32 33 34
/*****************************************************************************
 * Preamble
 *****************************************************************************/

35 36 37
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
38

39
#include <assert.h>
40 41 42
#include <math.h>
#include <stdlib.h>
#include <string.h>
43

44
#include <vlc_common.h>
45
#include <vlc_demux.h>
46
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac committed
47 48
#include <vlc_input.h>
#include <vlc_access.h>
49
#include <vlc_meta.h>
50
#include <vlc_charset.h> /* ToLocaleDup */
51
#include <vlc_url.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
52

53
#include "vcd/cdrom.h"  /* For CDDA_DATA_SIZE */
Gildas Bazin's avatar
 
Gildas Bazin committed
54

55
#ifdef HAVE_LIBCDDB
56 57
 #include <cddb/cddb.h>
 #include <errno.h>
58 59
#endif

60 61
static vcddev_t *DiscOpen(vlc_object_t *obj, const char *location,
                         const char *path, unsigned *restrict trackp)
62
{
63
    char *devpath;
64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    *trackp = var_InheritInteger(obj, "cdda-track");

    if (path != NULL)
        devpath = ToLocaleDup(path);
    else if (location[0] != '\0')
    {
#if (DIR_SEP_CHAR == '/')
        char *dec = vlc_uri_decode_duplicate(location);
        if (dec == NULL)
            return NULL;

        /* GNOME CDDA syntax */
        const char *sl = strrchr(dec, '/');
        if (sl != NULL)
        {
            if (sscanf(sl, "/Track %2u", trackp) == 1)
                dec[sl - dec] = '\0';
            else
                *trackp = 0;
        }

        if (unlikely(asprintf(&devpath, "/dev/%s", dec) == -1))
            devpath = NULL;
        free(dec);
#else
        (void) location;
        return NULL;
#endif
    }
94
    else
95 96 97
        devpath = var_InheritString(obj, "cd-audio");

    if (devpath == NULL)
98 99 100 101
        return NULL;

#if defined (_WIN32) || defined (__OS2__)
    /* Trim backslash after drive letter */
102 103
    if (devpath[0] != '\0' && !strcmp(&devpath[1], ":" DIR_SEP))
        devpath[2] = '\0';
104 105 106
#endif

    /* Open CDDA */
107
    vcddev_t *dev = ioctl_Open(obj, devpath);
108
    if (dev == NULL)
109 110
        msg_Warn(obj, "cannot open disc %s", devpath);
    free(devpath);
111 112 113 114

    return dev;
}

115
/* how many blocks Demux() will read in each iteration */
Laurent Aimar's avatar
Laurent Aimar committed
116 117
#define CDDA_BLOCKS_ONCE 20

118
struct demux_sys_t
Laurent Aimar's avatar
Laurent Aimar committed
119 120
{
    vcddev_t    *vcddev;                            /* vcd device descriptor */
121 122
    es_out_id_t *es;
    date_t       pts;
Laurent Aimar's avatar
Laurent Aimar committed
123

124 125 126
    unsigned start; /**< Track first sector */
    unsigned length; /**< Track total sectors */
    unsigned position; /**< Current offset within track sectors */
Laurent Aimar's avatar
Laurent Aimar committed
127 128
};

129
static int Demux(demux_t *demux)
Gildas Bazin's avatar
 
Gildas Bazin committed
130
{
131 132
    demux_sys_t *sys = demux->p_sys;
    unsigned count = CDDA_BLOCKS_ONCE;
Gildas Bazin's avatar
 
Gildas Bazin committed
133

134 135
    if (sys->position >= sys->length)
        return VLC_DEMUXER_EOF;
136

137 138
    if (sys->position + count >= sys->length)
        count = sys->length - sys->position;
Gildas Bazin's avatar
 
Gildas Bazin committed
139

140 141 142
    block_t *block = block_Alloc(count * CDDA_DATA_SIZE);
    if (unlikely(block == NULL))
        return VLC_DEMUXER_EOF;
Gildas Bazin's avatar
 
Gildas Bazin committed
143

144 145 146
    if (ioctl_ReadSectors(VLC_OBJECT(demux), sys->vcddev,
                          sys->start + sys->position,
                          block->p_buffer, count, CDDA_TYPE) < 0)
Gildas Bazin's avatar
 
Gildas Bazin committed
147
    {
148 149
        msg_Err(demux, "cannot read sector %u", sys->position);
        block_Release(block);
150

151 152 153
        /* Skip potentially bad sector */
        sys->position++;
        return VLC_DEMUXER_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
154 155
    }

156
    sys->position += count;
157

158 159 160
    block->i_nb_samples = block->i_buffer / 4;
    block->i_dts = block->i_pts = VLC_TS_0 + date_Get(&sys->pts);
    date_Increment(&sys->pts, block->i_nb_samples);
Gildas Bazin's avatar
 
Gildas Bazin committed
161

162 163 164
    es_out_Send(demux->out, sys->es, block);
    es_out_Control(demux->out, ES_OUT_SET_PCR, VLC_TS_0 + date_Get(&sys->pts));
    return VLC_DEMUXER_SUCCESS;
165
}
Gildas Bazin's avatar
 
Gildas Bazin committed
166

167
static int DemuxControl(demux_t *demux, int query, va_list args)
168
{
169 170 171 172 173
    demux_sys_t *sys = demux->p_sys;

    /* One sector is 40000/3 µs */
    static_assert (CDDA_DATA_SIZE * CLOCK_FREQ * 3 ==
                   4 * 44100 * INT64_C(40000), "Wrong time/sector ratio");
174

175
    switch (query)
176
    {
177 178 179 180
        case DEMUX_CAN_SEEK:
        case DEMUX_CAN_PAUSE:
        case DEMUX_CAN_CONTROL_PACE:
            *va_arg(args, bool*) = true;
181
            break;
182 183 184
        case DEMUX_GET_PTS_DELAY:
            *va_arg(args, int64_t *) =
                INT64_C(1000) * var_InheritInteger(demux, "disc-caching");
185
            break;
186 187

        case DEMUX_SET_PAUSE_STATE:
188 189
            break;

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
        case DEMUX_GET_POSITION:
            *va_arg(args, double *) = (double)(sys->position)
                                      / (double)(sys->length);
            break;
 
        case DEMUX_SET_POSITION:
            sys->position = lround(va_arg(args, double) * sys->length);
            break;

        case DEMUX_GET_LENGTH:
            *va_arg(args, mtime_t *) = (INT64_C(40000) * sys->length) / 3;
            break;
        case DEMUX_GET_TIME:
            *va_arg(args, mtime_t *) = (INT64_C(40000) * sys->position) / 3;
            break;
        case DEMUX_SET_TIME:
            sys->position = (va_arg(args, mtime_t) * 3) / INT64_C(40000);
207 208
            break;

209 210 211 212 213 214
        default:
            return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

215 216 217
static int DemuxOpen(vlc_object_t *obj)
{
    demux_t *demux = (demux_t *)obj;
218
    unsigned track;
219

220 221 222 223 224 225
    vcddev_t *dev = DiscOpen(obj, demux->psz_location, demux->psz_file,
                             &track);
    if (dev == NULL)
        return VLC_EGENERIC;

    if (track == 0 /* Whole disc -> use access plugin */)
226
        goto error;
227

228
    demux_sys_t *sys = vlc_malloc(obj, sizeof (*sys));
229
    if (unlikely(sys == NULL))
230
        goto error;
231

232 233
    demux->p_sys = sys;
    sys->vcddev = dev;
234 235 236 237 238 239
    sys->start = var_InheritInteger(obj, "cdda-first-sector");
    sys->length = var_InheritInteger(obj, "cdda-last-sector") - sys->start;

    /* Track number in input item */
    if (sys->start == (unsigned)-1 || sys->length == (unsigned)-1)
    {
240
        int *sectors = NULL; /* Track sectors */
241
        unsigned titles = ioctl_GetTracksMap(obj, dev, &sectors);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

        if (track > titles)
        {
            msg_Err(obj, "invalid track number: %u/%u", track, titles);
            free(sectors);
            goto error;
        }

        sys->start = sectors[track - 1];
        sys->length = sectors[track] - sys->start;
        free(sectors);
    }

    es_format_t fmt;

    es_format_Init(&fmt, AUDIO_ES, VLC_CODEC_S16L);
    fmt.audio.i_rate = 44100;
    fmt.audio.i_channels = 2;
    sys->es = es_out_Add(demux->out, &fmt);

    date_Init(&sys->pts, 44100, 1);
    date_Set(&sys->pts, 0);

    sys->position = 0;
    demux->pf_demux = Demux;
    demux->pf_control = DemuxControl;
    return VLC_SUCCESS;

error:
271
    ioctl_Close(obj, dev);
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    return VLC_EGENERIC;
}

static void DemuxClose(vlc_object_t *obj)
{
    demux_t *demux = (demux_t *)obj;
    demux_sys_t *sys = demux->p_sys;

    ioctl_Close(obj, sys->vcddev);
}

/*****************************************************************************
 * Access: local prototypes
 *****************************************************************************/
struct access_sys_t
{
    vcddev_t    *vcddev;                            /* vcd device descriptor */
289 290 291 292 293 294 295
    int         *p_sectors;                                 /* Track sectors */
    int          titles;
    int          cdtextc;
    vlc_meta_t **cdtextv;
#ifdef HAVE_LIBCDDB
    cddb_disc_t *cddb;
#endif
296 297
};

298
#ifdef HAVE_LIBCDDB
299
static cddb_disc_t *GetCDDBInfo( vlc_object_t *obj, int i_titles, int *p_sectors )
300
{
301
    if( !var_InheritBool( obj, "metadata-network-access" ) )
302
    {
303
        msg_Dbg( obj, "album art policy set to manual: not fetching" );
304 305 306 307 308 309 310
        return NULL;
    }

    /* */
    cddb_conn_t *p_cddb = cddb_new();
    if( !p_cddb )
    {
311
        msg_Warn( obj, "unable to use CDDB" );
312 313 314 315 316 317 318
        return NULL;
    }

    /* */

    cddb_http_enable( p_cddb );

319
    char *psz_tmp = var_InheritString( obj, "cddb-server" );
320 321 322 323 324 325
    if( psz_tmp )
    {
        cddb_set_server_name( p_cddb, psz_tmp );
        free( psz_tmp );
    }

326
    cddb_set_server_port( p_cddb, var_InheritInteger( obj, "cddb-port" ) );
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

    cddb_set_email_address( p_cddb, "vlc@videolan.org" );

    cddb_set_http_path_query( p_cddb, "/~cddb/cddb.cgi" );
    cddb_set_http_path_submit( p_cddb, "/~cddb/submit.cgi" );


    char *psz_cachedir;
    char *psz_temp = config_GetUserDir( VLC_CACHE_DIR );

    if( asprintf( &psz_cachedir, "%s" DIR_SEP "cddb", psz_temp ) > 0 ) {
        cddb_cache_enable( p_cddb );
        cddb_cache_set_dir( p_cddb, psz_cachedir );
        free( psz_cachedir );
    }
    free( psz_temp );

    cddb_set_timeout( p_cddb, 10 );

    /* */
    cddb_disc_t *p_disc = cddb_disc_new();
    if( !p_disc )
    {
350
        msg_Err( obj, "unable to create CDDB disc structure." );
351 352 353 354 355 356 357 358 359 360 361 362 363 364
        goto error;
    }

    int64_t i_length = 2000000; /* PreGap */
    for( int i = 0; i < i_titles; i++ )
    {
        cddb_track_t *t = cddb_track_new();
        cddb_track_set_frame_offset( t, p_sectors[i] + 150 );  /* Pregap offset */

        cddb_disc_add_track( p_disc, t );
        const int64_t i_size = ( p_sectors[i+1] - p_sectors[i] ) *
                               (int64_t)CDDA_DATA_SIZE;
        i_length += INT64_C(1000000) * i_size / 44100 / 4  ;

365
        msg_Dbg( obj, "Track %i offset: %i", i, p_sectors[i] + 150 );
366 367
    }

368
    msg_Dbg( obj, "Total length: %i", (int)(i_length/1000000) );
369 370 371 372
    cddb_disc_set_length( p_disc, (int)(i_length/1000000) );

    if( !cddb_disc_calc_discid( p_disc ) )
    {
373
        msg_Err( obj, "CDDB disc ID calculation failed" );
374 375 376 377 378 379
        goto error;
    }

    const int i_matches = cddb_query( p_cddb, p_disc );
    if( i_matches < 0 )
    {
380
        msg_Warn( obj, "CDDB error: %s", cddb_error_str(errno) );
381
        goto error;
382
    }
383 384
    else if( i_matches == 0 )
    {
385
        msg_Dbg( obj, "Couldn't find any matches in CDDB." );
386 387 388
        goto error;
    }
    else if( i_matches > 1 )
389
        msg_Warn( obj, "found %d matches in CDDB. Using first one.", i_matches );
390 391 392 393 394 395 396 397 398 399 400

    cddb_read( p_cddb, p_disc );

    cddb_destroy( p_cddb);
    return p_disc;

error:
    if( p_disc )
        cddb_disc_destroy( p_disc );
    cddb_destroy( p_cddb );
    return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
401
}
402
#endif /* HAVE_LIBCDDB */
403

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
404
static void AccessGetMeta(stream_t *access, vlc_meta_t *meta)
405
{
406 407
    access_sys_t *sys = access->p_sys;
    const char *str;
408

409
    vlc_meta_SetTitle(meta, "Audio CD");
410

411 412 413
    /* Retrieve CD-TEXT information */
    if (sys->cdtextc > 0 && sys->cdtextv[0] != NULL)
        vlc_meta_Merge(meta, sys->cdtextv[0]);
414

415 416 417 418 419
/* Return true if the given string is not NULL and not empty */
#define NONEMPTY( psz ) ( (psz) && *(psz) )
/* If the given string is NULL or empty, fill it by the return value of 'code' */
#define ON_EMPTY( psz, code ) do { if( !NONEMPTY( psz) ) { (psz) = code; } } while(0)

420
    /* Retrieve CDDB information (preferred over CD-TEXT) */
421
#ifdef HAVE_LIBCDDB
422
    if (sys->cddb != NULL)
423
    {
424 425 426
        str = cddb_disc_get_title(sys->cddb);
        if (NONEMPTY(str))
            vlc_meta_SetTitle(meta, str);
427

428 429 430 431 432 433
        str = cddb_disc_get_genre(sys->cddb);
        if (NONEMPTY(str))
            vlc_meta_SetGenre(meta, str);

        const unsigned year = cddb_disc_get_year(sys->cddb);
        if (year != 0)
434
        {
435 436 437 438
            char yearbuf[5];

            snprintf(yearbuf, sizeof (yearbuf), "%u", year);
            vlc_meta_SetDate(meta, yearbuf);
439 440
        }

441 442 443
        /* Set artist only if identical across tracks */
        str = cddb_disc_get_artist(sys->cddb);
        if (NONEMPTY(str))
444
        {
445
            for (int i = 0; i < sys->titles; i++)
446
            {
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
                cddb_track_t *t = cddb_disc_get_track(sys->cddb, i);
                if (t == NULL)
                    continue;

                const char *track_artist = cddb_track_get_artist(t);
                if (NONEMPTY(track_artist))
                {
                    if (str == NULL)
                        str = track_artist;
                    else
                    if (strcmp(str, track_artist))
                    {
                        str = NULL;
                        break;
                    }
                }
463 464
            }
        }
465
    }
466
#endif
467
}
468

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
469
static int ReadDir(stream_t *access, input_item_node_t *node)
470 471
{
    access_sys_t *sys = access->p_sys;
472

473
    /* Build title table */
474
    for (int i = 0; i < sys->titles; i++)
475
    {
476
        msg_Dbg(access, "track[%d] start=%d", i, sys->p_sectors[i]);
477

478 479
        /* Initial/default name */
        char *name;
480

481 482
        if (unlikely(asprintf(&name, _("Audio CD - Track %02i"), i + 1) == -1))
            name = NULL;
483 484

        /* Create playlist items */
485 486 487
        const mtime_t duration =
            (mtime_t)(sys->p_sectors[i + 1] - sys->p_sectors[i])
            * CDDA_DATA_SIZE * CLOCK_FREQ / 44100 / 2 / 2;
488

489 490 491 492
        input_item_t *item = input_item_NewDisc(access->psz_url,
                                                (name != NULL) ? name :
                                                access->psz_url, duration);
        free(name);
493

494
        if (unlikely(item == NULL))
495 496
            continue;

497 498
        char *opt;
        if (likely(asprintf(&opt, "cdda-track=%i", i + 1) != -1))
499
        {
500 501
            input_item_AddOption(item, opt, VLC_INPUT_OPTION_TRUSTED);
            free(opt);
502
        }
503 504 505

        if (likely(asprintf(&opt, "cdda-first-sector=%i",
                            sys->p_sectors[i]) != -1))
506
        {
507 508
            input_item_AddOption(item, opt, VLC_INPUT_OPTION_TRUSTED);
            free(opt);
509
        }
510 511 512

        if (likely(asprintf(&opt, "cdda-last-sector=%i",
                            sys->p_sectors[i + 1]) != -1))
513
        {
514 515
            input_item_AddOption(item, opt, VLC_INPUT_OPTION_TRUSTED);
            free(opt);
516
        }
517

518 519 520 521 522 523
        const char *title = NULL;
        const char *artist = NULL;
        const char *album = NULL;
        const char *genre = NULL;
        const char *description = NULL;
        int year = 0;
524

525
#ifdef HAVE_LIBCDDB
526
        if (sys->cddb != NULL)
527
        {
528 529
            cddb_track_t *t = cddb_disc_get_track(sys->cddb, i);
            if (t != NULL)
530
            {
531 532
                title = cddb_track_get_title(t);
                artist = cddb_track_get_artist(t);
533
            }
534 535 536 537 538

            ON_EMPTY(artist, cddb_disc_get_artist(sys->cddb));
            album = cddb_disc_get_title(sys->cddb);
            genre = cddb_disc_get_genre(sys->cddb);
            year = cddb_disc_get_year(sys->cddb);
539 540
        }
#endif
541
        const vlc_meta_t *m;
542

543
        if (sys->cdtextc > 0 && (m = sys->cdtextv[0]) != NULL)
544
        {
545 546 547 548
            ON_EMPTY(artist, vlc_meta_Get(m, vlc_meta_Artist));
            ON_EMPTY(album,  vlc_meta_Get(m, vlc_meta_Album));
            ON_EMPTY(genre,  vlc_meta_Get(m, vlc_meta_Genre));
            description =    vlc_meta_Get(m, vlc_meta_Description);
549 550
        }

551 552 553 554 555 556 557
        if (i + 1 < sys->cdtextc && (m = sys->cdtextv[i + 1]) != NULL)
        {
            ON_EMPTY(title,       vlc_meta_Get(m, vlc_meta_Title));
            ON_EMPTY(artist,      vlc_meta_Get(m, vlc_meta_Artist));
            ON_EMPTY(genre,       vlc_meta_Get(m, vlc_meta_Genre));
            ON_EMPTY(description, vlc_meta_Get(m, vlc_meta_Description));
        }
558

559
        if (NONEMPTY(title))
560
        {
561 562
            input_item_SetName(item, title);
            input_item_SetTitle(item, title);
563
        }
564

565 566 567 568 569
        if (NONEMPTY(artist))
            input_item_SetArtist(item, artist);

        if (NONEMPTY(genre))
            input_item_SetGenre(item, genre);
570

571 572
        if (NONEMPTY(description))
            input_item_SetDescription(item, description);
573

574 575
        if (NONEMPTY(album))
            input_item_SetAlbum(item, album);
576

577 578 579
        if (year != 0)
        {
            char yearbuf[5];
580

581 582 583
            snprintf(yearbuf, sizeof (yearbuf), "%u", year);
            input_item_SetDate(item, yearbuf);
        }
584

585 586 587
        char num[4];
        snprintf(num, sizeof (num), "%d", i + 1);
        input_item_SetTrackNum(item, num);
588

589 590
        input_item_node_AppendItem(node, item);
        input_item_Release(item);
591
    }
592 593
#undef ON_EMPTY
#undef NONEMPTY
594
    return VLC_SUCCESS;
595 596
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
597
static int AccessControl(stream_t *access, int query, va_list args)
598 599 600 601 602 603 604 605 606
{
    if (query == STREAM_GET_META)
    {
        AccessGetMeta(access, va_arg(args, vlc_meta_t *));
        return VLC_SUCCESS;
    }
    return access_vaDirectoryControlHelper(access, query, args);
}

607
static int AccessOpen(vlc_object_t *obj)
608
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
609
    stream_t *access = (stream_t *)obj;
610 611 612 613 614 615
    unsigned track;

    vcddev_t *dev = DiscOpen(obj, access->psz_location, access->psz_filepath,
                             &track);
    if (dev == NULL)
        return VLC_EGENERIC;
616

617 618 619
    if (track != 0 /* Only whole discs here */)
    {
        ioctl_Close(obj, dev);
620
        return VLC_EGENERIC;
621
    }
622

623
    access_sys_t *sys = vlc_malloc(obj, sizeof (*sys));
624
    if (unlikely(sys == NULL))
625
    {
626 627
        ioctl_Close(obj, dev);
        return VLC_ENOMEM;
628
    }
629 630

    sys->vcddev = dev;
631
    sys->p_sectors = NULL;
632

633
    sys->titles = ioctl_GetTracksMap(obj, dev, &sys->p_sectors);
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
    if (sys->titles < 0)
    {
        msg_Err(obj, "cannot count tracks");
        goto error;
    }

    if (sys->titles == 0)
    {
        msg_Err(obj, "no audio tracks found");
        goto error;
    }

#ifdef HAVE_LIBCDDB
    msg_Dbg(obj, "retrieving metadata with CDDB");

    sys->cddb = GetCDDBInfo(obj, sys->titles, sys->p_sectors);
    if (sys->cddb != NULL)
        msg_Dbg(obj, "disc ID: 0x%08x", cddb_disc_get_discid(sys->cddb));
    else
        msg_Dbg(obj, "CDDB failure");
#endif

656
    if (ioctl_GetCdText(obj, dev, &sys->cdtextv, &sys->cdtextc))
657 658 659 660 661 662
    {
        msg_Dbg(obj, "CD-TEXT information missing");
        sys->cdtextv = NULL;
        sys->cdtextc = 0;
    }

663 664 665 666 667 668
    access->p_sys = sys;
    access->pf_read = NULL;
    access->pf_block = NULL;
    access->pf_readdir = ReadDir;
    access->pf_seek = NULL;
    access->pf_control = AccessControl;
669
    return VLC_SUCCESS;
670

671
error:
672
    free(sys->p_sectors);
673
    ioctl_Close(obj, dev);
674 675
    return VLC_EGENERIC;
}
676

677
static void AccessClose(vlc_object_t *obj)
678
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
679
    stream_t *access = (stream_t *)obj;
680
    access_sys_t *sys = access->p_sys;
681

682 683 684 685 686 687 688 689 690 691 692 693 694
    for (int i = 0; i < sys->cdtextc; i++)
    {
        vlc_meta_t *meta = sys->cdtextv[i];
        if (meta != NULL)
            vlc_meta_Delete(meta);
    }
    free(sys->cdtextv);

#ifdef HAVE_LIBCDDB
    if (sys->cddb != NULL)
        cddb_disc_destroy(sys->cddb);
#endif

695
    free(sys->p_sectors);
696
    ioctl_Close(obj, sys->vcddev);
697
}
698

699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
/*****************************************************************************
 * Module descriptior
 *****************************************************************************/
#define CDAUDIO_DEV_TEXT N_("Audio CD device")
#if defined( _WIN32 ) || defined( __OS2__ )
# define CDAUDIO_DEV_LONGTEXT N_( \
    "This is the default Audio CD drive (or file) to use. Don't forget the " \
    "colon after the drive letter (e.g. D:)")
# define CD_DEVICE      "D:"
#else
# define CDAUDIO_DEV_LONGTEXT N_( \
    "This is the default Audio CD device to use." )
# if defined(__OpenBSD__)
#  define CD_DEVICE      "/dev/cd0c"
# elif defined(__linux__)
#  define CD_DEVICE      "/dev/sr0"
# else
#  define CD_DEVICE      "/dev/cdrom"
# endif
#endif
719

720 721 722 723 724 725
vlc_module_begin ()
    set_shortname( N_("Audio CD") )
    set_description( N_("Audio CD input") )
    set_capability( "access", 10 )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
726
    set_callbacks(AccessOpen, AccessClose)
727

728 729
    add_loadfile( "cd-audio", CD_DEVICE, CDAUDIO_DEV_TEXT,
                  CDAUDIO_DEV_LONGTEXT, false )
730

731 732 733 734 735 736 737
    add_usage_hint( N_("[cdda:][device][@[track]]") )
    add_integer( "cdda-track", 0 , NULL, NULL, true )
        change_volatile ()
    add_integer( "cdda-first-sector", -1, NULL, NULL, true )
        change_volatile ()
    add_integer( "cdda-last-sector", -1, NULL, NULL, true )
        change_volatile ()
738

739 740 741 742 743 744 745
#ifdef HAVE_LIBCDDB
    add_string( "cddb-server", "freedb.videolan.org", N_( "CDDB Server" ),
            N_( "Address of the CDDB server to use." ), true )
    add_integer( "cddb-port", 80, N_( "CDDB port" ),
            N_( "CDDB Server port to use." ), true )
        change_integer_range( 1, 65535 )
#endif
746

747
    add_shortcut( "cdda", "cddasimple" )
748 749 750 751

    add_submodule()
    set_capability( "access_demux", 10 )
    set_callbacks(DemuxOpen, DemuxClose)
752
vlc_module_end ()