fix calculation of size, when dealing with big file ranges
[enigma2.git] / lib / dvb / scan.cpp
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>
17 #include <errno.h>
18
19 #define SCAN_eDebug(x...) eDebug(x)
20 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
21
22 DEFINE_REF(eDVBScan);
23
24 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
25 {
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);
29 }
30
31 eDVBScan::~eDVBScan()
32 {
33 }
34
35 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
36 {
37         switch (onid.get())
38         {
39         case 0:
40         case 0x1111:
41                 return 0;
42         case 1:
43                 return orbital_position == 192;
44         case 0x00B1:
45                 return tsid != 0x00B0;
46         case 0x0002:
47                 return abs(orbital_position-282) < 6;
48         default:
49                 return onid.get() < 0xFF00;
50         }
51 }
52
53 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
54 {
55                 // on valid ONIDs, ignore frequency ("sub network") part
56         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
57                 hash &= ~0xFFFF;
58         return eDVBNamespace(hash);
59 }
60
61 void eDVBScan::stateChange(iDVBChannel *ch)
62 {
63         int state;
64         if (ch->getState(state))
65                 return;
66         if (m_channel_state == state)
67                 return;
68         
69         if (state == iDVBChannel::state_ok)
70         {
71                 startFilter();
72                 m_channel_state = state;
73         } else if (state == iDVBChannel::state_failed)
74         {
75                 m_ch_unavailable.push_back(m_ch_current);
76                 nextChannel();
77         }
78                         /* unavailable will timeout, anyway. */
79 }
80
81 RESULT eDVBScan::nextChannel()
82 {
83         ePtr<iDVBFrontend> fe;
84
85         m_SDT = 0; m_BAT = 0; m_NIT = 0;
86
87         m_ready = 0;
88         
89                 /* check what we need */
90         m_ready_all = readySDT;
91         
92         if (m_flags & scanNetworkSearch)
93                 m_ready_all |= readyNIT;
94         
95         if (m_flags & scanSearchBAT)
96                 m_ready_all |= readyBAT;
97         
98         if (m_ch_toScan.empty())
99         {
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());
104                 m_event(evtFinish);
105                 return -ENOENT;
106         }
107         
108         m_ch_current = m_ch_toScan.front();
109         
110         m_ch_toScan.pop_front();
111         
112         if (m_channel->getFrontend(fe))
113         {
114                 m_event(evtFail);
115                 return -ENOTSUP;
116         }
117
118         int fetype;
119         fe->getFrontendType(fetype);
120         if ( fetype == iDVBFrontend::feSatellite)
121         {
122                 eDVBFrontendParametersSatellite p;
123                 m_ch_current->getDVBS(p);
124                 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
125         }
126         else
127                 m_chid_current = eDVBChannelID();
128
129         m_channel_state = iDVBChannel::state_idle;
130         if (fe->tune(*m_ch_current))
131         {
132                 return nextChannel();
133                 m_event(evtFail);
134                 return -EINVAL;
135         }
136                 
137         m_event(evtUpdate);
138         return 0;
139 }
140
141 RESULT eDVBScan::startFilter()
142 {
143         assert(m_demux);
144         
145                         /* only start required filters filter */
146         
147         m_SDT = 0;
148
149         if (m_ready_all & readySDT)
150         {
151                 m_SDT = new eTable<ServiceDescriptionSection>();
152                 if (m_SDT->start(m_demux, eDVBSDTSpec()))
153                         return -1;
154                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
155         }
156
157         m_NIT = 0;
158         if (m_ready_all & readyNIT)
159         {
160                 m_NIT = new eTable<NetworkInformationSection>();
161                 if (m_NIT->start(m_demux, eDVBNITSpec()))
162                         return -1;
163                 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
164         }
165
166         m_BAT = 0;
167         if (m_ready_all & readyBAT)
168         {
169                 m_BAT = new eTable<BouquetAssociationSection>();
170                 if (m_BAT->start(m_demux, eDVBBATSpec()))
171                         return -1;
172                 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
173         }
174         
175         return 0;
176 }
177
178 void eDVBScan::SDTready(int err)
179 {
180         SCAN_eDebug("got sdt");
181         m_ready |= readySDT;
182         if (!err)
183                 m_ready |= validSDT;
184         channelDone();
185 }
186
187 void eDVBScan::NITready(int err)
188 {
189         SCAN_eDebug("got nit, err %d", err);
190         m_ready |= readyNIT;
191         if (!err)
192                 m_ready |= validNIT;
193         channelDone();
194 }
195
196 void eDVBScan::BATready(int err)
197 {
198         SCAN_eDebug("got bat");
199         m_ready |= readyBAT;
200         if (!err)
201                 m_ready |= validBAT;
202         channelDone();
203 }
204
205 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
206 {
207                 /* add it to the list of known channels. */
208         if (chid)
209                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
210 }
211
212 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
213 {
214                 /* check if we don't already have that channel ... */
215                 
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))
219                         return;
220
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))
224                         return;
225                 
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))
229                         return;
230
231                 /* ... on the current channel */
232         if (sameChannel(m_ch_current, feparm))
233                 return;
234
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 :)
237 }
238
239 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
240 {
241         int diff;
242         if (ch1->calculateDifference(ch2, diff))
243                 return 0;
244         if (diff < 4000) // more than 4mhz difference?
245                 return 1;
246         return 0;
247 }
248
249 void eDVBScan::channelDone()
250 {
251         if (m_ready & validSDT)
252         {
253                 unsigned long hash = 0;
254                 m_ch_current->getHash(hash);
255                 
256                 eDVBNamespace dvbnamespace = buildNamespace(
257                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
258                         (**m_SDT->getSections().begin()).getTransportStreamId(),
259                         hash);
260                 
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;
266         }
267         
268         if (m_ready & validNIT)
269         {
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)
273                 {
274                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
275                         
276                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
277                                 tsinfo != tsinfovec.end(); ++tsinfo)
278                         {
279                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
280                                         (*tsinfo)->getOriginalNetworkId());
281                                 
282                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
283                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
284                                 
285                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
286                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
287                                 {
288                                         switch ((*desc)->getTag())
289                                         {
290                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
291                                         {
292                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
293                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
294                                                 eDVBFrontendParametersCable cable;
295                                                 cable.set(d);
296                                                 feparm->setDVBC(cable);
297
298                                                 unsigned long hash=0;
299                                                 feparm->getHash(hash);
300                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
301
302                                                 addChannelToScan(
303                                                         eDVBChannelID(ns, tsid, onid),
304                                                         feparm);
305                                                 break;
306                                         }
307                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
308                                         {
309                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
310                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
311                                                 eDVBFrontendParametersTerrestrial terr;
312                                                 terr.set(d);
313                                                 feparm->setDVBT(terr);
314
315                                                 unsigned long hash=0;
316                                                 feparm->getHash(hash);
317                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
318
319                                                 addChannelToScan(
320                                                         eDVBChannelID(ns, tsid, onid),
321                                                         feparm);
322                                                 break;
323                                         }
324                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
325                                         {
326                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
327                                                 if (d.getFrequency() < 10000)
328                                                         break;
329                                                 
330                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
331                                                 eDVBFrontendParametersSatellite sat;
332                                                 sat.set(d);
333                                                 feparm->setDVBS(sat);
334                                                 unsigned long hash=0;
335                                                 feparm->getHash(hash);
336                                                 
337                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
338                                                 
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.");
342                                                 else
343                                                 {
344                                                         addChannelToScan(
345                                                                         eDVBChannelID(ns, tsid, onid),
346                                                                         feparm);
347                                                 }
348                                                 break;
349                                         }
350                                         default:
351                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
352                                                 break;
353                                         }
354                                 }
355                                 
356                         }
357                 }
358                 m_ready &= ~validNIT;
359         }
360         
361         if ((m_ready  & m_ready_all) != m_ready_all)
362                 return;
363         SCAN_eDebug("channel done!");
364         
365                 /* if we had services on this channel, we declare
366                    this channels as "known good". add it.
367                    
368                    (TODO: not yet implemented)
369                    a NIT entry could have possible overridden
370                    our frontend data with more exact data.
371                    
372                    (TODO: not yet implemented)
373                    the tuning process could have lead to more
374                    exact data than the user entered.
375                    
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
380                    good).
381                    
382                    These are the reasons for adding the transponder
383                    here, and not before.
384                 */
385         
386         if (!m_chid_current)
387                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
388         else
389                 addKnownGoodChannel(m_chid_current, m_ch_current);
390         
391         m_ch_scanned.push_back(m_ch_current);
392         nextChannel();
393 }
394
395 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
396 {
397         m_flags = flags;
398         m_ch_toScan.clear();
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();
404
405         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
406         {
407                 bool exist=false;
408                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
409                 {
410                         if (sameChannel(*i, *ii))
411                         {
412                                 exist=true;
413                                 break;
414                         }
415                 }
416                 if (!exist)
417                         m_ch_toScan.push_back(*i);
418         }
419
420         nextChannel();
421 }
422
423 void eDVBScan::insertInto(iDVBChannelList *db)
424 {
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)
430         {
431                 ePtr<eDVBService> dvb_service;
432                 if (!db->getService(service->first, dvb_service))
433                         *dvb_service = *service->second;
434                 else
435                         db->addService(service->first, service->second);
436         }
437 }
438
439 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
440 {
441         const ServiceDescriptionList &services = *sdt.getDescriptions();
442         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
443         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
444         
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;
448         
449         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
450         {
451                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
452
453                 eServiceReferenceDVB ref;
454                 ePtr<eDVBService> service = new eDVBService;
455                 
456                 ref.set(chid);
457                 ref.setServiceID((*s)->getServiceId());
458
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());
463                 
464                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
465                                 desc != (*s)->getDescriptors()->end(); ++desc)
466                 {
467                         switch ((*desc)->getTag())
468                         {
469                         case SERVICE_DESCRIPTOR:
470                         {
471                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
472                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
473                                 service->genSortName();
474
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());
477                                 break;
478                         }
479                         case CA_IDENTIFIER_DESCRIPTOR:
480                         {
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)
485                                 {
486                                         SCAN_eDebugNoNewLine("%04x ", *i);
487                                         service->m_ca.insert(*i);
488                                 }
489                                 SCAN_eDebug("");
490                                 break;
491                         }
492                         default:
493                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
494                                 break;
495                         }
496                 }
497                 
498                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
499                 
500                 if (i.second)
501                 {
502                         m_last_service = i.first;
503                         m_event(evtNewService);
504                 }
505         }
506         return 0;
507 }
508
509 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
510 {
511         connection = new eConnection(this, m_event.connect(event));
512         return 0;
513 }
514
515 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
516 {
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();
520 }
521
522 void eDVBScan::getLastServiceName(std::string &last_service_name)
523 {
524         if (m_last_service == m_new_services.end())
525                 last_service_name = "";
526         else
527                 last_service_name = m_last_service->second->m_service_name;
528 }