access.c 20 KB
Newer Older
1
2
3
/*****************************************************************************
 * access.c: DVB card input v4l2 only
 *****************************************************************************
David Kaplan's avatar
David Kaplan committed
4
 * Copyright (C) 1998-2010 the VideoLAN team
5
6
 *
 * Authors: Johan Bilien <jobi@via.ecp.fr>
Jean-Paul Saman's avatar
Jean-Paul Saman committed
7
 *          Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
8
 *          Christophe Massiot <massiot@via.ecp.fr>
9
 *          Laurent Aimar <fenrir@via.ecp.fr>
David Kaplan's avatar
David Kaplan committed
10
 *          David Kaplan <david@2of1.org>
11
12
13
14
15
16
17
18
19
20
21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
22
23
24
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25
26
27
28
29
30
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/
31
32
33
34
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

35
#include <vlc_common.h>
36
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
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"
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
46
#include "scan.h"
47

48
49
50
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
51
52
53
static int  Open( vlc_object_t *p_this );
static void Close( vlc_object_t *p_this );

54
#define PROBE_TEXT N_("Probe DVB card for capabilities")
zorglub's avatar
zorglub committed
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 */
David Kaplan's avatar
David Kaplan committed
58
59
60
#define SATELLITE_TEXT N_("Satellite scanning config")
#define SATELLITE_LONGTEXT N_("filename of config file in share/dvb/dvb-s")

61
62
63
64
65
vlc_module_begin ()
    set_shortname( N_("DVB") )
    set_description( N_("DVB input with v4l2 support") )
    set_category( CAT_INPUT )
    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,
David Kaplan's avatar
David Kaplan committed
70
                true )
71

72
    set_capability( "access", 0 )
73
74
75
    add_shortcut( "dvb",                        /* Generic name */
                  "dvb-s", "qpsk", "satellite", /* Satellite */
                  "dvb-c", "cable",             /* Cable */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
76
                  "dvb-t", "terrestrial" )      /* Terrestrial */
77

78
    set_callbacks( Open, Close )
Laurent Aimar's avatar
Laurent Aimar committed
79

80
vlc_module_end ()
81

82

83
/*****************************************************************************
84
 * Local prototypes
85
 *****************************************************************************/
86
static int Control( access_t *, int, va_list );
87

Laurent Aimar's avatar
Laurent Aimar committed
88
89
static block_t *BlockScan( access_t * );

90
91
#define DVB_READ_ONCE 20
#define DVB_READ_ONCE_START 2
Laurent Aimar's avatar
Laurent Aimar committed
92
#define DVB_READ_ONCE_SCAN 1
93
#define TS_PACKET_SIZE 188
94

95
#define DVB_SCAN_MAX_SIGNAL_TIME (1000*1000)
Laurent Aimar's avatar
Laurent Aimar committed
96
#define DVB_SCAN_MAX_LOCK_TIME (5000*1000)
97
#define DVB_SCAN_MAX_PROBE_TIME (45000*1000)
Laurent Aimar's avatar
Laurent Aimar committed
98

Laurent Aimar's avatar
Laurent Aimar committed
99
static void FilterUnset( access_t *, int i_max );
100
static void FilterSet( access_t *, int i_pid, int i_type );
101

102
103
static void VarInit( access_t * );
static int  ParseMRL( access_t * );
104

105
106
107
108
109
110
111
112
113
/*****************************************************************************
 * Open: open the frontend device
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys;

    /* Only if selected */
114
    if( *p_access->psz_access == '\0' )
115
116
        return VLC_EGENERIC;

ivoire's avatar
ivoire committed
117
    p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
118
119
120
    if( !p_sys )
        return VLC_ENOMEM;

121
122
123
124
125
    /* Create all variables */
    VarInit( p_access );

    /* Parse the command line */
    if( ParseMRL( p_access ) )
126
    {
127
        free( p_sys );
128
129
130
131
132
        var_Destroy( p_access, "dvb-modulation" );
        var_Destroy( p_access, "dvb-fec" );
        var_Destroy( p_access, "dvb-code-rate-hp" );
        var_Destroy( p_access, "dvb-code-rate-lp" );
        var_Destroy( p_access, "dvb-guard" );
133
        return VLC_EGENERIC;
134
135
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
136
137
    bool b_scan_mode = var_GetInteger( p_access, "dvb-frequency" ) == 0;
    if( b_scan_mode )
138
    {
Laurent Aimar's avatar
Laurent Aimar committed
139
140
141
142
        msg_Dbg( p_access, "DVB scan mode selected" );
        p_access->pf_block = BlockScan;
    }
    else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
143
144
145
146
        return VLC_EGENERIC; /* let the DTV plugin do the work */

    /* Getting frontend info */
    if( FrontendOpen( p_access) )
Laurent Aimar's avatar
Laurent Aimar committed
147
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
148
149
        free( p_sys );
        return VLC_EGENERIC;
150
151
    }

