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 m_pats.empty() && m_pmts.empty() &&
96  m_program_encryption_status.isEmpty() &&
97  !m_mgt && m_cvcts.empty() && m_tvcts.empty() &&
98  m_nits.empty() && m_sdts.empty();
99  }
100 
101  // MPEG
104  QMap<uint,uint> m_program_encryption_status; // pnum->enc_status
105 
106  // ATSC
107  const MasterGuideTable *m_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_inputName(_inputname),
153  m_testDecryption(test_decryption),
154  // Misc
155  m_analogSignalHandler(new AnalogSignalHandler(this))
156 {
157  m_current = m_scanTransports.end();
158 
159  // Create a stream data for digital signal monitors
160  DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
161  if (dtvSigMon)
162  {
163  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Connecting up DTVSignalMonitor");
164  ScanStreamData *data = new ScanStreamData();
165 
166  MSqlQuery query(MSqlQuery::InitCon());
167  query.prepare(
168  "SELECT dvb_nit_id "
169  "FROM videosource "
170  "WHERE videosource.sourceid = :SOURCEID");
171  query.bindValue(":SOURCEID", _sourceID);
172  if (!query.exec() || !query.isActive())
173  {
174  MythDB::DBError("ChannelScanSM", query);
175  }
176  else if (query.next())
177  {
178  int nitid = query.value(0).toInt();
179  data->SetRealNetworkID(nitid);
180  LOG(VB_CHANSCAN, LOG_INFO, LOC +
181  QString("Setting NIT-ID to %1").arg(nitid));
182  }
183 
184  dtvSigMon->SetStreamData(data);
189 
190 #ifdef USING_DVB
191  DVBChannel *dvbchannel = dynamic_cast<DVBChannel*>(m_channel);
192  if (dvbchannel && dvbchannel->GetRotor())
194 #endif
195 
196  data->AddMPEGListener(this);
197  data->AddATSCMainListener(this);
198  data->AddDVBMainListener(this);
199  data->AddDVBOtherListener(this);
200  }
201 }
202 
204 {
205  StopScanner();
206  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
207 
208  ScanStreamData *sd = nullptr;
209  if (GetDTVSignalMonitor())
210  {
212  }
213 
214  if (m_signalMonitor)
215  {
217  delete m_signalMonitor;
218  m_signalMonitor = nullptr;
219  }
220 
221  delete sd;
222 
224  {
225  delete m_analogSignalHandler;
226  m_analogSignalHandler = nullptr;
227  }
228 
230 }
231 
232 void ChannelScanSM::SetAnalog(bool is_analog)
233 {
235 
236  if (is_analog)
238 }
239 
241 {
242  QMutexLocker locker(&m_lock);
243 
244  QString cur_chan = (*m_current).m_friendlyName;
245  QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
246  QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
247 
248  QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
249 
250  if (!ChannelUtil::FindChannel(m_sourceID, freqid))
251  {
252  int chanid = ChannelUtil::CreateChanID(m_sourceID, freqid);
253 
254  QString callsign = QString("%1-%2")
255  .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
256 
257  bool ok = ChannelUtil::CreateChannel(
258  0 /* mplexid */,
259  m_sourceID,
260  chanid,
261  callsign,
262  "" /* service name */,
263  freqid /* channum */,
264  0 /* service id */,
265  0 /* ATSC major channel */,
266  0 /* ATSC minor channel */,
267  false /* use on air guide */,
268  false /* hidden */,
269  false /* hidden in guide */,
270  freqid);
271 
272  msg = (ok) ?
273  QObject::tr("Added Channel %1").arg(cur_chan) :
274  QObject::tr("Failed to add channel %1").arg(cur_chan);
275  }
276  else
277  {
278  // nothing to do here, XMLTV has better info
279  }
280 
282 
283  // tell UI we are done with these channels
284  if (m_scanning)
285  {
287  m_waitingForTables = false;
289  m_dvbt2Tried = true;
290  }
291 }
292 
304 bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
305 {
306  if (m_scanning)
307  return false;
308 
309  m_scanTransports.clear();
310  m_nextIt = m_scanTransports.end();
311 
312  vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
313 
314  if (multiplexes.empty())
315  {
316  LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
317  QString("sourceid %1").arg(sourceid));
318 
319  return false;
320  }
321 
322  for (size_t i = 0; i < multiplexes.size(); ++i)
323  AddToList(multiplexes[i]);
324 
325  m_extendScanList = follow_nit;
326  m_waitingForTables = false;
328  if (!m_scanTransports.empty())
329  {
330  m_nextIt = m_scanTransports.begin();
331  m_scanning = true;
332  }
333  else
334  {
335  LOG(VB_CHANSCAN, LOG_ERR, LOC +
336  "Unable to find add any transports for " +
337  QString("sourceid %1").arg(sourceid));
338 
339  return false;
340  }
341 
342 
343  return m_scanning;
344 }
345 
346 void ChannelScanSM::LogLines(const QString& string) const
347 {
348  QStringList lines = string.split('\n');
349  for (int i = 0; i < lines.size(); ++i)
350  LOG(VB_CHANSCAN, LOG_DEBUG, lines[i]);
351 }
352 
354 {
355  QMutexLocker locker(&m_lock);
356 
357  LOG(VB_CHANSCAN, LOG_INFO, LOC +
358  QString("Got a Program Association Table for %1")
359  .arg((*m_current).m_friendlyName));
360  LogLines(pat->toString());
361 
362  // Add pmts to list, so we can do MPEG scan properly.
364  for (uint i = 0; i < pat->ProgramCount(); ++i)
365  {
366  if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
367  sd->AddListeningPID(pat->ProgramPID(i));
368  }
369 }
370 
371 void ChannelScanSM::HandlePMT(uint /*program_num*/, const ProgramMapTable *pmt)
372 {
373  QMutexLocker locker(&m_lock);
374 
375  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1")
376  .arg((*m_current).m_friendlyName));
377  LogLines(pmt->toString());
378 
380  pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
382 }
383 
385 {
386  QMutexLocker locker(&m_lock);
387 
388  LOG(VB_CHANSCAN, LOG_INFO, LOC +
389  QString("Got a Virtual Channel Table for %1")
390  .arg((*m_current).m_friendlyName));
391  LogLines(vct->toString());
392 
393  for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
394  {
395  if (vct->IsAccessControlled(i))
396  {
398  }
399  }
400 
401  UpdateChannelInfo(true);
402 }
403 
405 {
406  QMutexLocker locker(&m_lock);
407 
408  LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
409  .arg((*m_current).m_friendlyName));
410  LogLines(mgt->toString());
411 
412  UpdateChannelInfo(true);
413 }
414 
423 {
424  QMutexLocker locker(&m_lock);
425 
426  LOG(VB_CHANSCAN, LOG_INFO, LOC +
427  QString("Got a Service Description Table for %1")
428  .arg((*m_current).m_friendlyName));
429  LogLines(sdt->toString());
430 
431  // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
432  if (!m_setOtherTables && (sdt->OriginalNetworkID() == 2 ||
433  sdt->OriginalNetworkID() == 59))
434  {
436  SetFreesatAdditionalSI(true);
437  m_setOtherTables = true;
438  // The whole BAT & SDTo group comes round in 10s
439  m_otherTableTimeout = 10000;
440  // Delay processing the SDT until we've seen BATs and SDTos
442 
443  LOG(VB_CHANSCAN, LOG_INFO, LOC +
444  QString("SDT has OriginalNetworkID %1, look for "
445  "additional Freesat SI").arg(sdt->OriginalNetworkID()));
446  }
447 
448  if ((uint)m_timer.elapsed() < m_otherTableTime)
449  {
450  // Set the version for the SDT so we see it again.
452  SetVersionSDT(sdt->TSID(), -1, 0);
453  }
454 
455  uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
456  m_tsScanned.insert(id);
457 
458  for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
459  {
460  if (sdt->IsEncrypted(i))
461  {
463  }
464  }
465 
466  UpdateChannelInfo(true);
467 }
468 
470 {
471  QMutexLocker locker(&m_lock);
472 
473  LOG(VB_CHANSCAN, LOG_INFO, LOC +
474  QString("Got a Network Information Table for %1")
475  .arg((*m_current).m_friendlyName));
476  LogLines(nit->toString());
477 
478  UpdateChannelInfo(true);
479 }
480 
482 {
483  QMutexLocker locker(&m_lock);
484 
485  LOG(VB_CHANSCAN, LOG_INFO, LOC +
486  QString("Got a Bouquet Association Table for %1")
487  .arg((*m_current).m_friendlyName));
488  LogLines(bat->toString());
489 
491 
492  for (uint i = 0; i < bat->TransportStreamCount(); ++i)
493  {
494  uint tsid = bat->TSID(i);
495  uint netid = bat->OriginalNetworkID(i);
496  desc_list_t parsed =
499  // Look for default authority
500  const unsigned char *def_auth =
502  const unsigned char *serv_list =
504 
505  if (def_auth && serv_list)
506  {
507  DefaultAuthorityDescriptor authority(def_auth);
508  ServiceListDescriptor services(serv_list);
509  if (!authority.IsValid() || !services.IsValid())
510  continue;
511 
512  for (uint j = 0; j < services.ServiceCount(); ++j)
513  {
514  // If the default authority is given in the SDT this
515  // overrides any definition in the BAT (or in the NIT)
516  LOG(VB_CHANSCAN, LOG_INFO, LOC +
517  QString("found default authority(BAT) for service %1 %2 %3")
518  .arg(netid).arg(tsid).arg(services.ServiceID(j)));
519  uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
520  services.ServiceID(j);
521  if (! m_defAuthorities.contains(index))
522  m_defAuthorities[index] = authority.DefaultAuthority();
523  }
524  }
525  }
526 }
527 
529 {
530  QMutexLocker locker(&m_lock);
531 
532  LOG(VB_CHANSCAN, LOG_INFO, LOC +
533  QString("Got a Service Description Table (other) for Transport ID %1")
534  .arg(tsid));
535  LogLines(sdt->toString());
536 
538 
539  uint netid = sdt->OriginalNetworkID();
540 
541  for (uint i = 0; i < sdt->ServiceCount(); ++i)
542  {
543  uint serviceId = sdt->ServiceID(i);
544  desc_list_t parsed =
546  sdt->ServiceDescriptorsLength(i));
547  // Look for default authority
548  const unsigned char *def_auth =
550  if (def_auth)
551  {
552  DefaultAuthorityDescriptor authority(def_auth);
553  if (!authority.IsValid())
554  continue;
555  LOG(VB_CHANSCAN, LOG_INFO, LOC +
556  QString("found default authority(SDTo) for service %1 %2 %3")
557  .arg(netid).arg(tsid).arg(serviceId));
558  m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
559  authority.DefaultAuthority();
560  }
561  }
562 }
563 
564 void ChannelScanSM::HandleEncryptionStatus(uint pnum, bool encrypted)
565 {
566  QMutexLocker locker(&m_lock);
567 
569 
572 
573  UpdateChannelInfo(true);
574 }
575 
577 {
578  if (!m_currentInfo || m_currentInfo->m_pmts.empty())
579  {
580  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
582  return false;
583  }
584 
585  do
586  {
587  uint pnum = 0;
588  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
589 #if 0
590  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
591  .arg(currentEncryptionStatusChecked.size())
592  .arg(currentEncryptionStatus.size()));
593 #endif
594  while (it != m_currentEncryptionStatus.end())
595  {
596  if (!m_currentEncryptionStatusChecked[it.key()])
597  {
598  pnum = it.key();
599  break;
600  }
601  ++it;
602  }
603 
604  if (!pnum)
605  break;
606 
608 
609  if (!m_testDecryption)
610  {
612  continue;
613  }
614 
615  const ProgramMapTable *pmt = nullptr;
616  for (uint i = 0; !pmt && (i < m_currentInfo->m_pmts.size()); ++i)
617  {
618  pmt = (m_currentInfo->m_pmts[i]->ProgramNumber() == pnum) ?
619  m_currentInfo->m_pmts[i] : nullptr;
620  }
621 
622  if (pmt)
623  {
624  QString cur_chan, cur_chan_tr;
625  GetCurrentTransportInfo(cur_chan, cur_chan_tr);
626 
627  QString msg_tr =
628  QObject::tr("%1 -- Testing decryption of program %2")
629  .arg(cur_chan_tr).arg(pnum);
630  QString msg =
631  QString("%1 -- Testing decryption of program %2")
632  .arg(cur_chan).arg(pnum);
633 
635  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
636 
637 #ifdef USING_DVB
638  if (GetDVBChannel())
639  GetDVBChannel()->SetPMT(pmt);
640 #endif // USING_DVB
641 
643 
645  m_timer.start();
646  return true;
647  }
648 
649  LOG(VB_GENERAL, LOG_INFO, LOC +
650  QString("Can't monitor decryption of program %1 -- no pmt")
651  .arg(pnum));
652 
653  } while (true);
654 
656  return false;
657 }
658 
660 {
663 
664  const DTVChannel *chan = GetDTVChannel();
665 
666  if (!chan)
667  return type;
668 
669  vector<DTVTunerType> tts = chan->GetTunerTypes();
670 
671  for (size_t i = 0; i < tts.size(); ++i)
672  {
673  if (tts[i] == type)
674  return type;
675  }
676 
677  if (!tts.empty())
678  return tts[0];
679 
680  return type;
681 }
682 
684 {
685  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
686  {
687  uint32_t tsid = nit->TSID(i);
688  uint32_t netid = nit->OriginalNetworkID(i);
689  uint32_t id = netid << 16 | tsid;
690 
691  if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
692  continue;
693 
694  const desc_list_t& list =
697 
698  for (size_t j = 0; j < list.size(); ++j)
699  {
700  int mplexid = -1;
701  uint64_t frequency = 0;
702  const MPEGDescriptor desc(list[j]);
703  uint tag = desc.DescriptorTag();
704  uint length = desc.DescriptorLength();
705  QString tagString = desc.DescriptorTagString();
706 
708 
709  LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("ts-loop j:%1 tag:%2 %3 length:%4")
710  .arg(j).arg(tag).arg(tagString).arg(length));
711 
712  switch (tag)
713  {
715  {
717  frequency = cd.FrequencyHz();
719  break;
720  }
722  {
723  const SatelliteDeliverySystemDescriptor cd(desc);
724  frequency = cd.FrequencyHz()/1000;
726  break;
727  }
729  {
730  const CableDeliverySystemDescriptor cd(desc);
731  frequency = cd.FrequencyHz();
733  break;
734  }
735  default:
736  LOG(VB_CHANSCAN, LOG_ERR, LOC +
737  "unknown delivery system descriptor");
738  continue;
739  }
740 
741  mplexid = ChannelUtil::GetMplexID(m_sourceID, frequency, tsid, netid);
742  mplexid = max(0, mplexid);
743 
744  tt = GuessDTVTunerType(tt);
745 
746  DTVMultiplex tuning;
747  if (mplexid)
748  {
749  if (!tuning.FillFromDB(tt, mplexid))
750  continue;
751  }
752  else if (!tuning.FillFromDeliverySystemDesc(tt, desc))
753  {
754  continue;
755  }
756 
757  m_extendTransports[id] = tuning;
758  break;
759  }
760  }
761 }
762 
763 bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
764 {
765  QMutexLocker locker(&m_mutex);
766 
767  if (m_current == m_scanTransports.end())
768  return true;
769 
770  if (wait_until_complete && m_currentTestingDecryption)
771  return false;
772 
774  if (!dtv_sm)
775  return false;
776 
777  const ScanStreamData *sd = dtv_sm->GetScanStreamData();
778 
779  if (!m_currentInfo)
781 
782  bool transport_tune_complete = true;
783 
784  // MPEG
785 
786  // Grab PAT tables
787  pat_vec_t pattmp = sd->GetCachedPATs();
788  QMap<uint,bool> tsid_checked;
789  for (size_t i = 0; i < pattmp.size(); ++i)
790  {
791  uint tsid = pattmp[i]->TransportStreamID();
792  if (tsid_checked[tsid])
793  continue;
794  tsid_checked[tsid] = true;
795  if (m_currentInfo->m_pats.contains(tsid))
796  continue;
797 
798  if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
799  {
800  m_currentInfo->m_pats[tsid] = sd->GetCachedPATs(tsid);
801  if (!m_currentInfo->m_pmts.empty())
802  {
804  m_currentInfo->m_pmts.clear();
805  }
806  }
807  else
808  transport_tune_complete = false;
809  }
810  transport_tune_complete &= !pattmp.empty();
811  sd->ReturnCachedPATTables(pattmp);
812 
813  // Grab PMT tables
814  if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
815  m_currentInfo->m_pmts.empty())
817 
818  // ATSC
819  if (!m_currentInfo->m_mgt && sd->HasCachedMGT())
821 
822  if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
823  m_currentInfo->m_cvcts.empty())
824  {
826  }
827 
828  if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
829  m_currentInfo->m_tvcts.empty())
830  {
832  }
833 
834  // DVB
835  if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
836  (m_currentInfo->m_nits.empty() ||
837  m_timer.elapsed() > (int)m_otherTableTime))
838  {
840  }
841 
842  sdt_vec_t sdttmp = sd->GetCachedSDTs();
843  tsid_checked.clear();
844  for (size_t i = 0; i < sdttmp.size(); ++i)
845  {
846  uint tsid = sdttmp[i]->TSID();
847  if (tsid_checked[tsid])
848  continue;
849  tsid_checked[tsid] = true;
850  if (m_currentInfo->m_sdts.contains(tsid))
851  continue;
852 
853  if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
854  m_currentInfo->m_sdts[tsid] = sd->GetCachedSDTSections(tsid);
855  }
856  sd->ReturnCachedSDTTables(sdttmp);
857 
858  // Check if transport tuning is complete
859  if (transport_tune_complete)
860  {
861  transport_tune_complete &= !m_currentInfo->m_pmts.empty();
862  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
863  {
864  transport_tune_complete &= sd->HasCachedMGT();
865  transport_tune_complete &=
866  (!m_currentInfo->m_tvcts.empty() || !m_currentInfo->m_cvcts.empty());
867  }
868  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
869  {
870  transport_tune_complete &= !m_currentInfo->m_nits.empty();
871  transport_tune_complete &= !m_currentInfo->m_sdts.empty();
872  }
873  if (transport_tune_complete)
874  {
875  LOG(VB_CHANSCAN, LOG_INFO, LOC +
876  QString("transport_tune_complete: "
877  "\n\t\t\tcurrentInfo->m_pmts.empty(): %1"
878  "\n\t\t\tsd->HasCachedAnyNIT(): %2"
879  "\n\t\t\tsd->HasCachedAnySDTs(): %3"
880  "\n\t\t\tcurrentInfo->m_nits.empty(): %4"
881  "\n\t\t\tcurrentInfo->m_sdts.empty(): %5")
882  .arg(m_currentInfo->m_pmts.empty())
883  .arg(sd->HasCachedAnyNIT())
884  .arg(sd->HasCachedAnySDTs())
885  .arg(m_currentInfo->m_nits.empty())
886  .arg(m_currentInfo->m_sdts.empty()));
887  }
888  }
889  if (!wait_until_complete)
890  transport_tune_complete = true;
891  if (transport_tune_complete)
892  {
893  LOG(VB_CHANSCAN, LOG_INFO, LOC +
894  QString("transport_tune_complete: wait_until_complete %1")
895  .arg(wait_until_complete));
896  }
897 
898  if (transport_tune_complete && !m_currentEncryptionStatus.empty())
900  {
901  //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
902 
904  return false;
905 
906  QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.begin();
907  for (; it != m_currentEncryptionStatus.end(); ++it)
908  {
910 
911  if (m_testDecryption)
912  {
913  QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
914  QString msg_tr2 = QObject::tr("Unknown decryption status");
915  if (kEncEncrypted == *it)
916  msg_tr2 = QObject::tr("Encrypted");
917  else if (kEncDecrypted == *it)
918  msg_tr2 = QObject::tr("Decrypted");
919  QString msg_tr =QString("%1, %2").arg(msg_tr1).arg(msg_tr2);
921  }
922 
923  QString msg = 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 
931  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
932  }
933  }
934 
935  // Append transports from the NIT to the scan list
936  if (transport_tune_complete && m_extendScanList &&
937  !m_currentInfo->m_nits.empty())
938  {
939  // Update transport with delivery system descriptors from the NIT
940  nit_vec_t::const_iterator it = m_currentInfo->m_nits.begin();
941  while (it != m_currentInfo->m_nits.end())
942  {
944  ++it;
945  }
946  }
947 
948  // Start scanning next transport if we are done with this one..
949  if (transport_tune_complete)
950  {
951  QString cchan, cchan_tr;
952  uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
953  m_channelsFound += cchan_cnt;
954  QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
955  QString chan = QString( "%1 -- Timed out").arg(cchan);
956  QString msg_tr = "";
957  QString msg = "";
958 
959  if (!m_currentInfo->IsEmpty())
960  {
961  LOG(VB_CHANSCAN, LOG_INFO, LOC +
962  QString("Adding %1, offset %2 to channelList.")
963  .arg((*m_current).m_tuning.toString()).arg(m_current.offset()));
964 
965  TransportScanItem &item = *m_current;
967 
968  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
969  QString("%1(%2) m_inputName: %3 ").arg(__FUNCTION__).arg(__LINE__).arg(m_inputName) +
970  QString("m_mod_sys:%1 %2").arg(item.m_tuning.m_mod_sys).arg(item.m_tuning.m_mod_sys.toString()));
971 
973  {
974  if (m_dvbt2Tried)
976  else
978  }
979 
981  m_currentInfo = nullptr;
982  }
983  else
984  {
985  delete m_currentInfo;
986  m_currentInfo = nullptr;
987  }
988 
990  if (HasTimedOut())
991  {
992  msg_tr = (cchan_cnt) ?
993  QObject::tr("%1 possible channels").arg(cchan_cnt) :
994  QObject::tr("no channels");
995  msg_tr = QString("%1, %2").arg(chan_tr).arg(msg_tr);
996  msg = (cchan_cnt) ?
997  QString("%1 possible channels").arg(cchan_cnt) :
998  QString("no channels");
999  msg = QString("%1, %2").arg(chan_tr).arg(msg);
1000  }
1001  else if ((m_current != m_scanTransports.end()) &&
1002  (m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1003  sm && !sm->HasSignalLock())
1004  {
1005  msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1006  msg = QString("%1, no signal").arg(chan);
1007  }
1008  else
1009  {
1010  msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1011  .arg(cchan_tr).arg(cchan_cnt);
1012 
1013  msg = QString("%1 -- Found %2 probable channels")
1014  .arg(cchan).arg(cchan_cnt);
1015  }
1016 
1018  LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1019 
1020  m_currentEncryptionStatus.clear();
1022 
1023  m_setOtherTables = false;
1024  m_otherTableTime = 0;
1025 
1026  if (m_scanning)
1027  {
1030  m_waitingForTables = false;
1032  m_dvbt2Tried = true;
1033  }
1034  else
1035  {
1038  }
1039 
1040  return true;
1041  }
1042 
1043  return false;
1044 }
1045 
1046 #define PCM_INFO_INIT(SISTD) \
1047  ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1048  info.m_db_mplexid = mplexid; info.m_source_id = m_sourceID; \
1049  info.m_service_id = pnum; info.m_freqid = freqidStr; \
1050  info.m_si_standard = SISTD;
1051 
1052 static void update_info(ChannelInsertInfo &info,
1053  const VirtualChannelTable *vct, uint i)
1054 {
1055  if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1056  vct->ServiceType(i) == 0x01 /* Analog TV */)
1057  {
1058  info.m_si_standard = "ntsc";
1059  info.m_format = "ntsc";
1060  }
1061 
1062  info.m_callsign = vct->ShortChannelName(i);
1063 
1064  info.m_service_name = vct->GetExtendedChannelName(i);
1065  if (info.m_service_name.isEmpty())
1066  info.m_service_name = vct->ShortChannelName(i);
1067 
1068  info.m_chan_num.clear();
1069 
1070  info.m_service_id = vct->ProgramNumber(i);
1071  info.m_atsc_major_channel = vct->MajorChannel(i);
1072  info.m_atsc_minor_channel = vct->MinorChannel(i);
1073 
1074  info.m_use_on_air_guide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1075 
1076  info.m_hidden = vct->IsHidden(i);
1077  info.m_hidden_in_guide = vct->IsHiddenInGuide(i);
1078 
1079  info.m_vct_tsid = vct->TransportStreamID();
1081  info.m_is_encrypted |= vct->IsAccessControlled(i);
1082  info.m_is_data_service = vct->ServiceType(i) == 0x04;
1083  info.m_is_audio_service = vct->ServiceType(i) == 0x03;
1084 
1085  info.m_in_vct = true;
1086 }
1087 
1088 static void update_info(ChannelInsertInfo &info,
1089  const ServiceDescriptionTable *sdt, uint i,
1090  const QMap<uint64_t, QString> &defAuthorities)
1091 {
1092  // HACK beg -- special exception for these networks
1093  // this enables useonairguide by default for all matching channels
1094  // (dbver == "1067")
1095  bool force_guide_present = (
1096  // Telenor (NO)
1097  (sdt->OriginalNetworkID() == 70) ||
1098 #if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1099  // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1100  (sdt->OriginalNetworkID() == 222) ||
1101 #endif
1102  // ERT (GR) from the private temporary allocation, see #9592:comment:17
1103  (sdt->OriginalNetworkID() == 65330) ||
1104  // Digitenne (NL) see #13427
1105  (sdt->OriginalNetworkID() == 8720)
1106  );
1107  // HACK end -- special exception for these networks
1108 
1109  // Figure out best service name and callsign...
1110  ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
1111  QString callsign;
1112  QString service_name;
1113  if (desc)
1114  {
1115  callsign = desc->ServiceShortName();
1116  if (callsign.trimmed().isEmpty())
1117  callsign = QString("%1-%2-%3")
1118  .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1119  .arg(sdt->ServiceID(i));
1120 
1121  service_name = desc->ServiceName();
1122  if (service_name.trimmed().isEmpty())
1123  service_name.clear();
1124  }
1125 
1126  if (info.m_callsign.isEmpty())
1127  info.m_callsign = callsign;
1128  if (info.m_service_name.isEmpty())
1129  info.m_service_name = service_name;
1130 
1131  info.m_use_on_air_guide =
1132  sdt->HasEITPresentFollowing(i) ||
1133  sdt->HasEITSchedule(i) ||
1134  force_guide_present;
1135 
1136  info.m_hidden = false;
1137  info.m_hidden_in_guide = false;
1138 
1139  info.m_is_data_service =
1140  (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1141  info.m_is_audio_service = (desc && desc->IsDigitalAudio());
1142  delete desc;
1143 
1144  info.m_service_id = sdt->ServiceID(i);
1145  info.m_sdt_tsid = sdt->TSID();
1146  info.m_orig_netid = sdt->OriginalNetworkID();
1147  info.m_in_sdt = true;
1148 
1149  desc_list_t parsed =
1151  sdt->ServiceDescriptorsLength(i));
1152  // Look for default authority
1153  const unsigned char *def_auth =
1155  if (def_auth)
1156  {
1157  DefaultAuthorityDescriptor authority(def_auth);
1158  if (authority.IsValid())
1159  {
1160  LOG(VB_CHANSCAN, LOG_INFO, QString("ChannelScanSM: found default "
1161  "authority(SDT) for service %1 %2 %3")
1162  .arg(info.m_orig_netid).arg(info.m_sdt_tsid).arg(info.m_service_id));
1163  info.m_default_authority = authority.DefaultAuthority();
1164  return;
1165  }
1166  }
1167 
1168  uint64_t index = (uint64_t)info.m_orig_netid << 32 |
1169  info.m_sdt_tsid << 16 | info.m_service_id;
1170  if (defAuthorities.contains(index))
1171  info.m_default_authority = defAuthorities[index];
1172 }
1173 
1175  QString &cur_chan, QString &cur_chan_tr) const
1176 {
1177  if (m_current.iter() == m_scanTransports.end())
1178  {
1179  cur_chan.clear();
1180  cur_chan_tr.clear();
1181  return 0;
1182  }
1183 
1184  uint max_chan_cnt = 0;
1185 
1186  QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1187  {
1188  for (int i = 0; i < list.size(); ++i)
1189  {
1190  max_chan_cnt +=
1191  (list[i].m_in_pat || list[i].m_in_pmt ||
1192  list[i].m_in_sdt || list[i].m_in_vct) ? 1 : 0;
1193  }
1194  }
1195 
1196  QString offset_str_tr = m_current.offset() ?
1197  QObject::tr(" offset %2").arg(m_current.offset()) : "";
1198  cur_chan_tr = QString("%1%2")
1199  .arg((*m_current).m_friendlyName).arg(offset_str_tr);
1200 
1201  QString offset_str = m_current.offset() ?
1202  QString(" offset %2").arg(m_current.offset()) : "";
1203  cur_chan = QString("%1%2")
1204  .arg((*m_current).m_friendlyName).arg(offset_str);
1205 
1206  return max_chan_cnt;
1207 }
1208 
1209 QMap<uint,ChannelInsertInfo>
1211  ScannedChannelInfo *scan_info) const
1212 {
1213  QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1214 
1215  uint mplexid = (*trans_info).m_mplexid;
1216  int freqid = (*trans_info).m_friendlyNum;
1217  QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1218  QString iptv_channel = (*trans_info).m_iptvChannel;
1219 
1220  // channels.conf
1221  const DTVChannelInfoList &echan = (*trans_info).m_expectedChannels;
1222  for (size_t i = 0; i < echan.size(); ++i)
1223  {
1224  uint pnum = echan[i].m_serviceid;
1225  PCM_INFO_INIT("mpeg");
1226  info.m_service_name = echan[i].m_name;
1227  info.m_in_channels_conf = true;
1228  }
1229 
1230  // PATs
1231  pat_map_t::const_iterator pat_list_it = scan_info->m_pats.begin();
1232  for (; pat_list_it != scan_info->m_pats.end(); ++pat_list_it)
1233  {
1234  pat_vec_t::const_iterator pat_it = (*pat_list_it).begin();
1235  for (; pat_it != (*pat_list_it).end(); ++pat_it)
1236  {
1237  bool could_be_opencable = false;
1238  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1239  {
1240  if (((*pat_it)->ProgramNumber(i) == 0) &&
1241  ((*pat_it)->ProgramPID(i) == 0x1ffc))
1242  {
1243  could_be_opencable = true;
1244  }
1245  }
1246 
1247  for (uint i = 0; i < (*pat_it)->ProgramCount(); ++i)
1248  {
1249  uint pnum = (*pat_it)->ProgramNumber(i);
1250  if (pnum)
1251  {
1252  PCM_INFO_INIT("mpeg");
1253  info.m_pat_tsid = (*pat_it)->TransportStreamID();
1254  info.m_could_be_opencable = could_be_opencable;
1255  info.m_in_pat = true;
1256  }
1257  }
1258  }
1259  }
1260 
1261  // PMTs
1262  pmt_vec_t::const_iterator pmt_it = scan_info->m_pmts.begin();
1263  for (; pmt_it != scan_info->m_pmts.end(); ++pmt_it)
1264  {
1265  const ProgramMapTable *pmt = *pmt_it;
1266  uint pnum = pmt->ProgramNumber();
1267  PCM_INFO_INIT("mpeg");
1268  for (uint i = 0; i < pmt->StreamCount(); ++i)
1269  {
1270  info.m_could_be_opencable |=
1271  (StreamID::OpenCableVideo == pmt->StreamType(i));
1272  }
1273 
1275  pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1277 
1278  for (size_t i = 0; i < descs.size(); ++i)
1279  {
1280  RegistrationDescriptor reg(descs[i]);
1281  if (!reg.IsValid())
1282  continue;
1283  if (reg.FormatIdentifierString() == "CUEI" ||
1284  reg.FormatIdentifierString() == "SCTE")
1285  info.m_could_be_opencable = true;
1286  }
1287 
1288  info.m_is_encrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1289  info.m_in_pmt = true;
1290  }
1291 
1292  // Cable VCTs
1293  cvct_vec_t::const_iterator cvct_it = scan_info->m_cvcts.begin();
1294  for (; cvct_it != scan_info->m_cvcts.end(); ++cvct_it)
1295  {
1296  for (uint i = 0; i < (*cvct_it)->ChannelCount(); ++i)
1297  {
1298  uint pnum = (*cvct_it)->ProgramNumber(i);
1299  PCM_INFO_INIT("atsc");
1300  update_info(info, *cvct_it, i);
1301  }
1302  }
1303 
1304  // Terrestrial VCTs
1305  tvct_vec_t::const_iterator tvct_it = scan_info->m_tvcts.begin();
1306  for (; tvct_it != scan_info->m_tvcts.end(); ++tvct_it)
1307  {
1308  for (uint i = 0; i < (*tvct_it)->ChannelCount(); ++i)
1309  {
1310  uint pnum = (*tvct_it)->ProgramNumber(i);
1311  PCM_INFO_INIT("atsc");
1312  update_info(info, *tvct_it, i);
1313  }
1314  }
1315 
1316  // SDTs
1317  sdt_map_t::const_iterator sdt_list_it = scan_info->m_sdts.begin();
1318  for (; sdt_list_it != scan_info->m_sdts.end(); ++sdt_list_it)
1319  {
1320  sdt_vec_t::const_iterator sdt_it = (*sdt_list_it).begin();
1321  for (; sdt_it != (*sdt_list_it).end(); ++sdt_it)
1322  {
1323  for (uint i = 0; i < (*sdt_it)->ServiceCount(); ++i)
1324  {
1325  uint pnum = (*sdt_it)->ServiceID(i);
1326  PCM_INFO_INIT("dvb");
1327  update_info(info, *sdt_it, i, m_defAuthorities);
1328  }
1329  }
1330  }
1331 
1332  // NIT
1333  QMap<qlonglong, uint> ukChanNums;
1334  QMap<qlonglong, uint> scnChanNums;
1335  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1336  for (dbchan_it = pnum_to_dbchan.begin();
1337  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1338  {
1339  ChannelInsertInfo &info = *dbchan_it;
1340 
1341  // NIT
1342  nit_vec_t::const_iterator nits_it = scan_info->m_nits.begin();
1343  for (; nits_it != scan_info->m_nits.end(); ++nits_it)
1344  {
1345  for (uint i = 0; i < (*nits_it)->TransportStreamCount(); ++i)
1346  {
1347  const NetworkInformationTable *nit = (*nits_it);
1348  if ((nit->TSID(i) == info.m_sdt_tsid) &&
1349  (nit->OriginalNetworkID(i) == info.m_orig_netid))
1350  {
1351  info.m_netid = nit->NetworkID();
1352  info.m_in_nit = true;
1353  }
1354  else
1355  {
1356  continue;
1357  }
1358 
1359  // Get channel numbers from UK Frequency List Descriptors
1360  const desc_list_t &list =
1362  nit->TransportDescriptorsLength(i));
1363 
1364  // Logical channel numbers
1365  {
1366  const unsigned char *desc =
1369 
1370  if (desc)
1371  {
1372  DVBLogicalChannelDescriptor uklist(desc);
1373  if (!uklist.IsValid())
1374  continue;
1375  for (uint j = 0; j < uklist.ChannelCount(); ++j)
1376  {
1377  ukChanNums[((qlonglong)info.m_orig_netid<<32) |
1378  uklist.ServiceID(j)] =
1379  uklist.ChannelNumber(j);
1380  }
1381  }
1382  }
1383 
1384  // HD Simulcast logical channel numbers
1385  {
1386  const unsigned char *desc =
1389 
1390  if (desc)
1391  {
1392  DVBSimulcastChannelDescriptor scnlist(desc);
1393  if (!scnlist.IsValid())
1394  continue;
1395  for (uint j = 0; j < scnlist.ChannelCount(); ++j)
1396  {
1397  scnChanNums[((qlonglong)info.m_orig_netid<<32) |
1398  scnlist.ServiceID(j)] =
1399  scnlist.ChannelNumber(j);
1400  }
1401  }
1402  }
1403  }
1404  }
1405  }
1406 
1407  // Get IPTV or DVB Logical channel numbers
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  if (!info.m_chan_num.isEmpty())
1414  continue;
1415 
1416  if (iptv_channel.isEmpty()) // DVB Logical channel numbers (LCN)
1417  {
1418  {
1419  // Look for a logical channel number in the HD simulcast channel numbers.
1420  // This gives the correct channel number when HD and SD versions of the same
1421  // channel are simultaneously broadcast and the receiver is capable
1422  // of receiving the HD signal.
1423  QMap<qlonglong, uint>::const_iterator it = scnChanNums.find
1424  (((qlonglong)info.m_orig_netid<<32) | info.m_service_id);
1425 
1426  if (it != scnChanNums.end())
1427  {
1428  info.m_chan_num = QString::number(*it);
1429  continue;
1430  }
1431  }
1432  {
1433  // If there is no simulcast for this channel then descriptor 0x83
1434  // gives the logical channel number. This can be either an SD
1435  // or an HD channel.
1436  QMap<qlonglong, uint>::const_iterator it = ukChanNums.find
1437  (((qlonglong)info.m_orig_netid<<32) | info.m_service_id);
1438 
1439  if (it != ukChanNums.end())
1440  info.m_chan_num = QString::number(*it);
1441  }
1442  }
1443  else // IPTV programs
1444  {
1445  info.m_chan_num = iptv_channel;
1446  if (info.m_service_id)
1447  info.m_chan_num += "-" + QString::number(info.m_service_id);
1448  }
1449 
1450  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1451  QString("GetChannelList: set chan_num '%1' for '%2'")
1452  .arg(info.m_chan_num).arg(info.m_callsign));
1453  }
1454 
1455  // Get QAM/SCTE/MPEG channel numbers
1456  for (dbchan_it = pnum_to_dbchan.begin();
1457  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1458  {
1459  ChannelInsertInfo &info = *dbchan_it;
1460 
1461  if (!info.m_chan_num.isEmpty())
1462  continue;
1463 
1464  if ((info.m_si_standard == "mpeg") ||
1465  (info.m_si_standard == "scte") ||
1466  (info.m_si_standard == "opencable"))
1467  {
1468  if (info.m_freqid.isEmpty())
1469  info.m_chan_num = QString("%1-%2")
1470  .arg(info.m_source_id)
1471  .arg(info.m_service_id);
1472  else
1473  info.m_chan_num = QString("%1-%2")
1474  .arg(info.m_freqid)
1475  .arg(info.m_service_id);
1476  }
1477  }
1478 
1479  // Check for decryption success
1480  for (dbchan_it = pnum_to_dbchan.begin();
1481  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1482  {
1483  uint pnum = dbchan_it.key();
1484  ChannelInsertInfo &info = *dbchan_it;
1485  info.m_decryption_status = scan_info->m_program_encryption_status[pnum];
1486  }
1487 
1488  return pnum_to_dbchan;
1489 }
1490 
1492 {
1493  ScanDTVTransportList list;
1494 
1495  uint cardid = m_channel->GetInputID();
1496 
1498  tuner_type = GuessDTVTunerType(tuner_type);
1499 
1500  ChannelList::const_iterator it = m_channelList.begin();
1501  for (; it != m_channelList.end(); ++it)
1502  {
1503  QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1504  GetChannelList(it->first, it->second);
1505 
1506  ScanDTVTransport item((*it->first).m_tuning, tuner_type, cardid);
1507  item.m_iptv_tuning = (*(it->first)).m_iptvTuning;
1508 
1509  QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1510  for (dbchan_it = pnum_to_dbchan.begin();
1511  dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1512  {
1513  item.m_channels.push_back(*dbchan_it);
1514  }
1515 
1516  if (!item.m_channels.empty())
1517  {
1518  if (addFullTS)
1519  {
1520  /* If addFullTS, then add a 'MPTS' channel
1521  which can be used to record the entire MPTS from
1522  the transport. */
1523  dbchan_it = pnum_to_dbchan.begin();
1524  ChannelInsertInfo info = *dbchan_it;
1525 
1526  // Use transport stream ID as (fake) service ID
1527  // to use in callsign and as channel number
1528  info.m_service_id = info.m_sdt_tsid ? info.m_sdt_tsid : info.m_pat_tsid;
1529 
1530  if (tuner_type == DTVTunerType::kTunerTypeASI)
1531  info.m_callsign = QString("MPTS_%1")
1532  .arg(CardUtil::GetDisplayName(cardid));
1533  else if (info.m_si_standard == "mpeg" ||
1534  info.m_si_standard == "scte" ||
1535  info.m_si_standard == "opencable")
1536  info.m_callsign = QString("MPTS_%1").arg(info.m_freqid);
1537  else if (info.m_atsc_major_channel > 0)
1538  info.m_callsign =
1539  QString("MPTS_%1").arg(info.m_atsc_major_channel);
1540  else if (info.m_service_id > 0)
1541  info.m_callsign = QString("MPTS_%1").arg(info.m_service_id);
1542  else if (!info.m_chan_num.isEmpty())
1543  info.m_callsign = QString("MPTS_%1").arg(info.m_chan_num);
1544  else
1545  info.m_callsign = "MPTS_UNKNOWN";
1546 
1547  info.m_service_name = info.m_callsign;
1548  info.m_atsc_minor_channel = 0;
1549  info.m_format = "MPTS";
1550  info.m_use_on_air_guide = false;
1551  info.m_is_encrypted = false;
1552  item.m_channels.push_back(info);
1553  }
1554 
1555  list.push_back(item);
1556  }
1557  }
1558 
1559  return list;
1560 }
1561 
1562 
1564 {
1565  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1566 }
1567 
1569 {
1570 #ifdef USING_DVB
1571  return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1572 #else
1573  return nullptr;
1574 #endif
1575 }
1576 
1578 {
1579  return dynamic_cast<DTVChannel*>(m_channel);
1580 }
1581 
1583 {
1584  return dynamic_cast<const DTVChannel*>(m_channel);
1585 }
1586 
1588 {
1589 #ifdef USING_HDHOMERUN
1590  return dynamic_cast<HDHRChannel*>(m_channel);
1591 #else
1592  return nullptr;
1593 #endif
1594 }
1595 
1597 {
1598 #ifdef USING_DVB
1599  return dynamic_cast<DVBChannel*>(m_channel);
1600 #else
1601  return nullptr;
1602 #endif
1603 }
1604 
1606 {
1607 #ifdef USING_DVB
1608  return dynamic_cast<const DVBChannel*>(m_channel);
1609 #else
1610  return nullptr;
1611 #endif
1612 }
1613 
1615 {
1616 #ifdef USING_V4L2
1617  return dynamic_cast<V4LChannel*>(m_channel);
1618 #else
1619  return nullptr;
1620 #endif
1621 }
1622 
1627 {
1628  while (m_scannerThread)
1629  {
1630  m_threadExit = true;
1631  if (m_scannerThread->wait(1000))
1632  {
1633  delete m_scannerThread;
1634  m_scannerThread = nullptr;
1635  }
1636  }
1637  m_threadExit = false;
1638  m_scannerThread = new MThread("Scanner", this);
1640 }
1641 
1646 {
1647  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
1648 
1649  while (!m_threadExit)
1650  {
1651  if (m_scanning)
1652  HandleActiveScan();
1653 
1654  usleep(10 * 1000);
1655  }
1656 
1657  LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
1658 }
1659 
1660 // See if we have timed out
1662 {
1664  (m_timer.elapsed() > kDecryptionTimeout))
1665  {
1667  return true;
1668  }
1669 
1670  if (!m_waitingForTables)
1671  return true;
1672 
1673 #ifdef USING_DVB
1674  // If the rotor is still moving, reset the timer and keep waiting
1676  if (sigmon)
1677  {
1678  const DiSEqCDevRotor *rotor = GetDVBChannel()->GetRotor();
1679  if (rotor)
1680  {
1681  bool was_moving, is_moving;
1682  sigmon->GetRotorStatus(was_moving, is_moving);
1683  if (was_moving && !is_moving)
1684  {
1685  m_timer.restart();
1686  return false;
1687  }
1688  }
1689  }
1690 #endif // USING_DVB
1691 
1692 
1693  // have the tables have timed out?
1694  if (m_timer.elapsed() > (int)m_channelTimeout)
1695  {
1696  // the channelTimeout alone is only valid if we have seen no tables..
1697  const ScanStreamData *sd = nullptr;
1698  if (GetDTVSignalMonitor())
1700 
1701  if (!sd)
1702  return true;
1703 
1704  if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
1705  return m_timer.elapsed() > (int) kDVBTableTimeout;
1706  if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
1707  return m_timer.elapsed() > (int) kATSCTableTimeout;
1708  if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
1709  return m_timer.elapsed() > (int) kMPEGTableTimeout;
1710 
1711  return true;
1712  }
1713 
1714  // ok the tables haven't timed out, but have we hit the signal timeout?
1716  if ((m_timer.elapsed() > (int)(*m_current).m_timeoutTune) &&
1717  sm && !sm->HasSignalLock())
1718  {
1719  const ScanStreamData *sd = nullptr;
1720  if (GetDTVSignalMonitor())
1722 
1723  if (!sd)
1724  return true;
1725 
1726  // Just is case we temporarily lose the signal after we've seen
1727  // tables...
1728  if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
1729  !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
1730  !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
1731  {
1732  return true;
1733  }
1734  }
1735 
1736  return false;
1737 }
1738 
1743 {
1744  QMutexLocker locker(&m_lock);
1745 
1746  bool do_post_insertion = m_waitingForTables;
1747 
1748  if (!HasTimedOut())
1749  return;
1750 
1751  if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
1752  {
1753  m_channelList.clear();
1754  m_channelsFound = 0;
1755  m_dvbt2Tried = true;
1756  }
1757 
1759  {
1760  // If we failed to get a lock with DVB-T try DVB-T2.
1761  m_dvbt2Tried = true;
1763  return;
1764  }
1765 
1766  if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
1767  {
1768  // Add channel to scanned list and potentially check decryption
1769  if (do_post_insertion && !UpdateChannelInfo(false))
1770  return;
1771 
1772  // Stop signal monitor for previous transport
1773  locker.unlock();
1774  m_signalMonitor->Stop();
1775  locker.relock();
1776  }
1777 
1778  m_current = m_nextIt; // Increment current
1779  m_dvbt2Tried = false;
1780 
1781  if (m_current != m_scanTransports.end())
1782  {
1784 
1785  // Increment nextIt
1786  m_nextIt = m_current;
1787  ++m_nextIt;
1788  }
1789  else if (!m_extendTransports.isEmpty())
1790  {
1791  --m_current;
1792  QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
1793  while (it != m_extendTransports.end())
1794  {
1795  if (!m_tsScanned.contains(it.key()))
1796  {
1797  QString name = QString("TransportID %1").arg(it.key() & 0xffff);
1799  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + " - " +
1800  item.m_tuning.toString());
1801  m_scanTransports.push_back(item);
1802  m_tsScanned.insert(it.key());
1803  }
1804  ++it;
1805  }
1806  m_extendTransports.clear();
1807  m_nextIt = m_current;
1808  ++m_nextIt;
1809  }
1810  else
1811  {
1813  m_scanning = false;
1815  }
1816 }
1817 
1819 {
1820  const TransportScanItem &item = *transport;
1821 
1822 #ifdef USING_DVB
1823  if (GetDVBSignalMonitor())
1824  {
1825  // always wait for rotor to finish
1828  }
1829 #endif // USING_DVB
1830 
1831  if (!GetDTVChannel())
1832  return false;
1833 
1834  if (item.m_mplexid > 0 && transport.offset() == 0)
1836 
1837  if (item.m_tuning.m_sistandard == "MPEG")
1838  return GetDTVChannel()->Tune(item.m_iptvTuning, true);
1839 
1840  const uint64_t freq = item.freq_offset(transport.offset());
1841  DTVMultiplex tuning = item.m_tuning;
1842  tuning.m_frequency = freq;
1843 
1845  {
1847  }
1849  {
1850  if (m_dvbt2Tried)
1852  else
1854  }
1855 
1856  return GetDTVChannel()->Tune(tuning);
1857 }
1858 
1860 {
1861  QString offset_str = (transport.offset()) ?
1862  QObject::tr(" offset %2").arg(transport.offset()) : "";
1863  QString cur_chan = QString("%1%2")
1864  .arg((*m_current).m_friendlyName).arg(offset_str);
1865  QString tune_msg_str =
1866  QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
1867  .arg(cur_chan).arg((*m_current).m_mplexid);
1868 
1869  const TransportScanItem &item = *transport;
1870 
1871  if (transport.offset() &&
1872  (item.freq_offset(transport.offset()) == item.freq_offset(0)))
1873  {
1874  m_waitingForTables = false;
1875  return; // nothing to do
1876  }
1877 
1878  if (m_channelsFound)
1879  {
1880  QString progress = QObject::tr(": Found %n", "", m_channelsFound);
1882  }
1883 
1885  LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
1886 
1887  if (!Tune(transport))
1888  { // If we did not tune successfully, bail with message
1890  LOG(VB_CHANSCAN, LOG_ERR, LOC +
1891  QString("Failed to tune %1 mplexid(%2) at offset %3")
1892  .arg(item.m_friendlyName).arg(item.m_mplexid)
1893  .arg(transport.offset()));
1894  return;
1895  }
1896 
1897  // If we have a DTV Signal Monitor, perform table scanner reset
1898  if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
1899  {
1901  GetDTVSignalMonitor()->SetChannel(-1,-1);
1902  GetDTVSignalMonitor()->SetDVBService(0, 0, -1);
1903  }
1904 
1905  // Start signal monitor for this channel
1907 
1908  m_timer.start();
1909  m_waitingForTables = (item.m_tuning.m_sistandard != "analog");
1910 }
1911 
1917 {
1918  LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
1919 
1920  while (m_scannerThread)
1921  {
1922  m_threadExit = true;
1923  if (m_scannerThread->wait(1000))
1924  {
1925  delete m_scannerThread;
1926  m_scannerThread = nullptr;
1927  }
1928  }
1929 
1930  if (m_signalMonitor)
1931  m_signalMonitor->Stop();
1932 }
1933 
1939  int SourceID,
1940  const QString &std,
1941  const QString &modulation,
1942  const QString &country,
1943  const QString &table_start,
1944  const QString &table_end)
1945 {
1946  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
1947  QString("%1: ").arg(__FUNCTION__) +
1948  QString("SourceID:%1 ").arg(SourceID) +
1949  QString("std:%1 ").arg(std) +
1950  QString("modulation:%1 ").arg(modulation) +
1951  QString("country:%1 ").arg(country) +
1952  QString("table_start:%1 ").arg(table_start) +
1953  QString("table_end:%1 ").arg(table_end));
1954 
1955  QString name("");
1956  if (m_scanning)
1957  return false;
1958 
1959  m_scanTransports.clear();
1960  m_nextIt = m_scanTransports.end();
1961 
1962  freq_table_list_t tables =
1963  get_matching_freq_tables(std, modulation, country);
1964 
1965  if (tables.empty())
1966  {
1967  QString msg = QString("No freq table for (%1, %2, %3) found")
1968  .arg(std).arg(modulation).arg(country);
1970  }
1971  LOG(VB_CHANSCAN, LOG_INFO, LOC +
1972  QString("Looked up freq table (%1, %2, %3) w/%4 entries")
1973  .arg(std).arg(modulation).arg(country).arg(tables.size()));
1974 
1975  QString start = table_start;
1976  const QString& end = table_end;
1977  freq_table_list_t::iterator it = tables.begin();
1978  for (; it != tables.end(); ++it)
1979  {
1980  const FrequencyTable &ft = **it;
1981  int name_num = ft.m_nameOffset;
1982  QString strNameFormat = ft.m_nameFormat;
1983  uint freq = ft.m_frequencyStart;
1984  while (freq <= ft.m_frequencyEnd)
1985  {
1986  name = strNameFormat;
1987  if (strNameFormat.indexOf("%") >= 0)
1988  name = strNameFormat.arg(name_num);
1989 
1990  if (start.isEmpty() || name == start)
1991  {
1992  start.clear();
1993 
1994  TransportScanItem item(SourceID, std, name, name_num,
1995  freq, ft, m_signalTimeout);
1996  m_scanTransports.push_back(item);
1997 
1998  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
1999  item.toString());
2000  }
2001 
2002  ++name_num;
2003  freq += ft.m_frequencyStep;
2004 
2005  if (!end.isEmpty() && name == end)
2006  break;
2007  }
2008  if (!end.isEmpty() && name == end)
2009  break;
2010  }
2011 
2012  while (!tables.empty())
2013  {
2014  delete tables.back();
2015  tables.pop_back();
2016  }
2017 
2018  m_extendScanList = true;
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 
2030  const QString &std,
2031  const QString &cardtype,
2032  const DTVChannelList &channels)
2033 {
2034  m_scanTransports.clear();
2035  m_nextIt = m_scanTransports.end();
2036 
2037  DTVTunerType tunertype;
2038  tunertype.Parse(cardtype);
2039 
2040  DTVChannelList::const_iterator it = channels.begin();
2041  for (uint i = 0; it != channels.end(); ++it, ++i)
2042  {
2043  DTVTransport tmp = *it;
2044  tmp.m_sistandard = std;
2045  TransportScanItem item(sourceid, QString::number(i),
2046  tunertype, tmp, m_signalTimeout);
2047 
2048  m_scanTransports.push_back(item);
2049 
2050  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
2051  }
2052 
2053  if (m_scanTransports.empty())
2054  {
2055  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
2056  return false;
2057  }
2058 
2059  m_timer.start();
2060  m_waitingForTables = false;
2061 
2062  m_nextIt = m_scanTransports.begin();
2063  m_transportsScanned = 0;
2064  m_scanning = true;
2065 
2066  return true;
2067 }
2068 
2070  const fbox_chan_map_t &iptv_channels)
2071 {
2072  m_scanTransports.clear();
2073  m_nextIt = m_scanTransports.end();
2074 
2075  fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2076  for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2077  {
2078  TransportScanItem item(sourceid, QString::number(idx),
2079  Ichan.value().m_tuning, Ichan.key(),
2080  m_signalTimeout);
2081 
2082  m_scanTransports.push_back(item);
2083 
2084  LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2085  }
2086 
2087  if (m_scanTransports.empty())
2088  {
2089  LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2090  return false;
2091  }
2092 
2093  m_timer.start();
2094  m_waitingForTables = false;
2095 
2096  m_nextIt = m_scanTransports.begin();
2097  m_transportsScanned = 0;
2098  m_scanning = true;
2099 
2100  return true;
2101 }
2102 
2103 
2109  int sourceid, const QMap<QString,QString> &startChan)
2110 {
2111  if (startChan.find("std") == startChan.end() ||
2112  startChan.find("type") == startChan.end())
2113  {
2114  return false;
2115  }
2116 
2117  QString std = *startChan.find("std");
2118  QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
2119  bool ok = false;
2120 
2121  if (m_scanning)
2122  return false;
2123 
2124  m_scanTransports.clear();
2125  m_nextIt = m_scanTransports.end();
2126 
2127  DTVMultiplex tuning;
2128 
2130  ok = type.Parse(startChan["type"]);
2131 
2132  if (ok)
2133  {
2134  ok = tuning.ParseTuningParams(
2135  type,
2136  startChan["frequency"], startChan["inversion"],
2137  startChan["symbolrate"], startChan["fec"],
2138  startChan["polarity"],
2139  startChan["coderate_hp"], startChan["coderate_lp"],
2140  startChan["constellation"], startChan["trans_mode"],
2141  startChan["guard_interval"], startChan["hierarchy"],
2142  startChan["modulation"], startChan["bandwidth"],
2143  startChan["mod_sys"], startChan["rolloff"]);
2144  }
2145 
2146  if (ok)
2147  {
2148  tuning.m_sistandard = si_std;
2149  TransportScanItem item(
2150  sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2151  tuning, m_signalTimeout);
2152  m_scanTransports.push_back(item);
2153  }
2154 
2155  if (!ok)
2156  return false;
2157 
2158  m_extendScanList = true;
2159 
2160  m_timer.start();
2161  m_waitingForTables = false;
2162 
2163  m_nextIt = m_scanTransports.begin();
2164  m_transportsScanned = 0;
2165  m_scanning = true;
2166 
2167  return true;
2168 }
2169 
2171 {
2172  MSqlQuery query(MSqlQuery::InitCon());
2173  query.prepare(
2174  "SELECT sourceid, sistandard, transportid, frequency, modulation "
2175  "FROM dtv_multiplex "
2176  "WHERE mplexid = :MPLEXID");
2177  query.bindValue(":MPLEXID", mplexid);
2178  if (!query.exec())
2179  {
2180  MythDB::DBError("ChannelScanSM::AddToList()", query);
2181  return false;
2182  }
2183 
2184  if (!query.next())
2185  {
2186  LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2187  QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2188  return false;
2189  }
2190 
2191  uint sourceid = query.value(0).toUInt();
2192  QString sistandard = query.value(1).toString();
2193  uint tsid = query.value(2).toUInt();
2195 
2196  QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2197  QString("Multiplex #%1").arg(mplexid);
2198 
2199  if (query.value(4).toString() == "8vsb")
2200  {
2201  QString chan = QString("%1 Hz").arg(query.value(3).toInt());
2202  struct CHANLIST *curList = chanlists[0].list;
2203  int totalChannels = chanlists[0].count;
2204  int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2205  for (int x = 0 ; x < totalChannels ; ++x)
2206  {
2207  if ((curList[x].freq <= findFrequency + 200) &&
2208  (curList[x].freq >= findFrequency - 200))
2209  {
2210  chan = QString("%1").arg(curList[x].name);
2211  }
2212  }
2213  fn = QObject::tr("ATSC Channel %1").arg(chan);
2215  }
2216 
2217  tt = GuessDTVTunerType(tt);
2218 
2219  TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2220 
2221  LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2222  QString("tunertype:%1 %2 sourceid:%3 sistandard:%4 fn:'%5' mplexid:%6")
2223  .arg(tt).arg(tt.toString()).arg(sourceid).arg(sistandard).arg(fn).arg(mplexid));
2224 
2225  if (item.m_tuning.FillFromDB(tt, mplexid))
2226  {
2227  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2228  m_scanTransports.push_back(item);
2229  return true;
2230  }
2231 
2232  LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2233  return false;
2234 }
2235 
2236 bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2237 {
2238  m_scanTransports.clear();
2239  m_nextIt = m_scanTransports.end();
2240 
2241  AddToList(mplexid);
2242 
2243  m_timer.start();
2244  m_waitingForTables = false;
2245 
2246  m_extendScanList = follow_nit;
2247  m_transportsScanned = 0;
2248  if (!m_scanTransports.empty())
2249  {
2250  m_nextIt = m_scanTransports.begin();
2251  m_scanning = true;
2252  return true;
2253  }
2254 
2255  return false;
2256 }
2257 
2258 bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2259 {
2260  m_scanTransports.clear();
2261  m_nextIt = m_scanTransports.end();
2262 
2263  m_signalTimeout = 30000;
2264  QString name;
2265  TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2266  m_scanTransports.push_back(item);
2267 
2268  m_timer.start();
2269  m_waitingForTables = false;
2270  m_extendScanList = false;
2271  m_transportsScanned = 0;
2272  m_nextIt = m_scanTransports.begin();
2273  m_scanning = true;
2274  return true;
2275 }
2276 
2281  const DTVChannelInfoList &channels,
2282  uint mpeg_program_num,
2283  QString &service_name,
2284  QString &callsign,
2285  QString &common_status_info)
2286 {
2287  if (channels.empty())
2288  return true;
2289 
2290  bool found = false;
2291  for (size_t i = 0; i < channels.size(); ++i)
2292  {
2293  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2294  QString("comparing %1 %2 against %3 %4")
2295  .arg(channels[i].m_serviceid).arg(channels[i].m_name)
2296  .arg(mpeg_program_num).arg(common_status_info));
2297 
2298  if (channels[i].m_serviceid == mpeg_program_num)
2299  {
2300  found = true;
2301  if (!channels[i].m_name.isEmpty())
2302  {
2303  service_name = channels[i].m_name;
2304  callsign = channels[i].m_name;
2305  }
2306  }
2307  }
2308 
2309  if (found)
2310  {
2311  common_status_info += QString(" %1 %2")
2312  .arg(QObject::tr("as")).arg(service_name);
2313  }
2314  else
2315  {
2317  QObject::tr("Skipping %1, not in imported channel map")
2318  .arg(common_status_info));
2319  }
2320 
2321  return found;
2322 }
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
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
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
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)
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
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
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
bool HasCachedAllPMTs(void) const
void Reset(void) override
bool ScanTransports(int SourceID, const QString &std, const QString &mod, const QString &country, const QString &table_start=QString(), const QString &table_end=QString())
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
uint ChannelCount() const
Definition: atsctables.h:221
ChannelBase * m_channel
bool ScanForChannels(uint sourceid, const QString &std, const QString &cardtype, const DTVChannelList &)
void SetRealNetworkID(int)
static uint FindChannel(uint sourceid, const QString &freqid)
bool TestNextProgramEncryption(void)
uint ChannelNumber(uint i) const
HDHRChannel * GetHDHRChannel(void)
uint ServiceCount() const
Number of services.
Definition: dvbtables.h:136
bool isActive(void) const
Definition: mythdbcon.h:204
void SetAnalog(bool is_analog)
Rotor class.
Definition: diseqc.h:293
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
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
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
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.
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:161
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: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)
Always MPEG-2??
Definition: mpegtables.h:117
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
void UpdateScanPercentCompleted(void)
Updates Transport Scan progress bar.
QString toString(void) const override
Definition: dvbtables.cpp:197
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:1706
QMutex m_lock
The big lock.
bool HasCachedAnyPAT(uint tsid) const