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))
124 fe->getFrontendType(fetype);
125 if ( fetype == iDVBFrontend::feSatellite)
127 eDVBFrontendParametersSatellite p;
128 m_ch_current->getDVBS(p);
129 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
132 m_chid_current = eDVBChannelID();
134 m_channel_state = iDVBChannel::state_idle;
135 if (fe->tune(*m_ch_current))
137 return nextChannel();
146 RESULT eDVBScan::startFilter()
151 /* only start required filters filter */
153 if (m_ready_all & readyPAT)
154 startSDT = m_ready & readyPAT;
157 if (startSDT && (m_ready_all & readySDT))
159 m_SDT = new eTable<ServiceDescriptionSection>();
160 if (m_ready & readyPAT && m_ready & validPAT)
162 std::vector<ProgramAssociationSection*>::const_iterator i =
163 m_PAT->getSections().begin();
164 assert(i != m_PAT->getSections().end());
165 int tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
166 if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
169 else if (m_SDT->start(m_demux, eDVBSDTSpec()))
171 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
174 if (!(m_ready & readyPAT))
177 if (m_ready_all & readyPAT)
179 m_PAT = new eTable<ProgramAssociationSection>();
180 if (m_PAT->start(m_demux, eDVBPATSpec()))
182 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
186 if (m_ready_all & readyNIT)
188 m_NIT = new eTable<NetworkInformationSection>();
189 if (m_NIT->start(m_demux, eDVBNITSpec()))
191 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
195 if (m_ready_all & readyBAT)
197 m_BAT = new eTable<BouquetAssociationSection>();
198 if (m_BAT->start(m_demux, eDVBBATSpec()))
200 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
207 void eDVBScan::SDTready(int err)
209 SCAN_eDebug("got sdt");
216 void eDVBScan::NITready(int err)
218 SCAN_eDebug("got nit, err %d", err);
225 void eDVBScan::BATready(int err)
227 SCAN_eDebug("got bat");
234 void eDVBScan::PATready(int err)
236 SCAN_eDebug("got pat");
240 startFilter(); // for starting the SDT filter
243 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
245 /* add it to the list of known channels. */
247 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
250 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
252 /* check if we don't already have that channel ... */
255 feparm->getSystem(type);
259 case iDVBFrontend::feSatellite:
261 eDVBFrontendParametersSatellite parm;
262 feparm->getDVBS(parm);
263 eDebug("try to add %d %d %d %d %d %d",
264 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
267 case iDVBFrontend::feCable:
269 eDVBFrontendParametersCable parm;
270 feparm->getDVBC(parm);
271 eDebug("try to add %d %d %d %d",
272 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
275 case iDVBFrontend::feTerrestrial:
277 eDVBFrontendParametersTerrestrial parm;
278 feparm->getDVBT(parm);
279 eDebug("try to add %d %d %d %d %d %d %d %d",
280 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
281 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
287 /* ... in the list of channels to scan */
288 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
290 if (sameChannel(*i, feparm))
294 *i = feparm; // update
299 eDebug("remove dupe");
300 m_ch_toScan.erase(i++);
310 eDebug("already in todo list");
314 /* ... in the list of successfully scanned channels */
315 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
316 if (sameChannel(*i, feparm))
318 eDebug("successfully scanned");
322 /* ... in the list of unavailable channels */
323 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
324 if (sameChannel(*i, feparm, true))
326 eDebug("scanned but not available");
330 /* ... on the current channel */
331 if (sameChannel(m_ch_current, feparm))
333 eDebug("is current");
337 eDebug("really add");
338 /* otherwise, add it to the todo list. */
339 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
342 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
345 if (ch1->calculateDifference(ch2, diff, exact))
347 if (diff < 4000) // more than 4mhz difference?
352 void eDVBScan::channelDone()
354 if (m_ready & validSDT)
356 unsigned long hash = 0;
358 // m_ch_current is not set, when eDVBScan is just used for a SDT update
360 m_channel->getCurrentFrontendParameters(m_ch_current);
362 m_ch_current->getHash(hash);
364 eDVBNamespace dvbnamespace = buildNamespace(
365 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
366 (**m_SDT->getSections().begin()).getTransportStreamId(),
369 SCAN_eDebug("SDT: ");
370 std::vector<ServiceDescriptionSection*>::const_iterator i;
371 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
372 processSDT(dvbnamespace, **i);
373 m_ready &= ~validSDT;
376 if (m_ready & validNIT)
379 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
380 m_ch_current->getSystem(system);
381 SCAN_eDebug("dumping NIT");
382 if (m_flags & clearToScanOnFirstNIT)
384 m_ch_toScan_backup = m_ch_toScan;
387 std::vector<NetworkInformationSection*>::const_iterator i;
388 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
390 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
392 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
393 tsinfo != tsinfovec.end(); ++tsinfo)
395 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
396 (*tsinfo)->getOriginalNetworkId());
398 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
399 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
401 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
402 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
404 switch ((*desc)->getTag())
406 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
408 if (system != iDVBFrontend::feCable)
409 break; // when current locked transponder is no cable transponder ignore this descriptor
410 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
411 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
412 eDVBFrontendParametersCable cable;
414 feparm->setDVBC(cable);
416 unsigned long hash=0;
417 feparm->getHash(hash);
418 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
421 eDVBChannelID(ns, tsid, onid),
425 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
427 if (system != iDVBFrontend::feTerrestrial)
428 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
429 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
430 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
431 eDVBFrontendParametersTerrestrial terr;
433 feparm->setDVBT(terr);
435 unsigned long hash=0;
436 feparm->getHash(hash);
437 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
440 eDVBChannelID(ns, tsid, onid),
444 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
446 if (system != iDVBFrontend::feSatellite)
447 break; // when current locked transponder is no satellite transponder ignore this descriptor
449 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
450 if (d.getFrequency() < 10000)
453 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
454 eDVBFrontendParametersSatellite sat;
456 feparm->setDVBS(sat);
457 unsigned long hash=0;
458 feparm->getHash(hash);
460 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
462 if ( m_chid_current.dvbnamespace.get() != -1 &&
463 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
464 SCAN_eDebug("dropping this transponder, it's on another satellite.");
468 eDVBChannelID(ns, tsid, onid),
474 SCAN_eDebug("descr<%x>", (*desc)->getTag());
482 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
483 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
486 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
488 if (m_flags & clearToScanOnFirstNIT)
490 if (m_ch_toScan.empty())
492 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
493 m_ch_toScan = m_ch_toScan_backup;
495 m_flags &= ~clearToScanOnFirstNIT;
497 m_ready &= ~validNIT;
500 if ((m_ready & m_ready_all) != m_ready_all)
502 SCAN_eDebug("channel done!");
504 /* if we had services on this channel, we declare
505 this channels as "known good". add it.
507 (TODO: not yet implemented)
508 a NIT entry could have possible overridden
509 our frontend data with more exact data.
511 (TODO: not yet implemented)
512 the tuning process could have lead to more
513 exact data than the user entered.
515 The channel id was probably corrected
516 by the data written in the SDT. this is
517 important, as "initial transponder lists"
518 usually don't have valid CHIDs (and that's
521 These are the reasons for adding the transponder
522 here, and not before.
526 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
529 addKnownGoodChannel(m_chid_current, m_ch_current);
531 m_ch_scanned.push_back(m_ch_current);
533 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
535 if (sameChannel(*i, m_ch_current))
537 eDebug("remove dupe 2");
538 m_ch_toScan.erase(i++);
548 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
552 m_ch_scanned.clear();
553 m_ch_unavailable.clear();
554 m_new_channels.clear();
555 m_new_services.clear();
556 m_last_service = m_new_services.end();
558 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
561 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
563 if (sameChannel(*i, *ii, true))
570 m_ch_toScan.push_back(*i);
576 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
578 if (m_flags & scanRemoveServices)
580 bool clearTerrestrial=false;
581 bool clearCable=false;
582 std::set<unsigned int> scanned_sat_positions;
584 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
585 for (;it != m_ch_scanned.end(); ++it)
588 (*it)->getSystem(system);
591 case iDVBFrontend::feSatellite:
593 eDVBFrontendParametersSatellite sat_parm;
594 (*it)->getDVBS(sat_parm);
595 scanned_sat_positions.insert(sat_parm.orbital_position);
598 case iDVBFrontend::feTerrestrial:
600 clearTerrestrial=true;
603 case iDVBFrontend::feCable:
611 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
614 (*it)->getSystem(system);
617 case iDVBFrontend::feSatellite:
619 eDVBFrontendParametersSatellite sat_parm;
620 (*it)->getDVBS(sat_parm);
621 scanned_sat_positions.insert(sat_parm.orbital_position);
624 case iDVBFrontend::feTerrestrial:
626 clearTerrestrial=true;
629 case iDVBFrontend::feCable:
637 if (clearTerrestrial)
640 chid.dvbnamespace=0xEEEE0000;
641 db->removeServices(chid);
646 chid.dvbnamespace=0xFFFF0000;
647 db->removeServices(chid);
649 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
652 if (m_flags & scanDontRemoveFeeds)
653 chid.dvbnamespace = eDVBNamespace((*x)<<16);
654 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
655 db->removeServices(chid, *x);
659 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
660 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
661 db->addChannelToList(ch->first, ch->second);
662 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
663 service(m_new_services.begin()); service != m_new_services.end(); ++service)
665 ePtr<eDVBService> dvb_service;
666 if (!db->getService(service->first, dvb_service))
668 if (dvb_service->m_flags & eDVBService::dxNoSDT)
670 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
672 dvb_service->m_service_name = service->second->m_service_name;
673 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
675 dvb_service->m_provider_name = service->second->m_provider_name;
676 if (service->second->m_ca.size())
677 dvb_service->m_ca = service->second->m_ca;
678 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
679 dvb_service->m_flags &= ~eDVBService::dxNewFound;
683 db->addService(service->first, service->second);
684 service->second->m_flags |= eDVBService::dxNewFound;
689 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
691 const ServiceDescriptionList &services = *sdt.getDescriptions();
692 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
693 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
695 /* save correct CHID for this channel */
696 m_chid_current = chid;
698 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
700 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
702 eServiceReferenceDVB ref;
703 ePtr<eDVBService> service = new eDVBService;
706 ref.setServiceID((*s)->getServiceId());
708 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
709 desc != (*s)->getDescriptors()->end(); ++desc)
710 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
711 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
713 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
714 desc != (*s)->getDescriptors()->end(); ++desc)
716 switch ((*desc)->getTag())
718 case SERVICE_DESCRIPTOR:
720 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
721 service->m_service_name = convertDVBUTF8(d.getServiceName());
722 service->genSortName();
724 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
725 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
728 case CA_IDENTIFIER_DESCRIPTOR:
730 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
731 const CaSystemIdList &caids = *d.getCaSystemIds();
732 SCAN_eDebugNoNewLine("CA ");
733 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
735 SCAN_eDebugNoNewLine("%04x ", *i);
736 service->m_ca.push_front(*i);
742 SCAN_eDebug("descr<%x>", (*desc)->getTag());
747 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
751 m_last_service = i.first;
752 m_event(evtNewService);
758 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
760 connection = new eConnection(this, m_event.connect(event));
764 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
766 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
767 transponders_total = m_ch_toScan.size() + transponders_done;
768 services = m_new_services.size();
771 void eDVBScan::getLastServiceName(std::string &last_service_name)
773 if (m_last_service == m_new_services.end())
774 last_service_name = "";
776 last_service_name = m_last_service->second->m_service_name;