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 m_ch_current->getSystem(system);
380 SCAN_eDebug("dumping NIT");
381 if (m_flags & clearToScanOnFirstNIT)
384 m_flags &= ~clearToScanOnFirstNIT;
386 std::vector<NetworkInformationSection*>::const_iterator i;
387 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
389 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
391 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
392 tsinfo != tsinfovec.end(); ++tsinfo)
394 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
395 (*tsinfo)->getOriginalNetworkId());
397 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
398 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
400 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
401 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
403 switch ((*desc)->getTag())
405 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
407 if (system != iDVBFrontend::feCable)
408 break; // when current locked transponder is no cable transponder ignore this descriptor
409 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
410 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
411 eDVBFrontendParametersCable cable;
413 feparm->setDVBC(cable);
415 unsigned long hash=0;
416 feparm->getHash(hash);
417 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
420 eDVBChannelID(ns, tsid, onid),
424 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
426 if (system != iDVBFrontend::feTerrestrial)
427 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
428 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
429 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
430 eDVBFrontendParametersTerrestrial terr;
432 feparm->setDVBT(terr);
434 unsigned long hash=0;
435 feparm->getHash(hash);
436 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
439 eDVBChannelID(ns, tsid, onid),
443 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
445 if (system != iDVBFrontend::feSatellite)
446 break; // when current locked transponder is no satellite transponder ignore this descriptor
448 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
449 if (d.getFrequency() < 10000)
452 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
453 eDVBFrontendParametersSatellite sat;
455 feparm->setDVBS(sat);
456 unsigned long hash=0;
457 feparm->getHash(hash);
459 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
461 if ( m_chid_current.dvbnamespace.get() != -1 &&
462 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
463 SCAN_eDebug("dropping this transponder, it's on another satellite.");
467 eDVBChannelID(ns, tsid, onid),
473 SCAN_eDebug("descr<%x>", (*desc)->getTag());
480 m_ready &= ~validNIT;
483 if ((m_ready & m_ready_all) != m_ready_all)
485 SCAN_eDebug("channel done!");
487 /* if we had services on this channel, we declare
488 this channels as "known good". add it.
490 (TODO: not yet implemented)
491 a NIT entry could have possible overridden
492 our frontend data with more exact data.
494 (TODO: not yet implemented)
495 the tuning process could have lead to more
496 exact data than the user entered.
498 The channel id was probably corrected
499 by the data written in the SDT. this is
500 important, as "initial transponder lists"
501 usually don't have valid CHIDs (and that's
504 These are the reasons for adding the transponder
505 here, and not before.
509 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
512 addKnownGoodChannel(m_chid_current, m_ch_current);
514 m_ch_scanned.push_back(m_ch_current);
516 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
518 if (sameChannel(*i, m_ch_current))
520 eDebug("remove dupe 2");
521 m_ch_toScan.erase(i++);
531 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
535 m_ch_scanned.clear();
536 m_ch_unavailable.clear();
537 m_new_channels.clear();
538 m_new_services.clear();
539 m_last_service = m_new_services.end();
541 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
544 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
546 if (sameChannel(*i, *ii, true))
553 m_ch_toScan.push_back(*i);
559 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
561 if (m_flags & scanRemoveServices)
563 bool clearTerrestrial=false;
564 bool clearCable=false;
565 std::set<unsigned int> scanned_sat_positions;
567 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
568 for (;it != m_ch_scanned.end(); ++it)
571 (*it)->getSystem(system);
574 case iDVBFrontend::feSatellite:
576 eDVBFrontendParametersSatellite sat_parm;
577 (*it)->getDVBS(sat_parm);
578 scanned_sat_positions.insert(sat_parm.orbital_position);
581 case iDVBFrontend::feTerrestrial:
583 clearTerrestrial=true;
586 case iDVBFrontend::feCable:
594 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
597 (*it)->getSystem(system);
600 case iDVBFrontend::feSatellite:
602 eDVBFrontendParametersSatellite sat_parm;
603 (*it)->getDVBS(sat_parm);
604 scanned_sat_positions.insert(sat_parm.orbital_position);
607 case iDVBFrontend::feTerrestrial:
609 clearTerrestrial=true;
612 case iDVBFrontend::feCable:
620 if (clearTerrestrial)
623 chid.dvbnamespace=0xEEEE0000;
624 db->removeServices(chid);
629 chid.dvbnamespace=0xFFFF0000;
630 db->removeServices(chid);
632 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
635 if (m_flags & scanDontRemoveFeeds)
636 chid.dvbnamespace = eDVBNamespace((*x)<<16);
637 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
638 db->removeServices(chid, *x);
642 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
643 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
644 db->addChannelToList(ch->first, ch->second);
645 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
646 service(m_new_services.begin()); service != m_new_services.end(); ++service)
648 ePtr<eDVBService> dvb_service;
649 if (!db->getService(service->first, dvb_service))
651 if (dvb_service->m_flags & eDVBService::dxNoSDT)
653 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
655 dvb_service->m_service_name = service->second->m_service_name;
656 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
658 dvb_service->m_provider_name = service->second->m_provider_name;
659 if (service->second->m_ca.size())
660 dvb_service->m_ca = service->second->m_ca;
661 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
662 dvb_service->m_flags &= ~eDVBService::dxNewFound;
666 db->addService(service->first, service->second);
667 service->second->m_flags |= eDVBService::dxNewFound;
672 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
674 const ServiceDescriptionList &services = *sdt.getDescriptions();
675 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
676 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
678 /* save correct CHID for this channel */
679 m_chid_current = chid;
681 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
683 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
685 eServiceReferenceDVB ref;
686 ePtr<eDVBService> service = new eDVBService;
689 ref.setServiceID((*s)->getServiceId());
691 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
692 desc != (*s)->getDescriptors()->end(); ++desc)
693 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
694 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
696 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
697 desc != (*s)->getDescriptors()->end(); ++desc)
699 switch ((*desc)->getTag())
701 case SERVICE_DESCRIPTOR:
703 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
704 service->m_service_name = convertDVBUTF8(d.getServiceName());
705 service->genSortName();
707 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
708 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
711 case CA_IDENTIFIER_DESCRIPTOR:
713 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
714 const CaSystemIdList &caids = *d.getCaSystemIds();
715 SCAN_eDebugNoNewLine("CA ");
716 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
718 SCAN_eDebugNoNewLine("%04x ", *i);
719 service->m_ca.push_front(*i);
725 SCAN_eDebug("descr<%x>", (*desc)->getTag());
730 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
734 m_last_service = i.first;
735 m_event(evtNewService);
741 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
743 connection = new eConnection(this, m_event.connect(event));
747 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
749 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
750 transponders_total = m_ch_toScan.size() + transponders_done;
751 services = m_new_services.size();
754 void eDVBScan::getLastServiceName(std::string &last_service_name)
756 if (m_last_service == m_new_services.end())
757 last_service_name = "";
759 last_service_name = m_last_service->second->m_service_name;