d0949a970ecc66a8d9cae261a1ba03f42e451737
[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 #include <set>
19
20 #define SCAN_eDebug(x...) eDebug(x)
21 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
22
23 DEFINE_REF(eDVBScan);
24
25 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
26 {
27         if (m_channel->getDemux(m_demux))
28                 SCAN_eDebug("scan: failed to allocate demux!");
29         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
30 }
31
32 eDVBScan::~eDVBScan()
33 {
34 }
35
36 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
37 {
38         switch (onid.get())
39         {
40         case 0:
41         case 0x1111:
42                 return 0;
43         case 1:
44                 return orbital_position == 192;
45         case 0x00B1:
46                 return tsid != 0x00B0;
47         case 0x0002:
48                 return abs(orbital_position-282) < 6;
49         default:
50                 return onid.get() < 0xFF00;
51         }
52 }
53
54 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
55 {
56                 // on valid ONIDs, ignore frequency ("sub network") part
57         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
58                 hash &= ~0xFFFF;
59         return eDVBNamespace(hash);
60 }
61
62 void eDVBScan::stateChange(iDVBChannel *ch)
63 {
64         int state;
65         if (ch->getState(state))
66                 return;
67         if (m_channel_state == state)
68                 return;
69         
70         if (state == iDVBChannel::state_ok)
71         {
72                 startFilter();
73                 m_channel_state = state;
74         } else if (state == iDVBChannel::state_failed)
75         {
76                 m_ch_unavailable.push_back(m_ch_current);
77                 nextChannel();
78         }
79                         /* unavailable will timeout, anyway. */
80 }
81
82 RESULT eDVBScan::nextChannel()
83 {
84         ePtr<iDVBFrontend> fe;
85
86         m_SDT = 0; m_BAT = 0; m_NIT = 0;
87
88         m_ready = 0;
89         
90                 /* check what we need */
91         m_ready_all = readySDT;
92         
93         if (m_flags & scanNetworkSearch)
94                 m_ready_all |= readyNIT;
95         
96         if (m_flags & scanSearchBAT)
97                 m_ready_all |= readyBAT;
98         
99         if (m_ch_toScan.empty())
100         {
101                 eDebug("no channels left to scan.");
102                 eDebug("%d channels scanned, %d were unavailable.", 
103                                 m_ch_scanned.size(), m_ch_unavailable.size());
104                 eDebug("%d channels in database.", m_new_channels.size());
105                 m_event(evtFinish);
106                 return -ENOENT;
107         }
108         
109         m_ch_current = m_ch_toScan.front();
110         
111         m_ch_toScan.pop_front();
112         
113         if (m_channel->getFrontend(fe))
114         {
115                 m_event(evtFail);
116                 return -ENOTSUP;
117         }
118
119         int fetype;
120         fe->getFrontendType(fetype);
121         if ( fetype == iDVBFrontend::feSatellite)
122         {
123                 eDVBFrontendParametersSatellite p;
124                 m_ch_current->getDVBS(p);
125                 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
126         }
127         else
128                 m_chid_current = eDVBChannelID();
129
130         m_channel_state = iDVBChannel::state_idle;
131         if (fe->tune(*m_ch_current))
132         {
133                 return nextChannel();
134                 m_event(evtFail);
135                 return -EINVAL;
136         }
137                 
138         m_event(evtUpdate);
139         return 0;
140 }
141
142 RESULT eDVBScan::startFilter()
143 {
144         assert(m_demux);
145         
146                         /* only start required filters filter */
147         
148         m_SDT = 0;
149
150         if (m_ready_all & readySDT)
151         {
152                 m_SDT = new eTable<ServiceDescriptionSection>();
153                 if (m_SDT->start(m_demux, eDVBSDTSpec()))
154                         return -1;
155                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
156         }
157
158         m_NIT = 0;
159         if (m_ready_all & readyNIT)
160         {
161                 m_NIT = new eTable<NetworkInformationSection>();
162                 if (m_NIT->start(m_demux, eDVBNITSpec()))
163                         return -1;
164                 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
165         }
166
167         m_BAT = 0;
168         if (m_ready_all & readyBAT)
169         {
170                 m_BAT = new eTable<BouquetAssociationSection>();
171                 if (m_BAT->start(m_demux, eDVBBATSpec()))
172                         return -1;
173                 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
174         }
175         
176         return 0;
177 }
178
179 void eDVBScan::SDTready(int err)
180 {
181         SCAN_eDebug("got sdt");
182         m_ready |= readySDT;
183         if (!err)
184                 m_ready |= validSDT;
185         channelDone();
186 }
187
188 void eDVBScan::NITready(int err)
189 {
190         SCAN_eDebug("got nit, err %d", err);
191         m_ready |= readyNIT;
192         if (!err)
193                 m_ready |= validNIT;
194         channelDone();
195 }
196
197 void eDVBScan::BATready(int err)
198 {
199         SCAN_eDebug("got bat");
200         m_ready |= readyBAT;
201         if (!err)
202                 m_ready |= validBAT;
203         channelDone();
204 }
205
206 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
207 {
208                 /* add it to the list of known channels. */
209         if (chid)
210                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
211 }
212
213 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
214 {
215                 /* check if we don't already have that channel ... */
216                 
217                 /* ... in the list of channels to scan */
218         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
219                 if (sameChannel(*i, feparm))
220                         return;
221
222                 /* ... in the list of successfully scanned channels */
223         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
224                 if (sameChannel(*i, feparm))
225                         return;
226                 
227                 /* ... in the list of unavailable channels */
228         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
229                 if (sameChannel(*i, feparm))
230                         return;
231
232                 /* ... on the current channel */
233         if (sameChannel(m_ch_current, feparm))
234                 return;
235
236                 /* otherwise, add it to the todo list. */
237         m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
238 }
239
240 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
241 {
242         int diff;
243         if (ch1->calculateDifference(ch2, diff))
244                 return 0;
245         if (diff < 4000) // more than 4mhz difference?
246                 return 1;
247         return 0;
248 }
249
250 void eDVBScan::channelDone()
251 {
252         if (m_ready & validSDT)
253         {
254                 unsigned long hash = 0;
255                 m_ch_current->getHash(hash);
256                 
257                 eDVBNamespace dvbnamespace = buildNamespace(
258                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
259                         (**m_SDT->getSections().begin()).getTransportStreamId(),
260                         hash);
261                 
262                 SCAN_eDebug("SDT: ");
263                 std::vector<ServiceDescriptionSection*>::const_iterator i;
264                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
265                         processSDT(dvbnamespace, **i);
266                 m_ready &= ~validSDT;
267         }
268         
269         if (m_ready & validNIT)
270         {
271                 SCAN_eDebug("dumping NIT");
272                 std::vector<NetworkInformationSection*>::const_iterator i;
273                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
274                 {
275                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
276                         
277                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
278                                 tsinfo != tsinfovec.end(); ++tsinfo)
279                         {
280                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
281                                         (*tsinfo)->getOriginalNetworkId());
282                                 
283                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
284                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
285                                 
286                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
287                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
288                                 {
289                                         switch ((*desc)->getTag())
290                                         {
291                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
292                                         {
293                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
294                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
295                                                 eDVBFrontendParametersCable cable;
296                                                 cable.set(d);
297                                                 feparm->setDVBC(cable);
298
299                                                 unsigned long hash=0;
300                                                 feparm->getHash(hash);
301                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
302
303                                                 addChannelToScan(
304                                                         eDVBChannelID(ns, tsid, onid),
305                                                         feparm);
306                                                 break;
307                                         }
308                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
309                                         {
310                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
311                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
312                                                 eDVBFrontendParametersTerrestrial terr;
313                                                 terr.set(d);
314                                                 feparm->setDVBT(terr);
315
316                                                 unsigned long hash=0;
317                                                 feparm->getHash(hash);
318                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
319
320                                                 addChannelToScan(
321                                                         eDVBChannelID(ns, tsid, onid),
322                                                         feparm);
323                                                 break;
324                                         }
325                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
326                                         {
327                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
328                                                 if (d.getFrequency() < 10000)
329                                                         break;
330                                                 
331                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
332                                                 eDVBFrontendParametersSatellite sat;
333                                                 sat.set(d);
334                                                 feparm->setDVBS(sat);
335                                                 unsigned long hash=0;
336                                                 feparm->getHash(hash);
337                                                 
338                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
339                                                 
340                                                 if ( m_chid_current.dvbnamespace.get() != -1 &&
341                                                         ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
342                                                         eDebug("dropping this transponder, it's on another satellite.");
343                                                 else
344                                                 {
345                                                         addChannelToScan(
346                                                                         eDVBChannelID(ns, tsid, onid),
347                                                                         feparm);
348                                                 }
349                                                 break;
350                                         }
351                                         default:
352                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
353                                                 break;
354                                         }
355                                 }
356                                 
357                         }
358                 }
359                 m_ready &= ~validNIT;
360         }
361         
362         if ((m_ready  & m_ready_all) != m_ready_all)
363                 return;
364         SCAN_eDebug("channel done!");
365         
366                 /* if we had services on this channel, we declare
367                    this channels as "known good". add it.
368                    
369                    (TODO: not yet implemented)
370                    a NIT entry could have possible overridden
371                    our frontend data with more exact data.
372                    
373                    (TODO: not yet implemented)
374                    the tuning process could have lead to more
375                    exact data than the user entered.
376                    
377                    The channel id was probably corrected
378                    by the data written in the SDT. this is
379                    important, as "initial transponder lists"
380                    usually don't have valid CHIDs (and that's
381                    good).
382                    
383                    These are the reasons for adding the transponder
384                    here, and not before.
385                 */
386         
387         if (!m_chid_current)
388                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
389         else
390                 addKnownGoodChannel(m_chid_current, m_ch_current);
391         
392         m_ch_scanned.push_back(m_ch_current);
393         nextChannel();
394 }
395
396 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
397 {
398         m_flags = flags;
399         m_ch_toScan.clear();
400         m_ch_scanned.clear();
401         m_ch_unavailable.clear();
402         m_new_channels.clear();
403         m_new_services.clear();
404         m_last_service = m_new_services.end();
405
406         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
407         {
408                 bool exist=false;
409                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
410                 {
411                         if (sameChannel(*i, *ii))
412                         {
413                                 exist=true;
414                                 break;
415                         }
416                 }
417                 if (!exist)
418                         m_ch_toScan.push_back(*i);
419         }
420
421         nextChannel();
422 }
423
424 void eDVBScan::insertInto(iDVBChannelList *db)
425 {
426         if (m_flags & scanRemoveServices)
427         {
428                 bool clearTerrestrial=false;
429                 bool clearCable=false;
430                 std::set<unsigned int> scanned_sat_positions;
431                 
432                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
433                 for (;it != m_ch_scanned.end(); ++it)
434                 {
435                         int system;
436                         (*it)->getSystem(system);
437                         switch(system)
438                         {
439                                 case iDVBFrontend::feSatellite:
440                                 {
441                                         eDVBFrontendParametersSatellite sat_parm;
442                                         (*it)->getDVBS(sat_parm);
443                                         scanned_sat_positions.insert(sat_parm.orbital_position);
444                                         break;
445                                 }
446                                 case iDVBFrontend::feTerrestrial:
447                                 {
448                                         clearTerrestrial=true;
449                                         break;
450                                 }
451                                 case iDVBFrontend::feCable:
452                                 {
453                                         clearCable=true;
454                                         break;
455                                 }
456                         }
457                 }
458
459                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
460                 {
461                         int system;
462                         (*it)->getSystem(system);
463                         switch(system)
464                         {
465                                 case iDVBFrontend::feSatellite:
466                                 {
467                                         eDVBFrontendParametersSatellite sat_parm;
468                                         (*it)->getDVBS(sat_parm);
469                                         scanned_sat_positions.insert(sat_parm.orbital_position);
470                                         break;
471                                 }
472                                 case iDVBFrontend::feTerrestrial:
473                                 {
474                                         clearTerrestrial=true;
475                                         break;
476                                 }
477                                 case iDVBFrontend::feCable:
478                                 {
479                                         clearCable=true;
480                                         break;
481                                 }
482                         }
483                 }
484
485                 if (clearTerrestrial)
486                 {
487                         eDVBChannelID chid;
488                         chid.dvbnamespace=0xEEEE0000;
489                         db->removeServices(chid);
490                 }
491                 if (clearCable)
492                 {
493                         eDVBChannelID chid;
494                         chid.dvbnamespace=0xFFFF0000;
495                         db->removeServices(chid);
496                 }
497                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
498                 {
499                         eDVBChannelID chid;
500                         if (m_flags & scanDontRemoveFeeds)
501                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
502                         eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
503                         db->removeServices(chid, *x);
504                 }
505         }
506
507         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
508                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
509                 db->addChannelToList(ch->first, ch->second);
510         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
511                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
512         {
513                 ePtr<eDVBService> dvb_service;
514                 if (!db->getService(service->first, dvb_service))
515                 {
516                         *dvb_service = *service->second;
517                         dvb_service->m_flags &= ~eDVBService::dxNewFound;
518                 }
519                 else
520                 {
521                         db->addService(service->first, service->second);
522                         service->second->m_flags |= eDVBService::dxNewFound;
523                 }
524         }
525 }
526
527 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
528 {
529         const ServiceDescriptionList &services = *sdt.getDescriptions();
530         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
531         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
532         
533                 /* save correct CHID for this channel if this is an ACTUAL_SDT */
534         if (sdt.getTableId() == TID_SDT_ACTUAL)
535                 m_chid_current = chid;
536         
537         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
538         {
539                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
540
541                 eServiceReferenceDVB ref;
542                 ePtr<eDVBService> service = new eDVBService;
543                 
544                 ref.set(chid);
545                 ref.setServiceID((*s)->getServiceId());
546
547                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
548                                 desc != (*s)->getDescriptors()->end(); ++desc)
549                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
550                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
551                 
552                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
553                                 desc != (*s)->getDescriptors()->end(); ++desc)
554                 {
555                         switch ((*desc)->getTag())
556                         {
557                         case SERVICE_DESCRIPTOR:
558                         {
559                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
560                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
561                                 service->genSortName();
562
563                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
564                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
565                                 break;
566                         }
567                         case CA_IDENTIFIER_DESCRIPTOR:
568                         {
569                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
570                                 const CaSystemIdList &caids = *d.getCaSystemIds();
571                                 SCAN_eDebugNoNewLine("CA ");
572                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
573                                 {
574                                         SCAN_eDebugNoNewLine("%04x ", *i);
575                                         service->m_ca.insert(*i);
576                                 }
577                                 SCAN_eDebug("");
578                                 break;
579                         }
580                         default:
581                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
582                                 break;
583                         }
584                 }
585                 
586                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
587                 
588                 if (i.second)
589                 {
590                         m_last_service = i.first;
591                         m_event(evtNewService);
592                 }
593         }
594         return 0;
595 }
596
597 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
598 {
599         connection = new eConnection(this, m_event.connect(event));
600         return 0;
601 }
602
603 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
604 {
605         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
606         transponders_total = m_ch_toScan.size() + transponders_done;
607         services = m_new_services.size();
608 }
609
610 void eDVBScan::getLastServiceName(std::string &last_service_name)
611 {
612         if (m_last_service == m_new_services.end())
613                 last_service_name = "";
614         else
615                 last_service_name = m_last_service->second->m_service_name;
616 }