vdr  2.0.4
eitscan.c
Go to the documentation of this file.
1 /*
2  * eitscan.c: EIT scanner
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: eitscan.c 2.7 2012/04/07 14:39:28 kls Exp $
8  */
9 
10 #include "eitscan.h"
11 #include <stdlib.h>
12 #include "channels.h"
13 #include "dvbdevice.h"
14 #include "skins.h"
15 #include "transfer.h"
16 
17 // --- cScanData -------------------------------------------------------------
18 
19 class cScanData : public cListObject {
20 private:
22 public:
23  cScanData(const cChannel *Channel);
24  virtual int Compare(const cListObject &ListObject) const;
25  int Source(void) const { return channel.Source(); }
26  int Transponder(void) const { return channel.Transponder(); }
27  const cChannel *GetChannel(void) const { return &channel; }
28  };
29 
31 {
32  channel = *Channel;
33 }
34 
35 int cScanData::Compare(const cListObject &ListObject) const
36 {
37  const cScanData *sd = (const cScanData *)&ListObject;
38  int r = Source() - sd->Source();
39  if (r == 0)
40  r = Transponder() - sd->Transponder();
41  return r;
42 }
43 
44 // --- cScanList -------------------------------------------------------------
45 
46 class cScanList : public cList<cScanData> {
47 public:
49  void AddTransponder(const cChannel *Channel);
50  };
51 
53 {
54  for (cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch))
55  AddTransponder(ch);
56  Sort();
57 }
58 
59 void cScanList::AddTransponder(const cChannel *Channel)
60 {
61  if (Channel->Source() && Channel->Transponder()) {
62  for (cScanData *sd = First(); sd; sd = Next(sd)) {
63  if (sd->Source() == Channel->Source() && ISTRANSPONDER(sd->Transponder(), Channel->Transponder()))
64  return;
65  }
66  Add(new cScanData(Channel));
67  }
68 }
69 
70 // --- cTransponderList ------------------------------------------------------
71 
72 class cTransponderList : public cList<cChannel> {
73 public:
74  void AddTransponder(cChannel *Channel);
75  };
76 
78 {
79  for (cChannel *ch = First(); ch; ch = Next(ch)) {
80  if (ch->Source() == Channel->Source() && ch->Transponder() == Channel->Transponder()) {
81  delete Channel;
82  return;
83  }
84  }
85  Add(Channel);
86 }
87 
88 // --- cEITScanner -----------------------------------------------------------
89 
91 
93 {
94  lastScan = lastActivity = time(NULL);
95  currentChannel = 0;
96  scanList = NULL;
97  transponderList = NULL;
98 }
99 
101 {
102  delete scanList;
103  delete transponderList;
104 }
105 
107 {
108  if (!transponderList)
111 }
112 
114 {
115  lastActivity = 0;
116 }
117 
119 {
120  if (currentChannel) {
122  currentChannel = 0;
123  }
124  lastActivity = time(NULL);
125 }
126 
128 {
129  if (Setup.EPGScanTimeout || !lastActivity) { // !lastActivity means a scan was forced
130  time_t now = time(NULL);
131  if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
132  if (Channels.Lock(false, 10)) {
133  if (!scanList) {
134  scanList = new cScanList;
135  if (transponderList) {
137  delete transponderList;
138  transponderList = NULL;
139  }
141  }
142  bool AnyDeviceSwitched = false;
143  for (int i = 0; i < cDevice::NumDevices(); i++) {
144  cDevice *Device = cDevice::GetDevice(i);
145  if (Device && Device->ProvidesEIT()) {
146  for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) {
147  const cChannel *Channel = ScanData->GetChannel();
148  if (Channel) {
149  if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
150  if (Device->ProvidesTransponder(Channel)) {
151  if (Device->Priority() < 0) {
152  bool MaySwitchTransponder = Device->MaySwitchTransponder(Channel);
153  if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) {
154  if (!MaySwitchTransponder) {
155  if (Device == cDevice::ActualDevice() && !currentChannel) {
156  cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
157  currentChannel = Device->CurrentChannel();
158  Skins.Message(mtInfo, tr("Starting EPG scan"));
159  }
160  }
161  //dsyslog("EIT scan: device %d source %-8s tp %5d", Device->DeviceNumber() + 1, *cSource::ToString(Channel->Source()), Channel->Transponder());
162  Device->SwitchChannel(Channel, false);
163  scanList->Del(ScanData);
164  AnyDeviceSwitched = true;
165  break;
166  }
167  }
168  }
169  }
170  }
171  }
172  }
173  }
174  if (!scanList->Count() || !AnyDeviceSwitched) {
175  delete scanList;
176  scanList = NULL;
177  if (lastActivity == 0) // this was a triggered scan
178  Activity();
179  }
180  Channels.Unlock();
181  }
182  lastScan = time(NULL);
183  }
184  }
185 }
186