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