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 <QCoreApplication>
28#include <iostream>
29
30// MythTv headers
31#include "channelscanner_web.h"
32
33#include "libmythbase/mythconfig.h"
35
36#include "channelscan_sm.h"
37#include "channelimporter.h"
38#include "libmythtv/cardutil.h"
40#if CONFIG_SATIP
42#endif // CONFIG_SATIP
43
44#define LOC QString("ChScanWeb: ")
45
47
49{
50 if (s_Instance == nullptr)
52 return s_Instance;
53}
54
55// Called from Web Service API
56// Run in http thread
58 const QString &DesiredServices,
59 bool freeToAirOnly,
64 bool AddFullTS,
65 bool TestDecryptable,
66 const QString &ScanType,
67 const QString &FreqTable,
68 QString modulation,
69 const QString &FirstChan,
70 const QString &LastChan,
71 uint ScanId,
74 uint MplexId,
75 const QString &frequency,
76 const QString &bandwidth,
77 const QString &polarity,
78 const QString &symbolrate,
79 const QString &inversion,
80 const QString &constellation,
81 const QString &modsys,
82 const QString &coderate_lp,
83 const QString &coderate_hp,
84 const QString &fec,
85 const QString &trans_mode,
86 const QString &guard_interval,
87 const QString &hierarchy,
88 const QString &rolloff)
89{
90
92 m_cardid = cardid;
93 m_scanId = ScanId;
94
95 QString subType = CardUtil::ProbeSubTypeName(cardid);
97
98#if CONFIG_SATIP
99 if (inputType == CardUtil::INPUT_TYPES::SATIP)
100 {
102 }
103#endif // CONFIG_SATIP
104
105 int nScanType = -99;
106 if (ScanType == "FULL")
107 {
108 switch(inputType) {
111 break;
114 break;
118 break;
121 break;
124 break;
130 else
132 break;
133 default:
134 break;
135 }
136 }
137 else if (ScanType == "FULLTUNED")
138 {
139 switch(inputType) {
142 break;
145 break;
148 break;
151 break;
154 break;
160 break;
161 default:
162 break;
163 }
164 }
165 else if (ScanType == "VBOXIMPORT")
166 {
167 nScanType = ScanTypeSetting::VBoxImport;
168 }
169 else if (ScanType == "HDHRIMPORT")
170 {
171 nScanType = ScanTypeSetting::HDHRImport;
172 }
173 else if (ScanType == "MPTSIMPORT")
174 {
176 }
177 else if (ScanType == "M3UIMPORT")
178 {
179 nScanType = ScanTypeSetting::IPTVImport;
180 }
181 else if (ScanType == "ASI" || ScanType == "MPTS")
182 {
184 }
185 else if (ScanType == "EXTIMPORT")
186 {
188 }
189 else if (ScanType == "IMPORT")
190 {
192 }
193 else if (ScanType == "ALLTRANSPORT")
194 {
196 }
197 else if (ScanType == "ONETRANSPORT")
198 {
200 }
201
202 if (nScanType == -99)
203 {
204 m_dlgMsg = QObject::tr("This scan type is not supported");
205 return false;
206 }
207 ServiceRequirements service_requirements
209 if (DesiredServices == "tv")
210 service_requirements = static_cast<ServiceRequirements> (kRequireVideo | kRequireAudio);
211 else if (DesiredServices == "audio")
212 service_requirements = kRequireAudio;
213 else if (DesiredServices == "all")
214 service_requirements = kRequireNothing;
215 QString freq_std;
216 switch(nScanType)
217 {
219 freq_std = "atsc";
220 break;
222 freq_std = "dvbc";
223 break;
226 freq_std = "dvbt";
227 break;
229 freq_std = "analog";
230 break;
231 }
232
233 switch (nScanType)
234 {
236 // in this case the modulation is supplied in the
237 // scan call so it is not changed here
238 break;
240 modulation = "qam";
241 break;
244 modulation = "ofdm";
245 break;
247 modulation = "analog";
248 break;
249 }
250
251 m_scantype = nScanType;
252
253 // Get startChan. Logic copied from ScanOptionalConfig::GetStartChan(void)
254 QMap<QString,QString> startChan;
255 if (ScanTypeSetting::NITAddScan_DVBT == nScanType)
256 {
257 startChan["std"] = "dvb";
258 startChan["type"] = "OFDM";
259 startChan["frequency"] = frequency;
260 startChan["inversion"] = inversion;
261 startChan["bandwidth"] = bandwidth;
262 startChan["coderate_hp"] = coderate_hp;
263 startChan["coderate_lp"] = coderate_lp;
264 startChan["constellation"] = constellation;
265 startChan["trans_mode"] = trans_mode;
266 startChan["guard_interval"] = guard_interval;
267 startChan["hierarchy"] = hierarchy;
268 }
269 else if (ScanTypeSetting::NITAddScan_DVBT2 == nScanType)
270 {
271 startChan["std"] = "dvb";
272 startChan["type"] = "DVB_T2";
273 startChan["frequency"] = frequency;
274 startChan["inversion"] = inversion;
275 startChan["bandwidth"] = bandwidth;
276 startChan["coderate_hp"] = coderate_hp;
277 startChan["coderate_lp"] = coderate_lp;
278 startChan["constellation"] = constellation;
279 startChan["trans_mode"] = trans_mode;
280 startChan["guard_interval"] = guard_interval;
281 startChan["hierarchy"] = hierarchy;
282 startChan["mod_sys"] = modsys;
283 }
284 else if (ScanTypeSetting::NITAddScan_DVBS == nScanType)
285 {
286 startChan["std"] = "dvb";
287 startChan["type"] = "QPSK";
288 startChan["modulation"] = "qpsk";
289 startChan["frequency"] = frequency;
290 startChan["inversion"] = inversion;
291 startChan["symbolrate"] = symbolrate;
292 startChan["fec"] = fec;
293 startChan["polarity"] = polarity;
294 }
295 else if (ScanTypeSetting::NITAddScan_DVBC == nScanType)
296 {
297 startChan["std"] = "dvb";
298 startChan["type"] = "QAM";
299 startChan["frequency"] = frequency;
300 startChan["symbolrate"] = symbolrate;
301 startChan["modulation"] = modulation;
302 startChan["mod_sys"] = modsys;
303 startChan["inversion"] = inversion;
304 startChan["fec"] = fec;
305 }
306 else if (ScanTypeSetting::NITAddScan_DVBS2 == nScanType)
307 {
308 startChan["std"] = "dvb";
309 startChan["type"] = "DVB_S2";
310 startChan["frequency"] = frequency;
311 startChan["inversion"] = inversion;
312 startChan["symbolrate"] = symbolrate;
313 startChan["fec"] = fec;
314 startChan["modulation"] = modulation;
315 startChan["polarity"] = polarity;
316 startChan["mod_sys"] = modsys;
317 startChan["rolloff"] = rolloff;
318 }
319
320 setupScan(cardid);
321
322 QString inputname = get_on_input("inputname", cardid);
323 int sourceid = get_on_input("sourceid", cardid).toUInt();
324
326 {
327 m_freeToAirOnly = freeToAirOnly;
333 m_serviceRequirements = service_requirements;
334 m_sourceid = sourceid;
335 // The import is handled by the monitor thread after the complete event
337 }
338 else if (nScanType == ScanTypeSetting::IPTVImport)
339 {
340 ImportM3U(cardid, inputname, sourceid, false);
341 }
342 else if (nScanType == ScanTypeSetting::VBoxImport)
343 {
344 ImportVBox(cardid, inputname, sourceid,
345 freeToAirOnly,
346 service_requirements);
347 }
348 else if (nScanType == ScanTypeSetting::HDHRImport)
349 {
350 ImportHDHR(cardid, inputname, sourceid,
351 service_requirements);
352 }
353 else if (nScanType == ScanTypeSetting::ExternRecImport)
354 {
355 ImportExternRecorder(cardid, inputname, sourceid);
356 }
357 else if (nScanType == ScanTypeSetting::IPTVImportMPTS)
358 {
359 ImportM3U(cardid, inputname, sourceid, true);
360 }
361 else
362 {
363 Scan(
364 nScanType,
365 cardid,
366 inputname,
367 sourceid,
368 IgnoreSignalTimeout, // do_ignore_signal_timeout,
369 FollowNITSetting, // do_follow_nit,
370 TestDecryptable,
371 freeToAirOnly,
376 AddFullTS,
377 service_requirements,
378 MplexId,
379 startChan,
380 freq_std,
381 modulation,
382 FreqTable,
383 FirstChan,
384 LastChan);
385 }
386
387 return true;
388}
389
391{
392 m_runType = 0;
393 m_onlysavescan = false;
394 m_interactive = false;
395 m_cardid = 0;
396 m_status = "IDLE";
397 m_statusLock = false;
399 m_statusSnr = 0;
400 m_statusText = "";
401 m_statusLog = "";
405 m_showSignalLock = false;
406 m_showSignalStrength = false;
407 m_showSignalNoise = false;
408 m_showRotorPos = false;
409 m_dlgMsg = "";
410 m_dlgButtons.clear();
411 m_dlgInputReq = false;
412 m_dlgButton = -1;
413 m_dlgString = "";
414}
415
417{
418 stopMon();
419 ResetStatus();
420 m_cardid = cardId;
421 m_status = "RUNNING";
422 m_monitorThread = new MThread("ScanMonitor");
424 m_scanMonitor = new ScanMonitor(this);
425 m_scanMonitor->moveToThread(m_monitorThread->qthread());
426}
427
428// run in an http thread to stop the scan
430{
431 if (m_scanMonitor)
432 {
434 }
435}
436
437// run in either a monitor thread when scan completes
438// or an http thread when starting the next scan
440{
441 if (m_monitorThread)
442 {
443 if (m_scanMonitor)
445 m_scanMonitor = nullptr;
447 if (QThread::currentThread() != m_monitorThread->qthread())
448 {
450 delete m_monitorThread;
451 m_monitorThread = nullptr;
452 }
453 }
454}
455
456
457// run in the monitor thread
459{
460 auto type = scanEvent->type();
464 {
466 {
467 m_statusText = tr("Scan Complete");
468 }
470 {
471 m_statusText = tr("Scan Shut Down");
472 }
474 {
475 m_statusText = tr("Scan Error") + " " + scanEvent->strValue();
476 }
477 if (m_sigmonScanner)
478 {
481 QString msg = tr("Found %1 Transports").arg(m_transports.size());
482 m_statusTitleText = msg;
483 }
484
485 bool success = (m_iptvScanner != nullptr);
486#if CONFIG_VBOX
487 success |= (m_vboxScanner != nullptr);
488#endif
489#ifndef _WIN32
490 success |= (m_externRecScanner != nullptr);
491#endif
492#if CONFIG_HDHOMERUN
493 success |= (m_hdhrScanner != nullptr);
494#endif
495 Teardown();
496
498 {
500 ChannelImporter ci(true, true, true, true, false,
507 ci.Process(transports, get_on_input("sourceid", m_cardid).toUInt());
508 }
510 {
511 Process(m_transports, success);
512 }
513 stopMon();
514 m_status = "IDLE";
515
516 }
518 {
519 log(scanEvent->strValue());
520 }
522 {
523 m_statusText = scanEvent->strValue();
524 }
526 {
527 m_statusProgress = scanEvent->intValue();
528 }
530 {
531 m_statusLock = scanEvent->boolValue();
532 }
534 {
535 m_statusSnr = scanEvent->intValue() * 100 / 65535;
536 }
538 {
539 m_statusTitleText = scanEvent->strValue();
540 }
542 {
543 m_statusRotorPosition = scanEvent->intValue();
544 }
546 {
547 m_statusSignalStrength = scanEvent->intValue() * 100 / 65535;
548 }
549
550 QString msg;
551 if (VERBOSE_LEVEL_NONE() || VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_INFO))
552 {
553 msg = QString("%1% S/N %2 %3 : %4 (%5) %6")
554 .arg(m_statusProgress, 3)
555 .arg(m_statusSnr)
556 .arg((m_statusLock) ? "l" : "L",
557 qPrintable(m_statusText),
558 qPrintable(scanEvent->strValue()))
559 .arg("", 20);
560 }
561
562 if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_INFO))
563 {
564 static QString s_oldMsg;
565 if (msg != s_oldMsg)
566 {
567 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
568 s_oldMsg = msg;
569 }
570 }
571 else if (VERBOSE_LEVEL_NONE())
572 {
573 if (msg.length() > 80)
574 msg = msg.left(77) + "...";
575 std::cout << "\r" << msg.toLatin1().constData() << "\r";
576 std::cout << std::flush;
577 }
578}
579
581{
582 LOG(VB_GENERAL, LOG_ERR, LOC + error);
583 // post_event(m_scanMonitor, ScannerEvent::ScanErrored, 0);
584 m_statusLog.append(error).append('\n');
585 m_dlgMsg = error;
586}
587
588void ChannelScannerWeb::log(const QString &msg)
589{
590 m_statusLog.append(msg).append("\n");
591}
592
593// run in the monitor thread
595 bool success)
596{
597 ChannelImporter ci(true, true, true, true, true,
600 ci.Process(_transports, m_sourceid);
601}
602
604 bool lock, bool strength, bool snr, bool rotorpos)
605{
606 m_showSignalLock = lock;
607 m_showSignalStrength = strength;
608 m_showSignalNoise = snr;
609 m_showRotorPos = rotorpos;
610}
static GlobalComboBoxSetting * FreqTable()
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:1258
#define LOC
ServiceRequirements
@ kRequireAudio
@ kRequireNothing
@ kRequireVideo
static INPUT_TYPES toInputType(const QString &name)
Definition: cardutil.h:78
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:3080
INPUT_TYPES
all the different inputs
Definition: cardutil.h:50
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
static bool HDHRdoesDVBC(const QString &device)
If the device is valid, check if the model does DVB-C.
Definition: cardutil.cpp:3106
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:983
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:283
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 exit(int retcode=0)
Use this to exit from the thread if you are using a Qt event loop.
Definition: mthread.cpp:278
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:233
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:68
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