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)
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 ... */
254 /* ... in the list of channels to scan */
255 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
256 if (sameChannel(*i, feparm))
259 /* ... in the list of successfully scanned channels */
260 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
261 if (sameChannel(*i, feparm))
264 /* ... in the list of unavailable channels */
265 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
266 if (sameChannel(*i, feparm))
269 /* ... on the current channel */
270 if (sameChannel(m_ch_current, feparm))
273 /* otherwise, add it to the todo list. */
274 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
277 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
280 if (ch1->calculateDifference(ch2, diff))
282 if (diff < 4000) // more than 4mhz difference?
287 void eDVBScan::channelDone()
289 if (m_ready & validSDT)
291 unsigned long hash = 0;
293 // m_ch_current is not set, when eDVBScan is just used for a SDT update
295 m_channel->getCurrentFrontendParameters(m_ch_current);
297 m_ch_current->getHash(hash);
299 eDVBNamespace dvbnamespace = buildNamespace(
300 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
301 (**m_SDT->getSections().begin()).getTransportStreamId(),
304 SCAN_eDebug("SDT: ");
305 std::vector<ServiceDescriptionSection*>::const_iterator i;
306 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
307 processSDT(dvbnamespace, **i);
308 m_ready &= ~validSDT;
311 if (m_ready & validNIT)
313 SCAN_eDebug("dumping NIT");
314 std::vector<NetworkInformationSection*>::const_iterator i;
315 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
317 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
319 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
320 tsinfo != tsinfovec.end(); ++tsinfo)
322 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
323 (*tsinfo)->getOriginalNetworkId());
325 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
326 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
328 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
329 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
331 switch ((*desc)->getTag())
333 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
335 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
336 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
337 eDVBFrontendParametersCable cable;
339 feparm->setDVBC(cable);
341 unsigned long hash=0;
342 feparm->getHash(hash);
343 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
346 eDVBChannelID(ns, tsid, onid),
350 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
352 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
353 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
354 eDVBFrontendParametersTerrestrial terr;
356 feparm->setDVBT(terr);
358 unsigned long hash=0;
359 feparm->getHash(hash);
360 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
363 eDVBChannelID(ns, tsid, onid),
367 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
369 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
370 if (d.getFrequency() < 10000)
373 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
374 eDVBFrontendParametersSatellite sat;
376 feparm->setDVBS(sat);
377 unsigned long hash=0;
378 feparm->getHash(hash);
380 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
382 if ( m_chid_current.dvbnamespace.get() != -1 &&
383 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
384 SCAN_eDebug("dropping this transponder, it's on another satellite.");
388 eDVBChannelID(ns, tsid, onid),
394 SCAN_eDebug("descr<%x>", (*desc)->getTag());
401 m_ready &= ~validNIT;
404 if ((m_ready & m_ready_all) != m_ready_all)
406 SCAN_eDebug("channel done!");
408 /* if we had services on this channel, we declare
409 this channels as "known good". add it.
411 (TODO: not yet implemented)
412 a NIT entry could have possible overridden
413 our frontend data with more exact data.
415 (TODO: not yet implemented)
416 the tuning process could have lead to more
417 exact data than the user entered.
419 The channel id was probably corrected
420 by the data written in the SDT. this is
421 important, as "initial transponder lists"
422 usually don't have valid CHIDs (and that's
425 These are the reasons for adding the transponder
426 here, and not before.
430 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
432 addKnownGoodChannel(m_chid_current, m_ch_current);
434 m_ch_scanned.push_back(m_ch_current);
438 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
442 m_ch_scanned.clear();
443 m_ch_unavailable.clear();
444 m_new_channels.clear();
445 m_new_services.clear();
446 m_last_service = m_new_services.end();
448 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
451 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
453 if (sameChannel(*i, *ii))
460 m_ch_toScan.push_back(*i);
466 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
468 if (m_flags & scanRemoveServices)
470 bool clearTerrestrial=false;
471 bool clearCable=false;
472 std::set<unsigned int> scanned_sat_positions;
474 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
475 for (;it != m_ch_scanned.end(); ++it)
478 (*it)->getSystem(system);
481 case iDVBFrontend::feSatellite:
483 eDVBFrontendParametersSatellite sat_parm;
484 (*it)->getDVBS(sat_parm);
485 scanned_sat_positions.insert(sat_parm.orbital_position);
488 case iDVBFrontend::feTerrestrial:
490 clearTerrestrial=true;
493 case iDVBFrontend::feCable:
501 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
504 (*it)->getSystem(system);
507 case iDVBFrontend::feSatellite:
509 eDVBFrontendParametersSatellite sat_parm;
510 (*it)->getDVBS(sat_parm);
511 scanned_sat_positions.insert(sat_parm.orbital_position);
514 case iDVBFrontend::feTerrestrial:
516 clearTerrestrial=true;
519 case iDVBFrontend::feCable:
527 if (clearTerrestrial)
530 chid.dvbnamespace=0xEEEE0000;
531 db->removeServices(chid);
536 chid.dvbnamespace=0xFFFF0000;
537 db->removeServices(chid);
539 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
542 if (m_flags & scanDontRemoveFeeds)
543 chid.dvbnamespace = eDVBNamespace((*x)<<16);
544 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
545 db->removeServices(chid, *x);
549 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
550 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
551 db->addChannelToList(ch->first, ch->second);
552 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
553 service(m_new_services.begin()); service != m_new_services.end(); ++service)
555 ePtr<eDVBService> dvb_service;
556 if (!db->getService(service->first, dvb_service))
558 if (dvb_service->m_flags & eDVBService::dxNoSDT)
560 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
562 dvb_service->m_service_name = service->second->m_service_name;
563 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
565 dvb_service->m_provider_name = service->second->m_provider_name;
566 if (service->second->m_ca.size())
567 dvb_service->m_ca = service->second->m_ca;
568 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
569 dvb_service->m_flags &= ~eDVBService::dxNewFound;
573 db->addService(service->first, service->second);
574 service->second->m_flags |= eDVBService::dxNewFound;
579 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
581 const ServiceDescriptionList &services = *sdt.getDescriptions();
582 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
583 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
585 /* save correct CHID for this channel */
586 m_chid_current = chid;
588 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
590 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
592 eServiceReferenceDVB ref;
593 ePtr<eDVBService> service = new eDVBService;
596 ref.setServiceID((*s)->getServiceId());
598 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
599 desc != (*s)->getDescriptors()->end(); ++desc)
600 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
601 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
603 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
604 desc != (*s)->getDescriptors()->end(); ++desc)
606 switch ((*desc)->getTag())
608 case SERVICE_DESCRIPTOR:
610 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
611 service->m_service_name = convertDVBUTF8(d.getServiceName());
612 service->genSortName();
614 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
615 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
618 case CA_IDENTIFIER_DESCRIPTOR:
620 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
621 const CaSystemIdList &caids = *d.getCaSystemIds();
622 SCAN_eDebugNoNewLine("CA ");
623 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
625 SCAN_eDebugNoNewLine("%04x ", *i);
626 service->m_ca.push_front(*i);
632 SCAN_eDebug("descr<%x>", (*desc)->getTag());
637 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
641 m_last_service = i.first;
642 m_event(evtNewService);
648 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
650 connection = new eConnection(this, m_event.connect(event));
654 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
656 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
657 transponders_total = m_ch_toScan.size() + transponders_done;
658 services = m_new_services.size();
661 void eDVBScan::getLastServiceName(std::string &last_service_name)
663 if (m_last_service == m_new_services.end())
664 last_service_name = "";
666 last_service_name = m_last_service->second->m_service_name;