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_failed)
74 m_ch_unavailable.push_back(m_ch_current);
77 /* unavailable will timeout, anyway. */
80 RESULT eDVBScan::nextChannel()
82 ePtr<iDVBFrontend> fe;
84 m_SDT = 0; m_BAT = 0; m_NIT = 0;
87 if (m_ch_toScan.empty())
89 eDebug("no channels left to scan.");
90 eDebug("%d channels scanned, %d were unavailable.",
91 m_ch_scanned.size(), m_ch_unavailable.size());
92 eDebug("%d channels in database.", m_new_channels.size());
97 m_ch_current = m_ch_toScan.front();
98 m_chid_current = eDVBChannelID();
100 m_ch_toScan.pop_front();
102 if (m_channel->getFrontend(fe))
108 m_channel_state = iDVBChannel::state_idle;
109 if (fe->tune(*m_ch_current))
111 return nextChannel();
120 RESULT eDVBScan::startFilter()
124 m_SDT = new eTable<ServiceDescriptionSection>();
125 if (m_SDT->start(m_demux, eDVBSDTSpec()))
127 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
130 m_NIT = new eTable<NetworkInformationSection>();
131 if (m_NIT->start(m_demux, eDVBNITSpec()))
133 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
135 m_BAT = new eTable<BouquetAssociationSection>();
136 if (m_BAT->start(m_demux, eDVBBATSpec()))
138 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
143 void eDVBScan::SDTready(int err)
145 SCAN_eDebug("got sdt");
152 void eDVBScan::NITready(int err)
154 SCAN_eDebug("got nit, err %d", err);
161 void eDVBScan::BATready(int err)
163 SCAN_eDebug("got bat");
170 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
172 /* add it to the list of known channels. */
174 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
177 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
179 /* check if we don't already have that channel ... */
181 /* ... in the list of channels to scan */
182 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
183 if (sameChannel(*i, feparm))
186 /* ... in the list of successfully scanned channels */
187 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
188 if (sameChannel(*i, feparm))
191 /* ... in the list of unavailable channels */
192 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
193 if (sameChannel(*i, feparm))
196 /* ... on the current channel */
197 if (sameChannel(m_ch_current, feparm))
200 /* otherwise, add it to the todo list. */
201 m_ch_toScan.push_back(feparm);
204 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
207 if (ch1->calculateDifference(ch2, diff))
209 if (diff < 4000) // more than 4mhz difference?
214 void eDVBScan::channelDone()
216 if (m_ready & validSDT)
218 unsigned long hash = 0;
219 m_ch_current->getHash(hash);
221 eDVBNamespace dvbnamespace = buildNamespace(
222 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
223 (**m_SDT->getSections().begin()).getTransportStreamId(),
226 SCAN_eDebug("SDT: ");
227 std::vector<ServiceDescriptionSection*>::const_iterator i;
228 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
229 processSDT(dvbnamespace, **i);
230 m_ready &= ~validSDT;
233 if (m_ready & validNIT)
235 SCAN_eDebug("dumping NIT");
236 std::vector<NetworkInformationSection*>::const_iterator i;
237 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
239 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
241 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
242 tsinfo != tsinfovec.end(); ++tsinfo)
244 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
245 (*tsinfo)->getOriginalNetworkId());
247 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
248 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
250 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
251 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
253 switch ((*desc)->getTag())
255 // case SERVICE_LIST_DESCRIPTOR:
256 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
258 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
259 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
261 (d.getOrbitalPosition()>>12)&0xF,
262 (d.getOrbitalPosition()>>8)&0xF,
263 (d.getOrbitalPosition()>>4)&0xF,
264 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
265 d.getPolarization() ? "hor" : "vert",
266 d.getModulation(), d.getSymbolRate(), d.getFecInner());
268 /* some sanity checking: below 100MHz is invalid */
269 if (d.getFrequency() < 10000)
272 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
273 eDVBFrontendParametersSatellite sat;
275 feparm->setDVBS(sat);
276 unsigned long hash=0;
277 feparm->getHash(hash);
279 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
282 eDVBChannelID(ns, tsid, onid),
287 SCAN_eDebug("descr<%x>", (*desc)->getTag());
294 m_ready &= ~validNIT;
297 if ((m_ready & readyAll) != readyAll)
299 SCAN_eDebug("channel done!");
301 /* if we had services on this channel, we declare
302 this channels as "known good". add it.
304 (TODO: not yet implemented)
305 a NIT entry could have possible overridden
306 our frontend data with more exact data.
308 (TODO: not yet implemented)
309 the tuning process could have lead to more
310 exact data than the user entered.
312 The channel id was probably corrected
313 by the data written in the SDT. this is
314 important, as "initial transponder lists"
315 usually don't have valid CHIDs (and that's
318 These are the reasons for adding the transponder
319 here, and not before.
323 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
325 addKnownGoodChannel(m_chid_current, m_ch_current);
327 m_ch_scanned.push_back(m_ch_current);
331 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders)
334 m_ch_scanned.clear();
335 m_ch_unavailable.clear();
336 m_new_channels.clear();
337 m_new_services.clear();
338 m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
342 void eDVBScan::insertInto(iDVBChannelList *db)
344 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
345 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
346 db->addChannelToList(ch->first, ch->second);
347 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
348 service(m_new_services.begin()); service != m_new_services.end(); ++service)
350 ePtr<eDVBService> dvb_service;
351 if (!db->getService(service->first, dvb_service))
352 *dvb_service = *service->second;
354 db->addService(service->first, service->second);
358 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
360 const ServiceDescriptionList &services = *sdt.getDescriptions();
361 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
362 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
364 /* save correct CHID for this channel if this is an ACTUAL_SDT */
365 if (sdt.getTableId() == TID_SDT_ACTUAL)
366 m_chid_current = chid;
368 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
370 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
372 eServiceReferenceDVB ref;
373 ePtr<eDVBService> service = new eDVBService;
376 ref.setServiceID((*s)->getServiceId());
378 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
379 desc != (*s)->getDescriptors()->end(); ++desc)
380 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
381 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
383 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
384 desc != (*s)->getDescriptors()->end(); ++desc)
386 switch ((*desc)->getTag())
388 case SERVICE_DESCRIPTOR:
390 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
391 service->m_service_name = convertDVBUTF8(d.getServiceName());
392 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
393 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
396 case CA_IDENTIFIER_DESCRIPTOR:
398 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
399 const CaSystemIdList &caids = *d.getCaSystemIds();
400 SCAN_eDebugNoNewLine("CA ");
401 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
403 SCAN_eDebugNoNewLine("%04x ", *i);
404 service->m_ca.insert(*i);
410 SCAN_eDebug("descr<%x>", (*desc)->getTag());
415 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
420 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
422 connection = new eConnection(this, m_event.connect(event));
426 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
428 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
429 transponders_total = m_ch_toScan.size() + transponders_done;
430 services = m_new_services.size();