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 618 Mhz 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)
169 if (tsid == -1 && m_SDT->start(m_demux, eDVBSDTSpec()))
171 else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
173 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
176 if (!(m_ready & readyPAT))
179 if (m_ready_all & readyPAT)
181 m_PAT = new eTable<ProgramAssociationSection>();
182 if (m_PAT->start(m_demux, eDVBPATSpec()))
184 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
188 if (m_ready_all & readyNIT)
190 m_NIT = new eTable<NetworkInformationSection>();
191 if (m_NIT->start(m_demux, eDVBNITSpec()))
193 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
197 if (m_ready_all & readyBAT)
199 m_BAT = new eTable<BouquetAssociationSection>();
200 if (m_BAT->start(m_demux, eDVBBATSpec()))
202 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
209 void eDVBScan::SDTready(int err)
211 SCAN_eDebug("got sdt");
218 void eDVBScan::NITready(int err)
220 SCAN_eDebug("got nit, err %d", err);
227 void eDVBScan::BATready(int err)
229 SCAN_eDebug("got bat");
236 void eDVBScan::PATready(int err)
238 SCAN_eDebug("got pat");
242 startFilter(); // for starting the SDT filter
245 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
247 /* add it to the list of known channels. */
249 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
252 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
254 /* check if we don't already have that channel ... */
257 feparm->getSystem(type);
261 case iDVBFrontend::feSatellite:
263 eDVBFrontendParametersSatellite parm;
264 feparm->getDVBS(parm);
265 eDebug("try to add %d %d %d %d %d %d",
266 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
269 case iDVBFrontend::feCable:
271 eDVBFrontendParametersCable parm;
272 feparm->getDVBC(parm);
273 eDebug("try to add %d %d %d %d",
274 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
277 case iDVBFrontend::feTerrestrial:
279 eDVBFrontendParametersTerrestrial parm;
280 feparm->getDVBT(parm);
281 eDebug("try to add %d %d %d %d %d %d %d %d",
282 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
283 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
289 /* ... in the list of channels to scan */
290 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
292 if (sameChannel(*i, feparm))
296 *i = feparm; // update
301 eDebug("remove dupe");
302 m_ch_toScan.erase(i++);
312 eDebug("already in todo list");
316 /* ... in the list of successfully scanned channels */
317 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
318 if (sameChannel(*i, feparm))
320 eDebug("successfully scanned");
324 /* ... in the list of unavailable channels */
325 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
326 if (sameChannel(*i, feparm, true))
328 eDebug("scanned but not available");
332 /* ... on the current channel */
333 if (sameChannel(m_ch_current, feparm))
335 eDebug("is current");
339 eDebug("really add");
340 /* otherwise, add it to the todo list. */
341 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
344 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
347 if (ch1->calculateDifference(ch2, diff, exact))
349 if (diff < 4000) // more than 4mhz difference?
354 void eDVBScan::channelDone()
356 if (m_ready & validSDT)
358 unsigned long hash = 0;
360 // m_ch_current is not set, when eDVBScan is just used for a SDT update
362 m_channel->getCurrentFrontendParameters(m_ch_current);
364 m_ch_current->getHash(hash);
366 eDVBNamespace dvbnamespace = buildNamespace(
367 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
368 (**m_SDT->getSections().begin()).getTransportStreamId(),
371 SCAN_eDebug("SDT: ");
372 std::vector<ServiceDescriptionSection*>::const_iterator i;
373 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
374 processSDT(dvbnamespace, **i);
375 m_ready &= ~validSDT;
378 if (m_ready & validNIT)
381 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
382 m_ch_current->getSystem(system);
383 SCAN_eDebug("dumping NIT");
384 if (m_flags & clearToScanOnFirstNIT)
386 m_ch_toScan_backup = m_ch_toScan;
389 std::vector<NetworkInformationSection*>::const_iterator i;
390 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
392 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
394 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
395 tsinfo != tsinfovec.end(); ++tsinfo)
397 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
398 (*tsinfo)->getOriginalNetworkId());
400 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
401 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
403 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
404 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
406 switch ((*desc)->getTag())
408 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
410 if (system != iDVBFrontend::feCable)
411 break; // when current locked transponder is no cable transponder ignore this descriptor
412 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
413 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
414 eDVBFrontendParametersCable cable;
416 feparm->setDVBC(cable);
418 unsigned long hash=0;
419 feparm->getHash(hash);
420 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
423 eDVBChannelID(ns, tsid, onid),
427 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
429 if (system != iDVBFrontend::feTerrestrial)
430 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
431 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
432 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
433 eDVBFrontendParametersTerrestrial terr;
435 feparm->setDVBT(terr);
437 unsigned long hash=0;
438 feparm->getHash(hash);
439 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
442 eDVBChannelID(ns, tsid, onid),
446 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
448 if (system != iDVBFrontend::feSatellite)
449 break; // when current locked transponder is no satellite transponder ignore this descriptor
451 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
452 if (d.getFrequency() < 10000)
455 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
456 eDVBFrontendParametersSatellite sat;
459 eDVBFrontendParametersSatellite p;
460 m_ch_current->getDVBS(p);
462 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
463 sat.orbital_position = p.orbital_position;
465 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
467 eDebug("found transponder with incorrect west/east flag ... correct this");
468 sat.orbital_position = p.orbital_position;
471 feparm->setDVBS(sat);
473 if ( p.orbital_position != sat.orbital_position)
474 SCAN_eDebug("dropping this transponder, it's on another satellite.");
477 unsigned long hash=0;
478 feparm->getHash(hash);
480 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
486 SCAN_eDebug("descr<%x>", (*desc)->getTag());
494 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
495 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
498 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
500 if (m_flags & clearToScanOnFirstNIT)
502 if (m_ch_toScan.empty())
504 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
505 m_ch_toScan = m_ch_toScan_backup;
507 m_flags &= ~clearToScanOnFirstNIT;
509 m_ready &= ~validNIT;
512 if ((m_ready & m_ready_all) != m_ready_all)
514 SCAN_eDebug("channel done!");
516 /* if we had services on this channel, we declare
517 this channels as "known good". add it.
519 (TODO: not yet implemented)
520 a NIT entry could have possible overridden
521 our frontend data with more exact data.
523 (TODO: not yet implemented)
524 the tuning process could have lead to more
525 exact data than the user entered.
527 The channel id was probably corrected
528 by the data written in the SDT. this is
529 important, as "initial transponder lists"
530 usually don't have valid CHIDs (and that's
533 These are the reasons for adding the transponder
534 here, and not before.
538 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
540 addKnownGoodChannel(m_chid_current, m_ch_current);
542 m_ch_scanned.push_back(m_ch_current);
544 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
546 if (sameChannel(*i, m_ch_current))
548 eDebug("remove dupe 2");
549 m_ch_toScan.erase(i++);
558 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
562 m_ch_scanned.clear();
563 m_ch_unavailable.clear();
564 m_new_channels.clear();
565 m_new_services.clear();
566 m_last_service = m_new_services.end();
568 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
571 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
573 if (sameChannel(*i, *ii, true))
580 m_ch_toScan.push_back(*i);
586 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
588 if (m_flags & scanRemoveServices)
590 bool clearTerrestrial=false;
591 bool clearCable=false;
592 std::set<unsigned int> scanned_sat_positions;
594 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
595 for (;it != m_ch_scanned.end(); ++it)
598 (*it)->getSystem(system);
601 case iDVBFrontend::feSatellite:
603 eDVBFrontendParametersSatellite sat_parm;
604 (*it)->getDVBS(sat_parm);
605 scanned_sat_positions.insert(sat_parm.orbital_position);
608 case iDVBFrontend::feTerrestrial:
610 clearTerrestrial=true;
613 case iDVBFrontend::feCable:
621 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
624 (*it)->getSystem(system);
627 case iDVBFrontend::feSatellite:
629 eDVBFrontendParametersSatellite sat_parm;
630 (*it)->getDVBS(sat_parm);
631 scanned_sat_positions.insert(sat_parm.orbital_position);
634 case iDVBFrontend::feTerrestrial:
636 clearTerrestrial=true;
639 case iDVBFrontend::feCable:
647 if (clearTerrestrial)
650 chid.dvbnamespace=0xEEEE0000;
651 db->removeServices(chid);
656 chid.dvbnamespace=0xFFFF0000;
657 db->removeServices(chid);
659 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
662 if (m_flags & scanDontRemoveFeeds)
663 chid.dvbnamespace = eDVBNamespace((*x)<<16);
664 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
665 db->removeServices(chid, *x);
669 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
670 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
671 db->addChannelToList(ch->first, ch->second);
672 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
673 service(m_new_services.begin()); service != m_new_services.end(); ++service)
675 ePtr<eDVBService> dvb_service;
676 if (!db->getService(service->first, dvb_service))
678 if (dvb_service->m_flags & eDVBService::dxNoSDT)
680 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
682 dvb_service->m_service_name = service->second->m_service_name;
683 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
685 dvb_service->m_provider_name = service->second->m_provider_name;
686 if (service->second->m_ca.size())
687 dvb_service->m_ca = service->second->m_ca;
688 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
689 dvb_service->m_flags &= ~eDVBService::dxNewFound;
693 db->addService(service->first, service->second);
694 if (!(m_flags & scanRemoveServices))
695 service->second->m_flags |= eDVBService::dxNewFound;
700 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
702 const ServiceDescriptionList &services = *sdt.getDescriptions();
703 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
704 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
706 /* save correct CHID for this channel */
707 m_chid_current = chid;
709 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
711 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
713 eServiceReferenceDVB ref;
714 ePtr<eDVBService> service = new eDVBService;
717 ref.setServiceID((*s)->getServiceId());
719 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
720 desc != (*s)->getDescriptors()->end(); ++desc)
721 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
722 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
724 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
725 desc != (*s)->getDescriptors()->end(); ++desc)
727 switch ((*desc)->getTag())
729 case SERVICE_DESCRIPTOR:
731 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
732 service->m_service_name = convertDVBUTF8(d.getServiceName());
733 service->genSortName();
735 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
736 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
739 case CA_IDENTIFIER_DESCRIPTOR:
741 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
742 const CaSystemIdList &caids = *d.getCaSystemIds();
743 SCAN_eDebugNoNewLine("CA ");
744 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
746 SCAN_eDebugNoNewLine("%04x ", *i);
747 service->m_ca.push_front(*i);
753 SCAN_eDebug("descr<%x>", (*desc)->getTag());
758 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
762 m_last_service = i.first;
763 m_event(evtNewService);
769 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
771 connection = new eConnection(this, m_event.connect(event));
775 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
777 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
778 transponders_total = m_ch_toScan.size() + transponders_done;
779 services = m_new_services.size();
782 void eDVBScan::getLastServiceName(std::string &last_service_name)
784 if (m_last_service == m_new_services.end())
785 last_service_name = "";
787 last_service_name = m_last_service->second->m_service_name;
790 RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
793 return m_channel->getFrontend(fe);
798 RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)