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