* doc/vlc-howto.sgml: Spelling mistakes, small updates, harmonization
[vlc.git] / plugins / satellite / input_satellite.c
1 /*****************************************************************************
2  * input_satellite.c: Satellite card input
3  *****************************************************************************
4  * Copyright (C) 1998-2002 VideoLAN
5  *
6  * Authors: Johan Bilien <jobi@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <videolan/vlc.h>
31
32 #ifdef HAVE_UNISTD_H
33 #   include <unistd.h>
34 #endif
35
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <string.h>
39 #include <errno.h>
40
41 #ifdef STRNCASECMP_IN_STRINGS_H
42 #   include <strings.h>
43 #endif
44
45 #include "stream_control.h"
46 #include "input_ext-intf.h"
47 #include "input_ext-dec.h"
48 #include "input_ext-plugins.h"
49
50 #include "satellite_tools.h"
51
52 #define SATELLITE_READ_ONCE 3
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int     SatelliteOpen       ( input_thread_t * );
58 static void    SatelliteClose      ( input_thread_t * );
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 /*****************************************************************************
66  * Functions exported as capabilities. They are declared as static so that
67  * we don't pollute the namespace too much.
68  *****************************************************************************/
69 void _M( access_getfunctions )( function_list_t * p_function_list )
70 {
71 #define access p_function_list->functions.access
72     access.pf_open             = SatelliteOpen;
73     access.pf_close            = SatelliteClose;
74     access.pf_read             = SatelliteRead;
75     access.pf_set_area         = SatelliteSetArea;
76     access.pf_set_program      = SatelliteSetProgram;
77     access.pf_seek             = SatelliteSeek;
78 #undef access
79 }
80
81 /*****************************************************************************
82  * SatelliteOpen : open the dvr device
83  *****************************************************************************/
84 static int SatelliteOpen( input_thread_t * p_input )
85 {
86     input_socket_t *    p_satellite;
87     char *              psz_parser;
88     char *              psz_next;
89     int                 i_fd = 0;
90     int                 i_freq = 0;
91     int                 i_srate = 0;
92     boolean_t           b_pol = 0;
93     int                 i_fec = 0;
94     float               f_fec = 1./2;
95     boolean_t           b_diseqc;
96     int                 i_lnb_lof1;
97     int                 i_lnb_lof2;
98     int                 i_lnb_slof;
99
100     /* parse the options passed in command line : */
101
102     psz_parser = strdup( p_input->psz_name );
103
104     if( !psz_parser )
105     {
106         return( -1 );
107     }
108
109     i_freq = (int)strtol( psz_parser, &psz_next, 10 );
110
111     if( *psz_next )
112     {
113         psz_parser = psz_next + 1;
114         b_pol = (boolean_t)strtol( psz_parser, &psz_next, 10 );
115             if( *psz_next )
116             {
117                 psz_parser = psz_next + 1;
118                 i_fec = (int)strtol( psz_parser, &psz_next, 10 );
119                 if( *psz_next )
120                 {
121                     psz_parser = psz_next + 1;
122                     i_srate = (int)strtol( psz_parser, &psz_next, 10 );
123                 }
124             }
125
126     }
127
128     if( i_freq > 12999 || i_freq < 10000 )
129     {
130         intf_WarnMsg( 1, "input: satellite: invalid frequency, using "\
131                 "default one" );
132         i_freq = config_GetIntVariable( "frequency" );
133         if( i_freq > 12999 || i_freq < 10000 )
134         {
135             intf_ErrMsg( "input: satellite: invalid default frequency" );
136             return -1;
137         }
138     }
139
140     if( i_srate > 30000 || i_srate < 1000 )
141     {
142         intf_WarnMsg( 1, "input: satellite: invalid symbol rate, using "\
143                 "default one" );
144         i_srate = config_GetIntVariable( "symbol-rate" );
145         if( i_srate > 30000 || i_srate < 1000 )
146         {
147             intf_ErrMsg( "input: satellite: invalid default symbol rate" );
148             return -1;
149         }
150     }
151
152     if( b_pol && b_pol != 1 )
153     {
154         intf_WarnMsg( 1, "input: satellite: invalid polarization, using "\
155                 "default one" );
156         b_pol = config_GetIntVariable( "polarization" );
157         fprintf(stderr, "%d\n", b_pol);
158         if( b_pol && b_pol != 1 )
159         {
160             intf_ErrMsg( "input: satellite: invalid default polarization" );
161             return -1;
162         }
163     }
164
165     if( i_fec > 7 || i_fec < 1 )
166     {
167         intf_WarnMsg( 1, "input: satellite: invalid FEC, using default one " );
168         i_fec = config_GetIntVariable( "fec" );
169         if( i_fec > 7 || i_fec < 1 )
170         {
171             intf_ErrMsg( "input: satellite: invalid default FEC" );
172             return -1;
173         }
174     }
175
176     switch( i_fec )
177     {
178         case 1:
179             f_fec = 1./2;
180             break;
181         case 2:
182             f_fec = 2./3;
183             break;
184         case 3:
185             f_fec = 3./4;
186             break;
187         case 4:
188             f_fec = 4./5;
189             break;
190         case 5:
191             f_fec = 5./6;
192             break;
193         case 6:
194             f_fec = 6./7;
195             break;
196         case 7:
197             f_fec = 7./8;
198             break;
199         default:
200             /* cannot happen */
201     }
202
203
204     /* Initialise structure */
205     p_satellite = malloc( sizeof( input_socket_t ) );
206
207     if( p_satellite == NULL )
208     {
209         intf_ErrMsg( "input: satellite: Out of memory" );
210         return -1;
211     }
212
213     p_input->p_access_data = (void *)p_satellite;
214
215     /* Open the DVR device */
216
217     intf_WarnMsg( 2, "input: opening file `%s'", DVR);
218
219     if( (p_satellite->i_handle = open( DVR,
220                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
221     {
222         intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
223         free( p_satellite );
224         return -1;
225     }
226
227
228     /* Get antenna configuration options */
229     b_diseqc = config_GetIntVariable( "diseqc" );
230     i_lnb_lof1 = config_GetIntVariable( "lnb-lof1" );
231     i_lnb_lof2 = config_GetIntVariable( "lnb-lof2" );
232     i_lnb_slof = config_GetIntVariable( "lnb-slof" );
233
234     /* Initialize the Satellite Card */
235
236     intf_WarnMsg( 2, "Initializing Sat Card with Freq: %d, Pol: %d, "\
237                         "FEC: %03f, Srate: %d",
238                         i_freq, b_pol, f_fec, i_srate );
239
240     if ( ioctl_SECControl( i_freq * 1000, b_pol, i_lnb_slof * 1000,
241                 b_diseqc ) < 0 )
242     {
243         intf_ErrMsg("input: satellite: An error occured when controling SEC");
244         close( p_satellite->i_handle );
245         free( p_satellite );
246         return -1;
247     }
248
249     intf_WarnMsg( 3, "Initializing Frontend device" );
250     switch (ioctl_SetQPSKFrontend ( i_freq * 1000, i_srate* 1000, f_fec,
251                 i_lnb_lof1 * 1000, i_lnb_lof2 * 1000, i_lnb_slof * 1000))
252     {
253         case -2:
254             intf_ErrMsg( "input: satellite: Frontend returned"\
255                     "an unexpected event" );
256             close( p_satellite->i_handle );
257             free( p_satellite );
258             return -1;
259             break;
260         case -3:
261             intf_ErrMsg( "input: satellite: Frontend returned\
262                     no event" );
263             close( p_satellite->i_handle );
264             free( p_satellite );
265             return -1;
266             break;
267         case -4:
268             intf_ErrMsg( "input: satellite: Frontend: time out\
269                     when polling for event" );
270             close( p_satellite->i_handle );
271             free( p_satellite );
272             return -1;
273             break;
274         case -5:
275              intf_ErrMsg( "input: satellite: An error occured when polling\
276                     Frontend device" );
277             close( p_satellite->i_handle );
278             free( p_satellite );
279             return -1;
280             break;
281         case -1:
282              intf_ErrMsg( "input: satellite: Frontend returned\
283                     an failure event" );
284             close( p_satellite->i_handle );
285             free( p_satellite );
286             return -1;
287             break;
288         default:
289             break;
290     }
291
292     intf_WarnMsg( 3, " Setting filter on PAT " );
293
294     if ( ioctl_SetDMXFilter( 0, &i_fd, 3 ) < 0 )
295     {
296         intf_ErrMsg( "input: satellite: An error occured when setting\
297                 filter on PAT" );
298         close( p_satellite->i_handle );
299         free( p_satellite );
300         return -1;
301     }
302
303     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
304     {
305         intf_ErrMsg( "input: satellite: Not enough memory to allow stream\
306                         structure" );
307         close( p_satellite->i_handle );
308         free( p_satellite );
309         return( -1 );
310     }
311
312     vlc_mutex_lock( &p_input->stream.stream_lock );
313
314     p_input->stream.b_pace_control = 1;
315     p_input->stream.b_seekable = 0;
316     p_input->stream.p_selected_area->i_tell = 0;
317
318     vlc_mutex_unlock( &p_input->stream.stream_lock );
319
320     p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
321     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
322
323     return 0;
324 }
325
326 /*****************************************************************************
327  * SatelliteClose : Closes the device
328  *****************************************************************************/
329 static void SatelliteClose( input_thread_t * p_input )
330 {
331     input_socket_t *    p_satellite;
332     int                 i_es_index;
333
334     if ( p_input->stream.p_selected_program )
335     {
336         for ( i_es_index = 1 ;
337                 i_es_index < p_input->stream.p_selected_program->
338                     i_es_number ;
339                 i_es_index ++ )
340         {
341 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
342             if ( p_es->p_decoder_fifo )
343             {
344                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
345             }
346 #undef p_es
347         }
348     }
349
350     p_satellite = (input_socket_t *)p_input;
351     close( p_satellite->i_handle );
352 }
353
354
355 /*****************************************************************************
356  * SatelliteRead: reads data from the satellite card
357  *****************************************************************************/
358 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
359                 size_t i_len )
360 {
361     int i;
362
363     /* if not set, set filters to the PMTs */
364     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
365     {
366         if ( p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd == 0 )
367         {
368             intf_WarnMsg( 2, "input: satellite: setting filter on pmt pid %d",
369                         p_input->stream.pp_programs[i]->pp_es[0]->i_id);
370             ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
371                        &p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd,
372                        3 );
373         }
374     }
375
376     return input_FDRead( p_input, p_buffer, i_len );
377 }
378
379
380
381
382 /*****************************************************************************
383  * SatelliteSetArea : Does nothing
384  *****************************************************************************/
385 static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
386 {
387     return -1;
388 }
389
390 /*****************************************************************************
391  * SatelliteSetProgram : Sets the card filters according to the
392  *                 selected program,
393  *                 and makes the appropriate changes to stream structure.
394  *****************************************************************************/
395 int SatelliteSetProgram( input_thread_t    * p_input,
396                          pgrm_descriptor_t * p_new_prg )
397 {
398     int                 i_es_index;
399
400     if ( p_input->stream.p_selected_program )
401     {
402         for ( i_es_index = 1 ; /* 0 should be the PMT */
403                 i_es_index < p_input->stream.p_selected_program->
404                     i_es_number ;
405                 i_es_index ++ )
406         {
407 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
408             if ( p_es->p_decoder_fifo )
409             {
410                 input_UnselectES( p_input , p_es );
411             }
412             if ( p_es->i_demux_fd )
413             {
414                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
415                 p_es->i_demux_fd = 0;
416             }
417 #undef p_es
418         }
419     }
420
421     for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
422     {
423 #define p_es p_new_prg->pp_es[i_es_index]
424         switch( p_es->i_cat )
425         {
426             case MPEG1_VIDEO_ES:
427             case MPEG2_VIDEO_ES:
428                 if ( p_main->b_video )
429                 {
430                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 1);
431                     input_SelectES( p_input , p_es );
432                 }
433                 break;
434             case MPEG1_AUDIO_ES:
435             case MPEG2_AUDIO_ES:
436                 if ( p_main->b_audio )
437                 {
438                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 2);
439                     input_SelectES( p_input , p_es );
440                 }
441                 break;
442             default:
443                 ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 3);
444                 input_SelectES( p_input , p_es );
445                 break;
446 #undef p_es
447         }
448     }
449
450     p_input->stream.p_selected_program = p_new_prg;
451
452     return( 0 );
453 }
454
455 /*****************************************************************************
456  * SatelliteSeek: does nothing (not a seekable stream
457  *****************************************************************************/
458 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
459 {
460     return;
461 }