access.c 18.8 KB
Newer Older
1 2 3
/*****************************************************************************
 * access.c: DVB card input v4l2 only
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 1998-2010 VLC authors and VideoLAN
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
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
12 13 14
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
15 16 17 18
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
21
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
22 23 24
 * You should have received a copy of the GNU Lesser 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>
Clément Stenac's avatar
Clément Stenac committed
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"
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
47
#include "scan.h"
48

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

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

62 63 64
#define SCANLIST_TEXT N_("Scan tuning list")
#define SCANLIST_LONGTEXT N_("filename containing initial scan tuning data")

65 66
#define SCAN_NIT_TEXT N_("Use NIT for scanning services")

67 68 69 70 71
vlc_module_begin ()
    set_shortname( N_("DVB") )
    set_description( N_("DVB input with v4l2 support") )
    set_category( CAT_INPUT )
    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,
David Kaplan's avatar
David Kaplan committed
76
                true )
77 78
    add_string( "dvb-scanlist", NULL, SCANLIST_TEXT, SCANLIST_LONGTEXT,
                true )
79
    add_bool( "dvb-scan-nit", true, SCAN_NIT_TEXT, NULL, true )
80

81
    set_capability( "access", 0 )
82 83 84
    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
85
                  "dvb-t", "terrestrial" )      /* Terrestrial */
86

87
    set_callbacks( Open, Close )
Laurent Aimar's avatar
Laurent Aimar committed
88

89
vlc_module_end ()
90

91

92
/*****************************************************************************
93
 * Local prototypes
94
 *****************************************************************************/
95
static int Control( access_t *, int, va_list );
96

Laurent Aimar's avatar
Laurent Aimar committed
97 98
static block_t *BlockScan( access_t * );

99
#define DVB_SCAN_MAX_SIGNAL_TIME (1000*1000)
Laurent Aimar's avatar
Laurent Aimar committed
100 101
#define DVB_SCAN_MAX_LOCK_TIME (5000*1000)

Laurent Aimar's avatar
Laurent Aimar committed
102
static void FilterUnset( access_t *, int i_max );
103
static void FilterSet( access_t *, int i_pid, int i_type );
104

105 106
static void VarInit( access_t * );
static int  ParseMRL( access_t * );
107

108 109 110 111 112 113 114 115 116
/*****************************************************************************
 * 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 */
117
    if( *p_access->psz_access == '\0' )
118 119
        return VLC_EGENERIC;

120
    p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
121 122 123
    if( !p_sys )
        return VLC_ENOMEM;

124 125 126 127 128
    /* Create all variables */
    VarInit( p_access );

    /* Parse the command line */
    if( ParseMRL( p_access ) )
129
    {
130 131
        free( p_sys );
        return VLC_EGENERIC;
132 133
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
134 135
    bool b_scan_mode = var_GetInteger( p_access, "dvb-frequency" ) == 0;
    if( b_scan_mode )
136
    {
Laurent Aimar's avatar
Laurent Aimar committed
137 138 139 140
        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
141 142 143 144
        return VLC_EGENERIC; /* let the DTV plugin do the work */

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

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

François Cartegnie's avatar
François Cartegnie committed
158 159
    scan_parameter_t parameter;
    scan_t *p_scan;
Laurent Aimar's avatar
Laurent Aimar committed
160

François Cartegnie's avatar
François Cartegnie committed
161
    scan_parameter_Init( &parameter );
162

François Cartegnie's avatar
François Cartegnie committed
163
    parameter.b_use_nit = var_InheritBool( p_access, "dvb-scan-nit" );
164

François Cartegnie's avatar
François Cartegnie committed
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, 0x11, OTHER_TYPE );    // SDT
    if( parameter.b_use_nit )
        FilterSet( p_access, 0x10, OTHER_TYPE );    // NIT
Laurent Aimar's avatar
Laurent Aimar committed
170

François Cartegnie's avatar
François Cartegnie committed
171
    if( FrontendFillScanParameter( p_access, &parameter ) ||
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
172
            (p_scan = scan_New( VLC_OBJECT(p_access), &parameter )) == NULL )
François Cartegnie's avatar
François Cartegnie committed
173
    {
174
        scan_parameter_Clean( &parameter );
François Cartegnie's avatar
François Cartegnie committed
175 176
        Close( VLC_OBJECT(p_access) );
        return VLC_EGENERIC;
177
    }
François Cartegnie's avatar
François Cartegnie committed
178 179 180
    scan_parameter_Clean( &parameter );
    p_sys->scan = p_scan;

Laurent Aimar's avatar
Laurent Aimar committed
181

182 183 184 185
    /* Set up access */
    p_access->pf_control = Control;
    access_InitFields( p_access );

186
    return VLC_SUCCESS;
187 188 189 190 191
}

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

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

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

203
    free( p_sys );
204 205
}

