]> git.sesse.net Git - vlc/blob - modules/access/dvb/access.c
Adding DVB module to support satellite, cable and terestrial DVB streaming. The statu...
[vlc] / modules / access / dvb / access.c
1 /*****************************************************************************
2  * access.c: DVB card input v4l2 only
3  *****************************************************************************
4  * Copyright (C) 1998-2003 VideoLAN
5  *
6  * Authors: Johan Bilien <jobi@via.ecp.fr>
7  *          Jean-Paul Saman <saman@natlab.research.philips.com>
8  *          Christopher Ross <ross@natlab.research.philips.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/input.h>
34
35 #include "../../demux/mpeg/system.h"
36
37 #ifdef HAVE_UNISTD_H
38 #   include <unistd.h>
39 #endif
40
41 #include <fcntl.h>
42 #include <sys/types.h>
43 #include <string.h>
44 #include <errno.h>
45
46 #ifdef STRNCASECMP_IN_STRINGS_H
47 #   include <strings.h>
48 #endif
49
50 /* DVB Card Drivers */
51 #include <linux/dvb/dmx.h>
52 #include <linux/dvb/frontend.h>
53
54 #include "dvb.h"
55
56 #define SATELLITE_READ_ONCE 3
57
58 /*****************************************************************************
59  * Local prototypes
60  *****************************************************************************/
61 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
62                               size_t i_len);
63 static int     SatelliteSetArea    ( input_thread_t *, input_area_t * );
64 static int     SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
65 static void    SatelliteSeek       ( input_thread_t *, off_t );
66
67 /*****************************************************************************
68  * Open: open the frontend device
69  *****************************************************************************/
70 int E_(Open) ( vlc_object_t *p_this )
71 {
72     struct dvb_frontend_info frontend_info;
73     struct dvb_frontend_parameters fep;
74     input_thread_t *    p_input = (input_thread_t *)p_this;
75     input_socket_t *    p_satellite;
76     char *              psz_parser;
77     char *              psz_next;
78     int                 i_fd = 0;
79                 unsigned int                            u_adapter = 1;
80                 unsigned int                            u_device = 0;
81     unsigned int        u_freq = 0;
82     unsigned int        u_srate = 0;
83     vlc_bool_t          b_polarisation = 0;
84     int                 i_fec = 0;
85     fe_code_rate_t      fe_fec = FEC_NONE;
86     vlc_bool_t          b_diseqc;
87     vlc_bool_t                                  b_no_probe;
88     int                 i_lnb_lof1;
89     int                 i_lnb_lof2;
90     int                 i_lnb_slof;
91                 char                                                            dvr[] = DVR;
92                 char                                                            frontend[] = FRONTEND;
93                 int                                                                     i_len = 0;
94
95     /* parse the options passed in command line : */
96     psz_parser = strdup( p_input->psz_name );
97
98     if( !psz_parser )
99     {
100         return( -1 );
101     }
102
103     p_input->pf_read = SatelliteRead;
104     p_input->pf_set_program = SatelliteSetProgram;
105     p_input->pf_set_area = SatelliteSetArea;
106     p_input->pf_seek = SatelliteSeek;
107
108     // Get adapter and device number to use for this dvb card
109     u_adapter = config_GetInt( p_input, "adapter" );
110     u_device  = config_GetInt( p_input, "device" );
111
112     /* Determine frontend device information and capabilities */
113     b_no_probe = config_GetInt( p_input, "no-probe" );
114     if (!b_no_probe)
115           {
116         if ( ioctl_InfoFrontend(&frontend_info, u_adapter, u_device) < 0 )
117         {
118                 msg_Err( p_input, "(access) cannot determine frontend info" );
119             return -1;
120         }
121         if (frontend_info.type != FE_QPSK)
122         {
123             msg_Err( p_input, "frontend not of type satellite" );
124             return -1;
125         }
126     }
127           else /* no frontend probing is done so use default values. */
128                 {
129                           int i_len;
130                           
131                           msg_Dbg( p_input, "Using default values for frontend info" );
132                   i_len = sizeof(FRONTEND);
133                 if (snprintf(frontend, sizeof(FRONTEND), FRONTEND, u_adapter, u_device) >= i_len)
134                 {
135                   printf( "error: snprintf() truncated string for FRONTEND" );
136                         frontend[sizeof(FRONTEND)] = '\0';
137         }
138                           frontend_info.name = frontend;
139                           frontend_info.type = FE_QPSK;
140           frontend_info.frequency_max = 12999;
141         frontend_info.frequency_min = 10000;
142                                 frontend_info.symbol_rate_max = 30000;
143         frontend_info.symbol_rate_min = 1000;
144                                 /* b_polarisation */
145     }
146
147     u_freq = (int)strtol( psz_parser, &psz_next, 10 );
148     if( *psz_next )
149     {
150         psz_parser = psz_next + 1;
151         b_polarisation = (vlc_bool_t)strtol( psz_parser, &psz_next, 10 );
152         if( *psz_next )
153         {
154             psz_parser = psz_next + 1;
155             i_fec = (int)strtol( psz_parser, &psz_next, 10 );
156             if( *psz_next )
157             {
158                 psz_parser = psz_next + 1;
159                 u_srate = (int)strtol( psz_parser, &psz_next, 10 );
160             }
161         }
162     }
163
164     if ( ((u_freq) > frontend_info.frequency_max) ||
165          ((u_freq) < frontend_info.frequency_min) )
166     {
167         msg_Warn( p_input, "invalid frequency %d, using default one", u_freq );
168         u_freq = config_GetInt( p_input, "frequency" );
169         if ( ((u_freq) > frontend_info.frequency_max) ||
170              ((u_freq) < frontend_info.frequency_min) )
171         {
172             msg_Err( p_input, "invalid default frequency" );
173             return -1;
174         }
175     }
176
177     if ( ((u_srate) > frontend_info.symbol_rate_max) ||
178          ((u_srate) < frontend_info.symbol_rate_min) )
179     {
180         msg_Warn( p_input, "invalid symbol rate, using default one" );
181         u_srate = config_GetInt( p_input, "symbol-rate" );
182         if ( ((u_srate) > frontend_info.symbol_rate_max) ||
183              ((u_srate) < frontend_info.symbol_rate_min) )
184         {
185             msg_Err( p_input, "invalid default symbol rate" );
186             return -1;
187         }
188     }
189
190     if( b_polarisation && b_polarisation != 1 )
191     {
192         msg_Warn( p_input, "invalid polarization, using default one" );
193         b_polarisation = config_GetInt( p_input, "polarization" );
194         if( b_polarisation && b_polarisation != 1 )
195         {
196             msg_Err( p_input, "invalid default polarization" );
197             return -1;
198         }
199     }
200
201     if( (i_fec > 7) || (i_fec < 1) )
202     {
203         msg_Warn( p_input, "invalid FEC, using default one" );
204         i_fec = config_GetInt( p_input, "fec" );
205         if( (i_fec > 7) || (i_fec < 1) )
206         {
207             msg_Err( p_input, "invalid default FEC" );
208             return -1;
209         }
210     }
211
212     switch( i_fec )
213     {
214         case 1:
215             fe_fec = FEC_1_2;
216             break;
217         case 2:
218             fe_fec = FEC_2_3;
219             break;
220         case 3:
221             fe_fec = FEC_3_4;
222             break;
223         case 4:
224             fe_fec = FEC_4_5;
225             break;
226         case 5:
227             fe_fec = FEC_5_6;
228             break;
229         case 6:
230             fe_fec = FEC_6_7;
231             break;
232         case 7:
233             fe_fec = FEC_7_8;
234             break;
235         case 8:
236             fe_fec = FEC_8_9;
237             break;
238         case 9:
239             fe_fec = FEC_AUTO;
240             break;
241         default:
242             /* cannot happen */
243             fe_fec = FEC_NONE;
244             break;
245     }
246
247     switch( frontend_info.type )
248     {
249         case FE_QPSK:
250             fep.frequency = u_freq * 1000;
251             fep.inversion = INVERSION_AUTO;
252             fep.u.qpsk.symbol_rate = u_srate * 1000;
253             fep.u.qpsk.fec_inner = fe_fec;
254             msg_Dbg( p_input, "satellite frontend found on %s", frontend_info.name );
255             break;
256         case FE_QAM:
257             msg_Dbg( p_input, "cable frontend found on %s", frontend_info.name );
258             break;
259         case FE_OFDM:
260             msg_Dbg( p_input, "terrestrial frontend found on %s", frontend_info.name );
261             break;
262         default:
263             msg_Err( p_input, "Could not determine frontend type on %s", frontend_info.name );
264             return -1;
265     }
266
267     /* Initialise structure */
268     p_satellite = malloc( sizeof( input_socket_t ) );
269
270     if( p_satellite == NULL )
271     {
272         msg_Err( p_input, "out of memory" );
273         return -1;
274     }
275
276     p_input->p_access_data = (void *)p_satellite;
277
278     /* Open the DVR device */
279           i_len = sizeof(DVR);
280                 if (snprintf(dvr, sizeof(DVR), DVR, u_adapter, u_device) >= i_len)
281                 {
282                   msg_Err( p_input, "error: snprintf() truncated string for DVR" );
283                         dvr[sizeof(DVR)] = '\0';
284     }
285     msg_Dbg( p_input, "opening DVR device '%s'", dvr );
286
287     if( (p_satellite->i_handle = open( dvr,
288                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
289     {
290         msg_Warn( p_input, "cannot open `%s' (%s)", dvr, strerror(errno) );
291         free( p_satellite );
292         return -1;
293     }
294
295     /* Get antenna configuration options */
296     b_diseqc = config_GetInt( p_input, "diseqc" );
297     i_lnb_lof1 = config_GetInt( p_input, "lnb-lof1" );
298     i_lnb_lof2 = config_GetInt( p_input, "lnb-lof2" );
299     i_lnb_slof = config_GetInt( p_input, "lnb-slof" );
300
301     /* Initialize the Satellite Card */
302     msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
303                       "FEC: %d, Srate: %d", u_freq, b_polarisation, fe_fec, u_srate );
304
305     msg_Dbg( p_input, "initializing frontend device" );
306 //    switch (ioctl_SetQPSKFrontend ( u_freq * 1000, i_srate* 1000, fe_fec,
307 //                i_lnb_lof1 * 1000, i_lnb_lof2 * 1000, i_lnb_slof * 1000))
308     switch (ioctl_SetQPSKFrontend ( fep, b_polarisation, u_adapter, u_device ))
309     {
310         case -2:
311             msg_Err( p_input, "frontend returned an unexpected event" );
312             close( p_satellite->i_handle );
313             free( p_satellite );
314             return -1;
315         case -3:
316             msg_Err( p_input, "frontend returned no event" );
317             close( p_satellite->i_handle );
318             free( p_satellite );
319             return -1;
320         case -4:
321             msg_Err( p_input, "frontend: timeout when polling for event" );
322             close( p_satellite->i_handle );
323             free( p_satellite );
324             return -1;
325         case -5:
326             msg_Err( p_input, "an error occured when polling frontend device" );
327             close( p_satellite->i_handle );
328             free( p_satellite );
329             return -1;
330         case -1:
331             msg_Err( p_input, "frontend returned a failure event" );
332             close( p_satellite->i_handle );
333             free( p_satellite );
334             return -1;
335         default:
336             break;
337     }
338
339     msg_Dbg( p_input, "setting filter on PAT\n" );
340
341     if ( ioctl_SetDMXFilter( 0, &i_fd, 3, u_adapter, u_device ) < 0 )
342     {
343         msg_Err( p_input, "an error occured when setting filter on PAT" );
344         close( p_satellite->i_handle );
345         free( p_satellite );
346         return -1;
347     }
348
349     msg_Dbg( p_input, "@@@ Initialising input stream\n" );
350
351     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
352     {
353         msg_Err( p_input, "could not initialize stream structure" );
354         close( p_satellite->i_handle );
355         free( p_satellite );
356         return( -1 );
357     }
358
359     vlc_mutex_lock( &p_input->stream.stream_lock );
360
361     p_input->stream.b_pace_control = 1;
362     p_input->stream.b_seekable = 0;
363     p_input->stream.p_selected_area->i_tell = 0;
364
365     vlc_mutex_unlock( &p_input->stream.stream_lock );
366
367     p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
368     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
369
370     msg_Dbg( p_input, "@@@ Leaving E_(Open)\n" );
371     return 0;
372 }
373
374 /*****************************************************************************
375  * Close : Close the device
376  *****************************************************************************/
377 void E_(Close) ( vlc_object_t *p_this )
378 {
379     input_thread_t *    p_input = (input_thread_t *)p_this;
380     input_socket_t *    p_satellite;
381     unsigned int        i_es_index;
382
383     if ( p_input->stream.p_selected_program )
384     {
385         for ( i_es_index = 1 ;
386                 i_es_index < p_input->stream.p_selected_program->i_es_number;
387                 i_es_index ++ )
388         {
389 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
390             if ( p_es->p_decoder_fifo )
391             {
392                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
393             }
394 #undef p_es
395         }
396     }
397
398     p_satellite = (input_socket_t *)p_input;
399     close( p_satellite->i_handle );
400 }
401
402 /*****************************************************************************
403  * SatelliteRead: reads data from the satellite card
404  *****************************************************************************/
405 static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
406                               size_t i_len )
407 {
408     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
409     ssize_t i_ret;
410                 unsigned int                            u_adapter = 1;
411                 unsigned int                      u_device = 0;
412  
413     unsigned int i;
414
415     msg_Dbg( p_input, "@@@ SatelliteRead seeking for %d program\n", p_input->stream.i_pgrm_number );
416
417     // Get adapter and device number to use for this dvb card
418     u_adapter = config_GetInt( p_input, "adapter" );
419     u_device  = config_GetInt( p_input, "device" );
420
421     /* if not set, set filters to the PMTs */
422     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
423     {
424         msg_Dbg( p_input, "@@@ trying to set filter on pmt pid %d",
425                      p_input->stream.pp_programs[i]->pp_es[0]->i_id );
426
427         if ( p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd == 0 )
428         {
429             msg_Dbg( p_input, "setting filter on pmt pid %d",
430                      p_input->stream.pp_programs[i]->pp_es[0]->i_id );
431
432             ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
433                        &p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd,
434                        3, u_adapter, u_device );
435         }
436     }
437
438     i_ret = read( p_access_data->i_handle, p_buffer, i_len );
439  
440     if( i_ret < 0 )
441     {
442 #   ifdef HAVE_ERRNO_H
443         msg_Err( p_input, "read failed (%s)", strerror(errno) );
444 #   else
445         msg_Err( p_input, "read failed" );
446 #   endif
447     }
448
449     msg_Dbg( p_input, "@@@ Searched all, returning %d\n", i_ret );
450  
451     return i_ret;
452 }
453
454 /*****************************************************************************
455  * SatelliteSetArea : Does nothing
456  *****************************************************************************/
457 static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
458 {
459     return -1;
460 }
461
462 /*****************************************************************************
463  * SatelliteSetProgram : Sets the card filters according to the
464  *                 selected program,
465  *                 and makes the appropriate changes to stream structure.
466  *****************************************************************************/
467 int SatelliteSetProgram( input_thread_t    * p_input,
468                                                                                            pgrm_descriptor_t * p_new_prg )
469 {
470     unsigned int i_es_index;
471                 unsigned int u_adapter = 1;
472                 unsigned int u_device = 0;
473
474     msg_Dbg( p_input, "@@@ SatelliteSetProgram enter\n" );
475
476     // Get adapter and device number to use for this dvb card
477     u_adapter = config_GetInt( p_input, "adapter" );
478     u_device  = config_GetInt( p_input, "device" );
479
480     if ( p_input->stream.p_selected_program )
481     {
482         for ( i_es_index = 1 ; /* 0 should be the PMT */
483                 i_es_index < p_input->stream.p_selected_program->i_es_number ;
484                 i_es_index ++ )
485         {
486 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
487             if ( p_es->p_decoder_fifo )
488             {
489                 input_UnselectES( p_input , p_es );
490             }
491             if ( p_es->i_demux_fd )
492             {
493                 ioctl_UnsetDMXFilter( p_es->i_demux_fd );
494                 p_es->i_demux_fd = 0;
495             }
496 #undef p_es
497         }
498     }
499
500     for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
501     {
502 #define p_es p_new_prg->pp_es[i_es_index]
503         switch( p_es->i_cat )
504         {
505             case MPEG1_VIDEO_ES:
506             case MPEG2_VIDEO_ES:
507                 if ( input_SelectES( p_input , p_es ) == 0 )
508                 {
509                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 1, u_adapter, u_device);
510                 }
511                 break;
512             case MPEG1_AUDIO_ES:
513             case MPEG2_AUDIO_ES:
514                 if ( input_SelectES( p_input , p_es ) == 0 )
515                 {
516                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 2, u_adapter, u_device);
517                     input_SelectES( p_input , p_es );
518                 }
519                 break;
520             default:
521                 ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 3, u_adapter, u_device);
522                 input_SelectES( p_input , p_es );
523                 break;
524 #undef p_es
525         }
526     }
527
528     p_input->stream.p_selected_program = p_new_prg;
529
530     msg_Dbg( p_input, "@@@ SatelliteSetProgram exit\n" );
531     return 0;
532 }
533
534 /*****************************************************************************
535  * SatelliteSeek: does nothing (not a seekable stream
536  *****************************************************************************/
537 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
538 {
539     ;
540 }
541