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);
287 /* ... in the list of channels to scan */
288 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
290 if (sameChannel(*i, feparm))
294 *i = feparm; // update
299 eDebug("remove dupe");
300 m_ch_toScan.erase(i++);
308 /* ... in the list of successfully scanned channels */
309 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
310 if (sameChannel(*i, feparm))
312 eDebug("successfully scanned");
316 /* ... in the list of unavailable channels */
317 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
318 if (sameChannel(*i, feparm, true))
320 eDebug("scanned but not available");
324 /* ... on the current channel */
325 if (sameChannel(m_ch_current, feparm))
327 eDebug("is current");
331 eDebug("really add");
332 /* otherwise, add it to the todo list. */
333 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
336 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
339 if (ch1->calculateDifference(ch2, diff, exact))
341 if (diff < 4000) // more than 4mhz difference?
346 void eDVBScan::channelDone()
348 if (m_ready & validSDT)
350 unsigned long hash = 0;
352 // m_ch_current is not set, when eDVBScan is just used for a SDT update
354 m_channel->getCurrentFrontendParameters(m_ch_current);
356 m_ch_current->getHash(hash);
358 eDVBNamespace dvbnamespace = buildNamespace(
359 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
360 (**m_SDT->getSections().begin()).getTransportStreamId(),
363 SCAN_eDebug("SDT: ");
364 std::vector<ServiceDescriptionSection*>::const_iterator i;
365 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
366 processSDT(dvbnamespace, **i);
367 m_ready &= ~validSDT;
370 if (m_ready & validNIT)
373 m_ch_current->getSystem(system);
374 SCAN_eDebug("dumping NIT");
375 if (m_flags & clearToScanOnFirstNIT)
378 m_flags &= ~clearToScanOnFirstNIT;
380 std::vector<NetworkInformationSection*>::const_iterator i;
381 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
383 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
385 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
386 tsinfo != tsinfovec.end(); ++tsinfo)
388 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
389 (*tsinfo)->getOriginalNetworkId());
391 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
392 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
394 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
395 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
397 switch ((*desc)->getTag())
399 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
401 if (system != iDVBFrontend::feCable)
402 break; // when current locked transponder is no cable transponder ignore this descriptor
403 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
404 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
405 eDVBFrontendParametersCable cable;
407 feparm->setDVBC(cable);
409 unsigned long hash=0;
410 feparm->getHash(hash);
411 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
414 eDVBChannelID(ns, tsid, onid),
418 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
420 if (system != iDVBFrontend::feTerrestrial)
421 break; // when current locked transponder is no terrestrial transponder ignore this descriptor
422 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
423 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
424 eDVBFrontendParametersTerrestrial terr;
426 feparm->setDVBT(terr);
428 unsigned long hash=0;
429 feparm->getHash(hash);
430 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
433 eDVBChannelID(ns, tsid, onid),
437 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
439 if (system != iDVBFrontend::feSatellite)
440 break; // when current locked transponder is no satellite transponder ignore this descriptor
442 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
443 if (d.getFrequency() < 10000)
446 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
447 eDVBFrontendParametersSatellite sat;
449 feparm->setDVBS(sat);
450 unsigned long hash=0;
451 feparm->getHash(hash);
453 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
455 if ( m_chid_current.dvbnamespace.get() != -1 &&
456 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
457 SCAN_eDebug("dropping this transponder, it's on another satellite.");
461 eDVBChannelID(ns, tsid, onid),
467 SCAN_eDebug("descr<%x>", (*desc)->getTag());
474 m_ready &= ~validNIT;
477 if ((m_ready & m_ready_all) != m_ready_all)
479 SCAN_eDebug("channel done!");
481 /* if we had services on this channel, we declare
482 this channels as "known good". add it.
484 (TODO: not yet implemented)
485 a NIT entry could have possible overridden
486 our frontend data with more exact data.
488 (TODO: not yet implemented)
489 the tuning process could have lead to more
490 exact data than the user entered.
492 The channel id was probably corrected
493 by the data written in the SDT. this is
494 important, as "initial transponder lists"
495 usually don't have valid CHIDs (and that's
498 These are the reasons for adding the transponder
499 here, and not before.
503 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
506 addKnownGoodChannel(m_chid_current, m_ch_current);
508 m_ch_scanned.push_back(m_ch_current);
510 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
512 if (sameChannel(*i, m_ch_current))
514 eDebug("remove dupe 2");
515 m_ch_toScan.erase(i++);
525 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
529 m_ch_scanned.clear();
530 m_ch_unavailable.clear();
531 m_new_channels.clear();
532 m_new_services.clear();
533 m_last_service = m_new_services.end();
535 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
538 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
540 if (sameChannel(*i, *ii, true))
547 m_ch_toScan.push_back(*i);
553 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
555 if (m_flags & scanRemoveServices)
557 bool clearTerrestrial=false;
558 bool clearCable=false;
559 std::set<unsigned int> scanned_sat_positions;
561 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
562 for (;it != m_ch_scanned.end(); ++it)
565 (*it)->getSystem(system);
568 case iDVBFrontend::feSatellite:
570 eDVBFrontendParametersSatellite sat_parm;
571 (*it)->getDVBS(sat_parm);
572 scanned_sat_positions.insert(sat_parm.orbital_position);
575 case iDVBFrontend::feTerrestrial:
577 clearTerrestrial=true;
580 case iDVBFrontend::feCable:
588 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
591 (*it)->getSystem(system);
594 case iDVBFrontend::feSatellite:
596 eDVBFrontendParametersSatellite sat_parm;
597 (*it)->getDVBS(sat_parm);
598 scanned_sat_positions.insert(sat_parm.orbital_position);
601 case iDVBFrontend::feTerrestrial:
603 clearTerrestrial=true;
606 case iDVBFrontend::feCable:
614 if (clearTerrestrial)
617 chid.dvbnamespace=0xEEEE0000;
618 db->removeServices(chid);
623 chid.dvbnamespace=0xFFFF0000;
624 db->removeServices(chid);
626 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
629 if (m_flags & scanDontRemoveFeeds)
630 chid.dvbnamespace = eDVBNamespace((*x)<<16);
631 // eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
632 db->removeServices(chid, *x);
636 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
637 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
638 db->addChannelToList(ch->first, ch->second);
639 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
640 service(m_new_services.begin()); service != m_new_services.end(); ++service)
642 ePtr<eDVBService> dvb_service;
643 if (!db->getService(service->first, dvb_service))
645 if (dvb_service->m_flags & eDVBService::dxNoSDT)
647 if (!(dvb_service->m_flags & eDVBService::dxHoldName))
649 dvb_service->m_service_name = service->second->m_service_name;
650 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
652 dvb_service->m_provider_name = service->second->m_provider_name;
653 if (service->second->m_ca.size())
654 dvb_service->m_ca = service->second->m_ca;
655 if (!dontRemoveOldFlags) // do not remove new found flags when not wished
656 dvb_service->m_flags &= ~eDVBService::dxNewFound;
660 db->addService(service->first, service->second);
661 service->second->m_flags |= eDVBService::dxNewFound;
666 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
668 const ServiceDescriptionList &services = *sdt.getDescriptions();
669 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
670 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
672 /* save correct CHID for this channel */
673 m_chid_current = chid;
675 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
677 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
679 eServiceReferenceDVB ref;
680 ePtr<eDVBService> service = new eDVBService;
683 ref.setServiceID((*s)->getServiceId());
685 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
686 desc != (*s)->getDescriptors()->end(); ++desc)
687 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
688 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
690 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
691 desc != (*s)->getDescriptors()->end(); ++desc)
693 switch ((*desc)->getTag())
695 case SERVICE_DESCRIPTOR:
697 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
698 service->m_service_name = convertDVBUTF8(d.getServiceName());
699 service->genSortName();
701 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
702 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
705 case CA_IDENTIFIER_DESCRIPTOR:
707 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
708 const CaSystemIdList &caids = *d.getCaSystemIds();
709 SCAN_eDebugNoNewLine("CA ");
710 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
712 SCAN_eDebugNoNewLine("%04x ", *i);
713 service->m_ca.push_front(*i);
719 SCAN_eDebug("descr<%x>", (*desc)->getTag());
724 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
728 m_last_service = i.first;
729 m_event(evtNewService);
735 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
737 connection = new eConnection(this, m_event.connect(event));
741 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
743 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
744 transponders_total = m_ch_toScan.size() + transponders_done;
745 services = m_new_services.size();
748 void eDVBScan::getLastServiceName(std::string &last_service_name)
750 if (m_last_service == m_new_services.end())
751 last_service_name = "";
753 last_service_name = m_last_service->second->m_service_name;