1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/service_description_section.h>
3 #include <dvbsi++/network_information_section.h>
4 #include <dvbsi++/bouquet_association_section.h>
5 #include <dvbsi++/descriptor_tag.h>
6 #include <dvbsi++/service_descriptor.h>
7 #include <dvbsi++/satellite_delivery_system_descriptor.h>
8 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
9 #include <dvbsi++/cable_delivery_system_descriptor.h>
10 #include <dvbsi++/ca_identifier_descriptor.h>
11 #include <lib/dvb/specs.h>
12 #include <lib/dvb/esection.h>
13 #include <lib/dvb/scan.h>
14 #include <lib/dvb/frontend.h>
15 #include <lib/base/eerror.h>
16 #include <lib/base/estring.h>
20 #define SCAN_eDebug(x...) eDebug(x)
21 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
25 eDVBScan::eDVBScan(iDVBChannel *channel)
26 :m_channel(channel), m_ready(0), m_flags(0), m_ready_all(readySDT)
27 ,m_channel_state(iDVBChannel::state_idle)
29 if (m_channel->getDemux(m_demux))
30 SCAN_eDebug("scan: failed to allocate demux!");
31 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
38 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
46 return orbital_position == 192;
48 return tsid != 0x00B0;
50 return abs(orbital_position-282) < 6;
52 return onid.get() < 0xFF00;
56 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
58 // on valid ONIDs, ignore frequency ("sub network") part
59 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
61 return eDVBNamespace(hash);
64 void eDVBScan::stateChange(iDVBChannel *ch)
67 if (ch->getState(state))
69 if (m_channel_state == state)
72 if (state == iDVBChannel::state_ok)
75 m_channel_state = state;
76 } else if (state == iDVBChannel::state_failed)
78 m_ch_unavailable.push_back(m_ch_current);
81 /* unavailable will timeout, anyway. */
84 RESULT eDVBScan::nextChannel()
86 ePtr<iDVBFrontend> fe;
88 m_SDT = 0; m_BAT = 0; m_NIT = 0;
92 /* check what we need */
93 m_ready_all = readySDT;
95 if (m_flags & scanNetworkSearch)
96 m_ready_all |= readyNIT;
98 if (m_flags & scanSearchBAT)
99 m_ready_all |= readyBAT;
101 if (m_ch_toScan.empty())
103 // SCAN_eDebug("no channels left to scan.");
104 // SCAN_eDebug("%d channels scanned, %d were unavailable.",
105 // m_ch_scanned.size(), m_ch_unavailable.size());
106 // SCAN_eDebug("%d channels in database.", m_new_channels.size());
111 m_ch_current = m_ch_toScan.front();
113 m_ch_toScan.pop_front();
115 if (m_channel->getFrontend(fe))
122 fe->getFrontendType(fetype);
123 if ( fetype == iDVBFrontend::feSatellite)
125 eDVBFrontendParametersSatellite p;
126 m_ch_current->getDVBS(p);
127 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
130 m_chid_current = eDVBChannelID();
132 m_channel_state = iDVBChannel::state_idle;
133 if (fe->tune(*m_ch_current))
135 return nextChannel();
144 RESULT eDVBScan::startFilter()
148 /* only start required filters filter */
152 if (m_ready_all & readySDT)
154 m_SDT = new eTable<ServiceDescriptionSection>();
155 if (m_SDT->start(m_demux, eDVBSDTSpec()))
157 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
161 if (m_ready_all & readyNIT)
163 m_NIT = new eTable<NetworkInformationSection>();
164 if (m_NIT->start(m_demux, eDVBNITSpec()))
166 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
170 if (m_ready_all & readyBAT)
172 m_BAT = new eTable<BouquetAssociationSection>();
173 if (m_BAT->start(m_demux, eDVBBATSpec()))
175 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
181 void eDVBScan::SDTready(int err)
183 SCAN_eDebug("got sdt");
190 void eDVBScan::NITready(int err)
192 SCAN_eDebug("got nit, err %d", err);
199 void eDVBScan::BATready(int err)
201 SCAN_eDebug("got bat");
208 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
210 /* add it to the list of known channels. */
212 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
215 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
217 /* check if we don't already have that channel ... */
219 /* ... in the list of channels to scan */
220 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
221 if (sameChannel(*i, feparm))
224 /* ... in the list of successfully scanned channels */
225 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
226 if (sameChannel(*i, feparm))
229 /* ... in the list of unavailable channels */
230 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
231 if (sameChannel(*i, feparm))
234 /* ... on the current channel */
235 if (sameChannel(m_ch_current, feparm))
238 /* otherwise, add it to the todo list. */
239 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
242 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
245 if (ch1->calculateDifference(ch2, diff))
247 if (diff < 4000) // more than 4mhz difference?
252 void eDVBScan::channelDone()
254 if (m_ready & validSDT)
256 unsigned long hash = 0;
258 // m_ch_current is not set, when eDVBScan is just used for a SDT update
260 m_channel->getCurrentFrontendParameters(m_ch_current);
262 m_ch_current->getHash(hash);
264 eDVBNamespace dvbnamespace = buildNamespace(
265 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
266 (**m_SDT->getSections().begin()).getTransportStreamId(),
269 SCAN_eDebug("SDT: ");
270 std::vector<ServiceDescriptionSection*>::const_iterator i;
271 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
272 processSDT(dvbnamespace, **i);
273 m_ready &= ~validSDT;
276 if (m_ready & validNIT)
278 SCAN_eDebug("dumping NIT");
279 std::vector<NetworkInformationSection*>::const_iterator i;
280 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
282 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
284 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
285 tsinfo != tsinfovec.end(); ++tsinfo)
287 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
288 (*tsinfo)->getOriginalNetworkId());
290 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
291 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
293 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
294 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
296 switch ((*desc)->getTag())
298 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
300 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
301 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
302 eDVBFrontendParametersCable cable;
304 feparm->setDVBC(cable);
306 unsigned long hash=0;
307 feparm->getHash(hash);
308 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
311 eDVBChannelID(ns, tsid, onid),
315 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
317 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
318 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
319 eDVBFrontendParametersTerrestrial terr;
321 feparm->setDVBT(terr);
323 unsigned long hash=0;
324 feparm->getHash(hash);
325 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
328 eDVBChannelID(ns, tsid, onid),
332 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
334 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
335 if (d.getFrequency() < 10000)
338 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
339 eDVBFrontendParametersSatellite sat;
341 feparm->setDVBS(sat);
342 unsigned long hash=0;
343 feparm->getHash(hash);
345 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
347 if ( m_chid_current.dvbnamespace.get() != -1 &&
348 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
349 SCAN_eDebug("dropping this transponder, it's on another satellite.");
353 eDVBChannelID(ns, tsid, onid),
359 SCAN_eDebug("descr<%x>", (*desc)->getTag());
366 m_ready &= ~validNIT;
369 if ((m_ready & m_ready_all) != m_ready_all)
371 SCAN_eDebug("channel done!");
373 /* if we had services on this channel, we declare
374 this channels as "known good". add it.
376 (TODO: not yet implemented)
377 a NIT entry could have possible overridden
378 our frontend data with more exact data.
380 (TODO: not yet implemented)
381 the tuning process could have lead to more
382 exact data than the user entered.
384 The channel id was probably corrected
385 by the data written in the SDT. this is
386 important, as "initial transponder lists"
387 usually don't have valid CHIDs (and that's
390 These are the reasons for adding the transponder
391 here, and not before.
395 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
397 addKnownGoodChannel(m_chid_current, m_ch_current);
399 m_ch_scanned.push_back(m_ch_current);
403 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
407 m_ch_scanned.clear();
408 m_ch_unavailable.clear();
409 m_new_channels.clear();
410 m_new_services.clear();
411 m_last_service = m_new_services.end();
413 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
416 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
418 if (sameChannel(*i, *ii))
425 m_ch_toScan.push_back(*i);
431 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
433 if (m_flags & scanRemoveServices)
435 bool clearTerrestrial=false;
436 bool clearCable=false;
437 std::set<unsigned int> scanned_sat_positions;
439 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
440 for (;it != m_ch_scanned.end(); ++it)
443 (*it)->getSystem(system);
446 case iDVBFrontend::feSatellite:
448 eDVBFrontendParametersSatellite sat_parm;
449 (*it)->getDVBS(sat_parm);
450 scanned_sat_positions.insert(sat_parm.orbital_position);
453 case iDVBFrontend::feTerrestrial:
455 clearTerrestrial=true;
458 case iDVBFrontend::feCable:
466 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
469 (*it)->getSystem(system);
472 case iDVBFrontend::feSatellite:
474 eDVBFrontendParametersSatellite sat_parm;
475 (*it)->getDVBS(sat_parm);
476 scanned_sat_positions.insert(sat_parm.orbital_position);
479 case iDVBFrontend::feTerrestrial:
481 clearTerrestrial=true;
484 case iDVBFrontend::feCable:
492 if (clearTerrestrial)
495 chid.dvbnamespace=0xEEEE0000;
496 db->removeServices(chid);
501 chid.dvbnamespace=0xFFFF0000;
502 db->removeServices(chid);
504 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
507 if (m_flags & scanDontRemoveFeeds)
508 chid.dvbnamespace = eDVBNamespace((*x)<<16);
509 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
510 db->removeServices(chid, *x);
514 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
515 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
516 db->addChannelToList(ch->first, ch->second);
517 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
518 service(m_new_services.begin()); service != m_new_services.end(); ++service)
520 ePtr<eDVBService> dvb_service;
521 if (!db->getService(service->first, dvb_service))
523 if (dvb_service->m_flags & eDVBService::dxNoSDT)
525 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
527 dvb_service->m_service_name = service->second->m_service_name;
528 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
530 dvb_service->m_provider_name = service->second->m_provider_name;
532 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
533 dvb_service->m_flags &= ~eDVBService::dxNewFound;
537 db->addService(service->first, service->second);
538 service->second->m_flags |= eDVBService::dxNewFound;
543 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
545 const ServiceDescriptionList &services = *sdt.getDescriptions();
546 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
547 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
549 /* save correct CHID for this channel if this is an ACTUAL_SDT */
550 if (sdt.getTableId() == TID_SDT_ACTUAL)
551 m_chid_current = chid;
553 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
555 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
557 eServiceReferenceDVB ref;
558 ePtr<eDVBService> service = new eDVBService;
561 ref.setServiceID((*s)->getServiceId());
563 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
564 desc != (*s)->getDescriptors()->end(); ++desc)
565 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
566 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
568 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
569 desc != (*s)->getDescriptors()->end(); ++desc)
571 switch ((*desc)->getTag())
573 case SERVICE_DESCRIPTOR:
575 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
576 service->m_service_name = convertDVBUTF8(d.getServiceName());
577 service->genSortName();
579 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
580 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
584 case CA_IDENTIFIER_DESCRIPTOR:
586 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
587 const CaSystemIdList &caids = *d.getCaSystemIds();
588 SCAN_eDebugNoNewLine("CA ");
589 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
591 SCAN_eDebugNoNewLine("%04x ", *i);
592 service->m_ca.insert(*i);
599 SCAN_eDebug("descr<%x>", (*desc)->getTag());
604 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
608 m_last_service = i.first;
609 m_event(evtNewService);
615 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
617 connection = new eConnection(this, m_event.connect(event));
621 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
623 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
624 transponders_total = m_ch_toScan.size() + transponders_done;
625 services = m_new_services.size();
628 void eDVBScan::getLastServiceName(std::string &last_service_name)
630 if (m_last_service == m_new_services.end())
631 last_service_name = "";
633 last_service_name = m_last_service->second->m_service_name;