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:
parent
bcee8ad43d
commit
cbc77f1f25
6
HISTORY
6
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.
|
||||
|
295
dvbdevice.c
295
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)
|
||||
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
|
||||
|
15
dvbdevice.h
15
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();
|
||||
|
Loading…
Reference in New Issue
Block a user