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 #include <unistd.h>
00032
00033
00034 #include <algorithm>
00035 using namespace std;
00036
00037
00038 #include <QObject>
00039
00040
00041 #include "channelscan_sm.h"
00042 #include "frequencies.h"
00043 #include "mythdbcon.h"
00044 #include "channelutil.h"
00045 #include "cardutil.h"
00046 #include "sourceutil.h"
00047 #include "mthread.h"
00048 #include "mythdb.h"
00049 #include "mythlogging.h"
00050
00051
00052 #include "dtvsignalmonitor.h"
00053 #include "scanstreamdata.h"
00054
00055
00056 #include "atsctables.h"
00057
00058
00059 #include "dvbsignalmonitor.h"
00060 #include "dvbtables.h"
00061
00062 #include "dvbchannel.h"
00063 #include "hdhrchannel.h"
00064 #include "v4lchannel.h"
00065
00069 const uint ChannelScanSM::kDVBTableTimeout = 30 * 1000;
00071 const uint ChannelScanSM::kATSCTableTimeout = 10 * 1000;
00073 const uint ChannelScanSM::kMPEGTableTimeout = 15 * 1000;
00074
00075 QString ChannelScanSM::loc(const ChannelScanSM *siscan)
00076 {
00077 if (siscan && siscan->channel)
00078 return QString("ChannelScanSM(%1)").arg(siscan->channel->GetDevice());
00079 return "ChannelScanSM(u)";
00080 }
00081
00082 #define LOC (ChannelScanSM::loc(this) + ": ")
00083
00084 #define kDecryptionTimeout 4250
00085
00086 class ScannedChannelInfo
00087 {
00088 public:
00089 ScannedChannelInfo() : mgt(NULL) {}
00090
00091 bool IsEmpty() const
00092 {
00093 return pats.empty() && pmts.empty() &&
00094 program_encryption_status.isEmpty() &&
00095 !mgt && cvcts.empty() && tvcts.empty() &&
00096 nits.empty() && sdts.empty();
00097 }
00098
00099
00100 pat_map_t pats;
00101 pmt_vec_t pmts;
00102 QMap<uint,uint> program_encryption_status;
00103
00104
00105 const MasterGuideTable *mgt;
00106 cvct_vec_t cvcts;
00107 tvct_vec_t tvcts;
00108
00109
00110 nit_vec_t nits;
00111 sdt_map_t sdts;
00112 };
00113
00137 ChannelScanSM::ChannelScanSM(
00138 ScanMonitor *_scan_monitor,
00139 const QString &_cardtype, ChannelBase *_channel,
00140 int _sourceID, uint signal_timeout, uint channel_timeout,
00141 const QString &_inputname, bool test_decryption)
00142 :
00143 scan_monitor(_scan_monitor),
00144 channel(_channel),
00145 signalMonitor(SignalMonitor::Init(_cardtype, -1, _channel)),
00146 sourceID(_sourceID),
00147 signalTimeout(signal_timeout),
00148 channelTimeout(channel_timeout),
00149 otherTableTimeout(0),
00150 otherTableTime(0),
00151 setOtherTables(false),
00152 inputname(_inputname),
00153 m_test_decryption(test_decryption),
00154 extend_scan_list(false),
00155
00156 scanDTVTunerType(DTVTunerType::kTunerTypeUnknown),
00157
00158 scanning(false),
00159 threadExit(false),
00160 waitingForTables(false),
00161
00162 transportsScanned(0),
00163 currentTestingDecryption(false),
00164
00165 channelsFound(999),
00166 currentInfo(NULL),
00167 analogSignalHandler(new AnalogSignalHandler(this)),
00168 scannerThread(NULL)
00169 {
00170 inputname.detach();
00171
00172 current = scanTransports.end();
00173
00174
00175 DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
00176 if (dtvSigMon)
00177 {
00178 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Connecting up DTVSignalMonitor");
00179 ScanStreamData *data = new ScanStreamData();
00180
00181 dtvSigMon->SetStreamData(data);
00182 dtvSigMon->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT |
00183 SignalMonitor::kDTVSigMon_WaitForVCT |
00184 SignalMonitor::kDTVSigMon_WaitForNIT |
00185 SignalMonitor::kDTVSigMon_WaitForSDT);
00186
00187 #ifdef USING_DVB
00188 DVBChannel *dvbchannel = dynamic_cast<DVBChannel*>(channel);
00189 if (dvbchannel && dvbchannel->GetRotor())
00190 dtvSigMon->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);
00191 #endif
00192
00193 data->AddMPEGListener(this);
00194 data->AddATSCMainListener(this);
00195 data->AddDVBMainListener(this);
00196 data->AddDVBOtherListener(this);
00197 }
00198 }
00199
00200 ChannelScanSM::~ChannelScanSM(void)
00201 {
00202 StopScanner();
00203 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
00204
00205 ScanStreamData *sd = NULL;
00206 if (GetDTVSignalMonitor())
00207 {
00208 sd = GetDTVSignalMonitor()->GetScanStreamData();
00209 }
00210
00211 if (signalMonitor)
00212 {
00213 signalMonitor->RemoveListener(analogSignalHandler);
00214 delete signalMonitor;
00215 signalMonitor = NULL;
00216 }
00217
00218 delete sd;
00219
00220 if (analogSignalHandler)
00221 {
00222 delete analogSignalHandler;
00223 analogSignalHandler = NULL;
00224 }
00225
00226 teardown_frequency_tables();
00227 }
00228
00229 void ChannelScanSM::SetAnalog(bool is_analog)
00230 {
00231 signalMonitor->RemoveListener(analogSignalHandler);
00232
00233 if (is_analog)
00234 signalMonitor->AddListener(analogSignalHandler);
00235 }
00236
00237 void ChannelScanSM::HandleAllGood(void)
00238 {
00239 QMutexLocker locker(&lock);
00240
00241 QString cur_chan = (*current).FriendlyName;
00242 QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
00243 QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
00244
00245 bool ok = false;
00246
00247 QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
00248
00249 if (!ChannelUtil::FindChannel(sourceID, freqid))
00250 {
00251 int chanid = ChannelUtil::CreateChanID(sourceID, freqid);
00252
00253 QString callsign = QString("%1-%2")
00254 .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
00255
00256 ok = ChannelUtil::CreateChannel(
00257 0 ,
00258 sourceID,
00259 chanid,
00260 callsign,
00261 "" ,
00262 freqid ,
00263 0 ,
00264 0 ,
00265 0 ,
00266 false ,
00267 false ,
00268 false ,
00269 freqid);
00270
00271 msg = (ok) ?
00272 QObject::tr("Added Channel %1").arg(cur_chan) :
00273 QObject::tr("Failed to add channel %1").arg(cur_chan);
00274 }
00275 else
00276 {
00277
00278 }
00279
00280 scan_monitor->ScanAppendTextToLog(msg);
00281
00282
00283 if (scanning)
00284 {
00285 UpdateScanPercentCompleted();
00286 waitingForTables = false;
00287 nextIt = current.nextTransport();
00288 }
00289 }
00290
00302 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
00303 {
00304 if (scanning)
00305 return false;
00306
00307 scanTransports.clear();
00308 nextIt = scanTransports.end();
00309
00310 vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
00311
00312 if (multiplexes.empty())
00313 {
00314 LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
00315 QString("sourceid %1").arg(sourceid));
00316
00317 return false;
00318 }
00319
00320 for (uint i = 0; i < multiplexes.size(); i++)
00321 AddToList(multiplexes[i]);
00322
00323 extend_scan_list = follow_nit;
00324 waitingForTables = false;
00325 transportsScanned = 0;
00326 if (scanTransports.size())
00327 {
00328 nextIt = scanTransports.begin();
00329 scanning = true;
00330 }
00331 else
00332 {
00333 LOG(VB_CHANSCAN, LOG_ERR, LOC +
00334 "Unable to find add any transports for " +
00335 QString("sourceid %1").arg(sourceid));
00336
00337 return false;
00338 }
00339
00340
00341 return scanning;
00342 }
00343
00344 void ChannelScanSM::HandlePAT(const ProgramAssociationTable *pat)
00345 {
00346 QMutexLocker locker(&lock);
00347
00348 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00349 QString("Got a Program Association Table for %1")
00350 .arg((*current).FriendlyName) + "\n" + pat->toString());
00351
00352
00353 ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
00354 for (uint i = 0; i < pat->ProgramCount(); i++)
00355 {
00356 if (pat->ProgramPID(i))
00357 sd->AddListeningPID(pat->ProgramPID(i));
00358 }
00359 }
00360
00361 void ChannelScanSM::HandlePMT(uint, const ProgramMapTable *pmt)
00362 {
00363 QMutexLocker locker(&lock);
00364
00365 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1")
00366 .arg((*current).FriendlyName) + "\n" + pmt->toString());
00367
00368 if (!currentTestingDecryption && pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
00369 currentEncryptionStatus[pmt->ProgramNumber()] = kEncUnknown;
00370 }
00371
00372 void ChannelScanSM::HandleVCT(uint, const VirtualChannelTable *vct)
00373 {
00374 QMutexLocker locker(&lock);
00375
00376 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00377 QString("Got a Virtual Channel Table for %1")
00378 .arg((*current).FriendlyName) + "\n" + vct->toString());
00379
00380 for (uint i = 0; !currentTestingDecryption && i < vct->ChannelCount(); i++)
00381 {
00382 if (vct->IsAccessControlled(i))
00383 {
00384 currentEncryptionStatus[vct->ProgramNumber(i)] = kEncUnknown;
00385 }
00386 }
00387
00388 UpdateChannelInfo(true);
00389 }
00390
00391 void ChannelScanSM::HandleMGT(const MasterGuideTable *mgt)
00392 {
00393 QMutexLocker locker(&lock);
00394
00395 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
00396 .arg((*current).FriendlyName) + "\n" + mgt->toString());
00397
00398 UpdateChannelInfo(true);
00399 }
00400
00401 void ChannelScanSM::HandleSDT(uint tsid, const ServiceDescriptionTable *sdt)
00402 {
00403 QMutexLocker locker(&lock);
00404
00405 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00406 QString("Got a Service Description Table for %1")
00407 .arg((*current).FriendlyName) + "\n" + sdt->toString());
00408
00409
00410 if (!setOtherTables && (sdt->OriginalNetworkID() == 2 ||
00411 sdt->OriginalNetworkID() == 59))
00412 {
00413 GetDTVSignalMonitor()->GetScanStreamData()->
00414 SetFreesatAdditionalSI(true);
00415 setOtherTables = true;
00416
00417 otherTableTimeout = 10000;
00418
00419 otherTableTime = timer.elapsed() + otherTableTimeout;
00420
00421 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00422 QString("SDT has OriginalNetworkID %1, look for "
00423 "additional Freesat SI").arg(sdt->OriginalNetworkID()));
00424 }
00425
00426 if ((uint)timer.elapsed() < otherTableTime)
00427 {
00428
00429 GetDTVSignalMonitor()->GetDVBStreamData()->SetVersionSDT(sdt->TSID(), -1, 0);
00430 }
00431
00432 uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
00433 ts_scanned.insert(id);
00434
00435 for (uint i = 0; !currentTestingDecryption && i < sdt->ServiceCount(); i++)
00436 {
00437 if (sdt->IsEncrypted(i))
00438 {
00439 currentEncryptionStatus[sdt->ServiceID(i)] = kEncUnknown;
00440 }
00441 }
00442
00443 UpdateChannelInfo(true);
00444 }
00445
00446 void ChannelScanSM::HandleNIT(const NetworkInformationTable *nit)
00447 {
00448 QMutexLocker locker(&lock);
00449
00450 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00451 QString("Got a Network Information Table for %1")
00452 .arg((*current).FriendlyName) + "\n" + nit->toString());
00453
00454 UpdateChannelInfo(true);
00455 }
00456
00457 void ChannelScanSM::HandleBAT(const BouquetAssociationTable *bat)
00458 {
00459 QMutexLocker locker(&lock);
00460
00461 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Got a Bouquet Association Table\n" +
00462 bat->toString());
00463
00464 otherTableTime = timer.elapsed() + otherTableTimeout;
00465
00466 for (uint i = 0; i < bat->TransportStreamCount(); i++)
00467 {
00468 uint tsid = bat->TSID(i);
00469 uint netid = bat->OriginalNetworkID(i);
00470 desc_list_t parsed =
00471 MPEGDescriptor::Parse(bat->TransportDescriptors(i),
00472 bat->TransportDescriptorsLength(i));
00473
00474 const unsigned char *def_auth =
00475 MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
00476 const unsigned char *serv_list =
00477 MPEGDescriptor::Find(parsed, DescriptorID::service_list);
00478
00479 if (def_auth && serv_list)
00480 {
00481 DefaultAuthorityDescriptor authority(def_auth);
00482 ServiceListDescriptor services(serv_list);
00483
00484 for (uint j = 0; j < services.ServiceCount(); j++)
00485 {
00486
00487
00488 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00489 QString("found default authority(BAT) for service %1 %2 %3")
00490 .arg(netid).arg(tsid).arg(services.ServiceID(j)));
00491 uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
00492 services.ServiceID(j);
00493 if (! defAuthorities.contains(index))
00494 defAuthorities[index] = authority.DefaultAuthority();
00495 }
00496 }
00497 }
00498 }
00499
00500 void ChannelScanSM::HandleSDTo(uint tsid, const ServiceDescriptionTable *sdt)
00501 {
00502 QMutexLocker locker(&lock);
00503
00504 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00505 "Got a Service Description Table (other)\n" + sdt->toString());
00506
00507 otherTableTime = timer.elapsed() + otherTableTimeout;
00508
00509 uint netid = sdt->OriginalNetworkID();
00510
00511 for (uint i = 0; i < sdt->ServiceCount(); i++)
00512 {
00513 uint serviceId = sdt->ServiceID(i);
00514 desc_list_t parsed =
00515 MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),
00516 sdt->ServiceDescriptorsLength(i));
00517
00518 const unsigned char *def_auth =
00519 MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
00520 if (def_auth)
00521 {
00522 DefaultAuthorityDescriptor authority(def_auth);
00523 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00524 QString("found default authority(SDTo) for service %1 %2 %3")
00525 .arg(netid).arg(tsid).arg(serviceId));
00526 defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
00527 authority.DefaultAuthority();
00528 }
00529 }
00530 }
00531
00532 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
00533 {
00534 QMutexLocker locker(&lock);
00535
00536 currentEncryptionStatus[pnum] = encrypted ? kEncEncrypted : kEncDecrypted;
00537
00538 if (kEncDecrypted == currentEncryptionStatus[pnum])
00539 currentTestingDecryption = false;
00540
00541 UpdateChannelInfo(true);
00542 }
00543
00544 bool ChannelScanSM::TestNextProgramEncryption(void)
00545 {
00546 if (!currentInfo || currentInfo->pmts.empty())
00547 {
00548 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
00549 currentTestingDecryption = false;
00550 return false;
00551 }
00552
00553 do
00554 {
00555 uint pnum = 0;
00556 QMap<uint, uint>::const_iterator it = currentEncryptionStatus.begin();
00557 #if 0
00558 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
00559 .arg(currentEncryptionStatusChecked.size())
00560 .arg(currentEncryptionStatus.size()));
00561 #endif
00562 while (it != currentEncryptionStatus.end())
00563 {
00564 if (!currentEncryptionStatusChecked[it.key()])
00565 {
00566 pnum = it.key();
00567 break;
00568 }
00569 ++it;
00570 }
00571
00572 if (!pnum)
00573 break;
00574
00575 currentEncryptionStatusChecked[pnum] = true;
00576
00577 if (!m_test_decryption)
00578 {
00579 currentEncryptionStatus[pnum] = kEncEncrypted;
00580 continue;
00581 }
00582
00583 const ProgramMapTable *pmt = NULL;
00584 for (uint i = 0; !pmt && (i < currentInfo->pmts.size()); i++)
00585 {
00586 pmt = (currentInfo->pmts[i]->ProgramNumber() == pnum) ?
00587 currentInfo->pmts[i] : NULL;
00588 }
00589
00590 if (pmt)
00591 {
00592 QString cur_chan, cur_chan_tr;
00593 GetCurrentTransportInfo(cur_chan, cur_chan_tr);
00594
00595 QString msg_tr =
00596 QObject::tr("%1 -- Testing decryption of program %2")
00597 .arg(cur_chan_tr).arg(pnum);
00598 QString msg =
00599 QString("%1 -- Testing decryption of program %2")
00600 .arg(cur_chan).arg(pnum);
00601
00602 scan_monitor->ScanAppendTextToLog(msg_tr);
00603 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
00604
00605 #ifdef USING_DVB
00606 if (GetDVBChannel())
00607 GetDVBChannel()->SetPMT(pmt);
00608 #endif // USING_DVB
00609
00610 GetDTVSignalMonitor()->GetStreamData()->TestDecryption(pmt);
00611
00612 currentTestingDecryption = true;
00613 timer.start();
00614 return true;
00615 }
00616
00617 LOG(VB_GENERAL, LOG_INFO, LOC +
00618 QString("Can't monitor decryption of program %1 -- no pmt")
00619 .arg(pnum));
00620
00621 } while (true);
00622
00623 currentTestingDecryption = false;
00624 return false;
00625 }
00626
00627 DTVTunerType ChannelScanSM::GuessDTVTunerType(DTVTunerType type) const
00628 {
00629 if (scanDTVTunerType != (int)DTVTunerType::kTunerTypeUnknown)
00630 type = scanDTVTunerType;
00631
00632 const DTVChannel *chan = GetDTVChannel();
00633
00634 if (!chan)
00635 return type;
00636
00637 vector<DTVTunerType> tts = chan->GetTunerTypes();
00638
00639 for (uint i = 0; i < tts.size(); ++i)
00640 {
00641 if (tts[i] == type)
00642 return type;
00643 }
00644
00645 if (!tts.empty())
00646 return tts[0];
00647
00648 return type;
00649 }
00650
00651 void ChannelScanSM::UpdateScanTransports(const NetworkInformationTable *nit)
00652 {
00653 for (uint i = 0; i < nit->TransportStreamCount(); ++i)
00654 {
00655 uint32_t tsid = nit->TSID(i);
00656 uint32_t netid = nit->OriginalNetworkID(i);
00657 uint32_t id = netid << 16 | tsid;
00658
00659 if (ts_scanned.contains(id) || extend_transports.contains(id))
00660 continue;
00661
00662 const desc_list_t& list =
00663 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
00664 nit->TransportDescriptorsLength(i));
00665
00666 for (uint j = 0; j < list.size(); ++j)
00667 {
00668 int mplexid = -1;
00669 uint64_t frequency = 0;
00670 const MPEGDescriptor desc(list[j]);
00671 uint tag = desc.DescriptorTag();
00672 DTVTunerType tt = DTVTunerType::kTunerTypeUnknown;
00673
00674 switch (tag)
00675 {
00676 case DescriptorID::terrestrial_delivery_system:
00677 {
00678 const TerrestrialDeliverySystemDescriptor cd(desc);
00679 frequency = cd.FrequencyHz();
00680 tt = DTVTunerType::kTunerTypeDVBT;
00681 break;
00682 }
00683 case DescriptorID::satellite_delivery_system:
00684 {
00685 const SatelliteDeliverySystemDescriptor cd(desc);
00686 frequency = cd.FrequencyHz()/1000;
00687 tt = DTVTunerType::kTunerTypeDVBS1;
00688 break;
00689 }
00690 case DescriptorID::cable_delivery_system:
00691 {
00692 const CableDeliverySystemDescriptor cd(desc);
00693 frequency = cd.FrequencyHz();
00694 tt = DTVTunerType::kTunerTypeDVBC;
00695 break;
00696 }
00697 default:
00698 LOG(VB_CHANSCAN, LOG_ERR, LOC +
00699 "unknown delivery system descriptor");
00700 continue;
00701 }
00702
00703 mplexid = ChannelUtil::GetMplexID(sourceID, frequency, tsid, netid);
00704 mplexid = max(0, mplexid);
00705
00706 tt = GuessDTVTunerType(tt);
00707
00708 DTVMultiplex tuning;
00709 if (mplexid)
00710 {
00711 if (!tuning.FillFromDB(tt, mplexid))
00712 continue;
00713 }
00714 else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
00715 {
00716 continue;
00717 }
00718
00719 extend_transports[id] = tuning;
00720 break;
00721 }
00722 }
00723 }
00724
00725 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
00726 {
00727 if (current == scanTransports.end())
00728 return true;
00729
00730 if (wait_until_complete && currentTestingDecryption)
00731 return false;
00732
00733 DTVSignalMonitor *dtv_sm = GetDTVSignalMonitor();
00734 if (!dtv_sm)
00735 return false;
00736
00737 const ScanStreamData *sd = dtv_sm->GetScanStreamData();
00738
00739 if (!currentInfo)
00740 currentInfo = new ScannedChannelInfo();
00741
00742 bool transport_tune_complete = true;
00743
00744
00745
00746
00747 pat_vec_t pattmp = sd->GetCachedPATs();
00748 QMap<uint,bool> tsid_checked;
00749 for (uint i = 0; i < pattmp.size(); i++)
00750 {
00751 uint tsid = pattmp[i]->TransportStreamID();
00752 if (tsid_checked[tsid])
00753 continue;
00754 tsid_checked[tsid] = true;
00755 if (currentInfo->pats.contains(tsid))
00756 continue;
00757
00758 if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
00759 {
00760 currentInfo->pats[tsid] = sd->GetCachedPATs(tsid);
00761 if (!currentInfo->pmts.empty())
00762 {
00763 sd->ReturnCachedPMTTables(currentInfo->pmts);
00764 currentInfo->pmts.clear();
00765 }
00766 }
00767 else
00768 transport_tune_complete = false;
00769 }
00770 transport_tune_complete &= !pattmp.empty();
00771 sd->ReturnCachedPATTables(pattmp);
00772
00773
00774 if ((!wait_until_complete || sd->HasCachedAllPMTs()) && currentInfo->pmts.empty())
00775 currentInfo->pmts = sd->GetCachedPMTs();
00776
00777
00778 if (!currentInfo->mgt && sd->HasCachedMGT())
00779 currentInfo->mgt = sd->GetCachedMGT();
00780
00781 if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
00782 currentInfo->cvcts.empty())
00783 {
00784 currentInfo->cvcts = sd->GetCachedCVCTs();
00785 }
00786
00787 if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
00788 currentInfo->tvcts.empty())
00789 {
00790 currentInfo->tvcts = sd->GetCachedTVCTs();
00791 }
00792
00793
00794 if ((!wait_until_complete || sd->HasCachedAllNIT()) && (currentInfo->nits.empty() ||
00795 timer.elapsed() > (int)otherTableTime))
00796 {
00797 currentInfo->nits = sd->GetCachedNIT();
00798 }
00799
00800 sdt_vec_t sdttmp = sd->GetCachedSDTs();
00801 tsid_checked.clear();
00802 for (uint i = 0; i < sdttmp.size(); i++)
00803 {
00804 uint tsid = sdttmp[i]->TSID();
00805 if (tsid_checked[tsid])
00806 continue;
00807 tsid_checked[tsid] = true;
00808 if (currentInfo->sdts.contains(tsid))
00809 continue;
00810
00811 if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
00812 currentInfo->sdts[tsid] = sd->GetCachedSDTs(tsid);
00813 }
00814 sd->ReturnCachedSDTTables(sdttmp);
00815
00816
00817 if (transport_tune_complete)
00818 {
00819 transport_tune_complete &= !currentInfo->pmts.empty();
00820 if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
00821 {
00822 transport_tune_complete &= sd->HasCachedMGT();
00823 transport_tune_complete &=
00824 (!currentInfo->tvcts.empty() || !currentInfo->cvcts.empty());
00825 }
00826 if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
00827 {
00828 transport_tune_complete &= !currentInfo->nits.empty();
00829 transport_tune_complete &= !currentInfo->sdts.empty();
00830 }
00831 if (transport_tune_complete)
00832 {
00833 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00834 QString("transport_tune_complete: "
00835 "\n\t\t\tcurrentInfo->pmts.empty(): %1"
00836 "\n\t\t\tsd->HasCachedAnyNIT(): %2"
00837 "\n\t\t\tsd->HasCachedAnySDTs(): %3"
00838 "\n\t\t\tcurrentInfo->nits.empty(): %4"
00839 "\n\t\t\tcurrentInfo->sdts.empty(): %5")
00840 .arg(currentInfo->pmts.empty())
00841 .arg(sd->HasCachedAnyNIT())
00842 .arg(sd->HasCachedAnySDTs())
00843 .arg(currentInfo->nits.empty())
00844 .arg(currentInfo->sdts.empty()));
00845 }
00846 }
00847 transport_tune_complete |= !wait_until_complete;
00848 if (transport_tune_complete)
00849 {
00850 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00851 QString("transport_tune_complete: wait_until_complete %1")
00852 .arg(wait_until_complete));
00853 }
00854
00855 if (transport_tune_complete && currentEncryptionStatus.size())
00857 {
00858
00859
00860 if (TestNextProgramEncryption())
00861 return false;
00862
00863 QMap<uint, uint>::const_iterator it = currentEncryptionStatus.begin();
00864 for (; it != currentEncryptionStatus.end(); ++it)
00865 {
00866 currentInfo->program_encryption_status[it.key()] = *it;
00867
00868 QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
00869 QString msg_tr2 = QObject::tr("Unknown decryption status");
00870 if (kEncEncrypted == *it)
00871 msg_tr2 = QObject::tr("Encrypted");
00872 else if (kEncDecrypted == *it)
00873 msg_tr2 = QObject::tr("Decrypted");
00874 QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
00875
00876 QString msg = LOC + QString("Program %1").arg(it.key());
00877 if (kEncEncrypted == *it)
00878 msg = msg + " -- Encrypted";
00879 else if (kEncDecrypted == *it)
00880 msg = msg + " -- Decrypted";
00881 else if (kEncUnknown == *it)
00882 msg = msg + " -- Unknown decryption status";
00883
00884 scan_monitor->ScanAppendTextToLog(msg_tr);
00885 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
00886 }
00887 }
00888
00889
00890 if (transport_tune_complete && extend_scan_list &&
00891 !currentInfo->nits.empty())
00892 {
00893
00894 nit_vec_t::const_iterator it = currentInfo->nits.begin();
00895 while (it != currentInfo->nits.end())
00896 {
00897 UpdateScanTransports(*it);
00898 ++it;
00899 }
00900 }
00901
00902
00903 if (transport_tune_complete)
00904 {
00905 QString cchan, cchan_tr;
00906 uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
00907 channelsFound += cchan_cnt;
00908 QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
00909 QString chan = QString( "%1 -- Timed out").arg(cchan);
00910 QString msg_tr = "";
00911 QString msg = "";
00912
00913 if (currentInfo && !currentInfo->IsEmpty())
00914 {
00915 LOG(VB_CHANSCAN, LOG_INFO, LOC +
00916 QString("Adding %1, offset %2 to channelList.")
00917 .arg((*current).tuning.toString()).arg(current.offset()));
00918 channelList << ChannelListItem(current, currentInfo);
00919 currentInfo = NULL;
00920 }
00921 else
00922 {
00923 delete currentInfo;
00924 currentInfo = NULL;
00925 }
00926
00927 SignalMonitor *sm = GetSignalMonitor();
00928 if ((timer.elapsed() > (int)channelTimeout))
00929 {
00930 msg_tr = (cchan_cnt) ?
00931 QObject::tr("%1 possible channels").arg(cchan_cnt) :
00932 QObject::tr("no channels");
00933 msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
00934 msg = (cchan_cnt) ?
00935 QString("%1 possible channels").arg(cchan_cnt) :
00936 QString("no channels");
00937 msg = QString("%1, %2").arg(chan_tr).arg(msg);
00938 }
00939 else if ((current != scanTransports.end()) &&
00940 (timer.elapsed() > (int)(*current).timeoutTune) &&
00941 sm && !sm->HasSignalLock())
00942 {
00943 msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
00944 msg = QString("%1, no signal").arg(chan);
00945 }
00946 else
00947 {
00948 msg_tr = QObject::tr("%1 -- Found %2 probable channels")
00949 .arg(cchan_tr).arg(cchan_cnt);
00950
00951 msg = QString("%1 -- Found %2 probable channels")
00952 .arg(cchan).arg(cchan_cnt);
00953 }
00954
00955 scan_monitor->ScanAppendTextToLog(msg_tr);
00956 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
00957
00958 currentEncryptionStatus.clear();
00959 currentEncryptionStatusChecked.clear();
00960
00961 setOtherTables = false;
00962 otherTableTime = 0;
00963
00964 if (scanning)
00965 {
00966 transportsScanned++;
00967 UpdateScanPercentCompleted();
00968 waitingForTables = false;
00969 nextIt = current.nextTransport();
00970 }
00971 else
00972 {
00973 scan_monitor->ScanPercentComplete(100);
00974 scan_monitor->ScanComplete();
00975 }
00976
00977 return true;
00978 }
00979
00980 return false;
00981 }
00982
00983 #define PCM_INFO_INIT(SISTD) \
00984 ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
00985 info.db_mplexid = mplexid; info.source_id = sourceID; \
00986 info.service_id = pnum; info.freqid = freqidStr; \
00987 info.si_standard = SISTD;
00988
00989 static void update_info(ChannelInsertInfo &info,
00990 const VirtualChannelTable *vct, uint i)
00991 {
00992 if (vct->ModulationMode(i) == 0x01 ||
00993 vct->ServiceType(i) == 0x01 )
00994 {
00995 info.si_standard = "ntsc";
00996 info.format = "ntsc";
00997 }
00998
00999 info.callsign = vct->ShortChannelName(i);
01000
01001 info.service_name = vct->GetExtendedChannelName(i);
01002 if (info.service_name.isEmpty())
01003 info.service_name = vct->ShortChannelName(i);
01004
01005 info.chan_num = QString::null;
01006
01007 info.service_id = vct->ProgramNumber(i);
01008 info.atsc_major_channel = vct->MajorChannel(i);
01009 info.atsc_minor_channel = vct->MinorChannel(i);
01010
01011 info.use_on_air_guide = !vct->IsHidden(i) ||
01012 (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
01013
01014 info.hidden = vct->IsHidden(i);
01015 info.hidden_in_guide = vct->IsHiddenInGuide(i);
01016
01017 info.vct_tsid = vct->TransportStreamID();
01018 info.vct_chan_tsid = vct->ChannelTransportStreamID(i);
01019 info.is_encrypted |= vct->IsAccessControlled(i);
01020 info.is_data_service = vct->ServiceType(i) == 0x04;
01021 info.is_audio_service = vct->ServiceType(i) == 0x03;
01022
01023 info.in_vct = true;
01024 }
01025
01026 static void update_info(ChannelInsertInfo &info,
01027 const ServiceDescriptionTable *sdt, uint i,
01028 const QMap<uint64_t, QString> &defAuthorities)
01029 {
01030
01031
01032 bool force_guide_present = (sdt->OriginalNetworkID() == 70);
01033
01034
01035
01036 ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
01037 QString callsign = QString::null;
01038 QString service_name = QString::null;
01039 if (desc)
01040 {
01041 callsign = desc->ServiceShortName();
01042 if (callsign.trimmed().isEmpty())
01043 callsign = QString("%1-%2-%3")
01044 .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
01045 .arg(sdt->ServiceID(i));
01046
01047 service_name = desc->ServiceName();
01048 if (service_name.trimmed().isEmpty())
01049 service_name = QString::null;
01050 }
01051
01052 if (info.callsign.isEmpty())
01053 info.callsign = callsign;
01054 if (info.service_name.isEmpty())
01055 info.service_name = service_name;
01056
01057 info.use_on_air_guide =
01058 sdt->HasEITPresentFollowing(i) ||
01059 sdt->HasEITSchedule(i) ||
01060 force_guide_present;
01061
01062 info.hidden = false;
01063 info.hidden_in_guide = false;
01064
01065 info.is_data_service =
01066 (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
01067 info.is_audio_service = (desc && desc->IsDigitalAudio());
01068 delete desc;
01069
01070 info.service_id = sdt->ServiceID(i);
01071 info.sdt_tsid = sdt->TSID();
01072 info.orig_netid = sdt->OriginalNetworkID();
01073 info.in_sdt = true;
01074
01075 desc_list_t parsed =
01076 MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),
01077 sdt->ServiceDescriptorsLength(i));
01078
01079 const unsigned char *def_auth =
01080 MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
01081 if (def_auth)
01082 {
01083 DefaultAuthorityDescriptor authority(def_auth);
01084 LOG(VB_CHANSCAN, LOG_INFO, QString("ChannelScanSM: found default "
01085 "authority(SDT) for service %1 %2 %3")
01086 .arg(info.orig_netid).arg(info.sdt_tsid).arg(info.service_id));
01087 info.default_authority = authority.DefaultAuthority();
01088 }
01089 else
01090 {
01091 uint64_t index = (uint64_t)info.orig_netid << 32 |
01092 info.sdt_tsid << 16 | info.service_id;
01093 if (defAuthorities.contains(index))
01094 info.default_authority = defAuthorities[index];
01095 }
01096 }
01097
01098 uint ChannelScanSM::GetCurrentTransportInfo(
01099 QString &cur_chan, QString &cur_chan_tr) const
01100 {
01101 if (current.iter() == scanTransports.end())
01102 {
01103 cur_chan = cur_chan_tr = QString::null;
01104 return 0;
01105 }
01106
01107 uint max_chan_cnt = 0;
01108
01109 QMap<uint,ChannelInsertInfo> list = GetChannelList(current, currentInfo);
01110 {
01111 for (int i = 0; i < list.size(); i++)
01112 {
01113 max_chan_cnt +=
01114 (list[i].in_pat || list[i].in_pmt ||
01115 list[i].in_sdt || list[i].in_vct) ? 1 : 0;
01116 }
01117 }
01118
01119 QString offset_str_tr = current.offset() ?
01120 QObject::tr(" offset %2").arg(current.offset()) : "";
01121 cur_chan_tr = QString("%1%2")
01122 .arg((*current).FriendlyName).arg(offset_str_tr);
01123
01124 QString offset_str = current.offset() ?
01125 QString(" offset %2").arg(current.offset()) : "";
01126 cur_chan = QString("%1%2")
01127 .arg((*current).FriendlyName).arg(offset_str);
01128
01129 return max_chan_cnt;
01130 }
01131
01132 QMap<uint,ChannelInsertInfo>
01133 ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
01134 ScannedChannelInfo *scan_info) const
01135 {
01136 QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
01137
01138 uint mplexid = (*trans_info).mplexid;
01139 int freqid = (*trans_info).friendlyNum;
01140 QString freqidStr = (freqid) ? QString::number(freqid) : QString::null;
01141
01142
01143 const DTVChannelInfoList &echan = (*trans_info).expectedChannels;
01144 for (uint i = 0; i < echan.size(); i++)
01145 {
01146 uint pnum = echan[i].serviceid;
01147 PCM_INFO_INIT("mpeg");
01148 info.service_name = echan[i].name;
01149 info.in_channels_conf = true;
01150 }
01151
01152
01153 pat_map_t::const_iterator pat_list_it = scan_info->pats.begin();
01154 for (; pat_list_it != scan_info->pats.end(); ++pat_list_it)
01155 {
01156 pat_vec_t::const_iterator pat_it = (*pat_list_it).begin();
01157 for (; pat_it != (*pat_list_it).end(); ++pat_it)
01158 {
01159 bool could_be_opencable = false;
01160 for (uint i = 0; i < (*pat_it)->ProgramCount(); i++)
01161 {
01162 if (((*pat_it)->ProgramNumber(i) == 0) &&
01163 ((*pat_it)->ProgramPID(i) == 0x1ffc))
01164 {
01165 could_be_opencable = true;
01166 }
01167 }
01168
01169 for (uint i = 0; i < (*pat_it)->ProgramCount(); i++)
01170 {
01171 uint pnum = (*pat_it)->ProgramNumber(i);
01172 if (pnum)
01173 {
01174 PCM_INFO_INIT("mpeg");
01175 info.pat_tsid = (*pat_it)->TransportStreamID();
01176 info.could_be_opencable = could_be_opencable;
01177 info.in_pat = true;
01178 }
01179 }
01180 }
01181 }
01182
01183
01184 pmt_vec_t::const_iterator pmt_it = scan_info->pmts.begin();
01185 for (; pmt_it != scan_info->pmts.end(); ++pmt_it)
01186 {
01187 const ProgramMapTable *pmt = *pmt_it;
01188 uint pnum = pmt->ProgramNumber();
01189 PCM_INFO_INIT("mpeg");
01190 for (uint i = 0; i < pmt->StreamCount(); i++)
01191 {
01192 info.could_be_opencable |=
01193 (StreamID::OpenCableVideo == pmt->StreamType(i));
01194 }
01195
01196 desc_list_t descs = MPEGDescriptor::ParseOnlyInclude(
01197 pmt->ProgramInfo(), pmt->ProgramInfoLength(),
01198 DescriptorID::registration);
01199
01200 for (uint i = 0; i < descs.size(); i++)
01201 {
01202 RegistrationDescriptor reg(descs[i]);
01203 if (reg.FormatIdentifierString() == "CUEI" ||
01204 reg.FormatIdentifierString() == "SCTE")
01205 info.is_opencable = true;
01206 }
01207
01208 info.is_encrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
01209 info.in_pmt = true;
01210 }
01211
01212
01213 cvct_vec_t::const_iterator cvct_it = scan_info->cvcts.begin();
01214 for (; cvct_it != scan_info->cvcts.end(); ++cvct_it)
01215 {
01216 for (uint i = 0; i < (*cvct_it)->ChannelCount(); i++)
01217 {
01218 uint pnum = (*cvct_it)->ProgramNumber(i);
01219 PCM_INFO_INIT("atsc");
01220 update_info(info, *cvct_it, i);
01221 }
01222 }
01223
01224
01225 tvct_vec_t::const_iterator tvct_it = scan_info->tvcts.begin();
01226 for (; tvct_it != scan_info->tvcts.end(); ++tvct_it)
01227 {
01228 for (uint i = 0; i < (*tvct_it)->ChannelCount(); i++)
01229 {
01230 uint pnum = (*tvct_it)->ProgramNumber(i);
01231 PCM_INFO_INIT("atsc");
01232 update_info(info, *tvct_it, i);
01233 }
01234 }
01235
01236
01237 sdt_map_t::const_iterator sdt_list_it = scan_info->sdts.begin();
01238 for (; sdt_list_it != scan_info->sdts.end(); ++sdt_list_it)
01239 {
01240 sdt_vec_t::const_iterator sdt_it = (*sdt_list_it).begin();
01241 for (; sdt_it != (*sdt_list_it).end(); ++sdt_it)
01242 {
01243 for (uint i = 0; i < (*sdt_it)->ServiceCount(); i++)
01244 {
01245 uint pnum = (*sdt_it)->ServiceID(i);
01246 PCM_INFO_INIT("dvb");
01247 update_info(info, *sdt_it, i, defAuthorities);
01248 }
01249 }
01250 }
01251
01252
01253 QMap<qlonglong, uint> ukChanNums;
01254 QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
01255 for (dbchan_it = pnum_to_dbchan.begin();
01256 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
01257 {
01258 ChannelInsertInfo &info = *dbchan_it;
01259
01260
01261 nit_vec_t::const_iterator nits_it = scan_info->nits.begin();
01262 for (; nits_it != scan_info->nits.end(); ++nits_it)
01263 {
01264 for (uint i = 0; i < (*nits_it)->TransportStreamCount(); i++)
01265 {
01266 const NetworkInformationTable *nit = (*nits_it);
01267 if ((nit->TSID(i) == info.sdt_tsid) &&
01268 (nit->OriginalNetworkID(i) == info.orig_netid))
01269 {
01270 info.netid = nit->NetworkID();
01271 info.in_nit = true;
01272 }
01273 else
01274 {
01275 continue;
01276 }
01277
01278
01279 const desc_list_t &list =
01280 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
01281 nit->TransportDescriptorsLength(i));
01282
01283 const unsigned char *desc =
01284 MPEGDescriptor::Find(
01285 list, PrivateDescriptorID::dvb_uk_channel_list);
01286
01287 if (desc)
01288 {
01289 UKChannelListDescriptor uklist(desc);
01290 for (uint j = 0; j < uklist.ChannelCount(); j++)
01291 {
01292 ukChanNums[((qlonglong)info.orig_netid<<32) |
01293 uklist.ServiceID(j)] =
01294 uklist.ChannelNumber(j);
01295 }
01296 }
01297 }
01298 }
01299 }
01300
01301
01302 for (dbchan_it = pnum_to_dbchan.begin();
01303 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
01304 {
01305 ChannelInsertInfo &info = *dbchan_it;
01306
01307 if (!info.chan_num.isEmpty())
01308 continue;
01309
01310 QMap<qlonglong, uint>::const_iterator it = ukChanNums.find(
01311 ((qlonglong)info.orig_netid<<32) | info.service_id);
01312
01313 if (it != ukChanNums.end())
01314 info.chan_num = QString::number(*it);
01315 }
01316
01317
01318 for (dbchan_it = pnum_to_dbchan.begin();
01319 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
01320 {
01321 ChannelInsertInfo &info = *dbchan_it;
01322
01323 if (!info.chan_num.isEmpty())
01324 continue;
01325
01326 if ((info.si_standard == "mpeg") ||
01327 (info.si_standard == "scte") ||
01328 (info.si_standard == "opencable"))
01329 info.chan_num = QString("%1-%2")
01330 .arg(info.freqid)
01331 .arg(info.service_id);
01332 }
01333
01334
01335 for (dbchan_it = pnum_to_dbchan.begin();
01336 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
01337 {
01338 uint pnum = dbchan_it.key();
01339 ChannelInsertInfo &info = *dbchan_it;
01340 info.decryption_status = scan_info->program_encryption_status[pnum];
01341 }
01342
01343 return pnum_to_dbchan;
01344 }
01345
01346 ScanDTVTransportList ChannelScanSM::GetChannelList(void) const
01347 {
01348 ScanDTVTransportList list;
01349
01350 uint cardid = channel->GetCardID();
01351
01352 DTVTunerType tuner_type = GuessDTVTunerType(DTVTunerType::kTunerTypeATSC);
01353
01354 ChannelList::const_iterator it = channelList.begin();
01355 for (; it != channelList.end(); ++it)
01356 {
01357 QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
01358 GetChannelList(it->first, it->second);
01359
01360 ScanDTVTransport item((*it->first).tuning, tuner_type, cardid);
01361
01362 QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
01363 for (dbchan_it = pnum_to_dbchan.begin();
01364 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
01365 {
01366 item.channels.push_back(*dbchan_it);
01367 }
01368 if (item.channels.size())
01369 list.push_back(item);
01370 }
01371
01372 return list;
01373 }
01374
01375
01376 DTVSignalMonitor* ChannelScanSM::GetDTVSignalMonitor(void)
01377 {
01378 return dynamic_cast<DTVSignalMonitor*>(signalMonitor);
01379 }
01380
01381 DVBSignalMonitor* ChannelScanSM::GetDVBSignalMonitor(void)
01382 {
01383 #ifdef USING_DVB
01384 return dynamic_cast<DVBSignalMonitor*>(signalMonitor);
01385 #else
01386 return NULL;
01387 #endif
01388 }
01389
01390 DTVChannel *ChannelScanSM::GetDTVChannel(void)
01391 {
01392 return dynamic_cast<DTVChannel*>(channel);
01393 }
01394
01395 const DTVChannel *ChannelScanSM::GetDTVChannel(void) const
01396 {
01397 return dynamic_cast<const DTVChannel*>(channel);
01398 }
01399
01400 HDHRChannel *ChannelScanSM::GetHDHRChannel(void)
01401 {
01402 #ifdef USING_HDHOMERUN
01403 return dynamic_cast<HDHRChannel*>(channel);
01404 #else
01405 return NULL;
01406 #endif
01407 }
01408
01409 DVBChannel *ChannelScanSM::GetDVBChannel(void)
01410 {
01411 #ifdef USING_DVB
01412 return dynamic_cast<DVBChannel*>(channel);
01413 #else
01414 return NULL;
01415 #endif
01416 }
01417
01418 const DVBChannel *ChannelScanSM::GetDVBChannel(void) const
01419 {
01420 #ifdef USING_DVB
01421 return dynamic_cast<const DVBChannel*>(channel);
01422 #else
01423 return NULL;
01424 #endif
01425 }
01426
01427 V4LChannel *ChannelScanSM::GetV4LChannel(void)
01428 {
01429 #ifdef USING_V4L2
01430 return dynamic_cast<V4LChannel*>(channel);
01431 #else
01432 return NULL;
01433 #endif
01434 }
01435
01439 void ChannelScanSM::StartScanner(void)
01440 {
01441 while (scannerThread)
01442 {
01443 threadExit = true;
01444 if (scannerThread->wait(1000))
01445 {
01446 delete scannerThread;
01447 scannerThread = NULL;
01448 }
01449 }
01450 threadExit = false;
01451 scannerThread = new MThread("Scanner", this);
01452 scannerThread->start();
01453 }
01454
01458 void ChannelScanSM::run(void)
01459 {
01460 LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
01461
01462 while (!threadExit)
01463 {
01464 if (scanning)
01465 HandleActiveScan();
01466
01467 usleep(10 * 1000);
01468 }
01469
01470 LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
01471 }
01472
01473
01474 bool ChannelScanSM::HasTimedOut(void)
01475 {
01476 if (currentTestingDecryption &&
01477 (timer.elapsed() > (int)kDecryptionTimeout))
01478 {
01479 currentTestingDecryption = false;
01480 return true;
01481 }
01482
01483 if (!waitingForTables)
01484 return true;
01485
01486 #ifdef USING_DVB
01487
01488 DVBSignalMonitor *sigmon = GetDVBSignalMonitor();
01489 if (sigmon)
01490 {
01491 const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
01492 if (rotor)
01493 {
01494 bool was_moving, is_moving;
01495 sigmon->GetRotorStatus(was_moving, is_moving);
01496 if (was_moving && !is_moving)
01497 {
01498 timer.restart();
01499 return false;
01500 }
01501 }
01502 }
01503 #endif // USING_DVB
01504
01505
01506
01507 if (timer.elapsed() > (int)channelTimeout)
01508 {
01509
01510 const ScanStreamData *sd = NULL;
01511 if (GetDTVSignalMonitor())
01512 sd = GetDTVSignalMonitor()->GetScanStreamData();
01513
01514 if (!sd)
01515 return true;
01516
01517 if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
01518 return timer.elapsed() > (int) kDVBTableTimeout;
01519 if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
01520 return timer.elapsed() > (int) kATSCTableTimeout;
01521 if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
01522 return timer.elapsed() > (int) kMPEGTableTimeout;
01523
01524 return true;
01525 }
01526
01527
01528 SignalMonitor *sm = GetSignalMonitor();
01529 if ((timer.elapsed() > (int)(*current).timeoutTune) &&
01530 sm && !sm->HasSignalLock())
01531 {
01532 const ScanStreamData *sd = NULL;
01533 if (GetDTVSignalMonitor())
01534 sd = GetDTVSignalMonitor()->GetScanStreamData();
01535
01536 if (!sd)
01537 return true;
01538
01539
01540
01541 if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
01542 !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
01543 !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
01544 {
01545 return true;
01546 }
01547 }
01548
01549 return false;
01550 }
01551
01555 void ChannelScanSM::HandleActiveScan(void)
01556 {
01557 QMutexLocker locker(&lock);
01558
01559 bool do_post_insertion = waitingForTables;
01560
01561 if (!HasTimedOut())
01562 return;
01563
01564 if (0 == nextIt.offset() && nextIt != scanTransports.begin())
01565 {
01566
01567 if (do_post_insertion && !UpdateChannelInfo(false))
01568 return;
01569
01570
01571 locker.unlock();
01572 signalMonitor->Stop();
01573 locker.relock();
01574 }
01575
01576 if (0 == nextIt.offset() && nextIt == scanTransports.begin())
01577 {
01578 channelList.clear();
01579 channelsFound = 0;
01580 }
01581
01582 current = nextIt;
01583
01584 if (current != scanTransports.end())
01585 {
01586 ScanTransport(current);
01587
01588
01589 nextIt = current;
01590 ++nextIt;
01591 }
01592 else if (!extend_transports.isEmpty())
01593 {
01594 --current;
01595 QMap<uint32_t,DTVMultiplex>::iterator it = extend_transports.begin();
01596 while (it != extend_transports.end())
01597 {
01598 if (!ts_scanned.contains(it.key()))
01599 {
01600 QString name = QString("TransportID %1").arg(it.key() & 0xffff);
01601 TransportScanItem item(sourceID, name, *it, signalTimeout);
01602 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
01603 item.
01604 tuning.toString());
01605 scanTransports.push_back(item);
01606 ts_scanned.insert(it.key());
01607 }
01608 ++it;
01609 }
01610 extend_transports.clear();
01611 nextIt = current;
01612 ++nextIt;
01613 }
01614 else
01615 {
01616 scan_monitor->ScanComplete();
01617 scanning = false;
01618 current = nextIt = scanTransports.end();
01619 }
01620 }
01621
01622 bool ChannelScanSM::Tune(const transport_scan_items_it_t transport)
01623 {
01624 const TransportScanItem &item = *transport;
01625
01626 #ifdef USING_DVB
01627 if (GetDVBSignalMonitor())
01628 {
01629
01630 GetDVBSignalMonitor()->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);
01631 GetDVBSignalMonitor()->SetRotorTarget(1.0f);
01632 }
01633 #endif // USING_DVB
01634
01635 if (!GetDTVChannel())
01636 return false;
01637
01638 if (item.mplexid > 0 && transport.offset() == 0)
01639 return GetDTVChannel()->TuneMultiplex(item.mplexid, inputname);
01640
01641 const uint64_t freq = item.freq_offset(transport.offset());
01642 DTVMultiplex tuning = item.tuning;
01643 tuning.frequency = freq;
01644 return GetDTVChannel()->Tune(tuning, inputname);
01645 }
01646
01647 void ChannelScanSM::ScanTransport(const transport_scan_items_it_t transport)
01648 {
01649 QString offset_str = (transport.offset()) ?
01650 QObject::tr(" offset %2").arg(transport.offset()) : "";
01651 QString cur_chan = QString("%1%2")
01652 .arg((*current).FriendlyName).arg(offset_str);
01653 QString tune_msg_str =
01654 QObject::tr("Tuning to %1 mplexid(%2)")
01655 .arg(cur_chan).arg((*current).mplexid);
01656
01657 const TransportScanItem &item = *transport;
01658
01659 if (transport.offset() &&
01660 (item.freq_offset(transport.offset()) == item.freq_offset(0)))
01661 {
01662 waitingForTables = false;
01663 return;
01664 }
01665
01666 if (channelsFound)
01667 {
01668 QString progress = QObject::tr(": Found %n", "", channelsFound);
01669 scan_monitor->ScanUpdateStatusTitleText(progress);
01670 }
01671
01672 scan_monitor->ScanUpdateStatusText(cur_chan);
01673 LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
01674
01675 if (!Tune(transport))
01676 {
01677 UpdateScanPercentCompleted();
01678 LOG(VB_CHANSCAN, LOG_ERR, LOC +
01679 QString("Failed to tune %1 mplexid(%2) at offset %3")
01680 .arg(item.FriendlyName).arg(item.mplexid)
01681 .arg(transport.offset()));
01682 return;
01683 }
01684
01685
01686 if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
01687 {
01688 GetDTVSignalMonitor()->GetScanStreamData()->Reset();
01689 GetDTVSignalMonitor()->SetChannel(-1,-1);
01690 }
01691
01692
01693 signalMonitor->Start();
01694
01695 timer.start();
01696 waitingForTables = (item.tuning.sistandard != "analog");
01697 }
01698
01703 void ChannelScanSM::StopScanner(void)
01704 {
01705 LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
01706
01707 while (scannerThread)
01708 {
01709 threadExit = true;
01710 if (scannerThread->wait(1000))
01711 {
01712 delete scannerThread;
01713 scannerThread = NULL;
01714 }
01715 }
01716
01717 if (signalMonitor)
01718 signalMonitor->Stop();
01719 }
01720
01725 bool ChannelScanSM::ScanTransports(
01726 int SourceID,
01727 const QString &std,
01728 const QString &modulation,
01729 const QString &country,
01730 const QString &table_start,
01731 const QString &table_end)
01732 {
01733 QString name("");
01734 if (scanning)
01735 return false;
01736
01737 scanTransports.clear();
01738 nextIt = scanTransports.end();
01739
01740 freq_table_list_t tables =
01741 get_matching_freq_tables(std, modulation, country);
01742
01743 if (tables.size() == 0)
01744 {
01745 QString msg = QString("No freq table for (%1, %2, %3) found")
01746 .arg(std).arg(modulation).arg(country);
01747 scan_monitor->ScanAppendTextToLog(msg);
01748 }
01749 LOG(VB_CHANSCAN, LOG_INFO, LOC +
01750 QString("Looked up freq table (%1, %2, %3) w/%4 entries")
01751 .arg(std).arg(modulation).arg(country).arg(tables.size()));
01752
01753 QString start = table_start;
01754 QString end = table_end;
01755 freq_table_list_t::iterator it = tables.begin();
01756 for (; it != tables.end(); ++it)
01757 {
01758 const FrequencyTable &ft = **it;
01759 int name_num = ft.name_offset;
01760 QString strNameFormat = ft.name_format;
01761 uint freq = ft.frequencyStart;
01762 while (freq <= ft.frequencyEnd)
01763 {
01764 name = strNameFormat;
01765 if (strNameFormat.indexOf("%") >= 0)
01766 name = strNameFormat.arg(name_num);
01767
01768 if (start.isEmpty() || name == start)
01769 {
01770 start = QString::null;
01771
01772 TransportScanItem item(SourceID, std, name, name_num,
01773 freq, ft, signalTimeout);
01774 scanTransports.push_back(item);
01775
01776 LOG(VB_CHANSCAN, LOG_INFO, LOC + item.toString());
01777 }
01778
01779 name_num++;
01780 freq += ft.frequencyStep;
01781
01782 if (!end.isEmpty() && name == end)
01783 break;
01784 }
01785 if (!end.isEmpty() && name == end)
01786 break;
01787 }
01788
01789 while (!tables.empty())
01790 {
01791 delete tables.back();
01792 tables.pop_back();
01793 }
01794
01795 extend_scan_list = true;
01796 timer.start();
01797 waitingForTables = false;
01798
01799 nextIt = scanTransports.begin();
01800 transportsScanned = 0;
01801 scanning = true;
01802
01803 return true;
01804 }
01805
01806 bool ChannelScanSM::ScanForChannels(uint sourceid,
01807 const QString &std,
01808 const QString &cardtype,
01809 const DTVChannelList &channels)
01810 {
01811 scanTransports.clear();
01812 nextIt = scanTransports.end();
01813
01814 DTVTunerType tunertype;
01815 tunertype.Parse(cardtype);
01816
01817 DTVChannelList::const_iterator it = channels.begin();
01818 for (uint i = 0; it != channels.end(); ++it, i++)
01819 {
01820 DTVTransport tmp = *it;
01821 tmp.sistandard = std;
01822 TransportScanItem item(sourceid, QString::number(i),
01823 tunertype, tmp, signalTimeout);
01824
01825 scanTransports.push_back(item);
01826
01827 LOG(VB_CHANSCAN, LOG_INFO, LOC + item.toString());
01828 }
01829
01830 if (scanTransports.empty())
01831 {
01832 LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
01833 return false;
01834 }
01835
01836 timer.start();
01837 waitingForTables = false;
01838
01839 nextIt = scanTransports.begin();
01840 transportsScanned = 0;
01841 scanning = true;
01842
01843 return true;
01844 }
01845
01850 bool ChannelScanSM::ScanTransportsStartingOn(
01851 int sourceid, const QMap<QString,QString> &startChan)
01852 {
01853 QMap<QString,QString>::const_iterator it;
01854
01855 if (startChan.find("std") == startChan.end() ||
01856 startChan.find("type") == startChan.end())
01857 {
01858 return false;
01859 }
01860
01861 QString std = *startChan.find("std");
01862 QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
01863 bool ok = false;
01864
01865 if (scanning)
01866 return false;
01867
01868 scanTransports.clear();
01869 nextIt = scanTransports.end();
01870
01871 DTVMultiplex tuning;
01872
01873 DTVTunerType type;
01874 ok = type.Parse(startChan["type"]);
01875
01876 if (ok)
01877 {
01878 ok = tuning.ParseTuningParams(
01879 type,
01880 startChan["frequency"], startChan["inversion"],
01881 startChan["symbolrate"], startChan["fec"],
01882 startChan["polarity"],
01883 startChan["coderate_hp"], startChan["coderate_lp"],
01884 startChan["constellation"], startChan["trans_mode"],
01885 startChan["guard_interval"], startChan["hierarchy"],
01886 startChan["modulation"], startChan["bandwidth"],
01887 startChan["mod_sys"], startChan["rolloff"]);
01888 }
01889
01890 if (ok)
01891 {
01892 tuning.sistandard = si_std;
01893 TransportScanItem item(
01894 sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
01895 tuning, signalTimeout);
01896 scanTransports.push_back(item);
01897 }
01898
01899 if (!ok)
01900 return false;
01901
01902 extend_scan_list = true;
01903
01904 timer.start();
01905 waitingForTables = false;
01906
01907 nextIt = scanTransports.begin();
01908 transportsScanned = 0;
01909 scanning = true;
01910
01911 return true;
01912 }
01913
01914 bool ChannelScanSM::AddToList(uint mplexid)
01915 {
01916 MSqlQuery query(MSqlQuery::InitCon());
01917 query.prepare(
01918 "SELECT sourceid, sistandard, transportid, frequency, modulation "
01919 "FROM dtv_multiplex "
01920 "WHERE mplexid = :MPLEXID");
01921 query.bindValue(":MPLEXID", mplexid);
01922 if (!query.exec())
01923 {
01924 MythDB::DBError("ChannelScanSM::AddToList()", query);
01925 return false;
01926 }
01927
01928 if (!query.next())
01929 {
01930 LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
01931 QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
01932 return false;
01933 }
01934
01935 uint sourceid = query.value(0).toUInt();
01936 QString sistandard = query.value(1).toString();
01937 uint tsid = query.value(2).toUInt();
01938 DTVTunerType tt = DTVTunerType::kTunerTypeUnknown;
01939
01940 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
01941 QString("Multiplex #%1").arg(mplexid);
01942
01943 if (query.value(4).toString() == "8vsb")
01944 {
01945 QString chan = QString("%1 Hz").arg(query.value(3).toInt());
01946 struct CHANLIST *curList = chanlists[0].list;
01947 int totalChannels = chanlists[0].count;
01948 int findFrequency = (query.value(3).toInt() / 1000) - 1750;
01949 for (int x = 0 ; x < totalChannels ; x++)
01950 {
01951 if ((curList[x].freq <= findFrequency + 200) &&
01952 (curList[x].freq >= findFrequency - 200))
01953 {
01954 chan = QString("%1").arg(curList[x].name);
01955 }
01956 }
01957 fn = QObject::tr("ATSC Channel %1").arg(chan);
01958 tt = DTVTunerType::kTunerTypeATSC;
01959 }
01960
01961 tt = GuessDTVTunerType(tt);
01962
01963 TransportScanItem item(sourceid, sistandard, fn, mplexid, signalTimeout);
01964
01965 if (item.tuning.FillFromDB(tt, mplexid))
01966 {
01967 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
01968 scanTransports.push_back(item);
01969 return true;
01970 }
01971
01972 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
01973 return false;
01974 }
01975
01976 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
01977 {
01978 scanTransports.clear();
01979 nextIt = scanTransports.end();
01980
01981 AddToList(mplexid);
01982
01983 timer.start();
01984 waitingForTables = false;
01985
01986 extend_scan_list = follow_nit;
01987 transportsScanned = 0;
01988 if (scanTransports.size())
01989 {
01990 nextIt = scanTransports.begin();
01991 scanning = true;
01992 return true;
01993 }
01994
01995 return false;
01996 }
01997
01998 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
01999 {
02000 scanTransports.clear();
02001 nextIt = scanTransports.end();
02002
02003 signalTimeout = 30000;
02004 QString name;
02005 TransportScanItem item(sourceID, sistandard, name, 0, signalTimeout);
02006 scanTransports.push_back(item);
02007
02008 timer.start();
02009 waitingForTables = false;
02010 extend_scan_list = false;
02011 transportsScanned = 0;
02012 nextIt = scanTransports.begin();
02013 scanning = true;
02014 return true;
02015 }
02016
02020 bool ChannelScanSM::CheckImportedList(
02021 const DTVChannelInfoList &channels,
02022 uint mpeg_program_num,
02023 QString &service_name,
02024 QString &callsign,
02025 QString &common_status_info)
02026 {
02027 if (channels.empty())
02028 return true;
02029
02030 bool found = false;
02031 for (uint i = 0; i < channels.size(); i++)
02032 {
02033 LOG(VB_GENERAL, LOG_DEBUG, LOC +
02034 QString("comparing %1 %2 against %3 %4")
02035 .arg(channels[i].serviceid).arg(channels[i].name)
02036 .arg(mpeg_program_num).arg(common_status_info));
02037
02038 if (channels[i].serviceid == mpeg_program_num)
02039 {
02040 found = true;
02041 if (!channels[i].name.isEmpty())
02042 {
02043 service_name = channels[i].name; service_name.detach();
02044 callsign = channels[i].name; callsign.detach();
02045 }
02046 }
02047 }
02048
02049 if (found)
02050 {
02051 common_status_info += QString(" %1 %2")
02052 .arg(QObject::tr("as")).arg(service_name);
02053 }
02054 else
02055 {
02056 scan_monitor->ScanAppendTextToLog(
02057 QObject::tr("Skipping %1, not in imported channel map")
02058 .arg(common_status_info));
02059 }
02060
02061 return found;
02062 }