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): m_channel(channel)
27 m_ready = m_flags = 0;
28 m_ready_all = readySDT;
29 m_channel_state = iDVBChannel::state_idle;
31 if (m_channel->getDemux(m_demux))
32 SCAN_eDebug("scan: failed to allocate demux!");
33 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
40 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
48 return orbital_position == 192;
50 return tsid != 0x00B0;
52 return abs(orbital_position-282) < 6;
54 return onid.get() < 0xFF00;
58 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
60 // on valid ONIDs, ignore frequency ("sub network") part
61 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
63 return eDVBNamespace(hash);
66 void eDVBScan::stateChange(iDVBChannel *ch)
69 if (ch->getState(state))
71 if (m_channel_state == state)
74 if (state == iDVBChannel::state_ok)
77 m_channel_state = state;
78 } else if (state == iDVBChannel::state_failed)
80 m_ch_unavailable.push_back(m_ch_current);
83 /* unavailable will timeout, anyway. */
86 RESULT eDVBScan::nextChannel()
88 ePtr<iDVBFrontend> fe;
90 m_SDT = 0; m_BAT = 0; m_NIT = 0;
94 /* check what we need */
95 m_ready_all = readySDT;
97 if (m_flags & scanNetworkSearch)
98 m_ready_all |= readyNIT;
100 if (m_flags & scanSearchBAT)
101 m_ready_all |= readyBAT;
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()
150 /* only start required filters filter */
154 if (m_ready_all & readySDT)
156 m_SDT = new eTable<ServiceDescriptionSection>();
157 if (m_SDT->start(m_demux, eDVBSDTSpec()))
159 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
163 if (m_ready_all & readyNIT)
165 m_NIT = new eTable<NetworkInformationSection>();
166 if (m_NIT->start(m_demux, eDVBNITSpec()))
168 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
172 if (m_ready_all & readyBAT)
174 m_BAT = new eTable<BouquetAssociationSection>();
175 if (m_BAT->start(m_demux, eDVBBATSpec()))
177 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
183 void eDVBScan::SDTready(int err)
185 SCAN_eDebug("got sdt");
192 void eDVBScan::NITready(int err)
194 SCAN_eDebug("got nit, err %d", err);
201 void eDVBScan::BATready(int err)
203 SCAN_eDebug("got bat");
210 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
212 /* add it to the list of known channels. */
214 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
217 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
219 /* check if we don't already have that channel ... */
221 /* ... in the list of channels to scan */
222 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
223 if (sameChannel(*i, feparm))
226 /* ... in the list of successfully scanned channels */
227 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
228 if (sameChannel(*i, feparm))
231 /* ... in the list of unavailable channels */
232 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
233 if (sameChannel(*i, feparm))
236 /* ... on the current channel */
237 if (sameChannel(m_ch_current, feparm))
240 /* otherwise, add it to the todo list. */
241 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
244 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
247 if (ch1->calculateDifference(ch2, diff))
249 if (diff < 4000) // more than 4mhz difference?
254 void eDVBScan::channelDone()
256 if (m_ready & validSDT)
258 unsigned long hash = 0;
260 ePtr<iDVBFrontendParameters> p = m_ch_current;
262 if (!p) // used in sdt scan
263 m_channel->getCurrentFrontendParameters(p);
267 eDVBNamespace dvbnamespace = buildNamespace(
268 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
269 (**m_SDT->getSections().begin()).getTransportStreamId(),
272 SCAN_eDebug("SDT: ");
273 std::vector<ServiceDescriptionSection*>::const_iterator i;
274 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
275 processSDT(dvbnamespace, **i);
276 m_ready &= ~validSDT;
279 if (m_ready & validNIT)
281 SCAN_eDebug("dumping NIT");
282 std::vector<NetworkInformationSection*>::const_iterator i;
283 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
285 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
287 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
288 tsinfo != tsinfovec.end(); ++tsinfo)
290 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
291 (*tsinfo)->getOriginalNetworkId());
293 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
294 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
296 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
297 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
299 switch ((*desc)->getTag())
301 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
303 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
304 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
305 eDVBFrontendParametersCable cable;
307 feparm->setDVBC(cable);
309 unsigned long hash=0;
310 feparm->getHash(hash);
311 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
314 eDVBChannelID(ns, tsid, onid),
318 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
320 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
321 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
322 eDVBFrontendParametersTerrestrial terr;
324 feparm->setDVBT(terr);
326 unsigned long hash=0;
327 feparm->getHash(hash);
328 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
331 eDVBChannelID(ns, tsid, onid),
335 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
337 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
338 if (d.getFrequency() < 10000)
341 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
342 eDVBFrontendParametersSatellite sat;
344 feparm->setDVBS(sat);
345 unsigned long hash=0;
346 feparm->getHash(hash);
348 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
350 if ( m_chid_current.dvbnamespace.get() != -1 &&
351 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
352 SCAN_eDebug("dropping this transponder, it's on another satellite.");
356 eDVBChannelID(ns, tsid, onid),
362 SCAN_eDebug("descr<%x>", (*desc)->getTag());
369 m_ready &= ~validNIT;
372 if ((m_ready & m_ready_all) != m_ready_all)
374 SCAN_eDebug("channel done!");
376 /* if we had services on this channel, we declare
377 this channels as "known good". add it.
379 (TODO: not yet implemented)
380 a NIT entry could have possible overridden
381 our frontend data with more exact data.
383 (TODO: not yet implemented)
384 the tuning process could have lead to more
385 exact data than the user entered.
387 The channel id was probably corrected
388 by the data written in the SDT. this is
389 important, as "initial transponder lists"
390 usually don't have valid CHIDs (and that's
393 These are the reasons for adding the transponder
394 here, and not before.
397 ePtr<iDVBFrontendParameters> p = m_ch_current;
399 m_channel->getCurrentFrontendParameters(p);
402 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
404 addKnownGoodChannel(m_chid_current, p);
406 m_ch_scanned.push_back(p);
410 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
414 m_ch_scanned.clear();
415 m_ch_unavailable.clear();
416 m_new_channels.clear();
417 m_new_services.clear();
418 m_last_service = m_new_services.end();
420 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
423 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
425 if (sameChannel(*i, *ii))
432 m_ch_toScan.push_back(*i);
438 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
440 if (m_flags & scanRemoveServices)
442 bool clearTerrestrial=false;
443 bool clearCable=false;
444 std::set<unsigned int> scanned_sat_positions;
446 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
447 for (;it != m_ch_scanned.end(); ++it)
450 (*it)->getSystem(system);
453 case iDVBFrontend::feSatellite:
455 eDVBFrontendParametersSatellite sat_parm;
456 (*it)->getDVBS(sat_parm);
457 scanned_sat_positions.insert(sat_parm.orbital_position);
460 case iDVBFrontend::feTerrestrial:
462 clearTerrestrial=true;
465 case iDVBFrontend::feCable:
473 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
476 (*it)->getSystem(system);
479 case iDVBFrontend::feSatellite:
481 eDVBFrontendParametersSatellite sat_parm;
482 (*it)->getDVBS(sat_parm);
483 scanned_sat_positions.insert(sat_parm.orbital_position);
486 case iDVBFrontend::feTerrestrial:
488 clearTerrestrial=true;
491 case iDVBFrontend::feCable:
499 if (clearTerrestrial)
502 chid.dvbnamespace=0xEEEE0000;
503 db->removeServices(chid);
508 chid.dvbnamespace=0xFFFF0000;
509 db->removeServices(chid);
511 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
514 if (m_flags & scanDontRemoveFeeds)
515 chid.dvbnamespace = eDVBNamespace((*x)<<16);
516 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
517 db->removeServices(chid, *x);
521 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
522 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
523 db->addChannelToList(ch->first, ch->second);
524 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
525 service(m_new_services.begin()); service != m_new_services.end(); ++service)
527 ePtr<eDVBService> dvb_service;
528 if (!db->getService(service->first, dvb_service))
530 if (dvb_service->m_flags & eDVBService::dxNoSDT)
532 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
534 dvb_service->m_service_name = service->second->m_service_name;
535 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
537 dvb_service->m_provider_name = service->second->m_provider_name;
539 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
540 dvb_service->m_flags &= ~eDVBService::dxNewFound;
544 db->addService(service->first, service->second);
545 service->second->m_flags |= eDVBService::dxNewFound;
550 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
552 const ServiceDescriptionList &services = *sdt.getDescriptions();
553 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
554 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
556 /* save correct CHID for this channel if this is an ACTUAL_SDT */
557 if (sdt.getTableId() == TID_SDT_ACTUAL)
558 m_chid_current = chid;
560 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
562 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
564 eServiceReferenceDVB ref;
565 ePtr<eDVBService> service = new eDVBService;
568 ref.setServiceID((*s)->getServiceId());
570 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
571 desc != (*s)->getDescriptors()->end(); ++desc)
572 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
573 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
575 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
576 desc != (*s)->getDescriptors()->end(); ++desc)
578 switch ((*desc)->getTag())
580 case SERVICE_DESCRIPTOR:
582 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
583 service->m_service_name = convertDVBUTF8(d.getServiceName());
584 service->genSortName();
586 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
587 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
590 case CA_IDENTIFIER_DESCRIPTOR:
592 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
593 const CaSystemIdList &caids = *d.getCaSystemIds();
594 SCAN_eDebugNoNewLine("CA ");
595 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
597 SCAN_eDebugNoNewLine("%04x ", *i);
598 service->m_ca.insert(*i);
604 SCAN_eDebug("descr<%x>", (*desc)->getTag());
609 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
613 m_last_service = i.first;
614 m_event(evtNewService);
620 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
622 connection = new eConnection(this, m_event.connect(event));
626 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
628 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
629 transponders_total = m_ch_toScan.size() + transponders_done;
630 services = m_new_services.size();
633 void eDVBScan::getLastServiceName(std::string &last_service_name)
635 if (m_last_service == m_new_services.end())
636 last_service_name = "";
638 last_service_name = m_last_service->second->m_service_name;