]> git.sesse.net Git - vlc/blob - modules/access/dvb/access.c
LGPL
[vlc] / modules / access / dvb / access.c
1 /*****************************************************************************
2  * access.c: DVB card input v4l2 only
3  *****************************************************************************
4  * Copyright (C) 1998-2010 VLC authors and VideoLAN
5  *
6  * Authors: Johan Bilien <jobi@via.ecp.fr>
7  *          Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Laurent Aimar <fenrir@via.ecp.fr>
10  *          David Kaplan <david@2of1.org>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_access.h>
38 #include <vlc_input.h>
39
40 #include <sys/types.h>
41 #include <poll.h>
42
43 #include <errno.h>
44
45 #include "dvb.h"
46 #include "scan.h"
47
48 /*****************************************************************************
49  * Module descriptor
50  *****************************************************************************/
51 static int  Open( vlc_object_t *p_this );
52 static void Close( vlc_object_t *p_this );
53
54 #define PROBE_TEXT N_("Probe DVB card for capabilities")
55 #define PROBE_LONGTEXT N_("Some DVB cards do not like to be probed for their capabilities, you can disable this feature if you experience some trouble.")
56
57 /* Satellite */
58 #define SATELLITE_TEXT N_("Satellite scanning config")
59 #define SATELLITE_LONGTEXT N_("filename of config file in share/dvb/dvb-s")
60
61 vlc_module_begin ()
62     set_shortname( N_("DVB") )
63     set_description( N_("DVB input with v4l2 support") )
64     set_category( CAT_INPUT )
65     set_subcategory( SUBCAT_INPUT_ACCESS )
66
67     add_bool( "dvb-probe", true, PROBE_TEXT, PROBE_LONGTEXT, true )
68     /* DVB-S (satellite) */
69     add_string( "dvb-satellite", NULL, SATELLITE_TEXT, SATELLITE_LONGTEXT,
70                 true )
71
72     set_capability( "access", 0 )
73     add_shortcut( "dvb",                        /* Generic name */
74                   "dvb-s", "qpsk", "satellite", /* Satellite */
75                   "dvb-c", "cable",             /* Cable */
76                   "dvb-t", "terrestrial" )      /* Terrestrial */
77
78     set_callbacks( Open, Close )
79
80 vlc_module_end ()
81
82
83 /*****************************************************************************
84  * Local prototypes
85  *****************************************************************************/
86 static int Control( access_t *, int, va_list );
87
88 static block_t *BlockScan( access_t * );
89
90 #define DVB_READ_ONCE 20
91 #define DVB_READ_ONCE_START 2
92 #define DVB_READ_ONCE_SCAN 1
93 #define TS_PACKET_SIZE 188
94
95 #define DVB_SCAN_MAX_SIGNAL_TIME (1000*1000)
96 #define DVB_SCAN_MAX_LOCK_TIME (5000*1000)
97 #define DVB_SCAN_MAX_PROBE_TIME (45000*1000)
98
99 static void FilterUnset( access_t *, int i_max );
100 static void FilterSet( access_t *, int i_pid, int i_type );
101
102 static void VarInit( access_t * );
103 static int  ParseMRL( access_t * );
104
105 /*****************************************************************************
106  * Open: open the frontend device
107  *****************************************************************************/
108 static int Open( vlc_object_t *p_this )
109 {
110     access_t     *p_access = (access_t*)p_this;
111     access_sys_t *p_sys;
112
113     /* Only if selected */
114     if( *p_access->psz_access == '\0' )
115         return VLC_EGENERIC;
116
117     p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
118     if( !p_sys )
119         return VLC_ENOMEM;
120
121     /* Create all variables */
122     VarInit( p_access );
123
124     /* Parse the command line */
125     if( ParseMRL( p_access ) )
126     {
127         free( p_sys );
128         var_Destroy( p_access, "dvb-modulation" );
129         var_Destroy( p_access, "dvb-fec" );
130         var_Destroy( p_access, "dvb-code-rate-hp" );
131         var_Destroy( p_access, "dvb-code-rate-lp" );
132         var_Destroy( p_access, "dvb-guard" );
133         return VLC_EGENERIC;
134     }
135
136     bool b_scan_mode = var_GetInteger( p_access, "dvb-frequency" ) == 0;
137     if( b_scan_mode )
138     {
139         msg_Dbg( p_access, "DVB scan mode selected" );
140         p_access->pf_block = BlockScan;
141     }
142     else
143         return VLC_EGENERIC; /* let the DTV plugin do the work */
144
145     /* Getting frontend info */
146     if( FrontendOpen( p_access) )
147     {
148         free( p_sys );
149         return VLC_EGENERIC;
150     }
151
152     /* Opening DVR device */
153     if( DVROpen( p_access ) < 0 )
154     {
155         FrontendClose( p_access );
156         free( p_sys );
157         return VLC_EGENERIC;
158     }
159
160     {
161         scan_parameter_t parameter;
162         scan_t *p_scan;
163
164         msg_Dbg( p_access, "setting filter on PAT/NIT/SDT (DVB only)" );
165         FilterSet( p_access, 0x00, OTHER_TYPE );    // PAT
166         FilterSet( p_access, 0x10, OTHER_TYPE );    // NIT
167         FilterSet( p_access, 0x11, OTHER_TYPE );    // SDT
168
169         if( FrontendGetScanParameter( p_access, &parameter ) ||
170             (p_scan = scan_New( VLC_OBJECT(p_access), &parameter )) == NULL )
171         {
172             Close( VLC_OBJECT(p_access) );
173             return VLC_EGENERIC;
174         }
175         p_sys->scan = p_scan;
176         p_sys->i_read_once = DVB_READ_ONCE_SCAN;
177     }
178
179     /* Set up access */
180     free( p_access->psz_demux );
181     p_access->psz_demux = strdup( "m3u8" );
182     p_access->pf_read = NULL;
183     p_access->pf_control = Control;
184     p_access->pf_seek = NULL;
185     access_InitFields( p_access );
186
187     return VLC_SUCCESS;
188 }
189
190 /*****************************************************************************
191  * Close : Close the device
192  *****************************************************************************/
193 static void Close( vlc_object_t *p_this )
194 {
195     access_t     *p_access = (access_t*)p_this;
196     access_sys_t *p_sys = p_access->p_sys;
197
198     FilterUnset( p_access, MAX_DEMUX );
199
200     DVRClose( p_access );
201     FrontendClose( p_access );
202     scan_Destroy( p_sys->scan );
203
204     free( p_sys );
205 }
206
207 /*****************************************************************************
208  * BlockScan:
209  *****************************************************************************/
210 static block_t *BlockScan( access_t *p_access )
211 {
212     access_sys_t *p_sys = p_access->p_sys;
213     scan_t *p_scan = p_sys->scan;
214     scan_configuration_t cfg;
215
216     /* */
217     if( scan_Next( p_scan, &cfg ) )
218     {
219         const bool b_first_eof = !p_access->info.b_eof;
220
221         if( b_first_eof )
222             msg_Warn( p_access, "Scanning finished" );
223
224         /* */
225         p_access->info.b_eof = true;
226         return b_first_eof ? scan_GetM3U( p_scan ) : NULL;
227     }
228
229     /* */
230     scan_session_t *session = scan_session_New( VLC_OBJECT(p_access), &cfg );
231     if( session == NULL )
232         return NULL;
233
234     /* */
235     msg_Dbg( p_access, "Scanning frequency %d", cfg.i_frequency );
236     var_SetInteger( p_access, "dvb-frequency", cfg.i_frequency );
237     msg_Dbg( p_access, " bandwidth %d", cfg.i_bandwidth );
238     var_SetInteger( p_access, "dvb-bandwidth", cfg.i_bandwidth );
239     if ( cfg.i_fec )
240     {
241         msg_Dbg( p_access, " FEC %d", cfg.i_fec );
242         var_SetInteger( p_access, "dvb-fec", cfg.i_fec );
243     }
244     if ( cfg.c_polarization )
245         var_SetInteger( p_access, "dvb-voltage", cfg.c_polarization == 'H' ? 18 : 13 );
246
247     if ( cfg.i_modulation )
248         var_SetInteger( p_access, "dvb-modulation", cfg.i_modulation );
249
250     if ( cfg.i_symbolrate )
251         var_SetInteger( p_access, "dvb-srate", cfg.i_symbolrate );
252
253     /* Setting frontend parameters for tuning the hardware */
254     if( FrontendSet( p_access ) < 0 )
255     {
256         msg_Err( p_access, "Failed to tune the frontend" );
257         p_access->info.b_eof = true;
258         scan_session_Destroy( p_scan, session );
259         return NULL;
260     }
261
262     /* */
263     int64_t i_scan_start = mdate();
264
265     bool b_has_dvb_signal = false;
266     bool b_has_lock = false;
267     int i_best_snr = -1;
268
269     for ( ; ; )
270     {
271         struct pollfd ufds[2];
272         int i_ret;
273
274         /* Initialize file descriptor sets */
275         memset (ufds, 0, sizeof (ufds));
276         ufds[0].fd = p_sys->i_handle;
277         ufds[0].events = POLLIN;
278         ufds[1].fd = p_sys->i_frontend_handle;
279         ufds[1].events = POLLPRI;
280
281         /* We'll wait 0.1 second if nothing happens */
282         /* Find if some data is available */
283         i_ret = poll( ufds, 2, 100 );
284
285         if( !vlc_object_alive (p_access) || scan_IsCancelled( p_scan ) )
286             break;
287
288         if( i_ret <= 0 )
289         {
290             const mtime_t i_scan_time = mdate() - i_scan_start;
291             frontend_status_t status;
292
293             FrontendGetStatus( p_access, &status );
294
295             b_has_dvb_signal |= status.b_has_carrier;
296             b_has_lock |= status.b_has_lock;
297
298             if( ( !b_has_dvb_signal && i_scan_time > DVB_SCAN_MAX_SIGNAL_TIME ) ||
299                 ( !b_has_lock && i_scan_time > DVB_SCAN_MAX_LOCK_TIME ) ||
300                 ( i_scan_time > DVB_SCAN_MAX_PROBE_TIME ) )
301             {
302                 msg_Dbg( p_access, "timed out scanning current frequency (s=%d l=%d)", b_has_dvb_signal, b_has_lock );
303                 break;
304             }
305         }
306
307         if( i_ret < 0 )
308         {
309             if( errno == EINTR )
310                 continue;
311
312             msg_Err( p_access, "poll error: %m" );
313             scan_session_Destroy( p_scan, session );
314
315             p_access->info.b_eof = true;
316             return NULL;
317         }
318
319         if( ufds[1].revents )
320         {
321             frontend_statistic_t stat;
322
323             FrontendPoll( p_access );
324
325             if( !FrontendGetStatistic( p_access, &stat ) )
326             {
327                 if( stat.i_snr > i_best_snr )
328                     i_best_snr = stat.i_snr;
329             }
330         }
331
332         if ( p_sys->i_frontend_timeout && mdate() > p_sys->i_frontend_timeout )
333         {
334             msg_Warn( p_access, "no lock, tuning again" );
335             FrontendSet( p_access );
336         }
337
338         if ( ufds[0].revents )
339         {
340             const int i_read_once = 1;
341             block_t *p_block = block_New( p_access, i_read_once * TS_PACKET_SIZE );
342
343             if( ( i_ret = read( p_sys->i_handle, p_block->p_buffer,
344                                 i_read_once * TS_PACKET_SIZE ) ) <= 0 )
345             {
346                 msg_Warn( p_access, "read failed (%m)" );
347                 block_Release( p_block );
348                 continue;
349             }
350             p_block->i_buffer = i_ret;
351
352             /* */
353             if( scan_session_Push( session, p_block ) )
354             {
355                 msg_Dbg( p_access, "finished scanning current frequency" );
356                 break;
357             }
358         }
359     }
360
361     /* */
362     if( i_best_snr > 0 )
363         scan_service_SetSNR( session, i_best_snr );
364
365     scan_session_Destroy( p_scan, session );
366     return NULL;
367 }
368
369 /*****************************************************************************
370  * Control:
371  *****************************************************************************/
372 static int Control( access_t *p_access, int i_query, va_list args )
373 {
374     bool         *pb_bool;
375     int64_t      *pi_64;
376     double       *pf1, *pf2;
377     frontend_statistic_t stat;
378
379     switch( i_query )
380     {
381         /* */
382         case ACCESS_CAN_SEEK:
383         case ACCESS_CAN_FASTSEEK:
384         case ACCESS_CAN_PAUSE:
385         case ACCESS_CAN_CONTROL_PACE:
386             pb_bool = (bool*)va_arg( args, bool* );
387             *pb_bool = false;
388             break;
389         /* */
390         case ACCESS_GET_PTS_DELAY:
391             pi_64 = (int64_t*)va_arg( args, int64_t * );
392             *pi_64 = DEFAULT_PTS_DELAY;
393             break;
394
395         /* */
396         case ACCESS_SET_PAUSE_STATE:
397         case ACCESS_GET_TITLE_INFO:
398         case ACCESS_SET_TITLE:
399         case ACCESS_SET_SEEKPOINT:
400         case ACCESS_GET_CONTENT_TYPE:
401             return VLC_EGENERIC;
402
403         case ACCESS_GET_SIGNAL:
404             pf1 = (double*)va_arg( args, double * );
405             pf2 = (double*)va_arg( args, double * );
406
407             *pf1 = *pf2 = 0;
408             if( !FrontendGetStatistic( p_access, &stat ) )
409             {
410                 *pf1 = (double)stat.i_snr / 65535.0;
411                 *pf2 = (double)stat.i_signal_strenth / 65535.0;
412             }
413             return VLC_SUCCESS;
414
415         case ACCESS_SET_PRIVATE_ID_STATE:
416         case ACCESS_SET_PRIVATE_ID_CA:
417             return VLC_EGENERIC;
418
419         default:
420             msg_Warn( p_access, "unimplemented query in control" );
421             return VLC_EGENERIC;
422
423     }
424     return VLC_SUCCESS;
425 }
426
427 /*****************************************************************************
428  * FilterSet/FilterUnset:
429  *****************************************************************************/
430 static void FilterSet( access_t *p_access, int i_pid, int i_type )
431 {
432     access_sys_t *p_sys = p_access->p_sys;
433     int i;
434
435     /* Find first free slot */
436     for( i = 0; i < MAX_DEMUX; i++ )
437     {
438         if( !p_sys->p_demux_handles[i].i_type )
439             break;
440
441         if( p_sys->p_demux_handles[i].i_pid == i_pid )
442             return; /* Already set */
443     }
444
445     if( i >= MAX_DEMUX )
446     {
447         msg_Err( p_access, "no free p_demux_handles !" );
448         return;
449     }
450
451     if( DMXSetFilter( p_access, i_pid,
452                            &p_sys->p_demux_handles[i].i_handle, i_type ) )
453     {
454         msg_Err( p_access, "DMXSetFilter failed" );
455         return;
456     }
457     p_sys->p_demux_handles[i].i_type = i_type;
458     p_sys->p_demux_handles[i].i_pid = i_pid;
459
460     if( p_sys->i_read_once < DVB_READ_ONCE )
461         p_sys->i_read_once++;
462 }
463
464 static void FilterUnset( access_t *p_access, int i_max )
465 {
466     access_sys_t *p_sys = p_access->p_sys;
467     int i;
468
469     for( i = 0; i < i_max; i++ )
470     {
471         if( p_sys->p_demux_handles[i].i_type )
472         {
473             DMXUnsetFilter( p_access, p_sys->p_demux_handles[i].i_handle );
474             p_sys->p_demux_handles[i].i_type = 0;
475         }
476     }
477 }
478
479 /*****************************************************************************
480  * VarInit/ParseMRL:
481  *****************************************************************************/
482 static void VarInit( access_t *p_access )
483 {
484     var_Destroy( p_access, "dvb-modulation" );
485     var_Destroy( p_access, "dvb-fec" );
486     var_Destroy( p_access, "dvb-code-rate-hp" );
487     var_Destroy( p_access, "dvb-code-rate-lp" );
488     var_Destroy( p_access, "dvb-guard" );
489
490     /* */
491     var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
492     var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
493     var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
494     var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
495     var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
496
497     /* */
498     var_Create( p_access, "dvb-satellite", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
499     var_Create( p_access, "dvb-satno", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
500     var_Create( p_access, "dvb-voltage", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
501     var_Create( p_access, "dvb-high-voltage", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
502     var_Create( p_access, "dvb-tone", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
503     var_Create( p_access, "dvb-fec", VLC_VAR_INTEGER );
504     var_Create( p_access, "dvb-srate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
505     var_Create( p_access, "dvb-lnb-lof1", VLC_VAR_INTEGER );
506     var_Create( p_access, "dvb-lnb-lof2", VLC_VAR_INTEGER );
507     var_Create( p_access, "dvb-lnb-slof", VLC_VAR_INTEGER );
508
509     /* */
510     var_Create( p_access, "dvb-modulation", VLC_VAR_INTEGER );
511
512     /* */
513     var_Create( p_access, "dvb-code-rate-hp", VLC_VAR_INTEGER );
514     var_Create( p_access, "dvb-code-rate-lp", VLC_VAR_INTEGER );
515     var_Create( p_access, "dvb-bandwidth", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
516     var_Create( p_access, "dvb-transmission", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
517     var_Create( p_access, "dvb-guard", VLC_VAR_INTEGER );
518     var_Create( p_access, "dvb-hierarchy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
519 }
520
521 /* */
522 static int ParseMRL( access_t *p_access )
523 {
524     char *psz_dup = strdup( p_access->psz_location );
525     char *psz_parser = psz_dup;
526     vlc_value_t         val;
527
528 #define GET_OPTION_INT( option )                                            \
529     if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
530     {                                                                       \
531         val.i_int = strtol( psz_parser + strlen(option "="), &psz_parser,   \
532                             0 );                                            \
533         var_Set( p_access, "dvb-" option, val );                            \
534     }
535
536 #define GET_OPTION_BOOL( option )                                           \
537     if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
538     {                                                                       \
539         val.b_bool = strtol( psz_parser + strlen(option "="), &psz_parser,  \
540                              0 );                                           \
541         var_Set( p_access, "dvb-" option, val );                            \
542     }
543
544 #define GET_OPTION_STRING( option )                                         \
545     if ( !strncmp( psz_parser, option "=", strlen( option "=" ) ) )         \
546     {                                                                       \
547         psz_parser += strlen( option "=" );                                 \
548         val.psz_string = psz_parser;                                        \
549         char *p_save;                                                       \
550         char *tok = strtok_r(val.psz_string, ":", &p_save);                 \
551         val.psz_string[tok - val.psz_string - 1] = 0;                       \
552         var_Set( p_access, "dvb-" option, val );                            \
553         psz_parser += strlen( val.psz_string );                             \
554     }
555
556     while( *psz_parser )
557     {
558         GET_OPTION_INT("adapter")
559         else GET_OPTION_INT("device")
560         else GET_OPTION_INT("frequency")
561         else GET_OPTION_INT("inversion")
562         else GET_OPTION_BOOL("probe")
563         else GET_OPTION_BOOL("budget-mode")
564
565         else GET_OPTION_STRING("satellite")
566         else GET_OPTION_INT("voltage")
567         else GET_OPTION_BOOL("high-voltage")
568         else GET_OPTION_INT("tone")
569         else GET_OPTION_INT("satno")
570         else GET_OPTION_INT("fec")
571         else GET_OPTION_INT("srate")
572         else GET_OPTION_INT("lnb-lof1")
573         else GET_OPTION_INT("lnb-lof2")
574         else GET_OPTION_INT("lnb-slof")
575
576         else GET_OPTION_INT("modulation")
577
578         else GET_OPTION_INT("code-rate-hp")
579         else GET_OPTION_INT("code-rate-lp")
580         else GET_OPTION_INT("bandwidth")
581         else GET_OPTION_INT("transmission")
582         else GET_OPTION_INT("guard")
583         else GET_OPTION_INT("hierarchy")
584
585         /* Redundant with voltage but much easier to use */
586         else if( !strncmp( psz_parser, "polarization=",
587                            strlen( "polarization=" ) ) )
588         {
589             psz_parser += strlen( "polarization=" );
590             if ( *psz_parser == 'V' || *psz_parser == 'v' )
591                 val.i_int = 13;
592             else if ( *psz_parser == 'H' || *psz_parser == 'h' )
593                 val.i_int = 18;
594             else
595             {
596                 msg_Err( p_access, "illegal polarization %c", *psz_parser );
597                 free( psz_dup );
598                 return VLC_EGENERIC;
599             }
600             var_Set( p_access, "dvb-voltage", val );
601         }
602         else
603         {
604             msg_Err( p_access, "unknown option (%s)", psz_parser );
605             free( psz_dup );
606             return VLC_EGENERIC;
607         }
608
609         if ( *psz_parser )
610             psz_parser++;
611     }
612 #undef GET_OPTION_INT
613 #undef GET_OPTION_BOOL
614 #undef GET_OPTION_STRING
615
616     free( psz_dup );
617     return VLC_SUCCESS;
618 }
619