mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Added support for DVB devices with more than one frontend that all use the same dvr and demux
This commit is contained in:
		
							
								
								
									
										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. | ||||
|   | ||||
							
								
								
									
										301
									
								
								dvbdevice.c
									
									
									
									
									
								
							
							
						
						
									
										301
									
								
								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 | ||||
|   | ||||
							
								
								
									
										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(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user