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>();
148 if (m_ready & readyPAT && m_ready & validPAT)
150 std::vector<ProgramAssociationSection*>::const_iterator i =
151 m_PAT->getSections().begin();
152 assert(i != m_PAT->getSections().end());
153 int tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
154 if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
157 else if (m_SDT->start(m_demux, eDVBSDTSpec()))
159 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
162 if (!(m_ready & readyPAT))
165 if (m_ready_all & readyPAT)
167 m_PAT = new eTable<ProgramAssociationSection>();
168 if (m_PAT->start(m_demux, eDVBPATSpec()))
170 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
174 if (m_ready_all & readyNIT)
176 m_NIT = new eTable<NetworkInformationSection>();
177 if (m_NIT->start(m_demux, eDVBNITSpec()))
179 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
183 if (m_ready_all & readyBAT)
185 m_BAT = new eTable<BouquetAssociationSection>();
186 if (m_BAT->start(m_demux, eDVBBATSpec()))
188 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
195 void eDVBScan::SDTready(int err)
197 SCAN_eDebug("got sdt");
204 void eDVBScan::NITready(int err)
206 SCAN_eDebug("got nit, err %d", err);
213 void eDVBScan::BATready(int err)
215 SCAN_eDebug("got bat");
222 void eDVBScan::PATready(int err)
224 SCAN_eDebug("got pat");
228 startFilter(); // for starting the SDT filter
231 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
233 /* add it to the list of known channels. */
235 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
238 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
240 /* check if we don't already have that channel ... */
243 feparm->getSystem(type);
247 case iDVBFrontend::feSatellite:
249 eDVBFrontendParametersSatellite parm;
250 feparm->getDVBS(parm);
251 eDebug("try to add %d %d %d %d %d %d",
252 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
255 case iDVBFrontend::feCable:
257 eDVBFrontendParametersCable parm;
258 feparm->getDVBC(parm);
259 eDebug("try to add %d %d %d %d",
260 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
263 case iDVBFrontend::feTerrestrial:
265 eDVBFrontendParametersTerrestrial parm;
266 feparm->getDVBT(parm);
267 eDebug("try to add %d %d %d %d %d %d %d %d",
268 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
269 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
275 /* ... in the list of channels to scan */
276 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
278 if (sameChannel(*i, feparm))
282 *i = feparm; // update
287 eDebug("remove dupe");
288 m_ch_toScan.erase(i++);
298 eDebug("already in todo list");
302 /* ... in the list of successfully scanned channels */
303 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
304 if (sameChannel(*i, feparm))
306 eDebug("successfully scanned");
310 /* ... in the list of unavailable channels */
311 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
312 if (sameChannel(*i, feparm, true))
314 eDebug("scanned but not available");
318 /* ... on the current channel */
319 if (sameChannel(m_ch_current, feparm))
321 eDebug("is current");
325 eDebug("really add");
326 /* otherwise, add it to the todo list. */
327 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
330 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
333 if (ch1->calculateDifference(ch2, diff, exact))
335 if (diff < 4000) // more than 4mhz difference?
340 void eDVBScan::channelDone()
342 if (m_ready & validSDT)
344 unsigned long hash = 0;
346 // m_ch_current is not set, when eDVBScan is just used for a SDT update
348 m_channel->getCurrentFrontendParameters(m_ch_current);
350 m_ch_current->getHash(hash);
352 eDVBNamespace dvbnamespace = buildNamespace(
353 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
354 (**m_SDT->getSections().begin()).getTransportStreamId(),
357 SCAN_eDebug("SDT: ");
358 std::vector<ServiceDescriptionSection*>::const_iterator i;
359 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
360 processSDT(dvbnamespace, **i);
361 m_ready &= ~validSDT;
364 if (m_ready & validNIT)
367 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
368 m_ch_current->getSystem(system);
369 SCAN_eDebug("dumping NIT");
370 if (m_flags & clearToScanOnFirstNIT)
372 m_ch_toScan_backup = m_ch_toScan;
375 std::vector<NetworkInformationSection*>::const_iterator i;
376 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
378 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
380 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
381 tsinfo != tsinfovec.end(); ++tsinfo)
383 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
384 (*tsinfo)->getOriginalNetworkId());
386 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
387 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
389 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
390 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
392 switch ((*desc)->getTag())
394 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
396 if (system != iDVBFrontend::feCable)
397 break; // when current locked transponder is no cable transponder ignore this descriptor
398 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
399 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
400 eDVBFrontendParametersCable cable;
402 feparm->setDVBC(cable);
404 unsigned long hash=0;
405 feparm->getHash(hash);
406 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
409 eDVBChannelID(ns, tsid, onid),
413 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
415 if (system != iDVBFrontend::feTerrestrial)
416 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
417 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
418 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
419 eDVBFrontendParametersTerrestrial terr;
421 feparm->setDVBT(terr);
423 unsigned long hash=0;
424 feparm->getHash(hash);
425 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
428 eDVBChannelID(ns, tsid, onid),
432 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
434 if (system != iDVBFrontend::feSatellite)
435 break; // when current locked transponder is no satellite transponder ignore this descriptor
437 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
438 if (d.getFrequency() < 10000)
441 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
442 eDVBFrontendParametersSatellite sat;
445 eDVBFrontendParametersSatellite p;
446 m_ch_current->getDVBS(p);
448 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
449 sat.orbital_position = p.orbital_position;
451 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
453 eDebug("found transponder with incorrect west/east flag ... correct this");
454 sat.orbital_position = p.orbital_position;
457 feparm->setDVBS(sat);
459 if ( p.orbital_position != sat.orbital_position)
460 SCAN_eDebug("dropping this transponder, it's on another satellite.");
463 unsigned long hash=0;
464 feparm->getHash(hash);
466 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
472 SCAN_eDebug("descr<%x>", (*desc)->getTag());
480 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
481 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
484 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
486 if (m_flags & clearToScanOnFirstNIT)
488 if (m_ch_toScan.empty())
490 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
491 m_ch_toScan = m_ch_toScan_backup;
493 m_flags &= ~clearToScanOnFirstNIT;
495 m_ready &= ~validNIT;
498 if ((m_ready & m_ready_all) != m_ready_all)
500 SCAN_eDebug("channel done!");
502 /* if we had services on this channel, we declare
503 this channels as "known good". add it.
505 (TODO: not yet implemented)
506 a NIT entry could have possible overridden
507 our frontend data with more exact data.
509 (TODO: not yet implemented)
510 the tuning process could have lead to more
511 exact data than the user entered.
513 The channel id was probably corrected
514 by the data written in the SDT. this is
515 important, as "initial transponder lists"
516 usually don't have valid CHIDs (and that's
519 These are the reasons for adding the transponder
520 here, and not before.
524 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
526 addKnownGoodChannel(m_chid_current, m_ch_current);
528 m_ch_scanned.push_back(m_ch_current);
530 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
532 if (sameChannel(*i, m_ch_current))
534 eDebug("remove dupe 2");
535 m_ch_toScan.erase(i++);
544 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
548 m_ch_scanned.clear();
549 m_ch_unavailable.clear();
550 m_new_channels.clear();
551 m_new_services.clear();
552 m_last_service = m_new_services.end();
554 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
557 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
559 if (sameChannel(*i, *ii, true))
566 m_ch_toScan.push_back(*i);
572 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
574 if (m_flags & scanRemoveServices)
576 bool clearTerrestrial=false;
577 bool clearCable=false;
578 std::set<unsigned int> scanned_sat_positions;
580 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
581 for (;it != m_ch_scanned.end(); ++it)
584 (*it)->getSystem(system);
587 case iDVBFrontend::feSatellite:
589 eDVBFrontendParametersSatellite sat_parm;
590 (*it)->getDVBS(sat_parm);
591 scanned_sat_positions.insert(sat_parm.orbital_position);
594 case iDVBFrontend::feTerrestrial:
596 clearTerrestrial=true;
599 case iDVBFrontend::feCable:
607 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
610 (*it)->getSystem(system);
613 case iDVBFrontend::feSatellite:
615 eDVBFrontendParametersSatellite sat_parm;
616 (*it)->getDVBS(sat_parm);
617 scanned_sat_positions.insert(sat_parm.orbital_position);
620 case iDVBFrontend::feTerrestrial:
622 clearTerrestrial=true;
625 case iDVBFrontend::feCable:
633 if (clearTerrestrial)
636 chid.dvbnamespace=0xEEEE0000;
637 db->removeServices(chid);
642 chid.dvbnamespace=0xFFFF0000;
643 db->removeServices(chid);
645 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
648 if (m_flags & scanDontRemoveFeeds)
649 chid.dvbnamespace = eDVBNamespace((*x)<<16);
650 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
651 db->removeServices(chid, *x);
655 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
656 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
657 db->addChannelToList(ch->first, ch->second);
658 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
659 service(m_new_services.begin()); service != m_new_services.end(); ++service)
661 ePtr<eDVBService> dvb_service;
662 if (!db->getService(service->first, dvb_service))
664 if (dvb_service->m_flags & eDVBService::dxNoSDT)
666 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
668 dvb_service->m_service_name = service->second->m_service_name;
669 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
671 dvb_service->m_provider_name = service->second->m_provider_name;
672 if (service->second->m_ca.size())
673 dvb_service->m_ca = service->second->m_ca;
674 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
675 dvb_service->m_flags &= ~eDVBService::dxNewFound;
679 db->addService(service->first, service->second);
680 if (!(m_flags & scanRemoveServices))
681 service->second->m_flags |= eDVBService::dxNewFound;
686 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
688 const ServiceDescriptionList &services = *sdt.getDescriptions();
689 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
690 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
692 /* save correct CHID for this channel */
693 m_chid_current = chid;
695 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
697 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
699 eServiceReferenceDVB ref;
700 ePtr<eDVBService> service = new eDVBService;
703 ref.setServiceID((*s)->getServiceId());
705 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
706 desc != (*s)->getDescriptors()->end(); ++desc)
707 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
708 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
710 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
711 desc != (*s)->getDescriptors()->end(); ++desc)
713 switch ((*desc)->getTag())
715 case SERVICE_DESCRIPTOR:
717 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
718 service->m_service_name = convertDVBUTF8(d.getServiceName());
719 service->genSortName();
721 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
722 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
725 case CA_IDENTIFIER_DESCRIPTOR:
727 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
728 const CaSystemIdList &caids = *d.getCaSystemIds();
729 SCAN_eDebugNoNewLine("CA ");
730 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
732 SCAN_eDebugNoNewLine("%04x ", *i);
733 service->m_ca.push_front(*i);
739 SCAN_eDebug("descr<%x>", (*desc)->getTag());
744 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
748 m_last_service = i.first;
749 m_event(evtNewService);
755 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
757 connection = new eConnection(this, m_event.connect(event));
761 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
763 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
764 transponders_total = m_ch_toScan.size() + transponders_done;
765 services = m_new_services.size();
768 void eDVBScan::getLastServiceName(std::string &last_service_name)
770 if (m_last_service == m_new_services.end())
771 last_service_name = "";
773 last_service_name = m_last_service->second->m_service_name;
776 RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
779 return m_channel->getFrontend(fe);
784 RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)