MythTV master
signalmonitor.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2// Copyright (c) 2005, Daniel Thor Kristjansson
3
4// C headers
5#include <csignal>
6#include <sys/types.h>
7#include <unistd.h>
8
9// MythTV headers
10#include "libmythbase/mythconfig.h"
11#include "libmythbase/compat.h"
15
16#include "scriptsignalmonitor.h"
17#include "signalmonitor.h"
18#include "tv_rec.h"
19
20extern "C" {
21#include "libavcodec/avcodec.h"
22}
23
24#if CONFIG_DVB
25# include "dvbsignalmonitor.h"
26# include "dvbchannel.h"
27#endif
28
29#if CONFIG_V4L2
30// Old
31# include "analogsignalmonitor.h"
32// New
33# include "v4l2encsignalmonitor.h"
34# include "v4lchannel.h"
35#endif
36
37#if CONFIG_HDHOMERUN
38# include "hdhrsignalmonitor.h"
39# include "hdhrchannel.h"
40#endif
41
42#if CONFIG_SATIP
43# include "satipsignalmonitor.h"
44# include "satipchannel.h"
45#endif
46
47#if CONFIG_IPTV
48# include "iptvsignalmonitor.h"
49# include "iptvchannel.h"
50#endif
51
52#if CONFIG_FIREWIRE
54# include "firewirechannel.h"
55#endif
56
57#if CONFIG_ASI
58# include "asisignalmonitor.h"
59# include "asichannel.h"
60#endif
61
62#if CONFIG_CETON
63# include "cetonsignalmonitor.h"
64# include "cetonchannel.h"
65#endif
66
68#include "ExternalChannel.h"
69
70// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
71#define DBG_SM(FUNC, MSG) LOG(VB_CHANNEL, LOG_DEBUG, \
72 QString("SigMon[%1](%2)::%3: %4").arg(m_inputid) \
73 .arg(m_channel->GetDevice(), FUNC, MSG))
74
92SignalMonitor *SignalMonitor::Init([[maybe_unused]] const QString& cardtype,
93 [[maybe_unused]] int db_cardnum,
94 [[maybe_unused]] ChannelBase *channel,
95 bool release_stream)
96{
97 SignalMonitor *signalMonitor = nullptr;
98
99 if (cardtype == "GuaranteedToFail")
100 {
101 // This lets all the conditionally compiled tests be set up as
102 // 'else if' statements
103 }
104#if CONFIG_DVB
105 else if (CardUtil::IsDVBInputType(cardtype))
106 {
107 auto *dvbc = dynamic_cast<DVBChannel*>(channel);
108 if (dvbc)
109 signalMonitor = new DVBSignalMonitor(db_cardnum, dvbc,
110 release_stream);
111 }
112#endif
113
114#if CONFIG_V4L2
115 else if ((cardtype.toUpper() == "HDPVR"))
116 {
117 auto *chan = dynamic_cast<V4LChannel*>(channel);
118 if (chan)
119 signalMonitor = new AnalogSignalMonitor(db_cardnum, chan,
120 release_stream);
121 }
122 else if (cardtype.toUpper() == "V4L2ENC")
123 {
124 auto *chan = dynamic_cast<V4LChannel*>(channel);
125 if (chan)
126 signalMonitor = new V4L2encSignalMonitor(db_cardnum, chan,
127 release_stream);
128 }
129#endif
130
131#if CONFIG_HDHOMERUN
132 else if (cardtype.toUpper() == "HDHOMERUN")
133 {
134 auto *hdhrc = dynamic_cast<HDHRChannel*>(channel);
135 if (hdhrc)
136 signalMonitor = new HDHRSignalMonitor(db_cardnum, hdhrc,
137 release_stream);
138 }
139#endif
140
141#if CONFIG_SATIP
142 else if (cardtype.toUpper() == "SATIP")
143 {
144 auto *satipchan = dynamic_cast<SatIPChannel*>(channel);
145 if (satipchan)
146 signalMonitor = new SatIPSignalMonitor(db_cardnum, satipchan, release_stream);
147 }
148#endif
149
150#if CONFIG_CETON
151 else if (cardtype.toUpper() == "CETON")
152 {
153 auto *cetonchan = dynamic_cast<CetonChannel*>(channel);
154 if (cetonchan)
155 signalMonitor = new CetonSignalMonitor(db_cardnum, cetonchan,
156 release_stream);
157 }
158#endif
159
160#if CONFIG_IPTV
161 else if (cardtype.toUpper() == "FREEBOX")
162 {
163 auto *fbc = dynamic_cast<IPTVChannel*>(channel);
164 if (fbc)
165 signalMonitor = new IPTVSignalMonitor(db_cardnum, fbc,
166 release_stream);
167 }
168#endif
169
170#if CONFIG_VBOX
171 else if (cardtype.toUpper() == "VBOX")
172 {
173 auto *fbc = dynamic_cast<IPTVChannel*>(channel);
174 if (fbc)
175 signalMonitor = new IPTVSignalMonitor(db_cardnum, fbc,
176 release_stream);
177 }
178#endif
179
180#if CONFIG_FIREWIRE
181 else if (cardtype.toUpper() == "FIREWIRE")
182 {
183 auto *fc = dynamic_cast<FirewireChannel*>(channel);
184 if (fc)
185 signalMonitor = new FirewireSignalMonitor(db_cardnum, fc,
186 release_stream);
187 }
188#endif
189
190#if CONFIG_ASI
191 else if (cardtype.toUpper() == "ASI")
192 {
193 auto *fc = dynamic_cast<ASIChannel*>(channel);
194 if (fc)
195 signalMonitor = new ASISignalMonitor(db_cardnum, fc,
196 release_stream);
197 }
198#endif
199
200 else if (cardtype.toUpper() == "EXTERNAL")
201 {
202 auto *fc = dynamic_cast<ExternalChannel*>(channel);
203 if (fc)
204 signalMonitor = new ExternalSignalMonitor(db_cardnum, fc,
205 release_stream);
206 }
207
208 if (!signalMonitor && channel)
209 {
210 signalMonitor = new ScriptSignalMonitor(db_cardnum, channel,
211 release_stream);
212 }
213
214 if (!signalMonitor)
215 {
216 LOG(VB_GENERAL, LOG_ERR,
217 QString("Failed to create signal monitor in Init(%1, %2, 0x%3)")
218 .arg(cardtype).arg(db_cardnum).arg((uintptr_t)channel,0,16));
219 }
220
221 return signalMonitor;
222}
223
237 bool _release_stream, uint64_t wait_for_mask)
238 : MThread("SignalMonitor"),
239 m_channel(_channel),
240 m_inputid(_inputid), m_flags(wait_for_mask),
241 m_releaseStream(_release_stream),
242 m_signalLock (QCoreApplication::translate("(Common)", "Signal Lock"),
243 "slock", 1, true, 0, 1, 0ms),
244 m_signalStrength(QCoreApplication::translate("(Common)", "Signal Power"),
245 "signal", 0, true, 0, 100, 0ms),
246 m_scriptStatus (QCoreApplication::translate("(Common)", "Script Status"),
247 "script", 3, true, 0, 3, 0ms)
248{
250 {
252 }
253}
254
259{
261 wait();
262}
263
264void SignalMonitor::AddFlags(uint64_t _flags)
265{
266 DBG_SM("AddFlags", sm_flags_to_string(_flags));
267 m_flags |= _flags;
268}
269
270void SignalMonitor::RemoveFlags(uint64_t _flags)
271{
272 DBG_SM("RemoveFlags", sm_flags_to_string(_flags));
273 m_flags &= ~_flags;
274}
275
276bool SignalMonitor::HasFlags(uint64_t _flags) const
277{
278 return (m_flags & _flags) == _flags;
279}
280
281bool SignalMonitor::HasAnyFlag(uint64_t _flags) const
282{
283 return (m_flags & _flags) != 0U;
284}
285
290{
291 DBG_SM("Start", "begin");
292 {
293 QMutexLocker locker(&m_startStopLock);
294 m_exit = false;
295 start();
296 while (!m_running)
297 m_startStopWait.wait(locker.mutex());
298 }
299 DBG_SM("Start", "end");
300}
301
306{
307 DBG_SM("Stop", "begin");
308
309 QMutexLocker locker(&m_startStopLock);
310 m_exit = true;
311 if (m_running)
312 {
313 locker.unlock();
314 wait();
315 }
316
317 DBG_SM("Stop", "end");
318}
319
329QStringList SignalMonitor::GetStatusList(void) const
330{
331 QStringList list;
332 m_statusLock.lock();
337 m_statusLock.unlock();
338
339 return list;
340}
341
344{
345 RunProlog();
346
347 QMutexLocker locker(&m_startStopLock);
348 m_running = true;
349 m_startStopWait.wakeAll();
350
351 while (!m_exit)
352 {
353 locker.unlock();
354
355 UpdateValues();
356
357 if (m_notifyFrontend && m_inputid>=0)
358 {
359 QStringList slist = GetStatusList();
360 MythEvent me(QString("SIGNAL %1").arg(m_inputid), slist);
362 }
363
364 locker.relock();
365 m_startStopWait.wait(locker.mutex(), m_updateRate.count());
366 }
367
368 // We need to send a last informational message because a
369 // signal update may have come in while we were sleeping
370 // if we are using the multithreaded dtvsignalmonitor.
371 locker.unlock();
372 if (m_notifyFrontend && m_inputid>=0)
373 {
374 QStringList slist = GetStatusList();
375 MythEvent me(QString("SIGNAL %1").arg(m_inputid), slist);
377 }
378 locker.relock();
379
380 m_running = false;
381 m_startStopWait.wakeAll();
382
383 RunEpilog();
384}
385
387{
388 QMutexLocker locker(&m_listenerLock);
389 for (auto & entry : m_listeners)
390 {
391 if (entry == listener)
392 return;
393 }
394 m_listeners.push_back(listener);
395}
396
398{
399 QMutexLocker locker(&m_listenerLock);
400
401 std::vector<SignalMonitorListener*> new_listeners;
402 for (auto & entry : m_listeners)
403 {
404 if (entry != listener)
405 new_listeners.push_back(entry);
406 }
407
408 m_listeners = new_listeners;
409}
410
413{
414 m_statusLock.lock();
415 const SignalMonitorValue& val = value;
416 m_statusLock.unlock();
417
418 QMutexLocker locker(&m_listenerLock);
419 for (auto *listener : m_listeners)
420 {
421 auto *dvblistener = dynamic_cast<DVBSignalMonitorListener*>(listener);
422
423 switch (type)
424 {
426 listener->StatusSignalLock(val);
427 break;
428 case kAllGood:
429 listener->AllGood();
430 break;
432 listener->StatusSignalStrength(val);
433 break;
435 listener->StatusChannelTuned(val);
436 break;
438 if (dvblistener)
439 dvblistener->StatusSignalToNoise(val);
440 break;
442 if (dvblistener)
443 dvblistener->StatusBitErrorRate(val);
444 break;
446 if (dvblistener)
447 dvblistener->StatusUncorrectedBlocks(val);
448 break;
450 if (dvblistener)
451 dvblistener->StatusRotorPosition(val);
452 break;
453 }
454 }
455}
456
458{
459 QMutexLocker locker(&m_statusLock);
460 if (m_scriptStatus.GetValue() < 2)
461 {
463 }
464}
465
467{
468 QMutexLocker locker(&m_listenerLock);
469 for (auto & entry : m_listeners)
470 entry->AllGood();
471}
472
474{
479}
-*- Mode: c++ -*-
Definition: asichannel.h:15
static bool IsDVBInputType(const QString &inputType)
Returns true iff the input_type is one of the DVB types.
Definition: cardutil.cpp:1030
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:32
virtual bool IsExternalChannelChangeInUse(void)
uint GetScriptStatus(bool holding_lock=false)
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:31
-*- Mode: c++ -*-
FirewireChannel Copyright (c) 2005 by Jim Westfall and Dave Abrahams Distributed as part of MythTV un...
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
void dispatch(const MythEvent &event)
This class is used as a container for messages.
Definition: mythevent.h:17
int GetValue() const
Returns the value.
QString GetName(void) const
Returns the long name of this value.
void SetValue(int _value)
QString GetStatus() const
Returns a signal monitor value as one long string.
Signal monitoring base class.
Definition: signalmonitor.h:31
~SignalMonitor() override
Stops monitoring thread.
std::chrono::milliseconds m_updateRate
void RemoveListener(SignalMonitorListener *listener)
QRecursiveMutex m_statusLock
volatile bool m_exit
virtual void RemoveFlags(uint64_t _flags)
QMutex m_listenerLock
void SendMessageAllGood(void)
void AddListener(SignalMonitorListener *listener)
static SignalMonitor * Init(const QString &cardtype, int db_cardnum, ChannelBase *channel, bool release_stream)
SignalMonitorValue m_signalLock
std::vector< SignalMonitorListener * > m_listeners
void SendMessage(SignalMonitorMessageType type, const SignalMonitorValue &val)
virtual QStringList GetStatusList(void) const
Returns QStringList containing all signals and their current values.
SignalMonitorValue m_scriptStatus
bool HasFlags(uint64_t _flags) const
virtual void Stop()
Stop signal monitoring thread.
volatile bool m_running
SignalMonitor(int, ChannelBase *, uint64_t, bool)=delete
ChannelBase * m_channel
virtual void EmitStatus(void)
static const uint64_t kSigMon_WaitForSig
QWaitCondition m_startStopWait
void run(void) override
Basic signal monitoring loop.
virtual void UpdateValues(void)
This should be overridden to actually do signal monitoring.
virtual void AddFlags(uint64_t _flags)
SignalMonitorValue m_signalStrength
QMutex m_startStopLock
virtual void Start()
Start signal monitoring thread.
volatile uint64_t m_flags
bool HasAnyFlag(uint64_t _flags) const
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:32
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define DBG_SM(FUNC, MSG)
QString sm_flags_to_string(uint64_t flags)
SignalMonitorMessageType
@ kStatusChannelTuned
@ kStatusBitErrorRate
@ kStatusUncorrectedBlocks
@ kStatusRotorPosition
@ kStatusSignalLock
@ kStatusSignalToNoise
@ kStatusSignalStrength
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:95