]> git.sesse.net Git - vlc/blob - modules/access/cdda/access.c
Break out demux into its own thing.
[vlc] / modules / access / cdda / access.c
1 /*****************************************************************************
2  * cddax.c : CD digital audio input module for vlc using libcdio
3  *****************************************************************************
4  * Copyright (C) 2000,2003 VideoLAN
5  * $Id: access.c,v 1.3 2003/11/30 02:41:00 rocky Exp $
6  *
7  * Authors: Rocky Bernstein <rocky@panix.com> 
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34 #include <sys/types.h>
35 #include <cdio/cdio.h>
36 #include <cdio/cd_types.h>
37
38 #include "codecs.h"
39 #include "vlc_keys.h"
40
41 #ifdef HAVE_UNISTD_H
42 #   include <unistd.h>
43 #endif
44
45 #include <string.h>
46
47 #include "cdda.h"
48
49 /* how many blocks Open will read in each loop */
50 #define CDDA_BLOCKS_ONCE 1
51 #define CDDA_DATA_ONCE   (CDDA_BLOCKS_ONCE * CDIO_CD_FRAMESIZE_RAW)
52
53 /* FIXME: This variable is a hack. Would be nice to eliminate. */
54 static input_thread_t *p_cdda_input = NULL;
55
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59 static int  CDDARead         ( input_thread_t *, byte_t *, size_t );
60 static void CDDASeek         ( input_thread_t *, off_t );
61 static int  CDDASetArea      ( input_thread_t *, input_area_t * );
62 static int  CDDASetProgram   ( input_thread_t *, pgrm_descriptor_t * );
63
64 /****************************************************************************
65  * Private functions
66  ****************************************************************************/
67
68 int
69 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
70                       vlc_value_t oldval, vlc_value_t val, void *p_data )
71 {
72   cdda_data_t *p_cdda;
73
74   if (NULL == p_cdda_input) return VLC_EGENERIC;
75   
76   p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
77
78   if (p_cdda->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
79     msg_Dbg( p_cdda_input, "Old debug (x%0x) %d, new debug (x%0x) %d", 
80              p_cdda->i_debug, p_cdda->i_debug, val.i_int, val.i_int);
81   }
82   p_cdda->i_debug = val.i_int;
83   return VLC_SUCCESS;
84 }
85
86 /* process messages that originate from libcdio. */
87 static void
88 cdio_log_handler (cdio_log_level_t level, const char message[])
89 {
90   cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_access_data;
91   switch (level) {
92   case CDIO_LOG_DEBUG:
93   case CDIO_LOG_INFO:
94     if (p_cdda->i_debug & INPUT_DBG_CDIO) 
95       msg_Dbg( p_cdda_input, message);
96     break;
97   case CDIO_LOG_WARN:
98     msg_Warn( p_cdda_input, message);
99     break;
100   case CDIO_LOG_ERROR:
101   case CDIO_LOG_ASSERT:
102     msg_Err( p_cdda_input, message);
103     break;
104   default:
105     msg_Warn( p_cdda_input, message,
106             _("The above message had unknown vcdimager log level"), 
107             level);
108   }
109   return;
110 }
111
112
113 /*****************************************************************************
114  * Open: open cdda
115  *****************************************************************************/
116 int 
117 E_(Open)( vlc_object_t *p_this )
118 {
119     input_thread_t *        p_input = (input_thread_t *)p_this;
120     char *                  psz_orig;
121     char *                  psz_parser;
122     char *                  psz_source;
123     cdda_data_t *           p_cdda;
124     int                     i;
125     int                     i_title = 1;
126     cddev_t                 *p_cddev;
127
128     /* Set where to log errors messages from libcdio. */
129     p_cdda_input = (input_thread_t *)p_this;
130
131     /* parse the options passed in command line : */
132     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
133
134     if( !psz_orig )
135     {
136         return( -1 );
137     }
138
139     while( *psz_parser && *psz_parser != '@' )
140     {
141         psz_parser++;
142     }
143
144     if( *psz_parser == '@' )
145     {
146         /* Found options */
147         *psz_parser = '\0';
148         ++psz_parser;
149
150         if ('T' == *psz_parser || 't' == *psz_parser ) 
151             ++psz_parser;
152           
153         i_title = (int)strtol( psz_parser, NULL, 10 );
154         i_title = i_title ? i_title : 1;
155     }
156
157     if( !*psz_source ) {
158       /* No source specified, so figure it out. */
159       if( !p_input->psz_access ) {
160         free( psz_orig );
161         return -1;
162       }
163       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
164       
165       if( !psz_source || 0==strlen(psz_source) ) {
166         /* Scan for a CD-ROM drive with a CD-DA in it. */
167         char **cd_drives = 
168           cdio_get_devices_with_cap(NULL,  CDIO_FS_AUDIO, false);
169         if (NULL == cd_drives) return -1;
170         if (cd_drives[0] == NULL) {
171           cdio_free_device_list(cd_drives);
172           return -1;
173         }
174         psz_source = strdup(cd_drives[0]);
175         cdio_free_device_list(cd_drives);
176       }
177     }
178
179     /* Open CDDA */
180     cdio_log_set_handler ( cdio_log_handler );
181
182     if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
183     {
184         msg_Warn( p_input, "could not open %s", psz_source );
185         free( psz_source );
186         return -1;
187     }
188     free( psz_source );
189
190     p_cdda = malloc( sizeof(cdda_data_t) );
191     if( p_cdda == NULL )
192     {
193         msg_Err( p_input, "out of memory" );
194         free( psz_source );
195         return -1;
196     }
197
198     p_cdda->p_cddev        = p_cddev;
199     p_cdda->i_debug        = config_GetInt( p_this, MODULE_STRING "-debug" );
200     p_input->p_access_data = (void *)p_cdda;
201
202     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
203
204     p_input->i_mtu = CDDA_DATA_ONCE;
205
206     /* We read the Table Of Content information */
207     p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
208                               p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
209     if( p_cdda->i_nb_tracks < 0 )
210         msg_Err( p_input, "unable to count tracks" );
211     else if( p_cdda->i_nb_tracks <= 0 )
212         msg_Err( p_input, "no audio tracks found" );
213
214     if( p_cdda->i_nb_tracks <= 1)
215     {
216         ioctl_Close( p_cdda->p_cddev );
217         free( p_cdda );
218         return -1;
219     }
220
221     if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
222         i_title = 1;
223
224     /* Set stream and area data */
225     vlc_mutex_lock( &p_input->stream.stream_lock );
226
227     /* Initialize ES structures */
228     input_InitStream( p_input, 0 );
229
230     /* cdda input method */
231     p_input->stream.i_method = INPUT_METHOD_CDDA;
232
233     p_input->stream.b_pace_control = 1;
234     p_input->stream.b_seekable = 1;
235     p_input->stream.i_mux_rate = 44100 * 4 / 50;
236
237 #define area p_input->stream.pp_areas
238     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
239     {
240         input_AddArea( p_input, i, 1 );
241
242         /* Absolute start offset and size */
243         area[i]->i_start =
244             (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
245         area[i]->i_size =
246             (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
247             * (off_t)CDIO_CD_FRAMESIZE_RAW;
248     }
249 #undef area
250
251     CDDAPlay( p_input, i_title);
252
253     vlc_mutex_unlock( &p_input->stream.stream_lock );
254
255     if( !p_input->psz_demux || !*p_input->psz_demux )
256     {
257         p_input->psz_demux = "cdda";
258     }
259
260     p_input->pf_read = CDDARead;
261     p_input->pf_seek = CDDASeek;
262     p_input->pf_set_area = CDDASetArea;
263     p_input->pf_set_program = CDDASetProgram;
264
265     /* Update default_pts to a suitable value for cdda access */
266     p_input->i_pts_delay = config_GetInt( p_input, 
267                                           MODULE_STRING "-caching" ) * 1000;
268
269     p_cdda->p_intf = intf_Create( p_input, "cddax" );
270     intf_RunThread( p_cdda->p_intf );
271
272     return 0;
273 }
274
275 /*****************************************************************************
276  * CDDAPlay: Arrange things so we play the specified track.
277  * VLC_TRUE is returned if there was no error.
278  *****************************************************************************/
279 vlc_bool_t
280 CDDAPlay( input_thread_t *p_input, int i_track )
281 {
282   cdda_data_t *p_cdda = (cdda_data_t *) p_input->p_access_data;
283
284   if( i_track >= p_cdda->i_nb_tracks || i_track < 1 )
285     return VLC_FALSE;
286
287   CDDASetArea( p_input, p_input->stream.pp_areas[i_track] );
288   return VLC_TRUE;
289 }
290
291 /*****************************************************************************
292  * CDDAClose: closes cdda
293  *****************************************************************************/
294 void 
295 E_(Close)( vlc_object_t *p_this )
296 {
297     input_thread_t *   p_input = (input_thread_t *)p_this;
298     cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
299
300     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
301     ioctl_Close( p_cdda->p_cddev );
302     free( p_cdda );
303     p_cdda_input = NULL;
304 }
305
306 /*****************************************************************************
307  * CDDARead: reads from the CDDA into PES packets.
308  *****************************************************************************
309  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
310  * bytes.
311  *****************************************************************************/
312 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
313                      size_t i_len )
314 {
315     cdda_data_t *           p_cdda;
316     int                     i_blocks;
317     int                     i_index;
318     int                     i_read;
319
320     p_cdda = (cdda_data_t *)p_input->p_access_data;
321
322     i_read = 0;
323
324     /* Compute the number of blocks we have to read */
325
326     i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
327
328     for ( i_index = 0; i_index < i_blocks; i_index++ )
329     {
330
331       if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer, 
332                                  p_cdda->i_sector) != 0)
333         {
334           msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
335           return -1;
336         }
337
338         p_cdda->i_sector ++;
339         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
340         {
341             input_area_t *p_area;
342
343             dbg_print( (INPUT_DBG_LSN|INPUT_DBG_CALL), 
344                        "end of track, cur: %u", p_cdda->i_sector );
345
346             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
347                 return 0; /* EOF */
348
349             vlc_mutex_lock( &p_input->stream.stream_lock );
350             p_area = p_input->stream.pp_areas[
351                     p_input->stream.p_selected_area->i_id + 1 ];
352
353             p_area->i_part = 1;
354             CDDASetArea( p_input, p_area );
355             vlc_mutex_unlock( &p_input->stream.stream_lock );
356         }
357         i_read += CDIO_CD_FRAMESIZE_RAW;
358     }
359
360     if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
361     {
362         msg_Err( p_input, "must read full sectors" );
363     }
364
365     return i_read;
366 }
367
368 /*****************************************************************************
369  * CDDASetProgram: Does nothing since a CDDA is mono_program
370  *****************************************************************************/
371 static int CDDASetProgram( input_thread_t * p_input,
372                            pgrm_descriptor_t * p_program)
373 {
374     cdda_data_t * p_cdda= (cdda_data_t *) p_input->p_access_data;
375     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "" );
376     return 0;
377 }
378
379 /*****************************************************************************
380  * CDDASetArea: initialize input data for title x.
381  * It should be called for each user navigation request.
382  ****************************************************************************/
383 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
384 {
385     cdda_data_t *p_cdda = (cdda_data_t*) p_input->p_access_data;
386     vlc_value_t val;
387
388     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "");
389
390     /* we can't use the interface slider until initilization is complete */
391     p_input->stream.b_seekable = 0;
392
393     if( p_area != p_input->stream.p_selected_area )
394     {
395         /* Change the default area */
396         p_input->stream.p_selected_area = p_area;
397
398         /* Change the current track */
399         p_cdda->i_track = p_area->i_id - 1;
400         p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
401
402         /* Update the navigation variables without triggering a callback */
403         val.i_int = p_area->i_id;
404         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
405     }
406
407     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
408
409     p_input->stream.p_selected_area->i_tell =
410         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
411          - p_input->stream.p_selected_area->i_start;
412
413     /* warn interface that something has changed */
414     p_input->stream.b_seekable = 1;
415     p_input->stream.b_changed = 1;
416
417     return 0;
418 }
419
420 /****************************************************************************
421  * CDDASeek
422  ****************************************************************************/
423 static void CDDASeek( input_thread_t * p_input, off_t i_off )
424 {
425     cdda_data_t * p_cdda;
426
427     p_cdda = (cdda_data_t *) p_input->p_access_data;
428
429     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
430                        + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
431
432     vlc_mutex_lock( &p_input->stream.stream_lock );
433     p_input->stream.p_selected_area->i_tell =
434         (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
435          - p_input->stream.p_selected_area->i_start;
436
437     vlc_mutex_unlock( &p_input->stream.stream_lock );
438
439     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
440     "sector %ud, offset: %lld, i_tell: %lld",  p_cdda->i_sector, i_off, 
441                p_input->stream.p_selected_area->i_tell );
442
443 }