now link dvb-s frontends to dvb-s2 frontends is possible
[enigma2.git] / lib / dvb / scan.cpp
1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/descriptor_tag.h>
3 #include <dvbsi++/service_descriptor.h>
4 #include <dvbsi++/satellite_delivery_system_descriptor.h>
5 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
6 #include <dvbsi++/cable_delivery_system_descriptor.h>
7 #include <dvbsi++/ca_identifier_descriptor.h>
8 #include <lib/dvb/specs.h>
9 #include <lib/dvb/esection.h>
10 #include <lib/dvb/scan.h>
11 #include <lib/dvb/frontend.h>
12 #include <lib/base/eerror.h>
13 #include <lib/base/estring.h>
14 #include <errno.h>
15
16 static bool scan_debug;
17 #define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
18 #define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
19
20 DEFINE_REF(eDVBScan);
21
22 eDVBScan::eDVBScan(iDVBChannel *channel, bool usePAT, bool debug)
23         :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
24         ,m_ready(0), m_ready_all(usePAT ? (readySDT|readyPAT) : readySDT)
25         ,m_flags(0), m_usePAT(usePAT)
26 {
27         scan_debug=debug;
28         if (m_channel->getDemux(m_demux))
29                 SCAN_eDebug("scan: failed to allocate demux!");
30         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
31 }
32
33 eDVBScan::~eDVBScan()
34 {
35 }
36
37 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
38 {
39         switch (onid.get())
40         {
41         case 0:
42         case 0x1111:
43                 return 0;
44         case 1:
45                 return orbital_position == 192;
46         case 0x00B1:
47                 return tsid != 0x00B0;
48         case 0x0002:
49                 return abs(orbital_position-282) < 6;
50         default:
51                 return onid.get() < 0xFF00;
52         }
53 }
54
55 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
56 {
57                 // on valid ONIDs, ignore frequency ("sub network") part
58         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
59                 hash &= ~0xFFFF;
60         return eDVBNamespace(hash);
61 }
62
63 void eDVBScan::stateChange(iDVBChannel *ch)
64 {
65         int state;
66         if (ch->getState(state))
67                 return;
68         if (m_channel_state == state)
69                 return;
70         
71         if (state == iDVBChannel::state_ok)
72         {
73                 startFilter();
74                 m_channel_state = state;
75         } else if (state == iDVBChannel::state_failed)
76         {
77                 m_ch_unavailable.push_back(m_ch_current);
78                 nextChannel();
79         }
80                         /* unavailable will timeout, anyway. */
81 }
82
83 RESULT eDVBScan::nextChannel()
84 {
85         ePtr<iDVBFrontend> fe;
86
87         m_SDT = 0; m_PAT = 0; m_BAT = 0; m_NIT = 0;
88
89         m_ready = 0;
90
91                 /* check what we need */
92         m_ready_all = readySDT;
93         
94         if (m_flags & scanNetworkSearch)
95                 m_ready_all |= readyNIT;
96         
97         if (m_flags & scanSearchBAT)
98                 m_ready_all |= readyBAT;
99
100         if (m_usePAT)
101                 m_ready_all |= readyPAT;
102
103         if (m_ch_toScan.empty())
104         {
105                 SCAN_eDebug("no channels left to scan.");
106                 SCAN_eDebug("%d channels scanned, %d were unavailable.", 
107                                 m_ch_scanned.size(), m_ch_unavailable.size());
108                 SCAN_eDebug("%d channels in database.", m_new_channels.size());
109                 m_event(evtFinish);
110                 return -ENOENT;
111         }
112         
113         m_ch_current = m_ch_toScan.front();
114         
115         m_ch_toScan.pop_front();
116         
117         if (m_channel->getFrontend(fe))
118         {
119                 m_event(evtFail);
120                 return -ENOTSUP;
121         }
122
123         m_chid_current = eDVBChannelID();
124
125         m_channel_state = iDVBChannel::state_idle;
126
127         if (fe->tune(*m_ch_current))
128                 return nextChannel();
129
130         m_event(evtUpdate);
131         return 0;
132 }
133
134 RESULT eDVBScan::startFilter()
135 {
136         bool startSDT=true;
137         assert(m_demux);
138
139                         /* only start required filters filter */
140
141         if (m_ready_all & readyPAT)
142                 startSDT = m_ready & readyPAT;
143
144         m_SDT = 0;
145         if (startSDT && (m_ready_all & readySDT))
146         {
147                 m_SDT = new eTable<ServiceDescriptionSection>();
148                 int tsid=-1;
149                 if (m_ready & readyPAT && m_ready & validPAT)
150                 {
151                         std::vector<ProgramAssociationSection*>::const_iterator i =
152                                 m_PAT->getSections().begin();
153                         assert(i != m_PAT->getSections().end());
154                         tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
155
156                         // KabelBW HACK ... on 618 Mhz the transport stream id in PAT and SDT is different
157                         {
158                                 int type;
159                                 m_ch_current->getSystem(type);
160                                 if (type == iDVBFrontend::feCable)
161                                 {
162                                         eDVBFrontendParametersCable parm;
163                                         m_ch_current->getDVBC(parm);
164                                         if (tsid == 0x00d7 & abs(parm.frequency-618000) < 2000)
165                                                 tsid = -1;
166                                 }
167                         }
168                 }
169                 if (tsid == -1 && m_SDT->start(m_demux, eDVBSDTSpec()))
170                         return -1;
171                 else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
172                         return -1;
173                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
174         }
175
176         if (!(m_ready & readyPAT))
177         {
178                 m_PAT = 0;
179                 if (m_ready_all & readyPAT)
180                 {
181                         m_PAT = new eTable<ProgramAssociationSection>();
182                         if (m_PAT->start(m_demux, eDVBPATSpec()))
183                                 return -1;
184                         CONNECT(m_PAT->tableReady, eDVBScan::PATready);
185                 }
186
187                 m_NIT = 0;
188                 if (m_ready_all & readyNIT)
189                 {
190                         m_NIT = new eTable<NetworkInformationSection>();
191                         if (m_NIT->start(m_demux, eDVBNITSpec()))
192                                 return -1;
193                         CONNECT(m_NIT->tableReady, eDVBScan::NITready);
194                 }
195
196                 m_BAT = 0;
197                 if (m_ready_all & readyBAT)
198                 {
199                         m_BAT = new eTable<BouquetAssociationSection>();
200                         if (m_BAT->start(m_demux, eDVBBATSpec()))
201                                 return -1;
202                         CONNECT(m_BAT->tableReady, eDVBScan::BATready);
203                 }
204         }
205
206         return 0;
207 }
208
209 void eDVBScan::SDTready(int err)
210 {
211         SCAN_eDebug("got sdt");
212         m_ready |= readySDT;
213         if (!err)
214                 m_ready |= validSDT;
215         channelDone();
216 }
217
218 void eDVBScan::NITready(int err)
219 {
220         SCAN_eDebug("got nit, err %d", err);
221         m_ready |= readyNIT;
222         if (!err)
223                 m_ready |= validNIT;
224         channelDone();
225 }
226
227 void eDVBScan::BATready(int err)
228 {
229         SCAN_eDebug("got bat");
230         m_ready |= readyBAT;
231         if (!err)
232                 m_ready |= validBAT;
233         channelDone();
234 }
235
236 void eDVBScan::PATready(int err)
237 {
238         SCAN_eDebug("got pat");
239         m_ready |= readyPAT;
240         if (!err)
241                 m_ready |= validPAT;
242         startFilter(); // for starting the SDT filter
243 }
244
245 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
246 {
247                 /* add it to the list of known channels. */
248         if (chid)
249                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
250 }
251
252 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
253 {
254                 /* check if we don't already have that channel ... */
255
256         int type;
257         feparm->getSystem(type);
258
259         switch(type)
260         {
261         case iDVBFrontend::feSatellite:
262         {
263                 eDVBFrontendParametersSatellite parm;
264                 feparm->getDVBS(parm);
265                 eDebug("try to add %d %d %d %d %d %d",
266                         parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
267                 break;
268         }
269         case iDVBFrontend::feCable:
270         {
271                 eDVBFrontendParametersCable parm;
272                 feparm->getDVBC(parm);
273                 eDebug("try to add %d %d %d %d",
274                         parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
275                 break;
276         }
277         case iDVBFrontend::feTerrestrial:
278         {
279                 eDVBFrontendParametersTerrestrial parm;
280                 feparm->getDVBT(parm);
281                 eDebug("try to add %d %d %d %d %d %d %d %d",
282                         parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
283                         parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
284                 break;
285         }
286         }
287
288         int found_count=0;
289                 /* ... in the list of channels to scan */
290         for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
291         {
292                 if (sameChannel(*i, feparm))
293                 {
294                         if (!found_count)
295                         {
296                                 *i = feparm;  // update
297                                 eDebug("update");
298                         }
299                         else
300                         {
301                                 eDebug("remove dupe");
302                                 m_ch_toScan.erase(i++);
303                                 continue;
304                         }
305                         ++found_count;
306                 }
307                 ++i;
308         }
309
310         if (found_count > 0)
311         {
312                 eDebug("already in todo list");
313                 return;
314         }
315
316                 /* ... in the list of successfully scanned channels */
317         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
318                 if (sameChannel(*i, feparm))
319                 {
320                         eDebug("successfully scanned");
321                         return;
322                 }
323
324                 /* ... in the list of unavailable channels */
325         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
326                 if (sameChannel(*i, feparm, true))
327                 {
328                         eDebug("scanned but not available");
329                         return;
330                 }
331
332                 /* ... on the current channel */
333         if (sameChannel(m_ch_current, feparm))
334         {
335                 eDebug("is current");
336                 return;
337         }
338
339         eDebug("really add");
340                 /* otherwise, add it to the todo list. */
341         m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
342 }
343
344 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
345 {
346         int diff;
347         if (ch1->calculateDifference(ch2, diff, exact))
348                 return 0;
349         if (diff < 4000) // more than 4mhz difference?
350                 return 1;
351         return 0;
352 }
353
354 void eDVBScan::channelDone()
355 {
356         if (m_ready & validSDT)
357         {
358                 unsigned long hash = 0;
359
360                 // m_ch_current is not set, when eDVBScan is just used for a SDT update
361                 if (!m_ch_current)
362                         m_channel->getCurrentFrontendParameters(m_ch_current);
363
364                 m_ch_current->getHash(hash);
365                 
366                 eDVBNamespace dvbnamespace = buildNamespace(
367                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
368                         (**m_SDT->getSections().begin()).getTransportStreamId(),
369                         hash);
370                 
371                 SCAN_eDebug("SDT: ");
372                 std::vector<ServiceDescriptionSection*>::const_iterator i;
373                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
374                         processSDT(dvbnamespace, **i);
375                 m_ready &= ~validSDT;
376         }
377         
378         if (m_ready & validNIT)
379         {
380                 int system;
381                 std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
382                 m_ch_current->getSystem(system);
383                 SCAN_eDebug("dumping NIT");
384                 if (m_flags & clearToScanOnFirstNIT)
385                 {
386                         m_ch_toScan_backup = m_ch_toScan;
387                         m_ch_toScan.clear();
388                 }
389                 std::vector<NetworkInformationSection*>::const_iterator i;
390                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
391                 {
392                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
393                         
394                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
395                                 tsinfo != tsinfovec.end(); ++tsinfo)
396                         {
397                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
398                                         (*tsinfo)->getOriginalNetworkId());
399                                 
400                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
401                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
402                                 
403                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
404                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
405                                 {
406                                         switch ((*desc)->getTag())
407                                         {
408                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
409                                         {
410                                                 if (system != iDVBFrontend::feCable)
411                                                         break; // when current locked transponder is no cable transponder ignore this descriptor
412                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
413                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
414                                                 eDVBFrontendParametersCable cable;
415                                                 cable.set(d);
416                                                 feparm->setDVBC(cable);
417
418                                                 unsigned long hash=0;
419                                                 feparm->getHash(hash);
420                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
421
422                                                 addChannelToScan(
423                                                         eDVBChannelID(ns, tsid, onid),
424                                                         feparm);
425                                                 break;
426                                         }
427                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
428                                         {
429                                                 if (system != iDVBFrontend::feTerrestrial)
430                                                         break; // when current locked transponder is no terrestrial transponder ignore this descriptor
431                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
432                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
433                                                 eDVBFrontendParametersTerrestrial terr;
434                                                 terr.set(d);
435                                                 feparm->setDVBT(terr);
436
437                                                 unsigned long hash=0;
438                                                 feparm->getHash(hash);
439                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
440
441                                                 addChannelToScan(
442                                                         eDVBChannelID(ns, tsid, onid),
443                                                         feparm);
444                                                 break;
445                                         }
446                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
447                                         {
448                                                 if (system != iDVBFrontend::feSatellite)
449                                                         break; // when current locked transponder is no satellite transponder ignore this descriptor
450
451                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
452                                                 if (d.getFrequency() < 10000)
453                                                         break;
454                                                 
455                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
456                                                 eDVBFrontendParametersSatellite sat;
457                                                 sat.set(d);
458
459                                                 eDVBFrontendParametersSatellite p;
460                                                 m_ch_current->getDVBS(p);
461
462                                                 if ( abs(p.orbital_position - sat.orbital_position) < 5 )
463                                                         sat.orbital_position = p.orbital_position;
464
465                                                 if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
466                                                 {
467                                                         eDebug("found transponder with incorrect west/east flag ... correct this");
468                                                         sat.orbital_position = p.orbital_position;
469                                                 }
470
471                                                 feparm->setDVBS(sat);
472
473                                                 if ( p.orbital_position != sat.orbital_position)
474                                                         SCAN_eDebug("dropping this transponder, it's on another satellite.");
475                                                 else
476                                                 {
477                                                         unsigned long hash=0;
478                                                         feparm->getHash(hash);
479                                                         addChannelToScan(
480                                                                         eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
481                                                                         feparm);
482                                                 }
483                                                 break;
484                                         }
485                                         default:
486                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
487                                                 break;
488                                         }
489                                 }
490                         }
491                         
492                 }
493
494                         /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
495                            no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
496                            has been found.
497
498                            This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
499                         */
500                 if (m_flags & clearToScanOnFirstNIT)
501                 {
502                         if (m_ch_toScan.empty())
503                         {
504                                 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
505                                 m_ch_toScan = m_ch_toScan_backup;
506                         } else
507                                 m_flags &= ~clearToScanOnFirstNIT;
508                 }
509                 m_ready &= ~validNIT;
510         }
511         
512         if ((m_ready  & m_ready_all) != m_ready_all)
513                 return;
514         SCAN_eDebug("channel done!");
515         
516                 /* if we had services on this channel, we declare
517                    this channels as "known good". add it.
518                    
519                    (TODO: not yet implemented)
520                    a NIT entry could have possible overridden
521                    our frontend data with more exact data.
522                    
523                    (TODO: not yet implemented)
524                    the tuning process could have lead to more
525                    exact data than the user entered.
526                    
527                    The channel id was probably corrected
528                    by the data written in the SDT. this is
529                    important, as "initial transponder lists"
530                    usually don't have valid CHIDs (and that's
531                    good).
532                    
533                    These are the reasons for adding the transponder
534                    here, and not before.
535                 */
536         
537         if (!m_chid_current)
538                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
539         else
540                 addKnownGoodChannel(m_chid_current, m_ch_current);
541         
542         m_ch_scanned.push_back(m_ch_current);
543         
544         for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
545         {
546                 if (sameChannel(*i, m_ch_current))
547                 {
548                         eDebug("remove dupe 2");
549                         m_ch_toScan.erase(i++);
550                         continue;
551                 }
552                 ++i;
553         }
554         
555         nextChannel();
556 }
557
558 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
559 {
560         m_flags = flags;
561         m_ch_toScan.clear();
562         m_ch_scanned.clear();
563         m_ch_unavailable.clear();
564         m_new_channels.clear();
565         m_new_services.clear();
566         m_last_service = m_new_services.end();
567
568         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
569         {
570                 bool exist=false;
571                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
572                 {
573                         if (sameChannel(*i, *ii, true))
574                         {
575                                 exist=true;
576                                 break;
577                         }
578                 }
579                 if (!exist)
580                         m_ch_toScan.push_back(*i);
581         }
582
583         nextChannel();
584 }
585
586 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
587 {
588         if (m_flags & scanRemoveServices)
589         {
590                 bool clearTerrestrial=false;
591                 bool clearCable=false;
592                 std::set<unsigned int> scanned_sat_positions;
593                 
594                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
595                 for (;it != m_ch_scanned.end(); ++it)
596                 {
597                         int system;
598                         (*it)->getSystem(system);
599                         switch(system)
600                         {
601                                 case iDVBFrontend::feSatellite:
602                                 {
603                                         eDVBFrontendParametersSatellite sat_parm;
604                                         (*it)->getDVBS(sat_parm);
605                                         scanned_sat_positions.insert(sat_parm.orbital_position);
606                                         break;
607                                 }
608                                 case iDVBFrontend::feTerrestrial:
609                                 {
610                                         clearTerrestrial=true;
611                                         break;
612                                 }
613                                 case iDVBFrontend::feCable:
614                                 {
615                                         clearCable=true;
616                                         break;
617                                 }
618                         }
619                 }
620
621                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
622                 {
623                         int system;
624                         (*it)->getSystem(system);
625                         switch(system)
626                         {
627                                 case iDVBFrontend::feSatellite:
628                                 {
629                                         eDVBFrontendParametersSatellite sat_parm;
630                                         (*it)->getDVBS(sat_parm);
631                                         scanned_sat_positions.insert(sat_parm.orbital_position);
632                                         break;
633                                 }
634                                 case iDVBFrontend::feTerrestrial:
635                                 {
636                                         clearTerrestrial=true;
637                                         break;
638                                 }
639                                 case iDVBFrontend::feCable:
640                                 {
641                                         clearCable=true;
642                                         break;
643                                 }
644                         }
645                 }
646
647                 if (clearTerrestrial)
648                 {
649                         eDVBChannelID chid;
650                         chid.dvbnamespace=0xEEEE0000;
651                         db->removeServices(chid);
652                 }
653                 if (clearCable)
654                 {
655                         eDVBChannelID chid;
656                         chid.dvbnamespace=0xFFFF0000;
657                         db->removeServices(chid);
658                 }
659                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
660                 {
661                         eDVBChannelID chid;
662                         if (m_flags & scanDontRemoveFeeds)
663                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
664 //                      eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
665                         db->removeServices(chid, *x);
666                 }
667         }
668
669         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
670                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
671                 db->addChannelToList(ch->first, ch->second);
672         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
673                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
674         {
675                 ePtr<eDVBService> dvb_service;
676                 if (!db->getService(service->first, dvb_service))
677                 {
678                         if (dvb_service->m_flags & eDVBService::dxNoSDT)
679                                 continue;
680                         if (!(dvb_service->m_flags & eDVBService::dxHoldName))
681                         {
682                                 dvb_service->m_service_name = service->second->m_service_name;
683                                 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
684                         }
685                         dvb_service->m_provider_name = service->second->m_provider_name;
686                         if (service->second->m_ca.size())
687                                 dvb_service->m_ca = service->second->m_ca;
688                         if (!dontRemoveOldFlags) // do not remove new found flags when not wished
689                                 dvb_service->m_flags &= ~eDVBService::dxNewFound;
690                 }
691                 else
692                 {
693                         db->addService(service->first, service->second);
694                         if (!(m_flags & scanRemoveServices))
695                                 service->second->m_flags |= eDVBService::dxNewFound;
696                 }
697         }
698 }
699
700 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
701 {
702         const ServiceDescriptionList &services = *sdt.getDescriptions();
703         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
704         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
705         
706         /* save correct CHID for this channel */
707         m_chid_current = chid;
708
709         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
710         {
711                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
712
713                 eServiceReferenceDVB ref;
714                 ePtr<eDVBService> service = new eDVBService;
715                 
716                 ref.set(chid);
717                 ref.setServiceID((*s)->getServiceId());
718
719                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
720                                 desc != (*s)->getDescriptors()->end(); ++desc)
721                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
722                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
723                 
724                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
725                                 desc != (*s)->getDescriptors()->end(); ++desc)
726                 {
727                         switch ((*desc)->getTag())
728                         {
729                         case SERVICE_DESCRIPTOR:
730                         {
731                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
732                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
733                                 service->genSortName();
734
735                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
736                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
737                                 break;
738                         }
739                         case CA_IDENTIFIER_DESCRIPTOR:
740                         {
741                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
742                                 const CaSystemIdList &caids = *d.getCaSystemIds();
743                                 SCAN_eDebugNoNewLine("CA ");
744                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
745                                 {
746                                         SCAN_eDebugNoNewLine("%04x ", *i);
747                                         service->m_ca.push_front(*i);
748                                 }
749                                 SCAN_eDebug("");
750                                 break;
751                         }
752                         default:
753                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
754                                 break;
755                         }
756                 }
757                 
758                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
759                 
760                 if (i.second)
761                 {
762                         m_last_service = i.first;
763                         m_event(evtNewService);
764                 }
765         }
766         return 0;
767 }
768
769 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
770 {
771         connection = new eConnection(this, m_event.connect(event));
772         return 0;
773 }
774
775 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
776 {
777         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
778         transponders_total = m_ch_toScan.size() + transponders_done;
779         services = m_new_services.size();
780 }
781
782 void eDVBScan::getLastServiceName(std::string &last_service_name)
783 {
784         if (m_last_service == m_new_services.end())
785                 last_service_name = "";
786         else
787                 last_service_name = m_last_service->second->m_service_name;
788 }
789
790 RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
791 {
792         if (m_channel)
793                 return m_channel->getFrontend(fe);
794         fe = 0;
795         return -1;
796 }
797
798 RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)
799 {
800         if (m_ch_current)
801         {
802                 tp = m_ch_current;
803                 return 0;
804         }
805         tp = 0;
806         return -1;
807 }