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_unavailable)
74 m_ch_unavailable.push_back(m_ch_current);
79 RESULT eDVBScan::nextChannel()
81 ePtr<iDVBFrontend> fe;
83 m_SDT = 0; m_BAT = 0; m_NIT = 0;
86 if (m_ch_toScan.empty())
88 eDebug("no channels left to scan.");
89 eDebug("%d channels scanned, %d were unavailable.",
90 m_ch_scanned.size(), m_ch_unavailable.size());
91 eDebug("%d channels in database.", m_new_channels.size());
96 m_ch_current = m_ch_toScan.front();
97 m_chid_current = eDVBChannelID();
99 m_ch_toScan.pop_front();
101 if (m_channel->getFrontend(fe))
107 m_channel_state = iDVBChannel::state_idle;
108 if (fe->tune(*m_ch_current))
110 return nextChannel();
119 RESULT eDVBScan::startFilter()
123 m_SDT = new eTable<ServiceDescriptionSection>();
124 if (m_SDT->start(m_demux, eDVBSDTSpec()))
126 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
129 m_NIT = new eTable<NetworkInformationSection>();
130 if (m_NIT->start(m_demux, eDVBNITSpec()))
132 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
134 m_BAT = new eTable<BouquetAssociationSection>();
135 if (m_BAT->start(m_demux, eDVBBATSpec()))
137 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
142 void eDVBScan::SDTready(int err)
144 SCAN_eDebug("got sdt");
151 void eDVBScan::NITready(int err)
153 SCAN_eDebug("got nit, err %d", err);
160 void eDVBScan::BATready(int err)
162 SCAN_eDebug("got bat");
169 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
171 /* add it to the list of known channels. */
173 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
176 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
178 /* check if we don't already have that channel ... */
180 /* ... in the list of channels to scan */
181 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
182 if (sameChannel(*i, feparm))
185 /* ... in the list of successfully scanned channels */
186 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
187 if (sameChannel(*i, feparm))
190 /* ... in the list of unavailable channels */
191 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
192 if (sameChannel(*i, feparm))
195 /* ... on the current channel */
196 if (sameChannel(m_ch_current, feparm))
199 /* otherwise, add it to the todo list. */
200 m_ch_toScan.push_back(feparm);
203 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
206 if (ch1->calculateDifference(ch2, diff))
208 if (diff < 4000) // more than 4mhz difference?
213 void eDVBScan::channelDone()
215 if (m_ready & validSDT)
217 unsigned long hash = 0;
218 m_ch_current->getHash(hash);
220 eDVBNamespace dvbnamespace = buildNamespace(
221 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
222 (**m_SDT->getSections().begin()).getTransportStreamId(),
225 SCAN_eDebug("SDT: ");
226 std::vector<ServiceDescriptionSection*>::const_iterator i;
227 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
228 processSDT(dvbnamespace, **i);
229 m_ready &= ~validSDT;
232 if (m_ready & validNIT)
234 SCAN_eDebug("dumping NIT");
235 std::vector<NetworkInformationSection*>::const_iterator i;
236 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
238 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
240 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
241 tsinfo != tsinfovec.end(); ++tsinfo)
243 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
244 (*tsinfo)->getOriginalNetworkId());
246 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
247 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
249 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
250 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
252 switch ((*desc)->getTag())
254 // case SERVICE_LIST_DESCRIPTOR:
255 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
257 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
258 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
260 (d.getOrbitalPosition()>>12)&0xF,
261 (d.getOrbitalPosition()>>8)&0xF,
262 (d.getOrbitalPosition()>>4)&0xF,
263 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
264 d.getPolarization() ? "hor" : "vert",
265 d.getModulation(), d.getSymbolRate(), d.getFecInner());
267 /* some sanity checking: below 100MHz is invalid */
268 if (d.getFrequency() < 10000)
271 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
272 eDVBFrontendParametersSatellite sat;
274 feparm->setDVBS(sat);
275 unsigned long hash=0;
276 feparm->getHash(hash);
278 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
281 eDVBChannelID(ns, tsid, onid),
286 SCAN_eDebug("descr<%x>", (*desc)->getTag());
293 m_ready &= ~validNIT;
296 if ((m_ready & readyAll) != readyAll)
298 SCAN_eDebug("channel done!");
300 /* if we had services on this channel, we declare
301 this channels as "known good". add it.
303 (TODO: not yet implemented)
304 a NIT entry could have possible overridden
305 our frontend data with more exact data.
307 (TODO: not yet implemented)
308 the tuning process could have lead to more
309 exact data than the user entered.
311 The channel id was probably corrected
312 by the data written in the SDT. this is
313 important, as "initial transponder lists"
314 usually don't have valid CHIDs (and that's
317 These are the reasons for adding the transponder
318 here, and not before.
322 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
324 addKnownGoodChannel(m_chid_current, m_ch_current);
326 m_ch_scanned.push_back(m_ch_current);
330 void eDVBScan::start(const std::list<ePtr<iDVBFrontendParameters> > &known_transponders)
333 m_ch_scanned.clear();
334 m_ch_unavailable.clear();
335 m_new_channels.clear();
336 m_new_services.clear();
337 m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
341 void eDVBScan::insertInto(iDVBChannelList *db)
343 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
344 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
345 db->addChannelToList(ch->first, ch->second);
346 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
347 service(m_new_services.begin()); service != m_new_services.end(); ++service)
349 ePtr<eDVBService> dvb_service;
350 if (!db->getService(service->first, dvb_service))
351 *dvb_service = *service->second;
353 db->addService(service->first, service->second);
357 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
359 const ServiceDescriptionList &services = *sdt.getDescriptions();
360 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
361 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
363 /* save correct CHID for this channel if this is an ACTUAL_SDT */
364 if (sdt.getTableId() == TID_SDT_ACTUAL)
365 m_chid_current = chid;
367 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
369 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
371 eServiceReferenceDVB ref;
372 ePtr<eDVBService> service = new eDVBService;
375 ref.setServiceID((*s)->getServiceId());
377 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
378 desc != (*s)->getDescriptors()->end(); ++desc)
379 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
380 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
382 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
383 desc != (*s)->getDescriptors()->end(); ++desc)
385 switch ((*desc)->getTag())
387 case SERVICE_DESCRIPTOR:
389 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
390 service->m_service_name = convertDVBUTF8(d.getServiceName());
391 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
392 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
395 case CA_IDENTIFIER_DESCRIPTOR:
397 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
398 const CaSystemIdList &caids = *d.getCaSystemIds();
399 SCAN_eDebugNoNewLine("CA ");
400 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
402 SCAN_eDebugNoNewLine("%04x ", *i);
403 service->m_ca.insert(*i);
409 SCAN_eDebug("descr<%x>", (*desc)->getTag());
414 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
419 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
421 connection = new eConnection(this, m_event.connect(event));
425 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
427 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
428 transponders_total = m_ch_toScan.size() + transponders_done;
429 services = m_new_services.size();