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 "mythmiscutil.h"
00017 #include "mythdb.h"
00018 #include "mythlogging.h"
00019 #include "mthread.h"
00020
00021 #define LOC QString("EITScanner: ")
00022 #define LOC_ID QString("EITScanner (%1): ").arg(cardnum)
00023
00031 QMutex EITScanner::resched_lock;
00032 QDateTime EITScanner::resched_next_time = QDateTime::currentDateTime();
00033 const uint EITScanner::kMinRescheduleInterval = 150;
00034
00035 EITScanner::EITScanner(uint _cardnum)
00036 : channel(NULL), eitSource(NULL),
00037 eitHelper(new EITHelper()), eventThread(new MThread("EIT", this)),
00038 exitThread(false),
00039 rec(NULL), activeScan(false),
00040 activeScanStopped(true), activeScanTrigTime(0),
00041 cardnum(_cardnum)
00042 {
00043 QStringList langPref = iso639_get_language_list();
00044 eitHelper->SetLanguagePreferences(langPref);
00045
00046 eventThread->start(QThread::IdlePriority);
00047 }
00048
00049 void EITScanner::TeardownAll(void)
00050 {
00051 StopActiveScan();
00052 if (!exitThread)
00053 {
00054 lock.lock();
00055 exitThread = true;
00056 exitThreadCond.wakeAll();
00057 lock.unlock();
00058 }
00059 eventThread->wait();
00060 delete eventThread;
00061 eventThread = NULL;
00062
00063 if (eitHelper)
00064 {
00065 delete eitHelper;
00066 eitHelper = NULL;
00067 }
00068 }
00069
00073 void EITScanner::run(void)
00074 {
00075 static const uint sz[] = { 2000, 1800, 1600, 1400, 1200, };
00076 static const float rt[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, };
00077
00078 lock.lock();
00079
00080 MythTimer t;
00081 uint eitCount = 0;
00082
00083 while (!exitThread)
00084 {
00085 lock.unlock();
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 LOG(VB_EIT, LOG_INFO,
00114 LOC_ID + QString("Added %1 EIT Events").arg(eitCount));
00115 eitCount = 0;
00116 RescheduleRecordings();
00117 }
00118
00119 if (activeScan && (QDateTime::currentDateTime() > activeScanNextTrig))
00120 {
00121
00122 if (eitCount)
00123 {
00124 LOG(VB_EIT, LOG_INFO,
00125 LOC_ID + QString("Added %1 EIT Events").arg(eitCount));
00126 eitCount = 0;
00127 RescheduleRecordings();
00128 }
00129
00130 if (activeScanNextChan == activeScanChannels.end())
00131 activeScanNextChan = activeScanChannels.begin();
00132
00133 if (!(*activeScanNextChan).isEmpty())
00134 {
00135 eitHelper->WriteEITCache();
00136 rec->SetChannel(*activeScanNextChan, TVRec::kFlagEITScan);
00137 LOG(VB_EIT, LOG_INFO,
00138 LOC_ID + QString("Now looking for EIT data on "
00139 "multiplex of channel %1")
00140 .arg(*activeScanNextChan));
00141 }
00142
00143 activeScanNextTrig = QDateTime::currentDateTime()
00144 .addSecs(activeScanTrigTime);
00145 ++activeScanNextChan;
00146
00147
00148 eitHelper->PruneEITCache(activeScanNextTrig.toTime_t() - 86400);
00149 }
00150
00151 lock.lock();
00152 if ((activeScan || activeScanStopped) && !exitThread)
00153 exitThreadCond.wait(&lock, 400);
00154
00155 if (!activeScan && !activeScanStopped)
00156 {
00157 activeScanStopped = true;
00158 activeScanCond.wakeAll();
00159 }
00160 }
00161 activeScanStopped = true;
00162 activeScanCond.wakeAll();
00163 lock.unlock();
00164 }
00165
00172 void EITScanner::RescheduleRecordings(void)
00173 {
00174 if (!resched_lock.tryLock())
00175 return;
00176
00177 if (resched_next_time > QDateTime::currentDateTime())
00178 {
00179 LOG(VB_EIT, LOG_INFO, LOC + "Rate limiting reschedules..");
00180 resched_lock.unlock();
00181 return;
00182 }
00183
00184 resched_next_time =
00185 QDateTime::currentDateTime().addSecs(kMinRescheduleInterval);
00186 resched_lock.unlock();
00187
00188 ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(), "EITScanner");
00189 }
00190
00195 void EITScanner::StartPassiveScan(ChannelBase *_channel,
00196 EITSource *_eitSource)
00197 {
00198 QMutexLocker locker(&lock);
00199
00200 uint sourceid = _channel->GetCurrentSourceID();
00201 eitSource = _eitSource;
00202 channel = _channel;
00203
00204 eitHelper->SetSourceID(sourceid);
00205 eitSource->SetEITHelper(eitHelper);
00206 eitSource->SetEITRate(1.0f);
00207
00208 LOG(VB_EIT, LOG_INFO, LOC_ID + "Started passive scan.");
00209 }
00210
00214 void EITScanner::StopPassiveScan(void)
00215 {
00216 QMutexLocker locker(&lock);
00217
00218 if (eitSource)
00219 {
00220 eitSource->SetEITHelper(NULL);
00221 eitSource = NULL;
00222 }
00223 channel = NULL;
00224
00225 eitHelper->WriteEITCache();
00226 eitHelper->SetSourceID(0);
00227 }
00228
00229 void EITScanner::StartActiveScan(TVRec *_rec, uint max_seconds_per_source)
00230 {
00231 rec = _rec;
00232
00233 if (!activeScanChannels.size())
00234 {
00235
00236 MSqlQuery query(MSqlQuery::InitCon());
00237 query.prepare(
00238 "SELECT channum, MIN(chanid) "
00239 "FROM channel, cardinput, capturecard, videosource "
00240 "WHERE cardinput.sourceid = channel.sourceid AND "
00241 " videosource.sourceid = channel.sourceid AND "
00242 " capturecard.cardid = cardinput.cardid AND "
00243 " channel.mplexid IS NOT NULL AND "
00244 " useonairguide = 1 AND "
00245 " useeit = 1 AND "
00246 " channum != '' AND "
00247 " cardinput.cardid = :CARDID "
00248 "GROUP BY mplexid "
00249 "ORDER BY cardinput.sourceid, mplexid, "
00250 " atsc_major_chan, atsc_minor_chan ");
00251 query.bindValue(":CARDID", rec->GetCaptureCardNum());
00252
00253 if (!query.exec() || !query.isActive())
00254 {
00255 MythDB::DBError("EITScanner::StartActiveScan", query);
00256 return;
00257 }
00258
00259 while (query.next())
00260 activeScanChannels.push_back(query.value(0).toString());
00261
00262 activeScanNextChan = activeScanChannels.begin();
00263 }
00264
00265 LOG(VB_EIT, LOG_INFO, LOC_ID +
00266 QString("StartActiveScan called with %1 multiplexes")
00267 .arg(activeScanChannels.size()));
00268
00269
00270
00271
00272 if (activeScanChannels.size())
00273 {
00274 uint randomStart = random() % activeScanChannels.size();
00275 activeScanNextChan = activeScanChannels.begin()+randomStart;
00276
00277 activeScanNextTrig = QDateTime::currentDateTime();
00278 activeScanTrigTime = max_seconds_per_source;
00279
00280
00281 activeScanTrigTime += random() % 29;
00282 activeScanStopped = false;
00283 activeScan = true;
00284 }
00285 }
00286
00287 void EITScanner::StopActiveScan(void)
00288 {
00289 QMutexLocker locker(&lock);
00290
00291 activeScanStopped = false;
00292 activeScan = false;
00293 exitThreadCond.wakeAll();
00294
00295 locker.unlock();
00296 StopPassiveScan();
00297 locker.relock();
00298
00299 while (!activeScan && !activeScanStopped)
00300 activeScanCond.wait(&lock, 100);
00301
00302 rec = NULL;
00303 }