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++/terrestrial_delivery_system_descriptor.h>
9 #include <dvbsi++/cable_delivery_system_descriptor.h>
10 #include <dvbsi++/ca_identifier_descriptor.h>
11 #include <lib/dvb/specs.h>
12 #include <lib/dvb/esection.h>
13 #include <lib/dvb/scan.h>
14 #include <lib/dvb/frontend.h>
15 #include <lib/base/eerror.h>
16 #include <lib/base/estring.h>
19 #define SCAN_eDebug(x...) eDebug(x)
20 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
24 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
26 if (m_channel->getDemux(m_demux))
27 SCAN_eDebug("scan: failed to allocate demux!");
28 m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
35 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
43 return orbital_position == 192;
45 return tsid != 0x00B0;
47 return abs(orbital_position-282) < 6;
49 return onid.get() < 0xFF00;
53 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
55 // on valid ONIDs, ignore frequency ("sub network") part
56 if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
58 return eDVBNamespace(hash);
61 void eDVBScan::stateChange(iDVBChannel *ch)
64 if (ch->getState(state))
66 if (m_channel_state == state)
69 if (state == iDVBChannel::state_ok)
72 m_channel_state = state;
73 } else if (state == iDVBChannel::state_failed)
75 m_ch_unavailable.push_back(m_ch_current);
78 /* unavailable will timeout, anyway. */
81 RESULT eDVBScan::nextChannel()
83 ePtr<iDVBFrontend> fe;
85 m_SDT = 0; m_BAT = 0; m_NIT = 0;
89 /* check what we need */
90 m_ready_all = readySDT;
92 if (m_flags & scanNetworkSearch)
93 m_ready_all |= readyNIT;
95 if (m_flags & scanSearchBAT)
96 m_ready_all |= readyBAT;
98 if (m_ch_toScan.empty())
100 eDebug("no channels left to scan.");
101 eDebug("%d channels scanned, %d were unavailable.",
102 m_ch_scanned.size(), m_ch_unavailable.size());
103 eDebug("%d channels in database.", m_new_channels.size());
108 m_ch_current = m_ch_toScan.front();
110 m_ch_toScan.pop_front();
112 if (m_channel->getFrontend(fe))
119 fe->getFrontendType(fetype);
120 if ( fetype == iDVBFrontend::feSatellite)
122 eDVBFrontendParametersSatellite p;
123 m_ch_current->getDVBS(p);
124 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
127 m_chid_current = eDVBChannelID();
129 m_channel_state = iDVBChannel::state_idle;
130 if (fe->tune(*m_ch_current))
132 return nextChannel();
141 RESULT eDVBScan::startFilter()
145 /* only start required filters filter */
149 if (m_ready_all & readySDT)
151 m_SDT = new eTable<ServiceDescriptionSection>();
152 if (m_SDT->start(m_demux, eDVBSDTSpec()))
154 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
158 if (m_ready_all & readyNIT)
160 m_NIT = new eTable<NetworkInformationSection>();
161 if (m_NIT->start(m_demux, eDVBNITSpec()))
163 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
167 if (m_ready_all & readyBAT)
169 m_BAT = new eTable<BouquetAssociationSection>();
170 if (m_BAT->start(m_demux, eDVBBATSpec()))
172 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
178 void eDVBScan::SDTready(int err)
180 SCAN_eDebug("got sdt");
187 void eDVBScan::NITready(int err)
189 SCAN_eDebug("got nit, err %d", err);
196 void eDVBScan::BATready(int err)
198 SCAN_eDebug("got bat");
205 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
207 /* add it to the list of known channels. */
209 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
212 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
214 /* check if we don't already have that channel ... */
216 /* ... in the list of channels to scan */
217 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
218 if (sameChannel(*i, feparm))
221 /* ... in the list of successfully scanned channels */
222 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
223 if (sameChannel(*i, feparm))
226 /* ... in the list of unavailable channels */
227 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
228 if (sameChannel(*i, feparm))
231 /* ... on the current channel */
232 if (sameChannel(m_ch_current, feparm))
235 /* otherwise, add it to the todo list. */
236 m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
239 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
242 if (ch1->calculateDifference(ch2, diff))
244 if (diff < 4000) // more than 4mhz difference?
249 void eDVBScan::channelDone()
251 if (m_ready & validSDT)
253 unsigned long hash = 0;
254 m_ch_current->getHash(hash);
256 eDVBNamespace dvbnamespace = buildNamespace(
257 (**m_SDT->getSections().begin()).getOriginalNetworkId(),
258 (**m_SDT->getSections().begin()).getTransportStreamId(),
261 SCAN_eDebug("SDT: ");
262 std::vector<ServiceDescriptionSection*>::const_iterator i;
263 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
264 processSDT(dvbnamespace, **i);
265 m_ready &= ~validSDT;
268 if (m_ready & validNIT)
270 SCAN_eDebug("dumping NIT");
271 std::vector<NetworkInformationSection*>::const_iterator i;
272 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
274 const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
276 for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
277 tsinfo != tsinfovec.end(); ++tsinfo)
279 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
280 (*tsinfo)->getOriginalNetworkId());
282 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
283 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
285 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
286 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
288 switch ((*desc)->getTag())
290 case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
292 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
293 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
294 eDVBFrontendParametersCable cable;
296 feparm->setDVBC(cable);
298 unsigned long hash=0;
299 feparm->getHash(hash);
300 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
303 eDVBChannelID(ns, tsid, onid),
307 case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
309 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
310 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
311 eDVBFrontendParametersTerrestrial terr;
313 feparm->setDVBT(terr);
315 unsigned long hash=0;
316 feparm->getHash(hash);
317 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
320 eDVBChannelID(ns, tsid, onid),
324 case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
326 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
327 if (d.getFrequency() < 10000)
330 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
331 eDVBFrontendParametersSatellite sat;
333 feparm->setDVBS(sat);
334 unsigned long hash=0;
335 feparm->getHash(hash);
337 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
339 if ( m_chid_current.dvbnamespace.get() != -1 &&
340 ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
341 eDebug("dropping this transponder, it's on another satellite.");
345 eDVBChannelID(ns, tsid, onid),
351 SCAN_eDebug("descr<%x>", (*desc)->getTag());
358 m_ready &= ~validNIT;
361 if ((m_ready & m_ready_all) != m_ready_all)
363 SCAN_eDebug("channel done!");
365 /* if we had services on this channel, we declare
366 this channels as "known good". add it.
368 (TODO: not yet implemented)
369 a NIT entry could have possible overridden
370 our frontend data with more exact data.
372 (TODO: not yet implemented)
373 the tuning process could have lead to more
374 exact data than the user entered.
376 The channel id was probably corrected
377 by the data written in the SDT. this is
378 important, as "initial transponder lists"
379 usually don't have valid CHIDs (and that's
382 These are the reasons for adding the transponder
383 here, and not before.
387 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
389 addKnownGoodChannel(m_chid_current, m_ch_current);
391 m_ch_scanned.push_back(m_ch_current);
395 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
399 m_ch_scanned.clear();
400 m_ch_unavailable.clear();
401 m_new_channels.clear();
402 m_new_services.clear();
403 m_last_service = m_new_services.end();
405 for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
408 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
410 if (sameChannel(*i, *ii))
417 m_ch_toScan.push_back(*i);
423 void eDVBScan::insertInto(iDVBChannelList *db)
425 for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
426 ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
427 db->addChannelToList(ch->first, ch->second);
428 for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
429 service(m_new_services.begin()); service != m_new_services.end(); ++service)
431 ePtr<eDVBService> dvb_service;
432 if (!db->getService(service->first, dvb_service))
433 *dvb_service = *service->second;
435 db->addService(service->first, service->second);
439 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
441 const ServiceDescriptionList &services = *sdt.getDescriptions();
442 SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
443 eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
445 /* save correct CHID for this channel if this is an ACTUAL_SDT */
446 if (sdt.getTableId() == TID_SDT_ACTUAL)
447 m_chid_current = chid;
449 for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
451 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
453 eServiceReferenceDVB ref;
454 ePtr<eDVBService> service = new eDVBService;
457 ref.setServiceID((*s)->getServiceId());
459 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
460 desc != (*s)->getDescriptors()->end(); ++desc)
461 if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
462 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
464 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
465 desc != (*s)->getDescriptors()->end(); ++desc)
467 switch ((*desc)->getTag())
469 case SERVICE_DESCRIPTOR:
471 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
472 service->m_service_name = convertDVBUTF8(d.getServiceName());
473 service->genSortName();
475 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
476 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
479 case CA_IDENTIFIER_DESCRIPTOR:
481 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
482 const CaSystemIdList &caids = *d.getCaSystemIds();
483 SCAN_eDebugNoNewLine("CA ");
484 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
486 SCAN_eDebugNoNewLine("%04x ", *i);
487 service->m_ca.insert(*i);
493 SCAN_eDebug("descr<%x>", (*desc)->getTag());
498 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
502 m_last_service = i.first;
503 m_event(evtNewService);
509 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
511 connection = new eConnection(this, m_event.connect(event));
515 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
517 transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
518 transponders_total = m_ch_toScan.size() + transponders_done;
519 services = m_new_services.size();
522 void eDVBScan::getLastServiceName(std::string &last_service_name)
524 if (m_last_service == m_new_services.end())
525 last_service_name = "";
527 last_service_name = m_last_service->second->m_service_name;