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_back(feparm);
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_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
382 void eDVBScan::insertInto(iDVBChannelList *db)
384 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
385 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
386 db->addChannelToList(ch->first, ch->second);
387 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
388 service(m_new_services.begin()); service != m_new_services.end(); ++service)
390 ePtr<eDVBService> dvb_service;
391 if (!db->getService(service->first, dvb_service))
392 *dvb_service = *service->second;
394 db->addService(service->first, service->second);
398 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
400 const ServiceDescriptionList &services = *sdt.getDescriptions();
401 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
402 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
404 /* save correct CHID for this channel if this is an ACTUAL_SDT */
405 if (sdt.getTableId() == TID_SDT_ACTUAL)
406 m_chid_current = chid;
408 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
410 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
412 eServiceReferenceDVB ref;
413 ePtr<eDVBService> service = new eDVBService;
416 ref.setServiceID((*s)->getServiceId());
418 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
419 desc != (*s)->getDescriptors()->end(); ++desc)
420 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
421 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
423 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
424 desc != (*s)->getDescriptors()->end(); ++desc)
426 switch ((*desc)->getTag())
428 case SERVICE_DESCRIPTOR:
430 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
431 service->m_service_name = convertDVBUTF8(d.getServiceName());
432 service->genSortName();
434 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
435 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
438 case CA_IDENTIFIER_DESCRIPTOR:
440 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
441 const CaSystemIdList &caids = *d.getCaSystemIds();
442 SCAN_eDebugNoNewLine("CA ");
443 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
445 SCAN_eDebugNoNewLine("%04x ", *i);
446 service->m_ca.insert(*i);
452 SCAN_eDebug("descr<%x>", (*desc)->getTag());
457 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
462 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
464 connection = new eConnection(this, m_event.connect(event));
468 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
470 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
471 transponders_total = m_ch_toScan.size() + transponders_done;
472 services = m_new_services.size();