vdr  1.7.27
eitscan.c
Go to the documentation of this file.
00001 /*
00002  * eitscan.c: EIT scanner
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: eitscan.c 2.6 2012/03/07 13:54:34 kls Exp $
00008  */
00009 
00010 #include "eitscan.h"
00011 #include <stdlib.h>
00012 #include "channels.h"
00013 #include "dvbdevice.h"
00014 #include "skins.h"
00015 #include "transfer.h"
00016 
00017 // --- cScanData -------------------------------------------------------------
00018 
00019 class cScanData : public cListObject {
00020 private:
00021   cChannel channel;
00022 public:
00023   cScanData(const cChannel *Channel);
00024   virtual int Compare(const cListObject &ListObject) const;
00025   int Source(void) const { return channel.Source(); }
00026   int Transponder(void) const { return channel.Transponder(); }
00027   const cChannel *GetChannel(void) const { return &channel; }
00028   };
00029 
00030 cScanData::cScanData(const cChannel *Channel)
00031 {
00032   channel = *Channel;
00033 }
00034 
00035 int cScanData::Compare(const cListObject &ListObject) const
00036 {
00037   const cScanData *sd = (const cScanData *)&ListObject;
00038   int r = Source() - sd->Source();
00039   if (r == 0)
00040      r = Transponder() - sd->Transponder();
00041   return r;
00042 }
00043 
00044 // --- cScanList -------------------------------------------------------------
00045 
00046 class cScanList : public cList<cScanData> {
00047 public:
00048   void AddTransponders(cList<cChannel> *Channels);
00049   void AddTransponder(const cChannel *Channel);
00050   };
00051 
00052 void cScanList::AddTransponders(cList<cChannel> *Channels)
00053 {
00054   for (cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch))
00055       AddTransponder(ch);
00056   Sort();
00057 }
00058 
00059 void cScanList::AddTransponder(const cChannel *Channel)
00060 {
00061   if (Channel->Source() && Channel->Transponder()) {
00062      for (cScanData *sd = First(); sd; sd = Next(sd)) {
00063          if (sd->Source() == Channel->Source() && ISTRANSPONDER(sd->Transponder(), Channel->Transponder()))
00064             return;
00065          }
00066      Add(new cScanData(Channel));
00067      }
00068 }
00069 
00070 // --- cTransponderList ------------------------------------------------------
00071 
00072 class cTransponderList : public cList<cChannel> {
00073 public:
00074   void AddTransponder(cChannel *Channel);
00075   };
00076 
00077 void cTransponderList::AddTransponder(cChannel *Channel)
00078 {
00079   for (cChannel *ch = First(); ch; ch = Next(ch)) {
00080       if (ch->Source() == Channel->Source() && ch->Transponder() == Channel->Transponder()) {
00081          delete Channel;
00082          return;
00083          }
00084       }
00085   Add(Channel);
00086 }
00087 
00088 // --- cEITScanner -----------------------------------------------------------
00089 
00090 cEITScanner EITScanner;
00091 
00092 cEITScanner::cEITScanner(void)
00093 {
00094   lastScan = lastActivity = time(NULL);
00095   currentChannel = 0;
00096   scanList = NULL;
00097   transponderList = NULL;
00098 }
00099 
00100 cEITScanner::~cEITScanner()
00101 {
00102   delete scanList;
00103   delete transponderList;
00104 }
00105 
00106 void cEITScanner::AddTransponder(cChannel *Channel)
00107 {
00108   if (!transponderList)
00109      transponderList = new cTransponderList;
00110   transponderList->AddTransponder(Channel);
00111 }
00112 
00113 void cEITScanner::ForceScan(void)
00114 {
00115   lastActivity = 0;
00116 }
00117 
00118 void cEITScanner::Activity(void)
00119 {
00120   if (currentChannel) {
00121      Channels.SwitchTo(currentChannel);
00122      currentChannel = 0;
00123      }
00124   lastActivity = time(NULL);
00125 }
00126 
00127 void cEITScanner::Process(void)
00128 {
00129   if (Setup.EPGScanTimeout || !lastActivity) { // !lastActivity means a scan was forced
00130      time_t now = time(NULL);
00131      if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
00132         if (Channels.Lock(false, 10)) {
00133            if (!scanList) {
00134               scanList = new cScanList;
00135               if (transponderList) {
00136                  scanList->AddTransponders(transponderList);
00137                  delete transponderList;
00138                  transponderList = NULL;
00139                  }
00140               scanList->AddTransponders(&Channels);
00141               }
00142            bool AnyDeviceSwitched = false;
00143            for (int i = 0; i < cDevice::NumDevices(); i++) {
00144                cDevice *Device = cDevice::GetDevice(i);
00145                if (Device && Device->ProvidesEIT()) {
00146                   for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) {
00147                       const cChannel *Channel = ScanData->GetChannel();
00148                       if (Channel) {
00149                          if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
00150                             if (Device->ProvidesTransponder(Channel)) {
00151                                if (!Device->Receiving()) {
00152                                   bool MaySwitchTransponder = Device->MaySwitchTransponder(Channel);
00153                                   if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) {
00154                                      if (!MaySwitchTransponder) {
00155                                         if (Device == cDevice::ActualDevice() && !currentChannel) {
00156                                            cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
00157                                            currentChannel = Device->CurrentChannel();
00158                                            Skins.Message(mtInfo, tr("Starting EPG scan"));
00159                                            }
00160                                         }
00161                                      //dsyslog("EIT scan: device %d  source  %-8s tp %5d", Device->DeviceNumber() + 1, *cSource::ToString(Channel->Source()), Channel->Transponder());
00162                                      Device->SwitchChannel(Channel, false);
00163                                      scanList->Del(ScanData);
00164                                      AnyDeviceSwitched = true;
00165                                      break;
00166                                      }
00167                                   }
00168                                }
00169                             }
00170                          }
00171                       }
00172                   }
00173                }
00174            if (!scanList->Count() || !AnyDeviceSwitched) {
00175               delete scanList;
00176               scanList = NULL;
00177               if (lastActivity == 0) // this was a triggered scan
00178                  Activity();
00179               }
00180            Channels.Unlock();
00181            }
00182         lastScan = time(NULL);
00183         }
00184      }
00185 }