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)
359 SCAN_eDebug("dumping NIT");
360 if (m_flags & clearToScanOnFirstNIT)
363 m_flags &= ~clearToScanOnFirstNIT;
365 std::vector<NetworkInformationSection*>::const_iterator i;
366 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
368 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
370 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
371 tsinfo != tsinfovec.end(); ++tsinfo)
373 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
374 (*tsinfo)->getOriginalNetworkId());
376 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
377 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
379 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
380 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
382 switch ((*desc)->getTag())
384 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
386 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
387 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
388 eDVBFrontendParametersCable cable;
390 feparm->setDVBC(cable);
392 unsigned long hash=0;
393 feparm->getHash(hash);
394 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
397 eDVBChannelID(ns, tsid, onid),
401 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
403 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
404 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
405 eDVBFrontendParametersTerrestrial terr;
407 feparm->setDVBT(terr);
409 unsigned long hash=0;
410 feparm->getHash(hash);
411 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
414 eDVBChannelID(ns, tsid, onid),
418 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
420 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
421 if (d.getFrequency() < 10000)
424 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
425 eDVBFrontendParametersSatellite sat;
427 feparm->setDVBS(sat);
428 unsigned long hash=0;
429 feparm->getHash(hash);
431 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
433 if ( m_chid_current.dvbnamespace.get() != -1 &&
434 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
435 SCAN_eDebug("dropping this transponder, it's on another satellite.");
439 eDVBChannelID(ns, tsid, onid),
445 SCAN_eDebug("descr<%x>", (*desc)->getTag());
452 m_ready &= ~validNIT;
455 if ((m_ready & m_ready_all) != m_ready_all)
457 SCAN_eDebug("channel done!");
459 /* if we had services on this channel, we declare
460 this channels as "known good". add it.
462 (TODO: not yet implemented)
463 a NIT entry could have possible overridden
464 our frontend data with more exact data.
466 (TODO: not yet implemented)
467 the tuning process could have lead to more
468 exact data than the user entered.
470 The channel id was probably corrected
471 by the data written in the SDT. this is
472 important, as "initial transponder lists"
473 usually don't have valid CHIDs (and that's
476 These are the reasons for adding the transponder
477 here, and not before.
481 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
483 addKnownGoodChannel(m_chid_current, m_ch_current);
485 m_ch_scanned.push_back(m_ch_current);
489 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
493 m_ch_scanned.clear();
494 m_ch_unavailable.clear();
495 m_new_channels.clear();
496 m_new_services.clear();
497 m_last_service = m_new_services.end();
499 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
502 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
504 if (sameChannel(*i, *ii))
511 m_ch_toScan.push_back(*i);
517 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
519 if (m_flags & scanRemoveServices)
521 bool clearTerrestrial=false;
522 bool clearCable=false;
523 std::set<unsigned int> scanned_sat_positions;
525 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
526 for (;it != m_ch_scanned.end(); ++it)
529 (*it)->getSystem(system);
532 case iDVBFrontend::feSatellite:
534 eDVBFrontendParametersSatellite sat_parm;
535 (*it)->getDVBS(sat_parm);
536 scanned_sat_positions.insert(sat_parm.orbital_position);
539 case iDVBFrontend::feTerrestrial:
541 clearTerrestrial=true;
544 case iDVBFrontend::feCable:
552 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
555 (*it)->getSystem(system);
558 case iDVBFrontend::feSatellite:
560 eDVBFrontendParametersSatellite sat_parm;
561 (*it)->getDVBS(sat_parm);
562 scanned_sat_positions.insert(sat_parm.orbital_position);
565 case iDVBFrontend::feTerrestrial:
567 clearTerrestrial=true;
570 case iDVBFrontend::feCable:
578 if (clearTerrestrial)
581 chid.dvbnamespace=0xEEEE0000;
582 db->removeServices(chid);
587 chid.dvbnamespace=0xFFFF0000;
588 db->removeServices(chid);
590 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
593 if (m_flags & scanDontRemoveFeeds)
594 chid.dvbnamespace = eDVBNamespace((*x)<<16);
595 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
596 db->removeServices(chid, *x);
600 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
601 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
602 db->addChannelToList(ch->first, ch->second);
603 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
604 service(m_new_services.begin()); service != m_new_services.end(); ++service)
606 ePtr<eDVBService> dvb_service;
607 if (!db->getService(service->first, dvb_service))
609 if (dvb_service->m_flags & eDVBService::dxNoSDT)
611 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
613 dvb_service->m_service_name = service->second->m_service_name;
614 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
616 dvb_service->m_provider_name = service->second->m_provider_name;
617 if (service->second->m_ca.size())
618 dvb_service->m_ca = service->second->m_ca;
619 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
620 dvb_service->m_flags &= ~eDVBService::dxNewFound;
624 db->addService(service->first, service->second);
625 service->second->m_flags |= eDVBService::dxNewFound;
630 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
632 const ServiceDescriptionList &services = *sdt.getDescriptions();
633 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
634 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
636 /* save correct CHID for this channel */
637 m_chid_current = chid;
639 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
641 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
643 eServiceReferenceDVB ref;
644 ePtr<eDVBService> service = new eDVBService;
647 ref.setServiceID((*s)->getServiceId());
649 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
650 desc != (*s)->getDescriptors()->end(); ++desc)
651 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
652 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
654 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
655 desc != (*s)->getDescriptors()->end(); ++desc)
657 switch ((*desc)->getTag())
659 case SERVICE_DESCRIPTOR:
661 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
662 service->m_service_name = convertDVBUTF8(d.getServiceName());
663 service->genSortName();
665 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
666 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
669 case CA_IDENTIFIER_DESCRIPTOR:
671 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
672 const CaSystemIdList &caids = *d.getCaSystemIds();
673 SCAN_eDebugNoNewLine("CA ");
674 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
676 SCAN_eDebugNoNewLine("%04x ", *i);
677 service->m_ca.push_front(*i);
683 SCAN_eDebug("descr<%x>", (*desc)->getTag());
688 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
692 m_last_service = i.first;
693 m_event(evtNewService);
699 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
701 connection = new eConnection(this, m_event.connect(event));
705 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
707 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
708 transponders_total = m_ch_toScan.size() + transponders_done;
709 services = m_new_services.size();
712 void eDVBScan::getLastServiceName(std::string &last_service_name)
714 if (m_last_service == m_new_services.end())
715 last_service_name = "";
717 last_service_name = m_last_service->second->m_service_name;