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))
170 if (tsid == -1 && m_SDT->start(m_demux, eDVBSDTSpec()))
172 else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
174 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
177 if (!(m_ready & readyPAT))
180 if (m_ready_all & readyPAT)
182 m_PAT = new eTable<ProgramAssociationSection>();
183 if (m_PAT->start(m_demux, eDVBPATSpec()))
185 CONNECT(m_PAT->tableReady, eDVBScan::PATready);
189 if (m_ready_all & readyNIT)
191 m_NIT = new eTable<NetworkInformationSection>();
192 if (m_NIT->start(m_demux, eDVBNITSpec()))
194 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
198 if (m_ready_all & readyBAT)
200 m_BAT = new eTable<BouquetAssociationSection>();
201 if (m_BAT->start(m_demux, eDVBBATSpec()))
203 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
210 void eDVBScan::SDTready(int err)
212 SCAN_eDebug("got sdt");
219 void eDVBScan::NITready(int err)
221 SCAN_eDebug("got nit, err %d", err);
228 void eDVBScan::BATready(int err)
230 SCAN_eDebug("got bat");
237 void eDVBScan::PATready(int err)
239 SCAN_eDebug("got pat");
243 startFilter(); // for starting the SDT filter
246 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
248 /* add it to the list of known channels. */
250 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
253 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
255 /* check if we don't already have that channel ... */
258 feparm->getSystem(type);
262 case iDVBFrontend::feSatellite:
264 eDVBFrontendParametersSatellite parm;
265 feparm->getDVBS(parm);
266 eDebug("try to add %d %d %d %d %d %d",
267 parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
270 case iDVBFrontend::feCable:
272 eDVBFrontendParametersCable parm;
273 feparm->getDVBC(parm);
274 eDebug("try to add %d %d %d %d",
275 parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
278 case iDVBFrontend::feTerrestrial:
280 eDVBFrontendParametersTerrestrial parm;
281 feparm->getDVBT(parm);
282 eDebug("try to add %d %d %d %d %d %d %d %d",
283 parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
284 parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
290 /* ... in the list of channels to scan */
291 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
293 if (sameChannel(*i, feparm))
297 *i = feparm; // update
302 eDebug("remove dupe");
303 m_ch_toScan.erase(i++);
313 eDebug("already in todo list");
317 /* ... in the list of successfully scanned channels */
318 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
319 if (sameChannel(*i, feparm))
321 eDebug("successfully scanned");
325 /* ... in the list of unavailable channels */
326 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
327 if (sameChannel(*i, feparm, true))
329 eDebug("scanned but not available");
333 /* ... on the current channel */
334 if (sameChannel(m_ch_current, feparm))
336 eDebug("is current");
340 eDebug("really add");
341 /* otherwise, add it to the todo list. */
342 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
345 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
348 if (ch1->calculateDifference(ch2, diff, exact))
350 if (diff < 4000) // more than 4mhz difference?
355 void eDVBScan::channelDone()
357 if (m_ready & validSDT)
359 unsigned long hash = 0;
361 // m_ch_current is not set, when eDVBScan is just used for a SDT update
363 m_channel->getCurrentFrontendParameters(m_ch_current);
365 m_ch_current->getHash(hash);
367 eDVBNamespace dvbnamespace = buildNamespace(
368 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
369 (**m_SDT->getSections().begin()).getTransportStreamId(),
372 SCAN_eDebug("SDT: ");
373 std::vector<ServiceDescriptionSection*>::const_iterator i;
374 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
375 processSDT(dvbnamespace, **i);
376 m_ready &= ~validSDT;
379 if (m_ready & validNIT)
382 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
383 m_ch_current->getSystem(system);
384 SCAN_eDebug("dumping NIT");
385 if (m_flags & clearToScanOnFirstNIT)
387 m_ch_toScan_backup = m_ch_toScan;
390 std::vector<NetworkInformationSection*>::const_iterator i;
391 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
393 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
395 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
396 tsinfo != tsinfovec.end(); ++tsinfo)
398 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
399 (*tsinfo)->getOriginalNetworkId());
401 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
402 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
404 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
405 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
407 switch ((*desc)->getTag())
409 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
411 if (system != iDVBFrontend::feCable)
412 break; // when current locked transponder is no cable transponder ignore this descriptor
413 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
414 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
415 eDVBFrontendParametersCable cable;
417 feparm->setDVBC(cable);
419 unsigned long hash=0;
420 feparm->getHash(hash);
421 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
424 eDVBChannelID(ns, tsid, onid),
428 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
430 if (system != iDVBFrontend::feTerrestrial)
431 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
432 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
433 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
434 eDVBFrontendParametersTerrestrial terr;
436 feparm->setDVBT(terr);
438 unsigned long hash=0;
439 feparm->getHash(hash);
440 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
443 eDVBChannelID(ns, tsid, onid),
447 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
449 if (system != iDVBFrontend::feSatellite)
450 break; // when current locked transponder is no satellite transponder ignore this descriptor
452 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
453 if (d.getFrequency() < 10000)
456 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
457 eDVBFrontendParametersSatellite sat;
460 eDVBFrontendParametersSatellite p;
461 m_ch_current->getDVBS(p);
463 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
464 sat.orbital_position = p.orbital_position;
466 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
468 eDebug("found transponder with incorrect west/east flag ... correct this");
469 sat.orbital_position = p.orbital_position;
472 feparm->setDVBS(sat);
474 if ( p.orbital_position != sat.orbital_position)
475 SCAN_eDebug("dropping this transponder, it's on another satellite.");
478 unsigned long hash=0;
479 feparm->getHash(hash);
481 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
487 SCAN_eDebug("descr<%x>", (*desc)->getTag());
495 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
496 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
499 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
501 if (m_flags & clearToScanOnFirstNIT)
503 if (m_ch_toScan.empty())
505 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
506 m_ch_toScan = m_ch_toScan_backup;
508 m_flags &= ~clearToScanOnFirstNIT;
510 m_ready &= ~validNIT;
513 if ((m_ready & m_ready_all) != m_ready_all)
515 SCAN_eDebug("channel done!");
517 /* if we had services on this channel, we declare
518 this channels as "known good". add it.
520 (TODO: not yet implemented)
521 a NIT entry could have possible overridden
522 our frontend data with more exact data.
524 (TODO: not yet implemented)
525 the tuning process could have lead to more
526 exact data than the user entered.
528 The channel id was probably corrected
529 by the data written in the SDT. this is
530 important, as "initial transponder lists"
531 usually don't have valid CHIDs (and that's
534 These are the reasons for adding the transponder
535 here, and not before.
539 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
541 addKnownGoodChannel(m_chid_current, m_ch_current);
543 m_ch_scanned.push_back(m_ch_current);
545 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
547 if (sameChannel(*i, m_ch_current))
549 eDebug("remove dupe 2");
550 m_ch_toScan.erase(i++);
559 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
563 m_ch_scanned.clear();
564 m_ch_unavailable.clear();
565 m_new_channels.clear();
566 m_new_services.clear();
567 m_last_service = m_new_services.end();
569 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
572 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
574 if (sameChannel(*i, *ii, true))
581 m_ch_toScan.push_back(*i);
587 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
589 if (m_flags & scanRemoveServices)
591 bool clearTerrestrial=false;
592 bool clearCable=false;
593 std::set<unsigned int> scanned_sat_positions;
595 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
596 for (;it != m_ch_scanned.end(); ++it)
599 (*it)->getSystem(system);
602 case iDVBFrontend::feSatellite:
604 eDVBFrontendParametersSatellite sat_parm;
605 (*it)->getDVBS(sat_parm);
606 scanned_sat_positions.insert(sat_parm.orbital_position);
609 case iDVBFrontend::feTerrestrial:
611 clearTerrestrial=true;
614 case iDVBFrontend::feCable:
622 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
625 (*it)->getSystem(system);
628 case iDVBFrontend::feSatellite:
630 eDVBFrontendParametersSatellite sat_parm;
631 (*it)->getDVBS(sat_parm);
632 scanned_sat_positions.insert(sat_parm.orbital_position);
635 case iDVBFrontend::feTerrestrial:
637 clearTerrestrial=true;
640 case iDVBFrontend::feCable:
648 if (clearTerrestrial)
651 chid.dvbnamespace=0xEEEE0000;
652 db->removeServices(chid);
657 chid.dvbnamespace=0xFFFF0000;
658 db->removeServices(chid);
660 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
663 if (m_flags & scanDontRemoveFeeds)
664 chid.dvbnamespace = eDVBNamespace((*x)<<16);
665 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
666 db->removeServices(chid, *x);
670 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
671 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
672 db->addChannelToList(ch->first, ch->second);
673 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
674 service(m_new_services.begin()); service != m_new_services.end(); ++service)
676 ePtr<eDVBService> dvb_service;
677 if (!db->getService(service->first, dvb_service))
679 if (dvb_service->m_flags & eDVBService::dxNoSDT)
681 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
683 dvb_service->m_service_name = service->second->m_service_name;
684 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
686 dvb_service->m_provider_name = service->second->m_provider_name;
687 if (service->second->m_ca.size())
688 dvb_service->m_ca = service->second->m_ca;
689 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
690 dvb_service->m_flags &= ~eDVBService::dxNewFound;
694 db->addService(service->first, service->second);
695 if (!(m_flags & scanRemoveServices))
696 service->second->m_flags |= eDVBService::dxNewFound;
701 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
703 const ServiceDescriptionList &services = *sdt.getDescriptions();
704 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
705 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
707 /* save correct CHID for this channel */
708 m_chid_current = chid;
710 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
712 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
714 eServiceReferenceDVB ref;
715 ePtr<eDVBService> service = new eDVBService;
718 ref.setServiceID((*s)->getServiceId());
720 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
721 desc != (*s)->getDescriptors()->end(); ++desc)
722 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
723 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
725 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
726 desc != (*s)->getDescriptors()->end(); ++desc)
728 switch ((*desc)->getTag())
730 case SERVICE_DESCRIPTOR:
732 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
733 service->m_service_name = convertDVBUTF8(d.getServiceName());
734 service->genSortName();
736 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
737 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
740 case CA_IDENTIFIER_DESCRIPTOR:
742 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
743 const CaSystemIdList &caids = *d.getCaSystemIds();
744 SCAN_eDebugNoNewLine("CA ");
745 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
747 SCAN_eDebugNoNewLine("%04x ", *i);
748 service->m_ca.push_front(*i);
754 SCAN_eDebug("descr<%x>", (*desc)->getTag());
759 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
763 m_last_service = i.first;
764 m_event(evtNewService);
770 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
772 connection = new eConnection(this, m_event.connect(event));
776 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
778 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
779 transponders_total = m_ch_toScan.size() + transponders_done;
780 services = m_new_services.size();
783 void eDVBScan::getLastServiceName(std::string &last_service_name)
785 if (m_last_service == m_new_services.end())
786 last_service_name = "";
788 last_service_name = m_last_service->second->m_service_name;
791 RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
794 return m_channel->getFrontend(fe);
799 RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)