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 QString ChannelScanSM::loc(const ChannelScanSM *siscan)
78 {
79  if (siscan && siscan->m_channel)
80  return QString("ChannelScanSM(%1)").arg(siscan->m_channel->GetDevice());
81  return "ChannelScanSM(u)";
82 }
83 
84 #define LOC (ChannelScanSM::loc(this) + ": ")
85 
86 #define kDecryptionTimeout 4250
87 
89 {
90  public:
91  ScannedChannelInfo() = default;
92 
93  bool IsEmpty() const
94  {
95  return pats.empty() && pmts.empty() &&
96  program_encryption_status.isEmpty() &&
97  !mgt && cvcts.empty() && tvcts.empty() &&
98  nits.empty() && sdts.empty();
99  }
100 
101  // MPEG
104  QMap<uint,uint> program_encryption_status; // pnum->enc_status
105 
106  // ATSC
107  const MasterGuideTable *mgt {nullptr};
110 
111  // DVB
114 };
115 
140  const QString &_cardtype, ChannelBase *_channel,
141  int _sourceID, uint signal_timeout,
142  uint channel_timeout, const QString &_inputname,
143  bool test_decryption)
144  : // Set in constructor
145  m_scanMonitor(_scan_monitor),
146  m_channel(_channel),
147  m_signalMonitor(SignalMonitor::Init(_cardtype, m_channel->GetInputID(),
148  _channel, true)),
149  m_sourceID(_sourceID),
150  m_signalTimeout(signal_timeout),
151  m_channelTimeout(channel_timeout),
152  m_otherTableTimeout(0),
153  m_otherTableTime(0),
154  m_setOtherTables(false),
155  m_inputName(_inputname),
156  m_testDecryption(test_decryption),
157  m_extendScanList(false),
158  // Optional state
159  m_scanDTVTunerType(DTVTunerType::kTunerTypeUnknown),
160  // State
161  m_scanning(false),
162  m_threadExit(false),
163  m_waitingForTables(false),
164  // Transports List
165  m_transportsScanned(0),
166  m_currentTestingDecryption(false),
167  // Misc
168  m_channelsFound(999),
169  m_currentInfo(nullptr),
170  m_analogSignalHandler(new AnalogSignalHandler(this)),
171  m_scannerThread(nullptr)
172 {
173  m_current = m_scanTransports.end();
174 
175  // Create a stream data for digital signal monitors
176  DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
177  if (dtvSigMon)
178  {
179  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Connecting up DTVSignalMonitor");
180  ScanStreamData *data = new ScanStreamData();
181 
182  MSqlQuery query(MSqlQuery::InitCon());
183  query.prepare(
184  "SELECT dvb_nit_id "
185  "FROM videosource "
186  "WHERE videosource.sourceid = :SOURCEID");
187  query.bindValue(":SOURCEID", _sourceID);
188  if (!query.exec() || !query.isActive())
189  {
190  MythDB::DBError("ChannelScanSM", query);
191  }
192  else if (query.next())
193  {
194  uint nitid = query.value(0).toInt();
195  data->SetRealNetworkID(nitid);
196  LOG(VB_CHANSCAN, LOG_INFO, LOC +
197  QString("Setting NIT-ID to %1").arg(nitid));
198  }
199 
200  dtvSigMon->SetStreamData(data);
205 
206 #ifdef USING_DVB
207  DVBChannel *dvbchannel = dynamic_cast<DVBChannel*>(m_channel);
208  if (dvbchannel && dvbchannel->GetRotor())
210 #endif
211 
212  data->AddMPEGListener(this);
213  data->AddATSCMainListener(this);
214  data->AddDVBMainListener(this);
215  data->AddDVBOtherListener(this);
216  }
217 }
218 
220 {
221  StopScanner();
222  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
223 
224  ScanStreamData *sd = nullptr;
225  if (GetDTVSignalMonitor())
226  {
228  }
229 
230  if (m_signalMonitor)
231  {
233  delete m_signalMonitor;
234  m_signalMonitor = nullptr;
235  }
236 
237  delete sd;
238 
240  {
241  delete m_analogSignalHandler;
242  m_analogSignalHandler = nullptr;
243  }
244 
246 }
247 
248 void ChannelScanSM::SetAnalog(bool is_analog)
249 {
251 
252  if (is_analog)
254 }
255 
257 {
258  QMutexLocker locker(&m_lock);
259 
260  QString cur_chan = (*m_current).FriendlyName;
261  QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
262  QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
263 
264  QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
265 
266  if (!ChannelUtil::FindChannel(m_sourceID, freqid))
267  {
268  int chanid = ChannelUtil::CreateChanID(m_sourceID, freqid);
269 
270  QString callsign = QString("%1-%2")
271  .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
272 
273  bool ok = ChannelUtil::CreateChannel(
274  0 /* mplexid */,
275  m_sourceID,
276  chanid,
277  callsign,
278  "" /* service name */,
279  freqid /* channum */,
280  0 /* service id */,
281  0 /* ATSC major channel */,
282  0 /* ATSC minor channel */,
283  false /* use on air guide */,
284  false /* hidden */,
285  false /* hidden in guide */,
286  freqid);
287 
288  msg = (ok) ?
289  QObject::tr("Added Channel %1").arg(cur_chan) :
290  QObject::tr("Failed to add channel %1").arg(cur_chan);
291  }
292  else
293  {
294  // nothing to do here, XMLTV & DataDirect have better info
295  }
296 
298 
299  // tell UI we are done with these channels
300  if (m_scanning)
301  {
303  m_waitingForTables = false;
305  m_dvbt2Tried = true;
306  }
307 }
308 
320 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
321 {
322  if (m_scanning)
323  return false;
324 
325  m_scanTransports.clear();
326  m_nextIt = m_scanTransports.end();
327 
328  vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
329 
330  if (multiplexes.empty())
331  {
332  LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
333  QString("sourceid %1").arg(sourceid));
334 
335  return false;
336  }
337 
338  for (uint i = 0; i < multiplexes.size(); ++i)
339  AddToList(multiplexes[i]);
340 
341  m_extendScanList = follow_nit;
342  m_waitingForTables = false;
344  if (!m_scanTransports.empty())
345  {
346  m_nextIt = m_scanTransports.begin();
347  m_scanning = true;
348  }
349  else
350  {
351  LOG(VB_CHANSCAN, LOG_ERR, LOC +
352  "Unable to find add any transports for " +
353  QString("sourceid %1").arg(sourceid));
354 
355  return false;
356  }
357 
358 
359  return m_scanning;
360 }
361 
362 void ChannelScanSM::LogLines(const QString& string) const
363 {
364  QStringList lines = string.split('\n');
365  for (int i = 0; i < lines.size(); ++i)
366  LOG(VB_CHANSCAN, LOG_INFO, lines[i]);
367 }
368 
370 {
371  QMutexLocker locker(&m_lock);
372 
373  LOG(VB_CHANSCAN, LOG_INFO, LOC +
374  QString("Got a Program Association Table for %1")
375  .arg((*m_current).FriendlyName));
376  LogLines(pat->toString());
377 
378  // Add pmts to list, so we can do MPEG scan properly.
380  for (uint i = 0; i < pat->ProgramCount(); ++i)
381  {
382  if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
383  sd->AddListeningPID(pat->ProgramPID(i));
384  }
385 }
386 
388 {
389  QMutexLocker locker(&m_lock);
390 
391  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1")
392  .arg((*m_current).FriendlyName));
393  LogLines(pmt->toString());
394 
396  pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
398 }
399 
401 {
402  QMutexLocker locker(&m_lock);
403 
404  LOG(VB_CHANSCAN, LOG_INFO, LOC +
405  QString("Got a Virtual Channel Table for %1")
406  .arg((*m_current).FriendlyName));
407  LogLines(vct->toString());
408 
409  for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
410  {
411  if (vct->IsAccessControlled(i))
412  {
414  }
415  }
416 
417  UpdateChannelInfo(true);
418 }
419 
421 {
422  QMutexLocker locker(&m_lock);
423 
424  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
425  .arg((*m_current).FriendlyName));
426  LogLines(mgt->toString());
427 
428  UpdateChannelInfo(true);
429 }
430 
439 {
440  QMutexLocker locker(&m_lock);
441 
442  LOG(VB_CHANSCAN, LOG_INFO, LOC +
443  QString("Got a Service Description Table for %1")
444  .arg((*m_current).FriendlyName));
445  LogLines(sdt->toString());
446 
447  // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
448  if (!m_setOtherTables && (sdt->OriginalNetworkID() == 2 ||
449  sdt->OriginalNetworkID() == 59))
450  {
452  SetFreesatAdditionalSI(true);
453  m_setOtherTables = true;
454  // The whole BAT & SDTo group comes round in 10s
455  m_otherTableTimeout = 10000;
456  // Delay processing the SDT until we've seen BATs and SDTos
458 
459  LOG(VB_CHANSCAN, LOG_INFO, LOC +
460  QString("SDT has OriginalNetworkID %1, look for "
461  "additional Freesat SI").arg(sdt->OriginalNetworkID()));
462  }
463 
464  if ((uint)m_timer.elapsed() < m_otherTableTime)
465  {
466  // Set the version for the SDT so we see it again.
468  SetVersionSDT(sdt->TSID(), -1, 0);
469  }
470 
471  uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
472  m_tsScanned.insert(id);
473 
474  for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
475  {
476  if (sdt->IsEncrypted(i))
477  {
479  }
480  }
481 
482  UpdateChannelInfo(true);
483 }
484 
486 {
487  QMutexLocker locker(&m_lock);
488 
489  LOG(VB_CHANSCAN, LOG_INFO, LOC +
490  QString("Got a Network Information Table for %1")
491  .arg((*m_current).FriendlyName));
492  LogLines(nit->toString());
493 
494  UpdateChannelInfo(true);
495 }
496 
498 {
499  QMutexLocker locker(&m_lock);
500 
501  LOG(VB_CHANSCAN, LOG_INFO, LOC +
502  QString("Got a Bouquet Association Table for %1")
503  .arg((*m_current).FriendlyName));
504  LogLines(bat->toString());
505 
507 
508  for (uint i = 0; i < bat->TransportStreamCount(); ++i)
509  {
510  uint tsid = bat->TSID(i);
511  uint netid = bat->OriginalNetworkID(i);
512  desc_list_t parsed =
515  // Look for default authority
516  const unsigned char *def_auth =
518  const unsigned char *serv_list =
520 
521  if (def_auth && serv_list)
522  {
523  DefaultAuthorityDescriptor authority(def_auth);
524  ServiceListDescriptor services(serv_list);
525 
526  for (uint j = 0; j < services.ServiceCount(); ++j)
527  {
528  // If the default authority is given in the SDT this
529  // overrides any definition in the BAT (or in the NIT)
530  LOG(VB_CHANSCAN, LOG_INFO, LOC +
531  QString("found default authority(BAT) for service %1 %2 %3")
532  .arg(netid).arg(tsid).arg(services.ServiceID(j)));
533  uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
534  services.ServiceID(j);
535  if (! m_defAuthorities.contains(index))
536  m_defAuthorities[index] = authority.DefaultAuthority();
537  }
538  }
539  }
540 }
541 
543 {
544  QMutexLocker locker(&m_lock);
545 
546  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Got a Service Description Table (other)");
547  LogLines(sdt->toString());
548 
550 
551  uint netid = sdt->OriginalNetworkID();
552 
553  for (uint i = 0; i < sdt->ServiceCount(); ++i)
554  {
555  uint serviceId = sdt->ServiceID(i);
556  desc_list_t parsed =
558  sdt->ServiceDescriptorsLength(i));
559  // Look for default authority
560  const unsigned char *def_auth =
562  if (def_auth)
563  {
564  DefaultAuthorityDescriptor authority(def_auth);
565  LOG(VB_CHANSCAN, LOG_INFO, LOC +
566  QString("found default authority(SDTo) for service %1 %2 %3")
567  .arg(netid).arg(tsid).arg(serviceId));
568  m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
569  authority.DefaultAuthority();
570  }
571  }
572 }
573 
574 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
575 {
576  QMutexLocker locker(&m_lock);
577 
579 
582 
583  UpdateChannelInfo(true);
584 }
585 
587 {
588  if (!m_currentInfo || m_currentInfo->pmts.empty())
589  {
590  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
592  return false;
593  }
594 
595  do
596  {
597  uint pnum = 0;
598  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
599 #if 0
600  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
601  .arg(currentEncryptionStatusChecked.size())
602  .arg(currentEncryptionStatus.size()));
603 #endif
604  while (it != m_currentEncryptionStatus.end())
605  {
606  if (!m_currentEncryptionStatusChecked[it.key()])
607  {
608  pnum = it.key();
609  break;
610  }
611  ++it;
612  }
613 
614  if (!pnum)
615  break;
616 
618 
619  if (!m_testDecryption)
620  {
622  continue;
623  }
624 
625  const ProgramMapTable *pmt = nullptr;
626  for (uint i = 0; !pmt && (i < m_currentInfo->pmts.size()); ++i)
627  {
628  pmt = (m_currentInfo->pmts[i]->ProgramNumber() == pnum) ?
629  m_currentInfo->pmts[i] : nullptr;
630  }
631 
632  if (pmt)
633  {
634  QString cur_chan, cur_chan_tr;
635  GetCurrentTransportInfo(cur_chan, cur_chan_tr);
636 
637  QString msg_tr =
638  QObject::tr("%1 -- Testing decryption of program %2")
639  .arg(cur_chan_tr).arg(pnum);
640  QString msg =
641  QString("%1 -- Testing decryption of program %2")
642  .arg(cur_chan).arg(pnum);
643 
645  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
646 
647 #ifdef USING_DVB
648  if (GetDVBChannel())
649  GetDVBChannel()->SetPMT(pmt);
650 #endif // USING_DVB
651 
653 
655  m_timer.start();
656  return true;
657  }
658 
659  LOG(VB_GENERAL, LOG_INFO, LOC +
660  QString("Can't monitor decryption of program %1 -- no pmt")
661  .arg(pnum));
662 
663  } while (true);
664 
666  return false;
667 }
668 
670 {
673 
674  const DTVChannel *chan = GetDTVChannel();
675 
676  if (!chan)
677  return type;
678 
679  vector<DTVTunerType> tts = chan->GetTunerTypes();
680 
681  for (uint i = 0; i < tts.size(); ++i)
682  {
683  if (tts[i] == type)
684  return type;
685  }
686 
687  if (!tts.empty())
688  return tts[0];
689 
690  return type;
691 }
692 
694 {
695  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
696  {
697  uint32_t tsid = nit->TSID(i);
698  uint32_t netid = nit->OriginalNetworkID(i);
699  uint32_t id = netid << 16 | tsid;
700 
701  if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
702  continue;
703 
704  const desc_list_t& list =
707 
708  for (uint j = 0; j < list.size(); ++j)
709  {
710  int mplexid = -1;
711  uint64_t frequency = 0;
712  const MPEGDescriptor desc(list[j]);
713  uint tag = desc.DescriptorTag();
715 
716  switch (tag)
717  {
719  {
721  frequency = cd.FrequencyHz();
723  break;
724  }
726  {
727  const SatelliteDeliverySystemDescriptor cd(desc);
728  frequency = cd.FrequencyHz()/1000;
730  break;
731  }
733  {
734  const CableDeliverySystemDescriptor cd(desc);
735  frequency = cd.FrequencyHz();
737  break;
738  }
739  default:
740  LOG(VB_CHANSCAN, LOG_ERR, LOC +
741  "unknown delivery system descriptor");
742  continue;
743  }
744 
745  mplexid = ChannelUtil::GetMplexID(m_sourceID, frequency, tsid, netid);
746  mplexid = max(0, mplexid);
747 
748  tt = GuessDTVTunerType(tt);
749 
750  DTVMultiplex tuning;
751  if (mplexid)
752  {
753  if (!tuning.FillFromDB(tt, mplexid))
754  continue;
755  }
756  else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
757  {
758  continue;
759  }
760 
761  m_extendTransports[id] = tuning;
762  break;
763  }
764  }
765 }
766 
767 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
768 {
769  QMutexLocker locker(&m_mutex);
770 
771  if (m_current == m_scanTransports.end())
772  return true;
773 
774  if (wait_until_complete && m_currentTestingDecryption)
775  return false;
776 
778  if (!dtv_sm)
779  return false;
780 
781  const ScanStreamData *sd = dtv_sm->GetScanStreamData();
782 
783  if (!m_currentInfo)
785 
786  bool transport_tune_complete = true;
787 
788  // MPEG
789 
790  // Grab PAT tables
791  pat_vec_t pattmp = sd->GetCachedPATs();
792  QMap<uint,bool> tsid_checked;
793  for (uint i = 0; i < pattmp.size(); ++i)
794  {
795  uint tsid = pattmp[i]->TransportStreamID();
796  if (tsid_checked[tsid])
797  continue;
798  tsid_checked[tsid] = true;
799  if (m_currentInfo->pats.contains(tsid))
800  continue;
801 
802  if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
803  {
804  m_currentInfo->pats[tsid] = sd->GetCachedPATs(tsid);
805  if (!m_currentInfo->pmts.empty())
806  {
808  m_currentInfo->pmts.clear();
809  }
810  }
811  else
812  transport_tune_complete = false;
813  }
814  transport_tune_complete &= !pattmp.empty();
815  sd->ReturnCachedPATTables(pattmp);
816 
817  // Grab PMT tables
818  if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
819  m_currentInfo->pmts.empty())
821 
822  // ATSC
823  if (!m_currentInfo->mgt && sd->HasCachedMGT())
824  m_currentInfo->mgt = sd->GetCachedMGT();
825 
826  if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
827  m_currentInfo->cvcts.empty())
828  {
830  }
831 
832  if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
833  m_currentInfo->tvcts.empty())
834  {
836  }
837 
838  // DVB
839  if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
840  (m_currentInfo->nits.empty() ||
841  m_timer.elapsed() > (int)m_otherTableTime))
842  {
844  }
845 
846  sdt_vec_t sdttmp = sd->GetCachedSDTs();
847  tsid_checked.clear();
848  for (uint i = 0; i < sdttmp.size(); ++i)
849  {
850  uint tsid = sdttmp[i]->TSID();
851  if (tsid_checked[tsid])
852  continue;
853  tsid_checked[tsid] = true;
854  if (m_currentInfo->sdts.contains(tsid))
855  continue;
856 
857  if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
858  m_currentInfo->sdts[tsid] = sd->GetCachedSDTSections(tsid);
859  }
860  sd->ReturnCachedSDTTables(sdttmp);
861 
862  // Check if transport tuning is complete
863  if (transport_tune_complete)
864  {
865  transport_tune_complete &= !m_currentInfo->pmts.empty();
866  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
867  {
868  transport_tune_complete &= sd->HasCachedMGT();
869  transport_tune_complete &=
870  (!m_currentInfo->tvcts.empty() || !m_currentInfo->cvcts.empty());
871  }
872  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
873  {
874  transport_tune_complete &= !m_currentInfo->nits.empty();
875  transport_tune_complete &= !m_currentInfo->sdts.empty();
876  }
877  if (transport_tune_complete)
878  {
879  LOG(VB_CHANSCAN, LOG_INFO, LOC +
880  QString("transport_tune_complete: "
881  "\n\t\t\tcurrentInfo->pmts.empty(): %1"
882  "\n\t\t\tsd->HasCachedAnyNIT(): %2"
883  "\n\t\t\tsd->HasCachedAnySDTs(): %3"
884  "\n\t\t\tcurrentInfo->nits.empty(): %4"
885  "\n\t\t\tcurrentInfo->sdts.empty(): %5")
886  .arg(m_currentInfo->pmts.empty())
887  .arg(sd->HasCachedAnyNIT())
888  .arg(sd->HasCachedAnySDTs())
889  .arg(m_currentInfo->nits.empty())
890  .arg(m_currentInfo->sdts.empty()));
891  }
892  }
893  if (!wait_until_complete)
894  transport_tune_complete = true;
895  if (transport_tune_complete)
896  {
897  LOG(VB_CHANSCAN, LOG_INFO, LOC +
898  QString("transport_tune_complete: wait_until_complete %1")
899  .arg(wait_until_complete));
900  }
901 
902  if (transport_tune_complete && m_currentEncryptionStatus.size())
904  {
905  //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
906 
908  return false;
909 
910  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
911  for (; it != m_currentEncryptionStatus.end(); ++it)
912  {
913  m_currentInfo->program_encryption_status[it.key()] = *it;
914 
915  QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
916  QString msg_tr2 = QObject::tr("Unknown decryption status");
917  if (kEncEncrypted == *it)
918  msg_tr2 = QObject::tr("Encrypted");
919  else if (kEncDecrypted == *it)
920  msg_tr2 = QObject::tr("Decrypted");
921  QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
922 
923  QString msg = LOC + QString("Program %1").arg(it.key());
924  if (kEncEncrypted == *it)
925  msg = msg + " -- Encrypted";
926  else if (kEncDecrypted == *it)
927  msg = msg + " -- Decrypted";
928  else if (kEncUnknown == *it)
929  msg = msg + " -- Unknown decryption status";
930 
932  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
933  }
934  }
935 
936  // append transports from the NIT to the scan list
937  if (transport_tune_complete && m_extendScanList &&
938  !m_currentInfo->nits.empty())
939  {
940  // append delivery system descriptos to scan list
941  nit_vec_t::const_iterator it = m_currentInfo->nits.begin();
942  while (it != m_currentInfo->nits.end())
943  {
945  ++it;
946  }
947  }
948 
949  // Start scanning next transport if we are done with this one..
950  if (transport_tune_complete)
951  {
952  QString cchan, cchan_tr;
953  uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
954  m_channelsFound += cchan_cnt;
955  QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
956  QString chan = QString( "%1 -- Timed out").arg(cchan);
957  QString msg_tr = "";
958  QString msg = "";
959 
960  if (!m_currentInfo->IsEmpty())
961  {
962  LOG(VB_CHANSCAN, LOG_INFO, LOC +
963  QString("Adding %1, offset %2 to channelList.")
964  .arg((*m_current).tuning.toString()).arg(m_current.offset()));
965 
966  TransportScanItem &item = *m_current;
968 
970  {
971  if (m_dvbt2Tried)
973  else
975  }
976 
978  m_currentInfo = nullptr;
979  }
980  else
981  {
982  delete m_currentInfo;
983  m_currentInfo = nullptr;
984  }
985 
987  if ((m_timer.elapsed() > (int)m_channelTimeout))
988  {
989  msg_tr = (cchan_cnt) ?
990  QObject::tr("%1 possible channels").arg(cchan_cnt) :
991  QObject::tr("no channels");
992  msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
993  msg = (cchan_cnt) ?
994  QString("%1 possible channels").arg(cchan_cnt) :
995  QString("no channels");
996  msg = QString("%1, %2").arg(chan_tr).arg(msg);
997  }
998  else if ((m_current != m_scanTransports.end()) &&
999  (m_timer.elapsed() > (int)(*m_current).timeoutTune) &&
1000  sm && !sm->HasSignalLock())
1001  {
1002  msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1003  msg = QString("%1, no signal").arg(chan);
1004  }
1005  else
1006  {
1007  msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1008  .arg(cchan_tr).arg(cchan_cnt);
1009 
1010  msg = QString("%1 -- Found %2 probable channels")
1011  .arg(cchan).arg(cchan_cnt);
1012  }
1013 
1015  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1016 
1017  m_currentEncryptionStatus.clear();
1019 
1020  m_setOtherTables = false;
1021  m_otherTableTime = 0;
1022 
1023  if (m_scanning)
1024  {
1027  m_waitingForTables = false;
1029  m_dvbt2Tried = true;
1030  }
1031  else
1032  {
1035  }
1036 
1037  return true;
1038  }
1039 
1040  return false;
1041 }
1042 
1043 #define PCM_INFO_INIT(SISTD) \
1044  ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1045  info.db_mplexid = mplexid; info.source_id = m_sourceID; \
1046  info.service_id = pnum; info.freqid = freqidStr; \
1047  info.si_standard = SISTD;
1048 
1049 static void update_info(ChannelInsertInfo &info,
1050  const VirtualChannelTable *vct, uint i)
1051 {
1052  if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1053  vct->ServiceType(i) == 0x01 /* Analog TV */)
1054  {
1055  info.si_standard = "ntsc";
1056  info.format = "ntsc";
1057  }
1058 
1059  info.callsign = vct->ShortChannelName(i);
1060 
1061  info.service_name = vct->GetExtendedChannelName(i);
1062  if (info.service_name.isEmpty())
1063  info.service_name = vct->ShortChannelName(i);
1064 
1065  info.chan_num.clear();
1066 
1067  info.service_id = vct->ProgramNumber(i);
1068  info.atsc_major_channel = vct->MajorChannel(i);
1069  info.atsc_minor_channel = vct->MinorChannel(i);
1070 
1071  info.use_on_air_guide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1072 
1073  info.hidden = vct->IsHidden(i);
1074  info.hidden_in_guide = vct->IsHiddenInGuide(i);
1075 
1076  info.vct_tsid = vct->TransportStreamID();
1077  info.vct_chan_tsid = vct->ChannelTransportStreamID(i);
1078  info.is_encrypted |= vct->IsAccessControlled(i);
1079  info.is_data_service = vct->ServiceType(i) == 0x04;
1080  info.is_audio_service = vct->ServiceType(i) == 0x03;
1081 
1082  info.in_vct = true;
1083 }
1084 
1085 static void update_info(ChannelInsertInfo &info,
1086  const ServiceDescriptionTable *sdt, uint i,
1087  const QMap<uint64_t, QString> &defAuthorities)
1088 {
1089  // HACK beg -- special exception for these networks
1090  // this enables useonairguide by default for all matching channels
1091  // (dbver == "1067")
1092  bool force_guide_present = (
1093  // Telenor (NO)
1094  (sdt->OriginalNetworkID() == 70) ||
1095 #if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1096  // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1097  (sdt->OriginalNetworkID() == 222) ||
1098 #endif
1099  // ERT (GR) from the private temporary allocation, see #9592:comment:17
1100  (sdt->OriginalNetworkID() == 65330)
1101  );
1102  // HACK end -- special exception for these networks
1103 
1104  // Figure out best service name and callsign...
1105  ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
1106  QString callsign;
1107  QString service_name;
1108  if (desc)
1109  {
1110  callsign = desc->ServiceShortName();
1111  if (callsign.trimmed().isEmpty())
1112  callsign = QString("%1-%2-%3")
1113  .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1114  .arg(sdt->ServiceID(i));
1115 
1116  service_name = desc->ServiceName();
1117  if (service_name.trimmed().isEmpty())
1118  service_name.clear();
1119  }
1120 
1121  if (info.callsign.isEmpty())
1122  info.callsign = callsign;
1123  if (info.service_name.isEmpty())
1124  info.service_name = service_name;
1125 
1126  info.use_on_air_guide =
1127  sdt->HasEITPresentFollowing(i) ||
1128  sdt->HasEITSchedule(i) ||
1129  force_guide_present;
1130 
1131  info.hidden = false;
1132  info.hidden_in_guide = false;
1133 
1134  info.is_data_service =
1135  (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1136  info.is_audio_service = (desc && desc->IsDigitalAudio());
1137  delete desc;
1138 
1139  info.service_id = sdt->ServiceID(i);
1140  info.sdt_tsid = sdt->TSID();
1141  info.orig_netid = sdt->OriginalNetworkID();
1142  info.in_sdt = true;
1143 
1144  desc_list_t parsed =
1146  sdt->ServiceDescriptorsLength(i));
1147  // Look for default authority
1148  const unsigned char *def_auth =
1150  if (def_auth)
1151  {
1152  DefaultAuthorityDescriptor authority(def_auth);
1153  LOG(VB_CHANSCAN, LOG_INFO, QString("ChannelScanSM: found default "
1154  "authority(SDT) for service %1 %2 %3")
1155  .arg(info.orig_netid).arg(info.sdt_tsid).arg(info.service_id));
1156  info.default_authority = authority.DefaultAuthority();
1157  }
1158  else
1159  {
1160  uint64_t index = (uint64_t)info.orig_netid << 32 |
1161  info.sdt_tsid << 16 | info.service_id;
1162  if (defAuthorities.contains(index))
1163  info.default_authority = defAuthorities[index];
1164  }
1165 }
1166 
1168  QString &cur_chan, QString &cur_chan_tr) const
1169 {
1170  if (m_current.iter() == m_scanTransports.end())
1171  {
1172  cur_chan.clear();
1173  cur_chan_tr.clear();
1174  return 0;
1175  }
1176 
1177  uint max_chan_cnt = 0;
1178 
1179  QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1180  {
1181  for (int i = 0; i < list.size(); ++i)
1182  {
1183  max_chan_cnt +=
1184  (list[i].in_pat || list[i].in_pmt ||
1185  list[i].in_sdt || list[i].in_vct) ? 1 : 0;
1186  }
1187  }
1188 
1189  QString offset_str_tr = m_current.offset() ?
1190  QObject::tr(" offset %2").arg(m_current.offset()) : "";
1191  cur_chan_tr = QString("%1%2")
1192  .arg((*m_current).FriendlyName).arg(offset_str_tr);
1193 
1194  QString offset_str = m_current.offset() ?
1195  QString(" offset %2").arg(m_current.offset()) : "";
1196  cur_chan = QString("%1%2")
1197  .arg((*m_current).FriendlyName).arg(offset_str);
1198 
1199  return max_chan_cnt;
1200 }
1201 
1202 QMap<uint,ChannelInsertInfo>
1204  ScannedChannelInfo *scan_info) const
1205 {
1206  QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1207 
1208  uint mplexid = (*trans_info).mplexid;
1209  int freqid = (*trans_info).friendlyNum;
1210  QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1211  QString iptv_channel = (*trans_info).iptv_channel;
1212 
1213  // channels.conf
1214  const DTVChannelInfoList &echan = (*trans_info).expectedChannels;
1215  for (uint i = 0; i < echan.size(); ++i)
1216  {
1217  uint pnum = echan[i].serviceid;
1218  PCM_INFO_INIT("mpeg");
1219  info.service_name = echan[i].name;
1220  info.in_channels_conf = true;
1221  }
1222 
1223  // PATs
1224  pat_map_t::const_iterator pat_list_it = scan_info->pats.begin();
1225  for (; pat_list_it != scan_info->pats.end(); ++pat_list_it)
1226  {
1227  pat_vec_t::const_iterator pat_it = (*pat_list_it).begin();
1228  for (; pat_it != (*pat_list_it).end(); ++pat_it)
1229  {
1230  bool could_be_opencable = false;
1231  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1232  {
1233  if (((*pat_it)->ProgramNumber(i) == 0) &&
1234  ((*pat_it)->ProgramPID(i) == 0x1ffc))
1235  {
1236  could_be_opencable = true;
1237  }
1238  }
1239 
1240  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1241  {
1242  uint pnum = (*pat_it)->ProgramNumber(i);
1243  if (pnum)
1244  {
1245  PCM_INFO_INIT("mpeg");
1246  info.pat_tsid = (*pat_it)->TransportStreamID();
1247  info.could_be_opencable = could_be_opencable;
1248  info.in_pat = true;
1249  }
1250  }
1251  }
1252  }
1253 
1254  // PMTs
1255  pmt_vec_t::const_iterator pmt_it = scan_info->pmts.begin();
1256  for (; pmt_it != scan_info->pmts.end(); ++pmt_it)
1257  {
1258  const ProgramMapTable *pmt = *pmt_it;
1259  uint pnum = pmt->ProgramNumber();
1260  PCM_INFO_INIT("mpeg");
1261  for (uint i = 0; i < pmt->StreamCount(); ++i)
1262  {
1263  info.could_be_opencable |=
1264  (StreamID::OpenCableVideo == pmt->StreamType(i));
1265  }
1266 
1268  pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1270 
1271  for (uint i = 0; i < descs.size(); ++i)
1272  {
1273  RegistrationDescriptor reg(descs[i]);
1274  if (reg.FormatIdentifierString() == "CUEI" ||
1275  reg.FormatIdentifierString() == "SCTE")
1276  info.could_be_opencable = true;
1277  }
1278 
1279  info.is_encrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1280  info.in_pmt = true;
1281  }
1282 
1283  // Cable VCTs
1284  cvct_vec_t::const_iterator cvct_it = scan_info->cvcts.begin();
1285  for (; cvct_it != scan_info->cvcts.end(); ++cvct_it)
1286  {
1287  for (uint i = 0; i < (*cvct_it)->ChannelCount(); ++i)
1288  {
1289  uint pnum = (*cvct_it)->ProgramNumber(i);
1290  PCM_INFO_INIT("atsc");
1291  update_info(info, *cvct_it, i);
1292  }
1293  }
1294 
1295  // Terrestrial VCTs
1296  tvct_vec_t::const_iterator tvct_it = scan_info->tvcts.begin();
1297  for (; tvct_it != scan_info->tvcts.end(); ++tvct_it)
1298  {
1299  for (uint i = 0; i < (*tvct_it)->ChannelCount(); ++i)
1300  {
1301  uint pnum = (*tvct_it)->ProgramNumber(i);
1302  PCM_INFO_INIT("atsc");
1303  update_info(info, *tvct_it, i);
1304  }
1305  }
1306 
1307  // SDTs
1308  sdt_map_t::const_iterator sdt_list_it = scan_info->sdts.begin();
1309  for (; sdt_list_it != scan_info->sdts.end(); ++sdt_list_it)
1310  {
1311  sdt_vec_t::const_iterator sdt_it = (*sdt_list_it).begin();
1312  for (; sdt_it != (*sdt_list_it).end(); ++sdt_it)
1313  {
1314  for (uint i = 0; i < (*sdt_it)->ServiceCount(); ++i)
1315  {
1316  uint pnum = (*sdt_it)->ServiceID(i);
1317  PCM_INFO_INIT("dvb");
1318  update_info(info, *sdt_it, i, m_defAuthorities);
1319  }
1320  }
1321  }
1322 
1323  // NIT
1324  QMap<qlonglong, uint> ukChanNums;
1325  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1326  for (dbchan_it = pnum_to_dbchan.begin();
1327  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1328  {
1329  ChannelInsertInfo &info = *dbchan_it;
1330 
1331  // NIT
1332  nit_vec_t::const_iterator nits_it = scan_info->nits.begin();
1333  for (; nits_it != scan_info->nits.end(); ++nits_it)
1334  {
1335  for (uint i = 0; i < (*nits_it)->TransportStreamCount(); ++i)
1336  {
1337  const NetworkInformationTable *nit = (*nits_it);
1338  if ((nit->TSID(i) == info.sdt_tsid) &&
1339  (nit->OriginalNetworkID(i) == info.orig_netid))
1340  {
1341  info.netid = nit->NetworkID();
1342  info.in_nit = true;
1343  }
1344  else
1345  {
1346  continue;
1347  }
1348 
1349  // Get channel numbers from UK Frequency List Descriptors
1350  const desc_list_t &list =
1352  nit->TransportDescriptorsLength(i));
1353 
1354  const unsigned char *desc =
1357 
1358  if (desc)
1359  {
1360  DVBLogicalChannelDescriptor uklist(desc);
1361  for (uint j = 0; j < uklist.ChannelCount(); ++j)
1362  {
1363  ukChanNums[((qlonglong)info.orig_netid<<32) |
1364  uklist.ServiceID(j)] =
1365  uklist.ChannelNumber(j);
1366  }
1367  }
1368  }
1369  }
1370  }
1371 
1372  // Get IPTV or DVB Logical channel numbers
1373  for (dbchan_it = pnum_to_dbchan.begin();
1374  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1375  {
1376  ChannelInsertInfo &info = *dbchan_it;
1377 
1378  if (!info.chan_num.isEmpty())
1379  continue;
1380 
1381  if (iptv_channel.isEmpty()) // DVB Logical channel numbers (LCN)
1382  {
1383  QMap<qlonglong, uint>::const_iterator it = ukChanNums.find
1384  (((qlonglong)info.orig_netid<<32) | info.service_id);
1385 
1386  if (it != ukChanNums.end())
1387  info.chan_num = QString::number(*it);
1388  }
1389  else // IPTV programs
1390  {
1391  info.chan_num = iptv_channel;
1392  if (info.service_id)
1393  info.chan_num += "-" + QString::number(info.service_id);
1394  }
1395 
1396  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1397  QString("GetChannelList: set chan_num '%1'").arg(info.chan_num));
1398  }
1399 
1400  // Get QAM/SCTE/MPEG channel numbers
1401  for (dbchan_it = pnum_to_dbchan.begin();
1402  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1403  {
1404  ChannelInsertInfo &info = *dbchan_it;
1405 
1406  if (!info.chan_num.isEmpty())
1407  continue;
1408 
1409  if ((info.si_standard == "mpeg") ||
1410  (info.si_standard == "scte") ||
1411  (info.si_standard == "opencable"))
1412  {
1413  if (info.freqid.isEmpty())
1414  info.chan_num = QString("%1-%2")
1415  .arg(info.source_id)
1416  .arg(info.service_id);
1417  else
1418  info.chan_num = QString("%1-%2")
1419  .arg(info.freqid)
1420  .arg(info.service_id);
1421  }
1422  }
1423 
1424  // Check for decryption success
1425  for (dbchan_it = pnum_to_dbchan.begin();
1426  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1427  {
1428  uint pnum = dbchan_it.key();
1429  ChannelInsertInfo &info = *dbchan_it;
1430  info.decryption_status = scan_info->program_encryption_status[pnum];
1431  }
1432 
1433  return pnum_to_dbchan;
1434 }
1435 
1437 {
1438  ScanDTVTransportList list;
1439 
1440  uint cardid = m_channel->GetInputID();
1441 
1443  tuner_type = GuessDTVTunerType(tuner_type);
1444 
1445  ChannelList::const_iterator it = m_channelList.begin();
1446  for (; it != m_channelList.end(); ++it)
1447  {
1448  QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1449  GetChannelList(it->first, it->second);
1450 
1451  ScanDTVTransport item((*it->first).tuning, tuner_type, cardid);
1452  item.iptv_tuning = (*(it->first)).iptv_tuning;
1453 
1454  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1455  for (dbchan_it = pnum_to_dbchan.begin();
1456  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1457  {
1458  item.channels.push_back(*dbchan_it);
1459  }
1460 
1461  if (item.channels.size())
1462  {
1463  if (addFullTS)
1464  {
1465  /* If addFullTS, then add a 'MPTS' channel
1466  which can be used to record the entire MPTS from
1467  the transport. */
1468  dbchan_it = pnum_to_dbchan.begin();
1469  ChannelInsertInfo info = *dbchan_it;
1470 
1471  if (tuner_type == DTVTunerType::kTunerTypeASI)
1472  info.callsign = QString("MPTS_%1")
1473  .arg(CardUtil::GetDisplayName(cardid));
1474  else if (info.si_standard == "mpeg" ||
1475  info.si_standard == "scte" ||
1476  info.si_standard == "opencable")
1477  info.callsign = QString("MPTS_%1").arg(info.freqid);
1478  else if (info.atsc_major_channel > 0)
1479  info.callsign =
1480  QString("MPTS_%1").arg(info.atsc_major_channel);
1481  else if (info.service_id > 0)
1482  info.callsign = QString("MPTS_%1").arg(info.service_id);
1483  else if (!info.chan_num.isEmpty())
1484  info.callsign = QString("MPTS_%1").arg(info.chan_num);
1485  else
1486  info.callsign = "MPTS_UNKNOWN";
1487 
1488  info.service_name = info.callsign;
1489  info.service_id = 0;
1490  info.atsc_minor_channel = 0;
1491  info.format = "MPTS";
1492  item.channels.push_back(info);
1493  }
1494 
1495  list.push_back(item);
1496  }
1497  }
1498 
1499  return list;
1500 }
1501 
1502 
1504 {
1505  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1506 }
1507 
1509 {
1510 #ifdef USING_DVB
1511  return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1512 #else
1513  return nullptr;
1514 #endif
1515 }
1516 
1518 {
1519  return dynamic_cast<DTVChannel*>(m_channel);
1520 }
1521 
1523 {
1524  return dynamic_cast<const DTVChannel*>(m_channel);
1525 }
1526 
1528 {
1529 #ifdef USING_HDHOMERUN
1530  return dynamic_cast<HDHRChannel*>(m_channel);
1531 #else
1532  return nullptr;
1533 #endif
1534 }
1535 
1537 {
1538 #ifdef USING_DVB
1539  return dynamic_cast<DVBChannel*>(m_channel);
1540 #else
1541  return nullptr;
1542 #endif
1543 }
1544 
1546 {
1547 #ifdef USING_DVB
1548  return dynamic_cast<const DVBChannel*>(m_channel);
1549 #else
1550  return nullptr;
1551 #endif
1552 }
1553 
1555 {
1556 #ifdef USING_V4L2
1557  return dynamic_cast<V4LChannel*>(m_channel);
1558 #else
1559  return nullptr;
1560 #endif
1561 }
1562 
1567 {
1568  while (m_scannerThread)
1569  {
1570  m_threadExit = true;
1571  if (m_scannerThread->wait(1000))
1572  {
1573  delete m_scannerThread;
1574  m_scannerThread = nullptr;
1575  }
1576  }
1577  m_threadExit = false;
1578  m_scannerThread = new MThread("Scanner", this);
1580 }
1581 
1586 {
1587  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
1588 
1589  while (!m_threadExit)
1590  {
1591  if (m_scanning)
1592  HandleActiveScan();
1593 
1594  usleep(10 * 1000);
1595  }
1596 
1597  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
1598 }
1599 
1600 // See if we have timed out
1602 {
1604  (m_timer.elapsed() > kDecryptionTimeout))
1605  {
1607  return true;
1608  }
1609 
1610  if (!m_waitingForTables)
1611  return true;
1612 
1613 #ifdef USING_DVB
1614  // If the rotor is still moving, reset the timer and keep waiting
1616  if (sigmon)
1617  {
1618  const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
1619  if (rotor)
1620  {
1621  bool was_moving, is_moving;
1622  sigmon->GetRotorStatus(was_moving, is_moving);
1623  if (was_moving && !is_moving)
1624  {
1625  m_timer.restart();
1626  return false;
1627  }
1628  }
1629  }
1630 #endif // USING_DVB
1631 
1632 
1633  // have the tables have timed out?
1634  if (m_timer.elapsed() > (int)m_channelTimeout)
1635  {
1636  // the channelTimeout alone is only valid if we have seen no tables..
1637  const ScanStreamData *sd = nullptr;
1638  if (GetDTVSignalMonitor())
1640 
1641  if (!sd)
1642  return true;
1643 
1644  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
1645  return m_timer.elapsed() > (int) kDVBTableTimeout;
1646  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
1647  return m_timer.elapsed() > (int) kATSCTableTimeout;
1648  if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
1649  return m_timer.elapsed() > (int) kMPEGTableTimeout;
1650 
1651  return true;
1652  }
1653 
1654  // ok the tables haven't timed out, but have we hit the signal timeout?
1656  if ((m_timer.elapsed() > (int)(*m_current).timeoutTune) &&
1657  sm && !sm->HasSignalLock())
1658  {
1659  const ScanStreamData *sd = nullptr;
1660  if (GetDTVSignalMonitor())
1662 
1663  if (!sd)
1664  return true;
1665 
1666  // Just is case we temporarily lose the signal after we've seen
1667  // tables...
1668  if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
1669  !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
1670  !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
1671  {
1672  return true;
1673  }
1674  }
1675 
1676  return false;
1677 }
1678 
1683 {
1684  QMutexLocker locker(&m_lock);
1685 
1686  bool do_post_insertion = m_waitingForTables;
1687 
1688  if (!HasTimedOut())
1689  return;
1690 
1691  if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
1692  {
1693  m_channelList.clear();
1694  m_channelsFound = 0;
1695  m_dvbt2Tried = true;
1696  }
1697 
1699  {
1700  // If we failed to get a lock with DVB-T try DVB-T2.
1701  m_dvbt2Tried = true;
1703  return;
1704  }
1705 
1706  if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
1707  {
1708  // Add channel to scanned list and potentially check decryption
1709  if (do_post_insertion && !UpdateChannelInfo(false))
1710  return;
1711 
1712  // Stop signal monitor for previous transport
1713  locker.unlock();
1714  m_signalMonitor->Stop();
1715  locker.relock();
1716  }
1717 
1718  m_current = m_nextIt; // Increment current
1719  m_dvbt2Tried = false;
1720 
1721  if (m_current != m_scanTransports.end())
1722  {
1724 
1725  // Increment nextIt
1726  m_nextIt = m_current;
1727  ++m_nextIt;
1728  }
1729  else if (!m_extendTransports.isEmpty())
1730  {
1731  --m_current;
1732  QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
1733  while (it != m_extendTransports.end())
1734  {
1735  if (!m_tsScanned.contains(it.key()))
1736  {
1737  QString name = QString("TransportID %1").arg(it.key() & 0xffff);
1739  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
1740  item.tuning.toString());
1741  m_scanTransports.push_back(item);
1742  m_tsScanned.insert(it.key());
1743  }
1744  ++it;
1745  }
1746  m_extendTransports.clear();
1747  m_nextIt = m_current;
1748  ++m_nextIt;
1749  }
1750  else
1751  {
1753  m_scanning = false;
1755  }
1756 }
1757 
1759 {
1760  const TransportScanItem &item = *transport;
1761 
1762 #ifdef USING_DVB
1763  if (GetDVBSignalMonitor())
1764  {
1765  // always wait for rotor to finish
1768  }
1769 #endif // USING_DVB
1770 
1771  if (!GetDTVChannel())
1772  return false;
1773 
1774  if (item.mplexid > 0 && transport.offset() == 0)
1776 
1777  if (item.tuning.sistandard == "MPEG")
1778  return GetDTVChannel()->Tune(item.iptv_tuning, true);
1779 
1780  const uint64_t freq = item.freq_offset(transport.offset());
1781  DTVMultiplex tuning = item.tuning;
1782  tuning.frequency = freq;
1783 
1785  {
1786  if (m_dvbt2Tried)
1788  else
1790  }
1791 
1792  return GetDTVChannel()->Tune(tuning);
1793 }
1794 
1796 {
1797  QString offset_str = (transport.offset()) ?
1798  QObject::tr(" offset %2").arg(transport.offset()) : "";
1799  QString cur_chan = QString("%1%2")
1800  .arg((*m_current).FriendlyName).arg(offset_str);
1801  QString tune_msg_str =
1802  QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
1803  .arg(cur_chan).arg((*m_current).mplexid);
1804 
1805  const TransportScanItem &item = *transport;
1806 
1807  if (transport.offset() &&
1808  (item.freq_offset(transport.offset()) == item.freq_offset(0)))
1809  {
1810  m_waitingForTables = false;
1811  return; // nothing to do
1812  }
1813 
1814  if (m_channelsFound)
1815  {
1816  QString progress = QObject::tr(": Found %n", "", m_channelsFound);
1818  }
1819 
1821  LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
1822 
1823  if (!Tune(transport))
1824  { // If we did not tune successfully, bail with message
1826  LOG(VB_CHANSCAN, LOG_ERR, LOC +
1827  QString("Failed to tune %1 mplexid(%2) at offset %3")
1828  .arg(item.FriendlyName).arg(item.mplexid)
1829  .arg(transport.offset()));
1830  return;
1831  }
1832 
1833  // If we have a DTV Signal Monitor, perform table scanner reset
1834  if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
1835  {
1837  GetDTVSignalMonitor()->SetChannel(-1,-1);
1838  }
1839 
1840  // Start signal monitor for this channel
1842 
1843  m_timer.start();
1844  m_waitingForTables = (item.tuning.sistandard != "analog");
1845 }
1846 
1852 {
1853  LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
1854 
1855  while (m_scannerThread)
1856  {
1857  m_threadExit = true;
1858  if (m_scannerThread->wait(1000))
1859  {
1860  delete m_scannerThread;
1861  m_scannerThread = nullptr;
1862  }
1863  }
1864 
1865  if (m_signalMonitor)
1866  m_signalMonitor->Stop();
1867 }
1868 
1874  int SourceID,
1875  const QString &std,
1876  const QString &modulation,
1877  const QString &country,
1878  const QString &table_start,
1879  const QString &table_end)
1880 {
1881  QString name("");
1882  if (m_scanning)
1883  return false;
1884 
1885  m_scanTransports.clear();
1886  m_nextIt = m_scanTransports.end();
1887 
1888  freq_table_list_t tables =
1889  get_matching_freq_tables(std, modulation, country);
1890 
1891  if (tables.size() == 0)
1892  {
1893  QString msg = QString("No freq table for (%1, %2, %3) found")
1894  .arg(std).arg(modulation).arg(country);
1896  }
1897  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1898  QString("Looked up freq table (%1, %2, %3) w/%4 entries")
1899  .arg(std).arg(modulation).arg(country).arg(tables.size()));
1900 
1901  QString start = table_start;
1902  QString end = table_end;
1903  freq_table_list_t::iterator it = tables.begin();
1904  for (; it != tables.end(); ++it)
1905  {
1906  const FrequencyTable &ft = **it;
1907  int name_num = ft.name_offset;
1908  QString strNameFormat = ft.name_format;
1909  uint freq = ft.frequencyStart;
1910  while (freq <= ft.frequencyEnd)
1911  {
1912  name = strNameFormat;
1913  if (strNameFormat.indexOf("%") >= 0)
1914  name = strNameFormat.arg(name_num);
1915 
1916  if (start.isEmpty() || name == start)
1917  {
1918  start.clear();
1919 
1920  TransportScanItem item(SourceID, std, name, name_num,
1921  freq, ft, m_signalTimeout);
1922  m_scanTransports.push_back(item);
1923 
1924  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
1925  item.toString());
1926  }
1927 
1928  ++name_num;
1929  freq += ft.frequencyStep;
1930 
1931  if (!end.isEmpty() && name == end)
1932  break;
1933  }
1934  if (!end.isEmpty() && name == end)
1935  break;
1936  }
1937 
1938  while (!tables.empty())
1939  {
1940  delete tables.back();
1941  tables.pop_back();
1942  }
1943 
1944  m_extendScanList = true;
1945  m_timer.start();
1946  m_waitingForTables = false;
1947 
1948  m_nextIt = m_scanTransports.begin();
1949  m_transportsScanned = 0;
1950  m_scanning = true;
1951 
1952  return true;
1953 }
1954 
1956  const QString &std,
1957  const QString &cardtype,
1958  const DTVChannelList &channels)
1959 {
1960  m_scanTransports.clear();
1961  m_nextIt = m_scanTransports.end();
1962 
1963  DTVTunerType tunertype;
1964  tunertype.Parse(cardtype);
1965 
1966  DTVChannelList::const_iterator it = channels.begin();
1967  for (uint i = 0; it != channels.end(); ++it, ++i)
1968  {
1969  DTVTransport tmp = *it;
1970  tmp.sistandard = std;
1971  TransportScanItem item(sourceid, QString::number(i),
1972  tunertype, tmp, m_signalTimeout);
1973 
1974  m_scanTransports.push_back(item);
1975 
1976  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
1977  }
1978 
1979  if (m_scanTransports.empty())
1980  {
1981  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
1982  return false;
1983  }
1984 
1985  m_timer.start();
1986  m_waitingForTables = false;
1987 
1988  m_nextIt = m_scanTransports.begin();
1989  m_transportsScanned = 0;
1990  m_scanning = true;
1991 
1992  return true;
1993 }
1994 
1996  const fbox_chan_map_t &iptv_channels)
1997 {
1998  m_scanTransports.clear();
1999  m_nextIt = m_scanTransports.end();
2000 
2001  fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2002  for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2003  {
2004  TransportScanItem item(sourceid, QString::number(idx),
2005  Ichan.value().m_tuning, Ichan.key(),
2006  m_signalTimeout);
2007 
2008  m_scanTransports.push_back(item);
2009 
2010  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2011  }
2012 
2013  if (m_scanTransports.empty())
2014  {
2015  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2016  return false;
2017  }
2018 
2019  m_timer.start();
2020  m_waitingForTables = false;
2021 
2022  m_nextIt = m_scanTransports.begin();
2023  m_transportsScanned = 0;
2024  m_scanning = true;
2025 
2026  return true;
2027 }
2028 
2029 
2035  int sourceid, const QMap<QString,QString> &startChan)
2036 {
2037  if (startChan.find("std") == startChan.end() ||
2038  startChan.find("type") == startChan.end())
2039  {
2040  return false;
2041  }
2042 
2043  QString std = *startChan.find("std");
2044  QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
2045  bool ok = false;
2046 
2047  if (m_scanning)
2048  return false;
2049 
2050  m_scanTransports.clear();
2051  m_nextIt = m_scanTransports.end();
2052 
2053  DTVMultiplex tuning;
2054 
2056  ok = type.Parse(startChan["type"]);
2057 
2058  if (ok)
2059  {
2060  ok = tuning.ParseTuningParams(
2061  type,
2062  startChan["frequency"], startChan["inversion"],
2063  startChan["symbolrate"], startChan["fec"],
2064  startChan["polarity"],
2065  startChan["coderate_hp"], startChan["coderate_lp"],
2066  startChan["constellation"], startChan["trans_mode"],
2067  startChan["guard_interval"], startChan["hierarchy"],
2068  startChan["modulation"], startChan["bandwidth"],
2069  startChan["mod_sys"], startChan["rolloff"]);
2070  }
2071 
2072  if (ok)
2073  {
2074  tuning.sistandard = si_std;
2075  TransportScanItem item(
2076  sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2077  tuning, m_signalTimeout);
2078  m_scanTransports.push_back(item);
2079  }
2080 
2081  if (!ok)
2082  return false;
2083 
2084  m_extendScanList = true;
2085 
2086  m_timer.start();
2087  m_waitingForTables = false;
2088 
2089  m_nextIt = m_scanTransports.begin();
2090  m_transportsScanned = 0;
2091  m_scanning = true;
2092 
2093  return true;
2094 }
2095 
2097 {
2098  MSqlQuery query(MSqlQuery::InitCon());
2099  query.prepare(
2100  "SELECT sourceid, sistandard, transportid, frequency, modulation "
2101  "FROM dtv_multiplex "
2102  "WHERE mplexid = :MPLEXID");
2103  query.bindValue(":MPLEXID", mplexid);
2104  if (!query.exec())
2105  {
2106  MythDB::DBError("ChannelScanSM::AddToList()", query);
2107  return false;
2108  }
2109 
2110  if (!query.next())
2111  {
2112  LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2113  QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2114  return false;
2115  }
2116 
2117  uint sourceid = query.value(0).toUInt();
2118  QString sistandard = query.value(1).toString();
2119  uint tsid = query.value(2).toUInt();
2121 
2122  QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2123  QString("Multiplex #%1").arg(mplexid);
2124 
2125  if (query.value(4).toString() == "8vsb")
2126  {
2127  QString chan = QString("%1 Hz").arg(query.value(3).toInt());
2128  struct CHANLIST *curList = chanlists[0].list;
2129  int totalChannels = chanlists[0].count;
2130  int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2131  for (int x = 0 ; x < totalChannels ; ++x)
2132  {
2133  if ((curList[x].freq <= findFrequency + 200) &&
2134  (curList[x].freq >= findFrequency - 200))
2135  {
2136  chan = QString("%1").arg(curList[x].name);
2137  }
2138  }
2139  fn = QObject::tr("ATSC Channel %1").arg(chan);
2141  }
2142 
2143  tt = GuessDTVTunerType(tt);
2144 
2145  TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2146 
2147  if (item.tuning.FillFromDB(tt, mplexid))
2148  {
2149  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2150  m_scanTransports.push_back(item);
2151  return true;
2152  }
2153 
2154  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2155  return false;
2156 }
2157 
2158 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2159 {
2160  m_scanTransports.clear();
2161  m_nextIt = m_scanTransports.end();
2162 
2163  AddToList(mplexid);
2164 
2165  m_timer.start();
2166  m_waitingForTables = false;
2167 
2168  m_extendScanList = follow_nit;
2169  m_transportsScanned = 0;
2170  if (!m_scanTransports.empty())
2171  {
2172  m_nextIt = m_scanTransports.begin();
2173  m_scanning = true;
2174  return true;
2175  }
2176 
2177  return false;
2178 }
2179 
2180 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2181 {
2182  m_scanTransports.clear();
2183  m_nextIt = m_scanTransports.end();
2184 
2185  m_signalTimeout = 30000;
2186  QString name;
2187  TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2188  m_scanTransports.push_back(item);
2189 
2190  m_timer.start();
2191  m_waitingForTables = false;
2192  m_extendScanList = false;
2193  m_transportsScanned = 0;
2194  m_nextIt = m_scanTransports.begin();
2195  m_scanning = true;
2196  return true;
2197 }
2198 
2203  const DTVChannelInfoList &channels,
2204  uint mpeg_program_num,
2205  QString &service_name,
2206  QString &callsign,
2207  QString &common_status_info)
2208 {
2209  if (channels.empty())
2210  return true;
2211 
2212  bool found = false;
2213  for (uint i = 0; i < channels.size(); ++i)
2214  {
2215  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2216  QString("comparing %1 %2 against %3 %4")
2217  .arg(channels[i].serviceid).arg(channels[i].name)
2218  .arg(mpeg_program_num).arg(common_status_info));
2219 
2220  if (channels[i].serviceid == mpeg_program_num)
2221  {
2222  found = true;
2223  if (!channels[i].name.isEmpty())
2224  {
2225  service_name = channels[i].name;
2226  callsign = channels[i].name;
2227  }
2228  }
2229  }
2230 
2231  if (found)
2232  {
2233  common_status_info += QString(" %1 %2")
2234  .arg(QObject::tr("as")).arg(service_name);
2235  }
2236  else
2237  {
2239  QObject::tr("Skipping %1, not in imported channel map")
2240  .arg(common_status_info));
2241  }
2242 
2243  return found;
2244 }
bool ScanTransportsStartingOn(int sourceid, const QMap< QString, QString > &valueMap)
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
bool HasCachedAnyNIT(bool current=true) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
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:295
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:105
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)
Definition: mythdbcon.cpp:875
void ScanUpdateStatusTitleText(const QString &status)
uint64_t frequencyEnd
The ending centre frequency.
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
static const int kTunerTypeDVBT
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void UpdateScanTransports(const NetworkInformationTable *nit)
bool IsDTV(void) const
static desc_list_t ParseOnlyInclude(const unsigned char *data, uint len, int descriptorid)
virtual void Start()
Start signal monitoring thread.
IPTVTuningData iptv_tuning
Definition: dtvmultiplex.h:102
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
QString name_format
pretty name format
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
volatile bool m_threadExit
static const int kTunerTypeUnknown
QString toString(void) const override
Definition: mpegtables.cpp:870
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:312
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:132
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:557
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:72
bool ScanTransport(uint mplexid, bool follow_nit)
uint DescriptorTag(void) const
DVB Logical Channel Descriptor.
ChannelList m_channelList
Found Channel Info.
uint64_t frequencyStart
The staring centre frequency.
uint TSID(uint i) const
Definition: dvbtables.h:221
void ScanPercentComplete(int pct)
DTVMultiplex tuning
Tuning info.
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:509
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
QMap< QString, IPTVChannelInfo > fbox_chan_map_t
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)
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.
bool HasCachedAllNIT(bool current=true) const
QString toString(void) const override
Definition: atsctables.cpp:69
static const uint64_t kDTVSigMon_WaitForNIT
virtual bool TuneMultiplex(uint mplexid, QString inputname)
To be used by the channel scanner and possibly the EIT scanner.
Definition: dtvchannel.cpp:393
QString toString(void) const override
Definition: atsctables.cpp:202
QString sistandard
Definition: dtvmultiplex.h:101
Overall structure.
QVariant value(int i) const
Definition: mythdbcon.h:182
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
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
uint mplexid
DB Mplexid.
uint frequencyStep
The step in frequency.
void SetChannel(int major, int minor)
struct CHANLISTS chanlists[]
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
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
uint StreamCount(void) const
Definition: mpegtables.h:714
bool IsHiddenInGuide(uint i) const
Definition: atsctables.h:288
QString default_authority
Definition: channelinfo.h:237
uint64_t frequency
Definition: dtvmultiplex.h:84
bool HasCachedAllPMTs(void) const
IPTVTuningData iptv_tuning
IPTV Tuning info.
void Reset(void) override
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)
QMap< uint, uint > program_encryption_status
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:188
void SetAnalog(bool is_analog)
Rotor class.
Definition: diseqc.h:292
QString FriendlyName
Name to display in scanner dialog.
QMap< uint, pat_vec_t > pat_map_t
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
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
QString service_name
Definition: channelinfo.h:225
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
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 *)
void HandleSDTo(uint tsid, const ServiceDescriptionTable *) override
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:144
const char * name
Definition: ParseText.cpp:339
ChannelInsertInfoList channels
Definition: dtvmultiplex.h:130
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 TransportStreamCount(void) const
Definition: dvbtables.h:216
virtual bool Tune(const DTVMultiplex &tuning)=0
This performs the actual frequency tuning and in some cases input switching.
QString DefaultAuthority(void) const
void HandleBAT(const BouquetAssociationTable *) override
const MasterGuideTable * GetCachedMGT(bool current=true) const
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
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
bool ScanTransports(int src, const QString &std, const QString &mod, const QString &table, 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...
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:819
int name_offset
Offset to add to the pretty name.
vector< DTVChannelInfo > DTVChannelInfoList
Definition: dtvconfparser.h:62
Scanning class for cards that support a SignalMonitor class.
static QString loc(const ChannelScanSM *)
static const int kTunerTypeASI
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
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:138
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
uint64_t freq_offset(uint i) const
QString toString(void) const override
Definition: mpegtables.cpp:806
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
bool ParseTuningParams(DTVTunerType type, QString frequency, QString inversion, QString symbolrate, QString fec, QString polarity, QString hp_code_rate, QString lp_code_rate, QString constellation, QString trans_mode, QString guard_interval, QString hierarchy, QString modulation, QString bandwidth, QString mod_sys, QString rolloff)
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
bool IsEncrypted(QString sistandard) const
Returns true iff PMT contains CA descriptor for a vid/aud stream.
Definition: mpegtables.cpp:552
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 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
void UpdateScanPercentCompleted(void)
Updates Transport Scan progress bar.
QString toString(void) const override
Definition: dvbtables.cpp:175
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:615
transport_scan_items_it_t m_nextIt
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
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:89
#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)
const unsigned char * ProgramInfo(void) const
Definition: mpegtables.h:699
uint TransportStreamID() const
Definition: atsctables.h:218
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
void ScanUpdateStatusText(const QString &status)
void HandleVCT(uint tsid, const VirtualChannelTable *) override
DTVModulationSystem mod_sys
modulation system (only DVB-S or DVB-S2 atm)
Definition: dtvmultiplex.h:96
const MasterGuideTable * mgt
virtual bool FillFromDB(DTVTunerType type, uint mplexid)
QPair< transport_scan_items_it_t, ScannedChannelInfo * > ChannelListItem
QString ServiceName(void) const
ScanMonitor * m_scanMonitor
uint ProgramPID(uint i) const
Definition: mpegtables.h:610
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1251
QMutex m_lock
The big lock.
bool HasCachedAnyPAT(uint tsid) const
Always MPEG-2??
Definition: mpegtables.h:117