1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/descriptor_tag.h>
3 #include <dvbsi++/service_descriptor.h>
4 #include <dvbsi++/satellite_delivery_system_descriptor.h>
5 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
6 #include <dvbsi++/cable_delivery_system_descriptor.h>
7 #include <dvbsi++/ca_identifier_descriptor.h>
8 #include <lib/dvb/specs.h>
9 #include <lib/dvb/esection.h>
10 #include <lib/dvb/scan.h>
11 #include <lib/dvb/frontend.h>
12 #include <lib/base/eerror.h>
13 #include <lib/base/estring.h>
16 static bool scan_debug;
17 #define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
18 #define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
22 eDVBScan::eDVBScan(iDVBChannel *channel, bool usePAT, bool debug)
23 :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
24 ,m_ready(0), m_ready_all(usePAT ? (readySDT|readyPAT) : readySDT)
25 ,m_flags(0), m_usePAT(usePAT)
28 if (m_channel->getDemux(m_demux))
29 SCAN_eDebug("scan: failed to allocate demux!");
30 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
37 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
45 return orbital_position == 192;
47 return tsid != 0x00B0;
49 return abs(orbital_position-282) < 6;
51 return onid.get() < 0xFF00;
55 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
57 // on valid ONIDs, ignore frequency ("sub network") part
58 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
60 return eDVBNamespace(hash);
63 void eDVBScan::stateChange(iDVBChannel *ch)
66 if (ch->getState(state))
68 if (m_channel_state == state)
71 if (state == iDVBChannel::state_ok)
74 m_channel_state = state;
75 } else if (state == iDVBChannel::state_failed)
77 m_ch_unavailable.push_back(m_ch_current);
80 /* unavailable will timeout, anyway. */
83 RESULT eDVBScan::nextChannel()
85 ePtr<iDVBFrontend> fe;
87 m_SDT = 0; m_PAT = 0; m_BAT = 0; m_NIT = 0;
91 /* check what we need */
92 m_ready_all = readySDT;
94 if (m_flags & scanNetworkSearch)
95 m_ready_all |= readyNIT;
97 if (m_flags & scanSearchBAT)
98 m_ready_all |= readyBAT;
101 m_ready_all |= readyPAT;
103 if (m_ch_toScan.empty())
105 SCAN_eDebug("no channels left to scan.");
106 SCAN_eDebug("%d channels scanned, %d were unavailable.",
107 m_ch_scanned.size(), m_ch_unavailable.size());
108 SCAN_eDebug("%d channels in database.", m_new_channels.size());
113 m_ch_current = m_ch_toScan.front();
115 m_ch_toScan.pop_front();
117 if (m_channel->getFrontend(fe))
123 m_chid_current = eDVBChannelID();
125 m_channel_state = iDVBChannel::state_idle;
127 if (fe->tune(*m_ch_current))
128 return nextChannel();
134 RESULT eDVBScan::startFilter()
139 /* only start required filters filter */
141 if (m_ready_all & readyPAT)
142 startSDT = m_ready & readyPAT;
145 if (startSDT && (m_ready_all & readySDT))
147 m_SDT = new eTable<ServiceDescriptionSection>();
149 if (m_ready & readyPAT && m_ready & validPAT)
151 std::vector<ProgramAssociationSection*>::const_iterator i =
152 m_PAT->getSections().begin();
153 assert(i != m_PAT->getSections().end());
154 tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
156 // KabelBW HACK ... on 618Mhz and 626Mhz the transport stream id in PAT and SDT is different
159 m_ch_current->getSystem(type);
160 if (type == iDVBFrontend::feCable)
162 eDVBFrontendParametersCable parm;
163 m_ch_current->getDVBC(parm);
164 if ((tsid == 0x00d7 && abs(parm.frequency-618000) < 2000) ||
165 (tsid == 0x00d8 && abs(parm.frequency-626000) < 2000))
172 if (m_SDT->start(m_demux, eDVBSDTSpec()))
175 else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
177 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
180 if (!(m_ready & readyPAT))
183 if (m_ready_all & readyPAT)
185 m_PAT = new eTable<ProgramAssociationSection>();
186 if (m_PAT->start(m_demux, eDVBPATSpec()))
188 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
192 if (m_ready_all & readyNIT)
194 m_NIT = new eTable<NetworkInformationSection>();
195 if (m_NIT->start(m_demux, eDVBNITSpec()))
197 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
201 if (m_ready_all & readyBAT)
203 m_BAT = new eTable<BouquetAssociationSection>();
204 if (m_BAT->start(m_demux, eDVBBATSpec()))
206 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
213 void eDVBScan::SDTready(int err)
215 SCAN_eDebug("got sdt");
222 void eDVBScan::NITready(int err)
224 SCAN_eDebug("got nit, err %d", err);
231 void eDVBScan::BATready(int err)
233 SCAN_eDebug("got bat");
240 void eDVBScan::PATready(int err)
242 SCAN_eDebug("got pat");
246 startFilter(); // for starting the SDT filter
249 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
251 /* add it to the list of known channels. */
253 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
256 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
258 /* check if we don't already have that channel ... */
261 feparm->getSystem(type);
265 case iDVBFrontend::feSatellite:
267 eDVBFrontendParametersSatellite parm;
268 feparm->getDVBS(parm);
269 eDebug("try to add %d %d %d %d %d %d",
270 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
273 case iDVBFrontend::feCable:
275 eDVBFrontendParametersCable parm;
276 feparm->getDVBC(parm);
277 eDebug("try to add %d %d %d %d",
278 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
281 case iDVBFrontend::feTerrestrial:
283 eDVBFrontendParametersTerrestrial parm;
284 feparm->getDVBT(parm);
285 eDebug("try to add %d %d %d %d %d %d %d %d",
286 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
287 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
293 /* ... in the list of channels to scan */
294 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
296 if (sameChannel(*i, feparm))
300 *i = feparm; // update
305 eDebug("remove dupe");
306 m_ch_toScan.erase(i++);
316 eDebug("already in todo list");
320 /* ... in the list of successfully scanned channels */
321 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
322 if (sameChannel(*i, feparm))
324 eDebug("successfully scanned");
328 /* ... in the list of unavailable channels */
329 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
330 if (sameChannel(*i, feparm, true))
332 eDebug("scanned but not available");
336 /* ... on the current channel */
337 if (sameChannel(m_ch_current, feparm))
339 eDebug("is current");
343 eDebug("really add");
344 /* otherwise, add it to the todo list. */
345 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
348 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
351 if (ch1->calculateDifference(ch2, diff, exact))
353 if (diff < 4000) // more than 4mhz difference?
358 void eDVBScan::channelDone()
360 if (m_ready & validSDT)
362 unsigned long hash = 0;
364 // m_ch_current is not set, when eDVBScan is just used for a SDT update
366 m_channel->getCurrentFrontendParameters(m_ch_current);
368 m_ch_current->getHash(hash);
370 eDVBNamespace dvbnamespace = buildNamespace(
371 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
372 (**m_SDT->getSections().begin()).getTransportStreamId(),
375 SCAN_eDebug("SDT: ");
376 std::vector<ServiceDescriptionSection*>::const_iterator i;
377 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
378 processSDT(dvbnamespace, **i);
379 m_ready &= ~validSDT;
382 if (m_ready & validNIT)
385 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
386 m_ch_current->getSystem(system);
387 SCAN_eDebug("dumping NIT");
388 if (m_flags & clearToScanOnFirstNIT)
390 m_ch_toScan_backup = m_ch_toScan;
393 std::vector<NetworkInformationSection*>::const_iterator i;
394 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
396 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
398 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
399 tsinfo != tsinfovec.end(); ++tsinfo)
401 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
402 (*tsinfo)->getOriginalNetworkId());
404 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
405 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
407 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
408 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
410 switch ((*desc)->getTag())
412 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
414 if (system != iDVBFrontend::feCable)
415 break; // when current locked transponder is no cable transponder ignore this descriptor
416 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
417 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
418 eDVBFrontendParametersCable cable;
420 feparm->setDVBC(cable);
422 unsigned long hash=0;
423 feparm->getHash(hash);
424 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
427 eDVBChannelID(ns, tsid, onid),
431 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
433 if (system != iDVBFrontend::feTerrestrial)
434 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
435 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
436 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
437 eDVBFrontendParametersTerrestrial terr;
439 feparm->setDVBT(terr);
441 unsigned long hash=0;
442 feparm->getHash(hash);
443 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
446 eDVBChannelID(ns, tsid, onid),
450 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
452 if (system != iDVBFrontend::feSatellite)
453 break; // when current locked transponder is no satellite transponder ignore this descriptor
455 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
456 if (d.getFrequency() < 10000)
459 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
460 eDVBFrontendParametersSatellite sat;
463 eDVBFrontendParametersSatellite p;
464 m_ch_current->getDVBS(p);
466 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
467 sat.orbital_position = p.orbital_position;
469 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
471 eDebug("found transponder with incorrect west/east flag ... correct this");
472 sat.orbital_position = p.orbital_position;
475 feparm->setDVBS(sat);
477 if ( p.orbital_position != sat.orbital_position)
478 SCAN_eDebug("dropping this transponder, it's on another satellite.");
481 unsigned long hash=0;
482 feparm->getHash(hash);
484 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
490 SCAN_eDebug("descr<%x>", (*desc)->getTag());
498 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
499 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
502 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
504 if (m_flags & clearToScanOnFirstNIT)
506 if (m_ch_toScan.empty())
508 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
509 m_ch_toScan = m_ch_toScan_backup;
511 m_flags &= ~clearToScanOnFirstNIT;
513 m_ready &= ~validNIT;
516 if ((m_ready & m_ready_all) != m_ready_all)
518 SCAN_eDebug("channel done!");
520 /* if we had services on this channel, we declare
521 this channels as "known good". add it.
523 (TODO: not yet implemented)
524 a NIT entry could have possible overridden
525 our frontend data with more exact data.
527 (TODO: not yet implemented)
528 the tuning process could have lead to more
529 exact data than the user entered.
531 The channel id was probably corrected
532 by the data written in the SDT. this is
533 important, as "initial transponder lists"
534 usually don't have valid CHIDs (and that's
537 These are the reasons for adding the transponder
538 here, and not before.
542 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
544 addKnownGoodChannel(m_chid_current, m_ch_current);
546 m_ch_scanned.push_back(m_ch_current);
548 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
550 if (sameChannel(*i, m_ch_current))
552 eDebug("remove dupe 2");
553 m_ch_toScan.erase(i++);
562 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
566 m_ch_scanned.clear();
567 m_ch_unavailable.clear();
568 m_new_channels.clear();
569 m_new_services.clear();
570 m_last_service = m_new_services.end();
572 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
575 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
577 if (sameChannel(*i, *ii, true))
584 m_ch_toScan.push_back(*i);
590 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
592 if (m_flags & scanRemoveServices)
594 bool clearTerrestrial=false;
595 bool clearCable=false;
596 std::set<unsigned int> scanned_sat_positions;
598 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
599 for (;it != m_ch_scanned.end(); ++it)
602 (*it)->getSystem(system);
605 case iDVBFrontend::feSatellite:
607 eDVBFrontendParametersSatellite sat_parm;
608 (*it)->getDVBS(sat_parm);
609 scanned_sat_positions.insert(sat_parm.orbital_position);
612 case iDVBFrontend::feTerrestrial:
614 clearTerrestrial=true;
617 case iDVBFrontend::feCable:
625 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
628 (*it)->getSystem(system);
631 case iDVBFrontend::feSatellite:
633 eDVBFrontendParametersSatellite sat_parm;
634 (*it)->getDVBS(sat_parm);
635 scanned_sat_positions.insert(sat_parm.orbital_position);
638 case iDVBFrontend::feTerrestrial:
640 clearTerrestrial=true;
643 case iDVBFrontend::feCable:
651 if (clearTerrestrial)
654 chid.dvbnamespace=0xEEEE0000;
655 db->removeServices(chid);
660 chid.dvbnamespace=0xFFFF0000;
661 db->removeServices(chid);
663 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
666 if (m_flags & scanDontRemoveFeeds)
667 chid.dvbnamespace = eDVBNamespace((*x)<<16);
668 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
669 db->removeServices(chid, *x);
673 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
674 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
675 db->addChannelToList(ch->first, ch->second);
676 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
677 service(m_new_services.begin()); service != m_new_services.end(); ++service)
679 ePtr<eDVBService> dvb_service;
680 if (!db->getService(service->first, dvb_service))
682 if (dvb_service->m_flags & eDVBService::dxNoSDT)
684 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
686 dvb_service->m_service_name = service->second->m_service_name;
687 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
689 dvb_service->m_provider_name = service->second->m_provider_name;
690 if (service->second->m_ca.size())
691 dvb_service->m_ca = service->second->m_ca;
692 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
693 dvb_service->m_flags &= ~eDVBService::dxNewFound;
697 db->addService(service->first, service->second);
698 if (!(m_flags & scanRemoveServices))
699 service->second->m_flags |= eDVBService::dxNewFound;
704 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
706 const ServiceDescriptionList &services = *sdt.getDescriptions();
707 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
708 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
710 /* save correct CHID for this channel */
711 m_chid_current = chid;
713 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
715 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
717 eServiceReferenceDVB ref;
718 ePtr<eDVBService> service = new eDVBService;
721 ref.setServiceID((*s)->getServiceId());
723 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
724 desc != (*s)->getDescriptors()->end(); ++desc)
725 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
726 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
728 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
729 desc != (*s)->getDescriptors()->end(); ++desc)
731 switch ((*desc)->getTag())
733 case SERVICE_DESCRIPTOR:
735 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
736 service->m_service_name = convertDVBUTF8(d.getServiceName());
737 service->genSortName();
739 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
740 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
743 case CA_IDENTIFIER_DESCRIPTOR:
745 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
746 const CaSystemIdList &caids = *d.getCaSystemIds();
747 SCAN_eDebugNoNewLine("CA ");
748 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
750 SCAN_eDebugNoNewLine("%04x ", *i);
751 service->m_ca.push_front(*i);
757 SCAN_eDebug("descr<%x>", (*desc)->getTag());
762 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
766 m_last_service = i.first;
767 m_event(evtNewService);
773 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
775 connection = new eConnection(this, m_event.connect(event));
779 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
781 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
782 transponders_total = m_ch_toScan.size() + transponders_done;
783 services = m_new_services.size();
786 void eDVBScan::getLastServiceName(std::string &last_service_name)
788 if (m_last_service == m_new_services.end())
789 last_service_name = "";
791 last_service_name = m_last_service->second->m_service_name;
794 RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
797 return m_channel->getFrontend(fe);
802 RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)