summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY6
-rw-r--r--dvbdevice.c301
-rw-r--r--dvbdevice.h15
3 files changed, 228 insertions, 94 deletions
diff --git a/HISTORY b/HISTORY
index ec660ae5..b9dbe6c9 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9348,7 +9348,7 @@ Video Disk Recorder Revision History
Senzel).
- Official release.
-2018-09-23: Version 2.4.1
+2018-10-29: Version 2.4.1
- Fixed handling the tfRecording flag in the SVDRP commands MODT and UPDT (reported
by Johann Friedrichs).
@@ -9367,3 +9367,7 @@ Video Disk Recorder Revision History
Binder).
- Now deactivating MTD support if a non MCD capable CAM is inserted after removing
a previously used CAM that is MCD capable (thanks to Helmut Binder).
+- Added support for DVB devices with more than one frontend that all use the same
+ dvr and demux. Note that in order for this to work, you must not set symbolic
+ links like "demux1 -> demux0" and "dvr1 -> dvr0", as is mentioned in some user
+ manuals of multi frontend DVB cards.
diff --git a/dvbdevice.c b/dvbdevice.c
index 8710e775..701d6f9d 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 4.16 2018/02/15 15:37:01 kls Exp $
+ * $Id: dvbdevice.c 4.17 2018/10/29 10:40:34 kls Exp $
*/
#include "dvbdevice.h"
@@ -293,6 +293,90 @@ bool cDvbTransponderParameters::Parse(const char *s)
return true;
}
+// --- cDvbFrontend ----------------------------------------------------------
+
+class cDvbFrontend {
+private:
+ int adapter, frontend;
+ int fd_frontend;
+ uint32_t subsystemId;
+ dvb_frontend_info frontendInfo;
+ cVector<int> deliverySystems;
+ int numModulations;
+ bool QueryDeliverySystems(void);
+public:
+ cDvbFrontend(int Adapter, int Frontend);
+ ~cDvbFrontend();
+ int Open(void);
+ void Close(void);
+ const char *FrontendName(void) { return frontendInfo.name; }
+ bool ProvidesDeliverySystem(int DeliverySystem) const;
+ bool ProvidesModulation(int System, int StreamId, int Modulation) const;
+ int NumDeliverySystems(void) const { return deliverySystems.Size(); }
+ int NumModulations(void) const { return numModulations; }
+ uint32_t SubsystemId(void) const { return subsystemId; }
+ };
+
+cDvbFrontend::cDvbFrontend(int Adapter, int Frontend)
+{
+ adapter = Adapter;
+ frontend = Frontend;
+ fd_frontend = -1;
+ subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, frontend);
+ numModulations = 0;
+ Open();
+ QueryDeliverySystems();
+ Close();
+}
+
+cDvbFrontend::~cDvbFrontend()
+{
+ Close();
+}
+
+int cDvbFrontend::Open(void)
+{
+ Close();
+ fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK, true);
+ return fd_frontend;
+}
+
+void cDvbFrontend::Close(void)
+{
+ if (fd_frontend >= 0) {
+ if (close(fd_frontend) != 0)
+ esyslog("ERROR: frontend %d/%d", adapter, frontend);
+ fd_frontend = -1;
+ }
+}
+
+bool cDvbFrontend::ProvidesDeliverySystem(int DeliverySystem) const
+{
+ for (int i = 0; i < deliverySystems.Size(); i++) {
+ if (deliverySystems[i] == DeliverySystem)
+ return true;
+ }
+ return false;
+}
+
+bool cDvbFrontend::ProvidesModulation(int System, int StreamId, int Modulation) const
+{
+ if (StreamId != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM))
+ return false;
+ if (Modulation == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
+ Modulation == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
+ Modulation == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
+ Modulation == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
+ Modulation == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
+ Modulation == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
+ Modulation == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
+ Modulation == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
+ Modulation == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
+ Modulation == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && System == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to de
+ return false;
+ return true;
+}
+
// --- cDvbTuner -------------------------------------------------------------
#define TUNER_POLL_TIMEOUT 10 // ms
@@ -303,9 +387,13 @@ private:
enum eTunerStatus { tsIdle, tsSet, tsPositioning, tsTuned, tsLocked };
int frontendType;
const cDvbDevice *device;
- int fd_frontend;
- int adapter, frontend;
- uint32_t subsystemId;
+ mutable int fd_frontend;
+ int adapter;
+ mutable int frontend;
+ cVector<cDvbFrontend *> dvbFrontends;
+ mutable cDvbFrontend *dvbFrontend;
+ int numDeliverySystems;
+ int numModulations;
int tuneTimeout;
int lockTimeout;
time_t lastTimeoutReport;
@@ -320,7 +408,7 @@ private:
const cScr *scr;
bool lnbPowerTurnedOn;
eTunerStatus tunerStatus;
- cMutex mutex;
+ mutable cMutex mutex;
cCondVar locked;
cCondVar newSet;
cDvbTuner *bondedTuner;
@@ -337,14 +425,19 @@ private:
bool SetFrontend(void);
virtual void Action(void);
public:
- cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
+ cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend);
virtual ~cDvbTuner();
+ bool ProvidesDeliverySystem(int DeliverySystem) const;
+ bool ProvidesModulation(int System, int StreamId, int Modulation) const;
+ bool ProvidesFrontend(const cChannel *Channel, bool Activate = false) const;
int FrontendType(void) const { return frontendType; }
+ const char *FrontendName(void) { return dvbFrontend->FrontendName(); }
+ int NumProvidedSystems(void) const { return numDeliverySystems + numModulations; }
bool Bond(cDvbTuner *Tuner);
void UnBond(void);
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
const cChannel *GetTransponder(void) const { return &channel; }
- uint32_t SubsystemId(void) const { return subsystemId; }
+ uint32_t SubsystemId(void) const { return dvbFrontend->SubsystemId(); }
bool IsTunedTo(const cChannel *Channel) const;
void SetChannel(const cChannel *Channel);
bool Locked(int TimeoutMs = 0);
@@ -356,14 +449,14 @@ public:
cMutex cDvbTuner::bondMutex;
-cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
+cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend)
{
frontendType = SYS_UNDEFINED;
device = Device;
- fd_frontend = Fd_Frontend;
+ fd_frontend = -1;
adapter = Adapter;
frontend = Frontend;
- subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, frontend);
+ dvbFrontend = NULL;
tuneTimeout = 0;
lockTimeout = 0;
lastTimeoutReport = 0;
@@ -379,7 +472,31 @@ cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int
tunerStatus = tsIdle;
bondedTuner = NULL;
bondedMaster = false;
- SetDescription("frontend %d/%d tuner", adapter, frontend);
+ cDvbFrontend *fe = new cDvbFrontend(adapter, frontend);
+ dvbFrontends.Append(fe);
+ numDeliverySystems = fe->NumDeliverySystems();
+ numModulations = fe->NumModulations();
+ cString FrontendNumbers = cString::sprintf("%d", frontend);
+ // Check for multiple frontends:
+ if (frontend == 0) {
+ for (int i = 1; ; i++) {
+ if (access(DvbName(DEV_DVB_FRONTEND, adapter, i), F_OK) == 0) {
+ if (access(DvbName(DEV_DVB_DEMUX, adapter, i), F_OK) != 0) {
+ fe = new cDvbFrontend(adapter, i);
+ dvbFrontends.Append(fe);
+ numDeliverySystems += fe->NumDeliverySystems();
+ //numModulations += fe->NumModulations(); // looks like in multi frontend devices all frontends report the same modulations
+ FrontendNumbers = cString::sprintf("%s+%d", *FrontendNumbers, i);
+ }
+ }
+ else
+ break;
+ }
+ }
+ // Open default frontend:
+ dvbFrontend = dvbFrontends[0];
+ fd_frontend = dvbFrontend->Open();
+ SetDescription("frontend %d/%s tuner", adapter, *FrontendNumbers);
Start();
}
@@ -396,6 +513,51 @@ cDvbTuner::~cDvbTuner()
ExecuteDiseqc(lastDiseqc, &Frequency);
}
*/
+ for (int i = 0; i < dvbFrontends.Size(); i++)
+ delete dvbFrontends[i];
+}
+
+bool cDvbTuner::ProvidesDeliverySystem(int DeliverySystem) const
+{
+ for (int i = 0; i < dvbFrontends.Size(); i++) {
+ if (dvbFrontends[i]->ProvidesDeliverySystem(DeliverySystem))
+ return true;
+ }
+ return false;
+}
+
+bool cDvbTuner::ProvidesModulation(int System, int StreamId, int Modulation) const
+{
+ for (int i = 0; i < dvbFrontends.Size(); i++) {
+ if (dvbFrontends[i]->ProvidesModulation(System, StreamId, Modulation))
+ return true;
+ }
+ return false;
+}
+
+static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp);//TODO
+
+bool cDvbTuner::ProvidesFrontend(const cChannel *Channel, bool Activate) const
+{
+ cDvbTransponderParameters dtp(Channel->Parameters());
+ int DeliverySystem = GetRequiredDeliverySystem(Channel, &dtp);
+ for (int i = 0; i < dvbFrontends.Size(); i++) {
+ if (dvbFrontends[i]->ProvidesDeliverySystem(DeliverySystem) && dvbFrontends[i]->ProvidesModulation(dtp.System(), dtp.StreamId(), dtp.Modulation())) {
+ if (Activate && dvbFrontend != dvbFrontends[i]) {
+ cMutexLock MutexLock(&mutex);
+ dvbFrontend->Close();
+ dvbFrontend = dvbFrontends[i];
+ fd_frontend = dvbFrontend->Open();
+ frontend = i;
+ dsyslog("using frontend %d/%d", adapter, frontend);
+ lastUncValue = 0;
+ lastUncDelta = 0;
+ lastUncChange = 0;
+ }
+ return true;
+ }
+ }
+ return false;
}
bool cDvbTuner::Bond(cDvbTuner *Tuner)
@@ -585,7 +747,7 @@ bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double
CmdSeq.props = Props;
Valid = DTV_STAT_VALID_NONE;
if (ioctl(fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return false;
}
if (Status) {
@@ -606,7 +768,7 @@ bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double
if (Per) { SETCMD(DTV_STAT_ERROR_BLOCK_COUNT, 0);
SETCMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0); }
if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return false;
}
int i = 0;
@@ -939,7 +1101,7 @@ int cDvbTuner::GetSignalStrength(void) const
SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
SETCMD(DTV_INNER_FEC, 0);
if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return -1;
}
int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
@@ -973,7 +1135,7 @@ int cDvbTuner::GetSignalStrength(void) const
uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
// Use the subsystemId to identify individual devices in case they need
// special treatment to map their Signal value into the range 0...0xFFFF.
- switch (subsystemId) {
+ switch (dvbFrontend->SubsystemId()) {
case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
MaxSignal = 670; break;
@@ -982,7 +1144,7 @@ int cDvbTuner::GetSignalStrength(void) const
if (s > 100)
s = 100;
#ifdef DEBUG_SIGNALSTRENGTH
- fprintf(stderr, "FE %d/%d: API3 %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
+ fprintf(stderr, "FE %d/%d: API3 %08X S = %04X %04X %3d%%\n", adapter, frontend, dvbFrontend->SubsystemId(), MaxSignal, Signal, s);
#endif
return s;
}
@@ -1005,7 +1167,7 @@ int cDvbTuner::GetSignalQuality(void) const
SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return -1;
}
int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
@@ -1132,7 +1294,7 @@ int cDvbTuner::GetSignalQuality(void) const
uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
// Use the subsystemId to identify individual devices in case they need
// special treatment to map their Snr value into the range 0...0xFFFF.
- switch (subsystemId) {
+ switch (dvbFrontend->SubsystemId()) {
case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
if (frontendType == SYS_DVBS2) {
@@ -1154,7 +1316,7 @@ int cDvbTuner::GetSignalQuality(void) const
if (q > 100)
q = 100;
#ifdef DEBUG_SIGNALQUALITY
- fprintf(stderr, "FE %d/%d: API3 %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
+ fprintf(stderr, "FE %d/%d: API3 %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, dvbFrontend->SubsystemId(), MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
#endif
return q;
}
@@ -1265,7 +1427,7 @@ bool cDvbTuner::SetFrontend(void)
CmdSeq.props = Props;
SETCMD(DTV_CLEAR, 0);
if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return false;
}
CmdSeq.num = 0;
@@ -1390,7 +1552,7 @@ bool cDvbTuner::SetFrontend(void)
}
SETCMD(DTV_TUNE, 0);
if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
- esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
return false;
}
return true;
@@ -1402,11 +1564,11 @@ void cDvbTuner::Action(void)
bool LostLock = false;
fe_status_t Status = (fe_status_t)0;
while (Running()) {
+ int WaitTime = 1000;
fe_status_t NewStatus;
if (GetFrontendStatus(NewStatus))
Status = NewStatus;
cMutexLock MutexLock(&mutex);
- int WaitTime = 1000;
switch (tunerStatus) {
case tsIdle:
break; // we want the TimedWait() below!
@@ -1542,7 +1704,7 @@ int cDvbDevice::setTransferModeForDolbyDigital = 1;
cMutex cDvbDevice::bondMutex;
const char *DeliverySystemNames[] = {
- "",
+ "???",
"DVB-C",
"DVB-C",
"DVB-T",
@@ -1580,16 +1742,10 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend)
frontend = Frontend;
ciAdapter = NULL;
dvbTuner = NULL;
- numDeliverySystems = 0;
- numModulations = 0;
bondedDevice = NULL;
needsDetachBondedReceivers = false;
tsBuffer = NULL;
- // Devices that are present on all card types:
-
- int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
-
// Common Interface:
fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
@@ -1603,12 +1759,7 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend)
// We only check the devices that must be present - the others will be checked before accessing them://XXX
- if (fd_frontend >= 0) {
- if (QueryDeliverySystems(fd_frontend))
- dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend);
- }
- else
- esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
+ dvbTuner = new cDvbTuner(this, adapter, frontend);
StartSectionHandler();
}
@@ -1623,12 +1774,12 @@ cDvbDevice::~cDvbDevice()
// caused segfaults. Besides, the program is about to terminate anyway...
}
-cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
+cString DvbName(const char *Name, int Adapter, int Frontend)
{
return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE, DEV_DVB_ADAPTER, Adapter, Name, Frontend);
}
-int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
+int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
{
cString FileName = DvbName(Name, Adapter, Frontend);
int fd = open(FileName, Mode);
@@ -1669,18 +1820,16 @@ bool cDvbDevice::Probe(int Adapter, int Frontend)
cString cDvbDevice::DeviceType(void) const
{
- if (dvbTuner) {
- if (dvbTuner->FrontendType() != SYS_UNDEFINED)
- return GetDeliverySystemName(dvbTuner->FrontendType());
- if (numDeliverySystems)
- return GetDeliverySystemName(deliverySystems[0]); // to have some reasonable default
- }
+ if (dvbTuner)
+ return GetDeliverySystemName(dvbTuner->FrontendType());
return "";
}
cString cDvbDevice::DeviceName(void) const
{
- return frontendInfo.name;
+ if (dvbTuner)
+ return dvbTuner->FrontendName();
+ return "";
}
bool cDvbDevice::Initialize(void)
@@ -1702,7 +1851,8 @@ bool cDvbDevice::Initialize(void)
while ((f = AdapterDir.Next()) != NULL) {
if (strstr(f->d_name, DEV_DVB_FRONTEND) == f->d_name) {
int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND), NULL, 10);
- Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
+ if (access(DvbName(DEV_DVB_DEMUX, Adapter, Frontend), F_OK) == 0) // we only create devices for actual demuxes
+ Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
}
}
}
@@ -1741,9 +1891,11 @@ bool cDvbDevice::Initialize(void)
return Found > 0;
}
-bool cDvbDevice::QueryDeliverySystems(int fd_frontend)
+//TODO move this up to cDvbFrontend later (leaving it here for now to keep the diff small)
+bool cDvbFrontend::QueryDeliverySystems(void)
{
- numDeliverySystems = 0;
+ deliverySystems.Clear();
+ numModulations = 0;
if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
LOG_ERROR;
return false;
@@ -1773,11 +1925,9 @@ bool cDvbDevice::QueryDeliverySystems(int fd_frontend)
int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
if (Result == 0) {
for (uint i = 0; i < Props[0].u.buffer.len; i++) {
- if (numDeliverySystems >= MAXDELIVERYSYSTEMS) {
- esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
- break;
- }
- deliverySystems[numDeliverySystems++] = Props[0].u.buffer.data[i];
+ // activate this line to simulate a multi-frontend device if you only have a single-frontend device with DVB-S and DVB-S2:
+ //if (frontend == 0 && Props[0].u.buffer.data[i] != SYS_DVBS || frontend == 1 && Props[0].u.buffer.data[i] != SYS_DVBS2)
+ deliverySystems.Append(Props[0].u.buffer.data[i]);
}
LegacyMode = false;
}
@@ -1788,22 +1938,22 @@ bool cDvbDevice::QueryDeliverySystems(int fd_frontend)
if (LegacyMode) {
// Legacy mode (DVB-API < 5.5):
switch (frontendInfo.type) {
- case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
+ case FE_QPSK: deliverySystems.Append(SYS_DVBS);
if (frontendInfo.caps & FE_CAN_2G_MODULATION)
- deliverySystems[numDeliverySystems++] = SYS_DVBS2;
+ deliverySystems.Append(SYS_DVBS2);
break;
- case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
+ case FE_OFDM: deliverySystems.Append(SYS_DVBT);
if (frontendInfo.caps & FE_CAN_2G_MODULATION)
- deliverySystems[numDeliverySystems++] = SYS_DVBT2;
+ deliverySystems.Append(SYS_DVBT2);
break;
- case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC; break;
- case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break;
+ case FE_QAM: deliverySystems.Append(SYS_DVBC_ANNEX_AC); break;
+ case FE_ATSC: deliverySystems.Append(SYS_ATSC); break;
default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
}
}
- if (numDeliverySystems > 0) {
+ if (deliverySystems.Size() > 0) {
cString ds("");
- for (int i = 0; i < numDeliverySystems; i++)
+ for (int i = 0; i < deliverySystems.Size(); i++)
ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", GetDeliverySystemName(deliverySystems[i]));
cString ms("");
if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
@@ -1999,11 +2149,7 @@ void cDvbDevice::CloseFilter(int Handle)
bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
{
- for (int i = 0; i < numDeliverySystems; i++) {
- if (deliverySystems[i] == DeliverySystem)
- return true;
- }
- return false;
+ return dvbTuner->ProvidesDeliverySystem(DeliverySystem);
}
bool cDvbDevice::ProvidesSource(int Source) const
@@ -2020,20 +2166,9 @@ bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
{
if (!ProvidesSource(Channel->Source()))
return false; // doesn't provide source
- cDvbTransponderParameters dtp(Channel->Parameters());
- if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) ||
- dtp.StreamId() != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM) ||
- dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
- dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
- dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
- dtp.Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
- dtp.Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
- dtp.Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
- dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
- dtp.Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
- dtp.Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
- dtp.Modulation() == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
+ if (!dvbTuner->ProvidesFrontend(Channel))
return false; // requires modulation system which frontend doesn't provide
+ cDvbTransponderParameters dtp(Channel->Parameters());
if (!cSource::IsSat(Channel->Source()) ||
(!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
return DeviceHooksProvidesTransponder(Channel);
@@ -2047,7 +2182,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
bool needsDetachReceivers = false;
needsDetachBondedReceivers = false;
- if (dvbTuner && ProvidesTransponder(Channel)) {
+ if (ProvidesTransponder(Channel)) {
result = hasPriority;
if (Priority > IDLEPRIORITY) {
if (Receiving()) {
@@ -2097,7 +2232,7 @@ bool cDvbDevice::ProvidesEIT(void) const
int cDvbDevice::NumProvidedSystems(void) const
{
- return numDeliverySystems + numModulations;
+ return dvbTuner ? dvbTuner->NumProvidedSystems() : 0;
}
const cPositioner *cDvbDevice::Positioner(void) const
@@ -2137,9 +2272,11 @@ bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
- if (dvbTuner)
+ if (dvbTuner->ProvidesFrontend(Channel, true)) {
dvbTuner->SetChannel(Channel);
- return true;
+ return true;
+ }
+ return false;
}
bool cDvbDevice::HasLock(int TimeoutMs) const
diff --git a/dvbdevice.h b/dvbdevice.h
index 0490a44f..530e8ba7 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.h 4.4 2017/05/09 11:24:47 kls Exp $
+ * $Id: dvbdevice.h 4.5 2018/10/20 11:39:11 kls Exp $
*/
#ifndef __DVBDEVICE_H
@@ -67,8 +67,6 @@ enum {
// --- End of definitions for older DVB API versions -------------------------
-#define MAXDELIVERYSYSTEMS 8
-
#define DEV_VIDEO "/dev/video"
#define DEV_DVB_BASE "/dev/dvb"
#define DEV_DVB_ADAPTER "adapter"
@@ -162,12 +160,12 @@ public:
class cDvbTuner;
+cString DvbName(const char *Name, int Adapter, int Frontend);
+int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError = false);
+
/// The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
class cDvbDevice : public cDevice {
-protected:
- static cString DvbName(const char *Name, int Adapter, int Frontend);
- static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError = false);
private:
static bool Exists(int Adapter, int Frontend);
///< Checks whether the given adapter/frontend exists.
@@ -182,16 +180,11 @@ public:
protected:
int adapter, frontend;
private:
- dvb_frontend_info frontendInfo;
- int deliverySystems[MAXDELIVERYSYSTEMS];
- int numDeliverySystems;
- int numModulations;
int fd_dvr, fd_ca;
bool checkTsBuffer;
static cMutex bondMutex;
cDvbDevice *bondedDevice;
mutable bool needsDetachBondedReceivers;
- bool QueryDeliverySystems(int fd_frontend);
public:
cDvbDevice(int Adapter, int Frontend);
virtual ~cDvbDevice();