4341c6cf3c70316a06620de31b90f5a21a6ad560
[vlc.git] / 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 #include <vlc_interrupt.h>
40
41 #include <sys/types.h>
42 #include <poll.h>
43
44 #include <errno.h>
45
46 #include "dvb.h"
47 #include "scan.h"
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52 static int  Open( vlc_object_t *p_this );
53 static void Close( vlc_object_t *p_this );
54
55 #define PROBE_TEXT N_("Probe DVB card for capabilities")
56 #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.")
57
58 /* Satellite */
59 #define SATELLITE_TEXT N_("Satellite scanning config")
60 #define SATELLITE_LONGTEXT N_("filename of config file in share/dvb/dvb-s")
61
62 #define SCANLIST_TEXT N_("Scan tuning list")
63 #define SCANLIST_LONGTEXT N_("filename containing initial scan tuning data")
64
65 #define SCAN_NIT_TEXT N_("Use NIT for scanning services")
66
67 vlc_module_begin ()
68     set_shortname( N_("DVB") )
69     set_description( N_("DVB input with v4l2 support") )
70     set_category( CAT_INPUT )
71     set_subcategory( SUBCAT_INPUT_ACCESS )
72
73     add_bool( "dvb-probe", true, PROBE_TEXT, PROBE_LONGTEXT, true )
74     /* DVB-S (satellite) */
75     add_string( "dvb-satellite", NULL, SATELLITE_TEXT, SATELLITE_LONGTEXT,
76                 true )
77     add_string( "dvb-scanlist", NULL, SCANLIST_TEXT, SCANLIST_LONGTEXT,
78                 true )
79     add_bool( "dvb-scan-nit", true, SCAN_NIT_TEXT, NULL, true )
80
81     set_capability( "access", 0 )
82     add_shortcut( "dvb",                        /* Generic name */
83                   "dvb-s", "qpsk", "satellite", /* Satellite */
84                   "dvb-c", "cable",             /* Cable */
85                   "dvb-t", "terrestrial" )      /* Terrestrial */
86
87     set_callbacks( Open, Close )
88
89 vlc_module_end ()
90
91
92 /*****************************************************************************
93  * Local prototypes
94  *****************************************************************************/
95 static int Control( access_t *, int, va_list );
96
97 static block_t *BlockScan( access_t * );
98
99 #define DVB_SCAN_MAX_LOCK_TIME (2*CLOCK_FREQ)
100
101 static void FilterUnset( access_t *, int i_max );
102 static void FilterSet( access_t *, int i_pid, int i_type );
103
104 static void VarInit( access_t * );
105 static int  ParseMRL( access_t * );
106
107 static int ScanFrontendTuningHandler( scan_t *, void *, const scan_tuner_config_t * );
108 static int ScanFilterHandler( scan_t *, void *, uint16_t, bool );
109 static int ScanStatsCallback( scan_t *p_scan, void *p_privdata, int *pi_snr );
110 static int ScanReadCallback( scan_t *, void *,  unsigned, size_t, uint8_t *, size_t *);
111
112 /*****************************************************************************
113  * Open: open the frontend device
114  *****************************************************************************/
115 static int Open( vlc_object_t *p_this )
116 {
117     access_t     *p_access = (access_t*)p_this;
118     access_sys_t *p_sys;
119
120     p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
121     if( !p_sys )
122         return VLC_ENOMEM;
123
124     /* Create all variables */
125     VarInit( p_access );
126
127     /* Parse the command line */
128     if( ParseMRL( p_access ) )
129     {
130         free( p_sys );
131         return VLC_EGENERIC;
132     }
133
134     bool b_scan_mode = var_GetInteger( p_access, "dvb-frequency" ) == 0;
135     if( b_scan_mode )
136     {
137         msg_Dbg( p_access, "DVB scan mode selected" );
138         p_access->pf_block = BlockScan;
139     }
140     else
141         return VLC_EGENERIC; /* let the DTV plugin do the work */
142
143     /* Getting frontend info */
144     if( FrontendOpen( p_this, &p_sys->dvb, p_access->psz_access ) )
145     {
146         free( p_sys );
147         return VLC_EGENERIC;
148     }
149
150     /* Opening DVR device */
151     if( DVROpen( p_this, &p_sys->dvb ) < 0 )
152     {
153         FrontendClose( p_this, &p_sys->dvb );
154         free( p_sys );
155         return VLC_EGENERIC;
156     }
157
158     scan_parameter_t parameter;
159     scan_t *p_scan;
160
161     scan_parameter_Init( &parameter );
162
163     parameter.b_use_nit = var_InheritBool( p_access, "dvb-scan-nit" );
164
165     if( FrontendFillScanParameter( p_this, &p_sys->dvb, &parameter ) ||
166             (p_scan = scan_New( VLC_OBJECT(p_access), &parameter,
167                                 ScanFrontendTuningHandler,
168                                 ScanStatsCallback,
169                                 ScanFilterHandler,
170                                 ScanReadCallback,
171                                 p_access )) == NULL )
172     {
173         scan_parameter_Clean( &parameter );
174         Close( VLC_OBJECT(p_access) );
175         return VLC_EGENERIC;
176     }
177
178     scan_parameter_Clean( &parameter );
179     p_sys->scan = p_scan;
180
181
182     /* Set up access */
183     p_access->pf_control = Control;
184     access_InitFields( p_access );
185
186     return VLC_SUCCESS;
187 }
188
189 /*****************************************************************************
190  * Close : Close the device
191  *****************************************************************************/
192 static void Close( vlc_object_t *p_this )
193 {
194     access_t     *p_access = (access_t*)p_this;
195     access_sys_t *p_sys = p_access->p_sys;
196
197     FilterUnset( p_access, MAX_DEMUX );
198
199     DVRClose( p_this, &p_sys->dvb );
200     FrontendClose( p_this, &p_sys->dvb );
201     scan_Destroy( p_sys->scan );
202
203     free( p_sys );
204 }
205
206 static int ScanFrontendTuningHandler( scan_t *p_scan, void *p_privdata,
207                                       const scan_tuner_config_t *p_cfg )
208 {
209     access_t *p_access = (access_t *) p_privdata;
210     VLC_UNUSED(p_scan);
211
212     var_SetInteger( p_access, "dvb-frequency", p_cfg->i_frequency );
213     var_SetInteger( p_access, "dvb-bandwidth", p_cfg->i_bandwidth );
214
215     if ( p_cfg->c_polarization )
216         var_SetInteger( p_access, "dvb-voltage", p_cfg->c_polarization == 'H' ? 18 : 13 );
217
218     if ( p_cfg->i_symbolrate )
219         var_SetInteger( p_access, "dvb-srate", p_cfg->i_symbolrate );
220
221     msg_Dbg( p_access, "Scanning frequency %d", p_cfg->i_frequency );
222     msg_Dbg( p_access, " bandwidth %d", p_cfg->i_bandwidth );
223
224     /* Setting frontend parameters for tuning the hardware */
225     if( FrontendSet( VLC_OBJECT(p_access), &p_access->p_sys->dvb ) < 0 )
226     {
227         msg_Err( p_access, "Failed to tune the frontend" );
228         return VLC_EGENERIC;
229     }
230
231     return VLC_SUCCESS;
232 }
233
234 static int ScanStatsCallback( scan_t *p_scan, void *p_privdata, int *pi_snr )
235 {
236     access_t *p_access = (access_t *) p_privdata;
237     VLC_UNUSED(p_scan);
238
239     frontend_statistic_t stat;
240     if( !FrontendGetStatistic( &p_access->p_sys->dvb, &stat ) )
241     {
242         *pi_snr = stat.i_snr;
243         return VLC_SUCCESS;
244     }
245
246     return VLC_EGENERIC;
247 }
248
249 static int ScanFilterHandler( scan_t *p_scan, void *p_privdata, uint16_t i_pid, bool b_set )
250 {
251     access_t *p_access = (access_t *) p_privdata;
252     VLC_UNUSED(p_scan);
253
254     if( b_set )
255         FilterSet( p_access, i_pid, OTHER_TYPE );
256
257     return VLC_SUCCESS;
258 }
259
260 static int ScanReadCallback( scan_t *p_scan, void *p_privdata,
261                              unsigned i_probe_timeout, size_t i_packets_max,
262                              uint8_t *p_packet, size_t *pi_count )
263 {
264     access_t *p_access = (access_t *) p_privdata;
265     access_sys_t *p_sys = p_access->p_sys;
266     *pi_count = 0;
267
268     /* Initialize file descriptor sets */
269     struct pollfd ufds[2];
270
271     ufds[0].fd = p_sys->dvb.i_handle;
272     ufds[0].events = POLLIN;
273     ufds[1].fd = p_sys->dvb.i_frontend_handle;
274     ufds[1].events = POLLPRI;
275
276     frontend_status_t status;
277     FrontendGetStatus( &p_sys->dvb, &status );
278     bool b_has_lock = status.b_has_lock;
279
280     mtime_t i_scan_start = mdate();
281
282     for( ; *pi_count == 0; )
283     {
284         /* Find if some data is available */
285         int i_ret;
286
287         mtime_t i_timeout = b_has_lock ? i_probe_timeout:
288                                          DVB_SCAN_MAX_LOCK_TIME;
289
290         do
291         {
292             mtime_t i_poll_timeout = i_scan_start - mdate() + i_timeout;
293
294             i_ret = 0;
295
296             if( vlc_killed() || scan_IsCancelled( p_scan ) )
297                 break;
298
299             if( i_poll_timeout >= 0 )
300                 i_ret = vlc_poll_i11e( ufds, 2, i_poll_timeout / 1000 );
301         }
302         while( i_ret < 0 && errno == EINTR );
303
304         if( i_ret < 0 )
305         {
306             return VLC_EGENERIC;
307         }
308         else if( i_ret == 0 )
309         {
310             return VLC_ENOITEM;
311         }
312
313         if( ufds[1].revents )
314         {
315             FrontendPoll( VLC_OBJECT(p_access), &p_sys->dvb );
316
317             FrontendGetStatus( &p_sys->dvb, &status );
318             if( status.b_has_lock && !b_has_lock )
319             {
320                 i_scan_start = mdate();
321                 b_has_lock = true;
322             }
323         }
324
325         if ( ufds[0].revents )
326         {
327             ssize_t i_read = read( p_sys->dvb.i_handle, p_packet, TS_PACKET_SIZE * i_packets_max );
328             if( i_read < 0 )
329             {
330                 msg_Warn( p_access, "read failed: %s", vlc_strerror_c(errno) );
331                 break;
332             }
333             else
334             {
335                 *pi_count = i_read / TS_PACKET_SIZE;
336             }
337         }
338     }
339
340     return VLC_SUCCESS;
341 }
342
343 /*****************************************************************************
344  * BlockScan:
345  *****************************************************************************/
346 static block_t *BlockScan( access_t *p_access )
347 {
348     access_sys_t *p_sys = p_access->p_sys;
349     scan_t *p_scan = p_sys->scan;
350     block_t *p_block = NULL;
351
352     if( scan_Run( p_scan ) != VLC_SUCCESS )
353     {
354         if( !p_access->info.b_eof )
355         {
356              msg_Warn( p_access, "Scanning finished" );
357              p_block = scan_GetM3U( p_scan );
358         }
359         p_access->info.b_eof = true;
360     }
361
362     return p_block;
363 }
364
365 /*****************************************************************************
366  * Control:
367  *****************************************************************************/
368 static int Control( access_t *p_access, int i_query, va_list args )
369 {
370     bool         *pb_bool;
371     int64_t      *pi_64;
372     double       *pf1, *pf2;
373     frontend_statistic_t stat;
374
375     switch( i_query )
376     {
377         case ACCESS_CAN_SEEK:
378         case ACCESS_CAN_FASTSEEK:
379         case ACCESS_CAN_PAUSE:
380         case ACCESS_CAN_CONTROL_PACE:
381             pb_bool = (bool*)va_arg( args, bool* );
382             *pb_bool = false;
383             break;
384
385         case ACCESS_GET_CONTENT_TYPE:
386             *va_arg( args, char** ) = strdup("application/vnd.apple.mpegurl"); // m3u8
387             return VLC_SUCCESS;
388
389         case ACCESS_GET_PTS_DELAY:
390             pi_64 = (int64_t*)va_arg( args, int64_t * );
391             *pi_64 = DEFAULT_PTS_DELAY;
392             break;
393
394         case ACCESS_GET_SIGNAL:
395             pf1 = (double*)va_arg( args, double * );
396             pf2 = (double*)va_arg( args, double * );
397
398             *pf1 = *pf2 = 0;
399             if( !FrontendGetStatistic( &p_access->p_sys->dvb, &stat ) )
400             {
401                 *pf1 = (double)stat.i_snr / 65535.0;
402                 *pf2 = (double)stat.i_signal_strenth / 65535.0;
403             }
404             break;
405
406         default:
407             return VLC_EGENERIC;
408
409     }
410     return VLC_SUCCESS;
411 }
412
413 /*****************************************************************************
414  * FilterSet/FilterUnset:
415  *****************************************************************************/
416 static void FilterSet( access_t *p_access, int i_pid, int i_type )
417 {
418     access_sys_t *p_sys = p_access->p_sys;
419     int i;
420
421     /* Find first free slot */
422     for( i = 0; i < MAX_DEMUX; i++ )
423     {
424         if( !p_sys->p_demux_handles[i].i_type )
425             break;
426
427         if( p_sys->p_demux_handles[i].i_pid == i_pid )
428             return; /* Already set */
429     }
430
431     if( i >= MAX_DEMUX )
432     {
433         msg_Err( p_access, "no free p_demux_handles !" );
434         return;
435     }
436
437     if( DMXSetFilter( VLC_OBJECT(p_access), i_pid,
438                            &p_sys->p_demux_handles[i].i_handle, i_type ) )
439     {
440         msg_Err( p_access, "DMXSetFilter failed" );
441         return;
442     }
443     p_sys->p_demux_handles[i].i_type = i_type;
444     p_sys->p_demux_handles[i].i_pid = i_pid;
445 }
446
447 static void FilterUnset( access_t *p_access, int i_max )
448 {
449     access_sys_t *p_sys = p_access->p_sys;
450     int i;
451
452     for( i = 0; i < i_max; i++ )
453     {
454         if( p_sys->p_demux_handles[i].i_type )
455         {
456             DMXUnsetFilter( VLC_OBJECT(p_access), p_sys->p_demux_handles[i].i_handle );
457             p_sys->p_demux_handles[i].i_type = 0;
458         }
459     }
460 }
461
462 /*****************************************************************************
463  * VarInit/ParseMRL:
464  *****************************************************************************/
465 static void VarInit( access_t *p_access )
466 {
467     var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
468     var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
469     var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
470     var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
471     var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
472
473     /* */
474     var_Create( p_access, "dvb-satellite", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
475     var_Create( p_access, "dvb-satno", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
476     var_Create( p_access, "dvb-voltage", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
477     var_Create( p_access, "dvb-high-voltage", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
478     var_Create( p_access, "dvb-tone", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
479     var_Create( p_access, "dvb-srate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
480     var_Create( p_access, "dvb-lnb-lof1", VLC_VAR_INTEGER );
481     var_Create( p_access, "dvb-lnb-lof2", VLC_VAR_INTEGER );
482     var_Create( p_access, "dvb-lnb-slof", VLC_VAR_INTEGER );
483
484     /* */
485     var_Create( p_access, "dvb-bandwidth", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
486     var_Create( p_access, "dvb-transmission", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
487     var_Create( p_access, "dvb-hierarchy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
488 }
489
490 /* */
491 static int ParseMRL( access_t *p_access )
492 {
493     char *psz_dup = strdup( p_access->psz_location );
494     char *psz_parser = psz_dup;
495     vlc_value_t         val;
496
497 #define GET_OPTION_INT( option )                                            \
498     if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
499     {                                                                       \
500         val.i_int = strtol( psz_parser + strlen(option "="), &psz_parser,   \
501                             0 );                                            \
502         var_Set( p_access, "dvb-" option, val );                            \
503     }
504
505 #define GET_OPTION_BOOL( option )                                           \
506     if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
507     {                                                                       \
508         val.b_bool = strtol( psz_parser + strlen(option "="), &psz_parser,  \
509                              0 );                                           \
510         var_Set( p_access, "dvb-" option, val );                            \
511     }
512
513 #define GET_OPTION_STRING( option )                                         \
514     if ( !strncmp( psz_parser, option "=", strlen( option "=" ) ) )         \
515     {                                                                       \
516         psz_parser += strlen( option "=" );                                 \
517         val.psz_string = psz_parser;                                        \
518         char *p_save;                                                       \
519         char *tok = strtok_r(val.psz_string, ":", &p_save);                 \
520         val.psz_string[tok - val.psz_string - 1] = 0;                       \
521         var_Set( p_access, "dvb-" option, val );                            \
522         psz_parser += strlen( val.psz_string );                             \
523     }
524
525     while( *psz_parser )
526     {
527         GET_OPTION_INT("adapter")
528         else GET_OPTION_INT("device")
529         else GET_OPTION_INT("frequency")
530         else GET_OPTION_INT("inversion")
531         else GET_OPTION_BOOL("probe")
532         else GET_OPTION_BOOL("budget-mode")
533
534         else GET_OPTION_STRING("satellite")
535         else GET_OPTION_INT("voltage")
536         else GET_OPTION_BOOL("high-voltage")
537         else GET_OPTION_INT("tone")
538         else GET_OPTION_INT("satno")
539         else GET_OPTION_INT("srate")
540         else GET_OPTION_INT("lnb-lof1")
541         else GET_OPTION_INT("lnb-lof2")
542         else GET_OPTION_INT("lnb-slof")
543
544         else GET_OPTION_INT("bandwidth")
545         else GET_OPTION_INT("transmission")
546         else GET_OPTION_INT("hierarchy")
547
548         /* Redundant with voltage but much easier to use */
549         else if( !strncmp( psz_parser, "polarization=",
550                            strlen( "polarization=" ) ) )
551         {
552             psz_parser += strlen( "polarization=" );
553             if ( *psz_parser == 'V' || *psz_parser == 'v' )
554                 val.i_int = 13;
555             else if ( *psz_parser == 'H' || *psz_parser == 'h' )
556                 val.i_int = 18;
557             else
558             {
559                 msg_Err( p_access, "illegal polarization %c", *psz_parser );
560                 free( psz_dup );
561                 return VLC_EGENERIC;
562             }
563             var_Set( p_access, "dvb-voltage", val );
564         }
565         else
566         {
567             msg_Err( p_access, "unknown option (%s)", psz_parser );
568             free( psz_dup );
569             return VLC_EGENERIC;
570         }
571
572         if ( *psz_parser )
573             psz_parser++;
574     }
575 #undef GET_OPTION_INT
576 #undef GET_OPTION_BOOL
577 #undef GET_OPTION_STRING
578
579     free( psz_dup );
580     return VLC_SUCCESS;
581 }
582