From e904129b79dffb0ac2c661b164157064d03b9095 Mon Sep 17 00:00:00 2001 From: Oliver Freyermuth Date: Tue, 19 Jan 2016 00:18:08 +0100 Subject: stream_dvb: support frontends with multiple delivery systems. Most common case would be DVB-C / DVB-T combination cards. Cards with multiple delivery systems are only supported starting from DVBv5 API (Kernel 2.6.38). In this case, we loop over all delivery systems and just treat them as different cards would be treated: They all get their own TUNER-type, channel-list parsing etc. --- stream/dvb_tune.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 10 deletions(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index 7ec4bcd9e8..1f982d6887 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -40,38 +40,93 @@ #include "dvb_tune.h" #include "common/msg.h" -int dvb_get_tuner_type(int fe_fd, struct mp_log *log) +int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) { +#ifdef DVB_USE_S2API + /* S2API is the DVB API new since 2.6.28. + It allows to query frontends with multiple delivery systems. */ + struct dtv_property p[] = {{ .cmd = DTV_ENUM_DELSYS }}; + struct dtv_properties cmdseq = {.num = 1, .props = p}; + mp_verbose(log, "Querying tuner type via DVBv5 API for frontend FD %d\n", + fe_fd); + if ((ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq)) < -0) { + mp_err(log, "FE_GET_PROPERTY error: %d, FD: %d\n\n", errno, fe_fd); + return 0; + } + int num_tuner_types = p[0].u.buffer.len; + mp_verbose(log, "Number of supported delivery systems: %d\n", num_tuner_types); + if (num_tuner_types == 0) { + mp_err(log, "Frontend FD %d returned no delivery systems!", fe_fd); + return 0; + } + (*tuner_types) = talloc_array(NULL, int, num_tuner_types); + int supported_tuners = 0; + for(;p[0].u.buffer.len > 0; p[0].u.buffer.len--) { + fe_delivery_system_t delsys = p[0].u.buffer.data[p[0].u.buffer.len - 1]; + /* Second level standards like like DVB-T2, DVB-S2 not treated here - + Cards can usually either only do S/T/C or both levels. + DVB-T2 probably needs more implementation details, + DVB-S2 is treated in the DVB-S branch already. */ + switch (delsys) { + case SYS_DVBT: + mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-T\n"); + (*tuner_types)[supported_tuners++] = TUNER_TER; + break; + case SYS_DVBC_ANNEX_AC: + mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-C\n"); + (*tuner_types)[supported_tuners++] = TUNER_CBL; + break; + case SYS_DVBS: + mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-S\n"); + (*tuner_types)[supported_tuners++] = TUNER_SAT; + break; +#ifdef DVB_ATSC + case SYS_ATSC: + mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); + (*tuner_types)[supported_tuners++] = TUNER_ATSC; + break; +#endif + default: + mp_err(log, "UNKNOWN TUNER TYPE\n"); + } + } + return supported_tuners; +#else struct dvb_frontend_info fe_info; int res = ioctl(fe_fd, FE_GET_INFO, &fe_info); if (res < 0) { mp_err(log, "FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); return 0; } - + switch (fe_info.type) { case FE_OFDM: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-T\n"); - return TUNER_TER; - + *tuner_types = talloc_array(NULL, int, 1); + (*tuner_types)[0] = TUNER_TER; + return 1; case FE_QPSK: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-S\n"); - return TUNER_SAT; - + *tuner_types = talloc_array(NULL, int, 1); + (*tuner_types)[0] = TUNER_SAT; + return 1; case FE_QAM: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-C\n"); - return TUNER_CBL; - + *tuner_types = talloc_array(NULL, int, 1); + (*tuner_types)[0] = TUNER_CBL; + return 1; #ifdef DVB_ATSC case FE_ATSC: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); - return TUNER_ATSC; + *tuner_types = talloc_array(NULL, int, 1); + (*tuner_types)[0] = TUNER_ATSC; + return 1; #endif default: mp_err(log, "UNKNOWN TUNER TYPE\n"); return 0; } - +#endif } int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt) -- cgit v1.2.3 From ab59c5f5227ea1ea03169f24c99ca75fae80ad1a Mon Sep 17 00:00:00 2001 From: Oliver Freyermuth Date: Wed, 20 Jan 2016 00:29:47 +0100 Subject: stream_dvb: don't requery tuner type, rely on initial query. Saves one unnecessary additional ioctl per tuning by just reusing existing information. Should also fix the case of multiple supported delivery types since we now rely on the initial query from the chosen configuration after channel list parsing instead of requerying the device. --- stream/dvb_tune.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index 1f982d6887..3c1095cc5d 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -442,8 +442,10 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, int timeout) { int hi_lo = 0, dfd; + + dvb_state_t* state = priv->state; + struct dvb_frontend_parameters feparams; - struct dvb_frontend_info fe_info; MP_VERBOSE(priv, "TUNE_IT, fd_frontend %d, freq %lu, srate %lu, " "pol %c, tone %i, diseqc %u\n", fd_frontend, @@ -451,12 +453,8 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, tone, diseqc); memset(&feparams, 0, sizeof(feparams)); - if (ioctl(fd_frontend, FE_GET_INFO, &fe_info) < 0) { - MP_FATAL(priv, "FE_GET_INFO FAILED\n"); - return -1; - } - MP_VERBOSE(priv, "Using DVB card \"%s\"\n", fe_info.name); + MP_VERBOSE(priv, "Using DVB card \"%s\"\n", state->cards[state->card].name); { /* discard stale QPSK events */ @@ -467,8 +465,8 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, } } - switch (fe_info.type) { - case FE_OFDM: + switch (state->tuner_type) { + case TUNER_TER: if (freq < 1000000) freq *= 1000UL; feparams.frequency = freq; @@ -487,7 +485,7 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, return -1; } break; - case FE_QPSK: + case TUNER_SAT: // DVB-S if (freq > 2200000) { // this must be an absolute frequency @@ -565,7 +563,7 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, } #endif break; - case FE_QAM: + case TUNER_CBL: feparams.frequency = freq; feparams.inversion = specInv; feparams.u.qam.symbol_rate = srate; @@ -578,7 +576,7 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, } break; #ifdef DVB_ATSC - case FE_ATSC: + case TUNER_ATSC: feparams.frequency = freq; feparams.u.vsb.modulation = modulation; MP_VERBOSE(priv, "tuning ATSC to %d, modulation=%d\n", freq, modulation); -- cgit v1.2.3 From 346cf7abf0a6c2ca4404440e24dd79f27fb39a23 Mon Sep 17 00:00:00 2001 From: Oliver Freyermuth Date: Wed, 20 Jan 2016 00:35:54 +0100 Subject: stream_dvb: improve messages on delivery-type detection. No need use use all capital letters, and don't warn if DVB-S2 is supported in addition since we handle that in DVB-S case already. Also, print the delivery system number for still unhandled delivery systems to simplify debugging. --- stream/dvb_tune.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index 3c1095cc5d..80a240e71b 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -69,25 +69,29 @@ int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) DVB-S2 is treated in the DVB-S branch already. */ switch (delsys) { case SYS_DVBT: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-T\n"); + mp_verbose(log, "Tuner type seems to be DVB-T\n"); (*tuner_types)[supported_tuners++] = TUNER_TER; break; case SYS_DVBC_ANNEX_AC: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-C\n"); + mp_verbose(log, "Tuner type seems to be DVB-C\n"); (*tuner_types)[supported_tuners++] = TUNER_CBL; break; case SYS_DVBS: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-S\n"); + mp_verbose(log, "Tuner type seems to be DVB-S\n"); (*tuner_types)[supported_tuners++] = TUNER_SAT; break; #ifdef DVB_ATSC case SYS_ATSC: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); + mp_verbose(log, "Tuner type seems to be DVB-ATSC\n"); (*tuner_types)[supported_tuners++] = TUNER_ATSC; break; #endif + case SYS_DVBS2: + // We actually handle that in the DVB-S branch, ok to ignore here. + mp_verbose(log, "Tuner supports DVB-S2\n"); + break; default: - mp_err(log, "UNKNOWN TUNER TYPE\n"); + mp_err(log, "Unhandled tuner type: %d\n", delsys); } } return supported_tuners; @@ -101,29 +105,29 @@ int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) switch (fe_info.type) { case FE_OFDM: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-T\n"); + mp_verbose(log, "Tuner type seems to be DVB-T\n"); *tuner_types = talloc_array(NULL, int, 1); (*tuner_types)[0] = TUNER_TER; return 1; case FE_QPSK: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-S\n"); + mp_verbose(log, "Tuner type seems to be DVB-S\n"); *tuner_types = talloc_array(NULL, int, 1); (*tuner_types)[0] = TUNER_SAT; return 1; case FE_QAM: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-C\n"); + mp_verbose(log, "Tuner type seems to be DVB-C\n"); *tuner_types = talloc_array(NULL, int, 1); (*tuner_types)[0] = TUNER_CBL; return 1; #ifdef DVB_ATSC case FE_ATSC: - mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); + mp_verbose(log, "Tuner type seems to be DVB-ATSC\n"); *tuner_types = talloc_array(NULL, int, 1); (*tuner_types)[0] = TUNER_ATSC; return 1; #endif default: - mp_err(log, "UNKNOWN TUNER TYPE\n"); + mp_err(log, "Unknown tuner type: %d\n", fe_info.type); return 0; } #endif -- cgit v1.2.3 From b2a5c16a9d8a2b2103d60f0ac1c512800161ac74 Mon Sep 17 00:00:00 2001 From: Oliver Freyermuth Date: Wed, 20 Jan 2016 20:46:15 +0100 Subject: stream_dvb: use DVBv5 API also for DVB-C tuning. Using the new API is a necessity for multiple-delivery-system devices, since the old API does not offer a way to switch the delivery system of the card. This should in principle also be done for DVB-T / ATSC, especially since most DVB-T devices also support DVB-C, but I can not test such an implementation due to lack of hardware (currently) so it seems better to leave the existing, tested code-path in place for now. --- stream/dvb_tune.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index 80a240e71b..de43907217 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -470,7 +470,7 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, } switch (state->tuner_type) { - case TUNER_TER: + case TUNER_TER: { if (freq < 1000000) freq *= 1000UL; feparams.frequency = freq; @@ -488,8 +488,9 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, MP_ERR(priv, "ERROR tuning channel\n"); return -1; } - break; - case TUNER_SAT: + } + break; + case TUNER_SAT: { // DVB-S if (freq > 2200000) { // this must be an absolute frequency @@ -566,8 +567,35 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, return -1; } #endif - break; - case TUNER_CBL: + } + break; + case TUNER_CBL: { +#ifdef DVB_USE_S2API + /* S2API is the DVB API new since 2.6.28. + * It is also needed for devices supporting multiple delivery systems, + * commonly DVB-C + DVB-T are supported here. + */ + fe_delivery_system_t delsys = SYS_DVBC_ANNEX_AC; + struct dtv_property p[] = { + { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, + { .cmd = DTV_FREQUENCY, .u.data = freq }, + { .cmd = DTV_INVERSION, .u.data = specInv }, + { .cmd = DTV_MODULATION, .u.data = modulation }, + { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, + { .cmd = DTV_INNER_FEC, .u.data = HP_CodeRate }, + { .cmd = DTV_TUNE }, + }; + struct dtv_properties cmdseq = { + .num = sizeof(p) / sizeof(p[0]), + .props = p + }; + MP_VERBOSE(priv, "tuning DVB-C to %d, srate=%d using DVBv5 API...\n", + freq, srate); + if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq)) == -1) { + MP_ERR(priv, "ERROR tuning channel\n"); + return -1; + } +#else feparams.frequency = freq; feparams.inversion = specInv; feparams.u.qam.symbol_rate = srate; @@ -578,9 +606,11 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, MP_ERR(priv, "ERROR tuning channel\n"); return -1; } - break; +#endif + } + break; #ifdef DVB_ATSC - case TUNER_ATSC: + case TUNER_ATSC: { feparams.frequency = freq; feparams.u.vsb.modulation = modulation; MP_VERBOSE(priv, "tuning ATSC to %d, modulation=%d\n", freq, modulation); @@ -588,7 +618,8 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, MP_ERR(priv, "ERROR tuning channel\n"); return -1; } - break; + } + break; #endif default: MP_VERBOSE(priv, "Unknown FE type. Aborting\n"); -- cgit v1.2.3 From 9a2a0b0bba600a76d405c64c7c8331ad3fade22f Mon Sep 17 00:00:00 2001 From: Oliver Freyermuth Date: Wed, 20 Jan 2016 20:56:10 +0100 Subject: stream_dvb: add verbose output in non-DVBv5 querying. May help in future debugging in case of old kernels with modern / obscure devices. --- stream/dvb_tune.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index de43907217..7b19f2df39 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -102,7 +102,9 @@ int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) mp_err(log, "FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); return 0; } - + + mp_verbose(log, "Queried tuner type of device named '%s', FD: %d\n", + fe_info.name, fe_fd); switch (fe_info.type) { case FE_OFDM: mp_verbose(log, "Tuner type seems to be DVB-T\n"); -- cgit v1.2.3 From 2df448b1f383ebb7d29bf64a1cfb827eb1fff70b Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 22 Jan 2016 11:55:47 +0100 Subject: dvb: remove trailing whitespace --- stream/dvb_tune.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'stream/dvb_tune.c') diff --git a/stream/dvb_tune.c b/stream/dvb_tune.c index 7b19f2df39..b83da040d0 100644 --- a/stream/dvb_tune.c +++ b/stream/dvb_tune.c @@ -43,7 +43,7 @@ int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) { #ifdef DVB_USE_S2API - /* S2API is the DVB API new since 2.6.28. + /* S2API is the DVB API new since 2.6.28. It allows to query frontends with multiple delivery systems. */ struct dtv_property p[] = {{ .cmd = DTV_ENUM_DELSYS }}; struct dtv_properties cmdseq = {.num = 1, .props = p}; @@ -63,9 +63,9 @@ int dvb_get_tuner_types(int fe_fd, struct mp_log *log, int** tuner_types) int supported_tuners = 0; for(;p[0].u.buffer.len > 0; p[0].u.buffer.len--) { fe_delivery_system_t delsys = p[0].u.buffer.data[p[0].u.buffer.len - 1]; - /* Second level standards like like DVB-T2, DVB-S2 not treated here - - Cards can usually either only do S/T/C or both levels. - DVB-T2 probably needs more implementation details, + /* Second level standards like like DVB-T2, DVB-S2 not treated here - + Cards can usually either only do S/T/C or both levels. + DVB-T2 probably needs more implementation details, DVB-S2 is treated in the DVB-S branch already. */ switch (delsys) { case SYS_DVBT: @@ -141,7 +141,7 @@ int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt) char frontend_dev[32], dvr_dev[32], demux_dev[32]; dvb_state_t* state = priv->state; - + sprintf(frontend_dev, "/dev/dvb/adapter%d/frontend0", n); sprintf(dvr_dev, "/dev/dvb/adapter%d/dvr0", n); sprintf(demux_dev, "/dev/dvb/adapter%d/demux0", n); @@ -180,7 +180,7 @@ int dvb_fix_demuxes(dvb_priv_t *priv, int cnt) { int i; char demux_dev[32]; - + dvb_state_t* state = priv->state; sprintf(demux_dev, "/dev/dvb/adapter%d/demux0", state->card); @@ -435,7 +435,7 @@ static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A); } -static int tune_it(dvb_priv_t *priv, int fd_frontend, +static int tune_it(dvb_priv_t *priv, int fd_frontend, unsigned int freq, unsigned int srate, char pol, int tone, bool is_dvb_s2, int stream_id, fe_spectral_inversion_t specInv, unsigned int diseqc, @@ -454,7 +454,7 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, struct dvb_frontend_parameters feparams; MP_VERBOSE(priv, "TUNE_IT, fd_frontend %d, freq %lu, srate %lu, " - "pol %c, tone %i, diseqc %u\n", fd_frontend, + "pol %c, tone %i, diseqc %u\n", fd_frontend, (long unsigned int)freq, (long unsigned int)srate, pol, tone, diseqc); @@ -574,8 +574,8 @@ static int tune_it(dvb_priv_t *priv, int fd_frontend, case TUNER_CBL: { #ifdef DVB_USE_S2API /* S2API is the DVB API new since 2.6.28. - * It is also needed for devices supporting multiple delivery systems, - * commonly DVB-C + DVB-T are supported here. + * It is also needed for devices supporting multiple delivery systems, + * commonly DVB-C + DVB-T are supported here. */ fe_delivery_system_t delsys = SYS_DVBC_ANNEX_AC; struct dtv_property p[] = { -- cgit v1.2.3