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>
19 static bool scan_debug;
20 #define SCAN_eDebug(x...) if (scan_debug) eDebug(x)
21 #define SCAN_eDebugNoNewLine(x...) if (scan_debug) eDebugNoNewLine(x)
25 eDVBScan::eDVBScan(iDVBChannel *channel, bool debug)
26 :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
27 ,m_ready(0), m_ready_all(readySDT), m_flags(0)
30 if (m_channel->getDemux(m_demux))
31 SCAN_eDebug("scan: failed to allocate demux!");
32 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
39 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
47 return orbital_position == 192;
49 return tsid != 0x00B0;
51 return abs(orbital_position-282) < 6;
53 return onid.get() < 0xFF00;
57 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
59 // on valid ONIDs, ignore frequency ("sub network") part
60 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
62 return eDVBNamespace(hash);
65 void eDVBScan::stateChange(iDVBChannel *ch)
68 if (ch->getState(state))
70 if (m_channel_state == state)
73 if (state == iDVBChannel::state_ok)
76 m_channel_state = state;
77 } else if (state == iDVBChannel::state_failed)
79 m_ch_unavailable.push_back(m_ch_current);
82 /* unavailable will timeout, anyway. */
85 RESULT eDVBScan::nextChannel()
87 ePtr<iDVBFrontend> fe;
89 m_SDT = 0; m_BAT = 0; m_NIT = 0;
93 /* check what we need */
94 m_ready_all = readySDT;
96 if (m_flags & scanNetworkSearch)
97 m_ready_all |= readyNIT;
99 if (m_flags & scanSearchBAT)
100 m_ready_all |= readyBAT;
102 if (m_ch_toScan.empty())
104 SCAN_eDebug("no channels left to scan.");
105 SCAN_eDebug("%d channels scanned, %d were unavailable.",
106 m_ch_scanned.size(), m_ch_unavailable.size());
107 SCAN_eDebug("%d channels in database.", m_new_channels.size());
112 m_ch_current = m_ch_toScan.front();
114 m_ch_toScan.pop_front();
116 if (m_channel->getFrontend(fe))
123 fe->getFrontendType(fetype);
124 if ( fetype == iDVBFrontend::feSatellite)
126 eDVBFrontendParametersSatellite p;
127 m_ch_current->getDVBS(p);
128 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
131 m_chid_current = eDVBChannelID();
133 m_channel_state = iDVBChannel::state_idle;
134 if (fe->tune(*m_ch_current))
136 return nextChannel();
145 RESULT eDVBScan::startFilter()
149 /* only start required filters filter */
153 if (m_ready_all & readySDT)
155 m_SDT = new eTable<ServiceDescriptionSection>();
156 if (m_SDT->start(m_demux, eDVBSDTSpec()))
158 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
162 if (m_ready_all & readyNIT)
164 m_NIT = new eTable<NetworkInformationSection>();
165 if (m_NIT->start(m_demux, eDVBNITSpec()))
167 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
171 if (m_ready_all & readyBAT)
173 m_BAT = new eTable<BouquetAssociationSection>();
174 if (m_BAT->start(m_demux, eDVBBATSpec()))
176 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
182 void eDVBScan::SDTready(int err)
184 SCAN_eDebug("got sdt");
191 void eDVBScan::NITready(int err)
193 SCAN_eDebug("got nit, err %d", err);
200 void eDVBScan::BATready(int err)
202 SCAN_eDebug("got bat");
209 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
211 /* add it to the list of known channels. */
213 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
216 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
218 /* check if we don't already have that channel ... */
220 /* ... in the list of channels to scan */
221 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
222 if (sameChannel(*i, feparm))
225 /* ... in the list of successfully scanned channels */
226 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
227 if (sameChannel(*i, feparm))
230 /* ... in the list of unavailable channels */
231 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
232 if (sameChannel(*i, feparm))
235 /* ... on the current channel */
236 if (sameChannel(m_ch_current, feparm))
239 /* otherwise, add it to the todo list. */
240 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
243 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
246 if (ch1->calculateDifference(ch2, diff))
248 if (diff < 4000) // more than 4mhz difference?
253 void eDVBScan::channelDone()
255 if (m_ready & validSDT)
257 unsigned long hash = 0;
259 // m_ch_current is not set, when eDVBScan is just used for a SDT update
261 m_channel->getCurrentFrontendParameters(m_ch_current);
263 m_ch_current->getHash(hash);
265 eDVBNamespace dvbnamespace = buildNamespace(
266 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
267 (**m_SDT->getSections().begin()).getTransportStreamId(),
270 SCAN_eDebug("SDT: ");
271 std::vector<ServiceDescriptionSection*>::const_iterator i;
272 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
273 processSDT(dvbnamespace, **i);
274 m_ready &= ~validSDT;
277 if (m_ready & validNIT)
279 SCAN_eDebug("dumping NIT");
280 std::vector<NetworkInformationSection*>::const_iterator i;
281 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
283 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
285 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
286 tsinfo != tsinfovec.end(); ++tsinfo)
288 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
289 (*tsinfo)->getOriginalNetworkId());
291 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
292 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
294 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
295 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
297 switch ((*desc)->getTag())
299 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
301 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
302 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
303 eDVBFrontendParametersCable cable;
305 feparm->setDVBC(cable);
307 unsigned long hash=0;
308 feparm->getHash(hash);
309 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
312 eDVBChannelID(ns, tsid, onid),
316 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
318 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
319 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
320 eDVBFrontendParametersTerrestrial terr;
322 feparm->setDVBT(terr);
324 unsigned long hash=0;
325 feparm->getHash(hash);
326 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
329 eDVBChannelID(ns, tsid, onid),
333 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
335 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
336 if (d.getFrequency() < 10000)
339 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
340 eDVBFrontendParametersSatellite sat;
342 feparm->setDVBS(sat);
343 unsigned long hash=0;
344 feparm->getHash(hash);
346 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
348 if ( m_chid_current.dvbnamespace.get() != -1 &&
349 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
350 SCAN_eDebug("dropping this transponder, it's on another satellite.");
354 eDVBChannelID(ns, tsid, onid),
360 SCAN_eDebug("descr<%x>", (*desc)->getTag());
367 m_ready &= ~validNIT;
370 if ((m_ready & m_ready_all) != m_ready_all)
372 SCAN_eDebug("channel done!");
374 /* if we had services on this channel, we declare
375 this channels as "known good". add it.
377 (TODO: not yet implemented)
378 a NIT entry could have possible overridden
379 our frontend data with more exact data.
381 (TODO: not yet implemented)
382 the tuning process could have lead to more
383 exact data than the user entered.
385 The channel id was probably corrected
386 by the data written in the SDT. this is
387 important, as "initial transponder lists"
388 usually don't have valid CHIDs (and that's
391 These are the reasons for adding the transponder
392 here, and not before.
396 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
398 addKnownGoodChannel(m_chid_current, m_ch_current);
400 m_ch_scanned.push_back(m_ch_current);
404 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
408 m_ch_scanned.clear();
409 m_ch_unavailable.clear();
410 m_new_channels.clear();
411 m_new_services.clear();
412 m_last_service = m_new_services.end();
414 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
417 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
419 if (sameChannel(*i, *ii))
426 m_ch_toScan.push_back(*i);
432 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
434 if (m_flags & scanRemoveServices)
436 bool clearTerrestrial=false;
437 bool clearCable=false;
438 std::set<unsigned int> scanned_sat_positions;
440 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
441 for (;it != m_ch_scanned.end(); ++it)
444 (*it)->getSystem(system);
447 case iDVBFrontend::feSatellite:
449 eDVBFrontendParametersSatellite sat_parm;
450 (*it)->getDVBS(sat_parm);
451 scanned_sat_positions.insert(sat_parm.orbital_position);
454 case iDVBFrontend::feTerrestrial:
456 clearTerrestrial=true;
459 case iDVBFrontend::feCable:
467 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
470 (*it)->getSystem(system);
473 case iDVBFrontend::feSatellite:
475 eDVBFrontendParametersSatellite sat_parm;
476 (*it)->getDVBS(sat_parm);
477 scanned_sat_positions.insert(sat_parm.orbital_position);
480 case iDVBFrontend::feTerrestrial:
482 clearTerrestrial=true;
485 case iDVBFrontend::feCable:
493 if (clearTerrestrial)
496 chid.dvbnamespace=0xEEEE0000;
497 db->removeServices(chid);
502 chid.dvbnamespace=0xFFFF0000;
503 db->removeServices(chid);
505 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
508 if (m_flags & scanDontRemoveFeeds)
509 chid.dvbnamespace = eDVBNamespace((*x)<<16);
510 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
511 db->removeServices(chid, *x);
515 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
516 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
517 db->addChannelToList(ch->first, ch->second);
518 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
519 service(m_new_services.begin()); service != m_new_services.end(); ++service)
521 ePtr<eDVBService> dvb_service;
522 if (!db->getService(service->first, dvb_service))
524 if (dvb_service->m_flags & eDVBService::dxNoSDT)
526 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
528 dvb_service->m_service_name = service->second->m_service_name;
529 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
531 dvb_service->m_provider_name = service->second->m_provider_name;
532 if (service->second->m_ca.size())
533 dvb_service->m_ca = service->second->m_ca;
534 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
535 dvb_service->m_flags &= ~eDVBService::dxNewFound;
539 db->addService(service->first, service->second);
540 service->second->m_flags |= eDVBService::dxNewFound;
545 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
547 const ServiceDescriptionList &services = *sdt.getDescriptions();
548 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
549 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
551 /* save correct CHID for this channel if this is an ACTUAL_SDT */
552 if (sdt.getTableId() == TID_SDT_ACTUAL)
553 m_chid_current = chid;
555 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
557 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
559 eServiceReferenceDVB ref;
560 ePtr<eDVBService> service = new eDVBService;
563 ref.setServiceID((*s)->getServiceId());
565 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
566 desc != (*s)->getDescriptors()->end(); ++desc)
567 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
568 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
570 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
571 desc != (*s)->getDescriptors()->end(); ++desc)
573 switch ((*desc)->getTag())
575 case SERVICE_DESCRIPTOR:
577 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
578 service->m_service_name = convertDVBUTF8(d.getServiceName());
579 service->genSortName();
581 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
582 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
585 case CA_IDENTIFIER_DESCRIPTOR:
587 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
588 const CaSystemIdList &caids = *d.getCaSystemIds();
589 SCAN_eDebugNoNewLine("CA ");
590 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
592 SCAN_eDebugNoNewLine("%04x ", *i);
593 service->m_ca.push_front(*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;