1 /*****************************************************************************
2 * access.c: DVB card input v4l2 only
3 *****************************************************************************
4 * Copyright (C) 1998-2010 VLC authors and VideoLAN
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>
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.
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.
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 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_access.h>
38 #include <vlc_input.h>
40 #include <sys/types.h>
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open( vlc_object_t *p_this );
52 static void Close( vlc_object_t *p_this );
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.")
58 #define SATELLITE_TEXT N_("Satellite scanning config")
59 #define SATELLITE_LONGTEXT N_("filename of config file in share/dvb/dvb-s")
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 )
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,
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 */
78 set_callbacks( Open, Close )
83 /*****************************************************************************
85 *****************************************************************************/
86 static int Control( access_t *, int, va_list );
88 static block_t *BlockScan( access_t * );
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
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)
99 static void FilterUnset( access_t *, int i_max );
100 static void FilterSet( access_t *, int i_pid, int i_type );
102 static void VarInit( access_t * );
103 static int ParseMRL( access_t * );
105 /*****************************************************************************
106 * Open: open the frontend device
107 *****************************************************************************/
108 static int Open( vlc_object_t *p_this )
110 access_t *p_access = (access_t*)p_this;
113 /* Only if selected */
114 if( *p_access->psz_access == '\0' )
117 p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
121 /* Create all variables */
124 /* Parse the command line */
125 if( ParseMRL( p_access ) )
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" );
136 bool b_scan_mode = var_GetInteger( p_access, "dvb-frequency" ) == 0;
139 msg_Dbg( p_access, "DVB scan mode selected" );
140 p_access->pf_block = BlockScan;
143 return VLC_EGENERIC; /* let the DTV plugin do the work */
145 /* Getting frontend info */
146 if( FrontendOpen( p_access) )
152 /* Opening DVR device */
153 if( DVROpen( p_access ) < 0 )
155 FrontendClose( p_access );
161 scan_parameter_t parameter;
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
169 if( FrontendGetScanParameter( p_access, ¶meter ) ||
170 (p_scan = scan_New( VLC_OBJECT(p_access), ¶meter )) == NULL )
172 Close( VLC_OBJECT(p_access) );
175 p_sys->scan = p_scan;
176 p_sys->i_read_once = DVB_READ_ONCE_SCAN;
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 );
190 /*****************************************************************************
191 * Close : Close the device
192 *****************************************************************************/
193 static void Close( vlc_object_t *p_this )
195 access_t *p_access = (access_t*)p_this;
196 access_sys_t *p_sys = p_access->p_sys;
198 FilterUnset( p_access, MAX_DEMUX );
200 DVRClose( p_access );
201 FrontendClose( p_access );
202 scan_Destroy( p_sys->scan );
207 /*****************************************************************************
209 *****************************************************************************/
210 static block_t *BlockScan( access_t *p_access )
212 access_sys_t *p_sys = p_access->p_sys;
213 scan_t *p_scan = p_sys->scan;
214 scan_configuration_t cfg;
217 if( scan_Next( p_scan, &cfg ) )
219 const bool b_first_eof = !p_access->info.b_eof;
222 msg_Warn( p_access, "Scanning finished" );
225 p_access->info.b_eof = true;
226 return b_first_eof ? scan_GetM3U( p_scan ) : NULL;
230 scan_session_t *session = scan_session_New( VLC_OBJECT(p_access), &cfg );
231 if( session == NULL )
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 );
241 msg_Dbg( p_access, " FEC %d", cfg.i_fec );
242 var_SetInteger( p_access, "dvb-fec", cfg.i_fec );
244 if ( cfg.c_polarization )
245 var_SetInteger( p_access, "dvb-voltage", cfg.c_polarization == 'H' ? 18 : 13 );
247 if ( cfg.i_modulation )
248 var_SetInteger( p_access, "dvb-modulation", cfg.i_modulation );
250 if ( cfg.i_symbolrate )
251 var_SetInteger( p_access, "dvb-srate", cfg.i_symbolrate );
253 /* Setting frontend parameters for tuning the hardware */
254 if( FrontendSet( p_access ) < 0 )
256 msg_Err( p_access, "Failed to tune the frontend" );
257 p_access->info.b_eof = true;
258 scan_session_Destroy( p_scan, session );
263 int64_t i_scan_start = mdate();
265 bool b_has_dvb_signal = false;
266 bool b_has_lock = false;
271 struct pollfd ufds[2];
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;
281 /* We'll wait 0.1 second if nothing happens */
282 /* Find if some data is available */
283 i_ret = poll( ufds, 2, 100 );
285 if( !vlc_object_alive (p_access) || scan_IsCancelled( p_scan ) )
290 const mtime_t i_scan_time = mdate() - i_scan_start;
291 frontend_status_t status;
293 FrontendGetStatus( p_access, &status );
295 b_has_dvb_signal |= status.b_has_carrier;
296 b_has_lock |= status.b_has_lock;
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 ) )
302 msg_Dbg( p_access, "timed out scanning current frequency (s=%d l=%d)", b_has_dvb_signal, b_has_lock );
312 msg_Err( p_access, "poll error: %m" );
313 scan_session_Destroy( p_scan, session );
315 p_access->info.b_eof = true;
319 if( ufds[1].revents )
321 frontend_statistic_t stat;
323 FrontendPoll( p_access );
325 if( !FrontendGetStatistic( p_access, &stat ) )
327 if( stat.i_snr > i_best_snr )
328 i_best_snr = stat.i_snr;
332 if ( p_sys->i_frontend_timeout && mdate() > p_sys->i_frontend_timeout )
334 msg_Warn( p_access, "no lock, tuning again" );
335 FrontendSet( p_access );
338 if ( ufds[0].revents )
340 const int i_read_once = 1;
341 block_t *p_block = block_New( p_access, i_read_once * TS_PACKET_SIZE );
343 if( ( i_ret = read( p_sys->i_handle, p_block->p_buffer,
344 i_read_once * TS_PACKET_SIZE ) ) <= 0 )
346 msg_Warn( p_access, "read failed (%m)" );
347 block_Release( p_block );
350 p_block->i_buffer = i_ret;
353 if( scan_session_Push( session, p_block ) )
355 msg_Dbg( p_access, "finished scanning current frequency" );
363 scan_service_SetSNR( session, i_best_snr );
365 scan_session_Destroy( p_scan, session );
369 /*****************************************************************************
371 *****************************************************************************/
372 static int Control( access_t *p_access, int i_query, va_list args )
377 frontend_statistic_t stat;
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* );
390 case ACCESS_GET_PTS_DELAY:
391 pi_64 = (int64_t*)va_arg( args, int64_t * );
392 *pi_64 = DEFAULT_PTS_DELAY;
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:
403 case ACCESS_GET_SIGNAL:
404 pf1 = (double*)va_arg( args, double * );
405 pf2 = (double*)va_arg( args, double * );
408 if( !FrontendGetStatistic( p_access, &stat ) )
410 *pf1 = (double)stat.i_snr / 65535.0;
411 *pf2 = (double)stat.i_signal_strenth / 65535.0;
415 case ACCESS_SET_PRIVATE_ID_STATE:
416 case ACCESS_SET_PRIVATE_ID_CA:
420 msg_Warn( p_access, "unimplemented query in control" );
427 /*****************************************************************************
428 * FilterSet/FilterUnset:
429 *****************************************************************************/
430 static void FilterSet( access_t *p_access, int i_pid, int i_type )
432 access_sys_t *p_sys = p_access->p_sys;
435 /* Find first free slot */
436 for( i = 0; i < MAX_DEMUX; i++ )
438 if( !p_sys->p_demux_handles[i].i_type )
441 if( p_sys->p_demux_handles[i].i_pid == i_pid )
442 return; /* Already set */
447 msg_Err( p_access, "no free p_demux_handles !" );
451 if( DMXSetFilter( p_access, i_pid,
452 &p_sys->p_demux_handles[i].i_handle, i_type ) )
454 msg_Err( p_access, "DMXSetFilter failed" );
457 p_sys->p_demux_handles[i].i_type = i_type;
458 p_sys->p_demux_handles[i].i_pid = i_pid;
460 if( p_sys->i_read_once < DVB_READ_ONCE )
461 p_sys->i_read_once++;
464 static void FilterUnset( access_t *p_access, int i_max )
466 access_sys_t *p_sys = p_access->p_sys;
469 for( i = 0; i < i_max; i++ )
471 if( p_sys->p_demux_handles[i].i_type )
473 DMXUnsetFilter( p_access, p_sys->p_demux_handles[i].i_handle );
474 p_sys->p_demux_handles[i].i_type = 0;
479 /*****************************************************************************
481 *****************************************************************************/
482 static void VarInit( access_t *p_access )
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" );
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 );
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 );
510 var_Create( p_access, "dvb-modulation", VLC_VAR_INTEGER );
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 );
522 static int ParseMRL( access_t *p_access )
524 char *psz_dup = strdup( p_access->psz_location );
525 char *psz_parser = psz_dup;
528 #define GET_OPTION_INT( option ) \
529 if ( !strncmp( psz_parser, option "=", strlen(option "=") ) ) \
531 val.i_int = strtol( psz_parser + strlen(option "="), &psz_parser, \
533 var_Set( p_access, "dvb-" option, val ); \
536 #define GET_OPTION_BOOL( option ) \
537 if ( !strncmp( psz_parser, option "=", strlen(option "=") ) ) \
539 val.b_bool = strtol( psz_parser + strlen(option "="), &psz_parser, \
541 var_Set( p_access, "dvb-" option, val ); \
544 #define GET_OPTION_STRING( option ) \
545 if ( !strncmp( psz_parser, option "=", strlen( option "=" ) ) ) \
547 psz_parser += strlen( option "=" ); \
548 val.psz_string = psz_parser; \
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 ); \
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")
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")
576 else GET_OPTION_INT("modulation")
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")
585 /* Redundant with voltage but much easier to use */
586 else if( !strncmp( psz_parser, "polarization=",
587 strlen( "polarization=" ) ) )
589 psz_parser += strlen( "polarization=" );
590 if ( *psz_parser == 'V' || *psz_parser == 'v' )
592 else if ( *psz_parser == 'H' || *psz_parser == 'h' )
596 msg_Err( p_access, "illegal polarization %c", *psz_parser );
600 var_Set( p_access, "dvb-voltage", val );
604 msg_Err( p_access, "unknown option (%s)", psz_parser );
612 #undef GET_OPTION_INT
613 #undef GET_OPTION_BOOL
614 #undef GET_OPTION_STRING