|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00002 00003 // POSIX headers 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 // If there have been any new events and we haven't 00110 // seen any in a while, tell scheduler to run. 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 // if there have been any new events, tell scheduler to run. 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 // 24 hours ago 00148 eitHelper->PruneEITCache(activeScanNextTrig.toTime_t() - 86400); 00149 } 00150 00151 lock.lock(); 00152 if ((activeScan || activeScanStopped) && !exitThread) 00153 exitThreadCond.wait(&lock, 400); // sleep up to 400 ms. 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 // TODO get input name and use it in crawl. 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 // Start at a random channel. This is so that multiple cards with 00270 // the same source don't all scan the same channels in the same 00271 // order when the backend is first started up. 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 // Add a little randomness to trigger time so multiple 00280 // cards will have a staggered channel changing time. 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 }
1.7.6.1