1 /*****************************************************************************
2 * cdda.c : CD digital audio input module for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2003-2006, 2008-2009 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Gildas Bazin <gbazin@netcourrier.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
27 * - Improve CDDB support (non-blocking, cache, ...)
28 * - Fix tracknumber in MRL
31 /*****************************************************************************
33 *****************************************************************************/
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_input.h>
43 #include <vlc_access.h>
45 #include <vlc_charset.h> /* ToLocaleDup */
47 #include <vlc_codecs.h> /* For WAVEHEADER */
48 #include "vcd/cdrom.h" /* For CDDA_DATA_SIZE */
51 #include <cddb/cddb.h>
55 /*****************************************************************************
57 *****************************************************************************/
58 static int Open ( vlc_object_t
* );
59 static void Close( vlc_object_t
* );
61 #define CACHING_TEXT N_("Caching value in ms")
62 #define CACHING_LONGTEXT N_( \
63 "Default caching value for Audio CDs. This " \
64 "value should be set in milliseconds." )
67 set_shortname( N_("Audio CD") )
68 set_description( N_("Audio CD input") )
69 set_capability( "access", 10 )
70 set_category( CAT_INPUT
)
71 set_subcategory( SUBCAT_INPUT_ACCESS
)
72 set_callbacks( Open
, Close
)
74 add_usage_hint( N_("[cdda:][device][@[track]]") )
75 add_integer( "cdda-caching", DEFAULT_PTS_DELAY
/ 1000, NULL
, CACHING_TEXT
,
76 CACHING_LONGTEXT
, true )
79 add_integer( "cdda-track", 0 , NULL
, NULL
, NULL
, true )
81 add_integer( "cdda-first-sector", -1, NULL
, NULL
, NULL
, true )
83 add_integer( "cdda-last-sector", -1, NULL
, NULL
, NULL
, true )
87 add_string( "cddb-server", "freedb.freedb.org", NULL
, N_( "CDDB Server" ),
88 N_( "Address of the CDDB server to use." ), true )
89 add_integer( "cddb-port", 8880, NULL
, N_( "CDDB port" ),
90 N_( "CDDB Server port to use." ), true )
93 add_shortcut( "cdda" )
94 add_shortcut( "cddasimple" )
98 /* how many blocks VCDRead will read in each loop */
99 #define CDDA_BLOCKS_ONCE 20
100 #define CDDA_DATA_ONCE (CDDA_BLOCKS_ONCE * CDDA_DATA_SIZE)
102 /*****************************************************************************
103 * Access: local prototypes
104 *****************************************************************************/
107 vcddev_t
*vcddev
; /* vcd device descriptor */
109 /* Current position */
110 int i_sector
; /* Current Sector */
111 int *p_sectors
; /* Track sectors */
113 /* Wave header for the output data */
114 WAVEHEADER waveheader
;
122 static block_t
*Block( access_t
* );
123 static int Seek( access_t
*, uint64_t );
124 static int Control( access_t
*, int, va_list );
126 static int GetTracks( access_t
*p_access
, input_item_t
*p_current
);
129 static cddb_disc_t
*GetCDDBInfo( access_t
*p_access
, int i_titles
, int *p_sectors
);
132 /*****************************************************************************
134 *****************************************************************************/
135 static int Open( vlc_object_t
*p_this
)
137 access_t
*p_access
= (access_t
*)p_this
;
142 if( !p_access
->psz_path
|| !*p_access
->psz_path
)
144 /* Only when selected */
145 if( !p_access
->psz_access
|| !*p_access
->psz_access
)
148 psz_name
= var_CreateGetString( p_this
, "cd-audio" );
149 if( !psz_name
|| !*psz_name
)
155 else psz_name
= ToLocaleDup( p_access
->psz_path
);
158 if( psz_name
[0] && psz_name
[1] == ':' &&
159 psz_name
[2] == '\\' && psz_name
[3] == '\0' ) psz_name
[2] = '\0';
163 if( (vcddev
= ioctl_Open( VLC_OBJECT(p_access
), psz_name
) ) == NULL
)
165 msg_Warn( p_access
, "could not open %s", psz_name
);
171 /* Set up p_access */
172 STANDARD_BLOCK_ACCESS_INIT
173 p_sys
->vcddev
= vcddev
;
175 /* Do we play a single track ? */
176 p_sys
->i_track
= var_CreateGetInteger( p_access
, "cdda-track" ) - 1;
178 if( p_sys
->i_track
< 0 )
180 /* We only do separate items if the whole disc is requested */
181 input_thread_t
*p_input
= access_GetParentInput( p_access
);
186 input_item_t
*p_current
= input_GetItem( p_input
);
188 i_ret
= GetTracks( p_access
, p_current
);
190 vlc_object_release( p_input
);
197 /* Build a WAV header for the output data */
198 memset( &p_sys
->waveheader
, 0, sizeof(WAVEHEADER
) );
199 SetWLE( &p_sys
->waveheader
.Format
, 1 ); /*WAVE_FORMAT_PCM*/
200 SetWLE( &p_sys
->waveheader
.BitsPerSample
, 16);
201 p_sys
->waveheader
.MainChunkID
= VLC_FOURCC('R', 'I', 'F', 'F');
202 p_sys
->waveheader
.Length
= 0; /* we just don't know */
203 p_sys
->waveheader
.ChunkTypeID
= VLC_FOURCC('W', 'A', 'V', 'E');
204 p_sys
->waveheader
.SubChunkID
= VLC_FOURCC('f', 'm', 't', ' ');
205 SetDWLE( &p_sys
->waveheader
.SubChunkLength
, 16);
206 SetWLE( &p_sys
->waveheader
.Modus
, 2);
207 SetDWLE( &p_sys
->waveheader
.SampleFreq
, 44100);
208 SetWLE( &p_sys
->waveheader
.BytesPerSample
,
209 2 /*Modus*/ * 16 /*BitsPerSample*/ / 8 );
210 SetDWLE( &p_sys
->waveheader
.BytesPerSec
,
211 2*16/8 /*BytesPerSample*/ * 44100 /*SampleFreq*/ );
212 p_sys
->waveheader
.DataChunkID
= VLC_FOURCC('d', 'a', 't', 'a');
213 p_sys
->waveheader
.DataLength
= 0; /* we just don't know */
215 p_sys
->i_first_sector
= var_CreateGetInteger( p_access
,
216 "cdda-first-sector" );
217 p_sys
->i_last_sector
= var_CreateGetInteger( p_access
,
218 "cdda-last-sector" );
219 /* Tracknumber in MRL */
220 if( p_sys
->i_first_sector
< 0 || p_sys
->i_last_sector
< 0 )
222 const int i_titles
= ioctl_GetTracksMap( VLC_OBJECT(p_access
),
223 p_sys
->vcddev
, &p_sys
->p_sectors
);
224 if( p_sys
->i_track
>= i_titles
)
226 msg_Err( p_access
, "invalid track number" );
229 p_sys
->i_first_sector
= p_sys
->p_sectors
[p_sys
->i_track
];
230 p_sys
->i_last_sector
= p_sys
->p_sectors
[p_sys
->i_track
+1];
233 p_sys
->i_sector
= p_sys
->i_first_sector
;
234 p_access
->info
.i_size
= (p_sys
->i_last_sector
- p_sys
->i_first_sector
)
235 * (int64_t)CDDA_DATA_SIZE
;
239 var_Create( p_access
, "cdda-caching", VLC_VAR_INTEGER
|VLC_VAR_DOINHERIT
);
244 free( p_sys
->p_sectors
);
245 ioctl_Close( VLC_OBJECT(p_access
), p_sys
->vcddev
);
250 /*****************************************************************************
252 *****************************************************************************/
253 static void Close( vlc_object_t
*p_this
)
255 access_t
*p_access
= (access_t
*)p_this
;
256 access_sys_t
*p_sys
= p_access
->p_sys
;
258 free( p_sys
->p_sectors
);
259 ioctl_Close( p_this
, p_sys
->vcddev
);
263 /*****************************************************************************
264 * Block: read data (CDDA_DATA_ONCE)
265 *****************************************************************************/
266 static block_t
*Block( access_t
*p_access
)
268 access_sys_t
*p_sys
= p_access
->p_sys
;
269 int i_blocks
= CDDA_BLOCKS_ONCE
;
272 if( p_sys
->i_track
< 0 ) p_access
->info
.b_eof
= true;
274 /* Check end of file */
275 if( p_access
->info
.b_eof
) return NULL
;
277 if( !p_sys
->b_header
)
279 /* Return only the header */
280 p_block
= block_New( p_access
, sizeof( WAVEHEADER
) );
281 memcpy( p_block
->p_buffer
, &p_sys
->waveheader
, sizeof(WAVEHEADER
) );
282 p_sys
->b_header
= true;
286 if( p_sys
->i_sector
>= p_sys
->i_last_sector
)
288 p_access
->info
.b_eof
= true;
292 /* Don't read too far */
293 if( p_sys
->i_sector
+ i_blocks
>= p_sys
->i_last_sector
)
294 i_blocks
= p_sys
->i_last_sector
- p_sys
->i_sector
;
296 /* Do the actual reading */
297 if( !( p_block
= block_New( p_access
, i_blocks
* CDDA_DATA_SIZE
) ) )
299 msg_Err( p_access
, "cannot get a new block of size: %i",
300 i_blocks
* CDDA_DATA_SIZE
);
304 if( ioctl_ReadSectors( VLC_OBJECT(p_access
), p_sys
->vcddev
,
305 p_sys
->i_sector
, p_block
->p_buffer
, i_blocks
, CDDA_TYPE
) < 0 )
307 msg_Err( p_access
, "cannot read sector %i", p_sys
->i_sector
);
308 block_Release( p_block
);
310 /* Try to skip one sector (in case of bad sectors) */
312 p_access
->info
.i_pos
+= CDDA_DATA_SIZE
;
316 /* Update a few values */
317 p_sys
->i_sector
+= i_blocks
;
318 p_access
->info
.i_pos
+= p_block
->i_buffer
;
323 /****************************************************************************
325 ****************************************************************************/
326 static int Seek( access_t
*p_access
, uint64_t i_pos
)
328 access_sys_t
*p_sys
= p_access
->p_sys
;
330 /* Next sector to read */
331 p_sys
->i_sector
= p_sys
->i_first_sector
+ i_pos
/ CDDA_DATA_SIZE
;
332 assert( p_sys
->i_sector
>= 0 );
333 p_access
->info
.i_pos
= i_pos
;
338 /*****************************************************************************
340 *****************************************************************************/
341 static int Control( access_t
*p_access
, int i_query
, va_list args
)
345 case ACCESS_CAN_SEEK
:
346 case ACCESS_CAN_FASTSEEK
:
347 case ACCESS_CAN_PAUSE
:
348 case ACCESS_CAN_CONTROL_PACE
:
349 *va_arg( args
, bool* ) = true;
352 case ACCESS_GET_PTS_DELAY
:
353 *va_arg( args
, int64_t * ) =
354 var_GetInteger( p_access
, "cdda-caching" ) * INT64_C(1000);
357 case ACCESS_SET_PAUSE_STATE
:
360 case ACCESS_GET_TITLE_INFO
:
361 case ACCESS_SET_TITLE
:
362 case ACCESS_GET_META
:
363 case ACCESS_SET_SEEKPOINT
:
364 case ACCESS_SET_PRIVATE_ID_STATE
:
365 case ACCESS_GET_CONTENT_TYPE
:
369 msg_Warn( p_access
, "unimplemented query in control" );
375 static int GetTracks( access_t
*p_access
, input_item_t
*p_current
)
377 access_sys_t
*p_sys
= p_access
->p_sys
;
379 const int i_titles
= ioctl_GetTracksMap( VLC_OBJECT(p_access
),
380 p_sys
->vcddev
, &p_sys
->p_sectors
);
384 msg_Err( p_access
, "unable to count tracks" );
385 else if( i_titles
<= 0 )
386 msg_Err( p_access
, "no audio tracks found" );
387 return VLC_EGENERIC
;;
391 input_item_SetName( p_current
, "Audio CD" );
393 const char *psz_album
= NULL
;
394 const char *psz_year
= NULL
;
395 const char *psz_genre
= NULL
;
396 const char *psz_artist
= NULL
;
397 const char *psz_description
= NULL
;
399 /* Return true if the given string is not NULL and not empty */
400 #define NONEMPTY( psz ) ( (psz) && *(psz) )
401 /* If the given string is NULL or empty, fill it by the return value of 'code' */
402 #define ON_EMPTY( psz, code ) do { if( !NONEMPTY( psz) ) { (psz) = code; } } while(0)
404 /* Retreive CDDB informations */
406 char psz_year_buffer
[4+1];
407 msg_Dbg( p_access
, "fetching infos with CDDB" );
408 cddb_disc_t
*p_disc
= GetCDDBInfo( p_access
, i_titles
, p_sys
->p_sectors
);
411 psz_album
= cddb_disc_get_title( p_disc
);
412 psz_genre
= cddb_disc_get_genre( p_disc
);
415 const unsigned i_year
= cddb_disc_get_year( p_disc
);
418 psz_year
= psz_year_buffer
;
419 snprintf( psz_year_buffer
, sizeof(psz_year_buffer
), "%u", i_year
);
422 /* Set artist only if unique */
423 for( int i
= 0; i
< i_titles
; i
++ )
425 cddb_track_t
*t
= cddb_disc_get_track( p_disc
, i
);
428 const char *psz_track_artist
= cddb_track_get_artist( t
);
429 if( psz_artist
&& psz_track_artist
&&
430 strcmp( psz_artist
, psz_track_artist
) )
435 psz_artist
= psz_track_artist
;
441 vlc_meta_t
**pp_cd_text
;
444 if( ioctl_GetCdText( VLC_OBJECT(p_access
), p_sys
->vcddev
, &pp_cd_text
, &i_cd_text
) )
446 msg_Dbg( p_access
, "CD-TEXT information missing" );
451 /* Retrieve CD-TEXT informations but prefer CDDB */
452 if( i_cd_text
> 0 && pp_cd_text
[0] )
454 const vlc_meta_t
*p_disc
= pp_cd_text
[0];
455 ON_EMPTY( psz_album
, vlc_meta_Get( p_disc
, vlc_meta_Album
) );
456 ON_EMPTY( psz_genre
, vlc_meta_Get( p_disc
, vlc_meta_Genre
) );
457 ON_EMPTY( psz_artist
, vlc_meta_Get( p_disc
, vlc_meta_Artist
) );
458 ON_EMPTY( psz_description
, vlc_meta_Get( p_disc
, vlc_meta_Description
) );
461 if( NONEMPTY( psz_album
) )
463 input_item_SetName( p_current
, psz_album
);
464 input_item_SetAlbum( p_current
, psz_album
);
467 if( NONEMPTY( psz_genre
) )
468 input_item_SetGenre( p_current
, psz_genre
);
470 if( NONEMPTY( psz_artist
) )
471 input_item_SetArtist( p_current
, psz_artist
);
473 if( NONEMPTY( psz_year
) )
474 input_item_SetDate( p_current
, psz_year
);
476 if( NONEMPTY( psz_description
) )
477 input_item_SetDescription( p_current
, psz_description
);
479 const mtime_t i_duration
= (int64_t)( p_sys
->p_sectors
[i_titles
] - p_sys
->p_sectors
[0] ) *
480 CDDA_DATA_SIZE
* 1000000 / 44100 / 2 / 2;
481 input_item_SetDuration( p_current
, i_duration
);
483 input_item_node_t
*p_root
= input_item_node_Create( p_current
);
485 /* Build title table */
486 for( int i
= 0; i
< i_titles
; i
++ )
488 input_item_t
*p_input_item
;
490 char *psz_uri
, *psz_opt
, *psz_first
, *psz_last
;
493 msg_Dbg( p_access
, "track[%d] start=%d", i
, p_sys
->p_sectors
[i
] );
496 if( asprintf( &psz_uri
, "cdda://%s", p_access
->psz_path
) == -1 )
498 if( asprintf( &psz_opt
, "cdda-track=%i", i
+1 ) == -1 )
500 if( asprintf( &psz_first
, "cdda-first-sector=%i",p_sys
->p_sectors
[i
] ) == -1 )
502 if( asprintf( &psz_last
, "cdda-last-sector=%i", p_sys
->p_sectors
[i
+1] ) == -1 )
505 /* Define a "default name" */
506 if( asprintf( &psz_name
, _("Audio CD - Track %02i"), (i
+1) ) == -1 )
509 /* Create playlist items */
510 const mtime_t i_duration
= (int64_t)( p_sys
->p_sectors
[i
+1] - p_sys
->p_sectors
[i
] ) *
511 CDDA_DATA_SIZE
* 1000000 / 44100 / 2 / 2;
512 p_input_item
= input_item_NewWithType( VLC_OBJECT( p_access
),
513 psz_uri
, psz_name
, 0, NULL
, 0, i_duration
,
515 input_item_CopyOptions( p_current
, p_input_item
);
516 input_item_AddOption( p_input_item
, psz_first
, VLC_INPUT_OPTION_TRUSTED
);
517 input_item_AddOption( p_input_item
, psz_last
, VLC_INPUT_OPTION_TRUSTED
);
518 input_item_AddOption( p_input_item
, psz_opt
, VLC_INPUT_OPTION_TRUSTED
);
520 const char *psz_track_title
= NULL
;
521 const char *psz_track_artist
= NULL
;
522 const char *psz_track_genre
= NULL
;
523 const char *psz_track_description
= NULL
;
526 /* Retreive CDDB informations */
529 cddb_track_t
*t
= cddb_disc_get_track( p_disc
, i
);
532 psz_track_title
= cddb_track_get_title( t
);
533 psz_track_artist
= cddb_track_get_artist( t
);
538 /* Retreive CD-TEXT informations but prefer CDDB */
539 if( i
+1 < i_cd_text
&& pp_cd_text
[i
+1] )
541 const vlc_meta_t
*t
= pp_cd_text
[i
+1];
543 ON_EMPTY( psz_track_title
, vlc_meta_Get( t
, vlc_meta_Title
) );
544 ON_EMPTY( psz_track_artist
, vlc_meta_Get( t
, vlc_meta_Artist
) );
545 ON_EMPTY( psz_track_genre
, vlc_meta_Get( t
, vlc_meta_Genre
) );
546 ON_EMPTY( psz_track_description
, vlc_meta_Get( t
, vlc_meta_Description
) );
550 ON_EMPTY( psz_track_artist
, psz_artist
);
551 ON_EMPTY( psz_track_genre
, psz_genre
);
552 ON_EMPTY( psz_track_description
, psz_description
);
555 if( NONEMPTY( psz_track_title
) )
557 input_item_SetName( p_input_item
, psz_track_title
);
558 input_item_SetTitle( p_input_item
, psz_track_title
);
561 if( NONEMPTY( psz_track_artist
) )
562 input_item_SetArtist( p_input_item
, psz_track_artist
);
564 if( NONEMPTY( psz_track_genre
) )
565 input_item_SetGenre( p_input_item
, psz_track_genre
);
567 if( NONEMPTY( psz_track_description
) )
568 input_item_SetDescription( p_input_item
, psz_track_description
);
570 if( NONEMPTY( psz_album
) )
571 input_item_SetAlbum( p_input_item
, psz_album
);
573 if( NONEMPTY( psz_year
) )
574 input_item_SetDate( p_input_item
, psz_year
);
577 snprintf( psz_num
, sizeof(psz_num
), "%d", 1+i
);
578 input_item_SetTrackNum( p_input_item
, psz_num
);
580 input_item_AddSubItem( p_current
, p_input_item
);
581 input_item_node_AppendItem( p_root
, p_input_item
);
582 vlc_gc_decref( p_input_item
);
583 free( psz_uri
); free( psz_opt
); free( psz_name
);
584 free( psz_first
); free( psz_last
);
589 input_item_AddSubItemTree( p_root
);
590 input_item_node_Delete( p_root
);
593 for( int i
= 0; i
< i_cd_text
; i
++ )
595 vlc_meta_t
*p_meta
= pp_cd_text
[i
];
598 vlc_meta_Delete( p_meta
);
604 cddb_disc_destroy( p_disc
);
610 static cddb_disc_t
*GetCDDBInfo( access_t
*p_access
, int i_titles
, int *p_sectors
)
612 if( var_CreateGetInteger( p_access
, "album-art" ) == ALBUM_ART_WHEN_ASKED
)
616 cddb_conn_t
*p_cddb
= cddb_new();
619 msg_Warn( p_access
, "unable to use CDDB" );
624 char *psz_tmp
= var_InheritString( p_access
, "cddb-server" );
627 cddb_set_server_name( p_cddb
, psz_tmp
);
631 cddb_set_server_port( p_cddb
, var_InheritInteger( p_access
, "cddb-port" ) );
633 cddb_set_email_address( p_cddb
, "vlc@videolan.org" );
636 cddb_cache_disable( p_cddb
);
638 // cddb_cache_set_dir( p_cddb,
639 // var_InheritString( p_access,
640 // MODULE_STRING "-cddb-cachedir") );
642 cddb_set_timeout( p_cddb
, 10 );
645 cddb_http_disable( p_cddb
);
648 cddb_disc_t
*p_disc
= cddb_disc_new();
651 msg_Err( p_access
, "unable to create CDDB disc structure." );
655 int64_t i_length
= 0;
656 for( int i
= 0; i
< i_titles
; i
++ )
658 cddb_track_t
*t
= cddb_track_new();
659 cddb_track_set_frame_offset( t
, p_sectors
[i
] );
660 cddb_disc_add_track( p_disc
, t
);
661 const int64_t i_size
= ( p_sectors
[i
+1] - p_sectors
[i
] ) *
662 (int64_t)CDDA_DATA_SIZE
;
663 i_length
+= INT64_C(1000000) * i_size
/ 44100 / 4 ;
666 cddb_disc_set_length( p_disc
, (int)(i_length
/1000000) );
668 if( !cddb_disc_calc_discid( p_disc
) )
670 msg_Err( p_access
, "CDDB disc ID calculation failed" );
674 const int i_matches
= cddb_query( p_cddb
, p_disc
);
677 msg_Warn( p_access
, "CDDB error: %s", cddb_error_str(errno
) );
680 else if( i_matches
== 0 )
682 msg_Dbg( p_access
, "Couldn't find any matches in CDDB." );
685 else if( i_matches
> 1 )
686 msg_Warn( p_access
, "found %d matches in CDDB. Using first one.", i_matches
);
688 cddb_read( p_cddb
, p_disc
);
690 cddb_destroy( p_cddb
);
695 cddb_disc_destroy( p_disc
);
696 cddb_destroy( p_cddb
);
699 #endif /*HAVE_LIBCDDB*/