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