]> git.sesse.net Git - vlc/blob - modules/access/dtv/access.c
b711b7ab2f15f3d844ceac27c2c357dae212b3f8
[vlc] / modules / access / dtv / access.c
1 /**
2  * @file access.c
3  * @brief Digital broadcasting input module for VLC media player
4  */
5 /*****************************************************************************
6  * Copyright © 2011 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_access.h>
29 #include <vlc_plugin.h>
30 #include <vlc_dialog.h>
31 #include <search.h>
32
33 #include "dtv/dtv.h"
34
35 #define CACHING_TEXT N_("Caching value (ms)")
36 #define CACHING_LONGTEXT N_( \
37     "The cache size (delay) for digital broadcasts (in milliseconds).")
38
39 #define ADAPTER_TEXT N_("DVB adapter")
40 #define ADAPTER_LONGTEXT N_( \
41     "If there is more than one digital broadcasting adapter, " \
42     "the adapter number must be selected. Numbering start from zero.")
43
44 #define DEVICE_TEXT N_("DVB device")
45 #define DEVICE_LONGTEXT N_( \
46     "If the selected adapter has more than one tuner, " \
47     "the tuner number must be selected. Numbering start from zero.")
48
49 #define BUDGET_TEXT N_("Do not demultiplex")
50 #define BUDGET_LONGTEXT N_( \
51     "Only useful programs are normally demultiplexed from the transponder. " \
52     "This option will disable demultiplexing and receive all programs.")
53
54 #define NAME_TEXT N_("Network name")
55 #define NAME_LONGTEXT N_("Unique network name in the System Tuning Spaces")
56
57 #define CREATE_TEXT N_("Network name to create")
58 #define CREATE_LONGTEXT N_("Create unique name in the System Tuning Spaces")
59
60 #define FREQ_TEXT N_("Frequency (kHz)")
61 #define FREQ_LONGTEXT N_( \
62     "TV channels are grouped by transponder (a.k.a. multiplex) " \
63     "on a given frequency. This is required to tune the receiver.")
64
65 #define MODULATION_TEXT N_("Modulation / Constellation")
66 #define MODULATION_LONGTEXT N_( \
67     "The digital signal can be modulated according with different " \
68     "constellations (depending on the delivery system). " \
69     "If the demodulator cannot detect the constellation automatically, " \
70     "it needs to be configured manually.")
71 static const char *const modulation_vlc[] = { "",
72     "QAM", "16QAM", "32QAM", "64QAM", "128QAM", "256QAM",
73     "8VSB", "16VSB",
74     "QPSK", "DQPSK", "8PSK", "16APSK", "32APSK",
75 };
76 static const char *const modulation_user[] = { N_("Undefined"),
77     "Auto QAM", "16-QAM", "32-QAM", "64-QAM", "128-QAM", "256-QAM",
78     "8-VSB", "16-VSB",
79     "QPSK", "DQPSK", "8-PSK", "16-APSK", "32-APSK",
80 };
81
82 #define SRATE_TEXT N_("Symbol rate (bauds)")
83 #define SRATE_LONGTEXT N_( \
84     "The symbol rate must be specified manually for some systems, " \
85     "notably DVB-C, DVB-S and DVB-S2.")
86
87 #define INVERSION_TEXT N_("Spectrum inversion")
88 #define INVERSION_LONGTEXT N_( \
89     "If the demodulator cannot detect spectral inversion correctly, " \
90     "it needs to be configured manually.")
91 const int auto_off_on_vlc[] = { -1, 0, 1 };
92 static const char *const auto_off_on_user[] = { N_("Automatic"),
93     N_("Off"), N_("On") };
94
95 #define CODE_RATE_TEXT N_("FEC code rate")
96 #define CODE_RATE_HP_TEXT N_("High-priority code rate")
97 #define CODE_RATE_LP_TEXT N_("Low-priority code rate")
98 #define CODE_RATE_LONGTEXT N_( \
99     "The code rate for Forward Error Correction can be specified.")
100 static const char *const code_rate_vlc[] = { "",
101     "0", /*"1/4", "1/3",*/ "1/2", "3/5", "2/3", "3/4",
102     "4/5", "5/6", "6/7", "7/8", "8/9", "9/10",
103 };
104 static const char *const code_rate_user[] = { N_("Automatic"),
105     N_("None"), /*"1/4", "1/3",*/ "1/2", "3/5", "2/3", "3/4",
106     "4/5", "5/6", "6/7", "7/8", "8/9", "9/10",
107 };
108
109 #define TRANSMISSION_TEXT N_("Transmission mode")
110 const int transmission_vlc[] = { -1,
111     2, 4, 8, /*16, 32,*/
112 };
113 static const char *const transmission_user[] = { N_("Automatic"),
114     "2k", "4k", "8k", /*"16k", "32k", */
115 };
116
117 #define BANDWIDTH_TEXT N_("Bandwidth (MHz)")
118 const int bandwidth_vlc[] = { 0,
119     8, 7, 6,
120 };
121 static const char *const bandwidth_user[] = { N_("Automatic"),
122     N_("8 MHz"), N_("7 MHz"), N_("6 MHz"),
123 };
124
125 #define GUARD_TEXT N_("Guard interval")
126 const char *const guard_vlc[] = { "",
127     /*"1/128",*/ "1/32", "1/16", /*"19/128",*/ "1/8", /*"9/256",*/ "1/4",
128 };
129 static const char *const guard_user[] = { N_("Automatic"),
130     /*"1/128",*/ "1/32", "1/16", /*"19/128",*/ "1/8", /*"9/256",*/ "1/4",
131 };
132
133 #define HIERARCHY_TEXT N_("Hierarchy mode")
134 const int hierarchy_vlc[] = { -1,
135     0, 1, 2, 4,
136 };
137 static const char *const hierarchy_user[] = { N_("Automatic"),
138     N_("None"), "1", "2", "4",
139 };
140
141 #define PILOT_TEXT N_("Pilot")
142
143 #define ROLLOFF_TEXT N_("Roll-off factor")
144 const int rolloff_vlc[] = { -1,
145     35, 20, 25,
146 };
147 static const char *const rolloff_user[] = { N_("Automatic"),
148     N_("0.35 (same as DVB-S)"), N_("0.20"), N_("0.25"),
149 };
150
151 #define POLARIZATION_TEXT N_("Polarization (Voltage)")
152 #define POLARIZATION_LONGTEXT N_( \
153     "To select the polarization of the transponder, a different voltage " \
154     "is normally applied to the low noise block-downconverter (LNB).")
155 static const char *const polarization_vlc[] = { "", "V", "H", "R", "L" };
156 static const char *const polarization_user[] = { N_("Unspecified (0V)"),
157     N_("Vertical (13V)"), N_("Horizontal (18V)"),
158     N_("Circular Right Hand (13V)"), N_("Circular Left Hand (18V)") };
159
160 #define HIGH_VOLTAGE_TEXT N_("High LNB voltage")
161 #define HIGH_VOLTAGE_LONGTEXT N_( \
162     "If the cables between the satellilte low noise block-downconverter and " \
163     "the receiver are long, higher voltage may be required.\n" \
164     "Not all receivers support this.")
165
166 #define LNB_LOW_TEXT N_("Local oscillator low frequency (kHz)")
167 #define LNB_HIGH_TEXT N_("Local oscillator high frequency (kHz)")
168 #define LNB_LONGTEXT N_( \
169     "The downconverter (LNB) will substract the local oscillator frequency " \
170     "from the satellite transmission frequency. " \
171     "The intermediate frequency (IF) on the RF cable is the result.")
172 #define LNB_SWITCH_TEXT N_("Universal LNB switch frequency (kHz)")
173 #define LNB_SWITCH_LONGTEXT N_( \
174     "If the satellite transmission frequency exceeds the switch frequency, " \
175     "the oscillator high frequency will be used as reference. " \
176     "Furthermore the automatic continuous 22kHz tone will be sent.")
177 #define TONE_TEXT N_("Continuous 22kHz tone")
178 #define TONE_LONGTEXT N_( \
179     "A continuous tone at 22kHz can be sent on the cable. " \
180     "This normally selects the higher frequency band from a universal LNB.")
181
182 #define SATNO_TEXT N_("DiSEqC LNB number")
183 #define SATNO_LONGTEXT N_( \
184     "If the satellite receiver is connected to multiple " \
185     "low noise block-downconverters (LNB) through a DiSEqC 1.0 switch, " \
186     "the correct LNB can be selected (1 to 4). " \
187     "If there is no switch, this parameter should be 0.")
188 #ifdef __linux__
189 static const int satno_vlc[] = { 0, 1, 2, 3, 4 };
190 static const char *const satno_user[] = { N_("Unspecified"),
191     "A/1", "B/2", "C/3", "D/4" };
192 #endif
193
194 /* BDA module additional DVB-S Parameters */
195 #define NETID_TEXT N_("Network identifier")
196 #define AZIMUTH_TEXT N_("Satellite azimuth")
197 #define AZIMUTH_LONGTEXT N_("Satellite azimuth in tenths of degree")
198 #define ELEVATION_TEXT N_("Satellite elevation")
199 #define ELEVATION_LONGTEXT N_("Satellite elevation in tenths of degree")
200 #define LONGITUDE_TEXT N_("Satellite longitude")
201 #define LONGITUDE_LONGTEXT N_( \
202     "Satellite longitude in tenths of degree. West is negative.")
203
204 #define RANGE_TEXT N_("Satellite range code")
205 #define RANGE_LONGTEXT N_("Satellite range code as defined by manufacturer " \
206    "e.g. DISEqC switch code")
207
208 /* ATSC */
209 #define MAJOR_CHANNEL_TEXT N_("Major channel")
210 #define MINOR_CHANNEL_TEXT N_("ATSC minor channel")
211 #define PHYSICAL_CHANNEL_TEXT N_("Physical channel")
212
213 static int  Open (vlc_object_t *);
214 static void Close (vlc_object_t *);
215
216 vlc_module_begin ()
217     set_shortname (N_("DTV"))
218     set_description (N_("Digital Television and Radio"))
219     set_category (CAT_INPUT)
220     set_subcategory (SUBCAT_INPUT_ACCESS)
221     set_capability ("access", 0)
222     set_callbacks (Open, Close)
223     add_shortcut ("dtv", "tv", "dvb", /* "radio", "dab",*/
224                   "cable", "dvb-c", "satellite", "dvb-s", "dvb-s2",
225                   "terrestrial", "dvb-t", "atsc", "cqam")
226
227     /* All options starting with dvb- can be overridden in the MRL, so they
228      * must all be "safe". Nevertheless, we do not mark as safe those that are
229      * really specific to the local system (e.g. device ID...).
230      * It wouldn't make sense to deliver those through a playlist. */
231
232     add_integer ("dvb-caching", DEFAULT_PTS_DELAY / 1000,
233                  CACHING_TEXT, CACHING_LONGTEXT, true)
234         change_integer_range (0, 60000)
235         change_safe ()
236 #ifdef __linux__
237     add_integer ("dvb-adapter", 0, ADAPTER_TEXT, ADAPTER_LONGTEXT, false)
238         change_integer_range (0, 255)
239     add_integer ("dvb-device", 0, DEVICE_TEXT, DEVICE_LONGTEXT, false)
240         change_integer_range (0, 255)
241     add_bool ("dvb-budget-mode", false, BUDGET_TEXT, BUDGET_LONGTEXT, true)
242 #endif
243 #ifdef WIN32
244     add_integer ("dvb-adapter", -1, ADAPTER_TEXT, ADAPTER_LONGTEXT, true)
245     add_string ("dvb-network-name", "", NAME_TEXT, NAME_LONGTEXT, true)
246     /* Hmm: is this one really safe??: */
247     add_string ("dvb-create-name", "", CREATE_TEXT, CREATE_LONGTEXT, true)
248         change_private ()
249 #endif
250     add_integer ("dvb-frequency", 0, FREQ_TEXT, FREQ_LONGTEXT, false)
251         change_integer_range (0, 107999999)
252         change_safe ()
253     add_integer ("dvb-inversion", -1, INVERSION_TEXT, INVERSION_LONGTEXT, true)
254         change_integer_list (auto_off_on_vlc, auto_off_on_user)
255         change_safe ()
256
257     set_section (N_("Terrestrial reception parameters"), NULL)
258     add_integer ("dvb-bandwidth", 0, BANDWIDTH_TEXT, BANDWIDTH_TEXT, true)
259         change_integer_list (bandwidth_vlc, bandwidth_user)
260         change_safe ()
261     add_string ("dvb-code-rate-hp", "",
262                 CODE_RATE_HP_TEXT, CODE_RATE_LONGTEXT, false)
263         change_string_list (code_rate_vlc, code_rate_user, NULL)
264         change_safe ()
265     add_string ("dvb-code-rate-lp", "",
266                 CODE_RATE_LP_TEXT, CODE_RATE_LONGTEXT, false)
267         change_string_list (code_rate_vlc, code_rate_user, NULL)
268         change_safe ()
269     add_integer ("dvb-transmission", 0,
270                  TRANSMISSION_TEXT, TRANSMISSION_TEXT, true)
271         change_integer_list (transmission_vlc, transmission_user)
272         change_safe ()
273     add_string ("dvb-guard", "", GUARD_TEXT, GUARD_TEXT, true)
274         change_string_list (guard_vlc, guard_user, NULL)
275         change_safe ()
276     add_integer ("dvb-hierarchy", -1, HIERARCHY_TEXT, HIERARCHY_TEXT, true)
277         change_integer_list (hierarchy_vlc, hierarchy_user)
278         change_safe ()
279
280     set_section (N_("Cable and satellite reception parameters"), NULL)
281     add_string ("dvb-modulation", 0,
282                  MODULATION_TEXT, MODULATION_LONGTEXT, false)
283         change_string_list (modulation_vlc, modulation_user, NULL)
284         change_safe ()
285     add_integer ("dvb-srate", 0, SRATE_TEXT, SRATE_LONGTEXT, false)
286         change_integer_range (0, UINT64_C(0xffffffff))
287         change_safe ()
288     add_string ("dvb-fec", "", CODE_RATE_TEXT, CODE_RATE_LONGTEXT, true)
289         change_string_list (code_rate_vlc, code_rate_user, NULL)
290         change_safe ()
291
292     set_section (N_("DVB-S2 parameters"), NULL)
293     add_integer ("dvb-pilot", -1, PILOT_TEXT, PILOT_TEXT, true)
294         change_integer_list (auto_off_on_vlc, auto_off_on_user)
295         change_safe ()
296     add_integer ("dvb-rolloff", -1, ROLLOFF_TEXT, ROLLOFF_TEXT, true)
297         change_integer_list (rolloff_vlc, rolloff_user)
298         change_safe ()
299
300     set_section (N_("Satellite equipment control"), NULL)
301     add_string ("dvb-polarization", "",
302                 POLARIZATION_TEXT, POLARIZATION_LONGTEXT, false)
303         change_string_list (polarization_vlc, polarization_user, NULL)
304         change_safe ()
305     add_integer ("dvb-voltage", 13, "", "", true)
306         change_integer_range (0, 18)
307         change_private ()
308         change_safe ()
309 #ifdef __linux__
310     add_bool ("dvb-high-voltage", false,
311               HIGH_VOLTAGE_TEXT, HIGH_VOLTAGE_LONGTEXT, false)
312 #endif
313     add_integer ("dvb-lnb-low", 0, LNB_LOW_TEXT, LNB_LONGTEXT, true)
314         change_integer_range (0, 0x7fffffff)
315         add_deprecated_alias ("dvb-lnb-lof1")
316     add_integer ("dvb-lnb-high", 0, LNB_HIGH_TEXT, LNB_LONGTEXT, true)
317         change_integer_range (0, 0x7fffffff)
318         add_deprecated_alias ("dvb-lnb-lof2")
319     add_integer ("dvb-lnb-switch", 11700000,
320                  LNB_SWITCH_TEXT, LNB_SWITCH_LONGTEXT, true)
321         change_integer_range (0, 0x7fffffff)
322         add_deprecated_alias ("dvb-lnb-slof")
323 #ifdef __linux
324     add_integer ("dvb-satno", 0, SATNO_TEXT, SATNO_LONGTEXT, true)
325         change_integer_list (satno_vlc, satno_user)
326     add_integer ("dvb-tone", -1, TONE_TEXT, TONE_LONGTEXT, true)
327         change_integer_list (auto_off_on_vlc, auto_off_on_user)
328 #endif
329 #ifdef WIN32
330     add_integer ("dvb-network-id", 0, NETID_TEXT, NETID_TEXT, true)
331     add_integer ("dvb-azimuth", 0, AZIMUTH_TEXT, AZIMUTH_LONGTEXT, true)
332     add_integer ("dvb-elevation", 0, ELEVATION_TEXT, ELEVATION_LONGTEXT, true)
333     add_integer ("dvb-longitude", 0, LONGITUDE_TEXT, LONGITUDE_LONGTEXT, true)
334     add_string ("dvb-range", "", RANGE_TEXT, RANGE_LONGTEXT, true)
335     /* dvb-range corresponds to the BDA InputRange parameter which is
336     * used by some drivers to control the diseqc */
337
338     set_section (N_("ATSC reception parameters"), NULL)
339     add_integer ("dvb-major-channel", 0, MAJOR_CHANNEL_TEXT, NULL, true)
340     add_integer ("dvb-minor-channel", 0, MINOR_CHANNEL_TEXT, NULL, true)
341     add_integer ("dvb-physical-channel", 0, PHYSICAL_CHANNEL_TEXT, NULL, true)
342 #endif
343 vlc_module_end ()
344
345 struct access_sys_t
346 {
347     dvb_device_t *dev;
348 };
349
350 struct delsys
351 {
352     int (*setup) (vlc_object_t *, dvb_device_t *, unsigned freq);
353     /* TODO: scan stuff */
354 };
355
356 static block_t *Read (access_t *);
357 static int Control (access_t *, int, va_list);
358 static const delsys_t *GuessSystem (const char *, dvb_device_t *);
359 static int Tune (vlc_object_t *, dvb_device_t *, const delsys_t *, unsigned);
360 static unsigned var_InheritFrequency (vlc_object_t *);
361
362 static int Open (vlc_object_t *obj)
363 {
364     access_t *access = (access_t *)obj;
365     access_sys_t *sys = malloc (sizeof (*sys));
366     if (unlikely(sys == NULL))
367         return VLC_ENOMEM;
368
369     var_LocationParse (obj, access->psz_location, "dvb-");
370     unsigned freq = var_InheritFrequency (obj);
371
372     dvb_device_t *dev = dvb_open (obj, freq != 0);
373     if (dev == NULL)
374     {
375         free (sys);
376         return VLC_EGENERIC;
377     }
378
379     sys->dev = dev;
380     access->p_sys = sys;
381
382     if (freq != 0)
383     {
384         const delsys_t *delsys = GuessSystem (access->psz_access, dev);
385         if (delsys == NULL || Tune (obj, dev, delsys, freq))
386         {
387             msg_Err (obj, "tuning to %u kHz failed", freq);
388             dialog_Fatal (obj, N_("Digital broadcasting"),
389                           N_("The selected digital tuner does not support "
390                              "the specified parameters.\n"
391                              "Please check the preferences."));
392             goto error;
393         }
394     }
395     dvb_add_pid (dev, 0);
396
397     access->pf_block = Read;
398     access->pf_control = Control;
399     if (access->psz_demux == NULL || !access->psz_demux[0])
400     {
401         free (access->psz_demux);
402         access->psz_demux = strdup ("ts");
403     }
404     return VLC_SUCCESS;
405
406 error:
407     Close (obj);
408     access->p_sys = NULL;
409     return VLC_EGENERIC;
410 }
411
412 static void Close (vlc_object_t *obj)
413 {
414     access_t *access = (access_t *)obj;
415     access_sys_t *sys = access->p_sys;
416
417     dvb_close (sys->dev);
418     free (sys);
419 }
420
421 static block_t *Read (access_t *access)
422 {
423 #define BUFSIZE (20*188)
424     block_t *block = block_Alloc (BUFSIZE);
425     if (unlikely(block == NULL))
426         return NULL;
427
428     access_sys_t *sys = access->p_sys;
429     ssize_t val = dvb_read (sys->dev, block->p_buffer, BUFSIZE);
430
431     if (val <= 0)
432     {
433         if (val == 0)
434             access->info.b_eof = true;
435         block_Release (block);
436         return NULL;
437     }
438
439     block->i_buffer = val;
440     return block;
441 }
442
443 static int Control (access_t *access, int query, va_list args)
444 {
445     access_sys_t *sys = access->p_sys;
446     dvb_device_t *dev = sys->dev;
447
448     switch (query)
449     {
450         case ACCESS_CAN_SEEK:
451         case ACCESS_CAN_FASTSEEK:
452         case ACCESS_CAN_PAUSE:
453         case ACCESS_CAN_CONTROL_PACE:
454         {
455             bool *v = va_arg (args, bool *);
456             *v = false;
457             return VLC_SUCCESS;
458         }
459
460         case ACCESS_GET_PTS_DELAY:
461         {
462             int64_t *v = va_arg (args, int64_t *);
463             *v = var_InheritInteger (access, "dvb-caching") * INT64_C(1000);
464             return VLC_SUCCESS;
465         }
466
467         case ACCESS_GET_TITLE_INFO:
468         case ACCESS_GET_META:
469             return VLC_EGENERIC;
470
471         case ACCESS_GET_CONTENT_TYPE:
472         {
473             char **pt = va_arg (args, char **);
474             *pt = strdup ("video/MP2T");
475             return VLC_SUCCESS;
476         }
477
478         case ACCESS_SET_PAUSE_STATE:
479         case ACCESS_SET_TITLE:
480         case ACCESS_SET_SEEKPOINT:
481             return VLC_EGENERIC;
482
483         case ACCESS_GET_SIGNAL:
484             *va_arg (args, double *) = dvb_get_snr (dev);
485             *va_arg (args, double *) = dvb_get_signal_strength (dev);
486             return VLC_SUCCESS;
487
488         case ACCESS_SET_PRIVATE_ID_STATE:
489         {
490             unsigned pid = va_arg (args, unsigned);
491             bool add = va_arg (args, unsigned);
492
493             if (unlikely(pid > 0x1FFF))
494                 return VLC_EGENERIC;
495             if (add)
496             {
497                 if (dvb_add_pid (dev, pid))
498                     return VLC_EGENERIC;
499             }
500             else
501                 dvb_remove_pid (dev, pid);
502             return VLC_SUCCESS;
503         }
504
505         case ACCESS_SET_PRIVATE_ID_CA:
506             /* TODO */
507             return VLC_EGENERIC;
508
509         case ACCESS_GET_PRIVATE_ID_STATE:
510             return VLC_EGENERIC;
511     }
512
513     msg_Warn (access, "unimplemented query %d in control", query);
514     return VLC_EGENERIC;
515 }
516
517
518 /*** Generic tuning ***/
519
520 /** Determines which delivery system to use. */
521 static const delsys_t *GuessSystem (const char *scheme, dvb_device_t *dev)
522 {
523     /* NOTE: We should guess the delivery system for the "cable", "satellite"
524      * and "terrestrial" shortcuts (i.e. DVB, ISDB, ATSC...). But there is
525      * seemingly no sane way to do get the info with Linux DVB version 5.2.
526      * In particular, the frontend infos distinguish only the modulator class
527      * (QPSK, QAM, OFDM or ATSC).
528      *
529      * Furthermore, if the demodulator supports 2G, we cannot guess whether
530      * 1G or 2G is intended. For backward compatibility, 1G is assumed
531      * (this is not a limitation of Linux DVB). We will probably need something
532      * smarter when 2G (semi automatic) scanning is implemented. */
533     if (!strcasecmp (scheme, "cable"))
534         scheme = "dvb-c";
535     else
536     if (!strcasecmp (scheme, "satellite"))
537         scheme = "dvb-s";
538     else
539     if (!strcasecmp (scheme, "terrestrial"))
540         scheme = "dvb-t";
541
542     if (!strcasecmp (scheme, "atsc"))
543         return &atsc;
544     if (!strcasecmp (scheme, "cqam"))
545         return &cqam;
546     if (!strcasecmp (scheme, "dvb-c"))
547         return &dvbc;
548     if (!strcasecmp (scheme, "dvb-s"))
549         return &dvbs;
550     if (!strcasecmp (scheme, "dvb-s2"))
551         return &dvbs2;
552     if (!strcasecmp (scheme, "dvb-t"))
553         return &dvbt;
554
555     return dvb_guess_system (dev);
556 }
557
558 /** Set parameters and tune the device */
559 static int Tune (vlc_object_t *obj, dvb_device_t *dev, const delsys_t *delsys,
560                  unsigned freq)
561 {
562     if (delsys->setup (obj, dev, freq)
563      || dvb_set_inversion (dev, var_InheritInteger (obj, "dvb-inversion"))
564      || dvb_tune (dev))
565         return VLC_EGENERIC;
566     return VLC_SUCCESS;
567 }
568
569 static unsigned var_InheritFrequency (vlc_object_t *obj)
570 {
571     unsigned freq = var_InheritInteger (obj, "dvb-frequency");
572     if (freq >= 108000000)
573     {
574         msg_Err (obj, "%u kHz frequency is too high.", freq);
575         freq /= 1000;
576         msg_Info (obj, "Assuming %u kHz carrier frequency instead.", freq);
577     }
578     return freq;
579 }
580
581 static uint32_t var_InheritCodeRate (vlc_object_t *obj, const char *varname)
582 {
583     char *code_rate = var_InheritString (obj, varname);
584     if (code_rate == NULL)
585         return VLC_FEC_AUTO;
586
587     uint16_t a, b;
588     int v = sscanf (code_rate, "%"SCNu16"/%"SCNu16, &a, &b);
589     free (code_rate);
590     switch (v)
591     {
592         case 2:
593             return VLC_FEC(a, b);
594         case 1:
595             if (a == 0)
596                 return 0;
597             /* Backward compatibility with VLC < 1.2 (= Linux DVBv3 enum) */
598             if (a < 9)
599             {
600                 msg_Warn (obj, "\"%s=%"PRIu16"\" option is obsolete. "
601                           "Use \"%s=%"PRIu16"/%"PRIu16"\" instead.",
602                           varname + 4, a, varname + 4, a, a + 1);
603                 return VLC_FEC(a, a + 1);
604             }
605             else
606                 msg_Warn (obj, "\"fec=9\" option is obsolete.");
607     }
608     return VLC_FEC_AUTO;
609 }
610
611 static int modcmp (const void *a, const void *b)
612 {
613     return strcasecmp (a, *(const char *const *)b);
614 }
615
616 static const char *var_InheritModulation (vlc_object_t *obj)
617 {
618     char *mod = var_InheritString (obj, "dvb-modulation");
619     if (mod == NULL)
620         return "";
621
622     size_t n = sizeof (modulation_vlc) / sizeof (modulation_vlc[0]);
623     const char *const *p = lfind (mod, modulation_vlc, &n, sizeof (mod), modcmp);
624     if (p != NULL)
625     {
626         free (mod);
627         return *p;
628     }
629
630     /* Backward compatibility with VLC < 1.2 */
631     const char *str;
632     switch (atoi (mod))
633     {
634         case -1:  str = "QPSK";   break;
635         case 0:   str = "QAM";    break;
636         case 8:   str = "8VSB";   break;
637         case 16:  str = "16QAM";  break;
638         case 32:  str = "32QAM";  break;
639         case 64:  str = "64QAM";  break;
640         case 128: str = "128QAM"; break;
641         case 256: str = "256QAM"; break;
642         default:  return "";
643     }
644
645     msg_Warn (obj, "\"modulation=%s\" option is obsolete. "
646                    "Use \"modulation=%s\" instead.", mod, str);
647     free (mod);
648     return str;
649 }
650
651 static unsigned var_InheritGuardInterval (vlc_object_t *obj)
652 {
653     char *guard = var_InheritString (obj, "dvb-guard");
654     if (guard == NULL)
655         return VLC_GUARD_AUTO;
656
657     uint16_t a, b;
658     int v = sscanf (guard, "%"SCNu16"/%"SCNu16, &a, &b);
659     free (guard);
660     switch (v)
661     {
662         case 1:
663             /* Backward compatibility with VLC < 1.2 */
664             if (a == 0)
665                 break;
666             msg_Warn (obj, "\"guard=%"PRIu16"\" option is obsolete. "
667                            "Use \"guard=1/%"PRIu16" instead.", a, a);
668             b = a;
669             a = 1;
670         case 2:
671             return VLC_GUARD(a, b);
672     }
673     return VLC_GUARD_AUTO;
674 }
675
676
677 /*** ATSC ***/
678 static int atsc_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
679 {
680     const char *mod = var_InheritModulation (obj);
681
682     return dvb_set_atsc (dev, freq, mod);
683 }
684
685 const delsys_t atsc = { .setup = atsc_setup };
686
687 static int cqam_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
688 {
689     const char *mod = var_InheritModulation (obj);
690
691     return dvb_set_cqam (dev, freq, mod);
692 }
693
694 const delsys_t cqam = { .setup = cqam_setup };
695
696
697 /*** DVB-C ***/
698 static int dvbc_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
699 {
700     const char *mod = var_InheritModulation (obj);
701     uint32_t fec = var_InheritCodeRate (obj, "dvb-fec");
702     unsigned srate = var_InheritInteger (obj, "dvb-srate");
703
704     return dvb_set_dvbc (dev, freq, mod, srate, fec);
705 }
706
707 const delsys_t dvbc = { .setup = dvbc_setup };
708
709
710 /*** DVB-S ***/
711 static char var_InheritPolarization (vlc_object_t *obj)
712 {
713     char pol;
714     char *polstr = var_InheritString (obj, "dvb-polarization");
715     if (polstr != NULL)
716     {
717         pol = *polstr;
718         free (polstr);
719         if (unlikely(pol >= 'a' && pol <= 'z'))
720             pol -= 'a' - 'A';
721         return pol;
722     }
723
724     /* Backward compatibility with VLC for Linux < 1.2 */
725     unsigned voltage = var_InheritInteger (obj, "dvb-voltage");
726     switch (voltage)
727     {
728         case 13:  pol = 'V'; break;
729         case 18:  pol = 'H'; break;
730         default:  return 0;
731     }
732
733     msg_Warn (obj, "\"voltage=%u\" option is obsolete. "
734                    "Use \"polarization=%c\" instead.", voltage, pol);
735     return pol;
736 }
737
738 static int sec_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
739 {
740     char pol = var_InheritPolarization (obj);
741     unsigned lowf = var_InheritInteger (obj, "dvb-lnb-low");
742     unsigned highf = var_InheritInteger (obj, "dvb-lnb-high");
743     unsigned switchf = var_InheritInteger (obj, "dvb-lnb-switch");
744
745     return dvb_set_sec (dev, freq, pol, lowf, highf, switchf);
746 }
747
748 static int dvbs_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
749 {
750     uint32_t fec = var_InheritCodeRate (obj, "dvb-fec");
751     uint32_t srate = var_InheritInteger (obj, "dvb-srate");
752
753     int ret = dvb_set_dvbs (dev, freq, srate, fec);
754     if (ret == 0)
755         ret = sec_setup (obj, dev, freq);
756     return ret;
757 }
758
759 static int dvbs2_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
760 {
761     const char *mod = var_InheritModulation (obj);
762     uint32_t fec = var_InheritCodeRate (obj, "dvb-fec");
763     uint32_t srate = var_InheritInteger (obj, "dvb-srate");
764     int pilot = var_InheritInteger (obj, "dvb-pilot");
765     int rolloff = var_InheritInteger (obj, "dvb-rolloff");
766
767     int ret = dvb_set_dvbs2 (dev, freq, mod, srate, fec, pilot, rolloff);
768     if (ret == 0)
769         ret = sec_setup (obj, dev, freq);
770     return ret;
771 }
772
773 const delsys_t dvbs = { .setup = dvbs_setup };
774 const delsys_t dvbs2 = { .setup = dvbs2_setup };
775
776
777 /*** DVB-T ***/
778 static int dvbt_setup (vlc_object_t *obj, dvb_device_t *dev, unsigned freq)
779 {
780     const char *mod = var_InheritModulation (obj);
781     uint32_t fec_hp = var_InheritCodeRate (obj, "dvb-code-rate-hp");
782     uint32_t fec_lp = var_InheritCodeRate (obj, "dvb-code-rate-lp");
783     uint32_t guard = var_InheritGuardInterval (obj);
784     uint32_t bw = var_InheritInteger (obj, "dvb-bandwidth");
785     int tx = var_InheritInteger (obj, "dvb-transmission");
786     int h = var_InheritInteger (obj, "dvb-hierarchy");
787
788     return dvb_set_dvbt (dev, freq, mod, fec_hp, fec_lp, bw, tx, guard, h);
789 }
790
791 const delsys_t dvbt = { .setup = dvbt_setup };