00001
00002
00003
00004
00005 #include <sys/types.h>
00006 #include <signal.h>
00007 #include <unistd.h>
00008
00009
00010 #include "scriptsignalmonitor.h"
00011 #include "signalmonitor.h"
00012 #include "mythcontext.h"
00013 #include "compat.h"
00014 #include "mythlogging.h"
00015 #include "tv_rec.h"
00016
00017 extern "C" {
00018 #include "libavcodec/avcodec.h"
00019 }
00020 #include "mythmiscutil.h"
00021
00022 #ifdef USING_DVB
00023 # include "dvbsignalmonitor.h"
00024 # include "dvbchannel.h"
00025 #endif
00026
00027 #ifdef USING_V4L2
00028 # include "analogsignalmonitor.h"
00029 # include "v4lchannel.h"
00030 #endif
00031
00032 #ifdef USING_HDHOMERUN
00033 # include "hdhrsignalmonitor.h"
00034 # include "hdhrchannel.h"
00035 #endif
00036
00037 #ifdef USING_IPTV
00038 # include "iptvsignalmonitor.h"
00039 # include "iptvchannel.h"
00040 #endif
00041
00042 #ifdef USING_FIREWIRE
00043 # include "firewiresignalmonitor.h"
00044 # include "firewirechannel.h"
00045 #endif
00046
00047 #ifdef USING_ASI
00048 # include "asisignalmonitor.h"
00049 # include "asichannel.h"
00050 #endif
00051
00052 #ifdef USING_CETON
00053 # include "cetonsignalmonitor.h"
00054 # include "cetonchannel.h"
00055 #endif
00056
00057 #undef DBG_SM
00058 #define DBG_SM(FUNC, MSG) LOG(VB_CHANNEL, LOG_DEBUG, \
00059 QString("SM(%1)::%2: %3").arg(channel->GetDevice()).arg(FUNC).arg(MSG))
00060
00078 static void ALRMhandler(int )
00079 {
00080 LOG(VB_GENERAL, LOG_NOTICE, "SignalMonitor: Got SIGALRM");
00081 signal(SIGINT, ALRMhandler);
00082 }
00083
00084 SignalMonitor *SignalMonitor::Init(QString cardtype, int db_cardnum,
00085 ChannelBase *channel)
00086 {
00087 (void) cardtype;
00088 (void) db_cardnum;
00089 (void) channel;
00090
00091 SignalMonitor *signalMonitor = NULL;
00092
00093 {
00094 QMutexLocker locker(avcodeclock);
00095 #if 0
00096 avcodec_register_all();
00097 #endif
00098 }
00099
00100 #ifdef USING_DVB
00101 if (CardUtil::IsDVBCardType(cardtype))
00102 {
00103 DVBChannel *dvbc = dynamic_cast<DVBChannel*>(channel);
00104 if (dvbc)
00105 signalMonitor = new DVBSignalMonitor(db_cardnum, dvbc);
00106 }
00107 #endif
00108
00109 #ifdef USING_V4L2
00110 if ((cardtype.toUpper() == "HDPVR"))
00111 {
00112 V4LChannel *chan = dynamic_cast<V4LChannel*>(channel);
00113 if (chan)
00114 signalMonitor = new AnalogSignalMonitor(db_cardnum, chan);
00115 }
00116 #endif
00117
00118 #ifdef USING_HDHOMERUN
00119 if (cardtype.toUpper() == "HDHOMERUN")
00120 {
00121 HDHRChannel *hdhrc = dynamic_cast<HDHRChannel*>(channel);
00122 if (hdhrc)
00123 signalMonitor = new HDHRSignalMonitor(db_cardnum, hdhrc);
00124 }
00125 #endif
00126
00127 #ifdef USING_CETON
00128 if (cardtype.toUpper() == "CETON")
00129 {
00130 CetonChannel *cetonchan = dynamic_cast<CetonChannel*>(channel);
00131 if (cetonchan)
00132 signalMonitor = new CetonSignalMonitor(db_cardnum, cetonchan);
00133 }
00134 #endif
00135
00136 #ifdef USING_IPTV
00137 if (cardtype.toUpper() == "FREEBOX")
00138 {
00139 IPTVChannel *fbc = dynamic_cast<IPTVChannel*>(channel);
00140 if (fbc)
00141 signalMonitor = new IPTVSignalMonitor(db_cardnum, fbc);
00142 }
00143 #endif
00144
00145 #ifdef USING_FIREWIRE
00146 if (cardtype.toUpper() == "FIREWIRE")
00147 {
00148 FirewireChannel *fc = dynamic_cast<FirewireChannel*>(channel);
00149 if (fc)
00150 signalMonitor = new FirewireSignalMonitor(db_cardnum, fc);
00151 }
00152 #endif
00153
00154 #ifdef USING_ASI
00155 if (cardtype.toUpper() == "ASI")
00156 {
00157 ASIChannel *fc = dynamic_cast<ASIChannel*>(channel);
00158 if (fc)
00159 signalMonitor = new ASISignalMonitor(db_cardnum, fc);
00160 }
00161 #endif
00162
00163 if (!signalMonitor && channel)
00164 {
00165 signalMonitor = new ScriptSignalMonitor(db_cardnum, channel);
00166 }
00167
00168 if (!signalMonitor)
00169 {
00170 LOG(VB_GENERAL, LOG_ERR,
00171 QString("Failed to create signal monitor in Init(%1, %2, 0x%3)")
00172 .arg(cardtype).arg(db_cardnum).arg((long)channel,0,16));
00173 }
00174
00175 return signalMonitor;
00176 }
00177
00191 SignalMonitor::SignalMonitor(int _capturecardnum, ChannelBase *_channel,
00192 uint64_t wait_for_mask)
00193 : MThread("SignalMonitor"),
00194 channel(_channel), pParent(NULL),
00195 capturecardnum(_capturecardnum), flags(wait_for_mask),
00196 update_rate(25), minimum_update_rate(5),
00197 update_done(false), notify_frontend(true),
00198 tablemon(false), eit_scan(false),
00199 signalLock (QObject::tr("Signal Lock"), "slock",
00200 1, true, 0, 1, 0),
00201 signalStrength(QObject::tr("Signal Power"), "signal",
00202 0, true, 0, 100, 0),
00203 scriptStatus (QObject::tr("Script Status"), "script",
00204 3, true, 0, 3, 0),
00205 running(false), exit(false),
00206 statusLock(QMutex::Recursive)
00207 {
00208 if (!channel->IsExternalChannelChangeSupported())
00209 {
00210 scriptStatus.SetValue(3);
00211 }
00212 }
00213
00217 SignalMonitor::~SignalMonitor()
00218 {
00219 Stop();
00220 wait();
00221 }
00222
00223 void SignalMonitor::AddFlags(uint64_t _flags)
00224 {
00225 DBG_SM("AddFlags", sm_flags_to_string(_flags));
00226 flags |= _flags;
00227 }
00228
00229 void SignalMonitor::RemoveFlags(uint64_t _flags)
00230 {
00231 DBG_SM("RemoveFlags", sm_flags_to_string(_flags));
00232 flags &= ~_flags;
00233 }
00234
00235 bool SignalMonitor::HasFlags(uint64_t _flags) const
00236 {
00237 return (flags & _flags) == _flags;
00238 }
00239
00240 bool SignalMonitor::HasAnyFlag(uint64_t _flags) const
00241 {
00242 return (flags & _flags);
00243 }
00244
00248 void SignalMonitor::Start()
00249 {
00250 DBG_SM("Start", "begin");
00251 {
00252 QMutexLocker locker(&startStopLock);
00253 exit = false;
00254 start();
00255 while (!running)
00256 startStopWait.wait(locker.mutex());
00257 }
00258 DBG_SM("Start", "end");
00259 }
00260
00264 void SignalMonitor::Stop()
00265 {
00266 DBG_SM("Stop", "begin");
00267
00268 QMutexLocker locker(&startStopLock);
00269 exit = true;
00270 if (running)
00271 {
00272 locker.unlock();
00273 wait();
00274 }
00275
00276 DBG_SM("Stop", "end");
00277 }
00278
00288 QStringList SignalMonitor::GetStatusList(void) const
00289 {
00290 QStringList list;
00291 statusLock.lock();
00292 list<<scriptStatus.GetName()<<scriptStatus.GetStatus();
00293 list<<signalLock.GetName()<<signalLock.GetStatus();
00294 if (HasFlags(kSigMon_WaitForSig))
00295 list<<signalStrength.GetName()<<signalStrength.GetStatus();
00296 statusLock.unlock();
00297
00298 return list;
00299 }
00300
00302 void SignalMonitor::run(void)
00303 {
00304 RunProlog();
00305
00306 QMutexLocker locker(&startStopLock);
00307 running = true;
00308 startStopWait.wakeAll();
00309
00310 while (!exit)
00311 {
00312 locker.unlock();
00313
00314 UpdateValues();
00315
00316 if (notify_frontend && capturecardnum>=0)
00317 {
00318 QStringList slist = GetStatusList();
00319 MythEvent me(QString("SIGNAL %1").arg(capturecardnum), slist);
00320 gCoreContext->dispatch(me);
00321 }
00322
00323 locker.relock();
00324 startStopWait.wait(locker.mutex(), update_rate);
00325 }
00326
00327
00328
00329
00330 locker.unlock();
00331 if (notify_frontend && capturecardnum>=0)
00332 {
00333 QStringList slist = GetStatusList();
00334 MythEvent me(QString("SIGNAL %1").arg(capturecardnum), slist);
00335 gCoreContext->dispatch(me);
00336 }
00337 locker.relock();
00338
00339 running = false;
00340 startStopWait.wakeAll();
00341
00342 RunEpilog();
00343 }
00344
00345 void SignalMonitor::AddListener(SignalMonitorListener *listener)
00346 {
00347 QMutexLocker locker(&listenerLock);
00348 for (uint i = 0; i < listeners.size(); i++)
00349 {
00350 if (listeners[i] == listener)
00351 return;
00352 }
00353 listeners.push_back(listener);
00354 }
00355
00356 void SignalMonitor::RemoveListener(SignalMonitorListener *listener)
00357 {
00358 QMutexLocker locker(&listenerLock);
00359
00360 vector<SignalMonitorListener*> new_listeners;
00361 for (uint i = 0; i < listeners.size(); i++)
00362 {
00363 if (listeners[i] != listener)
00364 new_listeners.push_back(listeners[i]);
00365 }
00366
00367 listeners = new_listeners;
00368 }
00369
00370 void SignalMonitor::SendMessage(
00371 SignalMonitorMessageType type, const SignalMonitorValue &value)
00372 {
00373 statusLock.lock();
00374 SignalMonitorValue val = value;
00375 statusLock.unlock();
00376
00377 QMutexLocker locker(&listenerLock);
00378 for (uint i = 0; i < listeners.size(); i++)
00379 {
00380 SignalMonitorListener *listener = listeners[i];
00381 DVBSignalMonitorListener *dvblistener =
00382 dynamic_cast<DVBSignalMonitorListener*>(listener);
00383
00384 switch (type)
00385 {
00386 case kStatusSignalLock:
00387 listener->StatusSignalLock(val);
00388 break;
00389 case kAllGood:
00390 listener->AllGood();
00391 break;
00392 case kStatusSignalStrength:
00393 listener->StatusSignalStrength(val);
00394 break;
00395 case kStatusChannelTuned:
00396 listener->StatusChannelTuned(val);
00397 break;
00398 case kStatusSignalToNoise:
00399 if (dvblistener)
00400 dvblistener->StatusSignalToNoise(val);
00401 break;
00402 case kStatusBitErrorRate:
00403 if (dvblistener)
00404 dvblistener->StatusBitErrorRate(val);
00405 break;
00406 case kStatusUncorrectedBlocks:
00407 if (dvblistener)
00408 dvblistener->StatusUncorrectedBlocks(val);
00409 break;
00410 case kStatusRotorPosition:
00411 if (dvblistener)
00412 dvblistener->StatusRotorPosition(val);
00413 break;
00414 }
00415 }
00416 }
00417
00418 void SignalMonitor::UpdateValues(void)
00419 {
00420 QMutexLocker locker(&statusLock);
00421 if (channel->IsExternalChannelChangeSupported() &&
00422 (scriptStatus.GetValue() < 2))
00423 {
00424 scriptStatus.SetValue(channel->GetScriptStatus());
00425 }
00426 }
00427
00428 void SignalMonitor::SendMessageAllGood(void)
00429 {
00430 QMutexLocker locker(&listenerLock);
00431 for (uint i = 0; i < listeners.size(); i++)
00432 listeners[i]->AllGood();
00433 }
00434
00435 void SignalMonitor::EmitStatus(void)
00436 {
00437 SendMessage(kStatusChannelTuned, scriptStatus);
00438 SendMessage(kStatusSignalLock, signalLock);
00439 if (HasFlags(kSigMon_WaitForSig))
00440 SendMessage(kStatusSignalStrength, signalStrength);
00441 }