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