152
    /* Opening DVR device */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
153
    if( DVROpen( p_access ) < 0 )
154
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
155
        FrontendClose( p_access );
156
157
        free( p_sys );
        return VLC_EGENERIC;
158
159
160
    }

    {
Laurent Aimar's avatar
Laurent Aimar committed
161
        scan_parameter_t parameter;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
162
        scan_t *p_scan;
Laurent Aimar's avatar
Laurent Aimar committed
163
164
165
166
167
168
169

        msg_Dbg( p_access, "setting filter on PAT/NIT/SDT (DVB only)" );
        FilterSet( p_access, 0x00, OTHER_TYPE );    // PAT
        FilterSet( p_access, 0x10, OTHER_TYPE );    // NIT
        FilterSet( p_access, 0x11, OTHER_TYPE );    // SDT

        if( FrontendGetScanParameter( p_access, &parameter ) ||
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
170
            (p_scan = scan_New( VLC_OBJECT(p_access), &parameter )) == NULL )
Laurent Aimar's avatar
Laurent Aimar committed
171
172
173
174
        {
            Close( VLC_OBJECT(p_access) );
            return VLC_EGENERIC;
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
175
176
        p_sys->scan = p_scan;
        p_sys->i_read_once = DVB_READ_ONCE_SCAN;
177
    }
Laurent Aimar's avatar
Laurent Aimar committed
178

179
    /* Set up access */
180
    free( p_access->psz_demux );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
181
    p_access->psz_demux = strdup( "m3u8" );
182
183
184
185
186
    p_access->pf_read = NULL;
    p_access->pf_control = Control;
    p_access->pf_seek = NULL;
    access_InitFields( p_access );

187
    return VLC_SUCCESS;
188
189
190
191
192
}

/*****************************************************************************
 * Close : Close the device
 *****************************************************************************/
193
static void Close( vlc_object_t *p_this )
194
{
195
196
    access_t     *p_access = (access_t*)p_this;
    access_sys_t *p_sys = p_access->p_sys;
197

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
198
    FilterUnset( p_access, MAX_DEMUX );
199

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
200
201
    DVRClose( p_access );
    FrontendClose( p_access );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
202
    scan_Destroy( p_sys->scan );
203

204
    free( p_sys );
205
206
}

Laurent Aimar's avatar
Laurent Aimar committed
207
208
209
210
211
212
/*****************************************************************************
 * BlockScan:
 *****************************************************************************/
