00001
00002
00003
00004 #include <sys/time.h>
00005 #include "compat.h"
00006
00007 #include <cstdlib>
00008
00009 #include "tv_rec.h"
00010
00011 #include "channelbase.h"
00012 #include "iso639.h"
00013 #include "eitscanner.h"
00014 #include "eithelper.h"
00015 #include "scheduledrecording.h"
00016 #include "util.h"
00017
00018 #define LOC QString("EITScanner: ")
00019 #define LOC_ID QString("EITScanner (%1): ").arg(cardnum)
00020
00021
00026 void EITThread::run(void)
00027 {
00028 scanner->RunEventLoop();
00029 }
00030
00038 QMutex EITScanner::resched_lock;
00039 QDateTime EITScanner::resched_next_time = QDateTime::currentDateTime();
00040 const uint EITScanner::kMinRescheduleInterval = 150;
00041
00042 EITScanner::EITScanner(uint _cardnum)
00043 : channel(NULL), eitSource(NULL), eitHelper(new EITHelper()),
00044 exitThread(false), rec(NULL), activeScan(false), cardnum(_cardnum)
00045 {
00046 QStringList langPref = iso639_get_language_list();
00047 eitHelper->SetLanguagePreferences(langPref);
00048
00049
00050 eventThread.scanner = this;
00051 eventThread.start(QThread::IdlePriority);
00052 }
00053
00054 void EITScanner::TeardownAll(void)
00055 {
00056 StopActiveScan();
00057 if (!exitThread)
00058 {
00059 exitThread = true;
00060 exitThreadCond.wakeAll();
00061 eventThread.wait();
00062 }
00063
00064 if (eitHelper)
00065 {
00066 delete eitHelper;
00067 eitHelper = NULL;
00068 }
00069 }
00070
00074 void EITScanner::RunEventLoop(void)
00075 {
00076 static const uint sz[] = { 2000, 1800, 1600, 1400, 1200, };
00077 static const float rt[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, };
00078
00079 exitThread = false;
00080
00081 MythTimer t;
00082 uint eitCount = 0;
00083
00084 while (!exitThread)
00085 {
00086 uint list_size = eitHelper->GetListSize();
00087
00088 float rate = 1.0f;
00089 for (uint i = 0; i < 5; i++)
00090 {
00091 if (list_size >= sz[i])
00092 {
00093 rate = rt[i];
00094 break;
00095 }
00096 }
00097
00098 lock.lock();
00099 if (eitSource)
00100 eitSource->SetEITRate(rate);
00101 lock.unlock();
00102
00103 if (list_size)
00104 {
00105 eitCount += eitHelper->ProcessEvents();
00106 t.start();
00107 }
00108
00109
00110
00111 if (eitCount && (t.elapsed() > 60 * 1000))
00112 {
00113 VERBOSE(VB_EIT, LOC_ID + "Added "<<eitCount<<" EIT Events");
00114 eitCount = 0;
00115 RescheduleRecordings();
00116 }
00117
00118 if (activeScan && (QDateTime::currentDateTime() > activeScanNextTrig))
00119 {
00120
00121 if (eitCount)
00122 {
00123 VERBOSE(VB_EIT, LOC_ID + "Added "<<eitCount<<" EIT Events");
00124 eitCount = 0;
00125 RescheduleRecordings();
00126 }
00127
00128 if (activeScanNextChan == activeScanChannels.end())
00129 activeScanNextChan = activeScanChannels.begin();
00130
00131 if (!(*activeScanNextChan).isEmpty())
00132 {
00133 eitHelper->WriteEITCache();
00134 rec->SetChannel(*activeScanNextChan, TVRec::kFlagEITScan);
00135 VERBOSE(VB_EIT, LOC_ID +
00136 QString("Now looking for EIT data on "
00137 "multiplex of channel %1")
00138 .arg(*activeScanNextChan));
00139 }
00140
00141 activeScanNextTrig = QDateTime::currentDateTime()
00142 .addSecs(activeScanTrigTime);
00143 activeScanNextChan++;
00144
00145
00146 eitHelper->PruneEITCache(activeScanNextTrig.toTime_t() - 86400);
00147 }
00148
00149 exitThreadCond.wait(400);
00150 }
00151 }
00152
00159 void EITScanner::RescheduleRecordings(void)
00160 {
00161 if (!resched_lock.tryLock())
00162 return;
00163
00164 if (resched_next_time > QDateTime::currentDateTime())
00165 {
00166 VERBOSE(VB_EIT, LOC + "Rate limiting reschedules..");
00167 resched_lock.unlock();
00168 return;
00169 }
00170
00171 resched_next_time =
00172 QDateTime::currentDateTime().addSecs(kMinRescheduleInterval);
00173 resched_lock.unlock();
00174
00175 ScheduledRecording::signalChange(-1);
00176 }
00177
00182 void EITScanner::StartPassiveScan(ChannelBase *_channel,
00183 EITSource *_eitSource,
00184 bool _ignore_source)
00185 {
00186 QMutexLocker locker(&lock);
00187
00188 uint sourceid = (_ignore_source) ? 0 : _channel->GetCurrentSourceID();
00189 eitSource = _eitSource;
00190 channel = _channel;
00191 ignore_source = _ignore_source;
00192
00193 if (ignore_source)
00194 VERBOSE(VB_EIT, LOC_ID + "EIT scan ignoring sourceid.");
00195
00196 eitHelper->SetSourceID(sourceid);
00197 eitSource->SetEITHelper(eitHelper);
00198 eitSource->SetEITRate(1.0f);
00199
00200 VERBOSE(VB_EIT, LOC_ID + "Started passive scan.");
00201 }
00202
00206 void EITScanner::StopPassiveScan(void)
00207 {
00208 QMutexLocker locker(&lock);
00209
00210 if (eitSource)
00211 {
00212 eitSource->SetEITHelper(NULL);
00213 eitSource = NULL;
00214 }
00215 channel = NULL;
00216
00217 eitHelper->WriteEITCache();
00218 eitHelper->SetSourceID(0);
00219 }
00220
00221 void EITScanner::StartActiveScan(TVRec *_rec, uint max_seconds_per_source,
00222 bool _ignore_source)
00223 {
00224 rec = _rec;
00225 ignore_source = _ignore_source;
00226
00227 if (!activeScanChannels.size())
00228 {
00229
00230 MSqlQuery query(MSqlQuery::InitCon());
00231 query.prepare(
00232 "SELECT channum, MIN(chanid) "
00233 "FROM channel, cardinput, capturecard, videosource "
00234 "WHERE cardinput.sourceid = channel.sourceid AND "
00235 " videosource.sourceid = channel.sourceid AND "
00236 " capturecard.cardid = cardinput.cardid AND "
00237 " channel.mplexid IS NOT NULL AND "
00238 " useonairguide = 1 AND "
00239 " useeit = 1 AND "
00240 " channum != '' AND "
00241 " cardinput.cardid = :CARDID "
00242 "GROUP BY mplexid "
00243 "ORDER BY cardinput.sourceid, mplexid, "
00244 " atsc_major_chan, atsc_minor_chan ");
00245 query.bindValue(":CARDID", rec->GetCaptureCardNum());
00246
00247 if (!query.exec() || !query.isActive())
00248 {
00249 MythContext::DBError("EITScanner::StartActiveScan", query);
00250 return;
00251 }
00252
00253 while (query.next())
00254 activeScanChannels.push_back(query.value(0).toString());
00255
00256 activeScanNextChan = activeScanChannels.begin();
00257 }
00258
00259 VERBOSE(VB_EIT, LOC_ID +
00260 QString("StartActiveScan called with %1 multiplexes")
00261 .arg(activeScanChannels.size()));
00262
00263
00264
00265
00266 if (activeScanChannels.size())
00267 {
00268 uint randomStart = random() % activeScanChannels.size();
00269 activeScanNextChan = activeScanChannels.at(randomStart);
00270
00271 activeScanNextTrig = QDateTime::currentDateTime();
00272 activeScanTrigTime = max_seconds_per_source;
00273
00274
00275 activeScanTrigTime += random() % 29;
00276 activeScan = true;
00277 }
00278 }
00279
00280 void EITScanner::StopActiveScan()
00281 {
00282 activeScan = false;
00283 rec = NULL;
00284 StopPassiveScan();
00285 }