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