|
MythTV
0.26-pre
|
00001 /* -*- Mode: c++ -*- 00002 * vim: set expandtab tabstop=4 shiftwidth=4: 00003 * 00004 * Original Project 00005 * MythTV http://www.mythtv.org 00006 * 00007 * Copyright (c) 2004, 2005 John Pullan <john@pullan.org> 00008 * Copyright (c) 2005 - 2007 Daniel Kristjansson 00009 * 00010 * Description: 00011 * Collection of classes to provide channel scanning functionallity 00012 * 00013 * This program is free software; you can redistribute it and/or 00014 * modify it under the terms of the GNU General Public License 00015 * as published by the Free Software Foundation; either version 2 00016 * of the License, or (at your option) any later version. 00017 * 00018 * This program is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 * GNU General Public License for more details. 00022 * 00023 * You should have received a copy of the GNU General Public License 00024 * along with this program; if not, write to the Free Software 00025 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00026 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00027 * 00028 */ 00029 00030 // C includes 00031 #include <unistd.h> 00032 00033 // C++ includes 00034 #include <algorithm> 00035 using namespace std; 00036 00037 // Qt includes 00038 #include <QObject> 00039 00040 // MythTV includes - General 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 // MythTV includes - DTV 00052 #include "dtvsignalmonitor.h" 00053 #include "scanstreamdata.h" 00054 00055 // MythTV includes - ATSC 00056 #include "atsctables.h" 00057 00058 // MythTV includes - DVB 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 // MPEG 00100 pat_map_t pats; 00101 pmt_vec_t pmts; 00102 QMap<uint,uint> program_encryption_status; // pnum->enc_status 00103 00104 // ATSC 00105 const MasterGuideTable *mgt; 00106 cvct_vec_t cvcts; 00107 tvct_vec_t tvcts; 00108 00109 // DVB 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 : // Set in constructor 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 // Optional state 00156 scanDTVTunerType(DTVTunerType::kTunerTypeUnknown), 00157 // State 00158 scanning(false), 00159 threadExit(false), 00160 waitingForTables(false), 00161 // Transports List 00162 transportsScanned(0), 00163 currentTestingDecryption(false), 00164 // Misc 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 // Create a stream data for digital signal monitors 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 /* mplexid */, 00258 sourceID, 00259 chanid, 00260 callsign, 00261 "" /* service name */, 00262 freqid /* channum */, 00263 0 /* service id */, 00264 0 /* ATSC major channel */, 00265 0 /* ATSC minor channel */, 00266 false /* use on air guide */, 00267 false /* hidden */, 00268 false /* hidden in guide */, 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 // nothing to do here, XMLTV & DataDirect have better info 00278 } 00279 00280 scan_monitor->ScanAppendTextToLog(msg); 00281 00282 // tell UI we are done with these channels 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 // Add pmts to list, so we can do MPEG scan properly. 00353 ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData(); 00354 for (uint i = 0; i < pat->ProgramCount(); i++) 00355 { 00356 if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe. 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 // If this is Astra 28.2 add start listening for Freesat BAT and SDTo 00410 if (!setOtherTables && (sdt->OriginalNetworkID() == 2 || 00411 sdt->OriginalNetworkID() == 59)) 00412 { 00413 GetDTVSignalMonitor()->GetScanStreamData()-> 00414 SetFreesatAdditionalSI(true); 00415 setOtherTables = true; 00416 // The whole BAT & SDTo group comes round in 10s 00417 otherTableTimeout = 10000; 00418 // Delay processing the SDT until we've seen BATs and SDTos 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 // Set the version for the SDT so we see it again. 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 // Look for default authority 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 // If the default authority is given in the SDT this 00487 // overrides any definition in the BAT (or in the NIT) 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 // Look for default authority 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 // MPEG 00745 00746 // Grab PAT tables 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 // Grab PMT tables 00774 if ((!wait_until_complete || sd->HasCachedAllPMTs()) && currentInfo->pmts.empty()) 00775 currentInfo->pmts = sd->GetCachedPMTs(); 00776 00777 // ATSC 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 // DVB 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 // Check if transport tuning is complete 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 //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption(); 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 // append transports from the NIT to the scan list 00890 if (transport_tune_complete && extend_scan_list && 00891 !currentInfo->nits.empty()) 00892 { 00893 // append delivery system descriptos to scan list 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 // Start scanning next transport if we are done with this one.. 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 /* NTSC Modulation */ || 00993 vct->ServiceType(i) == 0x01 /* Analog TV */) 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 // HACK beg -- special exception for this network 01031 // (dbver == "1067") 01032 bool force_guide_present = (sdt->OriginalNetworkID() == 70); 01033 // HACK end -- special exception for this network 01034 01035 // Figure out best service name and callsign... 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 // Look for default authority 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 // channels.conf 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 // PATs 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 // PMTs 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 // Cable VCTs 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 // Terrestrial VCTs 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 // SDTs 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 // NIT 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 // NIT 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 // Get channel numbers from UK Frequency List Descriptors 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 // Get UK channel numbers 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 // Get QAM/SCTE/MPEG channel numbers 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 // Check for decryption success 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 // See if we have timed out 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 // If the rotor is still moving, reset the timer and keep waiting 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 // have the tables have timed out? 01507 if (timer.elapsed() > (int)channelTimeout) 01508 { 01509 // the channelTimeout alone is only valid if we have seen no tables.. 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 // ok the tables haven't timed out, but have we hit the signal timeout? 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 // Just is case we temporarily lose the signal after we've seen 01540 // tables... 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 // Add channel to scanned list and potentially check decryption 01567 if (do_post_insertion && !UpdateChannelInfo(false)) 01568 return; 01569 01570 // Stop signal monitor for previous transport 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; // Increment current 01583 01584 if (current != scanTransports.end()) 01585 { 01586 ScanTransport(current); 01587 01588 // Increment nextIt 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 // always wait for rotor to finish 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; // nothing to do 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 { // If we did not tune successfully, bail with message 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 // If we have a DTV Signal Monitor, perform table scanner reset 01686 if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData()) 01687 { 01688 GetDTVSignalMonitor()->GetScanStreamData()->Reset(); 01689 GetDTVSignalMonitor()->SetChannel(-1,-1); 01690 } 01691 01692 // Start signal monitor for this channel 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 }
1.7.6.1