1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Added support for DVB devices with more than one frontend that all use the same dvr and demux

This commit is contained in:
Klaus Schmidinger 2018-10-29 12:16:35 +01:00
parent bcee8ad43d
commit cbc77f1f25
3 changed files with 228 additions and 94 deletions

View File

@ -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.

View File

@ -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)
if (dvbTuner)
return GetDeliverySystemName(dvbTuner->FrontendType());
if (numDeliverySystems)
return GetDeliverySystemName(deliverySystems[0]); // to have some reasonable default
}
return "";
}
cString cDvbDevice::DeviceName(void) const
{
return frontendInfo.name;
if (dvbTuner)
return dvbTuner->FrontendName();
return "";
}
bool cDvbDevice::Initialize(void)
@ -1702,6 +1851,7 @@ 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);
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 false;
}
bool cDvbDevice::HasLock(int TimeoutMs) const

View File

@ -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();