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