static block_t *BlockScan( access_t *p_access )
{
    access_sys_t *p_sys = p_access->p_sys;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
213
    scan_t *p_scan = p_sys->scan;
Laurent Aimar's avatar
Laurent Aimar committed
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    scan_configuration_t cfg;

    /* */
    if( scan_Next( p_scan, &cfg ) )
    {
        const bool b_first_eof = !p_access->info.b_eof;

        if( b_first_eof )
            msg_Warn( p_access, "Scanning finished" );

        /* */
        p_access->info.b_eof = true;
        return b_first_eof ? scan_GetM3U( p_scan ) : NULL;
    }

    /* */
230
231
    scan_session_t *session = scan_session_New( VLC_OBJECT(p_access), &cfg );
    if( session == NULL )
Laurent Aimar's avatar
Laurent Aimar committed
232
233
234
        return NULL;

    /* */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
235
    msg_Dbg( p_access, "Scanning frequency %d", cfg.i_frequency );
Laurent Aimar's avatar
Laurent Aimar committed
236
    var_SetInteger( p_access, "dvb-frequency", cfg.i_frequency );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
237
    msg_Dbg( p_access, " bandwidth %d", cfg.i_bandwidth );
Laurent Aimar's avatar
Laurent Aimar committed
238
    var_SetInteger( p_access, "dvb-bandwidth", cfg.i_bandwidth );
David Kaplan's avatar
David Kaplan committed
239
    if ( cfg.i_fec )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
240
241
    {
        msg_Dbg( p_access, " FEC %d", cfg.i_fec );
David Kaplan's avatar
David Kaplan committed
242
        var_SetInteger( p_access, "dvb-fec", cfg.i_fec );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
243
    }
David Kaplan's avatar
David Kaplan committed
244
245
    if ( cfg.c_polarization )
        var_SetInteger( p_access, "dvb-voltage", cfg.c_polarization == 'H' ? 18 : 13 );
Laurent Aimar's avatar
Laurent Aimar committed
246

247
248
249
    if ( cfg.i_modulation )
        var_SetInteger( p_access, "dvb-modulation", cfg.i_modulation );

250
251
252
    if ( cfg.i_symbolrate )
        var_SetInteger( p_access, "dvb-srate", cfg.i_symbolrate );

Laurent Aimar's avatar
Laurent Aimar committed
253
254
255
256
257
    /* Setting frontend parameters for tuning the hardware */
    if( FrontendSet( p_access ) < 0 )
    {
        msg_Err( p_access, "Failed to tune the frontend" );
        p_access->info.b_eof = true;
258
        scan_session_Destroy( p_scan, session );
Laurent Aimar's avatar
Laurent Aimar committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
        return NULL;
    }

    /* */
    int64_t i_scan_start = mdate();

    bool b_has_dvb_signal = false;
    bool b_has_lock = false;
    int i_best_snr = -1;

    for ( ; ; )
    {
        struct pollfd ufds[2];
        int i_ret;

        /* Initialize file descriptor sets */
        memset (ufds, 0, sizeof (ufds));
        ufds[0].fd = p_sys->i_handle;
        ufds[0].events = POLLIN;
        ufds[1].fd = p_sys->i_frontend_handle;
        ufds[1].events = POLLPRI;

        /* We'll wait 0.1 second if nothing happens */
        /* Find if some data is available */
        i_ret = poll( ufds, 2, 100 );

        if( !vlc_object_alive (p_access) || scan_IsCancelled( p_scan ) )
            break;

        if( i_ret <= 0 )
        {
            const mtime_t i_scan_time = mdate() - i_scan_start;
            frontend_status_t status;

            FrontendGetStatus( p_access, &status );

            b_has_dvb_signal |= status.b_has_carrier;
            b_has_lock |= status.b_has_lock;

            if( ( !b_has_dvb_signal && i_scan_time > DVB_SCAN_MAX_SIGNAL_TIME ) ||
                ( !b_has_lock && i_scan_time > DVB_SCAN_MAX_LOCK_TIME ) ||
                ( i_scan_time > DVB_SCAN_MAX_PROBE_TIME ) )
            {
                msg_Dbg( p_access, "timed out scanning current frequency (s=%d l=%d)", b_has_dvb_signal, b_has_lock );
                break;
            }
        }

        if( i_ret < 0 )
        {
            if( errno == EINTR )
                continue;

            msg_Err( p_access, "poll error: %m" );
313
            scan_session_Destroy( p_scan, session );
Laurent Aimar's avatar
Laurent Aimar committed
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

            p_access->info.b_eof = true;
            return NULL;
        }

        if( ufds[1].revents )
        {
            frontend_statistic_t stat;

            FrontendPoll( p_access );

            if( !FrontendGetStatistic( p_access, &stat ) )
            {
                if( stat.i_snr > i_best_snr )
                    i_best_snr = stat.i_snr;
            }
        }

        if ( p_sys->i_frontend_timeout && mdate() > p_sys->i_frontend_timeout )
        {
            msg_Warn( p_access, "no lock, tuning again" );
            FrontendSet( p_access );
        }

        if ( ufds[0].revents )
        {
            const int i_read_once = 1;
            block_t *p_block = block_New( p_access, i_read_once * TS_PACKET_SIZE );

            if( ( i_ret = read( p_sys->i_handle, p_block->p_buffer,
                                i_read_once * TS_PACKET_SIZE ) ) <= 0 )
            {
                msg_Warn( p_access, "read failed (%m)" );
                block_Release( p_block );
                continue;
            }
            p_block->i_buffer = i_ret;

            /* */
353
            if( scan_session_Push( session, p_block ) )
Laurent Aimar's avatar
Laurent Aimar committed
354
355
356
357
358
359
360
361
362
            {
                msg_Dbg( p_access, "finished scanning current frequency" );
                break;
            }
        }
    }

    /* */
    if( i_best_snr > 0 )
363
        scan_service_SetSNR( session, i_best_snr );
Laurent Aimar's avatar
Laurent Aimar committed
364

365
    scan_session_Destroy( p_scan, session );
Laurent Aimar's avatar
Laurent Aimar committed
366
367
368
    return NULL;
}

