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 using namespace std;
36 
37 // Qt includes
38 #include <QObject>
39 #include <QMutexLocker>
40 
41 // MythTV includes - General
42 #include "channelscan_sm.h"
43 #include "frequencies.h"
44 #include "scanwizardconfig.h"
45 #include "mythdbcon.h"
46 #include "channelutil.h"
47 #include "cardutil.h"
48 #include "sourceutil.h"
49 #include "mthread.h"
50 #include "mythdb.h"
51 #include "mythlogging.h"
52 
53 // MythTV includes - DTV
54 #include "dtvsignalmonitor.h"
55 #include "scanstreamdata.h"
56 
57 // MythTV includes - ATSC
58 #include "atsctables.h"
59 
60 // MythTV includes - DVB
61 #include "dvbsignalmonitor.h"
62 #include "dvbtables.h"
63 
64 #include "dvbchannel.h"
65 #include "hdhrchannel.h"
66 #include "v4lchannel.h"
67 
71 const uint ChannelScanSM::kDVBTableTimeout = 30 * 1000;
73 const uint ChannelScanSM::kATSCTableTimeout = 10 * 1000;
75 const uint ChannelScanSM::kMPEGTableTimeout = 15 * 1000;
76 
77 // Freesat default values
78 static const uint kFSATBouquetID = 272;
79 static const uint kFSATRegionID = 1;
80 static const uint kFSATRegionUndefined = 0xFFFF;
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_program_encryption_status.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_program_encryption_status; // 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, const 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(_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  ScanStreamData *data = new ScanStreamData();
172 
173 #if FSAT_IN_DB
174  MSqlQuery query(MSqlQuery::InitCon());
175  query.prepare(
176  "SELECT dvb_nit_id, bouquet_id, region_id "
177  "FROM videosource "
178  "WHERE videosource.sourceid = :SOURCEID");
179  query.bindValue(":SOURCEID", _sourceID);
180  if (!query.exec() || !query.isActive())
181  {
182  MythDB::DBError("ChannelScanSM", query);
183  }
184  else if (query.next())
185  {
186  int nitid = query.value(0).toInt();
187  data->SetRealNetworkID(nitid);
188  LOG(VB_CHANSCAN, LOG_INFO, LOC +
189  QString("Setting NIT-ID to %1").arg(nitid));
190 
191  m_fsat_bouquet_id = query.value(1).toInt();
192  m_fsat_region_id = query.value(2).toInt();
193  }
194 #else
195  MSqlQuery query(MSqlQuery::InitCon());
196  query.prepare(
197  "SELECT dvb_nit_id "
198  "FROM videosource "
199  "WHERE videosource.sourceid = :SOURCEID");
200  query.bindValue(":SOURCEID", _sourceID);
201  if (!query.exec() || !query.isActive())
202  {
203  MythDB::DBError("ChannelScanSM", query);
204  }
205  else if (query.next())
206  {
207  int nitid = query.value(0).toInt();
208  data->SetRealNetworkID(nitid);
209  LOG(VB_CHANSCAN, LOG_INFO, LOC +
210  QString("Setting NIT-ID to %1").arg(nitid));
211 
212  // Freesat settings default or from the environment until it is in table videosource
213  QString fsat_bouquet_id = QString(getenv("FSAT_BOUQUET_ID"));
214  m_fsat_bouquet_id = fsat_bouquet_id.isEmpty() ? kFSATBouquetID: fsat_bouquet_id.toInt();
215  QString fsat_region_id = QString(getenv("FSAT_REGION_ID"));
216  m_fsat_region_id = fsat_region_id.isEmpty() ? kFSATRegionID : fsat_region_id.toInt();
217  }
218 #endif
219  LOG(VB_CHANSCAN, LOG_INFO, LOC +
220  QString("Freesat bouquet_id:%1 region_id:%2")
222 
223  dtvSigMon->SetStreamData(data);
228 
229 #ifdef USING_DVB
230  DVBChannel *dvbchannel = dynamic_cast<DVBChannel*>(m_channel);
231  if (dvbchannel && dvbchannel->GetRotor())
233 #endif
234 
235  data->AddMPEGListener(this);
236  data->AddATSCMainListener(this);
237  data->AddDVBMainListener(this);
238  data->AddDVBOtherListener(this);
239  }
240 }
241 
243 {
244  StopScanner();
245  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
246 
247  ScanStreamData *sd = nullptr;
248  if (GetDTVSignalMonitor())
249  {
251  }
252 
253  if (m_signalMonitor)
254  {
256  delete m_signalMonitor;
257  m_signalMonitor = nullptr;
258  }
259 
260  delete sd;
261 
263  {
264  delete m_analogSignalHandler;
265  m_analogSignalHandler = nullptr;
266  }
267 
269 }
270 
271 void ChannelScanSM::SetAnalog(bool is_analog)
272 {
274 
275  if (is_analog)
277 }
278 
280 {
281  QMutexLocker locker(&m_lock);
282 
283  QString cur_chan = (*m_current).m_friendlyName;
284  QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
285  QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
286 
287  QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
288 
289  if (!ChannelUtil::FindChannel(m_sourceID, freqid))
290  {
291  int chanid = ChannelUtil::CreateChanID(m_sourceID, freqid);
292 
293  QString callsign = QString("%1-%2")
294  .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
295 
296  bool ok = ChannelUtil::CreateChannel(
297  0 /* mplexid */,
298  m_sourceID,
299  chanid,
300  callsign,
301  "" /* service name */,
302  freqid /* channum */,
303  0 /* service id */,
304  0 /* ATSC major channel */,
305  0 /* ATSC minor channel */,
306  false /* use on air guide */,
307  false /* hidden */,
308  false /* hidden in guide */,
309  freqid);
310 
311  msg = (ok) ?
312  QObject::tr("Added Channel %1").arg(cur_chan) :
313  QObject::tr("Failed to add channel %1").arg(cur_chan);
314  }
315  else
316  {
317  // nothing to do here, XMLTV has better info
318  }
319 
321 
322  // tell UI we are done with these channels
323  if (m_scanning)
324  {
326  m_waitingForTables = false;
328  m_dvbt2Tried = true;
329  }
330 }
331 
343 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
344 {
345  if (m_scanning)
346  return false;
347 
348  m_scanTransports.clear();
349  m_nextIt = m_scanTransports.end();
350 
351  vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
352 
353  if (multiplexes.empty())
354  {
355  LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
356  QString("sourceid %1").arg(sourceid));
357 
358  return false;
359  }
360 
361  for (size_t i = 0; i < multiplexes.size(); ++i)
362  AddToList(multiplexes[i]);
363 
364  m_extendScanList = follow_nit;
365  m_waitingForTables = false;
367  if (!m_scanTransports.empty())
368  {
369  m_nextIt = m_scanTransports.begin();
370  m_scanning = true;
371  }
372  else
373  {
374  LOG(VB_CHANSCAN, LOG_ERR, LOC +
375  "Unable to find add any transports for " +
376  QString("sourceid %1").arg(sourceid));
377 
378  return false;
379  }
380 
381 
382  return m_scanning;
383 }
384 
385 void ChannelScanSM::LogLines(const QString& string) const
386 {
387  QStringList lines = string.split('\n');
388  for (int i = 0; i < lines.size(); ++i)
389  LOG(VB_CHANSCAN, LOG_DEBUG, lines[i]);
390 }
391 
393 {
394  QMutexLocker locker(&m_lock);
395 
396  LOG(VB_CHANSCAN, LOG_INFO, LOC +
397  QString("Got a Program Association Table for %1")
398  .arg((*m_current).m_friendlyName));
399  LogLines(pat->toString());
400 
401  // Add pmts to list, so we can do MPEG scan properly.
403  for (uint i = 0; i < pat->ProgramCount(); ++i)
404  {
405  if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
406  sd->AddListeningPID(pat->ProgramPID(i));
407  }
408 }
409 
410 void ChannelScanSM::HandlePMT(uint /*program_num*/, const ProgramMapTable *pmt)
411 {
412  QMutexLocker locker(&m_lock);
413 
414  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1 program %2 (0x%3)")
415  .arg((*m_current).m_friendlyName).arg(pmt->ProgramNumber())
416  .arg(pmt->ProgramNumber(),4,16,QChar('0')));
417  LogLines(pmt->toString());
418 
420  pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
422 }
423 
425 {
426  QMutexLocker locker(&m_lock);
427 
428  LOG(VB_CHANSCAN, LOG_INFO, LOC +
429  QString("Got a Virtual Channel Table for %1")
430  .arg((*m_current).m_friendlyName));
431  LogLines(vct->toString());
432 
433  for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
434  {
435  if (vct->IsAccessControlled(i))
436  {
438  }
439  }
440 
441  UpdateChannelInfo(true);
442 }
443 
445 {
446  QMutexLocker locker(&m_lock);
447 
448  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
449  .arg((*m_current).m_friendlyName));
450  LogLines(mgt->toString());
451 
452  UpdateChannelInfo(true);
453 }
454 
463 {
464  QMutexLocker locker(&m_lock);
465 
466  LOG(VB_CHANSCAN, LOG_INFO, LOC +
467  QString("Got a Service Description Table for %1 section %2/%3")
468  .arg((*m_current).m_friendlyName)
469  .arg(sdt->Section()).arg(sdt->LastSection()));
470  LogLines(sdt->toString());
471 
472  // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
473  if (!m_setOtherTables && (
476  {
478  SetFreesatAdditionalSI(true);
479  m_setOtherTables = true;
480  // The whole BAT & SDTo group comes round in 10s
481  m_otherTableTimeout = 10000;
482  // Delay processing the SDT until we've seen BATs and SDTos
484 
485  LOG(VB_CHANSCAN, LOG_INFO, LOC +
486  QString("SDT has OriginalNetworkID %1, look for "
487  "additional Freesat SI").arg(sdt->OriginalNetworkID()));
488  }
489 
490  if ((uint)m_timer.elapsed() < m_otherTableTime)
491  {
492  // Set the version for the SDT so we see it again.
494  SetVersionSDT(sdt->TSID(), -1, 0);
495  }
496 
497  uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
498  m_tsScanned.insert(id);
499 
500  for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
501  {
502  if (sdt->IsEncrypted(i))
503  {
505  }
506  }
507 
508  UpdateChannelInfo(true);
509 }
510 
512 {
513  QMutexLocker locker(&m_lock);
514 
515  LOG(VB_CHANSCAN, LOG_INFO, LOC +
516  QString("Got a Network Information Table id %1 for %2 section %3/%4")
517  .arg(nit->NetworkID()).arg((*m_current).m_friendlyName)
518  .arg(nit->Section()).arg(nit->LastSection()));
519  LogLines(nit->toString());
520 
521  UpdateChannelInfo(true);
522 }
523 
525 {
526  QMutexLocker locker(&m_lock);
527 
528  LOG(VB_CHANSCAN, LOG_INFO, LOC +
529  QString("Got a Bouquet Association Table id %1 for %2 section %3/%4")
530  .arg(bat->BouquetID()).arg((*m_current).m_friendlyName)
531  .arg(bat->Section()).arg(bat->LastSection()));
532  LogLines(bat->toString());
533 
535 
536  for (uint i = 0; i < bat->TransportStreamCount(); ++i)
537  {
538  uint tsid = bat->TSID(i);
539  uint netid = bat->OriginalNetworkID(i);
540  desc_list_t parsed =
543  // Look for default authority
544  const unsigned char *def_auth =
546  const unsigned char *serv_list =
548 
549  if (def_auth && serv_list)
550  {
551  DefaultAuthorityDescriptor authority(def_auth);
552  ServiceListDescriptor services(serv_list);
553  if (!authority.IsValid() || !services.IsValid())
554  continue;
555 
556  LOG(VB_CHANSCAN, LOG_INFO, LOC +
557  QString("Found default authority '%1' in BAT for services in %2 %3")
558  .arg(authority.DefaultAuthority())
559  .arg(netid).arg(tsid));
560 
561  for (uint j = 0; j < services.ServiceCount(); ++j)
562  {
563  // If the default authority is given in the SDT this
564  // overrides any definition in the BAT (or in the NIT)
565  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
566  QString("Found default authority '%1' in BAT for service %2 %3 %4")
567  .arg(authority.DefaultAuthority())
568  .arg(netid).arg(tsid).arg(services.ServiceID(j)));
569  uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
570  services.ServiceID(j);
571  if (! m_defAuthorities.contains(index))
572  m_defAuthorities[index] = authority.DefaultAuthority();
573  }
574  }
575  }
576  UpdateChannelInfo(true);
577 }
578 
580 {
581  QMutexLocker locker(&m_lock);
582 
583  LOG(VB_CHANSCAN, LOG_INFO, LOC +
584  QString("Got a Service Description Table (other) for Transport ID %1 section %2/%3")
585  .arg(tsid).arg(sdt->Section()).arg(sdt->LastSection()));
586  LogLines(sdt->toString());
587 
589 
590  uint netid = sdt->OriginalNetworkID();
591 
592  for (uint i = 0; i < sdt->ServiceCount(); ++i)
593  {
594  uint serviceId = sdt->ServiceID(i);
595  desc_list_t parsed =
597  sdt->ServiceDescriptorsLength(i));
598  // Look for default authority
599  const unsigned char *def_auth =
601  if (def_auth)
602  {
603  DefaultAuthorityDescriptor authority(def_auth);
604  if (!authority.IsValid())
605  continue;
606  LOG(VB_CHANSCAN, LOG_INFO, LOC +
607  QString("Found default authority '%1' in SDTo for service %2 %3 %4")
608  .arg(authority.DefaultAuthority())
609  .arg(netid).arg(tsid).arg(serviceId));
610  m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
611  authority.DefaultAuthority();
612  }
613  }
614 }
615 
616 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
617 {
618  QMutexLocker locker(&m_lock);
619 
621 
624 
625  UpdateChannelInfo(true);
626 }
627 
629 {
630  if (!m_currentInfo || m_currentInfo->m_pmts.empty())
631  {
632  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
634  return false;
635  }
636 
637  do
638  {
639  uint pnum = 0;
640  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
641 #if 0
642  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
643  .arg(currentEncryptionStatusChecked.size())
644  .arg(currentEncryptionStatus.size()));
645 #endif
646  while (it != m_currentEncryptionStatus.end())
647  {
648  if (!m_currentEncryptionStatusChecked[it.key()])
649  {
650  pnum = it.key();
651  break;
652  }
653  ++it;
654  }
655 
656  if (!pnum)
657  break;
658 
660 
661  if (!m_testDecryption)
662  {
664  continue;
665  }
666 
667  const ProgramMapTable *pmt = nullptr;
668  for (uint i = 0; !pmt && (i < m_currentInfo->m_pmts.size()); ++i)
669  {
670  pmt = (m_currentInfo->m_pmts[i]->ProgramNumber() == pnum) ?
671  m_currentInfo->m_pmts[i] : nullptr;
672  }
673 
674  if (pmt)
675  {
676  QString cur_chan, cur_chan_tr;
677  GetCurrentTransportInfo(cur_chan, cur_chan_tr);
678 
679  QString msg_tr =
680  QObject::tr("%1 -- Testing decryption of program %2")
681  .arg(cur_chan_tr).arg(pnum);
682  QString msg =
683  QString("%1 -- Testing decryption of program %2")
684  .arg(cur_chan).arg(pnum);
685 
687  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
688 
689 #ifdef USING_DVB
690  if (GetDVBChannel())
691  GetDVBChannel()->SetPMT(pmt);
692 #endif // USING_DVB
693 
695 
697  m_timer.start();
698  return true;
699  }
700 
701  LOG(VB_GENERAL, LOG_INFO, LOC +
702  QString("Can't monitor decryption of program %1 -- no pmt")
703  .arg(pnum));
704 
705  } while (true);
706 
708  return false;
709 }
710 
712 {
715 
716  const DTVChannel *chan = GetDTVChannel();
717 
718  if (!chan)
719  return type;
720 
721  vector<DTVTunerType> tts = chan->GetTunerTypes();
722 
723  for (size_t i = 0; i < tts.size(); ++i)
724  {
725  if (tts[i] == type)
726  return type;
727  }
728 
729  if (!tts.empty())
730  return tts[0];
731 
732  return type;
733 }
734 
736 {
737  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
738  {
739  uint32_t tsid = nit->TSID(i);
740  uint32_t netid = nit->OriginalNetworkID(i);
741  uint32_t id = netid << 16 | tsid;
742 
743  if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
744  continue;
745 
746  const desc_list_t& list =
749 
750  for (size_t j = 0; j < list.size(); ++j)
751  {
752  int mplexid = -1;
753  uint64_t frequency = 0;
754  const MPEGDescriptor desc(list[j]);
755  uint tag = desc.DescriptorTag();
756  uint length = desc.DescriptorLength();
757  QString tagString = desc.DescriptorTagString();
758 
760 
761  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("ts-loop j:%1 tag:%2 %3 length:%4")
762  .arg(j).arg(tag).arg(tagString).arg(length));
763 
764  switch (tag)
765  {
767  {
769  frequency = cd.FrequencyHz();
771  break;
772  }
774  {
775  const SatelliteDeliverySystemDescriptor cd(desc);
776  frequency = cd.FrequencyHz()/1000;
778  break;
779  }
781  {
782  const CableDeliverySystemDescriptor cd(desc);
783  frequency = cd.FrequencyHz();
785  break;
786  }
787  default:
788  LOG(VB_CHANSCAN, LOG_ERR, LOC +
789  "unknown delivery system descriptor");
790  continue;
791  }
792 
793  mplexid = ChannelUtil::GetMplexID(m_sourceID, frequency, tsid, netid);
794  mplexid = max(0, mplexid);
795 
796  tt = GuessDTVTunerType(tt);
797 
798  DTVMultiplex tuning;
799  if (mplexid)
800  {
801  if (!tuning.FillFromDB(tt, mplexid))
802  continue;
803  }
804  else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
805  {
806  continue;
807  }
808 
809  m_extendTransports[id] = tuning;
810  break;
811  }
812  }
813 }
814 
815 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
816 {
817  QMutexLocker locker(&m_mutex);
818 
819  if (m_current == m_scanTransports.end())
820  return true;
821 
822  if (wait_until_complete && !m_waitingForTables)
823  return true;
824 
825  if (wait_until_complete && m_currentTestingDecryption)
826  return false;
827 
829  if (!dtv_sm)
830  return false;
831 
832  const ScanStreamData *sd = dtv_sm->GetScanStreamData();
833 
834  if (!m_currentInfo)
836 
837  bool transport_tune_complete = true;
838 
839  // MPEG
840 
841  // Grab PAT tables
842  pat_vec_t pattmp = sd->GetCachedPATs();
843  QMap<uint,bool> tsid_checked;
844  for (size_t i = 0; i < pattmp.size(); ++i)
845  {
846  uint tsid = pattmp[i]->TransportStreamID();
847  if (tsid_checked[tsid])
848  continue;
849  tsid_checked[tsid] = true;
850  if (m_currentInfo->m_pats.contains(tsid))
851  continue;
852 
853  if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
854  {
855  m_currentInfo->m_pats[tsid] = sd->GetCachedPATs(tsid);
856  if (!m_currentInfo->m_pmts.empty())
857  {
859  m_currentInfo->m_pmts.clear();
860  }
861  }
862  else
863  transport_tune_complete = false;
864  }
865  transport_tune_complete &= !pattmp.empty();
866  sd->ReturnCachedPATTables(pattmp);
867 
868  // Grab PMT tables
869  if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
870  m_currentInfo->m_pmts.empty())
872 
873  // ATSC
874  if (!m_currentInfo->m_mgt && sd->HasCachedMGT())
876 
877  if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
878  m_currentInfo->m_cvcts.empty())
879  {
881  }
882 
883  if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
884  m_currentInfo->m_tvcts.empty())
885  {
887  }
888 
889  // DVB
890  if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
891  (m_currentInfo->m_nits.empty() ||
892  m_timer.elapsed() > (int)m_otherTableTime))
893  {
895  }
896 
897  sdt_vec_t sdttmp = sd->GetCachedSDTs();
898  tsid_checked.clear();
899  for (size_t i = 0; i < sdttmp.size(); ++i)
900  {
901  uint tsid = sdttmp[i]->TSID();
902  if (tsid_checked[tsid])
903  continue;
904  tsid_checked[tsid] = true;
905  if (m_currentInfo->m_sdts.contains(tsid))
906  continue;
907 
908  if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
909  m_currentInfo->m_sdts[tsid] = sd->GetCachedSDTSections(tsid);
910  }
911  sd->ReturnCachedSDTTables(sdttmp);
912 
913  if ((!wait_until_complete || sd->HasCachedAllBATs()) &&
914  (m_currentInfo->m_bats.empty() ||
915  m_timer.elapsed() > (int)m_otherTableTime))
916  {
918  }
919 
920  // Check if transport tuning is complete
921  if (transport_tune_complete)
922  {
923  transport_tune_complete &= !m_currentInfo->m_pmts.empty();
924  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
925  {
926  transport_tune_complete &= sd->HasCachedMGT();
927  transport_tune_complete &=
928  (!m_currentInfo->m_tvcts.empty() || !m_currentInfo->m_cvcts.empty());
929  }
930  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
931  {
932  transport_tune_complete &= !m_currentInfo->m_nits.empty();
933  transport_tune_complete &= !m_currentInfo->m_sdts.empty();
934  }
935  if (sd->HasCachedAnyBATs())
936  {
937  transport_tune_complete &= !m_currentInfo->m_bats.empty();
938  }
939  if (transport_tune_complete)
940  {
941  LOG(VB_CHANSCAN, LOG_INFO, LOC +
942  QString("transport_tune_complete: "
943  "\n\t\t\tcurrentInfo->m_pmts.empty(): %1"
944  "\n\t\t\tsd->HasCachedAnyNIT(): %2"
945  "\n\t\t\tsd->HasCachedAnySDTs(): %3"
946  "\n\t\t\tsd->HasCachedAnyBATs(): %4"
947  "\n\t\t\tcurrentInfo->m_nits.empty(): %5"
948  "\n\t\t\tcurrentInfo->m_sdts.empty(): %6"
949  "\n\t\t\tcurrentInfo->m_bats.empty(): %7")
950  .arg(m_currentInfo->m_pmts.empty())
951  .arg(sd->HasCachedAnyNIT())
952  .arg(sd->HasCachedAnySDTs())
953  .arg(sd->HasCachedAnyBATs())
954  .arg(m_currentInfo->m_nits.empty())
955  .arg(m_currentInfo->m_sdts.empty())
956  .arg(m_currentInfo->m_bats.empty()));
957  }
958  }
959  if (!wait_until_complete)
960  transport_tune_complete = true;
961  if (transport_tune_complete)
962  {
963  LOG(VB_CHANSCAN, LOG_INFO, LOC +
964  QString("transport_tune_complete: wait_until_complete %1")
965  .arg(wait_until_complete));
966  }
967 
968  if (transport_tune_complete && !m_currentEncryptionStatus.empty())
970  {
971  //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
972 
974  return false;
975 
976  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
977  for (; it != m_currentEncryptionStatus.end(); ++it)
978  {
980 
981  if (m_testDecryption)
982  {
983  QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
984  QString msg_tr2 = QObject::tr("Unknown decryption status");
985  if (kEncEncrypted == *it)
986  msg_tr2 = QObject::tr("Encrypted");
987  else if (kEncDecrypted == *it)
988  msg_tr2 = QObject::tr("Decrypted");
989  QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
991  }
992 
993  QString msg = QString("Program %1").arg(it.key());
994  if (kEncEncrypted == *it)
995  msg = msg + " -- Encrypted";
996  else if (kEncDecrypted == *it)
997  msg = msg + " -- Decrypted";
998  else if (kEncUnknown == *it)
999  msg = msg + " -- Unknown decryption status";
1000 
1001  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1002  }
1003  }
1004 
1005  // Append transports from the NIT to the scan list
1006  if (transport_tune_complete && m_extendScanList &&
1007  !m_currentInfo->m_nits.empty())
1008  {
1009  // Update transport with delivery system descriptors from the NIT
1010  nit_vec_t::const_iterator it = m_currentInfo->m_nits.begin();
1011  while (it != m_currentInfo->m_nits.end())
1012  {
1013  UpdateScanTransports(*it);
1014  ++it;
1015  }
1016  }
1017 
1018  // Start scanning next transport if we are done with this one..
1019  if (transport_tune_complete)
1020  {
1021  QString cchan, cchan_tr;
1022  uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
1023  m_channelsFound += cchan_cnt;
1024  QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
1025  QString chan = QString( "%1 -- Timed out").arg(cchan);
1026  QString msg_tr = "";
1027  QString msg = "";
1028 
1029  if (!m_currentInfo->IsEmpty())
1030  {
1031  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1032  QString("Adding %1, offset %2 to channelList.")
1033  .arg((*m_current).m_tuning.toString()).arg(m_current.offset()));
1034 
1035  TransportScanItem &item = *m_current;
1037 
1038  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
1039  QString("%1(%2) m_inputName: %3 ").arg(__FUNCTION__).arg(__LINE__).arg(m_inputName) +
1040  QString("m_mod_sys:%1 %2").arg(item.m_tuning.m_mod_sys).arg(item.m_tuning.m_mod_sys.toString()));
1041 
1043  {
1044  if (m_dvbt2Tried)
1046  else
1048  }
1049 
1051  m_currentInfo = nullptr;
1052  }
1053  else
1054  {
1055  delete m_currentInfo;
1056  m_currentInfo = nullptr;
1057  }
1058 
1060  if (HasTimedOut())
1061  {
1062  msg_tr = (cchan_cnt) ?
1063  QObject::tr("%1 possible channels").arg(cchan_cnt) :
1064  QObject::tr("no channels");
1065  msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
1066  msg = (cchan_cnt) ?
1067  QString("%1 possible channels").arg(cchan_cnt) :
1068  QString("no channels");
1069  msg = QString("%1, %2").arg(chan_tr).arg(msg);
1070  }
1071  else if ((m_current != m_scanTransports.end()) &&
1072  (m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1073  sm && !sm->HasSignalLock())
1074  {
1075  msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1076  msg = QString("%1, no signal").arg(chan);
1077  }
1078  else
1079  {
1080  msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1081  .arg(cchan_tr).arg(cchan_cnt);
1082 
1083  msg = QString("%1 -- Found %2 probable channels")
1084  .arg(cchan).arg(cchan_cnt);
1085  }
1086 
1088  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1089 
1090  m_currentEncryptionStatus.clear();
1092 
1093  m_setOtherTables = false;
1094  m_otherTableTime = 0;
1095 
1096  if (m_scanning)
1097  {
1100  m_waitingForTables = false;
1102  m_dvbt2Tried = true;
1103  }
1104  else
1105  {
1108  }
1109 
1110  return true;
1111  }
1112 
1113  return false;
1114 }
1115 
1116 #define PCM_INFO_INIT(SISTD) \
1117  ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1118  info.m_db_mplexid = mplexid; info.m_source_id = m_sourceID; \
1119  info.m_service_id = pnum; info.m_freqid = freqidStr; \
1120  info.m_si_standard = SISTD;
1121 
1122 static void update_info(ChannelInsertInfo &info,
1123  const VirtualChannelTable *vct, uint i)
1124 {
1125  if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1126  vct->ServiceType(i) == 0x01 /* Analog TV */)
1127  {
1128  info.m_si_standard = "ntsc";
1129  info.m_format = "ntsc";
1130  }
1131 
1132  info.m_callsign = vct->ShortChannelName(i);
1133 
1134  info.m_service_name = vct->GetExtendedChannelName(i);
1135  if (info.m_service_name.isEmpty())
1136  info.m_service_name = vct->ShortChannelName(i);
1137 
1138  info.m_chan_num.clear();
1139 
1140  info.m_service_id = vct->ProgramNumber(i);
1141  info.m_atsc_major_channel = vct->MajorChannel(i);
1142  info.m_atsc_minor_channel = vct->MinorChannel(i);
1143 
1144  info.m_use_on_air_guide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1145 
1146  info.m_hidden = vct->IsHidden(i);
1147  info.m_hidden_in_guide = vct->IsHiddenInGuide(i);
1148 
1149  info.m_vct_tsid = vct->TransportStreamID();
1151  info.m_is_encrypted |= vct->IsAccessControlled(i);
1152  info.m_is_data_service = vct->ServiceType(i) == 0x04;
1153  info.m_is_audio_service = vct->ServiceType(i) == 0x03;
1154 
1155  info.m_in_vct = true;
1156 }
1157 
1158 static void update_info(ChannelInsertInfo &info,
1159  const ServiceDescriptionTable *sdt, uint i,
1160  const QMap<uint64_t, QString> &defAuthorities)
1161 {
1162  // HACK beg -- special exception for these networks
1163  // this enables useonairguide by default for all matching channels
1164  // (dbver == "1067")
1165  bool force_guide_present = (
1166  // Telenor (NO)
1168 #if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1169  // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1170  (sdt->OriginalNetworkID() == 222) ||
1171 #endif
1172  // ERT (GR) from the private temporary allocation, see #9592:comment:17
1173  (sdt->OriginalNetworkID() == 65330) ||
1174  // Digitenne (NL) see #13427
1176  );
1177  // HACK end -- special exception for these networks
1178 
1179  // Figure out best service name and callsign...
1180  ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
1181  QString callsign;
1182  QString service_name;
1183  if (desc)
1184  {
1185  callsign = desc->ServiceShortName();
1186  if (callsign.trimmed().isEmpty())
1187  callsign = QString("%1-%2-%3")
1188  .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1189  .arg(sdt->ServiceID(i));
1190 
1191  service_name = desc->ServiceName();
1192  if (service_name.trimmed().isEmpty())
1193  service_name.clear();
1194  }
1195 
1196  if (info.m_callsign.isEmpty())
1197  info.m_callsign = callsign;
1198  if (info.m_service_name.isEmpty())
1199  info.m_service_name = service_name;
1200 
1201  info.m_use_on_air_guide =
1202  sdt->HasEITPresentFollowing(i) ||
1203  sdt->HasEITSchedule(i) ||
1204  force_guide_present;
1205 
1206  info.m_hidden = false;
1207  info.m_hidden_in_guide = false;
1208 
1209  info.m_is_data_service =
1210  (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1211  info.m_is_audio_service = (desc && desc->IsDigitalAudio());
1212  delete desc;
1213 
1214  info.m_service_id = sdt->ServiceID(i);
1215  info.m_sdt_tsid = sdt->TSID();
1216  info.m_orig_netid = sdt->OriginalNetworkID();
1217  info.m_in_sdt = true;
1218 
1219  desc_list_t parsed =
1221  sdt->ServiceDescriptorsLength(i));
1222  // Look for default authority
1223  const unsigned char *def_auth =
1225  if (def_auth)
1226  {
1227  DefaultAuthorityDescriptor authority(def_auth);
1228  if (authority.IsValid())
1229  {
1230  LOG(VB_CHANSCAN, LOG_INFO,
1231  QString("ChannelScanSM: Found default authority '%1' in SDT for service %2 %3 %4")
1232  .arg(authority.DefaultAuthority())
1233  .arg(info.m_orig_netid).arg(info.m_sdt_tsid).arg(info.m_service_id));
1234  info.m_default_authority = authority.DefaultAuthority();
1235  return;
1236  }
1237  }
1238 
1239  // If no authority in the SDT then use the one found in the BAT or the SDTo
1240  uint64_t index = (uint64_t)info.m_orig_netid << 32 |
1241  info.m_sdt_tsid << 16 | info.m_service_id;
1242  if (defAuthorities.contains(index))
1243  info.m_default_authority = defAuthorities[index];
1244 }
1245 
1247  QString &cur_chan, QString &cur_chan_tr) const
1248 {
1249  if (m_current.iter() == m_scanTransports.end())
1250  {
1251  cur_chan.clear();
1252  cur_chan_tr.clear();
1253  return 0;
1254  }
1255 
1256  uint max_chan_cnt = 0;
1257 
1258  QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1259  {
1260  for (int i = 0; i < list.size(); ++i)
1261  {
1262  max_chan_cnt +=
1263  (list[i].m_in_pat || list[i].m_in_pmt ||
1264  list[i].m_in_sdt || list[i].m_in_vct) ? 1 : 0;
1265  }
1266  }
1267 
1268  QString offset_str_tr = m_current.offset() ?
1269  QObject::tr(" offset %2").arg(m_current.offset()) : "";
1270  cur_chan_tr = QString("%1%2")
1271  .arg((*m_current).m_friendlyName).arg(offset_str_tr);
1272 
1273  QString offset_str = m_current.offset() ?
1274  QString(" offset %2").arg(m_current.offset()) : "";
1275  cur_chan = QString("%1%2")
1276  .arg((*m_current).m_friendlyName).arg(offset_str);
1277 
1278  return max_chan_cnt;
1279 }
1280 
1281 QMap<uint,ChannelInsertInfo>
1283  ScannedChannelInfo *scan_info) const
1284 {
1285  QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1286 
1287  uint mplexid = (*trans_info).m_mplexid;
1288  int freqid = (*trans_info).m_friendlyNum;
1289  QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1290  QString iptv_channel = (*trans_info).m_iptvChannel;
1291 
1292  // channels.conf
1293  const DTVChannelInfoList &echan = (*trans_info).m_expectedChannels;
1294  for (size_t i = 0; i < echan.size(); ++i)
1295  {
1296  uint pnum = echan[i].m_serviceid;
1297  PCM_INFO_INIT("mpeg");
1298  info.m_service_name = echan[i].m_name;
1299  info.m_in_channels_conf = true;
1300  }
1301 
1302  // PATs
1303  pat_map_t::const_iterator pat_list_it = scan_info->m_pats.begin();
1304  for (; pat_list_it != scan_info->m_pats.end(); ++pat_list_it)
1305  {
1306  pat_vec_t::const_iterator pat_it = (*pat_list_it).begin();
1307  for (; pat_it != (*pat_list_it).end(); ++pat_it)
1308  {
1309  bool could_be_opencable = false;
1310  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1311  {
1312  if (((*pat_it)->ProgramNumber(i) == 0) &&
1313  ((*pat_it)->ProgramPID(i) == 0x1ffc))
1314  {
1315  could_be_opencable = true;
1316  }
1317  }
1318 
1319  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1320  {
1321  uint pnum = (*pat_it)->ProgramNumber(i);
1322  if (pnum)
1323  {
1324  PCM_INFO_INIT("mpeg");
1325  info.m_pat_tsid = (*pat_it)->TransportStreamID();
1326  info.m_could_be_opencable = could_be_opencable;
1327  info.m_in_pat = true;
1328  }
1329  }
1330  }
1331  }
1332 
1333  // PMTs
1334  pmt_vec_t::const_iterator pmt_it = scan_info->m_pmts.begin();
1335  for (; pmt_it != scan_info->m_pmts.end(); ++pmt_it)
1336  {
1337  const ProgramMapTable *pmt = *pmt_it;
1338  uint pnum = pmt->ProgramNumber();
1339  PCM_INFO_INIT("mpeg");
1340  for (uint i = 0; i < pmt->StreamCount(); ++i)
1341  {
1342  info.m_could_be_opencable |=
1343  (StreamID::OpenCableVideo == pmt->StreamType(i));
1344  }
1345 
1347  pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1349 
1350  for (size_t i = 0; i < descs.size(); ++i)
1351  {
1352  RegistrationDescriptor reg(descs[i]);
1353  if (!reg.IsValid())
1354  continue;
1355  if (reg.FormatIdentifierString() == "CUEI" ||
1356  reg.FormatIdentifierString() == "SCTE")
1357  info.m_could_be_opencable = true;
1358  }
1359 
1360  info.m_is_encrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1361  info.m_in_pmt = true;
1362  }
1363 
1364  // Cable VCTs
1365  cvct_vec_t::const_iterator cvct_it = scan_info->m_cvcts.begin();
1366  for (; cvct_it != scan_info->m_cvcts.end(); ++cvct_it)
1367  {
1368  for (uint i = 0; i < (*cvct_it)->ChannelCount(); ++i)
1369  {
1370  uint pnum = (*cvct_it)->ProgramNumber(i);
1371  PCM_INFO_INIT("atsc");
1372  update_info(info, *cvct_it, i);
1373  }
1374  }
1375 
1376  // Terrestrial VCTs
1377  tvct_vec_t::const_iterator tvct_it = scan_info->m_tvcts.begin();
1378  for (; tvct_it != scan_info->m_tvcts.end(); ++tvct_it)
1379  {
1380  for (uint i = 0; i < (*tvct_it)->ChannelCount(); ++i)
1381  {
1382  uint pnum = (*tvct_it)->ProgramNumber(i);
1383  PCM_INFO_INIT("atsc");
1384  update_info(info, *tvct_it, i);
1385  }
1386  }
1387 
1388  // SDTs
1389  sdt_map_t::const_iterator sdt_list_it = scan_info->m_sdts.begin();
1390  for (; sdt_list_it != scan_info->m_sdts.end(); ++sdt_list_it)
1391  {
1392  sdt_vec_t::const_iterator sdt_it = (*sdt_list_it).begin();
1393  for (; sdt_it != (*sdt_list_it).end(); ++sdt_it)
1394  {
1395  for (uint i = 0; i < (*sdt_it)->ServiceCount(); ++i)
1396  {
1397  uint pnum = (*sdt_it)->ServiceID(i);
1398  PCM_INFO_INIT("dvb");
1399  update_info(info, *sdt_it, i, m_defAuthorities);
1400  }
1401  }
1402  }
1403 
1404  // NIT
1405  QMap<qlonglong, uint> ukChanNums;
1406  QMap<qlonglong, uint> scnChanNums;
1407  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1408  for (dbchan_it = pnum_to_dbchan.begin();
1409  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1410  {
1411  ChannelInsertInfo &info = *dbchan_it;
1412 
1413  // NIT
1414  nit_vec_t::const_iterator nits_it = scan_info->m_nits.begin();
1415  for (; nits_it != scan_info->m_nits.end(); ++nits_it)
1416  {
1417  for (uint i = 0; i < (*nits_it)->TransportStreamCount(); ++i)
1418  {
1419  const NetworkInformationTable *nit = (*nits_it);
1420  if ((nit->TSID(i) == info.m_sdt_tsid) &&
1421  (nit->OriginalNetworkID(i) == info.m_orig_netid))
1422  {
1423  info.m_netid = nit->NetworkID();
1424  info.m_in_nit = true;
1425  }
1426  else
1427  {
1428  continue;
1429  }
1430 
1431  // Get channel numbers from UK Frequency List Descriptors
1432  const desc_list_t &list =
1434  nit->TransportDescriptorsLength(i));
1435 
1436  // Logical channel numbers
1437  {
1438  const unsigned char *desc =
1441 
1442  if (desc)
1443  {
1444  DVBLogicalChannelDescriptor uklist(desc);
1445  if (!uklist.IsValid())
1446  continue;
1447  for (uint j = 0; j < uklist.ChannelCount(); ++j)
1448  {
1449  ukChanNums[((qlonglong)info.m_orig_netid<<32) |
1450  uklist.ServiceID(j)] =
1451  uklist.ChannelNumber(j);
1452  }
1453  }
1454  }
1455 
1456  // HD Simulcast logical channel numbers
1457  {
1458  const unsigned char *desc =
1461 
1462  if (desc)
1463  {
1464  DVBSimulcastChannelDescriptor scnlist(desc);
1465  if (!scnlist.IsValid())
1466  continue;
1467  for (uint j = 0; j < scnlist.ChannelCount(); ++j)
1468  {
1469  scnChanNums[((qlonglong)info.m_orig_netid<<32) |
1470  scnlist.ServiceID(j)] =
1471  scnlist.ChannelNumber(j);
1472  }
1473  }
1474  }
1475  }
1476  }
1477  }
1478 
1479  // BAT
1480 
1481  // Freesat logical channel numbers
1482 
1483  // Get the Logical Channel Number (LCN) information from the BAT.
1484  // The first filter is on the bouquet ID.
1485  // Then collect all LCN for the selected region and
1486  // for the common (undefined) region with id 0xFFFF.
1487  // The LCN of the selected region has priority; if
1488  // a service is not defined there then look in the
1489  // LCN table of the common region.
1490  // This works because the BAT of each transport contains
1491  // the LCN of all transports and services, not only of the
1492  // transport that we are processing.
1493  // Region 0 is defined but does not have a name.
1494  //
1495  // For reference, this website has the Freesat channel numbers:
1496  // https://www.satellite-calculations.com/DVB/28.2E/28E_FreeSat_ChannelNumber.php
1497  //
1498 
1499  // Lookup tables for LCN to service ID
1500  QMap<uint,uint> lcn_region; // For the selected region
1501  QMap<uint,uint> lcn_common; // Undefined/common for all regions
1502  QMap<uint,uint> lcn_result; // Resulting table
1503 
1504  bat_vec_t::const_iterator bats_it = scan_info->m_bats.begin();
1505  for (; bats_it != scan_info->m_bats.end(); ++bats_it)
1506  {
1507  const BouquetAssociationTable *bat = *bats_it;
1508 
1509  // Bouquet selected by user: 272 is "England HD"
1510  if (bat->BouquetID() != m_fsat_bouquet_id)
1511  continue;
1512 
1513  for (uint t = 0; t < bat->TransportStreamCount(); ++t)
1514  {
1515  uint netid = bat->OriginalNetworkID(t);
1516 
1517  if (!(netid == OriginalNetworkID::SES2 || netid == OriginalNetworkID::BBC))
1518  continue;
1519 
1520  desc_list_t parsed =
1523 
1524  uint priv_dsid = 0;
1525  desc_list_t::const_iterator it = parsed.begin();
1526  for (; it != parsed.end(); ++it)
1527  {
1528  if ((*it)[0] == DescriptorID::private_data_specifier)
1529  {
1531  if (pd.IsValid())
1532  priv_dsid = pd.PrivateDataSpecifier();
1533  }
1534 
1535  if (priv_dsid == PrivateDataSpecifierID::FSAT &&
1537  {
1538  FreesatLCNDescriptor flcd(*it);
1539  if (flcd.IsValid())
1540  {
1541  for (uint i = 0; i<flcd.ServiceCount(); i++)
1542  {
1543  for (uint j=0; j<flcd.LCNCount(i); j++)
1544  {
1545  uint region_id = flcd.RegionID(i,j);
1546  uint service_id = flcd.ServiceID(i);
1547  uint lcn = flcd.LogicalChannelNumber(i,j);
1548  if (region_id == m_fsat_region_id)
1549  {
1550  lcn_region[lcn] = service_id;
1551  lcn_result[lcn] = service_id;
1552  }
1553  else if (region_id == kFSATRegionUndefined)
1554  {
1555  lcn_common[lcn] = service_id;
1556  if (lcn_result.value(lcn,0) == 0)
1557  lcn_result[lcn] = service_id;
1558  }
1559  }
1560  }
1561  }
1562  }
1563  }
1564  }
1565  }
1566 
1567  // Debug: print the resulting tables
1568  if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_DEBUG))
1569  {
1570  for (uint i=1; i<2000; ++i)
1571  {
1572  uint lreg = lcn_region.value(i,0);
1573  uint lcom = lcn_common.value(i,0);
1574  uint lres = lcn_result.value(i,0);
1575  if (lreg > 0 || lcom > 0 || lres > 0)
1576  {
1577  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
1578  QString("RRR lcn:%1 lreg:%2 lcom:%3 lres:%4")
1579  .arg(i,4).arg(lreg,5).arg(lcom,5).arg(lres,5));
1580  }
1581  }
1582  }
1583 
1584  // Create the reverse table for LCN lookup on service id
1585  // Lowest LCN is used in case the service has more than
1586  // one logical channel number.
1587  QMap<uint,uint> sid_lcn;
1588  for (uint lcn=1999; lcn>0; --lcn)
1589  {
1590  uint sid = lcn_result.value(lcn,0);
1591  if (sid > 0)
1592  sid_lcn[sid] = lcn;
1593  }
1594 
1595  // ------------------------------------------------------------------------
1596 
1597  // Get IPTV channel numbers
1598  for (dbchan_it = pnum_to_dbchan.begin();
1599  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1600  {
1601  ChannelInsertInfo &info = *dbchan_it;
1602 
1603  if (!info.m_chan_num.isEmpty())
1604  continue;
1605 
1606  if (!iptv_channel.isEmpty())
1607  {
1608  info.m_chan_num = iptv_channel;
1609  if (info.m_service_id)
1610  info.m_chan_num += "-" + QString::number(info.m_service_id);
1611  }
1612  }
1613 
1614  // Get DVB Logical Channel Numbers
1615  for (dbchan_it = pnum_to_dbchan.begin();
1616  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1617  {
1618  ChannelInsertInfo &info = *dbchan_it;
1619 
1620  if (!info.m_chan_num.isEmpty())
1621  continue;
1622 
1623  // DVB HD Simulcast channel numbers
1624  //
1625  // The HD simulcast channel number table gives the correct channel number
1626  // when HD and SD versions of the same channel are simultaneously broadcast
1627  // and the receiver is capable of receiving the HD signal.
1628  // The latter is assumed correct for a MythTV system.
1629  //
1630  if (info.m_chan_num.isEmpty())
1631  {
1632  qlonglong key = ((qlonglong)info.m_orig_netid<<32) | info.m_service_id;
1633  QMap<qlonglong, uint>::const_iterator it = scnChanNums.find(key);
1634 
1635  if (it != scnChanNums.end())
1636  {
1637  info.m_chan_num = QString::number(*it);
1638  }
1639  }
1640 
1641  // DVB Logical Channel Numbers (a.k.a. UK channel numbers)
1642  if (info.m_chan_num.isEmpty())
1643  {
1644  qlonglong key = ((qlonglong)info.m_orig_netid<<32) | info.m_service_id;
1645  QMap<qlonglong, uint>::const_iterator it = ukChanNums.find(key);
1646 
1647  if (it != ukChanNums.end())
1648  {
1649  info.m_chan_num = QString::number(*it);
1650  }
1651  }
1652 
1653  // DVB satellite Astra 28.2E Freesat channel numbers
1654  if (info.m_chan_num.isEmpty())
1655  {
1656  uint key = info.m_service_id;
1657  QMap<uint, uint>::const_iterator it = sid_lcn.find(key);
1658 
1659  if (it != sid_lcn.end())
1660  {
1661  info.m_chan_num = QString::number(*it);
1662  }
1663  }
1664 
1665  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1666  QString("GetChannelList: service %1 (0x%2) chan_num '%3' callsign '%4'")
1667  .arg(info.m_service_id).arg(info.m_service_id,4,16,QChar('0'))
1668  .arg(info.m_chan_num).arg(info.m_callsign));
1669  }
1670 
1671  // Get QAM/SCTE/MPEG channel numbers
1672  for (dbchan_it = pnum_to_dbchan.begin();
1673  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1674  {
1675  ChannelInsertInfo &info = *dbchan_it;
1676 
1677  if (!info.m_chan_num.isEmpty())
1678  continue;
1679 
1680  if ((info.m_si_standard == "mpeg") ||
1681  (info.m_si_standard == "scte") ||
1682  (info.m_si_standard == "opencable"))
1683  {
1684  if (info.m_freqid.isEmpty())
1685  info.m_chan_num = QString("%1-%2")
1686  .arg(info.m_source_id)
1687  .arg(info.m_service_id);
1688  else
1689  info.m_chan_num = QString("%1-%2")
1690  .arg(info.m_freqid)
1691  .arg(info.m_service_id);
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_decryption_status = scan_info->m_program_encryption_status[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  ChannelList::const_iterator it = m_channelList.begin();
1717  for (; it != m_channelList.end(); ++it)
1718  {
1719  QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1720  GetChannelList(it->first, it->second);
1721 
1722  ScanDTVTransport item((*it->first).m_tuning, tuner_type, cardid);
1723  item.m_iptv_tuning = (*(it->first)).m_iptvTuning;
1724 
1725  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1726  for (dbchan_it = pnum_to_dbchan.begin();
1727  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1728  {
1729  item.m_channels.push_back(*dbchan_it);
1730  }
1731 
1732  if (!item.m_channels.empty())
1733  {
1734  if (addFullTS)
1735  {
1736  /* If addFullTS, then add a 'MPTS' channel
1737  which can be used to record the entire MPTS from
1738  the transport. */
1739  dbchan_it = pnum_to_dbchan.begin();
1740  ChannelInsertInfo info = *dbchan_it;
1741 
1742  // Use transport stream ID as (fake) service ID
1743  // to use in callsign and as channel number
1744  info.m_service_id = info.m_sdt_tsid ? info.m_sdt_tsid : info.m_pat_tsid;
1745 
1746  if (tuner_type == DTVTunerType::kTunerTypeASI)
1747  info.m_callsign = QString("MPTS_%1")
1748  .arg(CardUtil::GetDisplayName(cardid));
1749  else if (info.m_si_standard == "mpeg" ||
1750  info.m_si_standard == "scte" ||
1751  info.m_si_standard == "opencable")
1752  info.m_callsign = QString("MPTS_%1").arg(info.m_freqid);
1753  else if (info.m_atsc_major_channel > 0)
1754  info.m_callsign =
1755  QString("MPTS_%1").arg(info.m_atsc_major_channel);
1756  else if (info.m_service_id > 0)
1757  info.m_callsign = QString("MPTS_%1").arg(info.m_service_id);
1758  else if (!info.m_chan_num.isEmpty())
1759  info.m_callsign = QString("MPTS_%1").arg(info.m_chan_num);
1760  else
1761  info.m_callsign = "MPTS_UNKNOWN";
1762 
1763  info.m_service_name = info.m_callsign;
1764  info.m_atsc_minor_channel = 0;
1765  info.m_format = "MPTS";
1766  info.m_use_on_air_guide = false;
1767  info.m_is_encrypted = false;
1768  item.m_channels.push_back(info);
1769  }
1770 
1771  list.push_back(item);
1772  }
1773  }
1774 
1775  return list;
1776 }
1777 
1778 
1780 {
1781  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1782 }
1783 
1785 {
1786 #ifdef USING_DVB
1787  return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1788 #else
1789  return nullptr;
1790 #endif
1791 }
1792 
1794 {
1795  return dynamic_cast<DTVChannel*>(m_channel);
1796 }
1797 
1799 {
1800  return dynamic_cast<const DTVChannel*>(m_channel);
1801 }
1802 
1804 {
1805 #ifdef USING_HDHOMERUN
1806  return dynamic_cast<HDHRChannel*>(m_channel);
1807 #else
1808  return nullptr;
1809 #endif
1810 }
1811 
1813 {
1814 #ifdef USING_DVB
1815  return dynamic_cast<DVBChannel*>(m_channel);
1816 #else
1817  return nullptr;
1818 #endif
1819 }
1820 
1822 {
1823 #ifdef USING_DVB
1824  return dynamic_cast<const DVBChannel*>(m_channel);
1825 #else
1826  return nullptr;
1827 #endif
1828 }
1829 
1831 {
1832 #ifdef USING_V4L2
1833  return dynamic_cast<V4LChannel*>(m_channel);
1834 #else
1835  return nullptr;
1836 #endif
1837 }
1838 
1843 {
1844  while (m_scannerThread)
1845  {
1846  m_threadExit = true;
1847  if (m_scannerThread->wait(1000))
1848  {
1849  delete m_scannerThread;
1850  m_scannerThread = nullptr;
1851  }
1852  }
1853  m_threadExit = false;
1854  m_scannerThread = new MThread("Scanner", this);
1856 }
1857 
1862 {
1863  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
1864 
1865  while (!m_threadExit)
1866  {
1867  if (m_scanning)
1868  HandleActiveScan();
1869 
1870  usleep(10 * 1000);
1871  }
1872 
1873  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
1874 }
1875 
1876 // See if we have timed out
1878 {
1880  (m_timer.elapsed() > kDecryptionTimeout))
1881  {
1883  return true;
1884  }
1885 
1886  if (!m_waitingForTables)
1887  return true;
1888 
1889 #ifdef USING_DVB
1890  // If the rotor is still moving, reset the timer and keep waiting
1892  if (sigmon)
1893  {
1894  const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
1895  if (rotor)
1896  {
1897  bool was_moving, is_moving;
1898  sigmon->GetRotorStatus(was_moving, is_moving);
1899  if (was_moving && !is_moving)
1900  {
1901  m_timer.restart();
1902  return false;
1903  }
1904  }
1905  }
1906 #endif // USING_DVB
1907 
1908 
1909  // have the tables have timed out?
1910  if (m_timer.elapsed() > (int)m_channelTimeout)
1911  {
1912  // the channelTimeout alone is only valid if we have seen no tables..
1913  const ScanStreamData *sd = nullptr;
1914  if (GetDTVSignalMonitor())
1916 
1917  if (!sd)
1918  return true;
1919 
1920  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
1921  return m_timer.elapsed() > (int) kDVBTableTimeout;
1922  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
1923  return m_timer.elapsed() > (int) kATSCTableTimeout;
1924  if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
1925  return m_timer.elapsed() > (int) kMPEGTableTimeout;
1926 
1927  return true;
1928  }
1929 
1930  // ok the tables haven't timed out, but have we hit the signal timeout?
1932  if ((m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1933  sm && !sm->HasSignalLock())
1934  {
1935  const ScanStreamData *sd = nullptr;
1936  if (GetDTVSignalMonitor())
1938 
1939  if (!sd)
1940  return true;
1941 
1942  // Just is case we temporarily lose the signal after we've seen
1943  // tables...
1944  if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
1945  !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
1946  !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
1947  {
1948  return true;
1949  }
1950  }
1951 
1952  return false;
1953 }
1954 
1959 {
1960  QMutexLocker locker(&m_lock);
1961 
1962  bool do_post_insertion = m_waitingForTables;
1963 
1964  if (!HasTimedOut())
1965  return;
1966 
1967  if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
1968  {
1969  m_channelList.clear();
1970  m_channelsFound = 0;
1971  m_dvbt2Tried = true;
1972  }
1973 
1975  {
1976  // If we failed to get a lock with DVB-T try DVB-T2.
1977  m_dvbt2Tried = true;
1979  return;
1980  }
1981 
1982  if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
1983  {
1984  // Add channel to scanned list and potentially check decryption
1985  if (do_post_insertion && !UpdateChannelInfo(false))
1986  return;
1987 
1988  // Stop signal monitor for previous transport
1989  locker.unlock();
1990  m_signalMonitor->Stop();
1991  locker.relock();
1992  }
1993 
1994  m_current = m_nextIt; // Increment current
1995  m_dvbt2Tried = false;
1996 
1997  if (m_current != m_scanTransports.end())
1998  {
2000 
2001  // Increment nextIt
2002  m_nextIt = m_current;
2003  ++m_nextIt;
2004  }
2005  else if (!m_extendTransports.isEmpty())
2006  {
2007  --m_current;
2008  QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
2009  while (it != m_extendTransports.end())
2010  {
2011  if (!m_tsScanned.contains(it.key()))
2012  {
2013  QString name = QString("TransportID %1").arg(it.key() & 0xffff);
2015  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
2016  item.m_tuning.toString());
2017  m_scanTransports.push_back(item);
2018  m_tsScanned.insert(it.key());
2019  }
2020  ++it;
2021  }
2022  m_extendTransports.clear();
2023  m_nextIt = m_current;
2024  ++m_nextIt;
2025  }
2026  else
2027  {
2029  m_scanning = false;
2031  }
2032 }
2033 
2035 {
2036  const TransportScanItem &item = *transport;
2037 
2038 #ifdef USING_DVB
2039  if (GetDVBSignalMonitor())
2040  {
2041  // always wait for rotor to finish
2044  }
2045 #endif // USING_DVB
2046 
2047  if (!GetDTVChannel())
2048  return false;
2049 
2050  if (item.m_mplexid > 0 && transport.offset() == 0)
2052 
2053  if (item.m_tuning.m_sistandard == "MPEG")
2054  return GetDTVChannel()->Tune(item.m_iptvTuning, true);
2055 
2056  const uint64_t freq = item.freq_offset(transport.offset());
2057  DTVMultiplex tuning = item.m_tuning;
2058  tuning.m_frequency = freq;
2059 
2061  {
2063  }
2065  {
2066  if (m_dvbt2Tried)
2068  else
2070  }
2071 
2072  return GetDTVChannel()->Tune(tuning);
2073 }
2074 
2076 {
2077  QString offset_str = (transport.offset()) ?
2078  QObject::tr(" offset %2").arg(transport.offset()) : "";
2079  QString cur_chan = QString("%1%2")
2080  .arg((*m_current).m_friendlyName).arg(offset_str);
2081  QString tune_msg_str =
2082  QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
2083  .arg(cur_chan).arg((*m_current).m_mplexid);
2084 
2085  const TransportScanItem &item = *transport;
2086 
2087  if (transport.offset() &&
2088  (item.freq_offset(transport.offset()) == item.freq_offset(0)))
2089  {
2090  m_waitingForTables = false;
2091  return; // nothing to do
2092  }
2093 
2094  if (m_channelsFound)
2095  {
2096  QString progress = QObject::tr(": Found %n", "", m_channelsFound);
2098  }
2099 
2101  LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
2102 
2103  if (!Tune(transport))
2104  { // If we did not tune successfully, bail with message
2106  LOG(VB_CHANSCAN, LOG_ERR, LOC +
2107  QString("Failed to tune %1 mplexid(%2) at offset %3")
2108  .arg(item.m_friendlyName).arg(item.m_mplexid)
2109  .arg(transport.offset()));
2110  return;
2111  }
2112 
2113  // If we have a DTV Signal Monitor, perform table scanner reset
2114  if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
2115  {
2117  GetDTVSignalMonitor()->SetChannel(-1,-1);
2118  GetDTVSignalMonitor()->SetDVBService(0, 0, -1);
2119  }
2120 
2121  // Start signal monitor for this channel
2123 
2124  m_timer.start();
2125  m_waitingForTables = (item.m_tuning.m_sistandard != "analog");
2126 }
2127 
2133 {
2134  LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
2135 
2136  while (m_scannerThread)
2137  {
2138  m_threadExit = true;
2139  if (m_scannerThread->wait(1000))
2140  {
2141  delete m_scannerThread;
2142  m_scannerThread = nullptr;
2143  }
2144  }
2145 
2146  if (m_signalMonitor)
2147  m_signalMonitor->Stop();
2148 }
2149 
2155  int SourceID,
2156  const QString &std,
2157  const QString &modulation,
2158  const QString &country,
2159  const QString &table_start,
2160  const QString &table_end)
2161 {
2162  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2163  QString("%1: ").arg(__FUNCTION__) +
2164  QString("SourceID:%1 ").arg(SourceID) +
2165  QString("std:%1 ").arg(std) +
2166  QString("modulation:%1 ").arg(modulation) +
2167  QString("country:%1 ").arg(country) +
2168  QString("table_start:%1 ").arg(table_start) +
2169  QString("table_end:%1 ").arg(table_end));
2170 
2171  QString name("");
2172  if (m_scanning)
2173  return false;
2174 
2175  m_scanTransports.clear();
2176  m_nextIt = m_scanTransports.end();
2177 
2178  freq_table_list_t tables =
2179  get_matching_freq_tables(std, modulation, country);
2180 
2181  if (tables.empty())
2182  {
2183  QString msg = QString("No freq table for (%1, %2, %3) found")
2184  .arg(std).arg(modulation).arg(country);
2186  }
2187  LOG(VB_CHANSCAN, LOG_INFO, LOC +
2188  QString("Looked up freq table (%1, %2, %3) w/%4 entries")
2189  .arg(std).arg(modulation).arg(country).arg(tables.size()));
2190 
2191  QString start = table_start;
2192  const QString& end = table_end;
2193  freq_table_list_t::iterator it = tables.begin();
2194  for (; it != tables.end(); ++it)
2195  {
2196  const FrequencyTable &ft = **it;
2197  int name_num = ft.m_nameOffset;
2198  QString strNameFormat = ft.m_nameFormat;
2199  uint freq = ft.m_frequencyStart;
2200  while (freq <= ft.m_frequencyEnd)
2201  {
2202  name = strNameFormat;
2203  if (strNameFormat.indexOf("%") >= 0)
2204  name = strNameFormat.arg(name_num);
2205 
2206  if (start.isEmpty() || name == start)
2207  {
2208  start.clear();
2209 
2210  TransportScanItem item(SourceID, std, name, name_num,
2211  freq, ft, m_signalTimeout);
2212  m_scanTransports.push_back(item);
2213 
2214  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
2215  item.toString());
2216  }
2217 
2218  ++name_num;
2219  freq += ft.m_frequencyStep;
2220 
2221  if (!end.isEmpty() && name == end)
2222  break;
2223  }
2224  if (!end.isEmpty() && name == end)
2225  break;
2226  }
2227 
2228  while (!tables.empty())
2229  {
2230  delete tables.back();
2231  tables.pop_back();
2232  }
2233 
2234  m_extendScanList = true;
2235  m_timer.start();
2236  m_waitingForTables = false;
2237 
2238  m_nextIt = m_scanTransports.begin();
2239  m_transportsScanned = 0;
2240  m_scanning = true;
2241 
2242  return true;
2243 }
2244 
2246  const QString &std,
2247  const QString &cardtype,
2248  const DTVChannelList &channels)
2249 {
2250  m_scanTransports.clear();
2251  m_nextIt = m_scanTransports.end();
2252 
2253  DTVTunerType tunertype;
2254  tunertype.Parse(cardtype);
2255 
2256  DTVChannelList::const_iterator it = channels.begin();
2257  for (uint i = 0; it != channels.end(); ++it, ++i)
2258  {
2259  DTVTransport tmp = *it;
2260  tmp.m_sistandard = std;
2261  TransportScanItem item(sourceid, QString::number(i),
2262  tunertype, tmp, m_signalTimeout);
2263 
2264  m_scanTransports.push_back(item);
2265 
2266  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
2267  }
2268 
2269  if (m_scanTransports.empty())
2270  {
2271  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
2272  return false;
2273  }
2274 
2275  m_timer.start();
2276  m_waitingForTables = false;
2277 
2278  m_nextIt = m_scanTransports.begin();
2279  m_transportsScanned = 0;
2280  m_scanning = true;
2281 
2282  return true;
2283 }
2284 
2286  const fbox_chan_map_t &iptv_channels)
2287 {
2288  m_scanTransports.clear();
2289  m_nextIt = m_scanTransports.end();
2290 
2291  fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2292  for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2293  {
2294  TransportScanItem item(sourceid, QString::number(idx),
2295  Ichan.value().m_tuning, Ichan.key(),
2296  m_signalTimeout);
2297 
2298  m_scanTransports.push_back(item);
2299 
2300  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2301  }
2302 
2303  if (m_scanTransports.empty())
2304  {
2305  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2306  return false;
2307  }
2308 
2309  m_timer.start();
2310  m_waitingForTables = false;
2311 
2312  m_nextIt = m_scanTransports.begin();
2313  m_transportsScanned = 0;
2314  m_scanning = true;
2315 
2316  return true;
2317 }
2318 
2319 
2325  int sourceid, const QMap<QString,QString> &startChan)
2326 {
2327  if (startChan.find("std") == startChan.end() ||
2328  startChan.find("type") == startChan.end())
2329  {
2330  return false;
2331  }
2332 
2333  QString std = *startChan.find("std");
2334  QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
2335  bool ok = false;
2336 
2337  if (m_scanning)
2338  return false;
2339 
2340  m_scanTransports.clear();
2341  m_nextIt = m_scanTransports.end();
2342 
2343  DTVMultiplex tuning;
2344 
2346  ok = type.Parse(startChan["type"]);
2347 
2348  if (ok)
2349  {
2350  ok = tuning.ParseTuningParams(
2351  type,
2352  startChan["frequency"], startChan["inversion"],
2353  startChan["symbolrate"], startChan["fec"],
2354  startChan["polarity"],
2355  startChan["coderate_hp"], startChan["coderate_lp"],
2356  startChan["constellation"], startChan["trans_mode"],
2357  startChan["guard_interval"], startChan["hierarchy"],
2358  startChan["modulation"], startChan["bandwidth"],
2359  startChan["mod_sys"], startChan["rolloff"]);
2360  }
2361 
2362  if (ok)
2363  {
2364  tuning.m_sistandard = si_std;
2365  TransportScanItem item(
2366  sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2367  tuning, m_signalTimeout);
2368  m_scanTransports.push_back(item);
2369  }
2370 
2371  if (!ok)
2372  return false;
2373 
2374  m_extendScanList = true;
2375 
2376  m_timer.start();
2377  m_waitingForTables = false;
2378 
2379  m_nextIt = m_scanTransports.begin();
2380  m_transportsScanned = 0;
2381  m_scanning = true;
2382 
2383  return true;
2384 }
2385 
2387 {
2388  MSqlQuery query(MSqlQuery::InitCon());
2389  query.prepare(
2390  "SELECT sourceid, sistandard, transportid, frequency, modulation "
2391  "FROM dtv_multiplex "
2392  "WHERE mplexid = :MPLEXID");
2393  query.bindValue(":MPLEXID", mplexid);
2394  if (!query.exec())
2395  {
2396  MythDB::DBError("ChannelScanSM::AddToList()", query);
2397  return false;
2398  }
2399 
2400  if (!query.next())
2401  {
2402  LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2403  QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2404  return false;
2405  }
2406 
2407  uint sourceid = query.value(0).toUInt();
2408  QString sistandard = query.value(1).toString();
2409  uint tsid = query.value(2).toUInt();
2411 
2412  QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2413  QString("Multiplex #%1").arg(mplexid);
2414 
2415  if (query.value(4).toString() == "8vsb")
2416  {
2417  QString chan = QString("%1 Hz").arg(query.value(3).toInt());
2418  struct CHANLIST *curList = chanlists[0].list;
2419  int totalChannels = chanlists[0].count;
2420  int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2421  for (int x = 0 ; x < totalChannels ; ++x)
2422  {
2423  if ((curList[x].freq <= findFrequency + 200) &&
2424  (curList[x].freq >= findFrequency - 200))
2425  {
2426  chan = QString("%1").arg(curList[x].name);
2427  }
2428  }
2429  fn = QObject::tr("ATSC Channel %1").arg(chan);
2431  }
2432 
2433  tt = GuessDTVTunerType(tt);
2434 
2435  TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2436 
2437  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2438  QString("tunertype:%1 %2 sourceid:%3 sistandard:%4 fn:'%5' mplexid:%6")
2439  .arg(tt).arg(tt.toString()).arg(sourceid).arg(sistandard).arg(fn).arg(mplexid));
2440 
2441  if (item.m_tuning.FillFromDB(tt, mplexid))
2442  {
2443  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2444  m_scanTransports.push_back(item);
2445  return true;
2446  }
2447 
2448  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2449  return false;
2450 }
2451 
2452 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2453 {
2454  m_scanTransports.clear();
2455  m_nextIt = m_scanTransports.end();
2456 
2457  AddToList(mplexid);
2458 
2459  m_timer.start();
2460  m_waitingForTables = false;
2461 
2462  m_extendScanList = follow_nit;
2463  m_transportsScanned = 0;
2464  if (!m_scanTransports.empty())
2465  {
2466  m_nextIt = m_scanTransports.begin();
2467  m_scanning = true;
2468  return true;
2469  }
2470 
2471  return false;
2472 }
2473 
2474 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2475 {
2476  m_scanTransports.clear();
2477  m_nextIt = m_scanTransports.end();
2478 
2479  m_signalTimeout = 30000;
2480  QString name;
2481  TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2482  m_scanTransports.push_back(item);
2483 
2484  m_timer.start();
2485  m_waitingForTables = false;
2486  m_extendScanList = false;
2487  m_transportsScanned = 0;
2488  m_nextIt = m_scanTransports.begin();
2489  m_scanning = true;
2490  return true;
2491 }
2492 
2497  const DTVChannelInfoList &channels,
2498  uint mpeg_program_num,
2499  QString &service_name,
2500  QString &callsign,
2501  QString &common_status_info)
2502 {
2503  if (channels.empty())
2504  return true;
2505 
2506  bool found = false;
2507  for (size_t i = 0; i < channels.size(); ++i)
2508  {
2509  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2510  QString("comparing %1 %2 against %3 %4")
2511  .arg(channels[i].m_serviceid).arg(channels[i].m_name)
2512  .arg(mpeg_program_num).arg(common_status_info));
2513 
2514  if (channels[i].m_serviceid == mpeg_program_num)
2515  {
2516  found = true;
2517  if (!channels[i].m_name.isEmpty())
2518  {
2519  service_name = channels[i].m_name;
2520  callsign = channels[i].m_name;
2521  }
2522  }
2523  }
2524 
2525  if (found)
2526  {
2527  common_status_info += QString(" %1 %2")
2528  .arg(QObject::tr("as")).arg(service_name);
2529  }
2530  else
2531  {
2533  QObject::tr("Skipping %1, not in imported channel map")
2534  .arg(common_status_info));
2535  }
2536 
2537  return found;
2538 }
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
bool Parse(const QString &_value)
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:231
unsigned long long FrequencyHz(void) const
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:121
void AddListener(SignalMonitorListener *listener)
V4LChannel * GetV4LChannel(void)
QString toString(void) const override
Definition: dvbtables.cpp:108
DVB HD Simulcast Logical Channel Descriptor.
uint TransportDescriptorsLength(uint i) const
Definition: dvbtables.h:227
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, QString icon=QString(), QString format="Default", QString xmltvid=QString(), QString default_authority=QString())
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 AddMPEGListener(MPEGStreamListener *)
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
QString m_service_name
Definition: channelinfo.h:205
static const int kTunerTypeDVBT
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
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
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:873
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
QMap< uint, uint > m_program_encryption_status
#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< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:141
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.
vector< const FrequencyTable * > freq_table_list_t
uint ServiceDescriptorsLength(uint i) const
desc_loop_length 12 3.4+p
Definition: dvbtables.h:153
vector< DTVTransport > DTVChannelList
Definition: dtvconfparser.h:70
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...
unsigned int uint
Definition: compat.h:140
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
static const uint kFSATBouquetID
QMap< QString, IPTVChannelInfo > fbox_chan_map_t
static const uint64_t kDTVSigMon_WaitForVCT
static const uint kFSATRegionID
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.
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
ChannelInsertInfoList m_channels
Definition: dtvmultiplex.h:139
uint Section(void) const
Definition: mpegtables.h:512
static const uint64_t kDTVSigMon_WaitForNIT
QString m_nameFormat
pretty name format
virtual bool TuneMultiplex(uint mplexid, QString inputname)
To be used by the channel scanner and possibly the EIT scanner.
Definition: dtvchannel.cpp:386
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...
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)
void AddDVBMainListener(DVBMainStreamListener *)
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)
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
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...
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:24
uint ChannelCount() const
Definition: atsctables.h:221
ChannelBase * m_channel
bool ScanForChannels(uint sourceid, const QString &std, const QString &cardtype, const DTVChannelList &)
void SetRealNetworkID(int)
static uint FindChannel(uint sourceid, const QString &freqid)
unsigned char t
Definition: ParseText.cpp:329
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
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
void AddATSCMainListener(ATSCMainStreamListener *)
uint m_frequencyStep
The step in frequency.
void HandleSDTo(uint tsid, const ServiceDescriptionTable *) override
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:144
const char * name
Definition: ParseText.cpp:328
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
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
void HandleBAT(const BouquetAssociationTable *) override
const MasterGuideTable * GetCachedMGT(bool current=true) const
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
QString m_friendlyName
Name to display in scanner dialog.
void HandleSDT(uint tsid, const ServiceDescriptionTable *) override
DTVTunerType m_scanDTVTunerType
static const uint kFSATRegionUndefined
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
vector< DTVChannelInfo > DTVChannelInfoList
Definition: dtvconfparser.h:60
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:226
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
vector< const ProgramMapTable * > pmt_vec_t
ServiceDescriptor * GetServiceDescriptor(uint i) const
Definition: dvbtables.cpp:162
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
uint ProgramNumber(void) const
Definition: mpegtables.h:693
uint OriginalNetworkID(uint i) const
original_network_id 16 2.0+p
Definition: dvbtables.h:72
uint TransportStreamCount(void) const
Definition: dvbtables.h:66
uint ProgramInfoLength(void) const
Definition: mpegtables.h:696
IPTVTuningData m_iptv_tuning
Definition: dtvmultiplex.h:112
QString toString(void) const override
Definition: dvbtables.cpp:19
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
ChannelScanSM(ScanMonitor *_scan_monitor, const QString &_cardtype, ChannelBase *_channel, int _sourceID, uint signal_timeout, uint channel_timeout, const QString &_inputname, bool test_decryption)
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
void AddDVBOtherListener(DVBOtherStreamListener *)
bool HasCachedAnySDTs(bool current=true) const
QString m_default_authority
Definition: channelinfo.h:217
uint LCNCount(int i) const
void UpdateScanPercentCompleted(void)
Updates Transport Scan progress bar.
QString toString(void) const override
Definition: dvbtables.cpp:198
virtual int GetInputID(void) const
Definition: channelbase.h:67
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.
QString toString() const
void HandleMGT(const MasterGuideTable *) override
pat_vec_t GetCachedPATs(uint tsid) const
DTVModulationSystem m_mod_sys
Modulation system.
Definition: dtvmultiplex.h:106
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 ServiceCount(void) const
void LogLines(const QString &string) 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)
QPair< transport_scan_items_it_t, ScannedChannelInfo * > ChannelListItem
QString ServiceName(void) const
uint64_t m_frequency
Definition: dtvmultiplex.h:94
ScanMonitor * m_scanMonitor
uint ProgramPID(uint i) const
Definition: mpegtables.h:610
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1700
QMutex m_lock
The big lock.
bool HasCachedAnyPAT(uint tsid) const
Always MPEG-2??
Definition: mpegtables.h:117