]> git.sesse.net Git - vlc/blob - modules/access/satellite/access.c
* Spelling fixes.
[vlc] / modules / access / satellite / access.c
1 /*****************************************************************************
2  * access.c: Satellite card input
3  *****************************************************************************
4  * Copyright (C) 1998-2003 VideoLAN
5  *
6  * Authors: Johan Bilien <jobi@via.ecp.fr>
7  *          Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33
34 #include "../../demux/mpeg/system.h"
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>
38 #endif
39
40 #include <fcntl.h>
41 #include <sys/types.h>
42 #include <string.h>
43 #include <errno.h>
44
45 #ifdef STRNCASECMP_IN_STRINGS_H
46 #   include <strings.h>
47 #endif
48
49 #include "dvb.h"
50
51 /* These are for the Dreambox port. I have no idea whether they're correct
52  * for other DVB adapters. --Meuuh */
53 #define SATELLITE_READ_ONCE (64 * 1024)
54 #define DMX_BUFFER_SIZE (1024 * 1024)
55
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
60                                      size_t i_len );
61 static int     SatelliteSetArea    ( input_thread_t *, input_area_t * );
62 static int     SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
63 static void    SatelliteSeek       ( input_thread_t *, off_t );
64
65 typedef struct demux_handle_t
66 {
67     int i_pid;
68     int i_handle;
69     int i_type;
70 } demux_handle_t;
71
72 #define PAT_TYPE 1
73 #define PMT_TYPE 2
74 #define ES_TYPE 3
75
76 #define MAX_DEMUX 8 
77
78 typedef struct thread_sat_data_t
79 {
80     int i_handle;
81     demux_handle_t p_demux_handles[MAX_DEMUX];
82 } thread_sat_data_t;
83
84 static void AllocateDemux( input_thread_t * p_input, int i_pid,
85                            int i_type )
86 {
87     thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
88     int                 i_demux;
89     int                 i;
90     i_demux = config_GetInt( p_input, "dvb-dmx" );
91
92     /* Find first free slot */
93     for ( i = 0; i < MAX_DEMUX; i++ )
94     {
95         if ( !p_satellite->p_demux_handles[i].i_type )
96         {
97             if (ioctl_SetDMXFilter( i_demux, i_pid, &p_satellite->p_demux_handles[i].i_handle, 3) < 0)
98             {
99                 msg_Warn(p_input, "ioctl_SetDMXFilter failed (%d)", i_pid);
100                 break;
101             }
102             p_satellite->p_demux_handles[i].i_type = i_type;
103             p_satellite->p_demux_handles[i].i_pid = i_pid;
104             break;
105         }
106     }
107 }
108
109 static void CloseProgram( input_thread_t * p_input )
110 {
111     thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
112     int i;
113
114     for ( i = 1; i < MAX_DEMUX; i++ )
115     {
116         if ( p_satellite->p_demux_handles[i].i_type )
117         {
118             ioctl_UnsetDMXFilter( p_satellite->p_demux_handles[i].i_handle );
119             p_satellite->p_demux_handles[i].i_type = 0;
120         }
121     }
122 }
123
124 /*****************************************************************************
125  * Open: open the dvr device
126  *****************************************************************************/
127 int E_(Open) ( vlc_object_t *p_this )
128 {
129     input_thread_t *    p_input = (input_thread_t *)p_this;
130     thread_sat_data_t * p_satellite;
131     char *              psz_parser;
132     char *              psz_next;
133     int                 i_freq = 0;
134     int                 i_srate = 0;
135     vlc_bool_t          b_pol = 0;
136     int                 i_fec = 0;
137     float               f_fec = 1./2;
138     vlc_bool_t          b_diseqc;
139     int                 i_lnb_lof1;
140     int                 i_lnb_lof2;
141     int                 i_lnb_slof;
142     int                 i_demux;
143     char                psz_dvr[255];
144     i_demux = config_GetInt( p_input, "dvb-dmx" );
145     snprintf(psz_dvr, sizeof(psz_dvr), DVR "%d", i_demux);
146
147     /* parse the options passed in command line : */
148
149     psz_parser = strdup( p_input->psz_name );
150
151     if( !psz_parser )
152     {
153         return( -1 );
154     }
155
156     p_input->pf_read = SatelliteRead;
157     p_input->pf_set_program = SatelliteSetProgram;
158     p_input->pf_set_area = SatelliteSetArea;
159     p_input->pf_seek = SatelliteSeek;
160
161     i_freq = (int)strtol( psz_parser, &psz_next, 10 );
162
163     if( *psz_next )
164     {
165         psz_parser = psz_next + 1;
166         b_pol = (vlc_bool_t)strtol( psz_parser, &psz_next, 10 );
167             if( *psz_next )
168             {
169                 psz_parser = psz_next + 1;
170                 i_fec = (int)strtol( psz_parser, &psz_next, 10 );
171                 if( *psz_next )
172                 {
173                     psz_parser = psz_next + 1;
174                     i_srate = (int)strtol( psz_parser, &psz_next, 10 );
175                 }
176             }
177
178     }
179
180     if( i_freq > (12999*1000) || i_freq < (10000*1000) )
181     {
182         msg_Warn( p_input, "invalid frequency, using default one" );
183         i_freq = config_GetInt( p_input, "frequency" );
184         if( i_freq && (i_freq > (12999*1000) || i_freq < (10000*1000)) )
185         {
186             msg_Err( p_input, "invalid default frequency" );
187             return -1;
188         }
189     }
190
191     if( i_freq && (i_srate > (30000*1000) || i_srate < (1000*1000)) )
192     {
193         msg_Warn( p_input, "invalid symbol rate, using default one" );
194         i_srate = config_GetInt( p_input, "symbol-rate" );
195         if( i_srate > (30000*1000) || i_srate < (1000*1000) )
196         {
197             msg_Err( p_input, "invalid default symbol rate" );
198             return -1;
199         }
200     }
201
202     if( i_freq && b_pol && b_pol != 1 )
203     {
204         msg_Warn( p_input, "invalid polarization, using default one" );
205         b_pol = config_GetInt( p_input, "polarization" );
206         if( b_pol && b_pol != 1 )
207         {
208             msg_Err( p_input, "invalid default polarization" );
209             return -1;
210         }
211     }
212
213     if( i_freq && (i_fec > 7 || i_fec < 1) )
214     {
215         msg_Warn( p_input, "invalid FEC, using default one" );
216         i_fec = config_GetInt( p_input, "fec" );
217         if( i_fec > 7 || i_fec < 1 )
218         {
219             msg_Err( p_input, "invalid default FEC" );
220             return -1;
221         }
222     }
223
224     if ( i_freq )
225     {
226         switch( i_fec )
227         {
228             case 1:
229                 f_fec = 1./2;
230                 break;
231             case 2:
232                 f_fec = 2./3;
233                 break;
234             case 3:
235                 f_fec = 3./4;
236                 break;
237             case 4:
238                 f_fec = 4./5;
239                 break;
240             case 5:
241                 f_fec = 5./6;
242                 break;
243             case 6:
244                 f_fec = 6./7;
245                 break;
246             case 7:
247                 f_fec = 7./8;
248                 break;
249             default:
250                 /* cannot happen */
251                 break;
252         }
253     }
254
255
256     /* Initialise structure */
257     p_satellite = malloc( sizeof( thread_sat_data_t ) );
258
259     if( p_satellite == NULL )
260     {
261         msg_Err( p_input, "out of memory" );
262         return -1;
263     }
264     memset( p_satellite, 0, sizeof( thread_sat_data_t ) );
265
266     p_input->p_access_data = (void *)p_satellite;
267
268     /* Open the DVR device */
269     msg_Dbg( p_input, "opening DVR device `%s'", psz_dvr );
270
271     if( (p_satellite->i_handle = open( psz_dvr,
272                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
273     {
274         msg_Warn( p_input, "cannot open `%s' (%s)", psz_dvr, strerror(errno) );
275         free( p_satellite );
276         return -1;
277     }
278
279     /* FIXME : this is from the Dreambox port. I have no idea whether it
280      * hurts or helps other DVB interfaces, so I just leave it here.
281      * Feel free to remove it if it breaks. --Meuuh */
282     ioctl_SetBufferSize( p_satellite->i_handle, DMX_BUFFER_SIZE );
283
284     /* Get antenna configuration options */
285     b_diseqc = config_GetInt( p_input, "diseqc" );
286     i_lnb_lof1 = config_GetInt( p_input, "lnb-lof1" );
287     i_lnb_lof2 = config_GetInt( p_input, "lnb-lof2" );
288     i_lnb_slof = config_GetInt( p_input, "lnb-slof" );
289
290     /* Initialize the Satellite Card */
291
292     if ( i_freq )
293     {
294         int i_tuner = config_GetInt( p_input, "dvb-tuner" );
295
296         msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
297                           "FEC: %03f, Srate: %d", i_freq, b_pol, f_fec, i_srate );
298
299         if ( ioctl_SECControl( i_tuner, i_freq, b_pol, i_lnb_slof, b_diseqc ) < 0 )
300         {
301             msg_Err( p_input, "an error occurred when controling SEC" );
302             close( p_satellite->i_handle );
303             free( p_satellite );
304             return -1;
305         }
306
307         msg_Dbg( p_input, "initializing frontend device" );
308         switch (ioctl_SetQPSKFrontend ( i_tuner, i_freq, i_srate, f_fec,
309                     i_lnb_lof1, i_lnb_lof2, i_lnb_slof))
310         {
311             case -2:
312                 msg_Err( p_input, "frontend returned an unexpected event" );
313                 close( p_satellite->i_handle );
314                 free( p_satellite );
315                 return -1;
316                 break;
317             case -3:
318                 msg_Err( p_input, "frontend returned no event" );
319                 close( p_satellite->i_handle );
320                 free( p_satellite );
321                 return -1;
322                 break;
323             case -4:
324                 msg_Err( p_input, "frontend: timeout when polling for event" );
325                 close( p_satellite->i_handle );
326                 free( p_satellite );
327                 return -1;
328                 break;
329             case -5:
330                 msg_Err( p_input, "an error occured when polling frontend device" );
331                 close( p_satellite->i_handle );
332                 free( p_satellite );
333                 return -1;
334                 break;
335             case -1:
336                 msg_Err( p_input, "frontend returned a failure event" );
337                 close( p_satellite->i_handle );
338                 free( p_satellite );
339                 return -1;
340                 break;
341             default:
342                 break;
343         }
344     } /* i_freq */
345
346     msg_Dbg( p_input, "setting filter on PAT" );
347     AllocateDemux( p_input, 0, PAT_TYPE );
348
349     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
350     {
351         msg_Err( p_input, "could not initialize stream structure" );
352         close( p_satellite->i_handle );
353         free( p_satellite );
354         return( -1 );
355     }
356
357     vlc_mutex_lock( &p_input->stream.stream_lock );
358
359     p_input->stream.b_pace_control = 1;
360     p_input->stream.b_seekable = 0;
361     p_input->stream.p_selected_area->i_tell = 0;
362
363     vlc_mutex_unlock( &p_input->stream.stream_lock );
364
365     p_input->i_mtu = SATELLITE_READ_ONCE;
366     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
367
368     return 0;
369 }
370
371 /*****************************************************************************
372  * Close : Close the device
373  *****************************************************************************/
374 void E_(Close) ( vlc_object_t *p_this )
375 {
376     input_thread_t *    p_input = (input_thread_t *)p_this;
377     thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
378
379     msg_Dbg( p_input, "unsetting filters on all pids" );
380     CloseProgram( p_input );
381     close( p_satellite->p_demux_handles[0].i_handle );
382
383     close( p_satellite->i_handle );
384 }
385
386 /*****************************************************************************
387  * SatelliteRead: reads data from the satellite card
388  *****************************************************************************/
389 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
390                               size_t i_len )
391 {
392     thread_sat_data_t * p_satellite = (thread_sat_data_t *)p_input->p_access_data;
393     ssize_t i_ret;
394
395     unsigned int i;
396
397     /* if not set, set filters to the PMTs */
398     /* This is kludgy and consumes way too much CPU power - the access
399      * module should have a callback from the demux when a new program
400      * is encountered. --Meuuh */
401     if ( !p_satellite->p_demux_handles[1].i_type )
402     {
403         int i_program = config_GetInt( p_input, "program" );
404
405         for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
406         {
407             /* Only set a filter on the selected program : some boards
408              * (read: Dreambox) only have 8 filters, so you don't want to
409              * spend them on unwanted PMTs. --Meuuh */
410             if ( (!i_program || p_input->stream.pp_programs[i]->i_number == i_program) )
411             {
412                 msg_Dbg( p_input, "setting filter on PMT pid %d",
413                          p_input->stream.pp_programs[i]->pp_es[0]->i_id );
414                 AllocateDemux( p_input, p_input->stream.pp_programs[i]->pp_es[0]->i_id, PMT_TYPE );
415             }
416         }
417     }
418
419     i_ret = read( p_satellite->i_handle, p_buffer, i_len );
420  
421     if( i_ret < 0 )
422     {
423 #   ifdef HAVE_ERRNO_H
424         msg_Err( p_input, "read failed (%s)", strerror(errno) );
425 #   else
426         msg_Err( p_input, "read failed" );
427 #   endif
428     }
429  
430     return i_ret;
431 }
432
433 /*****************************************************************************
434  * SatelliteSetArea : Does nothing
435  *****************************************************************************/
436 static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
437 {
438     return -1;
439 }
440
441 /*****************************************************************************
442  * SatelliteSetProgram : Sets the card filters according to the
443  *                 selected program,
444  *                 and makes the appropriate changes to stream structure.
445  *****************************************************************************/
446 int SatelliteSetProgram( input_thread_t    * p_input,
447                          pgrm_descriptor_t * p_new_prg )
448 {
449     unsigned int i_es_index;
450     vlc_value_t val;
451
452     if ( p_input->stream.p_selected_program )
453     {
454         for ( i_es_index = 0 ; /* 0 should be the PMT */
455                 i_es_index < p_input->stream.p_selected_program->
456                     i_es_number ;
457                 i_es_index ++ )
458         {
459 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
460             if ( p_es->p_dec )
461             {
462                 input_UnselectES( p_input , p_es );
463             }
464 #undef p_es
465         }
466     }
467
468     msg_Dbg( p_input, "unsetting filters on all pids" );
469     CloseProgram( p_input );
470     msg_Dbg( p_input, "setting filter on PMT pid %d",
471              p_new_prg->pp_es[0]->i_id );
472     AllocateDemux( p_input, p_new_prg->pp_es[0]->i_id, PMT_TYPE );
473
474     for ( i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
475     {
476 #define p_es p_new_prg->pp_es[i_es_index]
477         switch( p_es->i_cat )
478         {
479             case VIDEO_ES:
480                 msg_Dbg(p_input, "setting filter on video ES 0x%x",
481                         p_es->i_id);
482                 /* Always set the filter. This may seem a little odd, but
483                  * it allows you to stream the video with demuxstream
484                  * without having a decoder or a stream output behind.
485                  * The result is you'll sometimes filter a PID which you
486                  * don't really want, but in the most common cases it
487                  * should be OK. --Meuuh */
488                 AllocateDemux( p_input, p_es->i_id, ES_TYPE );
489                 input_SelectES( p_input , p_es );
490                 break;
491
492             case AUDIO_ES:
493                 msg_Dbg(p_input, "setting filter on audio ES 0x%x",
494                         p_es->i_id);
495                 AllocateDemux( p_input, p_es->i_id, ES_TYPE );
496                 input_SelectES( p_input , p_es );
497                 break;
498
499             default:
500                 /* Do not select private streams. This is to avoid the
501                  * limit of 8 filters on the Dreambox and possibly on
502                  * other boards. We should probably change that to
503                  * have the DVB subtitles, but filtering all private
504                  * streams including DVB tables and padding seems
505                  * nonsense to me. --Meuuh */
506 #if 0
507                 msg_Dbg(p_input, "setting filter on misc (0x%x) ES 0x%x",
508                         p_es->i_cat,
509                         p_es->i_id);
510                 AllocateDemux( p_input, p_es->i_id, ES_TYPE );
511                 input_SelectES( p_input , p_es );
512 #endif
513                 break;
514 #undef p_es
515         }
516     }
517
518     p_input->stream.p_selected_program = p_new_prg;
519
520     /* Update the navigation variables without triggering a callback */
521     val.i_int = p_new_prg->i_number;
522     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
523
524     return 0;
525 }
526
527 /*****************************************************************************
528  * SatelliteSeek: does nothing (not a seekable stream
529  *****************************************************************************/
530 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
531 {
532     ;
533 }
534