MythTV master
channelscanner_web.cpp
Go to the documentation of this file.
1/* -*- Mode: c++ -*-
2 * vim: set expandtab tabstop=4 shiftwidth=4:
3 *
4 * Original Project
5 * MythTV http://www.mythtv.org
6 *
7 * Copyright (c) 2008 Daniel Kristjansson
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
23 *
24 */
25
26// Qt headers
27#include <QtGlobal>
28#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
29#include <QtSystemDetection>
30#endif
31#include <QCoreApplication>
32#include <iostream>
33
34// MythTv headers
35#include "channelscanner_web.h"
36
37#include "libmythbase/mythconfig.h"
39
40#include "channelscan_sm.h"
41#include "channelimporter.h"
42#include "libmythtv/cardutil.h"
44#if CONFIG_SATIP
46#endif // CONFIG_SATIP
47
48#define LOC QString("ChScanWeb: ")
49
51
53{
54 if (s_Instance == nullptr)
56 return s_Instance;
57}
58
59// Called from Web Service API
60// Run in http thread
62 const QString &DesiredServices,
63 bool freeToAirOnly,
68 bool AddFullTS,
69 bool TestDecryptable,
70 const QString &ScanType,
71 const QString &FreqTable,
72 QString modulation,
73 const QString &FirstChan,
74 const QString &LastChan,
75 uint ScanId,
78 uint MplexId,
79 const QString &frequency,
80 const QString &bandwidth,
81 const QString &polarity,
82 const QString &symbolrate,
83 const QString &inversion,
84 const QString &constellation,
85 const QString &modsys,
86 const QString &coderate_lp,
87 const QString &coderate_hp,
88 const QString &fec,
89 const QString &trans_mode,
90 const QString &guard_interval,
91 const QString &hierarchy,
92 const QString &rolloff)
93{
94
96 m_cardid = cardid;
97 m_scanId = ScanId;
98
99 QString subType = CardUtil::ProbeSubTypeName(cardid);
100 CardUtil::INPUT_TYPES inputType = CardUtil::toInputType(subType);
101
102#if CONFIG_SATIP
103 if (inputType == CardUtil::INPUT_TYPES::SATIP)
104 {
106 }
107#endif // CONFIG_SATIP
108
109 int nScanType = -99;
110 if (ScanType == "FULL")
111 {
112 switch(inputType) {
115 break;
118 break;
122 break;
125 break;
128 break;
134 else
136 break;
137 default:
138 break;
139 }
140 }
141 else if (ScanType == "FULLTUNED")
142 {
143 switch(inputType) {
146 break;
149 break;
152 break;
155 break;
158 break;
164 break;
165 default:
166 break;
167 }
168 }
169 else if (ScanType == "VBOXIMPORT")
170 {
171 nScanType = ScanTypeSetting::VBoxImport;
172 }
173 else if (ScanType == "HDHRIMPORT")
174 {
175 nScanType = ScanTypeSetting::HDHRImport;
176 }
177 else if (ScanType == "MPTSIMPORT")
178 {
180 }
181 else if (ScanType == "M3UIMPORT")
182 {
183 nScanType = ScanTypeSetting::IPTVImport;
184 }
185 else if (ScanType == "ASI" || ScanType == "MPTS")
186 {
188 }
189 else if (ScanType == "EXTIMPORT")
190 {
192 }
193 else if (ScanType == "IMPORT")
194 {
196 }
197 else if (ScanType == "ALLTRANSPORT")
198 {
200 }
201 else if (ScanType == "ONETRANSPORT")
202 {
204 }
205
206 if (nScanType == -99)
207 {
208 m_dlgMsg = QObject::tr("This scan type is not supported");
209 return false;
210 }
211 ServiceRequirements service_requirements
213 if (DesiredServices == "tv")
214 service_requirements = static_cast<ServiceRequirements> (kRequireVideo | kRequireAudio);
215 else if (DesiredServices == "audio")
216 service_requirements = kRequireAudio;
217 else if (DesiredServices == "all")
218 service_requirements = kRequireNothing;
219 QString freq_std;
220 switch(nScanType)
221 {
223 freq_std = "atsc";
224 break;
226 freq_std = "dvbc";
227 break;
230 freq_std = "dvbt";
231 break;
233 freq_std = "analog";
234 break;
235 }
236
237 switch (nScanType)
238 {
240 // in this case the modulation is supplied in the
241 // scan call so it is not changed here
242 break;
244 modulation = "qam";
245 break;
248 modulation = "ofdm";
249 break;
251 modulation = "analog";
252 break;
253 }
254
255 m_scantype = nScanType;
256
257 // Get startChan. Logic copied from ScanOptionalConfig::GetStartChan(void)
258 QMap<QString,QString> startChan;
259 if (ScanTypeSetting::NITAddScan_DVBT == nScanType)
260 {
261 startChan["std"] = "dvb";
262 startChan["type"] = "OFDM";
263 startChan["frequency"] = frequency;
264 startChan["inversion"] = inversion;
265 startChan["bandwidth"] = bandwidth;
266 startChan["coderate_hp"] = coderate_hp;
267 startChan["coderate_lp"] = coderate_lp;
268 startChan["constellation"] = constellation;
269 startChan["trans_mode"] = trans_mode;
270 startChan["guard_interval"] = guard_interval;
271 startChan["hierarchy"] = hierarchy;
272 }
273 else if (ScanTypeSetting::NITAddScan_DVBT2 == nScanType)
274 {
275 startChan["std"] = "dvb";
276 startChan["type"] = "DVB_T2";
277 startChan["frequency"] = frequency;
278 startChan["inversion"] = inversion;
279 startChan["bandwidth"] = bandwidth;
280 startChan["coderate_hp"] = coderate_hp;
281 startChan["coderate_lp"] = coderate_lp;
282 startChan["constellation"] = constellation;
283 startChan["trans_mode"] = trans_mode;
284 startChan["guard_interval"] = guard_interval;
285 startChan["hierarchy"] = hierarchy;
286 startChan["mod_sys"] = modsys;
287 }
288 else if (ScanTypeSetting::NITAddScan_DVBS == nScanType)
289 {
290 startChan["std"] = "dvb";
291 startChan["type"] = "QPSK";
292 startChan["modulation"] = "qpsk";
293 startChan["frequency"] = frequency;
294 startChan["inversion"] = inversion;
295 startChan["symbolrate"] = symbolrate;
296 startChan["fec"] = fec;
297 startChan["polarity"] = polarity;
298 }
299 else if (ScanTypeSetting::NITAddScan_DVBC == nScanType)
300 {
301 startChan["std"] = "dvb";
302 startChan["type"] = "QAM";
303 startChan["frequency"] = frequency;
304 startChan["symbolrate"] = symbolrate;
305 startChan["modulation"] = modulation;
306 startChan["mod_sys"] = modsys;
307 startChan["inversion"] = inversion;
308 startChan["fec"] = fec;
309 }
310 else if (ScanTypeSetting::NITAddScan_DVBS2 == nScanType)
311 {
312 startChan["std"] = "dvb";
313 startChan["type"] = "DVB_S2";
314 startChan["frequency"] = frequency;
315 startChan["inversion"] = inversion;
316 startChan["symbolrate"] = symbolrate;
317 startChan["fec"] = fec;
318 startChan["modulation"] = modulation;
319 startChan["polarity"] = polarity;
320 startChan["mod_sys"] = modsys;
321 startChan["rolloff"] = rolloff;
322 }
323
324 setupScan(cardid);
325
326 QString inputname = get_on_input("inputname", cardid);
327 int sourceid = get_on_input("sourceid", cardid).toUInt();
328
330 {
331 m_freeToAirOnly = freeToAirOnly;
337 m_serviceRequirements = service_requirements;
338 m_sourceid = sourceid;
339 // The import is handled by the monitor thread after the complete event
341 }
342 else if (nScanType == ScanTypeSetting::IPTVImport)
343 {
344 ImportM3U(cardid, inputname, sourceid, false);
345 }
346 else if (nScanType == ScanTypeSetting::VBoxImport)
347 {
348 ImportVBox(cardid, inputname, sourceid,
349 freeToAirOnly,
350 service_requirements);
351 }
352 else if (nScanType == ScanTypeSetting::HDHRImport)
353 {
354 ImportHDHR(cardid, inputname, sourceid,
355 service_requirements);
356 }
357 else if (nScanType == ScanTypeSetting::ExternRecImport)
358 {
359 ImportExternRecorder(cardid, inputname, sourceid);
360 }
361 else if (nScanType == ScanTypeSetting::IPTVImportMPTS)
362 {
363 ImportM3U(cardid, inputname, sourceid, true);
364 }
365 else
366 {
367 Scan(
368 nScanType,
369 cardid,
370 inputname,
371 sourceid,
372 IgnoreSignalTimeout, // do_ignore_signal_timeout,
373 FollowNITSetting, // do_follow_nit,
374 TestDecryptable,
375 freeToAirOnly,
380 AddFullTS,
381 service_requirements,
382 MplexId,
383 startChan,
384 freq_std,
385 modulation,
386 FreqTable,
387 FirstChan,
388 LastChan);
389 }
390
391 return true;
392}
393
395{
396 m_runType = 0;
397 m_onlysavescan = false;
398 m_interactive = false;
399 m_cardid = 0;
400 m_status = "IDLE";
401 m_statusLock = false;
403 m_statusSnr = 0;
404 m_statusText = "";
405 m_statusLog = "";
409 m_showSignalLock = false;
410 m_showSignalStrength = false;
411 m_showSignalNoise = false;
412 m_showRotorPos = false;
413 m_dlgMsg = "";
414 m_dlgButtons.clear();
415 m_dlgInputReq = false;
416 m_dlgButton = -1;
417 m_dlgString = "";
418}
419
421{
422 stopMon();
423 ResetStatus();
424 m_cardid = cardId;
425 m_status = "RUNNING";
426 m_monitorThread = new MThread("ScanMonitor");
428 m_scanMonitor = new ScanMonitor(this);
429 m_scanMonitor->moveToThread(m_monitorThread->qthread());
430}
431
432// run in an http thread to stop the scan
434{
435 if (m_scanMonitor)
436 {
438 }
439}
440
441// run in either a monitor thread when scan completes
442// or an http thread when starting the next scan
444{
445 if (m_monitorThread)
446 {
447 if (m_scanMonitor)
449 m_scanMonitor = nullptr;
451 if (QThread::currentThread() != m_monitorThread->qthread())
452 {
454 delete m_monitorThread;
455 m_monitorThread = nullptr;
456 }
457 }
458}
459
460
461// run in the monitor thread
463{
464 auto type = scanEvent->type();
468 {
470 {
471 m_statusText = tr("Scan Complete");
472 }
474 {
475 m_statusText = tr("Scan Shut Down");
476 }
478 {
479 m_statusText = tr("Scan Error") + " " + scanEvent->strValue();
480 }
481 if (m_sigmonScanner)
482 {
485 QString msg = tr("Found %1 Transports").arg(m_transports.size());
486 m_statusTitleText = msg;
487 }
488
489 bool success = (m_iptvScanner != nullptr);
490#if CONFIG_VBOX
491 success |= (m_vboxScanner != nullptr);
492#endif
493#ifndef Q_OS_WINDOWS
494 success |= (m_externRecScanner != nullptr);
495#endif
496#if CONFIG_HDHOMERUN
497 success |= (m_hdhrScanner != nullptr);
498#endif
499 Teardown();
500
502 {
504 ChannelImporter ci(true, true, true, true, false,
511 ci.Process(transports, get_on_input("sourceid", m_cardid).toUInt());
512 }
514 {
515 Process(m_transports, success);
516 }
517 stopMon();
518 m_status = "IDLE";
519
520 }
522 {
523 log(scanEvent->strValue());
524 }
526 {
527 m_statusText = scanEvent->strValue();
528 }
530 {
531 m_statusProgress = scanEvent->intValue();
532 }
534 {
535 m_statusLock = scanEvent->boolValue();
536 }
538 {
539 m_statusSnr = scanEvent->intValue() * 100 / 65535;
540 }
542 {
543 m_statusTitleText = scanEvent->strValue();
544 }
546 {
547 m_statusRotorPosition = scanEvent->intValue();
548 }
550 {
551 m_statusSignalStrength = scanEvent->intValue() * 100 / 65535;
552 }
553
554 QString msg;
555 if (VERBOSE_LEVEL_NONE() || VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_INFO))
556 {
557 msg = QString("%1% S/N %2 %3 : %4 (%5) %6")
558 .arg(m_statusProgress, 3)
559 .arg(m_statusSnr)
560 .arg((m_statusLock) ? "l" : "L",
561 qPrintable(m_statusText),
562 qPrintable(scanEvent->strValue()))
563 .arg("", 20);
564 }
565
566 if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_INFO))
567 {
568 static QString s_oldMsg;
569 if (msg != s_oldMsg)
570 {
571 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
572 s_oldMsg = msg;
573 }
574 }
575 else if (VERBOSE_LEVEL_NONE())
576 {
577 if (msg.length() > 80)
578 msg = msg.left(77) + "...";
579 std::cout << "\r" << msg.toLatin1().constData() << "\r";
580 std::cout << std::flush;
581 }
582}
583
585{
586 LOG(VB_GENERAL, LOG_ERR, LOC + error);
587 // post_event(m_scanMonitor, ScannerEvent::ScanErrored, 0);
588 m_statusLog.append(error).append('\n');
589 m_dlgMsg = error;
590}
591
592void ChannelScannerWeb::log(const QString &msg)
593{
594 m_statusLog.append(msg).append("\n");
595}
596
597// run in the monitor thread
599 bool success)
600{
601 ChannelImporter ci(true, true, true, true, true,
604 ci.Process(_transports, m_sourceid);
605}
606
608 bool lock, bool strength, bool snr, bool rotorpos)
609{
610 m_showSignalLock = lock;
611 m_showSignalStrength = strength;
612 m_showSignalNoise = snr;
613 m_showRotorPos = rotorpos;
614}
static GlobalComboBoxSetting * FreqTable()
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:1264
#define LOC
ServiceRequirements
@ kRequireAudio
@ kRequireNothing
@ kRequireVideo
static INPUT_TYPES toInputType(const QString &name)
Definition: cardutil.h:80
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:3086
INPUT_TYPES
all the different inputs
Definition: cardutil.h:52
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:296
static bool HDHRdoesDVBC(const QString &device)
If the device is valid, check if the model does DVB-C.
Definition: cardutil.cpp:3112
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:989
void Process(const ScanDTVTransportList &_transports, int sourceid=-1)
chan_info_map_t GetChannelList(transport_scan_items_it_t trans_info, ScannedChannelInfo *scan_info) const
void StopScanner(void)
Stops the ChannelScanSM event loop and the signal monitor, blocking until both exit.
void MonitorProgress(bool lock, bool strength, bool snr, bool rotor) override
void Process(const ScanDTVTransportList &_transports, bool success=false)
static ChannelScannerWeb * s_Instance
void setupScan(int CardId)
void HandleEvent(const ScannerEvent *scanEvent) override
ScanDTVTransportList m_transports
bool StartScan(uint CardId, const QString &DesiredServices, bool FreeToAirOnly, bool ChannelNumbersOnly, bool CompleteChannelsOnly, bool FullChannelSearch, bool RemoveDuplicates, bool AddFullTS, bool TestDecryptable, const QString &ScanType, const QString &FreqTable, QString Modulation, const QString &FirstChan, const QString &LastChan, uint ScanId, bool IgnoreSignalTimeout, bool FollowNITSetting, uint MplexId, const QString &Frequency, const QString &Bandwidth, const QString &Polarity, const QString &SymbolRate, const QString &Inversion, const QString &Constellation, const QString &ModSys, const QString &CodeRate_LP, const QString &CodeRate_HP, const QString &FEC, const QString &Trans_Mode, const QString &Guard_Interval, const QString &Hierarchy, const QString &RollOff)
void InformUser(const QString &error) override
void log(const QString &msg)
static ChannelScannerWeb * getInstance()
ChannelScannerWeb(void)=default
friend class ScanMonitor
bool m_completeOnly
Only complete channels desired post scan?
IPTVChannelFetcher * m_iptvScanner
ChannelScanSM * m_sigmonScanner
virtual bool ImportHDHR(uint cardid, const QString &inputname, uint sourceid, ServiceRequirements serviceType)
virtual void Teardown(void)
virtual bool ImportM3U(uint cardid, const QString &inputname, uint sourceid, bool is_mpts)
bool m_fullSearch
Extended search for old channels post scan?
bool m_channelNumbersOnly
Only channels with logical channel numbers desired post scan?
bool m_freeToAirOnly
Only fta channels desired post scan?
bool m_removeDuplicates
Remove duplicate transports and channels?
virtual bool ImportVBox(uint cardid, const QString &inputname, uint sourceid, bool ftaOnly, ServiceRequirements serviceType)
ScanMonitor * m_scanMonitor
bool m_addFullTS
Add MPTS "full transport stream" channels.
ServiceRequirements m_serviceRequirements
Services desired post scan.
virtual bool ImportExternRecorder(uint cardid, const QString &inputname, uint sourceid)
void Scan(int scantype, uint cardid, const QString &inputname, uint sourceid, bool do_ignore_signal_timeout, bool do_follow_nit, bool do_test_decryption, bool do_fta_only, bool do_lcn_only, bool do_complete_only, bool do_full_channel_search, bool do_remove_duplicates, bool do_add_full_ts, ServiceRequirements service_requirements, uint mplexid, const QMap< QString, QString > &startChan, const QString &freq_std, const QString &mod, const QString &tbl, const QString &tbl_start=QString(), const QString &tbl_end=QString())
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:281
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:298
void exit(int retcode=0)
Use this to exit from the thread if you are using a Qt event loop.
Definition: mthread.cpp:276
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:231
static CardUtil::INPUT_TYPES toDVBInputType(const QString &deviceid)
Definition: satiputils.cpp:172
virtual void deleteLater(void)
Definition: scanmonitor.cpp:91
@ CurrentTransportScan
Scans the transport when there is no tuner (for ASI)
static const Type kSetStatusSignalLock
Definition: scanmonitor.h:116
QString strValue() const
Definition: scanmonitor.h:94
static const Type kScanShutdown
Definition: scanmonitor.h:107
static const Type kSetStatusTitleText
Definition: scanmonitor.h:111
static const Type kSetStatusSignalToNoise
Definition: scanmonitor.h:114
static const Type kSetStatusText
Definition: scanmonitor.h:110
bool boolValue() const
Definition: scanmonitor.h:100
static const Type kAppendTextToLog
Definition: scanmonitor.h:109
static const Type kSetStatusRotorPosition
Definition: scanmonitor.h:113
static const Type kScanComplete
Definition: scanmonitor.h:106
static const Type kSetPercentComplete
Definition: scanmonitor.h:112
static const Type kSetStatusSignalStrength
Definition: scanmonitor.h:115
int intValue() const
Definition: scanmonitor.h:97
static const Type kScanErrored
Definition: scanmonitor.h:108
unsigned int uint
Definition: compat.h:60
std::vector< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:143
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
static bool VERBOSE_LEVEL_NONE()
Definition: mythlogging.h:28
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def error(message)
Definition: smolt.py:409
ScanDTVTransportList LoadScan(uint scanid)
Definition: scaninfo.cpp:77
void post_event(QObject *dest, QEvent::Type type, int val)
Percentage to set to after the first tune.
Definition: scanmonitor.cpp:68