1 #include <lib/dvb/idvb.h>
2 #include <lib/dvb_si/sdt.h>
3 #include <lib/dvb_si/nit.h>
4 #include <lib/dvb_si/bat.h>
5 #include <lib/dvb_si/descriptor_tag.h>
6 #include <lib/dvb_si/service_descriptor.h>
7 #include <lib/dvb_si/satellite_delivery_system_descriptor.h>
8 #include <lib/dvb_si/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>
16 #define SCAN_eDebug(x...) eDebug(x)
17 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
21 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
23 if (m_channel->getDemux(m_demux))
24 SCAN_eDebug("scan: failed to allocate demux!");
25 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
32 int eDVBScan::isValidONIDTSID(eOriginalNetworkID onid, eTransportStreamID tsid)
43 return tsid != 0x00B0;
45 return tsid != 0x07E8;
51 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
53 // on valid ONIDs, ignore frequency ("sub network") part
54 if (isValidONIDTSID(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_unavailable)
73 m_ch_unavailable.push_back(m_ch_current);
78 RESULT eDVBScan::nextChannel()
80 ePtr<iDVBFrontend> fe;
82 m_SDT = 0; m_BAT = 0; m_NIT = 0;
85 if (m_ch_toScan.empty())
87 eDebug("no channels left to scan.");
88 eDebug("%d channels scanned, %d were unavailable.",
89 m_ch_scanned.size(), m_ch_unavailable.size());
90 eDebug("%d channels in database.", m_new_channels.size());
95 m_ch_current = m_ch_toScan.front();
96 m_chid_current = eDVBChannelID();
98 m_ch_toScan.pop_front();
100 if (m_channel->getFrontend(fe))
106 m_channel_state = iDVBChannel::state_idle;
107 if (fe->tune(*m_ch_current))
109 return nextChannel();
118 RESULT eDVBScan::startFilter()
122 m_SDT = new eTable<ServiceDescriptionTable>();
123 if (m_SDT->start(m_demux, eDVBSDTSpec()))
125 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
128 m_NIT = new eTable<NetworkInformationTable>();
129 if (m_NIT->start(m_demux, eDVBNITSpec()))
131 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
133 m_BAT = new eTable<BouquetAssociationTable>();
134 if (m_BAT->start(m_demux, eDVBBATSpec()))
136 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
141 void eDVBScan::SDTready(int err)
143 SCAN_eDebug("got sdt");
150 void eDVBScan::NITready(int err)
152 SCAN_eDebug("got nit, err %d", err);
159 void eDVBScan::BATready(int err)
161 SCAN_eDebug("got bat");
168 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
170 /* add it to the list of known channels. */
172 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
175 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
177 /* check if we don't already have that channel ... */
179 /* ... in the list of channels to scan */
180 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
181 if (sameChannel(*i, feparm))
184 /* ... in the list of successfully scanned channels */
185 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
186 if (sameChannel(*i, feparm))
189 /* ... in the list of unavailable channels */
190 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
191 if (sameChannel(*i, feparm))
194 /* ... on the current channel */
195 if (sameChannel(m_ch_current, feparm))
198 /* otherwise, add it to the todo list. */
199 m_ch_toScan.push_back(feparm);
202 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
205 if (ch1->calculateDifference(ch2, diff))
207 if (diff < 4000) // more than 4mhz difference?
212 void eDVBScan::channelDone()
214 if (m_ready & validSDT)
216 unsigned long hash = 0;
217 m_ch_current->getHash(hash);
219 eDVBNamespace dvbnamespace = buildNamespace(
220 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
221 (**m_SDT->getSections().begin()).getTransportStreamId(),
224 SCAN_eDebug("SDT: ");
225 ServiceDescriptionTableConstIterator i;
226 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
227 processSDT(dvbnamespace, **i);
228 m_ready &= ~validSDT;
231 if (m_ready & validNIT)
233 SCAN_eDebug("dumping NIT");
234 NetworkInformationTableConstIterator i;
235 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
237 const TransportStreamInfoVector &tsinfovec = *(*i)->getTsInfo();
239 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
240 tsinfo != tsinfovec.end(); ++tsinfo)
242 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
243 (*tsinfo)->getOriginalNetworkId());
245 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
246 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
248 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
249 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
251 switch ((*desc)->getTag())
253 // case SERVICE_LIST_DESCRIPTOR:
254 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
256 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
257 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
259 (d.getOrbitalPosition()>>12)&0xF,
260 (d.getOrbitalPosition()>>8)&0xF,
261 (d.getOrbitalPosition()>>4)&0xF,
262 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
263 d.getPolarization() ? "hor" : "vert",
264 d.getModulation(), d.getSymbolRate(), d.getFecInner());
266 /* some sanity checking: below 100MHz is invalid */
267 if (d.getFrequency() < 10000)
270 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
271 eDVBFrontendParametersSatellite sat;
273 feparm->setDVBS(sat);
274 unsigned long hash=0;
275 feparm->getHash(hash);
277 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
280 eDVBChannelID(ns, tsid, onid),
285 SCAN_eDebug("descr<%x>", (*desc)->getTag());
292 m_ready &= ~validNIT;
295 if ((m_ready & readyAll) != readyAll)
297 SCAN_eDebug("channel done!");
299 /* if we had services on this channel, we declare
300 this channels as "known good". add it.
302 (TODO: not yet implemented)
303 a NIT entry could have possible overridden
304 our frontend data with more exact data.
306 (TODO: not yet implemented)
307 the tuning process could have lead to more
308 exact data than the user entered.
310 The channel id was probably corrected
311 by the data written in the SDT. this is
312 important, as "initial transponder lists"
313 usually don't have valid CHIDs (and that's
316 These are the reasons for adding the transponder
317 here, and not before.
321 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
323 addKnownGoodChannel(m_chid_current, m_ch_current);
325 m_ch_scanned.push_back(m_ch_current);
329 void eDVBScan::start(const std::list<ePtr<iDVBFrontendParameters> > &known_transponders)
332 m_ch_scanned.clear();
333 m_ch_unavailable.clear();
334 m_new_channels.clear();
335 m_new_services.clear();
336 m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
340 void eDVBScan::insertInto(iDVBChannelList *db)
342 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
343 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
344 db->addChannelToList(ch->first, ch->second);
345 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
346 service(m_new_services.begin()); service != m_new_services.end(); ++service)
348 ePtr<eDVBService> dvb_service;
349 if (!db->getService(service->first, dvb_service))
350 *dvb_service = *service->second;
352 db->addService(service->first, service->second);
356 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionTable &sdt)
358 const ServiceDescriptionVector &services = *sdt.getDescriptions();
359 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
360 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
362 /* save correct CHID for this channel if this is an ACTUAL_SDT */
363 if (sdt.getTableId() == TID_SDT_ACTUAL)
364 m_chid_current = chid;
366 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
368 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
370 eServiceReferenceDVB ref;
371 ePtr<eDVBService> service = new eDVBService;
374 ref.setServiceID((*s)->getServiceId());
376 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
377 desc != (*s)->getDescriptors()->end(); ++desc)
378 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
379 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
381 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
382 desc != (*s)->getDescriptors()->end(); ++desc)
384 switch ((*desc)->getTag())
386 case SERVICE_DESCRIPTOR:
388 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
389 SCAN_eDebug("name '%s', provider_name '%s'", d.getServiceName().c_str(), d.getServiceProviderName().c_str());
390 service->m_service_name = d.getServiceName();
391 service->m_provider_name = d.getServiceProviderName();
394 case CA_IDENTIFIER_DESCRIPTOR:
396 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
397 const CaSystemIdVector &caids = *d.getCaSystemIds();
398 SCAN_eDebugNoNewLine("CA ");
399 for (CaSystemIdVector::const_iterator i(caids.begin()); i != caids.end(); ++i)
401 SCAN_eDebugNoNewLine("%04x ", *i);
402 service->m_ca.insert(*i);
408 SCAN_eDebug("descr<%x>", (*desc)->getTag());
413 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
418 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
420 connection = new eConnection(this, m_event.connect(event));
424 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
426 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
427 transponders_total = m_ch_toScan.size() + transponders_done;
428 services = m_new_services.size();