369
/*****************************************************************************
370
 * Control:
371
 *****************************************************************************/
372
static int Control( access_t *p_access, int i_query, va_list args )
373
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
374
    bool         *pb_bool;
375
    int64_t      *pi_64;
376
377
    double       *pf1, *pf2;
    frontend_statistic_t stat;
378

379
    switch( i_query )
380
    {
381
382
383
384
385
        /* */
        case ACCESS_CAN_SEEK:
        case ACCESS_CAN_FASTSEEK:
        case ACCESS_CAN_PAUSE:
        case ACCESS_CAN_CONTROL_PACE:
386
387
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = false;
388
389
390
391
            break;
        /* */
        case ACCESS_GET_PTS_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
392
            *pi_64 = DEFAULT_PTS_DELAY;
393
            break;
394
395
396
397
398
399

        /* */
        case ACCESS_SET_PAUSE_STATE:
        case ACCESS_GET_TITLE_INFO:
        case ACCESS_SET_TITLE:
        case ACCESS_SET_SEEKPOINT:
400
        case ACCESS_GET_CONTENT_TYPE:
401
402
            return VLC_EGENERIC;

403
404
405
406
407
408
409
410
411
412
413
414
        case ACCESS_GET_SIGNAL:
            pf1 = (double*)va_arg( args, double * );
            pf2 = (double*)va_arg( args, double * );

            *pf1 = *pf2 = 0;
            if( !FrontendGetStatistic( p_access, &stat ) )
            {
                *pf1 = (double)stat.i_snr / 65535.0;
                *pf2 = (double)stat.i_signal_strenth / 65535.0;
            }
            return VLC_SUCCESS;

415
        case ACCESS_SET_PRIVATE_ID_STATE:
416
        case ACCESS_SET_PRIVATE_ID_CA:
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
417
            return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
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
433
434
435
436
437
438
439
    access_sys_t *p_sys = p_access->p_sys;
    int i;

    /* Find first free slot */
    for( i = 0; i < MAX_DEMUX; i++ )
    {
        if( !p_sys->p_demux_handles[i].i_type )
            break;
Laurent Aimar's avatar
Laurent Aimar committed
440
441
442

        if( p_sys->p_demux_handles[i].i_pid == i_pid )
            return; /* Already set */
443
444
445
446
447
448
449
450
    }

    if( i >= MAX_DEMUX )
    {
        msg_Err( p_access, "no free p_demux_handles !" );
        return;
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
451
    if( DMXSetFilter( p_access, i_pid,
452
453
454
455
456
457
458
                           &p_sys->p_demux_handles[i].i_handle, i_type ) )
    {
        msg_Err( p_access, "DMXSetFilter failed" );
        return;
    }
    p_sys->p_demux_handles[i].i_type = i_type;
    p_sys->p_demux_handles[i].i_pid = i_pid;
459
460
461

    if( p_sys->i_read_once < DVB_READ_ONCE )
        p_sys->i_read_once++;
462
463
}

Laurent Aimar's avatar
Laurent Aimar committed
464
static void FilterUnset( access_t *p_access, int i_max )
465
{
466
467
    access_sys_t *p_sys = p_access->p_sys;
    int i;
468

Laurent Aimar's avatar
Laurent Aimar committed
469
    for( i = 0; i < i_max; i++ )
470
    {
471
        if( p_sys->p_demux_handles[i].i_type )
472
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
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
485
486
487
488
489
    var_Destroy( p_access, "dvb-modulation" );
    var_Destroy( p_access, "dvb-fec" );
    var_Destroy( p_access, "dvb-code-rate-hp" );
    var_Destroy( p_access, "dvb-code-rate-lp" );
    var_Destroy( p_access, "dvb-guard" );

490
    /* */
491
492
493
494
495
    var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
496
497

    /* */
David Kaplan's avatar
David Kaplan committed
498
    var_Create( p_access, "dvb-satellite", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
499
500
    var_Create( p_access, "dvb-satno", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-voltage", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Christophe Massiot's avatar
Christophe Massiot committed
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
506
507
    var_Create( p_access, "dvb-lnb-lof1", VLC_VAR_INTEGER );
    var_Create( p_access, "dvb-lnb-lof2", VLC_VAR_INTEGER );
    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
514
    var_Create( p_access, "dvb-code-rate-hp", VLC_VAR_INTEGER );
    var_Create( p_access, "dvb-code-rate-lp", VLC_VAR_INTEGER );
515
516
    var_Create( p_access, "dvb-bandwidth", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    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
523
}

/* */
static int ParseMRL( access_t *p_access )
{
524
    char *psz_dup = strdup( p_access->psz_location );
525
526
527
528
529
530
    char *psz_parser = psz_dup;
    vlc_value_t         val;

#define GET_OPTION_INT( option )                                            \
    if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
    {                                                                       \
531
532
533
        val.i_int = strtol( psz_parser + strlen(option "="), &psz_parser,   \
                            0 );                                            \
        var_Set( p_access, "dvb-" option, val );                            \
534
535
536
537
538
539
540
    }

#define GET_OPTION_BOOL( option )                                           \
    if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
    {                                                                       \
        val.b_bool = strtol( psz_parser + strlen(option "="), &psz_parser,  \
                             0 );                                           \
541
        var_Set( p_access, "dvb-" option, val );                            \
542
    }
543

David Kaplan's avatar
David Kaplan committed
544
545
546
547
548
549
550
551
552
553
554
555
#define GET_OPTION_STRING( option )                                         \
    if ( !strncmp( psz_parser, option "=", strlen( option "=" ) ) )         \
    {                                                                       \
        psz_parser += strlen( option "=" );                                 \
        val.psz_string = psz_parser;                                        \
        char *p_save;                                                       \
        char *tok = strtok_r(val.psz_string, ":", &p_save);                 \
        val.psz_string[tok - val.psz_string - 1] = 0;                       \
        var_Set( p_access, "dvb-" option, val );                            \
        psz_parser += strlen( val.psz_string );                             \
    }

556
557
558
559
560
561
562
563
    while( *psz_parser )
    {
        GET_OPTION_INT("adapter")
        else GET_OPTION_INT("device")
        else GET_OPTION_INT("frequency")
        else GET_OPTION_INT("inversion")
        else GET_OPTION_BOOL("probe")
        else GET_OPTION_BOOL("budget-mode")
564

David Kaplan's avatar
David Kaplan committed
565
        else GET_OPTION_STRING("satellite")
566
        else GET_OPTION_INT("voltage")
Christophe Massiot's avatar
Christophe Massiot committed
567
        else GET_OPTION_BOOL("high-voltage")
568
        else GET_OPTION_INT("tone")
Christophe Massiot's avatar
Christophe Massiot committed
569
        else GET_OPTION_INT("satno")
570
571
        else GET_OPTION_INT("fec")
        else GET_OPTION_INT("srate")
572
573
574
        else GET_OPTION_INT("lnb-lof1")
        else GET_OPTION_INT("lnb-lof2")
        else GET_OPTION_INT("lnb-slof")
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602

        else GET_OPTION_INT("modulation")

        else GET_OPTION_INT("code-rate-hp")
        else GET_OPTION_INT("code-rate-lp")
        else GET_OPTION_INT("bandwidth")
        else GET_OPTION_INT("transmission")
        else GET_OPTION_INT("guard")
        else GET_OPTION_INT("hierarchy")

        /* Redundant with voltage but much easier to use */
        else if( !strncmp( psz_parser, "polarization=",
                           strlen( "polarization=" ) ) )
        {
            psz_parser += strlen( "polarization=" );
            if ( *psz_parser == 'V' || *psz_parser == 'v' )
                val.i_int = 13;
            else if ( *psz_parser == 'H' || *psz_parser == 'h' )
                val.i_int = 18;
            else
            {
                msg_Err( p_access, "illegal polarization %c", *psz_parser );
                free( psz_dup );
                return VLC_EGENERIC;
            }
            var_Set( p_access, "dvb-voltage", val );
        }
        else
603
        {
604
            msg_Err( p_access, "unknown option (%s)", psz_parser );
605
606
            free( psz_dup );
            return VLC_EGENERIC;
607
        }
608

609
610
        if ( *psz_parser )
            psz_parser++;
611
    }
612
613
#undef GET_OPTION_INT
#undef GET_OPTION_BOOL
David Kaplan's avatar
David Kaplan committed
614
#undef GET_OPTION_STRING
615

616
617
618
    free( psz_dup );
    return VLC_SUCCESS;
}
619