MythTV  master
channelscan_sm.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  * vim: set expandtab tabstop=4 shiftwidth=4:
3  *
4  * Original Project
5  * MythTV http://www.mythtv.org
6  *
7  * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>
8  * Copyright (c) 2005 - 2007 Daniel Kristjansson
9  *
10  * Description:
11  * Collection of classes to provide channel scanning functionallity
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27  *
28  */
29 
30 // C includes
31 #include <unistd.h>
32 
33 // C++ includes
34 #include <algorithm>
35 #include <utility>
36 
37 using namespace std;
38 
39 // Qt includes
40 #include <QMutexLocker>
41 #include <QObject>
42 
43 // MythTV includes - General
44 #include "channelscan_sm.h"
45 #include "frequencies.h"
46 #include "scanwizardconfig.h"
47 #include "mythdbcon.h"
48 #include "channelutil.h"
49 #include "cardutil.h"
50 #include "sourceutil.h"
51 #include "mthread.h"
52 #include "mythdb.h"
53 #include "mythlogging.h"
54 
55 // MythTV includes - DTV
56 #include "dtvsignalmonitor.h"
57 #include "scanstreamdata.h"
58 
59 // MythTV includes - ATSC
60 #include "atsctables.h"
61 
62 // MythTV includes - DVB
63 #include "dvbsignalmonitor.h"
64 #include "dvbtables.h"
65 
66 #include "dvbchannel.h"
67 #include "hdhrchannel.h"
68 #include "v4lchannel.h"
69 
73 const uint ChannelScanSM::kDVBTableTimeout = 30 * 1000;
75 const uint ChannelScanSM::kATSCTableTimeout = 10 * 1000;
77 const uint ChannelScanSM::kMPEGTableTimeout = 15 * 1000;
78 
79 // Freesat and Sky
80 static const uint kRegionUndefined = 0xFFFF; // Not regional
81 
82 QString ChannelScanSM::loc(const ChannelScanSM *siscan)
83 {
84  if (siscan && siscan->m_channel)
85  return QString("ChannelScanSM(%1)").arg(siscan->m_channel->GetDevice());
86  return "ChannelScanSM(u)";
87 }
88 
89 #define LOC (ChannelScanSM::loc(this) + ": ")
90 
91 #define kDecryptionTimeout 4250
92 
94 {
95  public:
96  ScannedChannelInfo() = default;
97 
98  bool IsEmpty() const
99  {
100  return m_pats.empty() && m_pmts.empty() &&
101  m_programEncryptionStatus.isEmpty() &&
102  !m_mgt && m_cvcts.empty() &&
103  m_tvcts.empty() && m_nits.empty() &&
104  m_sdts.empty() && m_bats.empty();
105  }
106 
107  // MPEG
110  QMap<uint,uint> m_programEncryptionStatus; // pnum->enc_status
111 
112  // ATSC
113  const MasterGuideTable *m_mgt {nullptr};
116 
117  // DVB
121 };
122 
147  const QString &_cardtype, ChannelBase *_channel,
148  int _sourceID, uint signal_timeout,
149  uint channel_timeout, QString _inputname,
150  bool test_decryption)
151  : // Set in constructor
152  m_scanMonitor(_scan_monitor),
153  m_channel(_channel),
154  m_signalMonitor(SignalMonitor::Init(_cardtype, m_channel->GetInputID(),
155  _channel, true)),
156  m_sourceID(_sourceID),
157  m_signalTimeout(signal_timeout),
158  m_channelTimeout(channel_timeout),
159  m_inputName(std::move(_inputname)),
160  m_testDecryption(test_decryption),
161  // Misc
162  m_analogSignalHandler(new AnalogSignalHandler(this))
163 {
164  m_current = m_scanTransports.end();
165 
166  // Create a stream data for digital signal monitors
167  DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
168  if (dtvSigMon)
169  {
170  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Connecting up DTVSignalMonitor");
171  auto *data = new ScanStreamData();
172 
173  MSqlQuery query(MSqlQuery::InitCon());
174  query.prepare(
175  "SELECT dvb_nit_id, bouquet_id, region_id "
176  "FROM videosource "
177  "WHERE videosource.sourceid = :SOURCEID");
178  query.bindValue(":SOURCEID", _sourceID);
179  if (!query.exec() || !query.isActive())
180  {
181  MythDB::DBError("ChannelScanSM", query);
182  }
183  else if (query.next())
184  {
185  int nitid = query.value(0).toInt();
186  data->SetRealNetworkID(nitid);
187  LOG(VB_CHANSCAN, LOG_INFO, LOC +
188  QString("Setting NIT-ID to %1").arg(nitid));
189 
190  m_bouquetId = query.value(1).toUInt();
191  m_regionId = query.value(2).toUInt();
192  }
193 
194  LOG(VB_CHANSCAN, LOG_INFO, LOC +
195  QString("Freesat/Sky bouquet_id:%1 region_id:%2")
196  .arg(m_bouquetId).arg(m_regionId));
197 
198  dtvSigMon->SetStreamData(data);
203 
204 #ifdef USING_DVB
205  auto *dvbchannel = dynamic_cast<DVBChannel*>(m_channel);
206  if (dvbchannel && dvbchannel->GetRotor())
208 #endif
209 
210  data->AddMPEGListener(this);
211  data->AddATSCMainListener(this);
212  data->AddDVBMainListener(this);
213  data->AddDVBOtherListener(this);
214  }
215 }
216 
218 {
219  StopScanner();
220  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
221 
222  ScanStreamData *sd = nullptr;
223  if (GetDTVSignalMonitor())
224  {
226  }
227 
228  if (m_signalMonitor)
229  {
231  delete m_signalMonitor;
232  m_signalMonitor = nullptr;
233  }
234 
235  delete sd;
236 
238  {
239  delete m_analogSignalHandler;
240  m_analogSignalHandler = nullptr;
241  }
242 
244 }
245 
246 void ChannelScanSM::SetAnalog(bool is_analog)
247 {
249 
250  if (is_analog)
252 }
253 
255 {
256  QMutexLocker locker(&m_lock);
257 
258  QString cur_chan = (*m_current).m_friendlyName;
259  QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
260  QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
261 
262  QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
263 
264  if (!ChannelUtil::FindChannel(m_sourceID, freqid))
265  {
266  int chanid = ChannelUtil::CreateChanID(m_sourceID, freqid);
267 
268  QString callsign = QString("%1-%2")
269  .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
270 
271  bool ok = ChannelUtil::CreateChannel(
272  0 /* mplexid */,
273  m_sourceID,
274  chanid,
275  callsign,
276  "" /* service name */,
277  freqid /* channum */,
278  0 /* service id */,
279  0 /* ATSC major channel */,
280  0 /* ATSC minor channel */,
281  false /* use on air guide */,
282  kChannelVisible /* visible */,
283  freqid);
284 
285  msg = (ok) ?
286  QObject::tr("Added Channel %1").arg(cur_chan) :
287  QObject::tr("Failed to add channel %1").arg(cur_chan);
288  }
289  else
290  {
291  // nothing to do here, XMLTV has better info
292  }
293 
295 
296  // tell UI we are done with these channels
297  if (m_scanning)
298  {
300  m_waitingForTables = false;
302  m_dvbt2Tried = true;
303  }
304 }
305 
317 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
318 {
319  if (m_scanning)
320  return false;
321 
322  m_scanTransports.clear();
323  m_nextIt = m_scanTransports.end();
324 
325  vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
326 
327  if (multiplexes.empty())
328  {
329  LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
330  QString("sourceid %1").arg(sourceid));
331 
332  return false;
333  }
334 
335  for (uint multiplex : multiplexes)
336  AddToList(multiplex);
337 
338  m_extendScanList = follow_nit;
339  m_waitingForTables = false;
341  if (!m_scanTransports.empty())
342  {
343  m_nextIt = m_scanTransports.begin();
344  m_scanning = true;
345  }
346  else
347  {
348  LOG(VB_CHANSCAN, LOG_ERR, LOC +
349  "Unable to find add any transports for " +
350  QString("sourceid %1").arg(sourceid));
351 
352  return false;
353  }
354 
355 
356  return m_scanning;
357 }
358 
359 void ChannelScanSM::LogLines(const QString& string)
360 {
361  QStringList lines = string.split('\n');
362  for (int i = 0; i < lines.size(); ++i)
363  LOG(VB_CHANSCAN, LOG_DEBUG, lines[i]);
364 }
365 
367 {
368  QMutexLocker locker(&m_lock);
369 
370  LOG(VB_CHANSCAN, LOG_INFO, LOC +
371  QString("Got a Program Association Table for %1")
372  .arg((*m_current).m_friendlyName));
373  LogLines(pat->toString());
374 
375  // Add pmts to list, so we can do MPEG scan properly.
377  for (uint i = 0; i < pat->ProgramCount(); ++i)
378  {
379  if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
380  sd->AddListeningPID(pat->ProgramPID(i));
381  }
382 }
383 
384 void ChannelScanSM::HandlePMT(uint /*program_num*/, const ProgramMapTable *pmt)
385 {
386  QMutexLocker locker(&m_lock);
387 
388  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1 program %2 (0x%3)")
389  .arg((*m_current).m_friendlyName).arg(pmt->ProgramNumber())
390  .arg(pmt->ProgramNumber(),4,16,QChar('0')));
391  LogLines(pmt->toString());
392 
394  pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
396 }
397 
399 {
400  QMutexLocker locker(&m_lock);
401 
402  LOG(VB_CHANSCAN, LOG_INFO, LOC +
403  QString("Got a Virtual Channel Table for %1")
404  .arg((*m_current).m_friendlyName));
405  LogLines(vct->toString());
406 
407  for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
408  {
409  if (vct->IsAccessControlled(i))
410  {
412  }
413  }
414 
415  UpdateChannelInfo(true);
416 }
417 
419 {
420  QMutexLocker locker(&m_lock);
421 
422  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
423  .arg((*m_current).m_friendlyName));
424  LogLines(mgt->toString());
425 
426  UpdateChannelInfo(true);
427 }
428 
437 {
438  QMutexLocker locker(&m_lock);
439 
440  LOG(VB_CHANSCAN, LOG_INFO, LOC +
441  QString("Got a Service Description Table for %1 section %2/%3")
442  .arg((*m_current).m_friendlyName)
443  .arg(sdt->Section()).arg(sdt->LastSection()));
444  LogLines(sdt->toString());
445 
446  // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
447  if (!m_setOtherTables && (
450  {
452  SetFreesatAdditionalSI(true);
453  m_setOtherTables = true;
454  // The whole BAT & SDTo group comes round in 10s
455  m_otherTableTimeout = 10000;
456  // Delay processing the SDT until we've seen BATs and SDTos
458 
459  LOG(VB_CHANSCAN, LOG_INFO, LOC +
460  QString("SDT has OriginalNetworkID %1, look for "
461  "additional Freesat SI").arg(sdt->OriginalNetworkID()));
462  }
463 
464  if (!m_timer.hasExpired(m_otherTableTime))
465  {
466  // Set the version for the SDT so we see it again.
468  SetVersionSDT(sdt->TSID(), -1, 0);
469  }
470 
471  uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
472  m_tsScanned.insert(id);
473 
474  for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
475  {
476  if (sdt->IsEncrypted(i))
477  {
479  }
480  }
481 
482  UpdateChannelInfo(true);
483 }
484 
486 {
487  QMutexLocker locker(&m_lock);
488 
489  LOG(VB_CHANSCAN, LOG_INFO, LOC +
490  QString("Got a Network Information Table id %1 for %2 section %3/%4")
491  .arg(nit->NetworkID()).arg((*m_current).m_friendlyName)
492  .arg(nit->Section()).arg(nit->LastSection()));
493  LogLines(nit->toString());
494 
495  UpdateChannelInfo(true);
496 }
497 
499 {
500  QMutexLocker locker(&m_lock);
501 
502  LOG(VB_CHANSCAN, LOG_INFO, LOC +
503  QString("Got a Bouquet Association Table id %1 for %2 section %3/%4")
504  .arg(bat->BouquetID()).arg((*m_current).m_friendlyName)
505  .arg(bat->Section()).arg(bat->LastSection()));
506  LogLines(bat->toString());
507 
509 
510  for (uint i = 0; i < bat->TransportStreamCount(); ++i)
511  {
512  uint tsid = bat->TSID(i);
513  uint netid = bat->OriginalNetworkID(i);
514  desc_list_t parsed =
517  // Look for default authority
518  const unsigned char *def_auth =
520  const unsigned char *serv_list =
522 
523  if (def_auth && serv_list)
524  {
525  DefaultAuthorityDescriptor authority(def_auth);
526  ServiceListDescriptor services(serv_list);
527  if (!authority.IsValid() || !services.IsValid())
528  continue;
529 
530  LOG(VB_CHANSCAN, LOG_INFO, LOC +
531  QString("Found default authority '%1' in BAT for services in %2 %3")
532  .arg(authority.DefaultAuthority())
533  .arg(netid).arg(tsid));
534 
535  for (uint j = 0; j < services.ServiceCount(); ++j)
536  {
537  // If the default authority is given in the SDT this
538  // overrides any definition in the BAT (or in the NIT)
539  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
540  QString("Found default authority '%1' in BAT for service %2 %3 %4")
541  .arg(authority.DefaultAuthority())
542  .arg(netid).arg(tsid).arg(services.ServiceID(j)));
543  uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
544  services.ServiceID(j);
545  if (! m_defAuthorities.contains(index))
546  m_defAuthorities[index] = authority.DefaultAuthority();
547  }
548  }
549  }
550  UpdateChannelInfo(true);
551 }
552 
554 {
555  QMutexLocker locker(&m_lock);
556 
557  LOG(VB_CHANSCAN, LOG_INFO, LOC +
558  QString("Got a Service Description Table (other) for Transport ID %1 section %2/%3")
559  .arg(tsid).arg(sdt->Section()).arg(sdt->LastSection()));
560  LogLines(sdt->toString());
561 
563 
564  uint netid = sdt->OriginalNetworkID();
565 
566  for (uint i = 0; i < sdt->ServiceCount(); ++i)
567  {
568  uint serviceId = sdt->ServiceID(i);
569  desc_list_t parsed =
571  sdt->ServiceDescriptorsLength(i));
572  // Look for default authority
573  const unsigned char *def_auth =
575  if (def_auth)
576  {
577  DefaultAuthorityDescriptor authority(def_auth);
578  if (!authority.IsValid())
579  continue;
580  LOG(VB_CHANSCAN, LOG_INFO, LOC +
581  QString("Found default authority '%1' in SDTo for service %2 %3 %4")
582  .arg(authority.DefaultAuthority())
583  .arg(netid).arg(tsid).arg(serviceId));
584  m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
585  authority.DefaultAuthority();
586  }
587  }
588 }
589 
590 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
591 {
592  QMutexLocker locker(&m_lock);
593 
595 
598 
599  UpdateChannelInfo(true);
600 }
601 
603 {
604  if (!m_currentInfo || m_currentInfo->m_pmts.empty())
605  {
606  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
608  return false;
609  }
610 
611  do
612  {
613  uint pnum = 0;
614  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
615 #if 0
616  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
617  .arg(currentEncryptionStatusChecked.size())
618  .arg(currentEncryptionStatus.size()));
619 #endif
620  while (it != m_currentEncryptionStatus.end())
621  {
622  if (!m_currentEncryptionStatusChecked[it.key()])
623  {
624  pnum = it.key();
625  break;
626  }
627  ++it;
628  }
629 
630  if (!pnum)
631  break;
632 
634 
635  if (!m_testDecryption)
636  {
638  continue;
639  }
640 
641  const ProgramMapTable *pmt = nullptr;
642  for (uint i = 0; !pmt && (i < m_currentInfo->m_pmts.size()); ++i)
643  {
644  pmt = (m_currentInfo->m_pmts[i]->ProgramNumber() == pnum) ?
645  m_currentInfo->m_pmts[i] : nullptr;
646  }
647 
648  if (pmt)
649  {
650  QString cur_chan;
651  QString cur_chan_tr;
652  GetCurrentTransportInfo(cur_chan, cur_chan_tr);
653 
654  QString msg_tr =
655  QObject::tr("%1 -- Testing decryption of program %2")
656  .arg(cur_chan_tr).arg(pnum);
657  QString msg =
658  QString("%1 -- Testing decryption of program %2")
659  .arg(cur_chan).arg(pnum);
660 
662  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
663 
664 #ifdef USING_DVB
665  if (GetDVBChannel())
666  GetDVBChannel()->SetPMT(pmt);
667 #endif // USING_DVB
668 
670 
672  m_timer.start();
673  return true;
674  }
675 
676  LOG(VB_GENERAL, LOG_INFO, LOC +
677  QString("Can't monitor decryption of program %1 -- no pmt")
678  .arg(pnum));
679 
680  } while (true);
681 
683  return false;
684 }
685 
687 {
690 
691  const DTVChannel *chan = GetDTVChannel();
692 
693  if (!chan)
694  return type;
695 
696  vector<DTVTunerType> tts = chan->GetTunerTypes();
697 
698  for (auto & tt : tts)
699  {
700  if (tt == type)
701  return type;
702  }
703 
704  if (!tts.empty())
705  return tts[0];
706 
707  return type;
708 }
709 
711 {
712  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
713  {
714  uint32_t tsid = nit->TSID(i);
715  uint32_t netid = nit->OriginalNetworkID(i);
716  uint32_t id = netid << 16 | tsid;
717 
718  if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
719  continue;
720 
721  const desc_list_t& list =
724 
725  for (size_t j = 0; j < list.size(); ++j)
726  {
727  int mplexid = -1;
728  uint64_t frequency = 0;
729  const MPEGDescriptor desc(list[j]);
730  uint tag = desc.DescriptorTag();
731  uint length = desc.DescriptorLength();
732  QString tagString = desc.DescriptorTagString();
733 
735 
736  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("NIT ts-loop j:%1 tag:%2 (0x%3) '%4' length:%5")
737  .arg(j).arg(tag).arg(tag,0,16).arg(tagString).arg(length));
738 
739  switch (tag)
740  {
742  {
744  frequency = cd.FrequencyHz();
746  break;
747  }
749  {
750  // Additional info in the T2 descriptor not yet used
751  continue;
752  }
754  {
755  const SatelliteDeliverySystemDescriptor cd(desc);
756  frequency = cd.FrequencykHz();
758  break;
759  }
761  {
762  // Additional info in the S2 descriptor not yet used
763  continue;
764  }
766  {
767  const CableDeliverySystemDescriptor cd(desc);
768  frequency = cd.FrequencyHz();
770  break;
771  }
772  default:
773  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
774  QString("Descriptor %1 (0x%2) '%3' ignored")
775  .arg(tag).arg(tag,0,16).arg(tagString));
776  continue;
777  }
778 
779  mplexid = ChannelUtil::GetMplexID(m_sourceID, frequency, tsid, netid);
780  mplexid = max(0, mplexid);
781 
782  tt = GuessDTVTunerType(tt);
783 
784  DTVMultiplex tuning;
785  if (mplexid)
786  {
787  if (!tuning.FillFromDB(tt, mplexid))
788  continue;
789  }
790  else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
791  {
792  continue;
793  }
794 
795  m_extendTransports[id] = tuning;
796  break;
797  }
798  }
799 }
800 
801 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
802 {
803  QMutexLocker locker(&m_mutex);
804 
805  if (m_current == m_scanTransports.end())
806  return true;
807 
808  if (wait_until_complete && !m_waitingForTables)
809  return true;
810 
811  if (wait_until_complete && m_currentTestingDecryption)
812  return false;
813 
815  if (!dtv_sm)
816  return false;
817 
818  const ScanStreamData *sd = dtv_sm->GetScanStreamData();
819 
820  if (!m_currentInfo)
822 
823  bool transport_tune_complete = true;
824 
825  // MPEG
826 
827  // Grab PAT tables
828  pat_vec_t pattmp = sd->GetCachedPATs();
829  QMap<uint,bool> tsid_checked;
830  for (auto & pat : pattmp)
831  {
832  uint tsid = pat->TransportStreamID();
833  if (tsid_checked[tsid])
834  continue;
835  tsid_checked[tsid] = true;
836  if (m_currentInfo->m_pats.contains(tsid))
837  continue;
838 
839  if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
840  {
841  m_currentInfo->m_pats[tsid] = sd->GetCachedPATs(tsid);
842  if (!m_currentInfo->m_pmts.empty())
843  {
845  m_currentInfo->m_pmts.clear();
846  }
847  }
848  else
849  transport_tune_complete = false;
850  }
851  transport_tune_complete &= !pattmp.empty();
852  sd->ReturnCachedPATTables(pattmp);
853 
854  // Grab PMT tables
855  if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
856  m_currentInfo->m_pmts.empty())
858 
859  // ATSC
860  if (!m_currentInfo->m_mgt && sd->HasCachedMGT())
862 
863  if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
864  m_currentInfo->m_cvcts.empty())
865  {
867  }
868 
869  if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
870  m_currentInfo->m_tvcts.empty())
871  {
873  }
874 
875  // DVB
876  if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
877  (m_currentInfo->m_nits.empty() ||
878  m_timer.hasExpired(m_otherTableTime)))
879  {
881  }
882 
883  sdt_vec_t sdttmp = sd->GetCachedSDTs();
884  tsid_checked.clear();
885  for (auto & sdt : sdttmp)
886  {
887  uint tsid = sdt->TSID();
888  if (tsid_checked[tsid])
889  continue;
890  tsid_checked[tsid] = true;
891  if (m_currentInfo->m_sdts.contains(tsid))
892  continue;
893 
894  if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
895  m_currentInfo->m_sdts[tsid] = sd->GetCachedSDTSections(tsid);
896  }
897  sd->ReturnCachedSDTTables(sdttmp);
898 
899  if ((!wait_until_complete || sd->HasCachedAllBATs()) &&
900  (m_currentInfo->m_bats.empty() ||
901  m_timer.hasExpired(m_otherTableTime)))
902  {
904  }
905 
906  // Check if transport tuning is complete
907  if (transport_tune_complete)
908  {
909  transport_tune_complete &= !m_currentInfo->m_pmts.empty();
910  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
911  {
912  transport_tune_complete &= sd->HasCachedMGT();
913  transport_tune_complete &=
914  (!m_currentInfo->m_tvcts.empty() || !m_currentInfo->m_cvcts.empty());
915  }
916  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
917  {
918  transport_tune_complete &= !m_currentInfo->m_nits.empty();
919  transport_tune_complete &= !m_currentInfo->m_sdts.empty();
920  }
921  if (sd->HasCachedAnyBATs())
922  {
923  transport_tune_complete &= !m_currentInfo->m_bats.empty();
924  }
925  if (transport_tune_complete)
926  {
927  uint tsid = dtv_sm->GetTransportID();
928  LOG(VB_CHANSCAN, LOG_INFO, LOC +
929  QString("transport_tune_complete: ") +
930  QString("\n\t\t\tsd->HasCachedAnyNIT(): %1").arg(sd->HasCachedAnyNIT()) +
931  QString("\n\t\t\tsd->HasCachedAnySDTs(): %1").arg(sd->HasCachedAnySDTs()) +
932  QString("\n\t\t\tsd->HasCachedAnyBATs(): %1").arg(sd->HasCachedAnyBATs()) +
933  QString("\n\t\t\tsd->HasCachedAllPMTs(): %1").arg(sd->HasCachedAllPMTs()) +
934  QString("\n\t\t\tsd->HasCachedAllNIT(): %1").arg(sd->HasCachedAllNIT()) +
935  QString("\n\t\t\tsd->HasCachedAllSDT(%1): %2").arg(tsid,5).arg(sd->HasCachedAllSDT(tsid)) +
936  QString("\n\t\t\tsd->HasCachedAllBATs(): %1").arg(sd->HasCachedAllBATs()) +
937  QString("\n\t\t\tcurrentInfo->m_pmts.empty(): %1").arg(m_currentInfo->m_pmts.empty()) +
938  QString("\n\t\t\tcurrentInfo->m_nits.empty(): %1").arg(m_currentInfo->m_nits.empty()) +
939  QString("\n\t\t\tcurrentInfo->m_sdts.empty(): %1").arg(m_currentInfo->m_sdts.empty()) +
940  QString("\n\t\t\tcurrentInfo->m_bats.empty(): %1").arg(m_currentInfo->m_bats.empty()));
941  }
942  }
943  if (!wait_until_complete)
944  transport_tune_complete = true;
945  if (transport_tune_complete)
946  {
947  LOG(VB_CHANSCAN, LOG_INFO, LOC +
948  QString("transport_tune_complete: wait_until_complete %1")
949  .arg(wait_until_complete));
950  }
951 
952  if (transport_tune_complete && !m_currentEncryptionStatus.empty())
954  {
955  //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
956 
958  return false;
959 
960  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
961  for (; it != m_currentEncryptionStatus.end(); ++it)
962  {
963  m_currentInfo->m_programEncryptionStatus[it.key()] = *it;
964 
965  if (m_testDecryption)
966  {
967  QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
968  QString msg_tr2 = QObject::tr("Unknown decryption status");
969  if (kEncEncrypted == *it)
970  msg_tr2 = QObject::tr("Encrypted");
971  else if (kEncDecrypted == *it)
972  msg_tr2 = QObject::tr("Decrypted");
973  QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
975  }
976 
977  QString msg = QString("Program %1").arg(it.key());
978  if (kEncEncrypted == *it)
979  msg = msg + " -- Encrypted";
980  else if (kEncDecrypted == *it)
981  msg = msg + " -- Decrypted";
982  else if (kEncUnknown == *it)
983  msg = msg + " -- Unknown decryption status";
984 
985  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
986  }
987  }
988 
989  // Append transports from the NIT to the scan list
990  if (transport_tune_complete && m_extendScanList &&
991  !m_currentInfo->m_nits.empty())
992  {
993  // Update transport with delivery system descriptors from the NIT
994  nit_vec_t::const_iterator it = m_currentInfo->m_nits.begin();
995  while (it != m_currentInfo->m_nits.end())
996  {
998  ++it;
999  }
1000  }
1001 
1002  // Start scanning next transport if we are done with this one..
1003  if (transport_tune_complete)
1004  {
1005  QString cchan;
1006  QString cchan_tr;
1007  uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
1008  m_channelsFound += cchan_cnt;
1009  QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
1010  QString chan = QString( "%1 -- Timed out").arg(cchan);
1011  QString msg_tr = "";
1012  QString msg = "";
1013 
1014  if (!m_currentInfo->IsEmpty())
1015  {
1016  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1017  QString("Adding %1, offset %2 to channelList.")
1018  .arg((*m_current).m_tuning.toString()).arg(m_current.offset()));
1019 
1020  TransportScanItem &item = *m_current;
1022 
1023  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
1024  QString("%1(%2) m_inputName: %3 ").arg(__FUNCTION__).arg(__LINE__).arg(m_inputName) +
1025  QString("m_mod_sys:%1 %2").arg(item.m_tuning.m_modSys).arg(item.m_tuning.m_modSys.toString()));
1026 
1028  {
1029  if (m_dvbt2Tried)
1031  else
1033  }
1034 
1036  m_currentInfo = nullptr;
1037  }
1038  else
1039  {
1040  delete m_currentInfo;
1041  m_currentInfo = nullptr;
1042  }
1043 
1045  if (HasTimedOut())
1046  {
1047  msg_tr = (cchan_cnt) ?
1048  QObject::tr("%1 possible channels").arg(cchan_cnt) :
1049  QObject::tr("no channels");
1050  msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
1051  msg = (cchan_cnt) ?
1052  QString("%1 possible channels").arg(cchan_cnt) :
1053  QString("no channels");
1054  msg = QString("%1, %2").arg(chan_tr).arg(msg);
1055  }
1056  else if ((m_current != m_scanTransports.end()) &&
1057  m_timer.hasExpired((*m_current).m_timeoutTune) &&
1058  sm && !sm->HasSignalLock())
1059  {
1060  msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1061  msg = QString("%1, no signal").arg(chan);
1062  }
1063  else
1064  {
1065  msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1066  .arg(cchan_tr).arg(cchan_cnt);
1067 
1068  msg = QString("%1 -- Found %2 probable channels")
1069  .arg(cchan).arg(cchan_cnt);
1070  }
1071 
1073  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1074 
1075  m_currentEncryptionStatus.clear();
1077 
1078  m_setOtherTables = false;
1079  m_otherTableTime = 0;
1080 
1081  if (m_scanning)
1082  {
1085  m_waitingForTables = false;
1087  m_dvbt2Tried = true;
1088  }
1089  else
1090  {
1093  }
1094 
1095  return true;
1096  }
1097 
1098  return false;
1099 }
1100 
1101 #define PCM_INFO_INIT(SISTD) \
1102  ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1103  info.m_dbMplexId = mplexid; info.m_sourceId = m_sourceID; \
1104  info.m_serviceId = pnum; info.m_freqId = freqidStr; \
1105  info.m_siStandard = SISTD;
1106 
1107 static void update_info(ChannelInsertInfo &info,
1108  const VirtualChannelTable *vct, uint i)
1109 {
1110  if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1111  vct->ServiceType(i) == 0x01 /* Analog TV */)
1112  {
1113  info.m_siStandard = "ntsc";
1114  info.m_format = "ntsc";
1115  }
1116 
1117  info.m_callSign = vct->ShortChannelName(i);
1118 
1119  info.m_serviceName = vct->GetExtendedChannelName(i);
1120  if (info.m_serviceName.isEmpty())
1121  info.m_serviceName = vct->ShortChannelName(i);
1122 
1123  info.m_chanNum.clear();
1124 
1125  info.m_serviceId = vct->ProgramNumber(i);
1126  info.m_atscMajorChannel = vct->MajorChannel(i);
1127  info.m_atscMinorChannel = vct->MinorChannel(i);
1128 
1129  info.m_useOnAirGuide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1130 
1131  info.m_hidden = vct->IsHidden(i);
1132  info.m_hiddenInGuide = vct->IsHiddenInGuide(i);
1133 
1134  info.m_vctTsId = vct->TransportStreamID();
1135  info.m_vctChanTsId = vct->ChannelTransportStreamID(i);
1136  info.m_isEncrypted |= vct->IsAccessControlled(i);
1137  info.m_isDataService = vct->ServiceType(i) == 0x04;
1138  info.m_isAudioService = vct->ServiceType(i) == 0x03;
1139 
1140  info.m_inVct = true;
1141 }
1142 
1143 static void update_info(ChannelInsertInfo &info,
1144  const ServiceDescriptionTable *sdt, uint i,
1145  const QMap<uint64_t, QString> &defAuthorities)
1146 {
1147  // HACK beg -- special exception for these networks
1148  // this enables useonairguide by default for all matching channels
1149  // (dbver == "1067")
1150  bool force_guide_present = (
1151  // Telenor (NO)
1153 #if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1154  // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1155  (sdt->OriginalNetworkID() == 222) ||
1156 #endif
1157  // ERT (GR) from the private temporary allocation, see #9592:comment:17
1158  (sdt->OriginalNetworkID() == 65330) ||
1159  // Digitenne (NL) see #13427
1161  );
1162  // HACK end -- special exception for these networks
1163 
1164  // Figure out best service name and callsign...
1165  ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
1166  QString callsign;
1167  QString service_name;
1168  if (desc)
1169  {
1170  callsign = desc->ServiceShortName();
1171  if (callsign.trimmed().isEmpty())
1172  {
1173  callsign = QString("%1-%2-%3")
1174  .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1175  .arg(sdt->ServiceID(i));
1176  }
1177 
1178  service_name = desc->ServiceName();
1179  if (service_name.trimmed().isEmpty())
1180  service_name.clear();
1181 
1182  info.m_serviceType = desc->ServiceType();
1183  info.m_isDataService =
1184  (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1185  info.m_isAudioService = (desc && desc->IsDigitalAudio());
1186  delete desc;
1187  }
1188  else
1189  {
1190  LOG(VB_CHANSCAN, LOG_INFO, "ChannelScanSM: " +
1191  QString("No ServiceDescriptor for onid %1 tid %2 sid %3")
1192  .arg(sdt->OriginalNetworkID()).arg(sdt->TSID()).arg(sdt->ServiceID(i)));
1193  }
1194 
1195  if (info.m_callSign.isEmpty())
1196  info.m_callSign = callsign;
1197  if (info.m_serviceName.isEmpty())
1198  info.m_serviceName = service_name;
1199 
1200  info.m_useOnAirGuide =
1201  sdt->HasEITPresentFollowing(i) ||
1202  sdt->HasEITSchedule(i) ||
1203  force_guide_present;
1204 
1205  info.m_hidden = false;
1206  info.m_hiddenInGuide = false;
1207  info.m_serviceId = sdt->ServiceID(i);
1208  info.m_sdtTsId = sdt->TSID();
1209  info.m_origNetId = sdt->OriginalNetworkID();
1210  info.m_inSdt = true;
1211 
1212  desc_list_t parsed =
1214  sdt->ServiceDescriptorsLength(i));
1215  // Look for default authority
1216  const unsigned char *def_auth =
1218  if (def_auth)
1219  {
1220  DefaultAuthorityDescriptor authority(def_auth);
1221  if (authority.IsValid())
1222  {
1223  LOG(VB_CHANSCAN, LOG_INFO,
1224  QString("ChannelScanSM: Found default authority '%1' in SDT for service %2 %3 %4")
1225  .arg(authority.DefaultAuthority())
1226  .arg(info.m_origNetId).arg(info.m_sdtTsId).arg(info.m_serviceId));
1227  info.m_defaultAuthority = authority.DefaultAuthority();
1228  return;
1229  }
1230  }
1231 
1232  // If no authority in the SDT then use the one found in the BAT or the SDTo
1233  uint64_t index = (uint64_t)info.m_origNetId << 32 |
1234  info.m_sdtTsId << 16 | info.m_serviceId;
1235  if (defAuthorities.contains(index))
1236  info.m_defaultAuthority = defAuthorities[index];
1237 }
1238 
1240  QString &cur_chan, QString &cur_chan_tr) const
1241 {
1242  if (m_current.iter() == m_scanTransports.end())
1243  {
1244  cur_chan.clear();
1245  cur_chan_tr.clear();
1246  return 0;
1247  }
1248 
1249  uint max_chan_cnt = 0;
1250 
1251  QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1252  {
1253  foreach (auto & info, list)
1254  {
1255  max_chan_cnt +=
1256  (info.m_inPat || info.m_inPmt ||
1257  info.m_inSdt || info.m_inVct) ? 1 : 0;
1258  }
1259  }
1260 
1261  QString offset_str_tr = m_current.offset() ?
1262  QObject::tr(" offset %2").arg(m_current.offset()) : "";
1263  cur_chan_tr = QString("%1%2")
1264  .arg((*m_current).m_friendlyName).arg(offset_str_tr);
1265 
1266  QString offset_str = m_current.offset() ?
1267  QString(" offset %2").arg(m_current.offset()) : "";
1268  cur_chan = QString("%1%2")
1269  .arg((*m_current).m_friendlyName).arg(offset_str);
1270 
1271  return max_chan_cnt;
1272 }
1273 
1274 QMap<uint,ChannelInsertInfo>
1276  ScannedChannelInfo *scan_info) const
1277 {
1278  QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1279 
1280  uint mplexid = (*trans_info).m_mplexid;
1281  int freqid = (*trans_info).m_friendlyNum;
1282  QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1283  QString iptv_channel = (*trans_info).m_iptvChannel;
1284 
1285  // channels.conf
1286  const DTVChannelInfoList &echan = (*trans_info).m_expectedChannels;
1287  for (const auto & chan : echan)
1288  {
1289  uint pnum = chan.m_serviceid;
1290  PCM_INFO_INIT("mpeg");
1291  info.m_serviceName = chan.m_name;
1292  info.m_inChannelsConf = true;
1293  }
1294 
1295  // PATs
1296  foreach (auto pat_list, scan_info->m_pats)
1297  {
1298  for (auto pat : pat_list)
1299  {
1300  bool could_be_opencable = false;
1301  for (uint i = 0; i < pat->ProgramCount(); ++i)
1302  {
1303  if ((pat->ProgramNumber(i) == 0) &&
1304  (pat->ProgramPID(i) == 0x1ffc))
1305  {
1306  could_be_opencable = true;
1307  }
1308  }
1309 
1310  for (uint i = 0; i < pat->ProgramCount(); ++i)
1311  {
1312  uint pnum = pat->ProgramNumber(i);
1313  if (pnum)
1314  {
1315  PCM_INFO_INIT("mpeg");
1316  info.m_patTsId = pat->TransportStreamID();
1317  info.m_couldBeOpencable = could_be_opencable;
1318  info.m_inPat = true;
1319  }
1320  }
1321  }
1322  }
1323 
1324  // PMTs
1325  foreach (auto pmt, scan_info->m_pmts)
1326  {
1327  uint pnum = pmt->ProgramNumber();
1328  PCM_INFO_INIT("mpeg");
1329  for (uint i = 0; i < pmt->StreamCount(); ++i)
1330  {
1331  info.m_couldBeOpencable |=
1332  (StreamID::OpenCableVideo == pmt->StreamType(i));
1333  }
1334 
1336  pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1338 
1339  for (auto & desc : descs)
1340  {
1341  RegistrationDescriptor reg(desc);
1342  if (!reg.IsValid())
1343  continue;
1344  if (reg.FormatIdentifierString() == "CUEI" ||
1345  reg.FormatIdentifierString() == "SCTE")
1346  info.m_couldBeOpencable = true;
1347  }
1348 
1349  info.m_isEncrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1350  info.m_inPmt = true;
1351  }
1352 
1353  // Cable VCTs
1354  for (auto cvct : scan_info->m_cvcts)
1355  {
1356  for (uint i = 0; i < cvct->ChannelCount(); ++i)
1357  {
1358  uint pnum = cvct->ProgramNumber(i);
1359  PCM_INFO_INIT("atsc");
1360  update_info(info, cvct, i);
1361  }
1362  }
1363 
1364  // Terrestrial VCTs
1365  for (auto tvct : scan_info->m_tvcts)
1366  {
1367  for (uint i = 0; i < tvct->ChannelCount(); ++i)
1368  {
1369  uint pnum = tvct->ProgramNumber(i);
1370  PCM_INFO_INIT("atsc");
1371  update_info(info, tvct, i);
1372  }
1373  }
1374 
1375  // SDTs
1376  foreach (auto sdt_list, scan_info->m_sdts)
1377  {
1378  for (auto sdt_it : sdt_list)
1379  {
1380  for (uint i = 0; i < sdt_it->ServiceCount(); ++i)
1381  {
1382  uint pnum = sdt_it->ServiceID(i);
1383  PCM_INFO_INIT("dvb");
1384  update_info(info, sdt_it, i, m_defAuthorities);
1385  }
1386  }
1387  }
1388 
1389  // NIT
1390  QMap<qlonglong, uint> ukChanNums;
1391  QMap<qlonglong, uint> scnChanNums;
1392  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1393  for (dbchan_it = pnum_to_dbchan.begin();
1394  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1395  {
1396  ChannelInsertInfo &info = *dbchan_it;
1397 
1398  // NIT
1399  for (auto item : scan_info->m_nits)
1400  {
1401  for (uint i = 0; i < item->TransportStreamCount(); ++i)
1402  {
1403  const NetworkInformationTable *nit = item;
1404  if ((nit->TSID(i) == info.m_sdtTsId) &&
1405  (nit->OriginalNetworkID(i) == info.m_origNetId))
1406  {
1407  info.m_netId = nit->NetworkID();
1408  info.m_inNit = true;
1409  }
1410  else
1411  {
1412  continue;
1413  }
1414 
1415  // Get channel numbers from UK Frequency List Descriptors
1416  const desc_list_t &list =
1418  nit->TransportDescriptorsLength(i));
1419 
1420  // Logical channel numbers
1421  {
1422  const unsigned char *desc =
1425 
1426  if (desc)
1427  {
1428  DVBLogicalChannelDescriptor uklist(desc);
1429  if (!uklist.IsValid())
1430  continue;
1431  for (uint j = 0; j < uklist.ChannelCount(); ++j)
1432  {
1433  ukChanNums[((qlonglong)info.m_origNetId<<32) |
1434  uklist.ServiceID(j)] =
1435  uklist.ChannelNumber(j);
1436  }
1437  }
1438  }
1439 
1440  // HD Simulcast logical channel numbers
1441  {
1442  const unsigned char *desc =
1445 
1446  if (desc)
1447  {
1448  DVBSimulcastChannelDescriptor scnlist(desc);
1449  if (!scnlist.IsValid())
1450  continue;
1451  for (uint j = 0; j < scnlist.ChannelCount(); ++j)
1452  {
1453  scnChanNums[((qlonglong)info.m_origNetId<<32) |
1454  scnlist.ServiceID(j)] =
1455  scnlist.ChannelNumber(j);
1456  }
1457  }
1458  }
1459  }
1460  }
1461  }
1462 
1463  // BAT
1464 
1465  // Channel numbers for Freesat and Sky on Astra 28.2E
1466  //
1467  // Get the Logical Channel Number (LCN) information from the BAT.
1468  // The first filter is on the bouquet ID.
1469  // Then collect all LCN for the selected region and
1470  // for the common (undefined) region with id 0xFFFF.
1471  // The LCN of the selected region has priority; if
1472  // a service is not defined there then the value of the LCN
1473  // table of the common region is used.
1474  // This works because the BAT of each transport contains
1475  // the LCN of all transports and services for all bouquets.
1476  //
1477  // For reference, this website has the Freesat and Sky channel numbers
1478  // for each bouquet and region:
1479  // https://www.satellite-calculations.com/DVB/28.2E/28E_FreeSat_ChannelNumber.php
1480  // https://www.satellite-calculations.com/DVB/28.2E/28E_Sky_ChannelNumber.php
1481  //
1482 
1483  // Lookup table from LCN to service ID
1484  QMap<uint,qlonglong> lcn_sid;
1485 
1486  for (auto bat : scan_info->m_bats)
1487  {
1488  // Only the bouquet selected by user
1489  if (bat->BouquetID() != m_bouquetId)
1490  continue;
1491 
1492  for (uint t = 0; t < bat->TransportStreamCount(); ++t)
1493  {
1494  uint netid = bat->OriginalNetworkID(t);
1495 
1496  // No network check to allow scanning on all Sky satellites
1497 #if 0
1498  if (!(netid == OriginalNetworkID::SES2 ||
1499  netid == OriginalNetworkID::BBC ||
1500  netid == OriginalNetworkID::SKYNZ ))
1501  continue;
1502 #endif
1503  desc_list_t parsed =
1504  MPEGDescriptor::Parse(bat->TransportDescriptors(t),
1505  bat->TransportDescriptorsLength(t));
1506 
1507  uint priv_dsid = 0;
1508  for (auto item : parsed)
1509  {
1510  if (item[0] == DescriptorID::private_data_specifier)
1511  {
1513  if (pd.IsValid())
1514  priv_dsid = pd.PrivateDataSpecifier();
1515  }
1516 
1517  // Freesat logical channels
1518  if (priv_dsid == PrivateDataSpecifierID::FSAT &&
1520  {
1521  FreesatLCNDescriptor ld(item);
1522  if (ld.IsValid())
1523  {
1524  for (uint i = 0; i<ld.ServiceCount(); i++)
1525  {
1526  uint service_id = ld.ServiceID(i);
1527  for (uint j=0; j<ld.LCNCount(i); j++)
1528  {
1529  uint region_id = ld.RegionID(i,j);
1530  uint lcn = ld.LogicalChannelNumber(i,j);
1531  if (region_id == m_regionId)
1532  {
1533  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1534  }
1535  else if (region_id == kRegionUndefined)
1536  {
1537  if (lcn_sid.value(lcn,0) == 0)
1538  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1539  }
1540  }
1541  }
1542  }
1543  }
1544 
1545  // Sky logical channels
1546  if (priv_dsid == PrivateDataSpecifierID::BSB1 &&
1548  {
1549  SkyLCNDescriptor ld(item);
1550  if (ld.IsValid())
1551  {
1552  uint region_id = ld.RegionID();
1553  for (uint i = 0; i<ld.ServiceCount(); i++)
1554  {
1555  uint service_id = ld.ServiceID(i);
1556  uint lcn = ld.LogicalChannelNumber(i);
1557  if (region_id == m_regionId)
1558  {
1559  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1560  }
1561  else if (region_id == kRegionUndefined)
1562  {
1563  if (lcn_sid.value(lcn,0) == 0)
1564  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1565  }
1566 #if 0
1567  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1568  QString("LCN bid:%1 tid:%2 rid:%3 sid:%4 lcn:%5")
1569  .arg(bat->BouquetID()).arg(bat->TSID(t)).arg(region_id).arg(service_id).arg(lcn));
1570 #endif
1571  }
1572  }
1573  }
1574  }
1575  }
1576  }
1577 
1578  // Create the reverse table from service id to LCN.
1579  // If the service has more than one logical
1580  // channel number the lowest number is used.
1581  QMap<qlonglong, uint> sid_lcn;
1582  QMap<uint, qlonglong>::const_iterator r = lcn_sid.constEnd();
1583  while (r != lcn_sid.constBegin())
1584  {
1585  --r;
1586  qlonglong sid = r.value();
1587  uint lcn = r.key();
1588  sid_lcn[sid] = lcn;
1589  }
1590 
1591  // ------------------------------------------------------------------------
1592 
1593  // Get IPTV channel numbers
1594  for (dbchan_it = pnum_to_dbchan.begin();
1595  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1596  {
1597  ChannelInsertInfo &info = *dbchan_it;
1598 
1599  if (!info.m_chanNum.isEmpty())
1600  continue;
1601 
1602  if (!iptv_channel.isEmpty())
1603  {
1604  info.m_chanNum = iptv_channel;
1605  if (info.m_serviceId)
1606  info.m_chanNum += "-" + QString::number(info.m_serviceId);
1607  }
1608  }
1609 
1610  // Get DVB Logical Channel Numbers
1611  for (dbchan_it = pnum_to_dbchan.begin();
1612  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1613  {
1614  ChannelInsertInfo &info = *dbchan_it;
1615 
1616  if (!info.m_chanNum.isEmpty())
1617  continue;
1618 
1619  // DVB HD Simulcast channel numbers
1620  //
1621  // The HD simulcast channel number table gives the correct channel number
1622  // when HD and SD versions of the same channel are simultaneously broadcast
1623  // and the receiver is capable of receiving the HD signal.
1624  // The latter is assumed correct for a MythTV system.
1625  //
1626  if (info.m_chanNum.isEmpty())
1627  {
1628  qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
1629  QMap<qlonglong, uint>::const_iterator it = scnChanNums.find(key);
1630 
1631  if (it != scnChanNums.end())
1632  {
1633  info.m_chanNum = QString::number(*it);
1634  }
1635  }
1636 
1637  // DVB Logical Channel Numbers (a.k.a. UK channel numbers)
1638  if (info.m_chanNum.isEmpty())
1639  {
1640  qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
1641  QMap<qlonglong, uint>::const_iterator it = ukChanNums.find(key);
1642 
1643  if (it != ukChanNums.end())
1644  {
1645  info.m_chanNum = QString::number(*it);
1646  }
1647  }
1648 
1649  // Freesat and Sky channel numbers
1650  if (info.m_chanNum.isEmpty())
1651  {
1652  qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
1653  QMap<qlonglong, uint>::const_iterator it = sid_lcn.find(key);
1654 
1655  if (it != sid_lcn.end())
1656  {
1657  info.m_chanNum = QString::number(*it);
1658  }
1659  }
1660 
1661  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1662  QString("GetChannelList: service %1 (0x%2) chan_num '%3' callsign '%4'")
1663  .arg(info.m_serviceId).arg(info.m_serviceId,4,16,QChar('0'))
1664  .arg(info.m_chanNum).arg(info.m_callSign));
1665  }
1666 
1667  // Get QAM/SCTE/MPEG channel numbers
1668  for (dbchan_it = pnum_to_dbchan.begin();
1669  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1670  {
1671  ChannelInsertInfo &info = *dbchan_it;
1672 
1673  if (!info.m_chanNum.isEmpty())
1674  continue;
1675 
1676  if ((info.m_siStandard == "mpeg") ||
1677  (info.m_siStandard == "scte") ||
1678  (info.m_siStandard == "opencable"))
1679  {
1680  if (info.m_freqId.isEmpty())
1681  {
1682  info.m_chanNum = QString("%1-%2")
1683  .arg(info.m_sourceId)
1684  .arg(info.m_serviceId);
1685  }
1686  else
1687  {
1688  info.m_chanNum = QString("%1-%2")
1689  .arg(info.m_freqId)
1690  .arg(info.m_serviceId);
1691  }
1692  }
1693  }
1694 
1695  // Check for decryption success
1696  for (dbchan_it = pnum_to_dbchan.begin();
1697  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1698  {
1699  uint pnum = dbchan_it.key();
1700  ChannelInsertInfo &info = *dbchan_it;
1701  info.m_decryptionStatus = scan_info->m_programEncryptionStatus[pnum];
1702  }
1703 
1704  return pnum_to_dbchan;
1705 }
1706 
1708 {
1709  ScanDTVTransportList list;
1710 
1711  uint cardid = m_channel->GetInputID();
1712 
1714  tuner_type = GuessDTVTunerType(tuner_type);
1715 
1716  foreach (const auto & it, m_channelList)
1717  {
1718  QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1719  GetChannelList(it.first, it.second);
1720 
1721  ScanDTVTransport item((*it.first).m_tuning, tuner_type, cardid);
1722  item.m_iptvTuning = (*(it.first)).m_iptvTuning;
1723 
1724  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1725  for (dbchan_it = pnum_to_dbchan.begin();
1726  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1727  {
1728  item.m_channels.push_back(*dbchan_it);
1729  }
1730 
1731  if (!item.m_channels.empty())
1732  {
1733  if (addFullTS)
1734  {
1735  /* If addFullTS, then add a 'MPTS' channel
1736  which can be used to record the entire MPTS from
1737  the transport. */
1738  dbchan_it = pnum_to_dbchan.begin();
1739  ChannelInsertInfo info = *dbchan_it;
1740 
1741  // Use transport stream ID as (fake) service ID
1742  // to use in callsign and as channel number
1743  info.m_serviceId = info.m_sdtTsId ? info.m_sdtTsId : info.m_patTsId;
1744 
1745  if (tuner_type == DTVTunerType::kTunerTypeASI)
1746  {
1747  info.m_callSign = QString("MPTS_%1")
1748  .arg(CardUtil::GetDisplayName(cardid));
1749  }
1750  else if (info.m_siStandard == "mpeg" ||
1751  info.m_siStandard == "scte" ||
1752  info.m_siStandard == "opencable")
1753  {
1754  info.m_callSign = QString("MPTS_%1").arg(info.m_freqId);
1755  }
1756  else if (info.m_atscMajorChannel > 0)
1757  {
1758  info.m_callSign =
1759  QString("MPTS_%1").arg(info.m_atscMajorChannel);
1760  }
1761  else if (info.m_serviceId > 0)
1762  {
1763  info.m_callSign = QString("MPTS_%1").arg(info.m_serviceId);
1764  }
1765  else if (!info.m_chanNum.isEmpty())
1766  {
1767  info.m_callSign = QString("MPTS_%1").arg(info.m_chanNum);
1768  }
1769  else
1770  {
1771  info.m_callSign = "MPTS_UNKNOWN";
1772  }
1773 
1774  info.m_serviceName = info.m_callSign;
1775  info.m_atscMinorChannel = 0;
1776  info.m_format = "MPTS";
1777  info.m_useOnAirGuide = false;
1778  info.m_isEncrypted = false;
1779  item.m_channels.push_back(info);
1780  }
1781 
1782  list.push_back(item);
1783  }
1784  }
1785 
1786  return list;
1787 }
1788 
1789 
1791 {
1792  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1793 }
1794 
1796 {
1797 #ifdef USING_DVB
1798  return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1799 #else
1800  return nullptr;
1801 #endif
1802 }
1803 
1805 {
1806  return dynamic_cast<DTVChannel*>(m_channel);
1807 }
1808 
1810 {
1811  return dynamic_cast<const DTVChannel*>(m_channel);
1812 }
1813 
1815 {
1816 #ifdef USING_HDHOMERUN
1817  return dynamic_cast<HDHRChannel*>(m_channel);
1818 #else
1819  return nullptr;
1820 #endif
1821 }
1822 
1824 {
1825 #ifdef USING_DVB
1826  return dynamic_cast<DVBChannel*>(m_channel);
1827 #else
1828  return nullptr;
1829 #endif
1830 }
1831 
1833 {
1834 #ifdef USING_DVB
1835  return dynamic_cast<const DVBChannel*>(m_channel);
1836 #else
1837  return nullptr;
1838 #endif
1839 }
1840 
1842 {
1843 #ifdef USING_V4L2
1844  return dynamic_cast<V4LChannel*>(m_channel);
1845 #else
1846  return nullptr;
1847 #endif
1848 }
1849 
1854 {
1855  while (m_scannerThread)
1856  {
1857  m_threadExit = true;
1858  if (m_scannerThread->wait(1000))
1859  {
1860  delete m_scannerThread;
1861  m_scannerThread = nullptr;
1862  }
1863  }
1864  m_threadExit = false;
1865  m_scannerThread = new MThread("Scanner", this);
1867 }
1868 
1873 {
1874  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
1875 
1876  while (!m_threadExit)
1877  {
1878  if (m_scanning)
1879  HandleActiveScan();
1880 
1881  usleep(10 * 1000);
1882  }
1883 
1884  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
1885 }
1886 
1887 // See if we have timed out
1889 {
1891  m_timer.hasExpired(kDecryptionTimeout))
1892  {
1894  return true;
1895  }
1896 
1897  if (!m_waitingForTables)
1898  return true;
1899 
1900 #ifdef USING_DVB
1901  // If the rotor is still moving, reset the timer and keep waiting
1903  if (sigmon)
1904  {
1905  const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
1906  if (rotor)
1907  {
1908  bool was_moving = false;
1909  bool is_moving = false;
1910  sigmon->GetRotorStatus(was_moving, is_moving);
1911  if (was_moving && !is_moving)
1912  {
1913  m_timer.restart();
1914  return false;
1915  }
1916  }
1917  }
1918 #endif // USING_DVB
1919 
1920 
1921  // have the tables have timed out?
1922  if (m_timer.hasExpired(m_channelTimeout))
1923  {
1924  // the channelTimeout alone is only valid if we have seen no tables..
1925  const ScanStreamData *sd = nullptr;
1926  if (GetDTVSignalMonitor())
1928 
1929  if (!sd)
1930  return true;
1931 
1932  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
1933  return m_timer.hasExpired(kDVBTableTimeout);
1934  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
1935  return m_timer.hasExpired(kATSCTableTimeout);
1936  if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
1937  return m_timer.hasExpired(kMPEGTableTimeout);
1938 
1939  return true;
1940  }
1941 
1942  // ok the tables haven't timed out, but have we hit the signal timeout?
1944  if (m_timer.hasExpired((*m_current).m_timeoutTune) &&
1945  sm && !sm->HasSignalLock())
1946  {
1947  const ScanStreamData *sd = nullptr;
1948  if (GetDTVSignalMonitor())
1950 
1951  if (!sd)
1952  return true;
1953 
1954  // Just is case we temporarily lose the signal after we've seen
1955  // tables...
1956  if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
1957  !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
1958  !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
1959  {
1960  return true;
1961  }
1962  }
1963 
1964  return false;
1965 }
1966 
1971 {
1972  QMutexLocker locker(&m_lock);
1973 
1974  bool do_post_insertion = m_waitingForTables;
1975 
1976  if (!HasTimedOut())
1977  return;
1978 
1979  if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
1980  {
1981  m_channelList.clear();
1982  m_channelsFound = 0;
1983  m_dvbt2Tried = true;
1984  }
1985 
1987  {
1988  // If we failed to get a lock with DVB-T try DVB-T2.
1989  m_dvbt2Tried = true;
1991  return;
1992  }
1993 
1994  if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
1995  {
1996  // Add channel to scanned list and potentially check decryption
1997  if (do_post_insertion && !UpdateChannelInfo(false))
1998  return;
1999 
2000  // Stop signal monitor for previous transport
2001  locker.unlock();
2002  m_signalMonitor->Stop();
2003  locker.relock();
2004  }
2005 
2006  m_current = m_nextIt; // Increment current
2007  m_dvbt2Tried = false;
2008 
2009  if (m_current != m_scanTransports.end())
2010  {
2012 
2013  // Increment nextIt
2014  m_nextIt = m_current;
2015  ++m_nextIt;
2016  }
2017  else if (!m_extendTransports.isEmpty())
2018  {
2019  --m_current;
2020  QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
2021  while (it != m_extendTransports.end())
2022  {
2023  if (!m_tsScanned.contains(it.key()))
2024  {
2025  QString name = QString("TransportID %1").arg(it.key() & 0xffff);
2026  TransportScanItem item(m_sourceID, name, *it, m_signalTimeout);
2027  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
2028  item.m_tuning.toString());
2029  m_scanTransports.push_back(item);
2030  m_tsScanned.insert(it.key());
2031  }
2032  ++it;
2033  }
2034  m_extendTransports.clear();
2035  m_nextIt = m_current;
2036  ++m_nextIt;
2037  }
2038  else
2039  {
2041  m_scanning = false;
2043  }
2044 }
2045 
2047 {
2048  const TransportScanItem &item = *transport;
2049 
2050 #ifdef USING_DVB
2051  if (GetDVBSignalMonitor())
2052  {
2053  // always wait for rotor to finish
2056  }
2057 #endif // USING_DVB
2058 
2059  if (!GetDTVChannel())
2060  return false;
2061 
2062  if (item.m_mplexid > 0 && transport.offset() == 0)
2064 
2065  if (item.m_tuning.m_sistandard == "MPEG")
2066  return GetDTVChannel()->Tune(item.m_iptvTuning, true);
2067 
2068  const uint64_t freq = item.freq_offset(transport.offset());
2069  DTVMultiplex tuning = item.m_tuning;
2070  tuning.m_frequency = freq;
2071 
2073  {
2075  }
2077  {
2078  if (m_dvbt2Tried)
2080  else
2082  }
2083 
2084  return GetDTVChannel()->Tune(tuning);
2085 }
2086 
2088 {
2089  QString offset_str = (transport.offset()) ?
2090  QObject::tr(" offset %2").arg(transport.offset()) : "";
2091  QString cur_chan = QString("%1%2")
2092  .arg((*m_current).m_friendlyName).arg(offset_str);
2093  QString tune_msg_str =
2094  QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
2095  .arg(cur_chan).arg((*m_current).m_mplexid);
2096 
2097  const TransportScanItem &item = *transport;
2098 
2099  if (transport.offset() &&
2100  (item.freq_offset(transport.offset()) == item.freq_offset(0)))
2101  {
2102  m_waitingForTables = false;
2103  return; // nothing to do
2104  }
2105 
2106  if (m_channelsFound)
2107  {
2108  QString progress = QObject::tr(": Found %n", "", m_channelsFound);
2110  }
2111 
2113  LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
2114 
2115  if (!Tune(transport))
2116  { // If we did not tune successfully, bail with message
2118  LOG(VB_CHANSCAN, LOG_ERR, LOC +
2119  QString("Failed to tune %1 mplexid(%2) at offset %3")
2120  .arg(item.m_friendlyName).arg(item.m_mplexid)
2121  .arg(transport.offset()));
2122  return;
2123  }
2124 
2125  // If we have a DTV Signal Monitor, perform table scanner reset
2126  if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
2127  {
2129  GetDTVSignalMonitor()->SetChannel(-1,-1);
2130  GetDTVSignalMonitor()->SetDVBService(0, 0, -1);
2131  }
2132 
2133  // Start signal monitor for this channel
2135 
2136  m_timer.start();
2137  m_waitingForTables = (item.m_tuning.m_sistandard != "analog");
2138 }
2139 
2145 {
2146  LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
2147 
2148  while (m_scannerThread)
2149  {
2150  m_threadExit = true;
2151  if (m_scannerThread->wait(1000))
2152  {
2153  delete m_scannerThread;
2154  m_scannerThread = nullptr;
2155  }
2156  }
2157 
2158  if (m_signalMonitor)
2159  m_signalMonitor->Stop();
2160 }
2161 
2167  int SourceID,
2168  const QString &std,
2169  const QString &modulation,
2170  const QString &country,
2171  const QString &table_start,
2172  const QString &table_end)
2173 {
2174  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2175  QString("%1: ").arg(__FUNCTION__) +
2176  QString("SourceID:%1 ").arg(SourceID) +
2177  QString("std:%1 ").arg(std) +
2178  QString("modulation:%1 ").arg(modulation) +
2179  QString("country:%1 ").arg(country) +
2180  QString("table_start:%1 ").arg(table_start) +
2181  QString("table_end:%1 ").arg(table_end));
2182 
2183  QString name("");
2184  if (m_scanning)
2185  return false;
2186 
2187  m_scanTransports.clear();
2188  m_nextIt = m_scanTransports.end();
2189 
2190  freq_table_list_t tables =
2191  get_matching_freq_tables(std, modulation, country);
2192 
2193  if (tables.empty())
2194  {
2195  QString msg = QString("No freq table for (%1, %2, %3) found")
2196  .arg(std).arg(modulation).arg(country);
2198  }
2199  LOG(VB_CHANSCAN, LOG_INFO, LOC +
2200  QString("Looked up freq table (%1, %2, %3) w/%4 entries")
2201  .arg(std).arg(modulation).arg(country).arg(tables.size()));
2202 
2203  QString start = table_start;
2204  const QString& end = table_end;
2205  // NOLINTNEXTLINE(modernize-loop-convert)
2206  for (auto it = tables.begin(); it != tables.end(); ++it)
2207  {
2208  const FrequencyTable &ft = **it;
2209  int name_num = ft.m_nameOffset;
2210  QString strNameFormat = ft.m_nameFormat;
2211  uint freq = ft.m_frequencyStart;
2212  while (freq <= ft.m_frequencyEnd)
2213  {
2214  name = strNameFormat;
2215  if (strNameFormat.indexOf("%") >= 0)
2216  name = strNameFormat.arg(name_num);
2217 
2218  if (start.isEmpty() || name == start)
2219  {
2220  start.clear();
2221 
2222  TransportScanItem item(SourceID, std, name, name_num,
2223  freq, ft, m_signalTimeout);
2224  m_scanTransports.push_back(item);
2225 
2226  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
2227  item.toString());
2228  }
2229 
2230  ++name_num;
2231  freq += ft.m_frequencyStep;
2232 
2233  if (!end.isEmpty() && name == end)
2234  break;
2235  }
2236  if (!end.isEmpty() && name == end)
2237  break;
2238  }
2239 
2240  while (!tables.empty())
2241  {
2242  delete tables.back();
2243  tables.pop_back();
2244  }
2245 
2246  m_extendScanList = true;
2247  m_timer.start();
2248  m_waitingForTables = false;
2249 
2250  m_nextIt = m_scanTransports.begin();
2251  m_transportsScanned = 0;
2252  m_scanning = true;
2253 
2254  return true;
2255 }
2256 
2258  const QString &std,
2259  const QString &cardtype,
2260  const DTVChannelList &channels)
2261 {
2262  m_scanTransports.clear();
2263  m_nextIt = m_scanTransports.end();
2264 
2265  DTVTunerType tunertype;
2266  tunertype.Parse(cardtype);
2267 
2268  auto it = channels.cbegin();
2269  for (uint i = 0; it != channels.cend(); ++it, ++i)
2270  {
2271  DTVTransport tmp = *it;
2272  tmp.m_sistandard = std;
2273  TransportScanItem item(sourceid, QString::number(i),
2274  tunertype, tmp, m_signalTimeout);
2275 
2276  m_scanTransports.push_back(item);
2277 
2278  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
2279  }
2280 
2281  if (m_scanTransports.empty())
2282  {
2283  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
2284  return false;
2285  }
2286 
2287  m_timer.start();
2288  m_waitingForTables = false;
2289 
2290  m_nextIt = m_scanTransports.begin();
2291  m_transportsScanned = 0;
2292  m_scanning = true;
2293 
2294  return true;
2295 }
2296 
2298  const fbox_chan_map_t &iptv_channels)
2299 {
2300  m_scanTransports.clear();
2301  m_nextIt = m_scanTransports.end();
2302 
2303  fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2304  for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2305  {
2306  TransportScanItem item(sourceid, QString::number(idx),
2307  Ichan.value().m_tuning, Ichan.key(),
2308  m_signalTimeout);
2309 
2310  m_scanTransports.push_back(item);
2311 
2312  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2313  }
2314 
2315  if (m_scanTransports.empty())
2316  {
2317  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2318  return false;
2319  }
2320 
2321  m_timer.start();
2322  m_waitingForTables = false;
2323 
2324  m_nextIt = m_scanTransports.begin();
2325  m_transportsScanned = 0;
2326  m_scanning = true;
2327 
2328  return true;
2329 }
2330 
2331 
2337  int sourceid, const QMap<QString,QString> &startChan)
2338 {
2339  if (startChan.find("std") == startChan.end() ||
2340  startChan.find("type") == startChan.end())
2341  {
2342  return false;
2343  }
2344 
2345  QString std = *startChan.find("std");
2346  QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
2347  bool ok = false;
2348 
2349  if (m_scanning)
2350  return false;
2351 
2352  m_scanTransports.clear();
2353  m_nextIt = m_scanTransports.end();
2354 
2355  DTVMultiplex tuning;
2356 
2358  ok = type.Parse(startChan["type"]);
2359 
2360  if (ok)
2361  {
2362  ok = tuning.ParseTuningParams(
2363  type,
2364  startChan["frequency"], startChan["inversion"],
2365  startChan["symbolrate"], startChan["fec"],
2366  startChan["polarity"],
2367  startChan["coderate_hp"], startChan["coderate_lp"],
2368  startChan["constellation"], startChan["trans_mode"],
2369  startChan["guard_interval"], startChan["hierarchy"],
2370  startChan["modulation"], startChan["bandwidth"],
2371  startChan["mod_sys"], startChan["rolloff"]);
2372  }
2373 
2374  if (ok)
2375  {
2376  tuning.m_sistandard = si_std;
2377  TransportScanItem item(
2378  sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2379  tuning, m_signalTimeout);
2380  m_scanTransports.push_back(item);
2381  }
2382 
2383  if (!ok)
2384  return false;
2385 
2386  m_extendScanList = true;
2387 
2388  m_timer.start();
2389  m_waitingForTables = false;
2390 
2391  m_nextIt = m_scanTransports.begin();
2392  m_transportsScanned = 0;
2393  m_scanning = true;
2394 
2395  return true;
2396 }
2397 
2399 {
2400  MSqlQuery query(MSqlQuery::InitCon());
2401  query.prepare(
2402  "SELECT sourceid, sistandard, transportid, frequency, modulation "
2403  "FROM dtv_multiplex "
2404  "WHERE mplexid = :MPLEXID");
2405  query.bindValue(":MPLEXID", mplexid);
2406  if (!query.exec())
2407  {
2408  MythDB::DBError("ChannelScanSM::AddToList()", query);
2409  return false;
2410  }
2411 
2412  if (!query.next())
2413  {
2414  LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2415  QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2416  return false;
2417  }
2418 
2419  uint sourceid = query.value(0).toUInt();
2420  QString sistandard = query.value(1).toString();
2421  uint tsid = query.value(2).toUInt();
2423 
2424  QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2425  QString("Multiplex #%1").arg(mplexid);
2426 
2427  if (query.value(4).toString() == "8vsb")
2428  {
2429  QString chan = QString("%1 Hz").arg(query.value(3).toInt());
2430  struct CHANLIST *curList = chanlists[0].list;
2431  int totalChannels = chanlists[0].count;
2432  int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2433  for (int x = 0 ; x < totalChannels ; ++x)
2434  {
2435  if ((curList[x].freq <= findFrequency + 200) &&
2436  (curList[x].freq >= findFrequency - 200))
2437  {
2438  chan = QString("%1").arg(curList[x].name);
2439  }
2440  }
2441  fn = QObject::tr("ATSC Channel %1").arg(chan);
2443  }
2444 
2445  tt = GuessDTVTunerType(tt);
2446 
2447  TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2448 
2449  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2450  QString("tunertype:%1 %2 sourceid:%3 sistandard:%4 fn:'%5' mplexid:%6")
2451  .arg(tt).arg(tt.toString()).arg(sourceid).arg(sistandard).arg(fn).arg(mplexid));
2452 
2453  if (item.m_tuning.FillFromDB(tt, mplexid))
2454  {
2455  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2456  m_scanTransports.push_back(item);
2457  return true;
2458  }
2459 
2460  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2461  return false;
2462 }
2463 
2464 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2465 {
2466  m_scanTransports.clear();
2467  m_nextIt = m_scanTransports.end();
2468 
2469  AddToList(mplexid);
2470 
2471  m_timer.start();
2472  m_waitingForTables = false;
2473 
2474  m_extendScanList = follow_nit;
2475  m_transportsScanned = 0;
2476  if (!m_scanTransports.empty())
2477  {
2478  m_nextIt = m_scanTransports.begin();
2479  m_scanning = true;
2480  return true;
2481  }
2482 
2483  return false;
2484 }
2485 
2486 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2487 {
2488  m_scanTransports.clear();
2489  m_nextIt = m_scanTransports.end();
2490 
2491  m_signalTimeout = 30000;
2492  QString name;
2493  TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2494  m_scanTransports.push_back(item);
2495 
2496  m_timer.start();
2497  m_waitingForTables = false;
2498  m_extendScanList = false;
2499  m_transportsScanned = 0;
2500  m_nextIt = m_scanTransports.begin();
2501  m_scanning = true;
2502  return true;
2503 }
2504 
2509  const DTVChannelInfoList &channels,
2510  uint mpeg_program_num,
2511  QString &service_name,
2512  QString &callsign,
2513  QString &common_status_info)
2514 {
2515  if (channels.empty())
2516  return true;
2517 
2518  bool found = false;
2519  for (const auto & channel : channels)
2520  {
2521  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2522  QString("comparing %1 %2 against %3 %4")
2523  .arg(channel.m_serviceid).arg(channel.m_name)
2524  .arg(mpeg_program_num).arg(common_status_info));
2525 
2526  if (channel.m_serviceid == mpeg_program_num)
2527  {
2528  found = true;
2529  if (!channel.m_name.isEmpty())
2530  {
2531  service_name = channel.m_name;
2532  callsign = channel.m_name;
2533  }
2534  }
2535  }
2536 
2537  if (found)
2538  {
2539  common_status_info += QString(" %1 %2")
2540  .arg(QObject::tr("as")).arg(service_name);
2541  }
2542  else
2543  {
2545  QObject::tr("Skipping %1, not in imported channel map")
2546  .arg(common_status_info));
2547  }
2548 
2549  return found;
2550 }
uint BouquetID() const
Definition: dvbtables.h:195
bool HasCachedAnyNIT(bool current=true) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
void HandleBAT(const BouquetAssociationTable *bat) override
bool Parse(const QString &_value)
uint GetTransportID(void) const
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:231
ChannelScanSM(ScanMonitor *_scan_monitor, const QString &_cardtype, ChannelBase *_channel, int _sourceID, uint signal_timeout, uint channel_timeout, QString _inputname, bool test_decryption)
static vector< uint > GetMplexIDs(uint sourceid)
Definition: sourceutil.cpp:124
void AddListener(SignalMonitorListener *listener)
V4LChannel * GetV4LChannel(void)
QString toString(void) const override
Definition: dvbtables.cpp:127
DVB HD Simulcast Logical Channel Descriptor.
uint TransportDescriptorsLength(uint i) const
Definition: dvbtables.h:227
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
void ScanUpdateStatusTitleText(const QString &status)
QString m_defaultAuthority
Definition: channelinfo.h:233
int freq
Definition: frequencies.h:98
bool UpdateChannelInfo(bool wait_until_complete)
bool HasEITPresentFollowing(uint i) const
Definition: dvbtables.h:146
uint ProgramCount(void) const
Definition: mpegtables.h:610
DVBStreamData * GetDVBStreamData()
Returns the DVB stream data if it exists.
bool ScanCurrentTransport(const QString &sistandard)
void HandleActiveScan(void)
Handles the TRANSPORT_LIST ChannelScanSM mode.
uint MajorChannel(uint i) const
Definition: atsctables.h:244
bool IsEncrypted(uint i) const
free_CA_mode 1 3.3+p
Definition: dvbtables.h:151
bool HasCachedAllCVCTs(bool current=true) const
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
bool CheckImportedList(const DTVChannelInfoList &channels, uint mpeg_program_num, QString &service_name, QString &callsign, QString &common_status_info)
If we are scanning a dvb-utils import verify channel is in list.
static const int kTunerTypeDVBT
void UpdateScanTransports(const NetworkInformationTable *nit)
uint64_t m_frequencyEnd
The ending centre frequency.
bool IsDTV(void) const
virtual void Start()
Start signal monitoring thread.
transport_scan_items_t m_scanTransports
bool HasTimedOut(void)
Class used for doing a list of frequencies / transports.
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
sdt_vec_t GetCachedSDTSections(uint tsid, bool current=true) const
void HandleMGT(const MasterGuideTable *mgt) override
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
uint m_otherTableTimeout
uint MinorChannel(uint i) const
Definition: atsctables.h:249
#define LOC
This table tells the decoder on which PIDs to find A/V data.
Definition: dvbtables.h:101
static const int kTunerTypeATSC
void run(void) override
This runs the event loop for ChannelScanSM until 'threadExit' is true.
void TestDecryption(const ProgramMapTable *pmt)
QMap< uint32_t, DTVMultiplex > m_extendTransports
QMap< uint, sdt_vec_t > sdt_map_t
Definition: dvbstreamdata.h:19
ScanStreamData * GetScanStreamData()
Returns the scan stream data if it exists.
uint ServiceCount(void) const
volatile bool m_threadExit
static const int kTunerTypeUnknown
bool IsEncrypted(const QString &sistandard) const
Returns true iff PMT contains CA descriptor for a vid/aud stream.
Definition: mpegtables.cpp:551
QString toString(void) const override
Definition: mpegtables.cpp:879
cvct_vec_t GetCachedCVCTs(bool current=true) const
ScannedChannelInfo * m_currentInfo
uint ServiceID(uint i) const
service_id 16 0.0+p
Definition: dvbtables.h:141
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
#define kDecryptionTimeout
DVBChannel * GetDVBChannel(void)
void HandleEncryptionStatus(uint pnum, bool encrypted) override
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
bool HasSignalLock(void) const
Returns true iff scriptStatus.IsGood() and signalLock.IsGood() return true.
Definition: signalmonitor.h:76
bool Tune(const transport_scan_items_it_t &transport)
uint ProgramNumber(uint i) const
Definition: atsctables.h:266
pmt_vec_t GetCachedPMTs(void) const
vector< DTVTransport > DTVChannelList
Definition: dtvconfparser.h:71
void HandleVCT(uint tsid, const VirtualChannelTable *vct) override
uint ServiceType(uint i) const
Definition: atsctables.h:293
uint LastSection(void) const
Definition: mpegtables.h:525
IPTVTuningData m_iptvTuning
IPTV Tuning info.
IPTVTuningData m_iptvTuning
Definition: dtvmultiplex.h:112
uint ServiceDescriptorsLength(uint i) const
desc_loop_length 12 3.4+p
Definition: dvbtables.h:153
bool ScanTransport(uint mplexid, bool follow_nit)
uint DescriptorTag(void) const
DVB Logical Channel Descriptor.
const MasterGuideTable * m_mgt
ChannelList m_channelList
Found Channel Info.
uint TSID(uint i) const
Definition: dvbtables.h:221
void ScanPercentComplete(int pct)
uint RegionID(void) const
bool HasCachedMGT(bool current=true) const
struct CHANLIST * list
Definition: frequencies.h:103
bool ScanExistingTransports(uint sourceid, bool follow_nit)
If we are not already scanning a frequency table, this creates a new frequency table from database an...
QString GetExtendedChannelName(uint idx) const
Definition: atsctables.cpp:507
freq_table_list_t get_matching_freq_tables(const QString &format, const QString &modulation, const QString &country)
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:29
uint ChannelTransportStreamID(uint i) const
Definition: atsctables.h:261
QMap< uint, pat_vec_t > pat_map_t
DVBSignalMonitor * GetDVBSignalMonitor(void)
uint TSID() const
transport_stream_id 16 3.0 0x0000
Definition: dvbtables.h:129
uint32_t freq[4]
Definition: element.c:44
uint NetworkID(void) const
network_id 16 3.0 0x0000
Definition: dvbtables.h:50
uint ServiceID(uint i) const
static const uint kATSCTableTimeout
No logic here, lets just wait at least 10 seconds.
bool m_currentTestingDecryption
void HandleNIT(const NetworkInformationTable *nit) override
static const uint64_t kDTVSigMon_WaitForVCT
const unsigned char * ServiceDescriptors(uint i) const
for (j=0;j<N;j++) x 5.0+p { descriptor() }
Definition: dvbtables.h:157
bool teardown_frequency_tables(void)
QString DescriptorTagString(void) const
static guint32 * tmp
Definition: goom_core.c:35
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:80
static uint GetMplexID(uint sourceid, const QString &channum)
static const uint64_t kDTVSigMon_WaitForMGT
uint ModulationMode(uint i) const
Definition: atsctables.h:254
static const int kTunerTypeDVBS1
QString toString() const
bool HasCachedAllPAT(uint tsid) const
bool ScanIPTVChannels(uint sourceid, const fbox_chan_map_t &iptv_channels)
void HandleAllGood(void)
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
Definition: dvbchannel.cpp:999
int m_nameOffset
Offset to add to the pretty name.
bool HasCachedAllNIT(bool current=true) const
QString toString(void) const override
Definition: atsctables.cpp:69
virtual bool TuneMultiplex(uint mplexid, const QString &inputname)
To be used by the channel scanner and possibly the EIT scanner.
Definition: dtvchannel.cpp:394
DTVTunerType GuessDTVTunerType(DTVTunerType type) const
ChannelInsertInfoList m_channels
Definition: dtvmultiplex.h:138
uint Section(void) const
Definition: mpegtables.h:522
vector< const unsigned char * > desc_list_t
static const uint64_t kDTVSigMon_WaitForNIT
uint ServiceCount(void) const
vector< const ProgramMapTable * > pmt_vec_t
QString m_nameFormat
pretty name format
QString toString(void) const override
Definition: atsctables.cpp:200
bool ScanTransportsStartingOn(int sourceid, const QMap< QString, QString > &startChan)
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
static void LogLines(const QString &string)
Overall structure.
void HandleSDT(uint tsid, const ServiceDescriptionTable *sdt) override
QVariant value(int i) const
Definition: mythdbcon.h:198
static const uint kDVBTableTimeout
SDT's should be sent every 2 seconds and NIT's every 10 seconds, so lets wait at least 30 seconds,...
MThread * m_scannerThread
Scanner thread, runs ChannelScanSM::run()
chan_info_map_t GetChannelList(transport_scan_items_it_t trans_info, ScannedChannelInfo *scan_info) const
bool FillFromDeliverySystemDesc(DTVTunerType type, const MPEGDescriptor &desc)
uint LogicalChannelNumber(int i, int j) const
virtual void Stop()
Stop signal monitoring thread.
bool IsHidden(uint i) const
Definition: atsctables.h:281
uint OriginalNetworkID() const
original_network_id 16 8.0
Definition: dvbtables.h:132
void SetChannel(int major, int minor)
void SetDVBService(uint network_id, uint transport_id, int service_id)
struct CHANLISTS chanlists[]
static const int kTunerTypeDVBT2
void RemoveListener(SignalMonitorListener *listener)
bool HasCachedAnyVCTs(bool current=true) const
virtual void ReturnCachedPATTables(pat_vec_t &pats) const
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:34
static bool CreateChannel(uint db_mplexid, uint db_sourceid, uint new_channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0)
static const int kTunerTypeDVBC
static QString GetUnknownCallsign(void)
uint GetCurrentTransportInfo(QString &chan, QString &chan_tr) const
vector< const FrequencyTable * > freq_table_list_t
uint64_t m_frequencyStart
The staring centre frequency.
bool IsHiddenInGuide(uint i) const
Definition: atsctables.h:287
bool HasCachedAllPMTs(void) const
void Reset(void) override
bool ScanTransports(int SourceID, const QString &std, const QString &mod, const QString &country, const QString &table_start=QString(), const QString &table_end=QString())
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
uint ChannelCount() const
Definition: atsctables.h:221
ChannelBase * m_channel
QString ShortChannelName(uint i) const
Definition: atsctables.h:225
static uint FindChannel(uint sourceid, const QString &freqid)
vector< const ProgramAssociationTable * > pat_vec_t
bool TestNextProgramEncryption(void)
uint ChannelNumber(uint i) const
HDHRChannel * GetHDHRChannel(void)
uint ServiceCount() const
Number of services.
Definition: dvbtables.h:136
bool isActive(void) const
Definition: mythdbcon.h:204
void SetAnalog(bool is_analog)
Rotor class.
Definition: diseqc.h:295
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
Freesat Logical Channel Number descriptor.
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
bat_vec_t GetCachedBATs(bool current=true) const
void SetPMT(const ProgramMapTable *pmt)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:495
void ScanAppendTextToLog(const QString &status)
bool HasCachedAnyPMTs(void) const
bool IsDigitalAudio(void) const
unsigned int uint
Definition: compat.h:140
const char * name
Definition: frequencies.h:97
bool ParseTuningParams(DTVTunerType type, const QString &frequency, const QString &inversion, const QString &symbolrate, const QString &fec, const QString &polarity, const QString &hp_code_rate, const QString &lp_code_rate, const QString &ofdm_modulation, const QString &trans_mode, const QString &guard_interval, const QString &hierarchy, const QString &modulation, const QString &bandwidth, const QString &mod_sys, const QString &rolloff)
sdt_vec_t GetCachedSDTs(bool current=true) const
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
uint OriginalNetworkID(uint i) const
Definition: dvbtables.h:223
uint m_frequencyStep
The step in frequency.
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:144
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:35
void SetRotorTarget(float target) override
Sets rotor target pos from 0.0 to 1.0.
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
Definition: mpegtables.h:589
QMap< uint64_t, QString > m_defAuthorities
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
QString m_inputName
QString ServiceShortName(void) const
static const unsigned char * Find(const desc_list_t &parsed, uint desc_tag)
uint DescriptorLength(void) const
uint TransportStreamCount(void) const
Definition: dvbtables.h:216
bool HasCachedAllBATs(bool current=true) const
uint ServiceID(int i) const
virtual bool Tune(const DTVMultiplex &tuning)=0
This performs the actual frequency tuning and in some cases input switching.
~ChannelScanSM() override
vector< const TerrestrialVirtualChannelTable * > tvct_vec_t
QString m_sistandard
Definition: dtvmultiplex.h:111
vector< const CableVirtualChannelTable * > cvct_vec_t
QString DefaultAuthority(void) const
vector< DTVChannelInfo > DTVChannelInfoList
Definition: dtvconfparser.h:61
const MasterGuideTable * GetCachedMGT(bool current=true) const
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
QMap< uint, uint > m_programEncryptionStatus
QString m_friendlyName
Name to display in scanner dialog.
DTVTunerType m_scanDTVTunerType
transport_scan_items_it_t m_current
QString FormatIdentifierString(void) const
This class is intended to detect the presence of needed tables.
bool IsAccessControlled(uint i) const
Definition: atsctables.h:276
static void update_info(ChannelInsertInfo &info, const VirtualChannelTable *vct, uint i)
vector< const NetworkInformationTable * > nit_vec_t
Definition: dvbstreamdata.h:12
virtual QString GetDevice(void) const
Returns String representing device, useful for debugging.
Definition: channelbase.h:78
SignalMonitor * m_signalMonitor
Signal monitoring base class.
Definition: signalmonitor.h:32
void AddFlags(uint64_t _flags) override
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
Scanning class for cards that support a SignalMonitor class.
uint32_t PrivateDataSpecifier(void) const
bool HasCachedAnyBATs(bool current=true) const
static const int kTunerTypeASI
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool HasCachedAllSDT(uint tsid, bool current=true) const
nit_const_ptr_t GetCachedNIT(uint section_num, bool current=true) const
ServiceDescriptor * GetServiceDescriptor(uint i) const
Definition: dvbtables.cpp:164
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
QElapsedTimer m_timer
uint64_t freq_offset(uint i) const
uint RegionID(int i, int j) const
QString toString(void) const override
Definition: mpegtables.cpp:814
QString m_serviceName
Definition: channelinfo.h:219
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:74
QPair< transport_scan_items_it_t, ScannedChannelInfo * > ChannelListItem
uint ProgramNumber(void) const
Definition: mpegtables.h:703
uint OriginalNetworkID(uint i) const
original_network_id 16 2.0+p
Definition: dvbtables.h:72
static const uint kRegionUndefined
uint TransportStreamCount(void) const
Definition: dvbtables.h:66
QString toString(void) const override
Definition: dvbtables.cpp:30
void HandleSDTo(uint tsid, const ServiceDescriptionTable *sdt) override
bool IsEmpty() const
tvct_vec_t GetCachedTVCTs(bool current=true) const
DTVChannel * GetDTVChannel(void)
static const uint64_t kDTVSigMon_WaitForSDT
unsigned long long FrequencyHz(void) const
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
vector< const ServiceDescriptionTable * > sdt_vec_t
Definition: dvbstreamdata.h:17
uint ServiceID(int i) const
void ScanComplete(void)
Definition: scanmonitor.cpp:98
QSet< uint32_t > m_tsScanned
void StopScanner(void)
Stops the ChannelScanSM event loop and the signal monitor, blocking until both exit.
Sky Logical Channel Number descriptor.
bool AddToList(uint mplexid)
This table contains information about the channels transmitted on this multiplex.
Definition: atsctables.h:189
uint m_mplexid
DB Mplexid.
QString m_siStandard
Definition: channelinfo.h:242
uint TSID(uint i) const
transport_stream_id 16 0.0+p
Definition: dvbtables.h:70
transport_scan_items_it_t nextTransport() const
bool HasCachedAllTVCTs(bool current=true) const
Tells what channels can be found on each transponder for one bouquet (a bunch of channels from one pr...
Definition: dvbtables.h:179
bool HasCachedAnySDTs(bool current=true) const
uint LCNCount(int i) const
void UpdateScanPercentCompleted(void)
Updates Transport Scan progress bar.
QString toString(void) const override
Definition: dvbtables.cpp:200
virtual int GetInputID(void) const
Definition: channelbase.h:67
vector< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:140
bool ScanForChannels(uint sourceid, const QString &std, const QString &cardtype, const DTVChannelList &channels)
uint TransportDescriptorsLength(uint i) const
trans_desc_length 12 4.4+p
Definition: dvbtables.h:76
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
transport_scan_items_it_t m_nextIt
bool IsValid(void) const
SignalMonitor * GetSignalMonitor(void)
virtual void ReturnCachedPMTTables(pmt_vec_t &pmts) const
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
uint ServiceID(uint i) const
QMap< uint, uint > m_currentEncryptionStatus
void StartScanner(void)
Starts the ChannelScanSM event loop.
unsigned long long FrequencykHz(void) const
void ReturnCachedSDTTables(sdt_vec_t &sdts) const
QString toString() const
pat_vec_t GetCachedPATs(uint tsid) const
QMap< uint, bool > m_currentEncryptionStatusChecked
This table tells the decoder on which PIDs to find other tables.
Definition: dvbtables.h:21
list< TransportScanItem >::iterator iter()
uint ServiceType(void) const
uint LogicalChannelNumber(int i) const
static QString loc(const ChannelScanSM *siscan)
uint ServiceCount(void) const
virtual vector< DTVTunerType > GetTunerTypes(void) const
Returns a vector of supported tuning types.
Definition: dtvchannel.cpp:78
#define PCM_INFO_INIT(SISTD)
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:666
static desc_list_t Parse(const unsigned char *data, uint len)
uint ChannelNumber(uint i) const
uint TransportStreamID() const
Definition: atsctables.h:218
static desc_list_t ParseOnlyInclude(const unsigned char *data, uint len, int excluded_descid)
AnalogSignalHandler * m_analogSignalHandler
static const uint kMPEGTableTimeout
No logic here, lets just wait at least 15 seconds.
void HandlePAT(const ProgramAssociationTable *pat) override
DTVSignalMonitor * GetDTVSignalMonitor(void)
void GetRotorStatus(bool &was_moving, bool &is_moving) override
DTVMultiplex m_tuning
Tuning info.
void ScanUpdateStatusText(const QString &status)
vector< const BouquetAssociationTable * > bat_vec_t
Definition: dvbstreamdata.h:23
QString toString() const
virtual bool FillFromDB(DTVTunerType type, uint mplexid)
DTVModulationSystem m_modSys
Modulation system.
Definition: dtvmultiplex.h:106
QString ServiceName(void) const
uint64_t m_frequency
Definition: dtvmultiplex.h:94
QMap< QString, IPTVChannelInfo > fbox_chan_map_t
ScanMonitor * m_scanMonitor
uint ProgramPID(uint i) const
Definition: mpegtables.h:620
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1721
QMutex m_lock
The big lock.
bool HasCachedAnyPAT(uint tsid) const
Always MPEG-2??
Definition: mpegtables.h:120