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 if (m_channel->getDemux(m_demux))
28 SCAN_eDebug("scan: failed to allocate demux!");
29 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
36 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
44 return orbital_position == 192;
46 return tsid != 0x00B0;
48 return abs(orbital_position-282) < 6;
50 return onid.get() < 0xFF00;
54 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
56 // on valid ONIDs, ignore frequency ("sub network") part
57 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
59 return eDVBNamespace(hash);
62 void eDVBScan::stateChange(iDVBChannel *ch)
65 if (ch->getState(state))
67 if (m_channel_state == state)
70 if (state == iDVBChannel::state_ok)
73 m_channel_state = state;
74 } else if (state == iDVBChannel::state_failed)
76 m_ch_unavailable.push_back(m_ch_current);
79 /* unavailable will timeout, anyway. */
82 RESULT eDVBScan::nextChannel()
84 ePtr<iDVBFrontend> fe;
86 m_SDT = 0; m_BAT = 0; m_NIT = 0;
90 /* check what we need */
91 m_ready_all = readySDT;
93 if (m_flags & scanNetworkSearch)
94 m_ready_all |= readyNIT;
96 if (m_flags & scanSearchBAT)
97 m_ready_all |= readyBAT;
99 if (m_ch_toScan.empty())
101 eDebug("no channels left to scan.");
102 eDebug("%d channels scanned, %d were unavailable.",
103 m_ch_scanned.size(), m_ch_unavailable.size());
104 eDebug("%d channels in database.", m_new_channels.size());
109 m_ch_current = m_ch_toScan.front();
111 m_ch_toScan.pop_front();
113 if (m_channel->getFrontend(fe))
120 fe->getFrontendType(fetype);
121 if ( fetype == iDVBFrontend::feSatellite)
123 eDVBFrontendParametersSatellite p;
124 m_ch_current->getDVBS(p);
125 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
128 m_chid_current = eDVBChannelID();
130 m_channel_state = iDVBChannel::state_idle;
131 if (fe->tune(*m_ch_current))
133 return nextChannel();
142 RESULT eDVBScan::startFilter()
146 /* only start required filters filter */
150 if (m_ready_all & readySDT)
152 m_SDT = new eTable<ServiceDescriptionSection>();
153 if (m_SDT->start(m_demux, eDVBSDTSpec()))
155 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
159 if (m_ready_all & readyNIT)
161 m_NIT = new eTable<NetworkInformationSection>();
162 if (m_NIT->start(m_demux, eDVBNITSpec()))
164 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
168 if (m_ready_all & readyBAT)
170 m_BAT = new eTable<BouquetAssociationSection>();
171 if (m_BAT->start(m_demux, eDVBBATSpec()))
173 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
179 void eDVBScan::SDTready(int err)
181 SCAN_eDebug("got sdt");
188 void eDVBScan::NITready(int err)
190 SCAN_eDebug("got nit, err %d", err);
197 void eDVBScan::BATready(int err)
199 SCAN_eDebug("got bat");
206 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
208 /* add it to the list of known channels. */
210 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
213 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
215 /* check if we don't already have that channel ... */
217 /* ... in the list of channels to scan */
218 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
219 if (sameChannel(*i, feparm))
222 /* ... in the list of successfully scanned channels */
223 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
224 if (sameChannel(*i, feparm))
227 /* ... in the list of unavailable channels */
228 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
229 if (sameChannel(*i, feparm))
232 /* ... on the current channel */
233 if (sameChannel(m_ch_current, feparm))
236 /* otherwise, add it to the todo list. */
237 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
240 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
243 if (ch1->calculateDifference(ch2, diff))
245 if (diff < 4000) // more than 4mhz difference?
250 void eDVBScan::channelDone()
252 if (m_ready & validSDT)
254 unsigned long hash = 0;
255 m_ch_current->getHash(hash);
257 eDVBNamespace dvbnamespace = buildNamespace(
258 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
259 (**m_SDT->getSections().begin()).getTransportStreamId(),
262 SCAN_eDebug("SDT: ");
263 std::vector<ServiceDescriptionSection*>::const_iterator i;
264 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
265 processSDT(dvbnamespace, **i);
266 m_ready &= ~validSDT;
269 if (m_ready & validNIT)
271 SCAN_eDebug("dumping NIT");
272 std::vector<NetworkInformationSection*>::const_iterator i;
273 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
275 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
277 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
278 tsinfo != tsinfovec.end(); ++tsinfo)
280 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
281 (*tsinfo)->getOriginalNetworkId());
283 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
284 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
286 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
287 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
289 switch ((*desc)->getTag())
291 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
293 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
294 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
295 eDVBFrontendParametersCable cable;
297 feparm->setDVBC(cable);
299 unsigned long hash=0;
300 feparm->getHash(hash);
301 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
304 eDVBChannelID(ns, tsid, onid),
308 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
310 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
311 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
312 eDVBFrontendParametersTerrestrial terr;
314 feparm->setDVBT(terr);
316 unsigned long hash=0;
317 feparm->getHash(hash);
318 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
321 eDVBChannelID(ns, tsid, onid),
325 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
327 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
328 if (d.getFrequency() < 10000)
331 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
332 eDVBFrontendParametersSatellite sat;
334 feparm->setDVBS(sat);
335 unsigned long hash=0;
336 feparm->getHash(hash);
338 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
340 if ( m_chid_current.dvbnamespace.get() != -1 &&
341 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
342 eDebug("dropping this transponder, it's on another satellite.");
346 eDVBChannelID(ns, tsid, onid),
352 SCAN_eDebug("descr<%x>", (*desc)->getTag());
359 m_ready &= ~validNIT;
362 if ((m_ready & m_ready_all) != m_ready_all)
364 SCAN_eDebug("channel done!");
366 /* if we had services on this channel, we declare
367 this channels as "known good". add it.
369 (TODO: not yet implemented)
370 a NIT entry could have possible overridden
371 our frontend data with more exact data.
373 (TODO: not yet implemented)
374 the tuning process could have lead to more
375 exact data than the user entered.
377 The channel id was probably corrected
378 by the data written in the SDT. this is
379 important, as "initial transponder lists"
380 usually don't have valid CHIDs (and that's
383 These are the reasons for adding the transponder
384 here, and not before.
388 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
390 addKnownGoodChannel(m_chid_current, m_ch_current);
392 m_ch_scanned.push_back(m_ch_current);
396 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
400 m_ch_scanned.clear();
401 m_ch_unavailable.clear();
402 m_new_channels.clear();
403 m_new_services.clear();
404 m_last_service = m_new_services.end();
406 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
409 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
411 if (sameChannel(*i, *ii))
418 m_ch_toScan.push_back(*i);
424 void eDVBScan::insertInto(iDVBChannelList *db)
426 if (m_flags & scanRemoveServices)
428 bool clearTerrestrial=false;
429 bool clearCable=false;
430 std::set<unsigned int> scanned_sat_positions;
432 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
433 for (;it != m_ch_scanned.end(); ++it)
436 (*it)->getSystem(system);
439 case iDVBFrontend::feSatellite:
441 eDVBFrontendParametersSatellite sat_parm;
442 (*it)->getDVBS(sat_parm);
443 scanned_sat_positions.insert(sat_parm.orbital_position);
446 case iDVBFrontend::feTerrestrial:
448 clearTerrestrial=true;
451 case iDVBFrontend::feCable:
459 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
462 (*it)->getSystem(system);
465 case iDVBFrontend::feSatellite:
467 eDVBFrontendParametersSatellite sat_parm;
468 (*it)->getDVBS(sat_parm);
469 scanned_sat_positions.insert(sat_parm.orbital_position);
472 case iDVBFrontend::feTerrestrial:
474 clearTerrestrial=true;
477 case iDVBFrontend::feCable:
485 if (clearTerrestrial)
488 chid.dvbnamespace=0xEEEE0000;
489 db->removeServices(chid);
494 chid.dvbnamespace=0xFFFF0000;
495 db->removeServices(chid);
497 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
500 if (m_flags & scanDontRemoveFeed)
501 chid.dvbnamespace = eDVBNamespace((*it)<<16));
502 db->removeServices(chid, *it);
506 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
507 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
508 db->addChannelToList(ch->first, ch->second);
509 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
510 service(m_new_services.begin()); service != m_new_services.end(); ++service)
512 ePtr<eDVBService> dvb_service;
513 if (!db->getService(service->first, dvb_service))
514 *dvb_service = *service->second;
516 db->addService(service->first, service->second);
520 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
522 const ServiceDescriptionList &services = *sdt.getDescriptions();
523 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
524 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
526 /* save correct CHID for this channel if this is an ACTUAL_SDT */
527 if (sdt.getTableId() == TID_SDT_ACTUAL)
528 m_chid_current = chid;
530 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
532 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
534 eServiceReferenceDVB ref;
535 ePtr<eDVBService> service = new eDVBService;
538 ref.setServiceID((*s)->getServiceId());
540 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
541 desc != (*s)->getDescriptors()->end(); ++desc)
542 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
543 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
545 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
546 desc != (*s)->getDescriptors()->end(); ++desc)
548 switch ((*desc)->getTag())
550 case SERVICE_DESCRIPTOR:
552 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
553 service->m_service_name = convertDVBUTF8(d.getServiceName());
554 service->genSortName();
556 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
557 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
560 case CA_IDENTIFIER_DESCRIPTOR:
562 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
563 const CaSystemIdList &caids = *d.getCaSystemIds();
564 SCAN_eDebugNoNewLine("CA ");
565 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
567 SCAN_eDebugNoNewLine("%04x ", *i);
568 service->m_ca.insert(*i);
574 SCAN_eDebug("descr<%x>", (*desc)->getTag());
579 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
583 m_last_service = i.first;
584 m_event(evtNewService);
590 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
592 connection = new eConnection(this, m_event.connect(event));
596 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
598 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
599 transponders_total = m_ch_toScan.size() + transponders_done;
600 services = m_new_services.size();
603 void eDVBScan::getLastServiceName(std::string &last_service_name)
605 if (m_last_service == m_new_services.end())
606 last_service_name = "";
608 last_service_name = m_last_service->second->m_service_name;