00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <unistd.h>
00034
00035
00036 #include <qapplication.h>
00037
00038
00039 #include "mythcontext.h"
00040 #include "scanwizard.h"
00041 #include "scanwizardhelpers.h"
00042 #include "scanwizardscanner.h"
00043 #include "channelbase.h"
00044 #include "dtvsignalmonitor.h"
00045 #include "siscan.h"
00046 #include "dvbconfparser.h"
00047
00048 #ifdef USING_V4L
00049 #include "channel.h"
00050 #include "analogsignalmonitor.h"
00051 #endif
00052
00053 #ifdef USING_DVB
00054 #include "dvbchannel.h"
00055 #include "dvbsignalmonitor.h"
00056 #endif
00057
00058 #ifdef USING_HDHOMERUN
00059 #include "hdhrchannel.h"
00060 #include "hdhrsignalmonitor.h"
00061 #endif
00062
00063 #include "iptvchannelfetcher.h"
00064
00065 #define LOC QString("SWizScan: ")
00066 #define LOC_ERR QString("SWizScan, Error: ")
00067
00069 #define TRANSPORT_PCT 6
00071 #define TUNED_PCT 3
00072
00073 QString ScanWizardScanner::kTitle = QString::null;
00074
00075
00076 static void init_statics(void)
00077 {
00078 static QMutex lock;
00079 static bool do_init = true;
00080 QMutexLocker locker(&lock);
00081 if (do_init)
00082 {
00083 ScanWizardScanner::kTitle = ScanWizardScanner::tr("Scanning");
00084 do_init = false;
00085 }
00086 }
00087
00088 void post_event(QObject *dest, ScannerEvent::TYPE type, int val)
00089 {
00090 ScannerEvent* e = new ScannerEvent(type);
00091 e->intValue(val);
00092 QApplication::postEvent(dest, e);
00093 }
00094
00095 ScanWizardScanner::ScanWizardScanner(void)
00096 : VerticalConfigurationGroup(false, true, false, false),
00097 log(new LogList()), channel(NULL), popupProgress(NULL),
00098 scanner(NULL), freeboxScanner(NULL), nVideoSource(0)
00099 {
00100 init_statics();
00101
00102 setLabel(kTitle);
00103 addChild(log);
00104 }
00105
00106 ScanWizardScanner::~ScanWizardScanner()
00107 {
00108 Teardown();
00109
00110 QMutexLocker locker(&popupLock);
00111 StopPopup();
00112 }
00113
00114 void ScanWizardScanner::Teardown()
00115 {
00116
00117 if (scanner)
00118 {
00119 scanner->deleteLater();
00120 scanner = NULL;
00121 }
00122
00123 if (channel)
00124 {
00125 delete channel;
00126 channel = NULL;
00127 }
00128
00129 #ifdef USING_IPTV
00130 if (freeboxScanner)
00131 {
00132 freeboxScanner->Stop();
00133 freeboxScanner->deleteLater();
00134 freeboxScanner = NULL;
00135 }
00136 #endif
00137 }
00138
00139 void ScanWizardScanner::customEvent(QCustomEvent *e)
00140 {
00141 ScannerEvent *scanEvent = (ScannerEvent*) e;
00142
00143 switch (scanEvent->eventType())
00144 {
00145 case ScannerEvent::ScanComplete:
00146 {
00147 QMutexLocker locker(&popupLock);
00148 if (popupProgress)
00149 {
00150 popupProgress->SetScanProgress(1.0);
00151 popupProgress->accept();
00152 }
00153 }
00154 break;
00155
00156 case ScannerEvent::ScanShutdown:
00157 {
00158 Teardown();
00159 }
00160 break;
00161
00162 case ScannerEvent::AppendTextToLog:
00163 {
00164 log->updateText(scanEvent->strValue());
00165 }
00166 break;
00167
00168 default:
00169 break;
00170 }
00171
00172 QMutexLocker locker(&popupLock);
00173 if (!popupProgress)
00174 return;
00175
00176 switch (scanEvent->eventType())
00177 {
00178 case ScannerEvent::SetStatusText:
00179 popupProgress->SetStatusText(scanEvent->strValue());
00180 break;
00181 case ScannerEvent::SetStatusTitleText:
00182 popupProgress->SetStatusTitleText(scanEvent->strValue());
00183 break;
00184 case ScannerEvent::SetPercentComplete:
00185 popupProgress->SetScanProgress(scanEvent->intValue() * 0.01);
00186 break;
00187 case ScannerEvent::SetStatusSignalLock:
00188 popupProgress->SetStatusLock(scanEvent->intValue());
00189 break;
00190 case ScannerEvent::SetStatusSignalToNoise:
00191 popupProgress->SetStatusSignalToNoise(scanEvent->intValue());
00192 break;
00193 case ScannerEvent::SetStatusSignalStrength:
00194 popupProgress->SetStatusSignalStrength(scanEvent->intValue());
00195 break;
00196 default:
00197 break;
00198 }
00199 }
00200
00201 void ScanWizardScanner::scanComplete()
00202 {
00203 ScannerEvent::TYPE se = ScannerEvent::ScanComplete;
00204 QApplication::postEvent(this, new ScannerEvent(se));
00205 }
00206
00207 void ScanWizardScanner::transportScanComplete()
00208 {
00209 scanner->ScanServicesSourceID(nVideoSource);
00210 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
00211 e->intValue(TRANSPORT_PCT);
00212 QApplication::postEvent(this, e);
00213 }
00214
00215 void ScanWizardScanner::serviceScanPctComplete(int pct)
00216 {
00217 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
00218 int tmp = TRANSPORT_PCT + ((100 - TRANSPORT_PCT) * pct)/100;
00219 e->intValue(tmp);
00220 QApplication::postEvent(this, e);
00221 }
00222
00223 void ScanWizardScanner::updateText(const QString &str)
00224 {
00225 if (str.isEmpty())
00226 return;
00227 ScannerEvent* e = new ScannerEvent(ScannerEvent::AppendTextToLog);
00228 e->strValue(str);
00229 QApplication::postEvent(this, e);
00230 }
00231
00232 void ScanWizardScanner::updateStatusText(const QString &str)
00233 {
00234 QString msg = tr("Scanning");
00235 if (!str.isEmpty())
00236 msg = QString("%1 %2").arg(msg).arg(str);
00237
00238 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusText);
00239 e->strValue(msg);
00240 QApplication::postEvent(this, e);
00241 }
00242
00243 void ScanWizardScanner::dvbLock(const SignalMonitorValue &val)
00244 {
00245 dvbLock(val.GetValue());
00246 }
00247
00248 void ScanWizardScanner::dvbSNR(const SignalMonitorValue &val)
00249 {
00250 dvbSNR(val.GetNormalizedValue(0, 65535));
00251 }
00252
00253 void ScanWizardScanner::dvbSignalStrength(const SignalMonitorValue &val)
00254 {
00255 dvbSignalStrength(val.GetNormalizedValue(0, 65535));
00256 }
00257
00258 void ScanWizardScanner::dvbLock(int locked)
00259 {
00260 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalLock);
00261 e->intValue(locked);
00262 QApplication::postEvent(this, e);
00263 }
00264
00265 void ScanWizardScanner::dvbSNR(int i)
00266 {
00267 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalToNoise);
00268 e->intValue(i);
00269 QApplication::postEvent(this, e);
00270 }
00271
00272 void ScanWizardScanner::dvbSignalStrength(int i)
00273 {
00274 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalStrength);
00275 e->intValue(i);
00276 QApplication::postEvent(this, e);
00277 }
00278
00279
00280
00281 void ScanWizardScanner::Scan(
00282 int scantype,
00283 uint cardid,
00284 const QString &inputname,
00285 uint sourceid,
00286 bool do_delete_channels,
00287 bool do_rename_channels,
00288 bool do_ignore_signal_timeout,
00289
00290 uint mplexid ,
00291 const QMap<QString,QString> &startChan ,
00292 const QString &freq_std ,
00293 const QString &mod ,
00294 const QString &tbl ,
00295 const QString &atsc_format )
00296 {
00297 nVideoSource = sourceid;
00298 PreScanCommon(scantype, cardid, inputname,
00299 sourceid, do_ignore_signal_timeout);
00300
00301 VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete()");
00302
00303 if (!scanner)
00304 {
00305 VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete(): "
00306 "scanner does not exist...");
00307 return;
00308 }
00309
00310 scanner->StartScanner();
00311 updateStatusText("");
00312
00313 bool ok = false;
00314
00315 if (do_delete_channels && (ScanTypeSetting::TransportScan == scantype))
00316 {
00317 MSqlQuery query(MSqlQuery::InitCon());
00318 query.prepare("DELETE FROM channel "
00319 "WHERE sourceid = :SOURCEID AND "
00320 " mplexid = :MPLEXID");
00321 query.bindValue(":SOURCEID", sourceid);
00322 query.bindValue(":MPLEXID", mplexid);
00323 query.exec();
00324 }
00325 else if (do_delete_channels)
00326 {
00327 MSqlQuery query(MSqlQuery::InitCon());
00328 query.prepare("DELETE FROM channel "
00329 "WHERE sourceid = :SOURCEID");
00330 query.bindValue(":SOURCEID", sourceid);
00331 query.exec();
00332
00333 if (ScanTypeSetting::TransportScan != scantype)
00334 {
00335 query.prepare("DELETE FROM dtv_multiplex "
00336 "WHERE sourceid = :SOURCEID");
00337 query.bindValue(":SOURCEID", sourceid);
00338 query.exec();
00339 }
00340 }
00341
00342 scanner->SetChannelFormat(atsc_format);
00343 scanner->SetRenameChannels(do_rename_channels);
00344
00345 if ((ScanTypeSetting::FullScan_ATSC == scantype) ||
00346 (ScanTypeSetting::FullScan_OFDM == scantype) ||
00347 (ScanTypeSetting::FullScan_Analog == scantype))
00348 {
00349 VERBOSE(VB_SIPARSER, LOC +
00350 "ScanTransports("<<freq_std<<", "<<mod<<", "<<tbl<<")");
00351
00352
00353
00354 if ((mod.left(3).lower() == "qam") &&
00355 (scanner->GetSignalTimeout() < 1000))
00356 {
00357 scanner->SetSignalTimeout(1000);
00358 }
00359
00360
00361 scanner->SetAnalog(ScanTypeSetting::FullScan_Analog == scantype);
00362
00363 ok = scanner->ScanTransports(sourceid, freq_std, mod, tbl);
00364 }
00365 else if ((ScanTypeSetting::NITAddScan_OFDM == scantype) ||
00366 (ScanTypeSetting::NITAddScan_QPSK == scantype) ||
00367 (ScanTypeSetting::NITAddScan_QAM == scantype))
00368 {
00369 VERBOSE(VB_SIPARSER, LOC + "ScanTransports()");
00370
00371 ok = scanner->ScanTransportsStartingOn(sourceid, startChan);
00372 }
00373 else if (ScanTypeSetting::FullTransportScan == scantype)
00374 {
00375 VERBOSE(VB_SIPARSER, LOC + "ScanServicesSourceID("<<sourceid<<")");
00376
00377 ok = scanner->ScanServicesSourceID(sourceid);
00378 if (ok)
00379 {
00380 serviceScanPctComplete(0);
00381 }
00382 else
00383 {
00384 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00385 tr("ScanWizard"),
00386 tr("Error tuning to transport"));
00387 Teardown();
00388 }
00389 }
00390 else if ((ScanTypeSetting::DVBUtilsImport == scantype) && channels.size())
00391 {
00392 ok = true;
00393
00394 VERBOSE(VB_SIPARSER, LOC + "ScanForChannels("<<sourceid<<")");
00395
00396 QString card_type = CardUtil::GetRawCardType(cardid);
00397 QString sub_type = card_type;
00398 if (card_type == "DVB")
00399 {
00400 QString device = CardUtil::GetVideoDevice(cardid);
00401
00402 ok = !device.isEmpty();
00403 if (ok)
00404 sub_type = CardUtil::ProbeDVBType(device.toUInt()).upper();
00405 }
00406
00407 if (ok)
00408 {
00409 ok = scanner->ScanForChannels(sourceid, freq_std,
00410 sub_type, channels);
00411 }
00412 if (ok)
00413 {
00414 serviceScanPctComplete(0);
00415 }
00416 else
00417 {
00418 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00419 tr("ScanWizard"),
00420 tr("Error tuning to transport"));
00421 Teardown();
00422 }
00423 }
00424 else if (ScanTypeSetting::TransportScan == scantype)
00425 {
00426 VERBOSE(VB_SIPARSER, LOC + "ScanTransport("<<mplexid<<")");
00427
00428 ok = scanner->ScanTransport(mplexid);
00429 }
00430
00431 if (!ok)
00432 {
00433 VERBOSE(VB_IMPORTANT, "Failed to handle tune complete.");
00434 }
00435 }
00436
00437 void ScanWizardScanner::ImportDVBUtils(uint sourceid, int cardtype,
00438 const QString &file)
00439 {
00440 channels.clear();
00441
00442 DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN;
00443 type = (CardUtil::OFDM == cardtype) ? DTVConfParser::OFDM : type;
00444 type = (CardUtil::QPSK == cardtype) ? DTVConfParser::QPSK : type;
00445 type = (CardUtil::QAM == cardtype) ? DTVConfParser::QAM : type;
00446 type = ((CardUtil::ATSC == cardtype)||(CardUtil::HDHOMERUN == cardtype)) ?
00447 DTVConfParser::ATSC : type;
00448
00449 if (type == DTVConfParser::UNKNOWN)
00450 return;
00451
00452 DTVConfParser parser(type, sourceid, file);
00453
00454 DTVConfParser::return_t ret = parser.Parse();
00455 if (DTVConfParser::OK != ret)
00456 {
00457 QString msg = (DTVConfParser::ERROR_PARSE == ret) ?
00458 tr("Failed to parse '%1'") : tr("Failed to open '%1'");
00459
00460 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00461 tr("ScanWizard"), msg.arg(file));
00462 }
00463 else
00464 {
00465 channels = parser.GetChannels();
00466 }
00467 }
00468
00469 void ScanWizardScanner::PreScanCommon(int scantype,
00470 uint cardid,
00471 const QString &inputname,
00472 uint sourceid,
00473 bool do_ignore_signal_timeout)
00474 {
00475 uint signal_timeout = 1000;
00476 uint channel_timeout = 40000;
00477 CardUtil::GetTimeouts(cardid, signal_timeout, channel_timeout);
00478
00479 QString device = CardUtil::GetVideoDevice(cardid);
00480 if (device.isEmpty())
00481 {
00482 VERBOSE(VB_IMPORTANT, "No Device");
00483 return;
00484 }
00485
00486 QString card_type = CardUtil::GetRawCardType(cardid);
00487
00488 if ("DVB" == card_type)
00489 {
00490 QString sub_type = CardUtil::ProbeDVBType(device.toUInt()).upper();
00491 bool need_nit = (("QAM" == sub_type) ||
00492 ("QPSK" == sub_type) ||
00493 ("OFDM" == sub_type));
00494
00495
00496 if ((ScanTypeSetting::TransportScan == scantype) ||
00497 (ScanTypeSetting::FullTransportScan == scantype))
00498 {
00499 signal_timeout = (do_ignore_signal_timeout) ?
00500 channel_timeout * 10 : signal_timeout;
00501 }
00502
00503
00504
00505 channel_timeout += (need_nit) ? 22 * 1000 : 0;
00506 }
00507
00508 #ifdef USING_DVB
00509 if ("DVB" == card_type)
00510 channel = new DVBChannel(device.toInt());
00511 #endif
00512
00513 #ifdef USING_V4L
00514 if (("V4L" == card_type) || ("MPEG" == card_type))
00515 channel = new Channel(NULL, device);
00516 #endif
00517
00518 #ifdef USING_HDHOMERUN
00519 if ("HDHOMERUN" == card_type)
00520 {
00521 uint tuner = CardUtil::GetHDHRTuner(cardid);
00522 channel = new HDHRChannel(NULL, device, tuner);
00523 }
00524 #endif // USING_HDHOMERUN
00525
00526 if (!channel)
00527 {
00528 VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel not created");
00529 return;
00530 }
00531
00532
00533 channel->SetCardID(cardid);
00534
00535
00536 if (!channel->Open())
00537 {
00538 VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel could not be opened");
00539 return;
00540 }
00541
00542 scanner = new SIScan(card_type, channel, sourceid, signal_timeout,
00543 channel_timeout, inputname);
00544
00545 scanner->SetForceUpdate(true);
00546
00547 bool ftao = CardUtil::IgnoreEncrypted(cardid, inputname);
00548 scanner->SetFTAOnly(ftao);
00549
00550 bool tvo = CardUtil::TVOnly(cardid, inputname);
00551 scanner->SetTVOnly(tvo);
00552
00553 connect(scanner, SIGNAL(ServiceScanComplete(void)),
00554 this, SLOT( scanComplete(void)));
00555 connect(scanner, SIGNAL(TransportScanComplete(void)),
00556 this, SLOT( transportScanComplete(void)));
00557 connect(scanner, SIGNAL(ServiceScanUpdateStatusText(const QString&)),
00558 this, SLOT( updateStatusText(const QString&)));
00559 connect(scanner, SIGNAL(ServiceScanUpdateText(const QString&)),
00560 this, SLOT( updateText(const QString&)));
00561 connect(scanner, SIGNAL(TransportScanUpdateText(const QString&)),
00562 this, SLOT( updateText(const QString&)));
00563 connect(scanner, SIGNAL(PctServiceScanComplete(int)),
00564 this, SLOT( serviceScanPctComplete(int)));
00565
00566
00567 SignalMonitor *monitor = scanner->GetSignalMonitor();
00568 if (monitor)
00569 {
00570 connect(monitor,
00571 SIGNAL(StatusSignalLock(const SignalMonitorValue&)),
00572 this,
00573 SLOT( dvbLock( const SignalMonitorValue&)));
00574 connect(monitor,
00575 SIGNAL(StatusSignalStrength(const SignalMonitorValue&)),
00576 this,
00577 SLOT( dvbSignalStrength( const SignalMonitorValue&)));
00578 }
00579
00580 DVBSignalMonitor *dvbm = NULL;
00581
00582 #ifdef USING_DVB
00583 dvbm = scanner->GetDVBSignalMonitor();
00584 if (dvbm)
00585 {
00586 connect(dvbm,
00587 SIGNAL(StatusSignalToNoise(const SignalMonitorValue&)),
00588 this,
00589 SLOT( dvbSNR(const SignalMonitorValue&)));
00590 }
00591 #endif // USING_DVB
00592
00593 MonitorProgress(monitor, monitor, dvbm);
00594 }
00595
00596 void ScanWizardScanner::ImportM3U(uint cardid, const QString &inputname,
00597 uint sourceid)
00598 {
00599 (void) cardid;
00600 (void) inputname;
00601 (void) sourceid;
00602
00603 #ifdef USING_IPTV
00604
00605 freeboxScanner = new IPTVChannelFetcher(cardid, inputname, sourceid);
00606
00607 connect(freeboxScanner, SIGNAL(ServiceScanComplete(void)),
00608 this, SLOT( scanComplete(void)));
00609 connect(freeboxScanner, SIGNAL(ServiceScanUpdateText(const QString&)),
00610 this, SLOT( updateText(const QString&)));
00611 connect(freeboxScanner, SIGNAL(ServiceScanPercentComplete(int)),
00612 this, SLOT( serviceScanPctComplete(int)));
00613
00614 MonitorProgress(false, false, false);
00615
00616 if (!freeboxScanner->Scan())
00617 {
00618 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00619 tr("ScanWizard"),
00620 tr("Error starting scan"));
00621 }
00622 #endif // USING_IPTV
00623 }
00624
00625 void *spawn_popup(void *tmp)
00626 {
00627 ((ScanWizardScanner*)(tmp))->RunPopup();
00628 return NULL;
00629 }
00630
00631 void ScanWizardScanner::RunPopup(void)
00632 {
00633 DialogCode ret = popupProgress->exec();
00634
00635 popupLock.lock();
00636 popupProgress->deleteLater();
00637 popupProgress = NULL;
00638 popupLock.unlock();
00639
00640 post_event(this, ScannerEvent::ScanShutdown, ret);
00641 }
00642
00643 void ScanWizardScanner::StopPopup(void)
00644 {
00645 if (popupProgress)
00646 {
00647 popupProgress->reject();
00648 popupLock.unlock();
00649 pthread_join(popup_thread, NULL);
00650 popupLock.lock();
00651 }
00652 }
00653
00654 void ScanWizardScanner::MonitorProgress(bool lock, bool strength, bool snr)
00655 {
00656 QMutexLocker locker(&popupLock);
00657 StopPopup();
00658 popupProgress = new ScanProgressPopup(lock, strength, snr);
00659 if (pthread_create(&popup_thread, NULL, spawn_popup, this) != 0)
00660 {
00661 popupProgress->deleteLater();
00662 popupProgress = NULL;
00663 }
00664 }