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(eOriginalNetworkID onid, eTransportStreamID tsid)
44 return tsid != 0x00B0;
46 return tsid != 0x07E8;
52 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
54 // on valid ONIDs, ignore frequency ("sub network") part
55 if (isValidONIDTSID(onid, tsid))
57 return eDVBNamespace(hash);
60 void eDVBScan::stateChange(iDVBChannel *ch)
63 if (ch->getState(state))
65 if (m_channel_state == state)
68 if (state == iDVBChannel::state_ok)
71 m_channel_state = state;
72 } else if (state == iDVBChannel::state_failed)
74 m_ch_unavailable.push_back(m_ch_current);
77 /* unavailable will timeout, anyway. */
80 RESULT eDVBScan::nextChannel()
82 ePtr<iDVBFrontend> fe;
84 m_SDT = 0; m_BAT = 0; m_NIT = 0;
88 /* check what we need */
89 m_ready_all = readySDT;
91 if (m_flags & scanNetworkSearch)
92 m_ready_all |= readyNIT;
94 if (m_flags & scanSearchBAT)
95 m_ready_all |= readyBAT;
97 if (m_ch_toScan.empty())
99 eDebug("no channels left to scan.");
100 eDebug("%d channels scanned, %d were unavailable.",
101 m_ch_scanned.size(), m_ch_unavailable.size());
102 eDebug("%d channels in database.", m_new_channels.size());
107 m_ch_current = m_ch_toScan.front();
108 m_chid_current = eDVBChannelID();
110 m_ch_toScan.pop_front();
112 if (m_channel->getFrontend(fe))
118 m_channel_state = iDVBChannel::state_idle;
119 if (fe->tune(*m_ch_current))
121 return nextChannel();
130 RESULT eDVBScan::startFilter()
134 /* only start required filters filter */
138 if (m_ready_all & readySDT)
140 m_SDT = new eTable<ServiceDescriptionSection>();
141 if (m_SDT->start(m_demux, eDVBSDTSpec()))
143 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
147 if (m_ready_all & readyNIT)
149 m_NIT = new eTable<NetworkInformationSection>();
150 if (m_NIT->start(m_demux, eDVBNITSpec()))
152 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
156 if (m_ready_all & readyBAT)
158 m_BAT = new eTable<BouquetAssociationSection>();
159 if (m_BAT->start(m_demux, eDVBBATSpec()))
161 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
167 void eDVBScan::SDTready(int err)
169 SCAN_eDebug("got sdt");
176 void eDVBScan::NITready(int err)
178 SCAN_eDebug("got nit, err %d", err);
185 void eDVBScan::BATready(int err)
187 SCAN_eDebug("got bat");
194 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
196 /* add it to the list of known channels. */
198 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
201 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
203 /* check if we don't already have that channel ... */
205 /* ... in the list of channels to scan */
206 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
207 if (sameChannel(*i, feparm))
210 /* ... in the list of successfully scanned channels */
211 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
212 if (sameChannel(*i, feparm))
215 /* ... in the list of unavailable channels */
216 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
217 if (sameChannel(*i, feparm))
220 /* ... on the current channel */
221 if (sameChannel(m_ch_current, feparm))
224 /* otherwise, add it to the todo list. */
225 m_ch_toScan.push_back(feparm);
228 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
231 if (ch1->calculateDifference(ch2, diff))
233 if (diff < 4000) // more than 4mhz difference?
238 void eDVBScan::channelDone()
240 if (m_ready & validSDT)
242 unsigned long hash = 0;
243 m_ch_current->getHash(hash);
245 eDVBNamespace dvbnamespace = buildNamespace(
246 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
247 (**m_SDT->getSections().begin()).getTransportStreamId(),
250 SCAN_eDebug("SDT: ");
251 std::vector<ServiceDescriptionSection*>::const_iterator i;
252 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
253 processSDT(dvbnamespace, **i);
254 m_ready &= ~validSDT;
257 if (m_ready & validNIT)
259 SCAN_eDebug("dumping NIT");
260 std::vector<NetworkInformationSection*>::const_iterator i;
261 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
263 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
265 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
266 tsinfo != tsinfovec.end(); ++tsinfo)
268 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
269 (*tsinfo)->getOriginalNetworkId());
271 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
272 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
274 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
275 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
277 switch ((*desc)->getTag())
279 // case SERVICE_LIST_DESCRIPTOR:
280 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
282 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
283 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
285 (d.getOrbitalPosition()>>12)&0xF,
286 (d.getOrbitalPosition()>>8)&0xF,
287 (d.getOrbitalPosition()>>4)&0xF,
288 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
289 d.getPolarization() ? "hor" : "vert",
290 d.getModulation(), d.getSymbolRate(), d.getFecInner());
292 /* some sanity checking: below 100MHz is invalid */
293 if (d.getFrequency() < 10000)
296 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
297 eDVBFrontendParametersSatellite sat;
299 feparm->setDVBS(sat);
300 unsigned long hash=0;
301 feparm->getHash(hash);
303 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
305 if (m_chid_current && ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
306 eDebug("dropping this transponder, it's on another satellite.");
310 eDVBChannelID(ns, tsid, onid),
316 SCAN_eDebug("descr<%x>", (*desc)->getTag());
323 m_ready &= ~validNIT;
326 if ((m_ready & m_ready_all) != m_ready_all)
328 SCAN_eDebug("channel done!");
330 /* if we had services on this channel, we declare
331 this channels as "known good". add it.
333 (TODO: not yet implemented)
334 a NIT entry could have possible overridden
335 our frontend data with more exact data.
337 (TODO: not yet implemented)
338 the tuning process could have lead to more
339 exact data than the user entered.
341 The channel id was probably corrected
342 by the data written in the SDT. this is
343 important, as "initial transponder lists"
344 usually don't have valid CHIDs (and that's
347 These are the reasons for adding the transponder
348 here, and not before.
352 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
354 addKnownGoodChannel(m_chid_current, m_ch_current);
356 m_ch_scanned.push_back(m_ch_current);
360 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
364 m_ch_scanned.clear();
365 m_ch_unavailable.clear();
366 m_new_channels.clear();
367 m_new_services.clear();
368 m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
372 void eDVBScan::insertInto(iDVBChannelList *db)
374 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
375 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
376 db->addChannelToList(ch->first, ch->second);
377 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
378 service(m_new_services.begin()); service != m_new_services.end(); ++service)
380 ePtr<eDVBService> dvb_service;
381 if (!db->getService(service->first, dvb_service))
382 *dvb_service = *service->second;
384 db->addService(service->first, service->second);
388 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
390 const ServiceDescriptionList &services = *sdt.getDescriptions();
391 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
392 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
394 /* save correct CHID for this channel if this is an ACTUAL_SDT */
395 if (sdt.getTableId() == TID_SDT_ACTUAL)
396 m_chid_current = chid;
398 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
400 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
402 eServiceReferenceDVB ref;
403 ePtr<eDVBService> service = new eDVBService;
406 ref.setServiceID((*s)->getServiceId());
408 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
409 desc != (*s)->getDescriptors()->end(); ++desc)
410 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
411 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
413 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
414 desc != (*s)->getDescriptors()->end(); ++desc)
416 switch ((*desc)->getTag())
418 case SERVICE_DESCRIPTOR:
420 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
421 service->m_service_name = convertDVBUTF8(d.getServiceName());
422 service->genSortName();
424 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
425 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
428 case CA_IDENTIFIER_DESCRIPTOR:
430 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
431 const CaSystemIdList &caids = *d.getCaSystemIds();
432 SCAN_eDebugNoNewLine("CA ");
433 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
435 SCAN_eDebugNoNewLine("%04x ", *i);
436 service->m_ca.insert(*i);
442 SCAN_eDebug("descr<%x>", (*desc)->getTag());
447 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
452 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
454 connection = new eConnection(this, m_event.connect(event));
458 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
460 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
461 transponders_total = m_ch_toScan.size() + transponders_done;
462 services = m_new_services.size();