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);
286 /* ... in the list of channels to scan */
287 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
288 if (sameChannel(*i, feparm))
290 *i = feparm; // update
295 /* ... in the list of successfully scanned channels */
296 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
297 if (sameChannel(*i, feparm))
299 eDebug("successfully scanned");
303 /* ... in the list of unavailable channels */
304 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
305 if (sameChannel(*i, feparm, true))
307 eDebug("scanned but not available");
311 /* ... on the current channel */
312 if (sameChannel(m_ch_current, feparm))
314 eDebug("is current");
318 eDebug("really add");
319 /* otherwise, add it to the todo list. */
320 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
323 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
326 if (ch1->calculateDifference(ch2, diff, exact))
328 if (diff < 4000) // more than 4mhz difference?
333 void eDVBScan::channelDone()
335 if (m_ready & validSDT)
337 unsigned long hash = 0;
339 // m_ch_current is not set, when eDVBScan is just used for a SDT update
341 m_channel->getCurrentFrontendParameters(m_ch_current);
343 m_ch_current->getHash(hash);
345 eDVBNamespace dvbnamespace = buildNamespace(
346 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
347 (**m_SDT->getSections().begin()).getTransportStreamId(),
350 SCAN_eDebug("SDT: ");
351 std::vector<ServiceDescriptionSection*>::const_iterator i;
352 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
353 processSDT(dvbnamespace, **i);
354 m_ready &= ~validSDT;
357 if (m_ready & validNIT)
360 m_ch_current->getSystem(system);
361 SCAN_eDebug("dumping NIT");
362 if (m_flags & clearToScanOnFirstNIT)
365 m_flags &= ~clearToScanOnFirstNIT;
367 std::vector<NetworkInformationSection*>::const_iterator i;
368 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
370 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
372 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
373 tsinfo != tsinfovec.end(); ++tsinfo)
375 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
376 (*tsinfo)->getOriginalNetworkId());
378 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
379 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
381 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
382 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
384 switch ((*desc)->getTag())
386 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
388 if (system != iDVBFrontend::feCable)
389 break; // when current locked transponder is no cable transponder ignore this descriptor
390 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
391 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
392 eDVBFrontendParametersCable cable;
394 feparm->setDVBC(cable);
396 unsigned long hash=0;
397 feparm->getHash(hash);
398 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
401 eDVBChannelID(ns, tsid, onid),
405 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
407 if (system != iDVBFrontend::feTerrestrial)
408 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
409 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
410 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
411 eDVBFrontendParametersTerrestrial terr;
413 feparm->setDVBT(terr);
415 unsigned long hash=0;
416 feparm->getHash(hash);
417 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
420 eDVBChannelID(ns, tsid, onid),
424 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
426 if (system != iDVBFrontend::feSatellite)
427 break; // when current locked transponder is no satellite transponder ignore this descriptor
429 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
430 if (d.getFrequency() < 10000)
433 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
434 eDVBFrontendParametersSatellite sat;
436 feparm->setDVBS(sat);
437 unsigned long hash=0;
438 feparm->getHash(hash);
440 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
442 if ( m_chid_current.dvbnamespace.get() != -1 &&
443 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
444 SCAN_eDebug("dropping this transponder, it's on another satellite.");
448 eDVBChannelID(ns, tsid, onid),
454 SCAN_eDebug("descr<%x>", (*desc)->getTag());
461 m_ready &= ~validNIT;
464 if ((m_ready & m_ready_all) != m_ready_all)
466 SCAN_eDebug("channel done!");
468 /* if we had services on this channel, we declare
469 this channels as "known good". add it.
471 (TODO: not yet implemented)
472 a NIT entry could have possible overridden
473 our frontend data with more exact data.
475 (TODO: not yet implemented)
476 the tuning process could have lead to more
477 exact data than the user entered.
479 The channel id was probably corrected
480 by the data written in the SDT. this is
481 important, as "initial transponder lists"
482 usually don't have valid CHIDs (and that's
485 These are the reasons for adding the transponder
486 here, and not before.
490 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
492 addKnownGoodChannel(m_chid_current, m_ch_current);
494 m_ch_scanned.push_back(m_ch_current);
498 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
502 m_ch_scanned.clear();
503 m_ch_unavailable.clear();
504 m_new_channels.clear();
505 m_new_services.clear();
506 m_last_service = m_new_services.end();
508 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
511 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
513 if (sameChannel(*i, *ii))
520 m_ch_toScan.push_back(*i);
526 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
528 if (m_flags & scanRemoveServices)
530 bool clearTerrestrial=false;
531 bool clearCable=false;
532 std::set<unsigned int> scanned_sat_positions;
534 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
535 for (;it != m_ch_scanned.end(); ++it)
538 (*it)->getSystem(system);
541 case iDVBFrontend::feSatellite:
543 eDVBFrontendParametersSatellite sat_parm;
544 (*it)->getDVBS(sat_parm);
545 scanned_sat_positions.insert(sat_parm.orbital_position);
548 case iDVBFrontend::feTerrestrial:
550 clearTerrestrial=true;
553 case iDVBFrontend::feCable:
561 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
564 (*it)->getSystem(system);
567 case iDVBFrontend::feSatellite:
569 eDVBFrontendParametersSatellite sat_parm;
570 (*it)->getDVBS(sat_parm);
571 scanned_sat_positions.insert(sat_parm.orbital_position);
574 case iDVBFrontend::feTerrestrial:
576 clearTerrestrial=true;
579 case iDVBFrontend::feCable:
587 if (clearTerrestrial)
590 chid.dvbnamespace=0xEEEE0000;
591 db->removeServices(chid);
596 chid.dvbnamespace=0xFFFF0000;
597 db->removeServices(chid);
599 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
602 if (m_flags & scanDontRemoveFeeds)
603 chid.dvbnamespace = eDVBNamespace((*x)<<16);
604 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
605 db->removeServices(chid, *x);
609 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
610 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
611 db->addChannelToList(ch->first, ch->second);
612 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
613 service(m_new_services.begin()); service != m_new_services.end(); ++service)
615 ePtr<eDVBService> dvb_service;
616 if (!db->getService(service->first, dvb_service))
618 if (dvb_service->m_flags & eDVBService::dxNoSDT)
620 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
622 dvb_service->m_service_name = service->second->m_service_name;
623 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
625 dvb_service->m_provider_name = service->second->m_provider_name;
626 if (service->second->m_ca.size())
627 dvb_service->m_ca = service->second->m_ca;
628 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
629 dvb_service->m_flags &= ~eDVBService::dxNewFound;
633 db->addService(service->first, service->second);
634 service->second->m_flags |= eDVBService::dxNewFound;
639 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
641 const ServiceDescriptionList &services = *sdt.getDescriptions();
642 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
643 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
645 /* save correct CHID for this channel */
646 m_chid_current = chid;
648 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
650 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
652 eServiceReferenceDVB ref;
653 ePtr<eDVBService> service = new eDVBService;
656 ref.setServiceID((*s)->getServiceId());
658 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
659 desc != (*s)->getDescriptors()->end(); ++desc)
660 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
661 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
663 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
664 desc != (*s)->getDescriptors()->end(); ++desc)
666 switch ((*desc)->getTag())
668 case SERVICE_DESCRIPTOR:
670 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
671 service->m_service_name = convertDVBUTF8(d.getServiceName());
672 service->genSortName();
674 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
675 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
678 case CA_IDENTIFIER_DESCRIPTOR:
680 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
681 const CaSystemIdList &caids = *d.getCaSystemIds();
682 SCAN_eDebugNoNewLine("CA ");
683 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
685 SCAN_eDebugNoNewLine("%04x ", *i);
686 service->m_ca.push_front(*i);
692 SCAN_eDebug("descr<%x>", (*desc)->getTag());
697 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
701 m_last_service = i.first;
702 m_event(evtNewService);
708 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
710 connection = new eConnection(this, m_event.connect(event));
714 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
716 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
717 transponders_total = m_ch_toScan.size() + transponders_done;
718 services = m_new_services.size();
721 void eDVBScan::getLastServiceName(std::string &last_service_name)
723 if (m_last_service == m_new_services.end())
724 last_service_name = "";
726 last_service_name = m_last_service->second->m_service_name;