]> git.sesse.net Git - vlc/blob - modules/access/satellite/access.c
e4a9269ddde55f7dadee121a3db1779bb5533f6f
[vlc] / modules / access / satellite / access.c
1 /*****************************************************************************
2  * access.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 <vlc/vlc.h>
31 #include <vlc/input.h>
32
33 #include "../../demux/mpeg/system.h"
34
35 #ifdef HAVE_UNISTD_H
36 #   include <unistd.h>
37 #endif
38
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <string.h>
42 #include <errno.h>
43
44 #ifdef STRNCASECMP_IN_STRINGS_H
45 #   include <strings.h>
46 #endif
47
48 #include "dvb.h"
49
50 #define SATELLITE_READ_ONCE 3
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
56                                      size_t i_len );
57 static int     SatelliteSetArea    ( input_thread_t *, input_area_t * );
58 static int     SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
59 static void    SatelliteSeek       ( input_thread_t *, off_t );
60
61 /*****************************************************************************
62  * Open: open the dvr device
63  *****************************************************************************/
64 int E_(Open) ( vlc_object_t *p_this )
65 {
66     input_thread_t *    p_input = (input_thread_t *)p_this;
67     input_socket_t *    p_satellite;
68     char *              psz_parser;
69     char *              psz_next;
70     int                 i_fd = 0;
71     int                 i_freq = 0;
72     int                 i_srate = 0;
73     vlc_bool_t          b_pol = 0;
74     int                 i_fec = 0;
75     float               f_fec = 1./2;
76     vlc_bool_t          b_diseqc;
77     int                 i_lnb_lof1;
78     int                 i_lnb_lof2;
79     int                 i_lnb_slof;
80
81     /* parse the options passed in command line : */
82
83     psz_parser = strdup( p_input->psz_name );
84
85     if( !psz_parser )
86     {
87         return( -1 );
88     }
89
90     p_input->pf_read = SatelliteRead;
91     p_input->pf_set_program = SatelliteSetProgram;
92     p_input->pf_set_area = SatelliteSetArea;
93     p_input->pf_seek = SatelliteSeek;
94
95     i_freq = (int)strtol( psz_parser, &psz_next, 10 );
96
97     if( *psz_next )
98     {
99         psz_parser = psz_next + 1;
100         b_pol = (vlc_bool_t)strtol( psz_parser, &psz_next, 10 );
101             if( *psz_next )
102             {
103                 psz_parser = psz_next + 1;
104                 i_fec = (int)strtol( psz_parser, &psz_next, 10 );
105                 if( *psz_next )
106                 {
107                     psz_parser = psz_next + 1;
108                     i_srate = (int)strtol( psz_parser, &psz_next, 10 );
109                 }
110             }
111
112     }
113
114     if( i_freq > 12999 || i_freq < 10000 )
115     {
116         msg_Warn( p_input, "invalid frequency, using default one" );
117         i_freq = config_GetInt( p_input, "frequency" );
118         if( i_freq > 12999 || i_freq < 10000 )
119         {
120             msg_Err( p_input, "invalid default frequency" );
121             return -1;
122         }
123     }
124
125     if( i_srate > 30000 || i_srate < 1000 )
126     {
127         msg_Warn( p_input, "invalid symbol rate, using default one" );
128         i_srate = config_GetInt( p_input, "symbol-rate" );
129         if( i_srate > 30000 || i_srate < 1000 )
130         {
131             msg_Err( p_input, "invalid default symbol rate" );
132             return -1;
133         }
134     }
135
136     if( b_pol && b_pol != 1 )
137     {
138         msg_Warn( p_input, "invalid polarization, using default one" );
139         b_pol = config_GetInt( p_input, "polarization" );
140         if( b_pol && b_pol != 1 )
141         {
142             msg_Err( p_input, "invalid default polarization" );
143             return -1;
144         }
145     }
146
147     if( i_fec > 7 || i_fec < 1 )
148     {
149         msg_Warn( p_input, "invalid FEC, using default one" );
150         i_fec = config_GetInt( p_input, "fec" );
151         if( i_fec > 7 || i_fec < 1 )
152         {
153             msg_Err( p_input, "invalid default FEC" );
154             return -1;
155         }
156     }
157
158     switch( i_fec )
159     {
160         case 1:
161             f_fec = 1./2;
162             break;
163         case 2:
164             f_fec = 2./3;
165             break;
166         case 3:
167             f_fec = 3./4;
168             break;
169         case 4:
170             f_fec = 4./5;
171             break;
172         case 5:
173             f_fec = 5./6;
174             break;
175         case 6:
176             f_fec = 6./7;
177             break;
178         case 7:
179             f_fec = 7./8;
180             break;
181         default:
182             /* cannot happen */
183             break;
184     }
185
186
187     /* Initialise structure */
188     p_satellite = malloc( sizeof( input_socket_t ) );
189
190     if( p_satellite == NULL )
191     {
192         msg_Err( p_input, "out of memory" );
193         return -1;
194     }
195
196     p_input->p_access_data = (void *)p_satellite;
197
198     /* Open the DVR device */
199     msg_Dbg( p_input, "opening DVR device `%s'", DVR );
200
201     if( (p_satellite->i_handle = open( DVR,
202                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
203     {
204         msg_Warn( p_input, "cannot open `%s' (%s)", DVR, strerror(errno) );
205         free( p_satellite );
206         return -1;
207     }
208
209
210     /* Get antenna configuration options */
211     b_diseqc = config_GetInt( p_input, "diseqc" );
212     i_lnb_lof1 = config_GetInt( p_input, "lnb-lof1" );
213     i_lnb_lof2 = config_GetInt( p_input, "lnb-lof2" );
214     i_lnb_slof = config_GetInt( p_input, "lnb-slof" );
215
216     /* Initialize the Satellite Card */
217
218     msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
219                       "FEC: %03f, Srate: %d", i_freq, b_pol, f_fec, i_srate );
220
221     if ( ioctl_SECControl( i_freq * 1000, b_pol, i_lnb_slof * 1000,
222                 b_diseqc ) < 0 )
223     {
224         msg_Err( p_input, "an error occured when controling SEC" );
225         close( p_satellite->i_handle );
226         free( p_satellite );
227         return -1;
228     }
229
230     msg_Dbg( p_input, "initializing frontend device" );
231     switch (ioctl_SetQPSKFrontend ( i_freq * 1000, i_srate* 1000, f_fec,
232                 i_lnb_lof1 * 1000, i_lnb_lof2 * 1000, i_lnb_slof * 1000))
233     {
234         case -2:
235             msg_Err( p_input, "frontend returned an unexpected event" );
236             close( p_satellite->i_handle );
237             free( p_satellite );
238             return -1;
239             break;
240         case -3:
241             msg_Err( p_input, "frontend returned no event" );
242             close( p_satellite->i_handle );
243             free( p_satellite );
244             return -1;
245             break;
246         case -4:
247             msg_Err( p_input, "frontend: timeout when polling for event" );
248             close( p_satellite->i_handle );
249             free( p_satellite );
250             return -1;
251             break;
252         case -5:
253             msg_Err( p_input, "an error occured when polling frontend device" );
254             close( p_satellite->i_handle );
255             free( p_satellite );
256             return -1;
257             break;
258         case -1:
259             msg_Err( p_input, "frontend returned a failure event" );
260             close( p_satellite->i_handle );
261             free( p_satellite );
262             return -1;
263             break;
264         default:
265             break;
266     }
267
268     msg_Dbg( p_input, "setting filter on PAT" );
269
270     if ( ioctl_SetDMXFilter( 0, &i_fd, 3 ) < 0 )
271     {
272         msg_Err( p_input, "an error occured when setting filter on PAT" );
273         close( p_satellite->i_handle );
274         free( p_satellite );
275         return -1;
276     }
277
278     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
279     {
280         msg_Err( p_input, "could not initialize stream structure" );
281         close( p_satellite->i_handle );
282         free( p_satellite );
283         return( -1 );
284     }
285
286     vlc_mutex_lock( &p_input->stream.stream_lock );
287
288     p_input->stream.b_pace_control = 1;
289     p_input->stream.b_seekable = 0;
290     p_input->stream.p_selected_area->i_tell = 0;
291
292     vlc_mutex_unlock( &p_input->stream.stream_lock );
293
294     p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
295     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
296
297     return 0;
298 }
299
300 /*****************************************************************************
301  * Close : Close the device
302  *****************************************************************************/
303 void E_(Close) ( vlc_object_t *p_this )
304 {
305     input_thread_t *    p_input = (input_thread_t *)p_this;
306     input_socket_t *    p_satellite;
307     unsigned int        i_es_index;
308
309     if ( p_input->stream.p_selected_program )
310     {
311         for ( i_es_index = 1 ;
312                 i_es_index < p_input->stream.p_selected_program->
313                     i_es_number ;
314                 i_es_index ++ )
315         {
316 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
317             if ( p_es->p_decoder_fifo )
318             {
319                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
320             }
321 #undef p_es
322         }
323     }
324
325     p_satellite = (input_socket_t *)p_input;
326     close( p_satellite->i_handle );
327 }
328
329 /*****************************************************************************
330  * SatelliteRead: reads data from the satellite card
331  *****************************************************************************/
332 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
333                               size_t i_len )
334 {
335     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
336     ssize_t i_ret;
337  
338     unsigned int i;
339
340     /* if not set, set filters to the PMTs */
341     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
342     {
343         if ( p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd == 0 )
344         {
345             msg_Dbg( p_input, "setting filter on pmt pid %d",
346                      p_input->stream.pp_programs[i]->pp_es[0]->i_id );
347             ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
348                        &p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd,
349                        3 );
350         }
351     }
352
353     i_ret = read( p_access_data->i_handle, p_buffer, i_len );
354  
355     if( i_ret < 0 )
356     {
357 #   ifdef HAVE_ERRNO_H
358         msg_Err( p_input, "read failed (%s)", strerror(errno) );
359 #   else
360         msg_Err( p_input, "read failed" );
361 #   endif
362     }
363  
364     return i_ret;
365 }
366
367 /*****************************************************************************
368  * SatelliteSetArea : Does nothing
369  *****************************************************************************/
370 static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
371 {
372     return -1;
373 }
374
375 /*****************************************************************************
376  * SatelliteSetProgram : Sets the card filters according to the
377  *                 selected program,
378  *                 and makes the appropriate changes to stream structure.
379  *****************************************************************************/
380 int SatelliteSetProgram( input_thread_t    * p_input,
381                          pgrm_descriptor_t * p_new_prg )
382 {
383     unsigned int i_es_index;
384     vlc_value_t val;
385
386     if ( p_input->stream.p_selected_program )
387     {
388         for ( i_es_index = 1 ; /* 0 should be the PMT */
389                 i_es_index < p_input->stream.p_selected_program->
390                     i_es_number ;
391                 i_es_index ++ )
392         {
393 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
394             if ( p_es->p_decoder_fifo )
395             {
396                 input_UnselectES( p_input , p_es );
397             }
398             if ( p_es->i_demux_fd )
399             {
400                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
401                 p_es->i_demux_fd = 0;
402             }
403 #undef p_es
404         }
405     }
406
407     for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
408     {
409 #define p_es p_new_prg->pp_es[i_es_index]
410         switch( p_es->i_cat )
411         {
412             case MPEG1_VIDEO_ES:
413             case MPEG2_VIDEO_ES:
414             case MPEG2_MOTO_VIDEO_ES:
415                 if ( input_SelectES( p_input , p_es ) == 0 )
416                 {
417                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 1);
418                 }
419                 break;
420             case MPEG1_AUDIO_ES:
421             case MPEG2_AUDIO_ES:
422                 if ( input_SelectES( p_input , p_es ) == 0 )
423                 {
424                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 2);
425                     input_SelectES( p_input , p_es );
426                 }
427                 break;
428             default:
429                 ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 3);
430                 input_SelectES( p_input , p_es );
431                 break;
432 #undef p_es
433         }
434     }
435
436     p_input->stream.p_selected_program = p_new_prg;
437
438     /* Update the navigation variables without triggering a callback */
439     val.i_int = p_new_prg->i_number;
440     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val );
441
442     return 0;
443 }
444
445 /*****************************************************************************
446  * SatelliteSeek: does nothing (not a seekable stream
447  *****************************************************************************/
448 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
449 {
450     ;
451 }
452