more complete implementation of national option character subsets
[enigma2.git] / lib / dvb / scan.cpp
1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/descriptor_tag.h>
3 #include <dvbsi++/service_descriptor.h>
4 #include <dvbsi++/satellite_delivery_system_descriptor.h>
5 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
6 #include <dvbsi++/cable_delivery_system_descriptor.h>
7 #include <dvbsi++/ca_identifier_descriptor.h>
8 #include <lib/dvb/specs.h>
9 #include <lib/dvb/esection.h>
10 #include <lib/dvb/scan.h>
11 #include <lib/dvb/frontend.h>
12 #include <lib/base/eerror.h>
13 #include <lib/base/estring.h>
14 #include <errno.h>
15
16 static bool scan_debug;
17 #define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
18 #define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
19
20 DEFINE_REF(eDVBScan);
21
22 eDVBScan::eDVBScan(iDVBChannel *channel, bool usePAT, bool debug)
23         :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
24         ,m_ready(0), m_ready_all(usePAT ? (readySDT|readyPAT) : readySDT)
25         ,m_flags(0), m_usePAT(usePAT)
26 {
27         scan_debug=debug;
28         if (m_channel->getDemux(m_demux))
29                 SCAN_eDebug("scan: failed to allocate demux!");
30         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
31 }
32
33 eDVBScan::~eDVBScan()
34 {
35 }
36
37 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
38 {
39         switch (onid.get())
40         {
41         case 0:
42         case 0x1111:
43                 return 0;
44         case 1:
45                 return orbital_position == 192;
46         case 0x00B1:
47                 return tsid != 0x00B0;
48         case 0x0002:
49                 return abs(orbital_position-282) < 6;
50         default:
51                 return onid.get() < 0xFF00;
52         }
53 }
54
55 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
56 {
57                 // on valid ONIDs, ignore frequency ("sub network") part
58         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
59                 hash &= ~0xFFFF;
60         return eDVBNamespace(hash);
61 }
62
63 void eDVBScan::stateChange(iDVBChannel *ch)
64 {
65         int state;
66         if (ch->getState(state))
67                 return;
68         if (m_channel_state == state)
69                 return;
70         
71         if (state == iDVBChannel::state_ok)
72         {
73                 startFilter();
74                 m_channel_state = state;
75         } else if (state == iDVBChannel::state_failed)
76         {
77                 m_ch_unavailable.push_back(m_ch_current);
78                 nextChannel();
79         }
80                         /* unavailable will timeout, anyway. */
81 }
82
83 RESULT eDVBScan::nextChannel()
84 {
85         ePtr<iDVBFrontend> fe;
86
87         m_SDT = 0; m_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                 if (m_flags & clearToScanOnFirstNIT)
361                 {
362                         m_ch_toScan.clear();
363                         m_flags &= ~clearToScanOnFirstNIT;
364                 }
365                 std::vector<NetworkInformationSection*>::const_iterator i;
366                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
367                 {
368                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
369                         
370                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
371                                 tsinfo != tsinfovec.end(); ++tsinfo)
372                         {
373                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
374                                         (*tsinfo)->getOriginalNetworkId());
375                                 
376                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
377                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
378                                 
379                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
380                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
381                                 {
382                                         switch ((*desc)->getTag())
383                                         {
384                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
385                                         {
386                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
387                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
388                                                 eDVBFrontendParametersCable cable;
389                                                 cable.set(d);
390                                                 feparm->setDVBC(cable);
391
392                                                 unsigned long hash=0;
393                                                 feparm->getHash(hash);
394                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
395
396                                                 addChannelToScan(
397                                                         eDVBChannelID(ns, tsid, onid),
398                                                         feparm);
399                                                 break;
400                                         }
401                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
402                                         {
403                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
404                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
405                                                 eDVBFrontendParametersTerrestrial terr;
406                                                 terr.set(d);
407                                                 feparm->setDVBT(terr);
408
409                                                 unsigned long hash=0;
410                                                 feparm->getHash(hash);
411                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
412
413                                                 addChannelToScan(
414                                                         eDVBChannelID(ns, tsid, onid),
415                                                         feparm);
416                                                 break;
417                                         }
418                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
419                                         {
420                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
421                                                 if (d.getFrequency() < 10000)
422                                                         break;
423                                                 
424                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
425                                                 eDVBFrontendParametersSatellite sat;
426                                                 sat.set(d);
427                                                 feparm->setDVBS(sat);
428                                                 unsigned long hash=0;
429                                                 feparm->getHash(hash);
430                                                 
431                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
432                                                 
433                                                 if ( m_chid_current.dvbnamespace.get() != -1 &&
434                                                         ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
435                                                         SCAN_eDebug("dropping this transponder, it's on another satellite.");
436                                                 else
437                                                 {
438                                                         addChannelToScan(
439                                                                         eDVBChannelID(ns, tsid, onid),
440                                                                         feparm);
441                                                 }
442                                                 break;
443                                         }
444                                         default:
445                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
446                                                 break;
447                                         }
448                                 }
449                                 
450                         }
451                 }
452                 m_ready &= ~validNIT;
453         }
454         
455         if ((m_ready  & m_ready_all) != m_ready_all)
456                 return;
457         SCAN_eDebug("channel done!");
458         
459                 /* if we had services on this channel, we declare
460                    this channels as "known good". add it.
461                    
462                    (TODO: not yet implemented)
463                    a NIT entry could have possible overridden
464                    our frontend data with more exact data.
465                    
466                    (TODO: not yet implemented)
467                    the tuning process could have lead to more
468                    exact data than the user entered.
469                    
470                    The channel id was probably corrected
471                    by the data written in the SDT. this is
472                    important, as "initial transponder lists"
473                    usually don't have valid CHIDs (and that's
474                    good).
475                    
476                    These are the reasons for adding the transponder
477                    here, and not before.
478                 */
479
480         if (!m_chid_current)
481                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
482         else
483                 addKnownGoodChannel(m_chid_current, m_ch_current);
484         
485         m_ch_scanned.push_back(m_ch_current);
486         nextChannel();
487 }
488
489 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
490 {
491         m_flags = flags;
492         m_ch_toScan.clear();
493         m_ch_scanned.clear();
494         m_ch_unavailable.clear();
495         m_new_channels.clear();
496         m_new_services.clear();
497         m_last_service = m_new_services.end();
498
499         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
500         {
501                 bool exist=false;
502                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
503                 {
504                         if (sameChannel(*i, *ii))
505                         {
506                                 exist=true;
507                                 break;
508                         }
509                 }
510                 if (!exist)
511                         m_ch_toScan.push_back(*i);
512         }
513
514         nextChannel();
515 }
516
517 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
518 {
519         if (m_flags & scanRemoveServices)
520         {
521                 bool clearTerrestrial=false;
522                 bool clearCable=false;
523                 std::set<unsigned int> scanned_sat_positions;
524                 
525                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
526                 for (;it != m_ch_scanned.end(); ++it)
527                 {
528                         int system;
529                         (*it)->getSystem(system);
530                         switch(system)
531                         {
532                                 case iDVBFrontend::feSatellite:
533                                 {
534                                         eDVBFrontendParametersSatellite sat_parm;
535                                         (*it)->getDVBS(sat_parm);
536                                         scanned_sat_positions.insert(sat_parm.orbital_position);
537                                         break;
538                                 }
539                                 case iDVBFrontend::feTerrestrial:
540                                 {
541                                         clearTerrestrial=true;
542                                         break;
543                                 }
544                                 case iDVBFrontend::feCable:
545                                 {
546                                         clearCable=true;
547                                         break;
548                                 }
549                         }
550                 }
551
552                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
553                 {
554                         int system;
555                         (*it)->getSystem(system);
556                         switch(system)
557                         {
558                                 case iDVBFrontend::feSatellite:
559                                 {
560                                         eDVBFrontendParametersSatellite sat_parm;
561                                         (*it)->getDVBS(sat_parm);
562                                         scanned_sat_positions.insert(sat_parm.orbital_position);
563                                         break;
564                                 }
565                                 case iDVBFrontend::feTerrestrial:
566                                 {
567                                         clearTerrestrial=true;
568                                         break;
569                                 }
570                                 case iDVBFrontend::feCable:
571                                 {
572                                         clearCable=true;
573                                         break;
574                                 }
575                         }
576                 }
577
578                 if (clearTerrestrial)
579                 {
580                         eDVBChannelID chid;
581                         chid.dvbnamespace=0xEEEE0000;
582                         db->removeServices(chid);
583                 }
584                 if (clearCable)
585                 {
586                         eDVBChannelID chid;
587                         chid.dvbnamespace=0xFFFF0000;
588                         db->removeServices(chid);
589                 }
590                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
591                 {
592                         eDVBChannelID chid;
593                         if (m_flags & scanDontRemoveFeeds)
594                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
595 //                      eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
596                         db->removeServices(chid, *x);
597                 }
598         }
599
600         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
601                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
602                 db->addChannelToList(ch->first, ch->second);
603         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
604                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
605         {
606                 ePtr<eDVBService> dvb_service;
607                 if (!db->getService(service->first, dvb_service))
608                 {
609                         if (dvb_service->m_flags & eDVBService::dxNoSDT)
610                                 continue;
611                         if (!(dvb_service->m_flags & eDVBService::dxHoldName))
612                         {
613                                 dvb_service->m_service_name = service->second->m_service_name;
614                                 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
615                         }
616                         dvb_service->m_provider_name = service->second->m_provider_name;
617                         if (service->second->m_ca.size())
618                                 dvb_service->m_ca = service->second->m_ca;
619                         if (!dontRemoveOldFlags) // do not remove new found flags when not wished
620                                 dvb_service->m_flags &= ~eDVBService::dxNewFound;
621                 }
622                 else
623                 {
624                         db->addService(service->first, service->second);
625                         service->second->m_flags |= eDVBService::dxNewFound;
626                 }
627         }
628 }
629
630 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
631 {
632         const ServiceDescriptionList &services = *sdt.getDescriptions();
633         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
634         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
635         
636         /* save correct CHID for this channel */
637         m_chid_current = chid;
638
639         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
640         {
641                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
642
643                 eServiceReferenceDVB ref;
644                 ePtr<eDVBService> service = new eDVBService;
645                 
646                 ref.set(chid);
647                 ref.setServiceID((*s)->getServiceId());
648
649                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
650                                 desc != (*s)->getDescriptors()->end(); ++desc)
651                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
652                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
653                 
654                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
655                                 desc != (*s)->getDescriptors()->end(); ++desc)
656                 {
657                         switch ((*desc)->getTag())
658                         {
659                         case SERVICE_DESCRIPTOR:
660                         {
661                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
662                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
663                                 service->genSortName();
664
665                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
666                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
667                                 break;
668                         }
669                         case CA_IDENTIFIER_DESCRIPTOR:
670                         {
671                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
672                                 const CaSystemIdList &caids = *d.getCaSystemIds();
673                                 SCAN_eDebugNoNewLine("CA ");
674                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
675                                 {
676                                         SCAN_eDebugNoNewLine("%04x ", *i);
677                                         service->m_ca.push_front(*i);
678                                 }
679                                 SCAN_eDebug("");
680                                 break;
681                         }
682                         default:
683                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
684                                 break;
685                         }
686                 }
687                 
688                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
689                 
690                 if (i.second)
691                 {
692                         m_last_service = i.first;
693                         m_event(evtNewService);
694                 }
695         }
696         return 0;
697 }
698
699 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
700 {
701         connection = new eConnection(this, m_event.connect(event));
702         return 0;
703 }
704
705 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
706 {
707         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
708         transponders_total = m_ch_toScan.size() + transponders_done;
709         services = m_new_services.size();
710 }
711
712 void eDVBScan::getLastServiceName(std::string &last_service_name)
713 {
714         if (m_last_service == m_new_services.end())
715                 last_service_name = "";
716         else
717                 last_service_name = m_last_service->second->m_service_name;
718 }