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_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;
126 if (fe->tune(*m_ch_current))
128 return nextChannel();
137 RESULT eDVBScan::startFilter()
142 /* only start required filters filter */
144 if (m_ready_all & readyPAT)
145 startSDT = m_ready & readyPAT;
148 if (startSDT && (m_ready_all & readySDT))
150 m_SDT = new eTable<ServiceDescriptionSection>();
151 if (m_ready & readyPAT && m_ready & validPAT)
153 std::vector<ProgramAssociationSection*>::const_iterator i =
154 m_PAT->getSections().begin();
155 assert(i != m_PAT->getSections().end());
156 int tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
157 if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
160 else if (m_SDT->start(m_demux, eDVBSDTSpec()))
162 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
165 if (!(m_ready & readyPAT))
168 if (m_ready_all & readyPAT)
170 m_PAT = new eTable<ProgramAssociationSection>();
171 if (m_PAT->start(m_demux, eDVBPATSpec()))
173 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
177 if (m_ready_all & readyNIT)
179 m_NIT = new eTable<NetworkInformationSection>();
180 if (m_NIT->start(m_demux, eDVBNITSpec()))
182 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
186 if (m_ready_all & readyBAT)
188 m_BAT = new eTable<BouquetAssociationSection>();
189 if (m_BAT->start(m_demux, eDVBBATSpec()))
191 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
198 void eDVBScan::SDTready(int err)
200 SCAN_eDebug("got sdt");
207 void eDVBScan::NITready(int err)
209 SCAN_eDebug("got nit, err %d", err);
216 void eDVBScan::BATready(int err)
218 SCAN_eDebug("got bat");
225 void eDVBScan::PATready(int err)
227 SCAN_eDebug("got pat");
231 startFilter(); // for starting the SDT filter
234 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
236 /* add it to the list of known channels. */
238 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
241 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
243 /* check if we don't already have that channel ... */
246 feparm->getSystem(type);
250 case iDVBFrontend::feSatellite:
252 eDVBFrontendParametersSatellite parm;
253 feparm->getDVBS(parm);
254 eDebug("try to add %d %d %d %d %d %d",
255 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
258 case iDVBFrontend::feCable:
260 eDVBFrontendParametersCable parm;
261 feparm->getDVBC(parm);
262 eDebug("try to add %d %d %d %d",
263 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
266 case iDVBFrontend::feTerrestrial:
268 eDVBFrontendParametersTerrestrial parm;
269 feparm->getDVBT(parm);
270 eDebug("try to add %d %d %d %d %d %d %d %d",
271 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
272 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
278 /* ... in the list of channels to scan */
279 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
281 if (sameChannel(*i, feparm))
285 *i = feparm; // update
290 eDebug("remove dupe");
291 m_ch_toScan.erase(i++);
301 eDebug("already in todo list");
305 /* ... in the list of successfully scanned channels */
306 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
307 if (sameChannel(*i, feparm))
309 eDebug("successfully scanned");
313 /* ... in the list of unavailable channels */
314 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
315 if (sameChannel(*i, feparm, true))
317 eDebug("scanned but not available");
321 /* ... on the current channel */
322 if (sameChannel(m_ch_current, feparm))
324 eDebug("is current");
328 eDebug("really add");
329 /* otherwise, add it to the todo list. */
330 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
333 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
336 if (ch1->calculateDifference(ch2, diff, exact))
338 if (diff < 4000) // more than 4mhz difference?
343 void eDVBScan::channelDone()
345 if (m_ready & validSDT)
347 unsigned long hash = 0;
349 // m_ch_current is not set, when eDVBScan is just used for a SDT update
351 m_channel->getCurrentFrontendParameters(m_ch_current);
353 m_ch_current->getHash(hash);
355 eDVBNamespace dvbnamespace = buildNamespace(
356 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
357 (**m_SDT->getSections().begin()).getTransportStreamId(),
360 SCAN_eDebug("SDT: ");
361 std::vector<ServiceDescriptionSection*>::const_iterator i;
362 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
363 processSDT(dvbnamespace, **i);
364 m_ready &= ~validSDT;
367 if (m_ready & validNIT)
370 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
371 m_ch_current->getSystem(system);
372 SCAN_eDebug("dumping NIT");
373 if (m_flags & clearToScanOnFirstNIT)
375 m_ch_toScan_backup = m_ch_toScan;
378 std::vector<NetworkInformationSection*>::const_iterator i;
379 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
381 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
383 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
384 tsinfo != tsinfovec.end(); ++tsinfo)
386 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
387 (*tsinfo)->getOriginalNetworkId());
389 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
390 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
392 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
393 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
395 switch ((*desc)->getTag())
397 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
399 if (system != iDVBFrontend::feCable)
400 break; // when current locked transponder is no cable transponder ignore this descriptor
401 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
402 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
403 eDVBFrontendParametersCable cable;
405 feparm->setDVBC(cable);
407 unsigned long hash=0;
408 feparm->getHash(hash);
409 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
412 eDVBChannelID(ns, tsid, onid),
416 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
418 if (system != iDVBFrontend::feTerrestrial)
419 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
420 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
421 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
422 eDVBFrontendParametersTerrestrial terr;
424 feparm->setDVBT(terr);
426 unsigned long hash=0;
427 feparm->getHash(hash);
428 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
431 eDVBChannelID(ns, tsid, onid),
435 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
437 if (system != iDVBFrontend::feSatellite)
438 break; // when current locked transponder is no satellite transponder ignore this descriptor
440 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
441 if (d.getFrequency() < 10000)
444 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
445 eDVBFrontendParametersSatellite sat;
447 feparm->setDVBS(sat);
449 eDVBFrontendParametersSatellite p;
450 m_ch_current->getDVBS(p);
452 if ( p.orbital_position != sat.orbital_position )
453 SCAN_eDebug("dropping this transponder, it's on another satellite.");
456 unsigned long hash=0;
457 feparm->getHash(hash);
459 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
465 SCAN_eDebug("descr<%x>", (*desc)->getTag());
473 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
474 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
477 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
479 if (m_flags & clearToScanOnFirstNIT)
481 if (m_ch_toScan.empty())
483 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
484 m_ch_toScan = m_ch_toScan_backup;
486 m_flags &= ~clearToScanOnFirstNIT;
488 m_ready &= ~validNIT;
491 if ((m_ready & m_ready_all) != m_ready_all)
493 SCAN_eDebug("channel done!");
495 /* if we had services on this channel, we declare
496 this channels as "known good". add it.
498 (TODO: not yet implemented)
499 a NIT entry could have possible overridden
500 our frontend data with more exact data.
502 (TODO: not yet implemented)
503 the tuning process could have lead to more
504 exact data than the user entered.
506 The channel id was probably corrected
507 by the data written in the SDT. this is
508 important, as "initial transponder lists"
509 usually don't have valid CHIDs (and that's
512 These are the reasons for adding the transponder
513 here, and not before.
517 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
519 addKnownGoodChannel(m_chid_current, m_ch_current);
521 m_ch_scanned.push_back(m_ch_current);
523 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
525 if (sameChannel(*i, m_ch_current))
527 eDebug("remove dupe 2");
528 m_ch_toScan.erase(i++);
537 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
541 m_ch_scanned.clear();
542 m_ch_unavailable.clear();
543 m_new_channels.clear();
544 m_new_services.clear();
545 m_last_service = m_new_services.end();
547 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
550 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
552 if (sameChannel(*i, *ii, true))
559 m_ch_toScan.push_back(*i);
565 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
567 if (m_flags & scanRemoveServices)
569 bool clearTerrestrial=false;
570 bool clearCable=false;
571 std::set<unsigned int> scanned_sat_positions;
573 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
574 for (;it != m_ch_scanned.end(); ++it)
577 (*it)->getSystem(system);
580 case iDVBFrontend::feSatellite:
582 eDVBFrontendParametersSatellite sat_parm;
583 (*it)->getDVBS(sat_parm);
584 scanned_sat_positions.insert(sat_parm.orbital_position);
587 case iDVBFrontend::feTerrestrial:
589 clearTerrestrial=true;
592 case iDVBFrontend::feCable:
600 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
603 (*it)->getSystem(system);
606 case iDVBFrontend::feSatellite:
608 eDVBFrontendParametersSatellite sat_parm;
609 (*it)->getDVBS(sat_parm);
610 scanned_sat_positions.insert(sat_parm.orbital_position);
613 case iDVBFrontend::feTerrestrial:
615 clearTerrestrial=true;
618 case iDVBFrontend::feCable:
626 if (clearTerrestrial)
629 chid.dvbnamespace=0xEEEE0000;
630 db->removeServices(chid);
635 chid.dvbnamespace=0xFFFF0000;
636 db->removeServices(chid);
638 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
641 if (m_flags & scanDontRemoveFeeds)
642 chid.dvbnamespace = eDVBNamespace((*x)<<16);
643 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
644 db->removeServices(chid, *x);
648 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
649 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
650 db->addChannelToList(ch->first, ch->second);
651 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
652 service(m_new_services.begin()); service != m_new_services.end(); ++service)
654 ePtr<eDVBService> dvb_service;
655 if (!db->getService(service->first, dvb_service))
657 if (dvb_service->m_flags & eDVBService::dxNoSDT)
659 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
661 dvb_service->m_service_name = service->second->m_service_name;
662 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
664 dvb_service->m_provider_name = service->second->m_provider_name;
665 if (service->second->m_ca.size())
666 dvb_service->m_ca = service->second->m_ca;
667 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
668 dvb_service->m_flags &= ~eDVBService::dxNewFound;
672 db->addService(service->first, service->second);
673 service->second->m_flags |= eDVBService::dxNewFound;
678 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
680 const ServiceDescriptionList &services = *sdt.getDescriptions();
681 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
682 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
684 /* save correct CHID for this channel */
685 m_chid_current = chid;
687 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
689 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
691 eServiceReferenceDVB ref;
692 ePtr<eDVBService> service = new eDVBService;
695 ref.setServiceID((*s)->getServiceId());
697 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
698 desc != (*s)->getDescriptors()->end(); ++desc)
699 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
700 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
702 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
703 desc != (*s)->getDescriptors()->end(); ++desc)
705 switch ((*desc)->getTag())
707 case SERVICE_DESCRIPTOR:
709 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
710 service->m_service_name = convertDVBUTF8(d.getServiceName());
711 service->genSortName();
713 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
714 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
717 case CA_IDENTIFIER_DESCRIPTOR:
719 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
720 const CaSystemIdList &caids = *d.getCaSystemIds();
721 SCAN_eDebugNoNewLine("CA ");
722 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
724 SCAN_eDebugNoNewLine("%04x ", *i);
725 service->m_ca.push_front(*i);
731 SCAN_eDebug("descr<%x>", (*desc)->getTag());
736 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
740 m_last_service = i.first;
741 m_event(evtNewService);
747 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
749 connection = new eConnection(this, m_event.connect(event));
753 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
755 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
756 transponders_total = m_ch_toScan.size() + transponders_done;
757 services = m_new_services.size();
760 void eDVBScan::getLastServiceName(std::string &last_service_name)
762 if (m_last_service == m_new_services.end())
763 last_service_name = "";
765 last_service_name = m_last_service->second->m_service_name;