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 & scanDontRemoveFeeds)
501 chid.dvbnamespace = eDVBNamespace((*x)<<16);
502 eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
503 db->removeServices(chid, *x);
507 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
508 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
509 db->addChannelToList(ch->first, ch->second);
510 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
511 service(m_new_services.begin()); service != m_new_services.end(); ++service)
513 ePtr<eDVBService> dvb_service;
514 if (!db->getService(service->first, dvb_service))
515 *dvb_service = *service->second;
517 db->addService(service->first, service->second);
521 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
523 const ServiceDescriptionList &services = *sdt.getDescriptions();
524 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
525 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
527 /* save correct CHID for this channel if this is an ACTUAL_SDT */
528 if (sdt.getTableId() == TID_SDT_ACTUAL)
529 m_chid_current = chid;
531 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
533 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
535 eServiceReferenceDVB ref;
536 ePtr<eDVBService> service = new eDVBService;
539 ref.setServiceID((*s)->getServiceId());
541 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
542 desc != (*s)->getDescriptors()->end(); ++desc)
543 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
544 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
546 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
547 desc != (*s)->getDescriptors()->end(); ++desc)
549 switch ((*desc)->getTag())
551 case SERVICE_DESCRIPTOR:
553 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
554 service->m_service_name = convertDVBUTF8(d.getServiceName());
555 service->genSortName();
557 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
558 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
561 case CA_IDENTIFIER_DESCRIPTOR:
563 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
564 const CaSystemIdList &caids = *d.getCaSystemIds();
565 SCAN_eDebugNoNewLine("CA ");
566 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
568 SCAN_eDebugNoNewLine("%04x ", *i);
569 service->m_ca.insert(*i);
575 SCAN_eDebug("descr<%x>", (*desc)->getTag());
580 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
584 m_last_service = i.first;
585 m_event(evtNewService);
591 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
593 connection = new eConnection(this, m_event.connect(event));
597 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
599 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
600 transponders_total = m_ch_toScan.size() + transponders_done;
601 services = m_new_services.size();
604 void eDVBScan::getLastServiceName(std::string &last_service_name)
606 if (m_last_service == m_new_services.end())
607 last_service_name = "";
609 last_service_name = m_last_service->second->m_service_name;