Laurent Aimar's avatar
Laurent Aimar committed
206 207 208 209 210 211
/*****************************************************************************
 * 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
212
    scan_t *p_scan = p_sys->scan;
213
    scan_tuner_config_t cfg;
Laurent Aimar's avatar
Laurent Aimar committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

    /* */
    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;
    }

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

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

241 242 243
    if ( cfg.i_symbolrate )
        var_SetInteger( p_access, "dvb-srate", cfg.i_symbolrate );

Laurent Aimar's avatar
Laurent Aimar committed
244 245 246 247
    /* Setting frontend parameters for tuning the hardware */
    if( FrontendSet( p_access ) < 0 )
    {
        msg_Err( p_access, "Failed to tune the frontend" );
248
        //p_access->info.b_eof = true;
249
        scan_session_Destroy( p_scan, session );
Laurent Aimar's avatar
Laurent Aimar committed
250 251 252 253 254
        return NULL;
    }

    /* */
    int64_t i_scan_start = mdate();
255
    int64_t i_probe_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
256 257 258 259 260

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

261 262 263 264 265 266 267 268
    /* Initialize file descriptor sets */
    struct pollfd ufds[2];

    ufds[0].fd = p_sys->i_handle;
    ufds[0].events = POLLIN;
    ufds[1].fd = p_sys->i_frontend_handle;
    ufds[1].events = POLLPRI;

Laurent Aimar's avatar
Laurent Aimar committed
269 270
    for ( ; ; )
    {
271 272 273 274
        frontend_status_t status;
        FrontendGetStatus( p_access, &status );
        b_has_dvb_signal |= status.b_has_carrier;
        b_has_lock |= status.b_has_lock;
Laurent Aimar's avatar
Laurent Aimar committed
275

276 277 278 279 280
        int64_t i_scan_end;
        if( i_probe_start )
        {
            i_scan_end = i_probe_start + scan_session_GetTablesTimeout( session );
        }
281
        else
282 283 284 285 286 287 288
        {
            i_scan_end = i_scan_start;
            if( !b_has_dvb_signal )
                i_scan_end += DVB_SCAN_MAX_SIGNAL_TIME;
            else if( !b_has_lock )
                i_scan_end += DVB_SCAN_MAX_LOCK_TIME;
        }
Laurent Aimar's avatar
Laurent Aimar committed
289

290 291
        /* Find if some data is available */
        int i_ret;
Laurent Aimar's avatar
Laurent Aimar committed
292

293
        do
Laurent Aimar's avatar
Laurent Aimar committed
294
        {
295
            int64_t timeout = i_scan_end - mdate();
Laurent Aimar's avatar
Laurent Aimar committed
296

297
            i_ret = 0;
Laurent Aimar's avatar
Laurent Aimar committed
298

299
            if( vlc_killed() || scan_IsCancelled( p_scan ) )
Laurent Aimar's avatar
Laurent Aimar committed
300
                break;
301 302 303

            if( timeout >= 0 )
                i_ret = vlc_poll_i11e( ufds, 2, timeout / 1000 );
Laurent Aimar's avatar
Laurent Aimar committed
304
        }
305
        while( i_ret < 0 && errno == EINTR );
Laurent Aimar's avatar
Laurent Aimar committed
306 307 308

        if( i_ret < 0 )
        {
309
            msg_Err( p_access, "poll error: %s", vlc_strerror_c(errno) );
Laurent Aimar's avatar
Laurent Aimar committed
310
            p_access->info.b_eof = true;
311 312 313 314 315 316 317 318 319
            break;
        }

        if( i_ret == 0 )
        {
            msg_Dbg( p_access,
                     "timed out scanning current frequency (s=%d l=%d)",
                     b_has_dvb_signal, b_has_lock );
            break;
Laurent Aimar's avatar
Laurent Aimar committed
320 321 322 323 324 325 326 327 328 329 330
        }

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

            FrontendPoll( p_access );

            if( !FrontendGetStatistic( p_access, &stat ) )
            {
                if( stat.i_snr > i_best_snr )
331
                {
Laurent Aimar's avatar
Laurent Aimar committed
332
                    i_best_snr = stat.i_snr;
333 334
                    scan_session_SetSNR( session, i_best_snr );
                }
Laurent Aimar's avatar
Laurent Aimar committed
335 336 337 338 339 340 341 342 343 344 345
            }
        }

        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 )
        {
346 347 348
            if( i_probe_start == 0 )
                i_probe_start = mdate();

349 350
            ssize_t i_read = read( p_sys->i_handle, &p_sys->packet, TS_PACKET_SIZE );
            if( i_read <= 0 )
Laurent Aimar's avatar
Laurent Aimar committed
351
            {
352
                msg_Warn( p_access, "read failed: %s", vlc_strerror_c(errno) );
Laurent Aimar's avatar
Laurent Aimar committed
353 354 355 356
                continue;
            }

            /* */
357 358
            if( i_read == TS_PACKET_SIZE &&
                scan_session_Push( session, &p_sys->packet ) )
Laurent Aimar's avatar
Laurent Aimar committed
359 360 361 362 363 364 365
            {
                msg_Dbg( p_access, "finished scanning current frequency" );
                break;
            }
        }
    }

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

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

