00001 #include <unistd.h>
00002
00003 #include <algorithm>
00004 using namespace std;
00005
00006 #include "dtvchannel.h"
00007 #include "dvbchannel.h"
00008 #include "dtvsignalmonitor.h"
00009 #include "scanstreamdata.h"
00010 #include "mpegtables.h"
00011 #include "atsctables.h"
00012 #include "dvbtables.h"
00013 #include "compat.h"
00014
00015 #undef DBG_SM
00016 #define DBG_SM(FUNC, MSG) LOG(VB_CHANNEL, LOG_INFO, \
00017 QString("DTVSM(%1)::%2: %3").arg(channel->GetDevice()).arg(FUNC).arg(MSG))
00018
00019 #define LOC QString("DTVSM(%1): ").arg(channel->GetDevice())
00020
00021
00022
00023 static bool insert_crc(QList<uint64_t> &seen_crc, const PSIPTable &psip)
00024 {
00025 uint64_t key = (((uint64_t)psip.TableID()) << 32) | psip.CRC();
00026
00027 QList<uint64_t>::iterator it =
00028 lower_bound(seen_crc.begin(), seen_crc.end(), key);
00029
00030 if ((it == seen_crc.end()) || (*it != key))
00031 {
00032 seen_crc.insert(it, key);
00033 return true;
00034 }
00035
00036 return false;
00037 }
00038
00043 DTVSignalMonitor::DTVSignalMonitor(int db_cardnum,
00044 DTVChannel *_channel,
00045 uint64_t wait_for_mask)
00046 : SignalMonitor(db_cardnum, _channel, wait_for_mask),
00047 stream_data(NULL),
00048 seenPAT(QObject::tr("Seen")+" PAT", "seen_pat", 1, true, 0, 1, 0),
00049 seenPMT(QObject::tr("Seen")+" PMT", "seen_pmt", 1, true, 0, 1, 0),
00050 seenMGT(QObject::tr("Seen")+" MGT", "seen_mgt", 1, true, 0, 1, 0),
00051 seenVCT(QObject::tr("Seen")+" VCT", "seen_vct", 1, true, 0, 1, 0),
00052 seenNIT(QObject::tr("Seen")+" NIT", "seen_nit", 1, true, 0, 1, 0),
00053 seenSDT(QObject::tr("Seen")+" SDT", "seen_sdt", 1, true, 0, 1, 0),
00054 seenCrypt(QObject::tr("Seen")+" Crypt", "seen_crypt", 1, true, 0, 1, 0),
00055 matchingPAT(QObject::tr("Matching")+" PAT", "matching_pat", 1, true, 0, 1, 0),
00056 matchingPMT(QObject::tr("Matching")+" PMT", "matching_pmt", 1, true, 0, 1, 0),
00057 matchingMGT(QObject::tr("Matching")+" MGT", "matching_mgt", 1, true, 0, 1, 0),
00058 matchingVCT(QObject::tr("Matching")+" VCT", "matching_vct", 1, true, 0, 1, 0),
00059 matchingNIT(QObject::tr("Matching")+" NIT", "matching_nit", 1, true, 0, 1, 0),
00060 matchingSDT(QObject::tr("Matching")+" SDT", "matching_sdt", 1, true, 0, 1, 0),
00061 matchingCrypt(QObject::tr("Matching")+" Crypt", "matching_crypt",
00062 1, true, 0, 1, 0),
00063 majorChannel(-1), minorChannel(-1),
00064 networkID(0), transportID(0),
00065 detectedNetworkID(0), detectedTransportID(0),
00066 programNumber(-1),
00067 ignore_encrypted(false)
00068 {
00069 }
00070
00071 DTVSignalMonitor::~DTVSignalMonitor()
00072 {
00073 SetStreamData(NULL);
00074 }
00075
00076 DTVChannel *DTVSignalMonitor::GetDTVChannel(void)
00077 {
00078 return dynamic_cast<DTVChannel*>(channel);
00079 }
00080
00081 QStringList DTVSignalMonitor::GetStatusList(void) const
00082 {
00083 QStringList list = SignalMonitor::GetStatusList();
00084 QMutexLocker locker(&statusLock);
00085
00086
00087 if (flags & kDTVSigMon_WaitForPAT)
00088 {
00089 list<<seenPAT.GetName()<<seenPAT.GetStatus();
00090 list<<matchingPAT.GetName()<<matchingPAT.GetStatus();
00091 }
00092 if (flags & kDTVSigMon_WaitForPMT)
00093 {
00094 #define DEBUG_PMT 0
00095 #if DEBUG_PMT
00096 static int seenGood = -1;
00097 static int matchingGood = -1;
00098 #endif
00099 list<<seenPMT.GetName()<<seenPMT.GetStatus();
00100 list<<matchingPMT.GetName()<<matchingPMT.GetStatus();
00101 #if DEBUG_PMT
00102 if ((seenGood != (int)seenPMT.IsGood()) ||
00103 (matchingGood != (int)matchingPMT.IsGood()))
00104 {
00105 DBG_SM("GetStatusList", QString("WaitForPMT seen(%1) matching(%2)")
00106 .arg(seenPMT.IsGood())
00107 .arg(matchingPMT.IsGood()));
00108 seenGood = (int)seenPMT.IsGood();
00109 matchingGood = (int)matchingPMT.IsGood();
00110 }
00111 #endif
00112 }
00113
00114 if (flags & kDTVSigMon_WaitForMGT)
00115 {
00116 list<<seenMGT.GetName()<<seenMGT.GetStatus();
00117 list<<matchingMGT.GetName()<<matchingMGT.GetStatus();
00118 }
00119 if (flags & kDTVSigMon_WaitForVCT)
00120 {
00121 list<<seenVCT.GetName()<<seenVCT.GetStatus();
00122 list<<matchingVCT.GetName()<<matchingVCT.GetStatus();
00123 }
00124
00125 if (flags & kDTVSigMon_WaitForNIT)
00126 {
00127 list<<seenNIT.GetName()<<seenNIT.GetStatus();
00128 list<<matchingNIT.GetName()<<matchingNIT.GetStatus();
00129 }
00130 if (flags & kDTVSigMon_WaitForSDT)
00131 {
00132 list<<seenSDT.GetName()<<seenSDT.GetStatus();
00133 list<<matchingSDT.GetName()<<matchingSDT.GetStatus();
00134 }
00135 if (flags & kDTVSigMon_WaitForCrypt)
00136 {
00137 list<<seenCrypt.GetName()<<seenCrypt.GetStatus();
00138 list<<matchingCrypt.GetName()<<matchingCrypt.GetStatus();
00139 }
00140 if (error != "")
00141 {
00142 list<<"error"<<error;
00143 }
00144 return list;
00145 }
00146
00147 void DTVSignalMonitor::AddFlags(uint64_t _flags)
00148 {
00149 SignalMonitor::AddFlags(_flags);
00150 UpdateMonitorValues();
00151 }
00152
00153 void DTVSignalMonitor::RemoveFlags(uint64_t _flags)
00154 {
00155 SignalMonitor::RemoveFlags(_flags);
00156 UpdateMonitorValues();
00157 }
00158
00159 void DTVSignalMonitor::UpdateMonitorValues(void)
00160 {
00161 QMutexLocker locker(&statusLock);
00162 seenPAT.SetValue( (flags & kDTVSigMon_PATSeen) ? 1 : 0);
00163 seenPMT.SetValue( (flags & kDTVSigMon_PMTSeen) ? 1 : 0);
00164 seenMGT.SetValue( (flags & kDTVSigMon_MGTSeen) ? 1 : 0);
00165 seenVCT.SetValue( (flags & kDTVSigMon_VCTSeen) ? 1 : 0);
00166 seenNIT.SetValue( (flags & kDTVSigMon_NITSeen) ? 1 : 0);
00167 seenSDT.SetValue( (flags & kDTVSigMon_SDTSeen) ? 1 : 0);
00168 seenCrypt.SetValue( (flags & kDTVSigMon_CryptSeen)? 1 : 0);
00169 matchingPAT.SetValue((flags & kDTVSigMon_PATMatch) ? 1 : 0);
00170 matchingPMT.SetValue((flags & kDTVSigMon_PMTMatch) ? 1 : 0);
00171 matchingMGT.SetValue((flags & kDTVSigMon_MGTMatch) ? 1 : 0);
00172 matchingVCT.SetValue((flags & kDTVSigMon_VCTMatch) ? 1 : 0);
00173 matchingNIT.SetValue((flags & kDTVSigMon_NITMatch) ? 1 : 0);
00174 matchingSDT.SetValue((flags & kDTVSigMon_SDTMatch) ? 1 : 0);
00175 matchingCrypt.SetValue((flags & kDTVSigMon_CryptMatch) ? 1 : 0);
00176 }
00177
00178 void DTVSignalMonitor::UpdateListeningForEIT(void)
00179 {
00180 vector<uint> add_eit, del_eit;
00181
00182 if (GetStreamData()->HasEITPIDChanges(eit_pids) &&
00183 GetStreamData()->GetEITPIDChanges(eit_pids, add_eit, del_eit))
00184 {
00185 for (uint i = 0; i < del_eit.size(); i++)
00186 {
00187 uint_vec_t::iterator it;
00188 it = find(eit_pids.begin(), eit_pids.end(), del_eit[i]);
00189 if (it != eit_pids.end())
00190 eit_pids.erase(it);
00191 GetStreamData()->RemoveListeningPID(del_eit[i]);
00192 }
00193
00194 for (uint i = 0; i < add_eit.size(); i++)
00195 {
00196 eit_pids.push_back(add_eit[i]);
00197 GetStreamData()->AddListeningPID(add_eit[i]);
00198 }
00199 }
00200 }
00201
00202 void DTVSignalMonitor::SetChannel(int major, int minor)
00203 {
00204 DBG_SM(QString("SetChannel(%1, %2)").arg(major).arg(minor), "");
00205 seen_table_crc.clear();
00206 if (GetATSCStreamData() && (majorChannel != major || minorChannel != minor))
00207 {
00208 RemoveFlags(kDTVSigMon_PATSeen | kDTVSigMon_PATMatch |
00209 kDTVSigMon_PMTSeen | kDTVSigMon_PMTMatch |
00210 kDTVSigMon_VCTSeen | kDTVSigMon_VCTMatch |
00211 kDTVSigMon_CryptSeen | kDTVSigMon_CryptMatch);
00212 majorChannel = major;
00213 minorChannel = minor;
00214 GetATSCStreamData()->SetDesiredChannel(major, minor);
00215 AddFlags(kDTVSigMon_WaitForVCT | kDTVSigMon_WaitForPAT);
00216 }
00217 }
00218
00219 void DTVSignalMonitor::SetProgramNumber(int progNum)
00220 {
00221 DBG_SM(QString("SetProgramNumber(%1)").arg(progNum), "");
00222 seen_table_crc.clear();
00223 if (programNumber != progNum)
00224 {
00225 RemoveFlags(kDTVSigMon_PMTSeen | kDTVSigMon_PMTMatch |
00226 kDTVSigMon_CryptSeen | kDTVSigMon_CryptMatch);
00227 programNumber = progNum;
00228 if (GetStreamData())
00229 GetStreamData()->SetDesiredProgram(programNumber);
00230 AddFlags(kDTVSigMon_WaitForPMT);
00231 }
00232 }
00233
00234 void DTVSignalMonitor::SetDVBService(uint netid, uint tsid, int serviceid)
00235 {
00236 DBG_SM(QString("SetDVBService(transport_id: %1, network_id: %2, "
00237 "service_id: %3)").arg(tsid).arg(netid).arg(serviceid), "");
00238 seen_table_crc.clear();
00239
00240 if (netid == networkID && tsid == transportID &&
00241 serviceid == programNumber)
00242 {
00243 return;
00244 }
00245
00246 RemoveFlags(kDTVSigMon_PMTSeen | kDTVSigMon_PMTMatch |
00247 kDTVSigMon_SDTSeen | kDTVSigMon_SDTMatch |
00248 kDTVSigMon_CryptSeen | kDTVSigMon_CryptMatch);
00249
00250 transportID = tsid;
00251 networkID = netid;
00252 programNumber = serviceid;
00253
00254 if (GetDVBStreamData())
00255 {
00256 GetDVBStreamData()->SetDesiredService(netid, tsid, programNumber);
00257 AddFlags(kDTVSigMon_WaitForPMT | kDTVSigMon_WaitForSDT);
00258 GetDVBStreamData()->AddListeningPID(DVB_SDT_PID);
00259 }
00260 }
00261
00262 void DTVSignalMonitor::SetStreamData(MPEGStreamData *data)
00263 {
00264 if (stream_data)
00265 stream_data->RemoveMPEGListener(this);
00266
00267 ATSCStreamData *atsc = GetATSCStreamData();
00268 DVBStreamData *dvb = GetDVBStreamData();
00269 if (atsc)
00270 {
00271 atsc->RemoveATSCMainListener(this);
00272 atsc->RemoveATSCAuxListener(this);
00273 }
00274 if (dvb)
00275 dvb->RemoveDVBMainListener(this);
00276
00277 stream_data = data;
00278 if (!data)
00279 return;
00280
00281 data->AddMPEGListener(this);
00282
00283 atsc = GetATSCStreamData();
00284 dvb = GetDVBStreamData();
00285 if (atsc)
00286 {
00287 atsc->AddATSCMainListener(this);
00288 atsc->AddATSCAuxListener(this);
00289 }
00290 if (dvb)
00291 dvb->AddDVBMainListener(this);
00292 }
00293
00294
00295 void DTVSignalMonitor::HandlePAT(const ProgramAssociationTable *pat)
00296 {
00297 AddFlags(kDTVSigMon_PATSeen);
00298 int pmt_pid = pat->FindPID(programNumber);
00299 if (GetStreamData() && pmt_pid)
00300 {
00301 AddFlags(kDTVSigMon_PATMatch);
00302 GetStreamData()->AddListeningPID(pmt_pid);
00303 insert_crc(seen_table_crc, *pat);
00304 return;
00305 }
00306
00307 if (programNumber >= 0)
00308 {
00309
00310
00311
00312
00313 uint tsid = pat->TransportStreamID();
00314 GetStreamData()->SetVersionPAT(tsid, -1,0);
00315
00316
00317 if (insert_crc(seen_table_crc, *pat))
00318 {
00319 QString errStr = QString("Program #%1 not found in PAT!")
00320 .arg(programNumber);
00321 LOG(VB_GENERAL, LOG_ERR, LOC + errStr + "\n" + pat->toString());
00322 }
00323 if (pat->ProgramCount() == 1)
00324 {
00325 LOG(VB_GENERAL, LOG_ERR, LOC + "But there is only one program "
00326 "in the PAT, so we'll just use it");
00327 SetProgramNumber(pat->ProgramNumber(0));
00328 AddFlags(kDTVSigMon_PATMatch);
00329 GetStreamData()->AddListeningPID(pat->ProgramPID(0));
00330 }
00331 }
00332 }
00333
00334 void DTVSignalMonitor::HandlePMT(uint, const ProgramMapTable *pmt)
00335 {
00336 AddFlags(kDTVSigMon_PMTSeen);
00337
00338 if (programNumber < 0)
00339 return;
00340
00341 if (pmt->ProgramNumber() != (uint)programNumber)
00342 {
00343 if (insert_crc(seen_table_crc, *pmt))
00344 {
00345 LOG(VB_GENERAL, LOG_ERR, LOC +
00346 QString("Wrong PMT; pmt->pn(%1) desired(%2)")
00347 .arg(pmt->ProgramNumber()).arg(programNumber));
00348 }
00349 return;
00350 }
00351
00352 if (pmt->IsEncrypted(GetDTVChannel()->GetSIStandard())) {
00353 LOG(VB_GENERAL, LOG_NOTICE, LOC +
00354 QString("PMT says program %1 is encrypted").arg(programNumber));
00355 GetStreamData()->TestDecryption(pmt);
00356 }
00357
00358
00359 uint hasAudio = 0;
00360 uint hasVideo = 0;
00361
00362 for (uint i = 0; i < pmt->StreamCount(); i++)
00363 {
00364 hasVideo += pmt->IsVideo(i, GetDTVChannel()->GetSIStandard());
00365 hasAudio += pmt->IsAudio(i, GetDTVChannel()->GetSIStandard());
00366 }
00367
00368 if ((hasVideo >= GetStreamData()->GetVideoStreamsRequired()) &&
00369 (hasAudio >= GetStreamData()->GetAudioStreamsRequired()))
00370 {
00371 if (pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()) &&
00372 !ignore_encrypted)
00373 AddFlags(kDTVSigMon_WaitForCrypt);
00374
00375 AddFlags(kDTVSigMon_PMTMatch);
00376 }
00377 else
00378 {
00379 LOG(VB_GENERAL, LOG_ERR, LOC +
00380 QString("We want %1 audio and %2 video streams")
00381 .arg(GetStreamData()->GetAudioStreamsRequired())
00382 .arg(GetStreamData()->GetVideoStreamsRequired()) +
00383 QString("\n\t\t\tBut have %1 audio and %2 video streams")
00384 .arg(hasAudio).arg(hasVideo));
00385 }
00386 }
00387
00388 void DTVSignalMonitor::HandleSTT(const SystemTimeTable*)
00389 {
00390 LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("Time Offset: %1")
00391 .arg(GetStreamData()->TimeOffset()));
00392 }
00393
00394 void DTVSignalMonitor::HandleMGT(const MasterGuideTable* mgt)
00395 {
00396 AddFlags(kDTVSigMon_MGTSeen);
00397
00398 if (!GetATSCStreamData())
00399 return;
00400
00401 for (uint i=0; i<mgt->TableCount(); i++)
00402 {
00403 if ((TableClass::TVCTc == mgt->TableClass(i)) ||
00404 (TableClass::CVCTc == mgt->TableClass(i)))
00405 {
00406 GetATSCStreamData()->AddListeningPID(mgt->TablePID(i));
00407 AddFlags(kDTVSigMon_MGTMatch);
00408 }
00409 }
00410 }
00411
00412 void DTVSignalMonitor::HandleTVCT(
00413 uint, const TerrestrialVirtualChannelTable* tvct)
00414 {
00415 AddFlags(kDTVSigMon_VCTSeen | kDTVSigMon_TVCTSeen);
00416 int idx = tvct->Find(majorChannel, minorChannel);
00417
00418 if (minorChannel < 0)
00419 return;
00420
00421 if (idx < 0)
00422 {
00423 if (insert_crc(seen_table_crc, *tvct))
00424 {
00425 LOG(VB_GENERAL, LOG_ERR, LOC +
00426 QString("Could not find channel %1_%2 in TVCT")
00427 .arg(majorChannel).arg(minorChannel));
00428 LOG(VB_GENERAL, LOG_ERR, LOC + tvct->toString());
00429 }
00430 GetATSCStreamData()->SetVersionTVCT(tvct->TransportStreamID(),-1);
00431 return;
00432 }
00433
00434 DBG_SM("SetVCT()", QString("tvct->ProgramNumber(idx %1): prog num %2")
00435 .arg(idx).arg(tvct->ProgramNumber(idx)));
00436
00437 SetProgramNumber(tvct->ProgramNumber(idx));
00438 AddFlags(kDTVSigMon_VCTMatch | kDTVSigMon_TVCTMatch);
00439 }
00440
00441 void DTVSignalMonitor::HandleCVCT(uint, const CableVirtualChannelTable* cvct)
00442 {
00443 AddFlags(kDTVSigMon_VCTSeen | kDTVSigMon_CVCTSeen);
00444 int idx = cvct->Find(majorChannel, minorChannel);
00445
00446 if (idx < 0)
00447 {
00448 if (insert_crc(seen_table_crc, *cvct))
00449 {
00450 LOG(VB_GENERAL, LOG_ERR, LOC +
00451 QString("Could not find channel %1_%2 in CVCT")
00452 .arg(majorChannel).arg(minorChannel));
00453 LOG(VB_GENERAL, LOG_ERR, LOC + cvct->toString());
00454 }
00455 GetATSCStreamData()->SetVersionCVCT(cvct->TransportStreamID(),-1);
00456 return;
00457 }
00458
00459 DBG_SM("SetVCT()", QString("cvct->ProgramNumber(idx %1): prog num %2")
00460 .arg(idx).arg(cvct->ProgramNumber(idx)));
00461
00462 SetProgramNumber(cvct->ProgramNumber(idx));
00463 AddFlags(kDTVSigMon_VCTMatch | kDTVSigMon_CVCTMatch);
00464 }
00465
00466 void DTVSignalMonitor::HandleTDT(const TimeDateTable*)
00467 {
00468 LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("Time Offset: %1")
00469 .arg(GetStreamData()->TimeOffset()));
00470 }
00471
00472 void DTVSignalMonitor::HandleNIT(const NetworkInformationTable *nit)
00473 {
00474 DBG_SM("SetNIT()", QString("net_id = %1").arg(nit->NetworkID()));
00475 AddFlags(kDTVSigMon_NITSeen);
00476 if (!GetDVBStreamData())
00477 return;
00478 }
00479
00480 void DTVSignalMonitor::HandleSDT(uint, const ServiceDescriptionTable *sdt)
00481 {
00482 AddFlags(kDTVSigMon_SDTSeen);
00483
00484 detectedNetworkID = sdt->OriginalNetworkID();
00485 detectedTransportID = sdt->TSID();
00486
00487 if (sdt->OriginalNetworkID() != networkID || sdt->TSID() != transportID)
00488 {
00489 GetDVBStreamData()->SetVersionSDT(sdt->TSID(), -1, 0);
00490 }
00491 else
00492 {
00493 DBG_SM("SetSDT()", QString("tsid = %1 orig_net_id = %2")
00494 .arg(sdt->TSID()).arg(sdt->OriginalNetworkID()));
00495 AddFlags(kDTVSigMon_SDTMatch);
00496 RemoveFlags(kDVBSigMon_WaitForPos);
00497 }
00498 }
00499
00500 void DTVSignalMonitor::HandleEncryptionStatus(uint, bool enc_status)
00501 {
00502 AddFlags(kDTVSigMon_CryptSeen);
00503 if (!enc_status)
00504 AddFlags(kDTVSigMon_CryptMatch);
00505 }
00506
00507 ATSCStreamData *DTVSignalMonitor::GetATSCStreamData()
00508 {
00509 return dynamic_cast<ATSCStreamData*>(stream_data);
00510 }
00511
00512 DVBStreamData *DTVSignalMonitor::GetDVBStreamData()
00513 {
00514 return dynamic_cast<DVBStreamData*>(stream_data);
00515 }
00516
00517 ScanStreamData *DTVSignalMonitor::GetScanStreamData()
00518 {
00519 return dynamic_cast<ScanStreamData*>(stream_data);
00520 }
00521
00522 const ATSCStreamData *DTVSignalMonitor::GetATSCStreamData() const
00523 {
00524 return dynamic_cast<const ATSCStreamData*>(stream_data);
00525 }
00526
00527 const DVBStreamData *DTVSignalMonitor::GetDVBStreamData() const
00528 {
00529 return dynamic_cast<const DVBStreamData*>(stream_data);
00530 }
00531
00532 const ScanStreamData *DTVSignalMonitor::GetScanStreamData() const
00533 {
00534 return dynamic_cast<const ScanStreamData*>(stream_data);
00535 }
00536
00537 bool DTVSignalMonitor::IsAllGood(void) const
00538 {
00539 QMutexLocker locker(&statusLock);
00540 if (!SignalMonitor::IsAllGood())
00541 return false;
00542 if ((flags & kDTVSigMon_WaitForPAT) && !matchingPAT.IsGood())
00543 return false;
00544 if ((flags & kDTVSigMon_WaitForPMT) && !matchingPMT.IsGood())
00545 return false;
00546 if ((flags & kDTVSigMon_WaitForMGT) && !matchingMGT.IsGood())
00547 return false;
00548 if ((flags & kDTVSigMon_WaitForVCT) && !matchingVCT.IsGood())
00549 return false;
00550 if ((flags & kDTVSigMon_WaitForNIT) && !matchingNIT.IsGood())
00551 return false;
00552 if ((flags & kDTVSigMon_WaitForSDT) && !matchingSDT.IsGood())
00553 return false;
00554 if ((flags & kDTVSigMon_WaitForCrypt) && !matchingCrypt.IsGood())
00555 return false;
00556
00557 return true;
00558 }