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 // Astra 28.2E satellite Freesat/BSkyB
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_bouquet_id = query.value(1).toUInt();
191  m_region_id = query.value(2).toUInt();
192  }
193 
194  LOG(VB_CHANSCAN, LOG_INFO, LOC +
195  QString("Freesat/BSkyB bouquet_id:%1 region_id:%2")
196  .arg(m_bouquet_id).arg(m_region_id));
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  false /* hidden */,
283  false /* hidden in guide */,
284  freqid);
285 
286  msg = (ok) ?
287  QObject::tr("Added Channel %1").arg(cur_chan) :
288  QObject::tr("Failed to add channel %1").arg(cur_chan);
289  }
290  else
291  {
292  // nothing to do here, XMLTV has better info
293  }
294 
296 
297  // tell UI we are done with these channels
298  if (m_scanning)
299  {
301  m_waitingForTables = false;
303  m_dvbt2Tried = true;
304  }
305 }
306 
318 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
319 {
320  if (m_scanning)
321  return false;
322 
323  m_scanTransports.clear();
324  m_nextIt = m_scanTransports.end();
325 
326  vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
327 
328  if (multiplexes.empty())
329  {
330  LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
331  QString("sourceid %1").arg(sourceid));
332 
333  return false;
334  }
335 
336  for (size_t i = 0; i < multiplexes.size(); ++i)
337  AddToList(multiplexes[i]);
338 
339  m_extendScanList = follow_nit;
340  m_waitingForTables = false;
342  if (!m_scanTransports.empty())
343  {
344  m_nextIt = m_scanTransports.begin();
345  m_scanning = true;
346  }
347  else
348  {
349  LOG(VB_CHANSCAN, LOG_ERR, LOC +
350  "Unable to find add any transports for " +
351  QString("sourceid %1").arg(sourceid));
352 
353  return false;
354  }
355 
356 
357  return m_scanning;
358 }
359 
360 void ChannelScanSM::LogLines(const QString& string)
361 {
362  QStringList lines = string.split('\n');
363  for (int i = 0; i < lines.size(); ++i)
364  LOG(VB_CHANSCAN, LOG_DEBUG, lines[i]);
365 }
366 
368 {
369  QMutexLocker locker(&m_lock);
370 
371  LOG(VB_CHANSCAN, LOG_INFO, LOC +
372  QString("Got a Program Association Table for %1")
373  .arg((*m_current).m_friendlyName));
374  LogLines(pat->toString());
375 
376  // Add pmts to list, so we can do MPEG scan properly.
378  for (uint i = 0; i < pat->ProgramCount(); ++i)
379  {
380  if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
381  sd->AddListeningPID(pat->ProgramPID(i));
382  }
383 }
384 
385 void ChannelScanSM::HandlePMT(uint /*program_num*/, const ProgramMapTable *pmt)
386 {
387  QMutexLocker locker(&m_lock);
388 
389  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1 program %2 (0x%3)")
390  .arg((*m_current).m_friendlyName).arg(pmt->ProgramNumber())
391  .arg(pmt->ProgramNumber(),4,16,QChar('0')));
392  LogLines(pmt->toString());
393 
395  pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
397 }
398 
400 {
401  QMutexLocker locker(&m_lock);
402 
403  LOG(VB_CHANSCAN, LOG_INFO, LOC +
404  QString("Got a Virtual Channel Table for %1")
405  .arg((*m_current).m_friendlyName));
406  LogLines(vct->toString());
407 
408  for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
409  {
410  if (vct->IsAccessControlled(i))
411  {
413  }
414  }
415 
416  UpdateChannelInfo(true);
417 }
418 
420 {
421  QMutexLocker locker(&m_lock);
422 
423  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
424  .arg((*m_current).m_friendlyName));
425  LogLines(mgt->toString());
426 
427  UpdateChannelInfo(true);
428 }
429 
438 {
439  QMutexLocker locker(&m_lock);
440 
441  LOG(VB_CHANSCAN, LOG_INFO, LOC +
442  QString("Got a Service Description Table for %1 section %2/%3")
443  .arg((*m_current).m_friendlyName)
444  .arg(sdt->Section()).arg(sdt->LastSection()));
445  LogLines(sdt->toString());
446 
447  // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
448  if (!m_setOtherTables && (
451  {
453  SetFreesatAdditionalSI(true);
454  m_setOtherTables = true;
455  // The whole BAT & SDTo group comes round in 10s
456  m_otherTableTimeout = 10000;
457  // Delay processing the SDT until we've seen BATs and SDTos
459 
460  LOG(VB_CHANSCAN, LOG_INFO, LOC +
461  QString("SDT has OriginalNetworkID %1, look for "
462  "additional Freesat SI").arg(sdt->OriginalNetworkID()));
463  }
464 
465  if ((uint)m_timer.elapsed() < m_otherTableTime)
466  {
467  // Set the version for the SDT so we see it again.
469  SetVersionSDT(sdt->TSID(), -1, 0);
470  }
471 
472  uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
473  m_tsScanned.insert(id);
474 
475  for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
476  {
477  if (sdt->IsEncrypted(i))
478  {
480  }
481  }
482 
483  UpdateChannelInfo(true);
484 }
485 
487 {
488  QMutexLocker locker(&m_lock);
489 
490  LOG(VB_CHANSCAN, LOG_INFO, LOC +
491  QString("Got a Network Information Table id %1 for %2 section %3/%4")
492  .arg(nit->NetworkID()).arg((*m_current).m_friendlyName)
493  .arg(nit->Section()).arg(nit->LastSection()));
494  LogLines(nit->toString());
495 
496  UpdateChannelInfo(true);
497 }
498 
500 {
501  QMutexLocker locker(&m_lock);
502 
503  LOG(VB_CHANSCAN, LOG_INFO, LOC +
504  QString("Got a Bouquet Association Table id %1 for %2 section %3/%4")
505  .arg(bat->BouquetID()).arg((*m_current).m_friendlyName)
506  .arg(bat->Section()).arg(bat->LastSection()));
507  LogLines(bat->toString());
508 
510 
511  for (uint i = 0; i < bat->TransportStreamCount(); ++i)
512  {
513  uint tsid = bat->TSID(i);
514  uint netid = bat->OriginalNetworkID(i);
515  desc_list_t parsed =
518  // Look for default authority
519  const unsigned char *def_auth =
521  const unsigned char *serv_list =
523 
524  if (def_auth && serv_list)
525  {
526  DefaultAuthorityDescriptor authority(def_auth);
527  ServiceListDescriptor services(serv_list);
528  if (!authority.IsValid() || !services.IsValid())
529  continue;
530 
531  LOG(VB_CHANSCAN, LOG_INFO, LOC +
532  QString("Found default authority '%1' in BAT for services in %2 %3")
533  .arg(authority.DefaultAuthority())
534  .arg(netid).arg(tsid));
535 
536  for (uint j = 0; j < services.ServiceCount(); ++j)
537  {
538  // If the default authority is given in the SDT this
539  // overrides any definition in the BAT (or in the NIT)
540  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
541  QString("Found default authority '%1' in BAT for service %2 %3 %4")
542  .arg(authority.DefaultAuthority())
543  .arg(netid).arg(tsid).arg(services.ServiceID(j)));
544  uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
545  services.ServiceID(j);
546  if (! m_defAuthorities.contains(index))
547  m_defAuthorities[index] = authority.DefaultAuthority();
548  }
549  }
550  }
551  UpdateChannelInfo(true);
552 }
553 
555 {
556  QMutexLocker locker(&m_lock);
557 
558  LOG(VB_CHANSCAN, LOG_INFO, LOC +
559  QString("Got a Service Description Table (other) for Transport ID %1 section %2/%3")
560  .arg(tsid).arg(sdt->Section()).arg(sdt->LastSection()));
561  LogLines(sdt->toString());
562 
564 
565  uint netid = sdt->OriginalNetworkID();
566 
567  for (uint i = 0; i < sdt->ServiceCount(); ++i)
568  {
569  uint serviceId = sdt->ServiceID(i);
570  desc_list_t parsed =
572  sdt->ServiceDescriptorsLength(i));
573  // Look for default authority
574  const unsigned char *def_auth =
576  if (def_auth)
577  {
578  DefaultAuthorityDescriptor authority(def_auth);
579  if (!authority.IsValid())
580  continue;
581  LOG(VB_CHANSCAN, LOG_INFO, LOC +
582  QString("Found default authority '%1' in SDTo for service %2 %3 %4")
583  .arg(authority.DefaultAuthority())
584  .arg(netid).arg(tsid).arg(serviceId));
585  m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
586  authority.DefaultAuthority();
587  }
588  }
589 }
590 
591 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
592 {
593  QMutexLocker locker(&m_lock);
594 
596 
599 
600  UpdateChannelInfo(true);
601 }
602 
604 {
605  if (!m_currentInfo || m_currentInfo->m_pmts.empty())
606  {
607  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
609  return false;
610  }
611 
612  do
613  {
614  uint pnum = 0;
615  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
616 #if 0
617  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
618  .arg(currentEncryptionStatusChecked.size())
619  .arg(currentEncryptionStatus.size()));
620 #endif
621  while (it != m_currentEncryptionStatus.end())
622  {
623  if (!m_currentEncryptionStatusChecked[it.key()])
624  {
625  pnum = it.key();
626  break;
627  }
628  ++it;
629  }
630 
631  if (!pnum)
632  break;
633 
635 
636  if (!m_testDecryption)
637  {
639  continue;
640  }
641 
642  const ProgramMapTable *pmt = nullptr;
643  for (uint i = 0; !pmt && (i < m_currentInfo->m_pmts.size()); ++i)
644  {
645  pmt = (m_currentInfo->m_pmts[i]->ProgramNumber() == pnum) ?
646  m_currentInfo->m_pmts[i] : nullptr;
647  }
648 
649  if (pmt)
650  {
651  QString cur_chan;
652  QString cur_chan_tr;
653  GetCurrentTransportInfo(cur_chan, cur_chan_tr);
654 
655  QString msg_tr =
656  QObject::tr("%1 -- Testing decryption of program %2")
657  .arg(cur_chan_tr).arg(pnum);
658  QString msg =
659  QString("%1 -- Testing decryption of program %2")
660  .arg(cur_chan).arg(pnum);
661 
663  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
664 
665 #ifdef USING_DVB
666  if (GetDVBChannel())
667  GetDVBChannel()->SetPMT(pmt);
668 #endif // USING_DVB
669 
671 
673  m_timer.start();
674  return true;
675  }
676 
677  LOG(VB_GENERAL, LOG_INFO, LOC +
678  QString("Can't monitor decryption of program %1 -- no pmt")
679  .arg(pnum));
680 
681  } while (true);
682 
684  return false;
685 }
686 
688 {
691 
692  const DTVChannel *chan = GetDTVChannel();
693 
694  if (!chan)
695  return type;
696 
697  vector<DTVTunerType> tts = chan->GetTunerTypes();
698 
699  for (size_t i = 0; i < tts.size(); ++i)
700  {
701  if (tts[i] == type)
702  return type;
703  }
704 
705  if (!tts.empty())
706  return tts[0];
707 
708  return type;
709 }
710 
712 {
713  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
714  {
715  uint32_t tsid = nit->TSID(i);
716  uint32_t netid = nit->OriginalNetworkID(i);
717  uint32_t id = netid << 16 | tsid;
718 
719  if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
720  continue;
721 
722  const desc_list_t& list =
725 
726  for (size_t j = 0; j < list.size(); ++j)
727  {
728  int mplexid = -1;
729  uint64_t frequency = 0;
730  const MPEGDescriptor desc(list[j]);
731  uint tag = desc.DescriptorTag();
732  uint length = desc.DescriptorLength();
733  QString tagString = desc.DescriptorTagString();
734 
736 
737  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("NIT ts-loop j:%1 tag:%2 (0x%3) '%4' length:%5")
738  .arg(j).arg(tag).arg(tag,0,16).arg(tagString).arg(length));
739 
740  switch (tag)
741  {
743  {
745  frequency = cd.FrequencyHz();
747  break;
748  }
750  {
751  // Additional info in the T2 descriptor not yet used
752  continue;
753  }
755  {
756  const SatelliteDeliverySystemDescriptor cd(desc);
757  frequency = cd.FrequencykHz();
759  break;
760  }
762  {
763  // Additional info in the S2 descriptor not yet used
764  continue;
765  }
767  {
768  const CableDeliverySystemDescriptor cd(desc);
769  frequency = cd.FrequencyHz();
771  break;
772  }
773  default:
774  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
775  QString("Descriptor %1 (0x%2) '%3' ignored")
776  .arg(tag).arg(tag,0,16).arg(tagString));
777  continue;
778  }
779 
780  mplexid = ChannelUtil::GetMplexID(m_sourceID, frequency, tsid, netid);
781  mplexid = max(0, mplexid);
782 
783  tt = GuessDTVTunerType(tt);
784 
785  DTVMultiplex tuning;
786  if (mplexid)
787  {
788  if (!tuning.FillFromDB(tt, mplexid))
789  continue;
790  }
791  else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
792  {
793  continue;
794  }
795 
796  m_extendTransports[id] = tuning;
797  break;
798  }
799  }
800 }
801 
802 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
803 {
804  QMutexLocker locker(&m_mutex);
805 
806  if (m_current == m_scanTransports.end())
807  return true;
808 
809  if (wait_until_complete && !m_waitingForTables)
810  return true;
811 
812  if (wait_until_complete && m_currentTestingDecryption)
813  return false;
814 
816  if (!dtv_sm)
817  return false;
818 
819  const ScanStreamData *sd = dtv_sm->GetScanStreamData();
820 
821  if (!m_currentInfo)
823 
824  bool transport_tune_complete = true;
825 
826  // MPEG
827 
828  // Grab PAT tables
829  pat_vec_t pattmp = sd->GetCachedPATs();
830  QMap<uint,bool> tsid_checked;
831  for (size_t i = 0; i < pattmp.size(); ++i)
832  {
833  uint tsid = pattmp[i]->TransportStreamID();
834  if (tsid_checked[tsid])
835  continue;
836  tsid_checked[tsid] = true;
837  if (m_currentInfo->m_pats.contains(tsid))
838  continue;
839 
840  if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
841  {
842  m_currentInfo->m_pats[tsid] = sd->GetCachedPATs(tsid);
843  if (!m_currentInfo->m_pmts.empty())
844  {
846  m_currentInfo->m_pmts.clear();
847  }
848  }
849  else
850  transport_tune_complete = false;
851  }
852  transport_tune_complete &= !pattmp.empty();
853  sd->ReturnCachedPATTables(pattmp);
854 
855  // Grab PMT tables
856  if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
857  m_currentInfo->m_pmts.empty())
859 
860  // ATSC
861  if (!m_currentInfo->m_mgt && sd->HasCachedMGT())
863 
864  if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
865  m_currentInfo->m_cvcts.empty())
866  {
868  }
869 
870  if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
871  m_currentInfo->m_tvcts.empty())
872  {
874  }
875 
876  // DVB
877  if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
878  (m_currentInfo->m_nits.empty() ||
879  m_timer.elapsed() > (int)m_otherTableTime))
880  {
882  }
883 
884  sdt_vec_t sdttmp = sd->GetCachedSDTs();
885  tsid_checked.clear();
886  for (size_t i = 0; i < sdttmp.size(); ++i)
887  {
888  uint tsid = sdttmp[i]->TSID();
889  if (tsid_checked[tsid])
890  continue;
891  tsid_checked[tsid] = true;
892  if (m_currentInfo->m_sdts.contains(tsid))
893  continue;
894 
895  if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
896  m_currentInfo->m_sdts[tsid] = sd->GetCachedSDTSections(tsid);
897  }
898  sd->ReturnCachedSDTTables(sdttmp);
899 
900  if ((!wait_until_complete || sd->HasCachedAllBATs()) &&
901  (m_currentInfo->m_bats.empty() ||
902  m_timer.elapsed() > (int)m_otherTableTime))
903  {
905  }
906 
907  // Check if transport tuning is complete
908  if (transport_tune_complete)
909  {
910  transport_tune_complete &= !m_currentInfo->m_pmts.empty();
911  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
912  {
913  transport_tune_complete &= sd->HasCachedMGT();
914  transport_tune_complete &=
915  (!m_currentInfo->m_tvcts.empty() || !m_currentInfo->m_cvcts.empty());
916  }
917  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
918  {
919  transport_tune_complete &= !m_currentInfo->m_nits.empty();
920  transport_tune_complete &= !m_currentInfo->m_sdts.empty();
921  }
922  if (sd->HasCachedAnyBATs())
923  {
924  transport_tune_complete &= !m_currentInfo->m_bats.empty();
925  }
926  if (transport_tune_complete)
927  {
928  uint tsid = dtv_sm->GetTransportID();
929  LOG(VB_CHANSCAN, LOG_INFO, LOC +
930  QString("transport_tune_complete: ") +
931  QString("\n\t\t\tsd->HasCachedAnyNIT(): %1").arg(sd->HasCachedAnyNIT()) +
932  QString("\n\t\t\tsd->HasCachedAnySDTs(): %1").arg(sd->HasCachedAnySDTs()) +
933  QString("\n\t\t\tsd->HasCachedAnyBATs(): %1").arg(sd->HasCachedAnyBATs()) +
934  QString("\n\t\t\tsd->HasCachedAllPMTs(): %1").arg(sd->HasCachedAllPMTs()) +
935  QString("\n\t\t\tsd->HasCachedAllNIT(): %1").arg(sd->HasCachedAllNIT()) +
936  QString("\n\t\t\tsd->HasCachedAllSDT(%1): %2").arg(tsid,5).arg(sd->HasCachedAllSDT(tsid)) +
937  QString("\n\t\t\tsd->HasCachedAllBATs(): %1").arg(sd->HasCachedAllBATs()) +
938  QString("\n\t\t\tcurrentInfo->m_pmts.empty(): %1").arg(m_currentInfo->m_pmts.empty()) +
939  QString("\n\t\t\tcurrentInfo->m_nits.empty(): %1").arg(m_currentInfo->m_nits.empty()) +
940  QString("\n\t\t\tcurrentInfo->m_sdts.empty(): %1").arg(m_currentInfo->m_sdts.empty()) +
941  QString("\n\t\t\tcurrentInfo->m_bats.empty(): %1").arg(m_currentInfo->m_bats.empty()));
942  }
943  }
944  if (!wait_until_complete)
945  transport_tune_complete = true;
946  if (transport_tune_complete)
947  {
948  LOG(VB_CHANSCAN, LOG_INFO, LOC +
949  QString("transport_tune_complete: wait_until_complete %1")
950  .arg(wait_until_complete));
951  }
952 
953  if (transport_tune_complete && !m_currentEncryptionStatus.empty())
955  {
956  //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
957 
959  return false;
960 
961  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
962  for (; it != m_currentEncryptionStatus.end(); ++it)
963  {
964  m_currentInfo->m_programEncryptionStatus[it.key()] = *it;
965 
966  if (m_testDecryption)
967  {
968  QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
969  QString msg_tr2 = QObject::tr("Unknown decryption status");
970  if (kEncEncrypted == *it)
971  msg_tr2 = QObject::tr("Encrypted");
972  else if (kEncDecrypted == *it)
973  msg_tr2 = QObject::tr("Decrypted");
974  QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
976  }
977 
978  QString msg = QString("Program %1").arg(it.key());
979  if (kEncEncrypted == *it)
980  msg = msg + " -- Encrypted";
981  else if (kEncDecrypted == *it)
982  msg = msg + " -- Decrypted";
983  else if (kEncUnknown == *it)
984  msg = msg + " -- Unknown decryption status";
985 
986  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
987  }
988  }
989 
990  // Append transports from the NIT to the scan list
991  if (transport_tune_complete && m_extendScanList &&
992  !m_currentInfo->m_nits.empty())
993  {
994  // Update transport with delivery system descriptors from the NIT
995  nit_vec_t::const_iterator it = m_currentInfo->m_nits.begin();
996  while (it != m_currentInfo->m_nits.end())
997  {
999  ++it;
1000  }
1001  }
1002 
1003  // Start scanning next transport if we are done with this one..
1004  if (transport_tune_complete)
1005  {
1006  QString cchan;
1007  QString cchan_tr;
1008  uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
1009  m_channelsFound += cchan_cnt;
1010  QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
1011  QString chan = QString( "%1 -- Timed out").arg(cchan);
1012  QString msg_tr = "";
1013  QString msg = "";
1014 
1015  if (!m_currentInfo->IsEmpty())
1016  {
1017  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1018  QString("Adding %1, offset %2 to channelList.")
1019  .arg((*m_current).m_tuning.toString()).arg(m_current.offset()));
1020 
1021  TransportScanItem &item = *m_current;
1023 
1024  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
1025  QString("%1(%2) m_inputName: %3 ").arg(__FUNCTION__).arg(__LINE__).arg(m_inputName) +
1026  QString("m_mod_sys:%1 %2").arg(item.m_tuning.m_modSys).arg(item.m_tuning.m_modSys.toString()));
1027 
1029  {
1030  if (m_dvbt2Tried)
1032  else
1034  }
1035 
1037  m_currentInfo = nullptr;
1038  }
1039  else
1040  {
1041  delete m_currentInfo;
1042  m_currentInfo = nullptr;
1043  }
1044 
1046  if (HasTimedOut())
1047  {
1048  msg_tr = (cchan_cnt) ?
1049  QObject::tr("%1 possible channels").arg(cchan_cnt) :
1050  QObject::tr("no channels");
1051  msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
1052  msg = (cchan_cnt) ?
1053  QString("%1 possible channels").arg(cchan_cnt) :
1054  QString("no channels");
1055  msg = QString("%1, %2").arg(chan_tr).arg(msg);
1056  }
1057  else if ((m_current != m_scanTransports.end()) &&
1058  (m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1059  sm && !sm->HasSignalLock())
1060  {
1061  msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1062  msg = QString("%1, no signal").arg(chan);
1063  }
1064  else
1065  {
1066  msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1067  .arg(cchan_tr).arg(cchan_cnt);
1068 
1069  msg = QString("%1 -- Found %2 probable channels")
1070  .arg(cchan).arg(cchan_cnt);
1071  }
1072 
1074  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1075 
1076  m_currentEncryptionStatus.clear();
1078 
1079  m_setOtherTables = false;
1080  m_otherTableTime = 0;
1081 
1082  if (m_scanning)
1083  {
1086  m_waitingForTables = false;
1088  m_dvbt2Tried = true;
1089  }
1090  else
1091  {
1094  }
1095 
1096  return true;
1097  }
1098 
1099  return false;
1100 }
1101 
1102 #define PCM_INFO_INIT(SISTD) \
1103  ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1104  info.m_db_mplexid = mplexid; info.m_source_id = m_sourceID; \
1105  info.m_service_id = pnum; info.m_freqid = freqidStr; \
1106  info.m_si_standard = SISTD;
1107 
1108 static void update_info(ChannelInsertInfo &info,
1109  const VirtualChannelTable *vct, uint i)
1110 {
1111  if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1112  vct->ServiceType(i) == 0x01 /* Analog TV */)
1113  {
1114  info.m_si_standard = "ntsc";
1115  info.m_format = "ntsc";
1116  }
1117 
1118  info.m_callsign = vct->ShortChannelName(i);
1119 
1120  info.m_service_name = vct->GetExtendedChannelName(i);
1121  if (info.m_service_name.isEmpty())
1122  info.m_service_name = vct->ShortChannelName(i);
1123 
1124  info.m_chan_num.clear();
1125 
1126  info.m_service_id = vct->ProgramNumber(i);
1127  info.m_atsc_major_channel = vct->MajorChannel(i);
1128  info.m_atsc_minor_channel = vct->MinorChannel(i);
1129 
1130  info.m_use_on_air_guide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1131 
1132  info.m_hidden = vct->IsHidden(i);
1133  info.m_hidden_in_guide = vct->IsHiddenInGuide(i);
1134 
1135  info.m_vct_tsid = vct->TransportStreamID();
1137  info.m_is_encrypted |= vct->IsAccessControlled(i);
1138  info.m_is_data_service = vct->ServiceType(i) == 0x04;
1139  info.m_is_audio_service = vct->ServiceType(i) == 0x03;
1140 
1141  info.m_in_vct = true;
1142 }
1143 
1144 static void update_info(ChannelInsertInfo &info,
1145  const ServiceDescriptionTable *sdt, uint i,
1146  const QMap<uint64_t, QString> &defAuthorities)
1147 {
1148  // HACK beg -- special exception for these networks
1149  // this enables useonairguide by default for all matching channels
1150  // (dbver == "1067")
1151  bool force_guide_present = (
1152  // Telenor (NO)
1154 #if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1155  // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1156  (sdt->OriginalNetworkID() == 222) ||
1157 #endif
1158  // ERT (GR) from the private temporary allocation, see #9592:comment:17
1159  (sdt->OriginalNetworkID() == 65330) ||
1160  // Digitenne (NL) see #13427
1162  );
1163  // HACK end -- special exception for these networks
1164 
1165  // Figure out best service name and callsign...
1166  ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
1167  QString callsign;
1168  QString service_name;
1169  if (desc)
1170  {
1171  callsign = desc->ServiceShortName();
1172  if (callsign.trimmed().isEmpty())
1173  callsign = QString("%1-%2-%3")
1174  .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1175  .arg(sdt->ServiceID(i));
1176 
1177  service_name = desc->ServiceName();
1178  if (service_name.trimmed().isEmpty())
1179  service_name.clear();
1180 
1181  info.m_service_type = desc->ServiceType();
1182  info.m_is_data_service =
1183  (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1184  info.m_is_audio_service = (desc && desc->IsDigitalAudio());
1185  delete desc;
1186  }
1187  else
1188  {
1189  LOG(VB_CHANSCAN, LOG_INFO, "ChannelScanSM: " +
1190  QString("No ServiceDescriptor for onid %1 tid %2 sid %3")
1191  .arg(sdt->OriginalNetworkID()).arg(sdt->TSID()).arg(sdt->ServiceID(i)));
1192  }
1193 
1194  if (info.m_callsign.isEmpty())
1195  info.m_callsign = callsign;
1196  if (info.m_service_name.isEmpty())
1197  info.m_service_name = service_name;
1198 
1199  info.m_use_on_air_guide =
1200  sdt->HasEITPresentFollowing(i) ||
1201  sdt->HasEITSchedule(i) ||
1202  force_guide_present;
1203 
1204  info.m_hidden = false;
1205  info.m_hidden_in_guide = false;
1206  info.m_service_id = sdt->ServiceID(i);
1207  info.m_sdt_tsid = sdt->TSID();
1208  info.m_orig_netid = sdt->OriginalNetworkID();
1209  info.m_in_sdt = true;
1210 
1211  desc_list_t parsed =
1213  sdt->ServiceDescriptorsLength(i));
1214  // Look for default authority
1215  const unsigned char *def_auth =
1217  if (def_auth)
1218  {
1219  DefaultAuthorityDescriptor authority(def_auth);
1220  if (authority.IsValid())
1221  {
1222  LOG(VB_CHANSCAN, LOG_INFO,
1223  QString("ChannelScanSM: Found default authority '%1' in SDT for service %2 %3 %4")
1224  .arg(authority.DefaultAuthority())
1225  .arg(info.m_orig_netid).arg(info.m_sdt_tsid).arg(info.m_service_id));
1226  info.m_default_authority = authority.DefaultAuthority();
1227  return;
1228  }
1229  }
1230 
1231  // If no authority in the SDT then use the one found in the BAT or the SDTo
1232  uint64_t index = (uint64_t)info.m_orig_netid << 32 |
1233  info.m_sdt_tsid << 16 | info.m_service_id;
1234  if (defAuthorities.contains(index))
1235  info.m_default_authority = defAuthorities[index];
1236 }
1237 
1239  QString &cur_chan, QString &cur_chan_tr) const
1240 {
1241  if (m_current.iter() == m_scanTransports.end())
1242  {
1243  cur_chan.clear();
1244  cur_chan_tr.clear();
1245  return 0;
1246  }
1247 
1248  uint max_chan_cnt = 0;
1249 
1250  QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1251  {
1252  for (int i = 0; i < list.size(); ++i)
1253  {
1254  max_chan_cnt +=
1255  (list[i].m_in_pat || list[i].m_in_pmt ||
1256  list[i].m_in_sdt || list[i].m_in_vct) ? 1 : 0;
1257  }
1258  }
1259 
1260  QString offset_str_tr = m_current.offset() ?
1261  QObject::tr(" offset %2").arg(m_current.offset()) : "";
1262  cur_chan_tr = QString("%1%2")
1263  .arg((*m_current).m_friendlyName).arg(offset_str_tr);
1264 
1265  QString offset_str = m_current.offset() ?
1266  QString(" offset %2").arg(m_current.offset()) : "";
1267  cur_chan = QString("%1%2")
1268  .arg((*m_current).m_friendlyName).arg(offset_str);
1269 
1270  return max_chan_cnt;
1271 }
1272 
1273 QMap<uint,ChannelInsertInfo>
1275  ScannedChannelInfo *scan_info) const
1276 {
1277  QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1278 
1279  uint mplexid = (*trans_info).m_mplexid;
1280  int freqid = (*trans_info).m_friendlyNum;
1281  QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1282  QString iptv_channel = (*trans_info).m_iptvChannel;
1283 
1284  // channels.conf
1285  const DTVChannelInfoList &echan = (*trans_info).m_expectedChannels;
1286  for (size_t i = 0; i < echan.size(); ++i)
1287  {
1288  uint pnum = echan[i].m_serviceid;
1289  PCM_INFO_INIT("mpeg");
1290  info.m_service_name = echan[i].m_name;
1291  info.m_in_channels_conf = true;
1292  }
1293 
1294  // PATs
1295  pat_map_t::const_iterator pat_list_it = scan_info->m_pats.begin();
1296  for (; pat_list_it != scan_info->m_pats.end(); ++pat_list_it)
1297  {
1298  auto pat_it = (*pat_list_it).cbegin();
1299  for (; pat_it != (*pat_list_it).cend(); ++pat_it)
1300  {
1301  bool could_be_opencable = false;
1302  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1303  {
1304  if (((*pat_it)->ProgramNumber(i) == 0) &&
1305  ((*pat_it)->ProgramPID(i) == 0x1ffc))
1306  {
1307  could_be_opencable = true;
1308  }
1309  }
1310 
1311  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1312  {
1313  uint pnum = (*pat_it)->ProgramNumber(i);
1314  if (pnum)
1315  {
1316  PCM_INFO_INIT("mpeg");
1317  info.m_pat_tsid = (*pat_it)->TransportStreamID();
1318  info.m_could_be_opencable = could_be_opencable;
1319  info.m_in_pat = true;
1320  }
1321  }
1322  }
1323  }
1324 
1325  // PMTs
1326  pmt_vec_t::const_iterator pmt_it = scan_info->m_pmts.begin();
1327  for (; pmt_it != scan_info->m_pmts.end(); ++pmt_it)
1328  {
1329  const ProgramMapTable *pmt = *pmt_it;
1330  uint pnum = pmt->ProgramNumber();
1331  PCM_INFO_INIT("mpeg");
1332  for (uint i = 0; i < pmt->StreamCount(); ++i)
1333  {
1334  info.m_could_be_opencable |=
1335  (StreamID::OpenCableVideo == pmt->StreamType(i));
1336  }
1337 
1339  pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1341 
1342  for (size_t i = 0; i < descs.size(); ++i)
1343  {
1344  RegistrationDescriptor reg(descs[i]);
1345  if (!reg.IsValid())
1346  continue;
1347  if (reg.FormatIdentifierString() == "CUEI" ||
1348  reg.FormatIdentifierString() == "SCTE")
1349  info.m_could_be_opencable = true;
1350  }
1351 
1352  info.m_is_encrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1353  info.m_in_pmt = true;
1354  }
1355 
1356  // Cable VCTs
1357  cvct_vec_t::const_iterator cvct_it = scan_info->m_cvcts.begin();
1358  for (; cvct_it != scan_info->m_cvcts.end(); ++cvct_it)
1359  {
1360  for (uint i = 0; i < (*cvct_it)->ChannelCount(); ++i)
1361  {
1362  uint pnum = (*cvct_it)->ProgramNumber(i);
1363  PCM_INFO_INIT("atsc");
1364  update_info(info, *cvct_it, i);
1365  }
1366  }
1367 
1368  // Terrestrial VCTs
1369  tvct_vec_t::const_iterator tvct_it = scan_info->m_tvcts.begin();
1370  for (; tvct_it != scan_info->m_tvcts.end(); ++tvct_it)
1371  {
1372  for (uint i = 0; i < (*tvct_it)->ChannelCount(); ++i)
1373  {
1374  uint pnum = (*tvct_it)->ProgramNumber(i);
1375  PCM_INFO_INIT("atsc");
1376  update_info(info, *tvct_it, i);
1377  }
1378  }
1379 
1380  // SDTs
1381  sdt_map_t::const_iterator sdt_list_it = scan_info->m_sdts.begin();
1382  for (; sdt_list_it != scan_info->m_sdts.end(); ++sdt_list_it)
1383  {
1384  auto sdt_it = (*sdt_list_it).cbegin();
1385  for (; sdt_it != (*sdt_list_it).cend(); ++sdt_it)
1386  {
1387  for (uint i = 0; i < (*sdt_it)->ServiceCount(); ++i)
1388  {
1389  uint pnum = (*sdt_it)->ServiceID(i);
1390  PCM_INFO_INIT("dvb");
1391  update_info(info, *sdt_it, i, m_defAuthorities);
1392  }
1393  }
1394  }
1395 
1396  // NIT
1397  QMap<qlonglong, uint> ukChanNums;
1398  QMap<qlonglong, uint> scnChanNums;
1399  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1400  for (dbchan_it = pnum_to_dbchan.begin();
1401  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1402  {
1403  ChannelInsertInfo &info = *dbchan_it;
1404 
1405  // NIT
1406  nit_vec_t::const_iterator nits_it = scan_info->m_nits.begin();
1407  for (; nits_it != scan_info->m_nits.end(); ++nits_it)
1408  {
1409  for (uint i = 0; i < (*nits_it)->TransportStreamCount(); ++i)
1410  {
1411  const NetworkInformationTable *nit = (*nits_it);
1412  if ((nit->TSID(i) == info.m_sdt_tsid) &&
1413  (nit->OriginalNetworkID(i) == info.m_orig_netid))
1414  {
1415  info.m_netid = nit->NetworkID();
1416  info.m_in_nit = true;
1417  }
1418  else
1419  {
1420  continue;
1421  }
1422 
1423  // Get channel numbers from UK Frequency List Descriptors
1424  const desc_list_t &list =
1426  nit->TransportDescriptorsLength(i));
1427 
1428  // Logical channel numbers
1429  {
1430  const unsigned char *desc =
1433 
1434  if (desc)
1435  {
1436  DVBLogicalChannelDescriptor uklist(desc);
1437  if (!uklist.IsValid())
1438  continue;
1439  for (uint j = 0; j < uklist.ChannelCount(); ++j)
1440  {
1441  ukChanNums[((qlonglong)info.m_orig_netid<<32) |
1442  uklist.ServiceID(j)] =
1443  uklist.ChannelNumber(j);
1444  }
1445  }
1446  }
1447 
1448  // HD Simulcast logical channel numbers
1449  {
1450  const unsigned char *desc =
1453 
1454  if (desc)
1455  {
1456  DVBSimulcastChannelDescriptor scnlist(desc);
1457  if (!scnlist.IsValid())
1458  continue;
1459  for (uint j = 0; j < scnlist.ChannelCount(); ++j)
1460  {
1461  scnChanNums[((qlonglong)info.m_orig_netid<<32) |
1462  scnlist.ServiceID(j)] =
1463  scnlist.ChannelNumber(j);
1464  }
1465  }
1466  }
1467  }
1468  }
1469  }
1470 
1471  // BAT
1472 
1473  // Channel numbers for Freesat and BSkyB on Astra 28.2E
1474  //
1475  // Get the Logical Channel Number (LCN) information from the BAT.
1476  // The first filter is on the bouquet ID.
1477  // Then collect all LCN for the selected region and
1478  // for the common (undefined) region with id 0xFFFF.
1479  // The LCN of the selected region has priority; if
1480  // a service is not defined there then the value of the LCN
1481  // table of the common region is used.
1482  // This works because the BAT of each transport contains
1483  // the LCN of all transports and services for all bouquets.
1484  //
1485  // For reference, this website has the Freesat and BSkyB channel numbers
1486  // for each bouquet and region:
1487  // https://www.satellite-calculations.com/DVB/28.2E/28E_FreeSat_ChannelNumber.php
1488  // https://www.satellite-calculations.com/DVB/28.2E/28E_Sky_ChannelNumber.php
1489  //
1490 
1491  // Lookup table from LCN to service ID
1492  QMap<uint,qlonglong> lcn_sid;
1493 
1494  bat_vec_t::const_iterator bats_it = scan_info->m_bats.begin();
1495  for (; bats_it != scan_info->m_bats.end(); ++bats_it)
1496  {
1497  const BouquetAssociationTable *bat = *bats_it;
1498 
1499  // Only the bouquet selected by user
1500  if (bat->BouquetID() != m_bouquet_id)
1501  continue;
1502 
1503  for (uint t = 0; t < bat->TransportStreamCount(); ++t)
1504  {
1505  uint netid = bat->OriginalNetworkID(t);
1506 
1507  if (!(netid == OriginalNetworkID::SES2 || netid == OriginalNetworkID::BBC))
1508  continue;
1509 
1510  desc_list_t parsed =
1513 
1514  uint priv_dsid = 0;
1515  desc_list_t::const_iterator it = parsed.begin();
1516  for (; it != parsed.end(); ++it)
1517  {
1518  if ((*it)[0] == DescriptorID::private_data_specifier)
1519  {
1521  if (pd.IsValid())
1522  priv_dsid = pd.PrivateDataSpecifier();
1523  }
1524 
1525  // Freesat logical channels
1526  if (priv_dsid == PrivateDataSpecifierID::FSAT &&
1528  {
1529  FreesatLCNDescriptor ld(*it);
1530  if (ld.IsValid())
1531  {
1532  for (uint i = 0; i<ld.ServiceCount(); i++)
1533  {
1534  uint service_id = ld.ServiceID(i);
1535  for (uint j=0; j<ld.LCNCount(i); j++)
1536  {
1537  uint region_id = ld.RegionID(i,j);
1538  uint lcn = ld.LogicalChannelNumber(i,j);
1539  if (region_id == m_region_id)
1540  {
1541  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1542  }
1543  else if (region_id == kRegionUndefined)
1544  {
1545  if (lcn_sid.value(lcn,0) == 0)
1546  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1547  }
1548  }
1549  }
1550  }
1551  }
1552 
1553  // BSkyB logical channels
1554  if (priv_dsid == PrivateDataSpecifierID::BSB1 &&
1556  {
1557  BSkyBLCNDescriptor ld(*it);
1558  if (ld.IsValid())
1559  {
1560  uint region_id = ld.RegionID();
1561  for (uint i = 0; i<ld.ServiceCount(); i++)
1562  {
1563  uint service_id = ld.ServiceID(i);
1564  uint lcn = ld.LogicalChannelNumber(i);
1565  if (region_id == m_region_id)
1566  {
1567  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1568  }
1569  else if (region_id == kRegionUndefined)
1570  {
1571  if (lcn_sid.value(lcn,0) == 0)
1572  lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1573  }
1574 #if 0
1575  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1576  QString("LCN bid:%1 tid:%2 rid:%3 sid:%4 lcn:%5")
1577  .arg(bat->BouquetID()).arg(bat->TSID(t)).arg(region_id).arg(service_id).arg(lcn));
1578 #endif
1579  }
1580  }
1581  }
1582  }
1583  }
1584  }
1585 
1586  // Create the reverse table from service id to LCN.
1587  // If the service has more than one logical
1588  // channel number the lowest number is used.
1589  QMap<qlonglong, uint> sid_lcn;
1590  QMap<uint, qlonglong>::const_iterator r = lcn_sid.constEnd();
1591  while (r != lcn_sid.constBegin())
1592  {
1593  --r;
1594  qlonglong sid = r.value();
1595  uint lcn = r.key();
1596  sid_lcn[sid] = lcn;
1597  }
1598 
1599  // ------------------------------------------------------------------------
1600 
1601  // Get IPTV channel numbers
1602  for (dbchan_it = pnum_to_dbchan.begin();
1603  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1604  {
1605  ChannelInsertInfo &info = *dbchan_it;
1606 
1607  if (!info.m_chan_num.isEmpty())
1608  continue;
1609 
1610  if (!iptv_channel.isEmpty())
1611  {
1612  info.m_chan_num = iptv_channel;
1613  if (info.m_service_id)
1614  info.m_chan_num += "-" + QString::number(info.m_service_id);
1615  }
1616  }
1617 
1618  // Get DVB Logical Channel Numbers
1619  for (dbchan_it = pnum_to_dbchan.begin();
1620  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1621  {
1622  ChannelInsertInfo &info = *dbchan_it;
1623 
1624  if (!info.m_chan_num.isEmpty())
1625  continue;
1626 
1627  // DVB HD Simulcast channel numbers
1628  //
1629  // The HD simulcast channel number table gives the correct channel number
1630  // when HD and SD versions of the same channel are simultaneously broadcast
1631  // and the receiver is capable of receiving the HD signal.
1632  // The latter is assumed correct for a MythTV system.
1633  //
1634  if (info.m_chan_num.isEmpty())
1635  {
1636  qlonglong key = ((qlonglong)info.m_orig_netid<<32) | info.m_service_id;
1637  QMap<qlonglong, uint>::const_iterator it = scnChanNums.find(key);
1638 
1639  if (it != scnChanNums.end())
1640  {
1641  info.m_chan_num = QString::number(*it);
1642  }
1643  }
1644 
1645  // DVB Logical Channel Numbers (a.k.a. UK channel numbers)
1646  if (info.m_chan_num.isEmpty())
1647  {
1648  qlonglong key = ((qlonglong)info.m_orig_netid<<32) | info.m_service_id;
1649  QMap<qlonglong, uint>::const_iterator it = ukChanNums.find(key);
1650 
1651  if (it != ukChanNums.end())
1652  {
1653  info.m_chan_num = QString::number(*it);
1654  }
1655  }
1656 
1657  // DVB satellite Astra 28.2E Freesat or BSkyB channel numbers
1658  if (info.m_chan_num.isEmpty())
1659  {
1660  qlonglong key = ((qlonglong)info.m_orig_netid<<32) | info.m_service_id;
1661  QMap<qlonglong, uint>::const_iterator it = sid_lcn.find(key);
1662 
1663  if (it != sid_lcn.end())
1664  {
1665  info.m_chan_num = QString::number(*it);
1666  }
1667  }
1668 
1669  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1670  QString("GetChannelList: service %1 (0x%2) chan_num '%3' callsign '%4'")
1671  .arg(info.m_service_id).arg(info.m_service_id,4,16,QChar('0'))
1672  .arg(info.m_chan_num).arg(info.m_callsign));
1673  }
1674 
1675  // Get QAM/SCTE/MPEG channel numbers
1676  for (dbchan_it = pnum_to_dbchan.begin();
1677  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1678  {
1679  ChannelInsertInfo &info = *dbchan_it;
1680 
1681  if (!info.m_chan_num.isEmpty())
1682  continue;
1683 
1684  if ((info.m_si_standard == "mpeg") ||
1685  (info.m_si_standard == "scte") ||
1686  (info.m_si_standard == "opencable"))
1687  {
1688  if (info.m_freqid.isEmpty())
1689  info.m_chan_num = QString("%1-%2")
1690  .arg(info.m_source_id)
1691  .arg(info.m_service_id);
1692  else
1693  info.m_chan_num = QString("%1-%2")
1694  .arg(info.m_freqid)
1695  .arg(info.m_service_id);
1696  }
1697  }
1698 
1699  // Check for decryption success
1700  for (dbchan_it = pnum_to_dbchan.begin();
1701  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1702  {
1703  uint pnum = dbchan_it.key();
1704  ChannelInsertInfo &info = *dbchan_it;
1705  info.m_decryption_status = scan_info->m_programEncryptionStatus[pnum];
1706  }
1707 
1708  return pnum_to_dbchan;
1709 }
1710 
1712 {
1713  ScanDTVTransportList list;
1714 
1715  uint cardid = m_channel->GetInputID();
1716 
1718  tuner_type = GuessDTVTunerType(tuner_type);
1719 
1720  ChannelList::const_iterator it = m_channelList.begin();
1721  for (; it != m_channelList.end(); ++it)
1722  {
1723  QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1724  GetChannelList(it->first, it->second);
1725 
1726  ScanDTVTransport item((*it->first).m_tuning, tuner_type, cardid);
1727  item.m_iptvTuning = (*(it->first)).m_iptvTuning;
1728 
1729  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1730  for (dbchan_it = pnum_to_dbchan.begin();
1731  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1732  {
1733  item.m_channels.push_back(*dbchan_it);
1734  }
1735 
1736  if (!item.m_channels.empty())
1737  {
1738  if (addFullTS)
1739  {
1740  /* If addFullTS, then add a 'MPTS' channel
1741  which can be used to record the entire MPTS from
1742  the transport. */
1743  dbchan_it = pnum_to_dbchan.begin();
1744  ChannelInsertInfo info = *dbchan_it;
1745 
1746  // Use transport stream ID as (fake) service ID
1747  // to use in callsign and as channel number
1748  info.m_service_id = info.m_sdt_tsid ? info.m_sdt_tsid : info.m_pat_tsid;
1749 
1750  if (tuner_type == DTVTunerType::kTunerTypeASI)
1751  info.m_callsign = QString("MPTS_%1")
1752  .arg(CardUtil::GetDisplayName(cardid));
1753  else if (info.m_si_standard == "mpeg" ||
1754  info.m_si_standard == "scte" ||
1755  info.m_si_standard == "opencable")
1756  info.m_callsign = QString("MPTS_%1").arg(info.m_freqid);
1757  else if (info.m_atsc_major_channel > 0)
1758  info.m_callsign =
1759  QString("MPTS_%1").arg(info.m_atsc_major_channel);
1760  else if (info.m_service_id > 0)
1761  info.m_callsign = QString("MPTS_%1").arg(info.m_service_id);
1762  else if (!info.m_chan_num.isEmpty())
1763  info.m_callsign = QString("MPTS_%1").arg(info.m_chan_num);
1764  else
1765  info.m_callsign = "MPTS_UNKNOWN";
1766 
1767  info.m_service_name = info.m_callsign;
1768  info.m_atsc_minor_channel = 0;
1769  info.m_format = "MPTS";
1770  info.m_use_on_air_guide = false;
1771  info.m_is_encrypted = false;
1772  item.m_channels.push_back(info);
1773  }
1774 
1775  list.push_back(item);
1776  }
1777  }
1778 
1779  return list;
1780 }
1781 
1782 
1784 {
1785  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1786 }
1787 
1789 {
1790 #ifdef USING_DVB
1791  return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1792 #else
1793  return nullptr;
1794 #endif
1795 }
1796 
1798 {
1799  return dynamic_cast<DTVChannel*>(m_channel);
1800 }
1801 
1803 {
1804  return dynamic_cast<const DTVChannel*>(m_channel);
1805 }
1806 
1808 {
1809 #ifdef USING_HDHOMERUN
1810  return dynamic_cast<HDHRChannel*>(m_channel);
1811 #else
1812  return nullptr;
1813 #endif
1814 }
1815 
1817 {
1818 #ifdef USING_DVB
1819  return dynamic_cast<DVBChannel*>(m_channel);
1820 #else
1821  return nullptr;
1822 #endif
1823 }
1824 
1826 {
1827 #ifdef USING_DVB
1828  return dynamic_cast<const DVBChannel*>(m_channel);
1829 #else
1830  return nullptr;
1831 #endif
1832 }
1833 
1835 {
1836 #ifdef USING_V4L2
1837  return dynamic_cast<V4LChannel*>(m_channel);
1838 #else
1839  return nullptr;
1840 #endif
1841 }
1842 
1847 {
1848  while (m_scannerThread)
1849  {
1850  m_threadExit = true;
1851  if (m_scannerThread->wait(1000))
1852  {
1853  delete m_scannerThread;
1854  m_scannerThread = nullptr;
1855  }
1856  }
1857  m_threadExit = false;
1858  m_scannerThread = new MThread("Scanner", this);
1860 }
1861 
1866 {
1867  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
1868 
1869  while (!m_threadExit)
1870  {
1871  if (m_scanning)
1872  HandleActiveScan();
1873 
1874  usleep(10 * 1000);
1875  }
1876 
1877  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
1878 }
1879 
1880 // See if we have timed out
1882 {
1884  (m_timer.elapsed() > kDecryptionTimeout))
1885  {
1887  return true;
1888  }
1889 
1890  if (!m_waitingForTables)
1891  return true;
1892 
1893 #ifdef USING_DVB
1894  // If the rotor is still moving, reset the timer and keep waiting
1896  if (sigmon)
1897  {
1898  const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
1899  if (rotor)
1900  {
1901  bool was_moving;
1902  bool is_moving;
1903  sigmon->GetRotorStatus(was_moving, is_moving);
1904  if (was_moving && !is_moving)
1905  {
1906  m_timer.restart();
1907  return false;
1908  }
1909  }
1910  }
1911 #endif // USING_DVB
1912 
1913 
1914  // have the tables have timed out?
1915  if (m_timer.elapsed() > (int)m_channelTimeout)
1916  {
1917  // the channelTimeout alone is only valid if we have seen no tables..
1918  const ScanStreamData *sd = nullptr;
1919  if (GetDTVSignalMonitor())
1921 
1922  if (!sd)
1923  return true;
1924 
1925  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
1926  return m_timer.elapsed() > (int) kDVBTableTimeout;
1927  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
1928  return m_timer.elapsed() > (int) kATSCTableTimeout;
1929  if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
1930  return m_timer.elapsed() > (int) kMPEGTableTimeout;
1931 
1932  return true;
1933  }
1934 
1935  // ok the tables haven't timed out, but have we hit the signal timeout?
1937  if ((m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1938  sm && !sm->HasSignalLock())
1939  {
1940  const ScanStreamData *sd = nullptr;
1941  if (GetDTVSignalMonitor())
1943 
1944  if (!sd)
1945  return true;
1946 
1947  // Just is case we temporarily lose the signal after we've seen
1948  // tables...
1949  if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
1950  !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
1951  !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
1952  {
1953  return true;
1954  }
1955  }
1956 
1957  return false;
1958 }
1959 
1964 {
1965  QMutexLocker locker(&m_lock);
1966 
1967  bool do_post_insertion = m_waitingForTables;
1968 
1969  if (!HasTimedOut())
1970  return;
1971 
1972  if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
1973  {
1974  m_channelList.clear();
1975  m_channelsFound = 0;
1976  m_dvbt2Tried = true;
1977  }
1978 
1980  {
1981  // If we failed to get a lock with DVB-T try DVB-T2.
1982  m_dvbt2Tried = true;
1984  return;
1985  }
1986 
1987  if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
1988  {
1989  // Add channel to scanned list and potentially check decryption
1990  if (do_post_insertion && !UpdateChannelInfo(false))
1991  return;
1992 
1993  // Stop signal monitor for previous transport
1994  locker.unlock();
1995  m_signalMonitor->Stop();
1996  locker.relock();
1997  }
1998 
1999  m_current = m_nextIt; // Increment current
2000  m_dvbt2Tried = false;
2001 
2002  if (m_current != m_scanTransports.end())
2003  {
2005 
2006  // Increment nextIt
2007  m_nextIt = m_current;
2008  ++m_nextIt;
2009  }
2010  else if (!m_extendTransports.isEmpty())
2011  {
2012  --m_current;
2013  QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
2014  while (it != m_extendTransports.end())
2015  {
2016  if (!m_tsScanned.contains(it.key()))
2017  {
2018  QString name = QString("TransportID %1").arg(it.key() & 0xffff);
2019  TransportScanItem item(m_sourceID, name, *it, m_signalTimeout);
2020  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
2021  item.m_tuning.toString());
2022  m_scanTransports.push_back(item);
2023  m_tsScanned.insert(it.key());
2024  }
2025  ++it;
2026  }
2027  m_extendTransports.clear();
2028  m_nextIt = m_current;
2029  ++m_nextIt;
2030  }
2031  else
2032  {
2034  m_scanning = false;
2036  }
2037 }
2038 
2040 {
2041  const TransportScanItem &item = *transport;
2042 
2043 #ifdef USING_DVB
2044  if (GetDVBSignalMonitor())
2045  {
2046  // always wait for rotor to finish
2049  }
2050 #endif // USING_DVB
2051 
2052  if (!GetDTVChannel())
2053  return false;
2054 
2055  if (item.m_mplexid > 0 && transport.offset() == 0)
2057 
2058  if (item.m_tuning.m_sistandard == "MPEG")
2059  return GetDTVChannel()->Tune(item.m_iptvTuning, true);
2060 
2061  const uint64_t freq = item.freq_offset(transport.offset());
2062  DTVMultiplex tuning = item.m_tuning;
2063  tuning.m_frequency = freq;
2064 
2066  {
2068  }
2070  {
2071  if (m_dvbt2Tried)
2073  else
2075  }
2076 
2077  return GetDTVChannel()->Tune(tuning);
2078 }
2079 
2081 {
2082  QString offset_str = (transport.offset()) ?
2083  QObject::tr(" offset %2").arg(transport.offset()) : "";
2084  QString cur_chan = QString("%1%2")
2085  .arg((*m_current).m_friendlyName).arg(offset_str);
2086  QString tune_msg_str =
2087  QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
2088  .arg(cur_chan).arg((*m_current).m_mplexid);
2089 
2090  const TransportScanItem &item = *transport;
2091 
2092  if (transport.offset() &&
2093  (item.freq_offset(transport.offset()) == item.freq_offset(0)))
2094  {
2095  m_waitingForTables = false;
2096  return; // nothing to do
2097  }
2098 
2099  if (m_channelsFound)
2100  {
2101  QString progress = QObject::tr(": Found %n", "", m_channelsFound);
2103  }
2104 
2106  LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
2107 
2108  if (!Tune(transport))
2109  { // If we did not tune successfully, bail with message
2111  LOG(VB_CHANSCAN, LOG_ERR, LOC +
2112  QString("Failed to tune %1 mplexid(%2) at offset %3")
2113  .arg(item.m_friendlyName).arg(item.m_mplexid)
2114  .arg(transport.offset()));
2115  return;
2116  }
2117 
2118  // If we have a DTV Signal Monitor, perform table scanner reset
2119  if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
2120  {
2122  GetDTVSignalMonitor()->SetChannel(-1,-1);
2123  GetDTVSignalMonitor()->SetDVBService(0, 0, -1);
2124  }
2125 
2126  // Start signal monitor for this channel
2128 
2129  m_timer.start();
2130  m_waitingForTables = (item.m_tuning.m_sistandard != "analog");
2131 }
2132 
2138 {
2139  LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
2140 
2141  while (m_scannerThread)
2142  {
2143  m_threadExit = true;
2144  if (m_scannerThread->wait(1000))
2145  {
2146  delete m_scannerThread;
2147  m_scannerThread = nullptr;
2148  }
2149  }
2150 
2151  if (m_signalMonitor)
2152  m_signalMonitor->Stop();
2153 }
2154 
2160  int SourceID,
2161  const QString &std,
2162  const QString &modulation,
2163  const QString &country,
2164  const QString &table_start,
2165  const QString &table_end)
2166 {
2167  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2168  QString("%1: ").arg(__FUNCTION__) +
2169  QString("SourceID:%1 ").arg(SourceID) +
2170  QString("std:%1 ").arg(std) +
2171  QString("modulation:%1 ").arg(modulation) +
2172  QString("country:%1 ").arg(country) +
2173  QString("table_start:%1 ").arg(table_start) +
2174  QString("table_end:%1 ").arg(table_end));
2175 
2176  QString name("");
2177  if (m_scanning)
2178  return false;
2179 
2180  m_scanTransports.clear();
2181  m_nextIt = m_scanTransports.end();
2182 
2183  freq_table_list_t tables =
2184  get_matching_freq_tables(std, modulation, country);
2185 
2186  if (tables.empty())
2187  {
2188  QString msg = QString("No freq table for (%1, %2, %3) found")
2189  .arg(std).arg(modulation).arg(country);
2191  }
2192  LOG(VB_CHANSCAN, LOG_INFO, LOC +
2193  QString("Looked up freq table (%1, %2, %3) w/%4 entries")
2194  .arg(std).arg(modulation).arg(country).arg(tables.size()));
2195 
2196  QString start = table_start;
2197  const QString& end = table_end;
2198  auto it = tables.begin();
2199  for (; it != tables.end(); ++it)
2200  {
2201  const FrequencyTable &ft = **it;
2202  int name_num = ft.m_nameOffset;
2203  QString strNameFormat = ft.m_nameFormat;
2204  uint freq = ft.m_frequencyStart;
2205  while (freq <= ft.m_frequencyEnd)
2206  {
2207  name = strNameFormat;
2208  if (strNameFormat.indexOf("%") >= 0)
2209  name = strNameFormat.arg(name_num);
2210 
2211  if (start.isEmpty() || name == start)
2212  {
2213  start.clear();
2214 
2215  TransportScanItem item(SourceID, std, name, name_num,
2216  freq, ft, m_signalTimeout);
2217  m_scanTransports.push_back(item);
2218 
2219  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
2220  item.toString());
2221  }
2222 
2223  ++name_num;
2224  freq += ft.m_frequencyStep;
2225 
2226  if (!end.isEmpty() && name == end)
2227  break;
2228  }
2229  if (!end.isEmpty() && name == end)
2230  break;
2231  }
2232 
2233  while (!tables.empty())
2234  {
2235  delete tables.back();
2236  tables.pop_back();
2237  }
2238 
2239  m_extendScanList = true;
2240  m_timer.start();
2241  m_waitingForTables = false;
2242 
2243  m_nextIt = m_scanTransports.begin();
2244  m_transportsScanned = 0;
2245  m_scanning = true;
2246 
2247  return true;
2248 }
2249 
2251  const QString &std,
2252  const QString &cardtype,
2253  const DTVChannelList &channels)
2254 {
2255  m_scanTransports.clear();
2256  m_nextIt = m_scanTransports.end();
2257 
2258  DTVTunerType tunertype;
2259  tunertype.Parse(cardtype);
2260 
2261  auto it = channels.cbegin();
2262  for (uint i = 0; it != channels.cend(); ++it, ++i)
2263  {
2264  DTVTransport tmp = *it;
2265  tmp.m_sistandard = std;
2266  TransportScanItem item(sourceid, QString::number(i),
2267  tunertype, tmp, m_signalTimeout);
2268 
2269  m_scanTransports.push_back(item);
2270 
2271  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
2272  }
2273 
2274  if (m_scanTransports.empty())
2275  {
2276  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
2277  return false;
2278  }
2279 
2280  m_timer.start();
2281  m_waitingForTables = false;
2282 
2283  m_nextIt = m_scanTransports.begin();
2284  m_transportsScanned = 0;
2285  m_scanning = true;
2286 
2287  return true;
2288 }
2289 
2291  const fbox_chan_map_t &iptv_channels)
2292 {
2293  m_scanTransports.clear();
2294  m_nextIt = m_scanTransports.end();
2295 
2296  fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2297  for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2298  {
2299  TransportScanItem item(sourceid, QString::number(idx),
2300  Ichan.value().m_tuning, Ichan.key(),
2301  m_signalTimeout);
2302 
2303  m_scanTransports.push_back(item);
2304 
2305  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2306  }
2307 
2308  if (m_scanTransports.empty())
2309  {
2310  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2311  return false;
2312  }
2313 
2314  m_timer.start();
2315  m_waitingForTables = false;
2316 
2317  m_nextIt = m_scanTransports.begin();
2318  m_transportsScanned = 0;
2319  m_scanning = true;
2320 
2321  return true;
2322 }
2323 
2324 
2330  int sourceid, const QMap<QString,QString> &startChan)
2331 {
2332  if (startChan.find("std") == startChan.end() ||
2333  startChan.find("type") == startChan.end())
2334  {
2335  return false;
2336  }
2337 
2338  QString std = *startChan.find("std");
2339  QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
2340  bool ok = false;
2341 
2342  if (m_scanning)
2343  return false;
2344 
2345  m_scanTransports.clear();
2346  m_nextIt = m_scanTransports.end();
2347 
2348  DTVMultiplex tuning;
2349 
2351  ok = type.Parse(startChan["type"]);
2352 
2353  if (ok)
2354  {
2355  ok = tuning.ParseTuningParams(
2356  type,
2357  startChan["frequency"], startChan["inversion"],
2358  startChan["symbolrate"], startChan["fec"],
2359  startChan["polarity"],
2360  startChan["coderate_hp"], startChan["coderate_lp"],
2361  startChan["constellation"], startChan["trans_mode"],
2362  startChan["guard_interval"], startChan["hierarchy"],
2363  startChan["modulation"], startChan["bandwidth"],
2364  startChan["mod_sys"], startChan["rolloff"]);
2365  }
2366 
2367  if (ok)
2368  {
2369  tuning.m_sistandard = si_std;
2370  TransportScanItem item(
2371  sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2372  tuning, m_signalTimeout);
2373  m_scanTransports.push_back(item);
2374  }
2375 
2376  if (!ok)
2377  return false;
2378 
2379  m_extendScanList = true;
2380 
2381  m_timer.start();
2382  m_waitingForTables = false;
2383 
2384  m_nextIt = m_scanTransports.begin();
2385  m_transportsScanned = 0;
2386  m_scanning = true;
2387 
2388  return true;
2389 }
2390 
2392 {
2393  MSqlQuery query(MSqlQuery::InitCon());
2394  query.prepare(
2395  "SELECT sourceid, sistandard, transportid, frequency, modulation "
2396  "FROM dtv_multiplex "
2397  "WHERE mplexid = :MPLEXID");
2398  query.bindValue(":MPLEXID", mplexid);
2399  if (!query.exec())
2400  {
2401  MythDB::DBError("ChannelScanSM::AddToList()", query);
2402  return false;
2403  }
2404 
2405  if (!query.next())
2406  {
2407  LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2408  QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2409  return false;
2410  }
2411 
2412  uint sourceid = query.value(0).toUInt();
2413  QString sistandard = query.value(1).toString();
2414  uint tsid = query.value(2).toUInt();
2416 
2417  QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2418  QString("Multiplex #%1").arg(mplexid);
2419 
2420  if (query.value(4).toString() == "8vsb")
2421  {
2422  QString chan = QString("%1 Hz").arg(query.value(3).toInt());
2423  struct CHANLIST *curList = chanlists[0].list;
2424  int totalChannels = chanlists[0].count;
2425  int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2426  for (int x = 0 ; x < totalChannels ; ++x)
2427  {
2428  if ((curList[x].freq <= findFrequency + 200) &&
2429  (curList[x].freq >= findFrequency - 200))
2430  {
2431  chan = QString("%1").arg(curList[x].name);
2432  }
2433  }
2434  fn = QObject::tr("ATSC Channel %1").arg(chan);
2436  }
2437 
2438  tt = GuessDTVTunerType(tt);
2439 
2440  TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2441 
2442  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2443  QString("tunertype:%1 %2 sourceid:%3 sistandard:%4 fn:'%5' mplexid:%6")
2444  .arg(tt).arg(tt.toString()).arg(sourceid).arg(sistandard).arg(fn).arg(mplexid));
2445 
2446  if (item.m_tuning.FillFromDB(tt, mplexid))
2447  {
2448  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2449  m_scanTransports.push_back(item);
2450  return true;
2451  }
2452 
2453  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2454  return false;
2455 }
2456 
2457 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2458 {
2459  m_scanTransports.clear();
2460  m_nextIt = m_scanTransports.end();
2461 
2462  AddToList(mplexid);
2463 
2464  m_timer.start();
2465  m_waitingForTables = false;
2466 
2467  m_extendScanList = follow_nit;
2468  m_transportsScanned = 0;
2469  if (!m_scanTransports.empty())
2470  {
2471  m_nextIt = m_scanTransports.begin();
2472  m_scanning = true;
2473  return true;
2474  }
2475 
2476  return false;
2477 }
2478 
2479 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2480 {
2481  m_scanTransports.clear();
2482  m_nextIt = m_scanTransports.end();
2483 
2484  m_signalTimeout = 30000;
2485  QString name;
2486  TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2487  m_scanTransports.push_back(item);
2488 
2489  m_timer.start();
2490  m_waitingForTables = false;
2491  m_extendScanList = false;
2492  m_transportsScanned = 0;
2493  m_nextIt = m_scanTransports.begin();
2494  m_scanning = true;
2495  return true;
2496 }
2497 
2502  const DTVChannelInfoList &channels,
2503  uint mpeg_program_num,
2504  QString &service_name,
2505  QString &callsign,
2506  QString &common_status_info)
2507 {
2508  if (channels.empty())
2509  return true;
2510 
2511  bool found = false;
2512  for (size_t i = 0; i < channels.size(); ++i)
2513  {
2514  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2515  QString("comparing %1 %2 against %3 %4")
2516  .arg(channels[i].m_serviceid).arg(channels[i].m_name)
2517  .arg(mpeg_program_num).arg(common_status_info));
2518 
2519  if (channels[i].m_serviceid == mpeg_program_num)
2520  {
2521  found = true;
2522  if (!channels[i].m_name.isEmpty())
2523  {
2524  service_name = channels[i].m_name;
2525  callsign = channels[i].m_name;
2526  }
2527  }
2528  }
2529 
2530  if (found)
2531  {
2532  common_status_info += QString(" %1 %2")
2533  .arg(QObject::tr("as")).arg(service_name);
2534  }
2535  else
2536  {
2538  QObject::tr("Skipping %1, not in imported channel map")
2539  .arg(common_status_info));
2540  }
2541 
2542  return found;
2543 }
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:782
uint ServiceCount(void) const
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)
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
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:863
void ScanUpdateStatusTitleText(const QString &status)
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:600
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:245
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
QString m_service_name
Definition: channelinfo.h:207
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
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:250
#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
bool CheckImportedList(const DTVChannelInfoList &, 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.
ScanStreamData * GetScanStreamData()
Returns the scan stream data if it exists.
void HandlePMT(uint, const ProgramMapTable *) override
DTVTunerType GuessDTVTunerType(DTVTunerType) const
uint ServiceCount(void) const
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, bool hidden, bool hidden_in_guide, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0)
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:552
QString toString(void) const override
Definition: mpegtables.cpp:874
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:73
bool Tune(const transport_scan_items_it_t &transport)
uint ProgramNumber(uint i) const
Definition: atsctables.h:267
pmt_vec_t GetCachedPMTs(void) const
vector< DTVTransport > DTVChannelList
Definition: dtvconfparser.h:70
uint ServiceType(uint i) const
Definition: atsctables.h:294
void SetPMT(const ProgramMapTable *)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:495
uint LastSection(void) const
Definition: mpegtables.h:515
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)
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:262
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
vector< const unsigned char * > desc_list_t
static const uint kATSCTableTimeout
No logic here, lets just wait at least 10 seconds.
bool m_currentTestingDecryption
uint RegionID(void) const
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:255
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.
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:395
ChannelInsertInfoList m_channels
Definition: dtvmultiplex.h:139
uint Section(void) const
Definition: mpegtables.h:512
static const uint64_t kDTVSigMon_WaitForNIT
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.
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 StreamType(uint i) const
Definition: mpegtables.h:702
uint LogicalChannelNumber(int i, int j) const
virtual void Stop()
Stop signal monitoring thread.
bool IsHidden(uint i) const
Definition: atsctables.h:282
QMap< uint, sdt_vec_t > sdt_map_t
Definition: dvbstreamdata.h:19
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)
uint ServiceID(int i) const
struct CHANLISTS chanlists[]
static const int kTunerTypeDVBT2
void RemoveListener(SignalMonitorListener *listener)
bool HasCachedAnyVCTs(bool current=true) const
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:34
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.
uint StreamCount(void) const
Definition: mpegtables.h:714
bool IsHiddenInGuide(uint i) const
Definition: atsctables.h:288
vector< const BouquetAssociationTable * > bat_vec_t
Definition: dvbstreamdata.h:23
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
bool ScanForChannels(uint sourceid, const QString &std, const QString &cardtype, const DTVChannelList &)
static uint FindChannel(uint sourceid, const QString &freqid)
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:293
Freesat Logical Channel Number descriptor.
QMap< uint, pat_vec_t > pat_map_t
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
bat_vec_t GetCachedBATs(bool current=true) const
void ScanAppendTextToLog(const QString &status)
bool HasCachedAnyPMTs(void) const
vector< const CableVirtualChannelTable * > cvct_vec_t
void HandleNIT(const NetworkInformationTable *) override
vector< const TerrestrialVirtualChannelTable * > tvct_vec_t
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)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
sdt_vec_t GetCachedSDTs(bool current=true) const
void ReturnCachedSDTTables(sdt_vec_t &) const
uint OriginalNetworkID(uint i) const
Definition: dvbtables.h:223
uint m_frequencyStep
The step in frequency.
void HandleSDTo(uint tsid, const ServiceDescriptionTable *) override
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:144
BSkyB Logical Channel Number descriptor.
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:32
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:579
QMap< uint64_t, QString > m_defAuthorities
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
vector< const NetworkInformationTable * > nit_vec_t
Definition: dvbstreamdata.h:12
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
const char * m_name
Definition: ParseText.cpp:328
virtual bool Tune(const DTVMultiplex &tuning)=0
This performs the actual frequency tuning and in some cases input switching.
QString m_sistandard
Definition: dtvmultiplex.h:111
QString DefaultAuthority(void) const
vector< DTVChannelInfo > DTVChannelInfoList
Definition: dtvconfparser.h:60
void HandleBAT(const BouquetAssociationTable *) override
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.
void HandleSDT(uint tsid, const ServiceDescriptionTable *) override
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:277
static void update_info(ChannelInsertInfo &info, const VirtualChannelTable *vct, uint i)
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:807
Scanning class for cards that support a SignalMonitor class.
uint32_t PrivateDataSpecifier(void) const
bool HasCachedAnyBATs(bool current=true) const
static QString loc(const ChannelScanSM *)
static const int kTunerTypeASI
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString m_si_standard
Definition: channelinfo.h:229
void HandlePAT(const ProgramAssociationTable *) override
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
uint64_t freq_offset(uint i) const
uint RegionID(int i, int j) const
QString toString(void) const override
Definition: mpegtables.cpp:809
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:693
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
uint ProgramInfoLength(void) const
Definition: mpegtables.h:696
QString toString(void) const override
Definition: dvbtables.cpp:30
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 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.
vector< const ProgramAssociationTable * > pat_vec_t
bool AddToList(uint mplexid)
This table contains information about the channels transmitted on this multiplex.
Definition: atsctables.h:189
uint m_mplexid
DB Mplexid.
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
QString m_default_authority
Definition: channelinfo.h:220
uint LCNCount(int i) const
void UpdateScanPercentCompleted(void)
Updates Transport Scan progress bar.
uint LogicalChannelNumber(int i) const
QString toString(void) const override
Definition: dvbtables.cpp:200
virtual int GetInputID(void) const
Definition: channelbase.h:67
vector< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:141
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)
vector< const ServiceDescriptionTable * > sdt_vec_t
Definition: dvbstreamdata.h:17
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
QString toString() const
void HandleMGT(const MasterGuideTable *) override
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 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:656
static desc_list_t Parse(const unsigned char *data, uint len)
uint ChannelNumber(uint i) const
const unsigned char * ProgramInfo(void) const
Definition: mpegtables.h:699
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.
virtual void ReturnCachedPMTTables(pmt_vec_t &) const
DTVSignalMonitor * GetDTVSignalMonitor(void)
virtual void ReturnCachedPATTables(pat_vec_t &) const
const QString ShortChannelName(uint i) const
Definition: atsctables.h:225
void GetRotorStatus(bool &was_moving, bool &is_moving) override
DTVMultiplex m_tuning
Tuning info.
void ScanUpdateStatusText(const QString &status)
void HandleVCT(uint tsid, const VirtualChannelTable *) override
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:610
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1729
QMutex m_lock
The big lock.
bool HasCachedAnyPAT(uint tsid) const
Always MPEG-2??
Definition: mpegtables.h:117