do not scan transponders without SDT more than once (this fixes the never
[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                                                 feparm->setDVBS(sat);
448
449                                                 eDVBFrontendParametersSatellite p;
450                                                 m_ch_current->getDVBS(p);
451
452                                                 if ( p.orbital_position != sat.orbital_position )
453                                                         SCAN_eDebug("dropping this transponder, it's on another satellite.");
454                                                 else
455                                                 {
456                                                         unsigned long hash=0;
457                                                         feparm->getHash(hash);
458                                                         addChannelToScan(
459                                                                         eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
460                                                                         feparm);
461                                                 }
462                                                 break;
463                                         }
464                                         default:
465                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
466                                                 break;
467                                         }
468                                 }
469                         }
470                         
471                 }
472
473                         /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
474                            no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
475                            has been found.
476
477                            This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
478                         */
479                 if (m_flags & clearToScanOnFirstNIT)
480                 {
481                         if (m_ch_toScan.empty())
482                         {
483                                 eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
484                                 m_ch_toScan = m_ch_toScan_backup;
485                         } else
486                                 m_flags &= ~clearToScanOnFirstNIT;
487                 }
488                 m_ready &= ~validNIT;
489         }
490         
491         if ((m_ready  & m_ready_all) != m_ready_all)
492                 return;
493         SCAN_eDebug("channel done!");
494         
495                 /* if we had services on this channel, we declare
496                    this channels as "known good". add it.
497                    
498                    (TODO: not yet implemented)
499                    a NIT entry could have possible overridden
500                    our frontend data with more exact data.
501                    
502                    (TODO: not yet implemented)
503                    the tuning process could have lead to more
504                    exact data than the user entered.
505                    
506                    The channel id was probably corrected
507                    by the data written in the SDT. this is
508                    important, as "initial transponder lists"
509                    usually don't have valid CHIDs (and that's
510                    good).
511                    
512                    These are the reasons for adding the transponder
513                    here, and not before.
514                 */
515         
516         if (!m_chid_current)
517                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
518         else
519                 addKnownGoodChannel(m_chid_current, m_ch_current);
520         
521         m_ch_scanned.push_back(m_ch_current);
522         
523         for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
524         {
525                 if (sameChannel(*i, m_ch_current))
526                 {
527                         eDebug("remove dupe 2");
528                         m_ch_toScan.erase(i++);
529                         continue;
530                 }
531                 ++i;
532         }
533         
534         nextChannel();
535 }
536
537 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
538 {
539         m_flags = flags;
540         m_ch_toScan.clear();
541         m_ch_scanned.clear();
542         m_ch_unavailable.clear();
543         m_new_channels.clear();
544         m_new_services.clear();
545         m_last_service = m_new_services.end();
546
547         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
548         {
549                 bool exist=false;
550                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
551                 {
552                         if (sameChannel(*i, *ii, true))
553                         {
554                                 exist=true;
555                                 break;
556                         }
557                 }
558                 if (!exist)
559                         m_ch_toScan.push_back(*i);
560         }
561
562         nextChannel();
563 }
564
565 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
566 {
567         if (m_flags & scanRemoveServices)
568         {
569                 bool clearTerrestrial=false;
570                 bool clearCable=false;
571                 std::set<unsigned int> scanned_sat_positions;
572                 
573                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
574                 for (;it != m_ch_scanned.end(); ++it)
575                 {
576                         int system;
577                         (*it)->getSystem(system);
578                         switch(system)
579                         {
580                                 case iDVBFrontend::feSatellite:
581                                 {
582                                         eDVBFrontendParametersSatellite sat_parm;
583                                         (*it)->getDVBS(sat_parm);
584                                         scanned_sat_positions.insert(sat_parm.orbital_position);
585                                         break;
586                                 }
587                                 case iDVBFrontend::feTerrestrial:
588                                 {
589                                         clearTerrestrial=true;
590                                         break;
591                                 }
592                                 case iDVBFrontend::feCable:
593                                 {
594                                         clearCable=true;
595                                         break;
596                                 }
597                         }
598                 }
599
600                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
601                 {
602                         int system;
603                         (*it)->getSystem(system);
604                         switch(system)
605                         {
606                                 case iDVBFrontend::feSatellite:
607                                 {
608                                         eDVBFrontendParametersSatellite sat_parm;
609                                         (*it)->getDVBS(sat_parm);
610                                         scanned_sat_positions.insert(sat_parm.orbital_position);
611                                         break;
612                                 }
613                                 case iDVBFrontend::feTerrestrial:
614                                 {
615                                         clearTerrestrial=true;
616                                         break;
617                                 }
618                                 case iDVBFrontend::feCable:
619                                 {
620                                         clearCable=true;
621                                         break;
622                                 }
623                         }
624                 }
625
626                 if (clearTerrestrial)
627                 {
628                         eDVBChannelID chid;
629                         chid.dvbnamespace=0xEEEE0000;
630                         db->removeServices(chid);
631                 }
632                 if (clearCable)
633                 {
634                         eDVBChannelID chid;
635                         chid.dvbnamespace=0xFFFF0000;
636                         db->removeServices(chid);
637                 }
638                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
639                 {
640                         eDVBChannelID chid;
641                         if (m_flags & scanDontRemoveFeeds)
642                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
643 //                      eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
644                         db->removeServices(chid, *x);
645                 }
646         }
647
648         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
649                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
650                 db->addChannelToList(ch->first, ch->second);
651         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
652                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
653         {
654                 ePtr<eDVBService> dvb_service;
655                 if (!db->getService(service->first, dvb_service))
656                 {
657                         if (dvb_service->m_flags & eDVBService::dxNoSDT)
658                                 continue;
659                         if (!(dvb_service->m_flags & eDVBService::dxHoldName))
660                         {
661                                 dvb_service->m_service_name = service->second->m_service_name;
662                                 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
663                         }
664                         dvb_service->m_provider_name = service->second->m_provider_name;
665                         if (service->second->m_ca.size())
666                                 dvb_service->m_ca = service->second->m_ca;
667                         if (!dontRemoveOldFlags) // do not remove new found flags when not wished
668                                 dvb_service->m_flags &= ~eDVBService::dxNewFound;
669                 }
670                 else
671                 {
672                         db->addService(service->first, service->second);
673                         service->second->m_flags |= eDVBService::dxNewFound;
674                 }
675         }
676 }
677
678 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
679 {
680         const ServiceDescriptionList &services = *sdt.getDescriptions();
681         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
682         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
683         
684         /* save correct CHID for this channel */
685         m_chid_current = chid;
686
687         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
688         {
689                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
690
691                 eServiceReferenceDVB ref;
692                 ePtr<eDVBService> service = new eDVBService;
693                 
694                 ref.set(chid);
695                 ref.setServiceID((*s)->getServiceId());
696
697                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
698                                 desc != (*s)->getDescriptors()->end(); ++desc)
699                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
700                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
701                 
702                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
703                                 desc != (*s)->getDescriptors()->end(); ++desc)
704                 {
705                         switch ((*desc)->getTag())
706                         {
707                         case SERVICE_DESCRIPTOR:
708                         {
709                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
710                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
711                                 service->genSortName();
712
713                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
714                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
715                                 break;
716                         }
717                         case CA_IDENTIFIER_DESCRIPTOR:
718                         {
719                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
720                                 const CaSystemIdList &caids = *d.getCaSystemIds();
721                                 SCAN_eDebugNoNewLine("CA ");
722                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
723                                 {
724                                         SCAN_eDebugNoNewLine("%04x ", *i);
725                                         service->m_ca.push_front(*i);
726                                 }
727                                 SCAN_eDebug("");
728                                 break;
729                         }
730                         default:
731                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
732                                 break;
733                         }
734                 }
735                 
736                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
737                 
738                 if (i.second)
739                 {
740                         m_last_service = i.first;
741                         m_event(evtNewService);
742                 }
743         }
744         return 0;
745 }
746
747 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
748 {
749         connection = new eConnection(this, m_event.connect(event));
750         return 0;
751 }
752
753 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
754 {
755         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
756         transponders_total = m_ch_toScan.size() + transponders_done;
757         services = m_new_services.size();
758 }
759
760 void eDVBScan::getLastServiceName(std::string &last_service_name)
761 {
762         if (m_last_service == m_new_services.end())
763                 last_service_name = "";
764         else
765                 last_service_name = m_last_service->second->m_service_name;
766 }