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++/ca_identifier_descriptor.h>
9 #include <lib/dvb/specs.h>
10 #include <lib/dvb/esection.h>
11 #include <lib/dvb/scan.h>
12 #include <lib/dvb/frontend.h>
13 #include <lib/base/eerror.h>
14 #include <lib/base/estring.h>
17 #define SCAN_eDebug(x...) eDebug(x)
18 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
22 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
24 if (m_channel->getDemux(m_demux))
25 SCAN_eDebug("scan: failed to allocate demux!");
26 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
33 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
41 return orbital_position == 192;
43 return tsid != 0x00B0;
45 return abs(orbital_position-282) < 6;
47 return onid.get() < 0xFF00;
51 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
53 // on valid ONIDs, ignore frequency ("sub network") part
54 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
56 return eDVBNamespace(hash);
59 void eDVBScan::stateChange(iDVBChannel *ch)
62 if (ch->getState(state))
64 if (m_channel_state == state)
67 if (state == iDVBChannel::state_ok)
70 m_channel_state = state;
71 } else if (state == iDVBChannel::state_failed)
73 m_ch_unavailable.push_back(m_ch_current);
76 /* unavailable will timeout, anyway. */
79 RESULT eDVBScan::nextChannel()
81 ePtr<iDVBFrontend> fe;
83 m_SDT = 0; m_BAT = 0; m_NIT = 0;
87 /* check what we need */
88 m_ready_all = readySDT;
90 if (m_flags & scanNetworkSearch)
91 m_ready_all |= readyNIT;
93 if (m_flags & scanSearchBAT)
94 m_ready_all |= readyBAT;
96 if (m_ch_toScan.empty())
98 eDebug("no channels left to scan.");
99 eDebug("%d channels scanned, %d were unavailable.",
100 m_ch_scanned.size(), m_ch_unavailable.size());
101 eDebug("%d channels in database.", m_new_channels.size());
106 m_ch_current = m_ch_toScan.front();
108 m_ch_toScan.pop_front();
110 if (m_channel->getFrontend(fe))
117 fe->getFrontendType(fetype);
118 if ( fetype == iDVBFrontend::feSatellite)
120 eDVBFrontendParametersSatellite p;
121 m_ch_current->getDVBS(p);
122 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
125 m_chid_current = eDVBChannelID();
127 m_channel_state = iDVBChannel::state_idle;
128 if (fe->tune(*m_ch_current))
130 return nextChannel();
139 RESULT eDVBScan::startFilter()
143 /* only start required filters filter */
147 if (m_ready_all & readySDT)
149 m_SDT = new eTable<ServiceDescriptionSection>();
150 if (m_SDT->start(m_demux, eDVBSDTSpec()))
152 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
156 if (m_ready_all & readyNIT)
158 m_NIT = new eTable<NetworkInformationSection>();
159 if (m_NIT->start(m_demux, eDVBNITSpec()))
161 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
165 if (m_ready_all & readyBAT)
167 m_BAT = new eTable<BouquetAssociationSection>();
168 if (m_BAT->start(m_demux, eDVBBATSpec()))
170 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
176 void eDVBScan::SDTready(int err)
178 SCAN_eDebug("got sdt");
185 void eDVBScan::NITready(int err)
187 SCAN_eDebug("got nit, err %d", err);
194 void eDVBScan::BATready(int err)
196 SCAN_eDebug("got bat");
203 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
205 /* add it to the list of known channels. */
207 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
210 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
212 /* check if we don't already have that channel ... */
214 /* ... in the list of channels to scan */
215 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
216 if (sameChannel(*i, feparm))
219 /* ... in the list of successfully scanned channels */
220 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
221 if (sameChannel(*i, feparm))
224 /* ... in the list of unavailable channels */
225 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
226 if (sameChannel(*i, feparm))
229 /* ... on the current channel */
230 if (sameChannel(m_ch_current, feparm))
233 /* otherwise, add it to the todo list. */
234 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
237 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
240 if (ch1->calculateDifference(ch2, diff))
242 if (diff < 4000) // more than 4mhz difference?
247 void eDVBScan::channelDone()
249 if (m_ready & validSDT)
251 unsigned long hash = 0;
252 m_ch_current->getHash(hash);
254 eDVBNamespace dvbnamespace = buildNamespace(
255 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
256 (**m_SDT->getSections().begin()).getTransportStreamId(),
259 SCAN_eDebug("SDT: ");
260 std::vector<ServiceDescriptionSection*>::const_iterator i;
261 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
262 processSDT(dvbnamespace, **i);
263 m_ready &= ~validSDT;
266 if (m_ready & validNIT)
268 SCAN_eDebug("dumping NIT");
269 std::vector<NetworkInformationSection*>::const_iterator i;
270 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
272 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
274 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
275 tsinfo != tsinfovec.end(); ++tsinfo)
277 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
278 (*tsinfo)->getOriginalNetworkId());
280 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
281 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
283 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
284 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
286 switch ((*desc)->getTag())
288 // case SERVICE_LIST_DESCRIPTOR:
289 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
291 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
292 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
294 (d.getOrbitalPosition()>>12)&0xF,
295 (d.getOrbitalPosition()>>8)&0xF,
296 (d.getOrbitalPosition()>>4)&0xF,
297 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
298 d.getPolarization() ? "hor" : "vert",
299 d.getModulation(), d.getSymbolRate(), d.getFecInner());
301 /* some sanity checking: below 100MHz is invalid */
302 if (d.getFrequency() < 10000)
305 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
306 eDVBFrontendParametersSatellite sat;
308 feparm->setDVBS(sat);
309 unsigned long hash=0;
310 feparm->getHash(hash);
312 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
314 if ( m_chid_current.dvbnamespace.get() != -1 &&
315 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
316 eDebug("dropping this transponder, it's on another satellite.");
320 eDVBChannelID(ns, tsid, onid),
326 SCAN_eDebug("descr<%x>", (*desc)->getTag());
333 m_ready &= ~validNIT;
336 if ((m_ready & m_ready_all) != m_ready_all)
338 SCAN_eDebug("channel done!");
340 /* if we had services on this channel, we declare
341 this channels as "known good". add it.
343 (TODO: not yet implemented)
344 a NIT entry could have possible overridden
345 our frontend data with more exact data.
347 (TODO: not yet implemented)
348 the tuning process could have lead to more
349 exact data than the user entered.
351 The channel id was probably corrected
352 by the data written in the SDT. this is
353 important, as "initial transponder lists"
354 usually don't have valid CHIDs (and that's
357 These are the reasons for adding the transponder
358 here, and not before.
362 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
364 addKnownGoodChannel(m_chid_current, m_ch_current);
366 m_ch_scanned.push_back(m_ch_current);
370 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
374 m_ch_scanned.clear();
375 m_ch_unavailable.clear();
376 m_new_channels.clear();
377 m_new_services.clear();
379 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
382 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
384 if (sameChannel(*i, *ii))
391 m_ch_toScan.push_back(*i);
397 void eDVBScan::insertInto(iDVBChannelList *db)
399 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
400 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
401 db->addChannelToList(ch->first, ch->second);
402 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
403 service(m_new_services.begin()); service != m_new_services.end(); ++service)
405 ePtr<eDVBService> dvb_service;
406 if (!db->getService(service->first, dvb_service))
407 *dvb_service = *service->second;
409 db->addService(service->first, service->second);
413 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
415 const ServiceDescriptionList &services = *sdt.getDescriptions();
416 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
417 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
419 /* save correct CHID for this channel if this is an ACTUAL_SDT */
420 if (sdt.getTableId() == TID_SDT_ACTUAL)
421 m_chid_current = chid;
423 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
425 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
427 eServiceReferenceDVB ref;
428 ePtr<eDVBService> service = new eDVBService;
431 ref.setServiceID((*s)->getServiceId());
433 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
434 desc != (*s)->getDescriptors()->end(); ++desc)
435 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
436 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
438 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
439 desc != (*s)->getDescriptors()->end(); ++desc)
441 switch ((*desc)->getTag())
443 case SERVICE_DESCRIPTOR:
445 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
446 service->m_service_name = convertDVBUTF8(d.getServiceName());
447 service->genSortName();
449 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
450 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
453 case CA_IDENTIFIER_DESCRIPTOR:
455 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
456 const CaSystemIdList &caids = *d.getCaSystemIds();
457 SCAN_eDebugNoNewLine("CA ");
458 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
460 SCAN_eDebugNoNewLine("%04x ", *i);
461 service->m_ca.insert(*i);
467 SCAN_eDebug("descr<%x>", (*desc)->getTag());
472 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
477 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
479 connection = new eConnection(this, m_event.connect(event));
483 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
485 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
486 transponders_total = m_ch_toScan.size() + transponders_done;
487 services = m_new_services.size();