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();
107 m_chid_current = eDVBChannelID();
109 m_ch_toScan.pop_front();
111 if (m_channel->getFrontend(fe))
117 m_channel_state = iDVBChannel::state_idle;
118 if (fe->tune(*m_ch_current))
120 return nextChannel();
129 RESULT eDVBScan::startFilter()
133 /* only start required filters filter */
137 if (m_ready_all & readySDT)
139 m_SDT = new eTable<ServiceDescriptionSection>();
140 if (m_SDT->start(m_demux, eDVBSDTSpec()))
142 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
146 if (m_ready_all & readyNIT)
148 m_NIT = new eTable<NetworkInformationSection>();
149 if (m_NIT->start(m_demux, eDVBNITSpec()))
151 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
155 if (m_ready_all & readyBAT)
157 m_BAT = new eTable<BouquetAssociationSection>();
158 if (m_BAT->start(m_demux, eDVBBATSpec()))
160 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
166 void eDVBScan::SDTready(int err)
168 SCAN_eDebug("got sdt");
175 void eDVBScan::NITready(int err)
177 SCAN_eDebug("got nit, err %d", err);
184 void eDVBScan::BATready(int err)
186 SCAN_eDebug("got bat");
193 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
195 /* add it to the list of known channels. */
197 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
200 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
202 /* check if we don't already have that channel ... */
204 /* ... in the list of channels to scan */
205 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
206 if (sameChannel(*i, feparm))
209 /* ... in the list of successfully scanned channels */
210 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
211 if (sameChannel(*i, feparm))
214 /* ... in the list of unavailable channels */
215 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
216 if (sameChannel(*i, feparm))
219 /* ... on the current channel */
220 if (sameChannel(m_ch_current, feparm))
223 /* otherwise, add it to the todo list. */
224 m_ch_toScan.push_back(feparm);
227 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
230 if (ch1->calculateDifference(ch2, diff))
232 if (diff < 4000) // more than 4mhz difference?
237 void eDVBScan::channelDone()
239 if (m_ready & validSDT)
241 unsigned long hash = 0;
242 m_ch_current->getHash(hash);
244 eDVBNamespace dvbnamespace = buildNamespace(
245 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
246 (**m_SDT->getSections().begin()).getTransportStreamId(),
249 SCAN_eDebug("SDT: ");
250 std::vector<ServiceDescriptionSection*>::const_iterator i;
251 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
252 processSDT(dvbnamespace, **i);
253 m_ready &= ~validSDT;
256 if (m_ready & validNIT)
258 SCAN_eDebug("dumping NIT");
259 std::vector<NetworkInformationSection*>::const_iterator i;
260 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
262 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
264 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
265 tsinfo != tsinfovec.end(); ++tsinfo)
267 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
268 (*tsinfo)->getOriginalNetworkId());
270 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
271 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
273 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
274 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
276 switch ((*desc)->getTag())
278 // case SERVICE_LIST_DESCRIPTOR:
279 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
281 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
282 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
284 (d.getOrbitalPosition()>>12)&0xF,
285 (d.getOrbitalPosition()>>8)&0xF,
286 (d.getOrbitalPosition()>>4)&0xF,
287 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
288 d.getPolarization() ? "hor" : "vert",
289 d.getModulation(), d.getSymbolRate(), d.getFecInner());
291 /* some sanity checking: below 100MHz is invalid */
292 if (d.getFrequency() < 10000)
295 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
296 eDVBFrontendParametersSatellite sat;
298 feparm->setDVBS(sat);
299 unsigned long hash=0;
300 feparm->getHash(hash);
302 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
304 if (m_chid_current && ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
305 eDebug("dropping this transponder, it's on another satellite.");
309 eDVBChannelID(ns, tsid, onid),
315 SCAN_eDebug("descr<%x>", (*desc)->getTag());
322 m_ready &= ~validNIT;
325 if ((m_ready & m_ready_all) != m_ready_all)
327 SCAN_eDebug("channel done!");
329 /* if we had services on this channel, we declare
330 this channels as "known good". add it.
332 (TODO: not yet implemented)
333 a NIT entry could have possible overridden
334 our frontend data with more exact data.
336 (TODO: not yet implemented)
337 the tuning process could have lead to more
338 exact data than the user entered.
340 The channel id was probably corrected
341 by the data written in the SDT. this is
342 important, as "initial transponder lists"
343 usually don't have valid CHIDs (and that's
346 These are the reasons for adding the transponder
347 here, and not before.
351 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
353 addKnownGoodChannel(m_chid_current, m_ch_current);
355 m_ch_scanned.push_back(m_ch_current);
359 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
363 m_ch_scanned.clear();
364 m_ch_unavailable.clear();
365 m_new_channels.clear();
366 m_new_services.clear();
367 m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
371 void eDVBScan::insertInto(iDVBChannelList *db)
373 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
374 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
375 db->addChannelToList(ch->first, ch->second);
376 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
377 service(m_new_services.begin()); service != m_new_services.end(); ++service)
379 ePtr<eDVBService> dvb_service;
380 if (!db->getService(service->first, dvb_service))
381 *dvb_service = *service->second;
383 db->addService(service->first, service->second);
387 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
389 const ServiceDescriptionList &services = *sdt.getDescriptions();
390 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
391 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
393 /* save correct CHID for this channel if this is an ACTUAL_SDT */
394 if (sdt.getTableId() == TID_SDT_ACTUAL)
395 m_chid_current = chid;
397 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
399 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
401 eServiceReferenceDVB ref;
402 ePtr<eDVBService> service = new eDVBService;
405 ref.setServiceID((*s)->getServiceId());
407 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
408 desc != (*s)->getDescriptors()->end(); ++desc)
409 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
410 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
412 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
413 desc != (*s)->getDescriptors()->end(); ++desc)
415 switch ((*desc)->getTag())
417 case SERVICE_DESCRIPTOR:
419 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
420 service->m_service_name = convertDVBUTF8(d.getServiceName());
421 service->genSortName();
423 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
424 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
427 case CA_IDENTIFIER_DESCRIPTOR:
429 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
430 const CaSystemIdList &caids = *d.getCaSystemIds();
431 SCAN_eDebugNoNewLine("CA ");
432 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
434 SCAN_eDebugNoNewLine("%04x ", *i);
435 service->m_ca.insert(*i);
441 SCAN_eDebug("descr<%x>", (*desc)->getTag());
446 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
451 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
453 connection = new eConnection(this, m_event.connect(event));
457 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
459 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
460 transponders_total = m_ch_toScan.size() + transponders_done;
461 services = m_new_services.size();