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();
378 m_last_service = m_new_services.end();
380 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
383 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
385 if (sameChannel(*i, *ii))
392 m_ch_toScan.push_back(*i);
398 void eDVBScan::insertInto(iDVBChannelList *db)
400 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
401 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
402 db->addChannelToList(ch->first, ch->second);
403 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
404 service(m_new_services.begin()); service != m_new_services.end(); ++service)
406 ePtr<eDVBService> dvb_service;
407 if (!db->getService(service->first, dvb_service))
408 *dvb_service = *service->second;
410 db->addService(service->first, service->second);
414 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
416 const ServiceDescriptionList &services = *sdt.getDescriptions();
417 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
418 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
420 /* save correct CHID for this channel if this is an ACTUAL_SDT */
421 if (sdt.getTableId() == TID_SDT_ACTUAL)
422 m_chid_current = chid;
424 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
426 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
428 eServiceReferenceDVB ref;
429 ePtr<eDVBService> service = new eDVBService;
432 ref.setServiceID((*s)->getServiceId());
434 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
435 desc != (*s)->getDescriptors()->end(); ++desc)
436 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
437 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
439 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
440 desc != (*s)->getDescriptors()->end(); ++desc)
442 switch ((*desc)->getTag())
444 case SERVICE_DESCRIPTOR:
446 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
447 service->m_service_name = convertDVBUTF8(d.getServiceName());
448 service->genSortName();
450 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
451 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
454 case CA_IDENTIFIER_DESCRIPTOR:
456 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
457 const CaSystemIdList &caids = *d.getCaSystemIds();
458 SCAN_eDebugNoNewLine("CA ");
459 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
461 SCAN_eDebugNoNewLine("%04x ", *i);
462 service->m_ca.insert(*i);
468 SCAN_eDebug("descr<%x>", (*desc)->getTag());
473 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
477 m_last_service = i.first;
478 m_event(evtNewService);
484 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
486 connection = new eConnection(this, m_event.connect(event));
490 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
492 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
493 transponders_total = m_ch_toScan.size() + transponders_done;
494 services = m_new_services.size();
497 void eDVBScan::getLastServiceName(std::string &last_service_name)
499 if (m_last_service == m_new_services.end())
500 last_service_name = "";
502 last_service_name = m_last_service->second->m_service_name;