380
    switch( i_query )
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
            break;
389

Edward Wang's avatar
Edward Wang committed
390 391 392 393
        case ACCESS_GET_CONTENT_TYPE:
            *va_arg( args, char** ) = strdup("application/vnd.apple.mpegurl"); // m3u8
            return VLC_SUCCESS;

394 395
        case ACCESS_GET_PTS_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
396
            *pi_64 = DEFAULT_PTS_DELAY;
397
            break;
398

399 400 401 402 403 404 405 406 407 408
        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;
            }
409
            break;
Christophe Massiot's avatar
Christophe Massiot committed
410

411 412
        default:
            return VLC_EGENERIC;
413

414 415
    }
    return VLC_SUCCESS;
416 417 418
}

/*****************************************************************************
419
 * FilterSet/FilterUnset:
420
 *****************************************************************************/
421
static void FilterSet( access_t *p_access, int i_pid, int i_type )
422
{
423 424 425 426 427 428 429 430
    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
431 432 433

        if( p_sys->p_demux_handles[i].i_pid == i_pid )
            return; /* Already set */
434 435 436 437 438 439 440 441
    }

    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
442
    if( DMXSetFilter( p_access, i_pid,
443 444 445 446 447 448 449
                           &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;
450 451
}

Laurent Aimar's avatar
Laurent Aimar committed
452
static void FilterUnset( access_t *p_access, int i_max )
453
{
454 455
    access_sys_t *p_sys = p_access->p_sys;
    int i;
456

Laurent Aimar's avatar
Laurent Aimar committed
457
    for( i = 0; i < i_max; i++ )
458
    {
459
        if( p_sys->p_demux_handles[i].i_type )
460
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
461
            DMXUnsetFilter( p_access, p_sys->p_demux_handles[i].i_handle );
462
            p_sys->p_demux_handles[i].i_type = 0;
463 464 465 466 467
        }
    }
}

/*****************************************************************************
468
 * VarInit/ParseMRL:
469
 *****************************************************************************/
470
static void VarInit( access_t *p_access )
471
{
472 473 474 475 476
    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 );
477 478

    /* */
David Kaplan's avatar
David Kaplan committed
479
    var_Create( p_access, "dvb-satellite", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
480 481
    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
482
    var_Create( p_access, "dvb-high-voltage", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
483 484
    var_Create( p_access, "dvb-tone", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-srate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
485 486 487
    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 );
488 489

    /* */
490 491 492
    var_Create( p_access, "dvb-bandwidth", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-transmission", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_access, "dvb-hierarchy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
493 494 495 496 497
}

/* */
static int ParseMRL( access_t *p_access )
{
498
    char *psz_dup = strdup( p_access->psz_location );
499 500 501 502 503 504
    char *psz_parser = psz_dup;
    vlc_value_t         val;

#define GET_OPTION_INT( option )                                            \
    if ( !strncmp( psz_parser, option "=", strlen(option "=") ) )           \
    {                                                                       \
505 506 507
        val.i_int = strtol( psz_parser + strlen(option "="), &psz_parser,   \
                            0 );                                            \
        var_Set( p_access, "dvb-" option, val );                            \
508 509 510 511 512 513 514
    }

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

David Kaplan's avatar
David Kaplan committed
518 519 520 521 522 523 524 525 526 527 528 529
#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 );                             \
    }

530 531 532 533 534 535 536 537
    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")
538

David Kaplan's avatar
David Kaplan committed
539
        else GET_OPTION_STRING("satellite")
540
        else GET_OPTION_INT("voltage")
Christophe Massiot's avatar
Christophe Massiot committed
541
        else GET_OPTION_BOOL("high-voltage")
542
        else GET_OPTION_INT("tone")
Christophe Massiot's avatar
Christophe Massiot committed
543
        else GET_OPTION_INT("satno")
544
        else GET_OPTION_INT("srate")
545 546 547
        else GET_OPTION_INT("lnb-lof1")
        else GET_OPTION_INT("lnb-lof2")
        else GET_OPTION_INT("lnb-slof")
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570

        else GET_OPTION_INT("bandwidth")
        else GET_OPTION_INT("transmission")
        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
571
        {
572
            msg_Err( p_access, "unknown option (%s)", psz_parser );
573 574
            free( psz_dup );
            return VLC_EGENERIC;
575
        }
576

577 578
        if ( *psz_parser )
            psz_parser++;
579
    }
580 581
#undef GET_OPTION_INT
#undef GET_OPTION_BOOL
David Kaplan's avatar
David Kaplan committed
582
#undef GET_OPTION_STRING
583

584 585 586
    free( psz_dup );
    return VLC_SUCCESS;
}
587