MythTV  0.26-pre
signalmonitor.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 // Copyright (c) 2005, Daniel Thor Kristjansson
00003 
00004 // C headers
00005 #include <sys/types.h>
00006 #include <signal.h>
00007 #include <unistd.h>
00008 
00009 // MythTV headers
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 /*sig*/)
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     // We need to send a last informational message because a
00328     // signal update may have come in while we were sleeping
00329     // if we are using the multithreaded dtvsignalmonitor.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends