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;
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;
448 eDVBFrontendParametersSatellite p;
449 m_ch_current->getDVBS(p);
451 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
452 sat.orbital_position = p.orbital_position;
454 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
456 eDebug("found transponder with incorrect west/east flag ... correct this");
457 sat.orbital_position = p.orbital_position;
460 feparm->setDVBS(sat);
462 if ( p.orbital_position != sat.orbital_position)
463 SCAN_eDebug("dropping this transponder, it's on another satellite.");
466 unsigned long hash=0;
467 feparm->getHash(hash);
469 eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
475 SCAN_eDebug("descr<%x>", (*desc)->getTag());
483 /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
484 no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
487 This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
489 if (m_flags & clearToScanOnFirstNIT)
491 if (m_ch_toScan.empty())
493 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
494 m_ch_toScan = m_ch_toScan_backup;
496 m_flags &= ~clearToScanOnFirstNIT;
498 m_ready &= ~validNIT;
501 if ((m_ready & m_ready_all) != m_ready_all)
503 SCAN_eDebug("channel done!");
505 /* if we had services on this channel, we declare
506 this channels as "known good". add it.
508 (TODO: not yet implemented)
509 a NIT entry could have possible overridden
510 our frontend data with more exact data.
512 (TODO: not yet implemented)
513 the tuning process could have lead to more
514 exact data than the user entered.
516 The channel id was probably corrected
517 by the data written in the SDT. this is
518 important, as "initial transponder lists"
519 usually don't have valid CHIDs (and that's
522 These are the reasons for adding the transponder
523 here, and not before.
527 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++);
547 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
551 m_ch_scanned.clear();
552 m_ch_unavailable.clear();
553 m_new_channels.clear();
554 m_new_services.clear();
555 m_last_service = m_new_services.end();
557 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
560 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
562 if (sameChannel(*i, *ii, true))
569 m_ch_toScan.push_back(*i);
575 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
577 if (m_flags & scanRemoveServices)
579 bool clearTerrestrial=false;
580 bool clearCable=false;
581 std::set<unsigned int> scanned_sat_positions;
583 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
584 for (;it != m_ch_scanned.end(); ++it)
587 (*it)->getSystem(system);
590 case iDVBFrontend::feSatellite:
592 eDVBFrontendParametersSatellite sat_parm;
593 (*it)->getDVBS(sat_parm);
594 scanned_sat_positions.insert(sat_parm.orbital_position);
597 case iDVBFrontend::feTerrestrial:
599 clearTerrestrial=true;
602 case iDVBFrontend::feCable:
610 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
613 (*it)->getSystem(system);
616 case iDVBFrontend::feSatellite:
618 eDVBFrontendParametersSatellite sat_parm;
619 (*it)->getDVBS(sat_parm);
620 scanned_sat_positions.insert(sat_parm.orbital_position);
623 case iDVBFrontend::feTerrestrial:
625 clearTerrestrial=true;
628 case iDVBFrontend::feCable:
636 if (clearTerrestrial)
639 chid.dvbnamespace=0xEEEE0000;
640 db->removeServices(chid);
645 chid.dvbnamespace=0xFFFF0000;
646 db->removeServices(chid);
648 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
651 if (m_flags & scanDontRemoveFeeds)
652 chid.dvbnamespace = eDVBNamespace((*x)<<16);
653 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
654 db->removeServices(chid, *x);
658 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
659 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
660 db->addChannelToList(ch->first, ch->second);
661 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
662 service(m_new_services.begin()); service != m_new_services.end(); ++service)
664 ePtr<eDVBService> dvb_service;
665 if (!db->getService(service->first, dvb_service))
667 if (dvb_service->m_flags & eDVBService::dxNoSDT)
669 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
671 dvb_service->m_service_name = service->second->m_service_name;
672 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
674 dvb_service->m_provider_name = service->second->m_provider_name;
675 if (service->second->m_ca.size())
676 dvb_service->m_ca = service->second->m_ca;
677 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
678 dvb_service->m_flags &= ~eDVBService::dxNewFound;
682 db->addService(service->first, service->second);
683 service->second->m_flags |= eDVBService::dxNewFound;
688 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
690 const ServiceDescriptionList &services = *sdt.getDescriptions();
691 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
692 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
694 /* save correct CHID for this channel */
695 m_chid_current = chid;
697 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
699 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
701 eServiceReferenceDVB ref;
702 ePtr<eDVBService> service = new eDVBService;
705 ref.setServiceID((*s)->getServiceId());
707 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
708 desc != (*s)->getDescriptors()->end(); ++desc)
709 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
710 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
712 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
713 desc != (*s)->getDescriptors()->end(); ++desc)
715 switch ((*desc)->getTag())
717 case SERVICE_DESCRIPTOR:
719 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
720 service->m_service_name = convertDVBUTF8(d.getServiceName());
721 service->genSortName();
723 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
724 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
727 case CA_IDENTIFIER_DESCRIPTOR:
729 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
730 const CaSystemIdList &caids = *d.getCaSystemIds();
731 SCAN_eDebugNoNewLine("CA ");
732 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
734 SCAN_eDebugNoNewLine("%04x ", *i);
735 service->m_ca.push_front(*i);
741 SCAN_eDebug("descr<%x>", (*desc)->getTag());
746 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
750 m_last_service = i.first;
751 m_event(evtNewService);
757 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
759 connection = new eConnection(this, m_event.connect(event));
763 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
765 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
766 transponders_total = m_ch_toScan.size() + transponders_done;
767 services = m_new_services.size();
770 void eDVBScan::getLastServiceName(std::string &last_service_name)
772 if (m_last_service == m_new_services.end())
773 last_service_name = "";
775 last_service_name = m_last_service->second->m_service_name;