8b895dc9f8a42a59ea959604e162a033bb2f0a30
[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         int found_count=0;
287                 /* ... in the list of channels to scan */
288         for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
289         {
290                 if (sameChannel(*i, feparm))
291                 {
292                         if (!found_count)
293                         {
294                                 *i = feparm;  // update
295                                 eDebug("update");
296                         }
297                         else
298                         {
299                                 eDebug("remove dupe");
300                                 m_ch_toScan.erase(i++);
301                                 continue;
302                         }
303                         ++found_count;
304                 }
305                 ++i;
306         }
307
308         if (found_count > 0)
309         {
310                 eDebug("already in todo list");
311                 return;
312         }
313
314                 /* ... in the list of successfully scanned channels */
315         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
316                 if (sameChannel(*i, feparm))
317                 {
318                         eDebug("successfully scanned");
319                         return;
320                 }
321
322                 /* ... in the list of unavailable channels */
323         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
324                 if (sameChannel(*i, feparm, true))
325                 {
326                         eDebug("scanned but not available");
327                         return;
328                 }
329
330                 /* ... on the current channel */
331         if (sameChannel(m_ch_current, feparm))
332         {
333                 eDebug("is current");
334                 return;
335         }
336
337         eDebug("really add");
338                 /* otherwise, add it to the todo list. */
339         m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
340 }
341
342 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
343 {
344         int diff;
345         if (ch1->calculateDifference(ch2, diff, exact))
346                 return 0;
347         if (diff < 4000) // more than 4mhz difference?
348                 return 1;
349         return 0;
350 }
351
352 void eDVBScan::channelDone()
353 {
354         if (m_ready & validSDT)
355         {
356                 unsigned long hash = 0;
357
358                 // m_ch_current is not set, when eDVBScan is just used for a SDT update
359                 if (!m_ch_current)
360                         m_channel->getCurrentFrontendParameters(m_ch_current);
361
362                 m_ch_current->getHash(hash);
363                 
364                 eDVBNamespace dvbnamespace = buildNamespace(
365                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
366                         (**m_SDT->getSections().begin()).getTransportStreamId(),
367                         hash);
368                 
369                 SCAN_eDebug("SDT: ");
370                 std::vector<ServiceDescriptionSection*>::const_iterator i;
371                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
372                         processSDT(dvbnamespace, **i);
373                 m_ready &= ~validSDT;
374         }
375         
376         if (m_ready & validNIT)
377         {
378                 int system;
379                 m_ch_current->getSystem(system);
380                 SCAN_eDebug("dumping NIT");
381                 if (m_flags & clearToScanOnFirstNIT)
382                 {
383                         m_ch_toScan.clear();
384                         m_flags &= ~clearToScanOnFirstNIT;
385                 }
386                 std::vector<NetworkInformationSection*>::const_iterator i;
387                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
388                 {
389                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
390                         
391                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
392                                 tsinfo != tsinfovec.end(); ++tsinfo)
393                         {
394                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
395                                         (*tsinfo)->getOriginalNetworkId());
396                                 
397                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
398                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
399                                 
400                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
401                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
402                                 {
403                                         switch ((*desc)->getTag())
404                                         {
405                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
406                                         {
407                                                 if (system != iDVBFrontend::feCable)
408                                                         break; // when current locked transponder is no cable transponder ignore this descriptor
409                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
410                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
411                                                 eDVBFrontendParametersCable cable;
412                                                 cable.set(d);
413                                                 feparm->setDVBC(cable);
414
415                                                 unsigned long hash=0;
416                                                 feparm->getHash(hash);
417                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
418
419                                                 addChannelToScan(
420                                                         eDVBChannelID(ns, tsid, onid),
421                                                         feparm);
422                                                 break;
423                                         }
424                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
425                                         {
426                                                 if (system != iDVBFrontend::feTerrestrial)
427                                                         break; // when current locked transponder is no terrestrial transponder ignore this descriptor
428                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
429                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
430                                                 eDVBFrontendParametersTerrestrial terr;
431                                                 terr.set(d);
432                                                 feparm->setDVBT(terr);
433
434                                                 unsigned long hash=0;
435                                                 feparm->getHash(hash);
436                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
437
438                                                 addChannelToScan(
439                                                         eDVBChannelID(ns, tsid, onid),
440                                                         feparm);
441                                                 break;
442                                         }
443                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
444                                         {
445                                                 if (system != iDVBFrontend::feSatellite)
446                                                         break; // when current locked transponder is no satellite transponder ignore this descriptor
447
448                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
449                                                 if (d.getFrequency() < 10000)
450                                                         break;
451                                                 
452                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
453                                                 eDVBFrontendParametersSatellite sat;
454                                                 sat.set(d);
455                                                 feparm->setDVBS(sat);
456                                                 unsigned long hash=0;
457                                                 feparm->getHash(hash);
458                                                 
459                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
460                                                 
461                                                 if ( m_chid_current.dvbnamespace.get() != -1 &&
462                                                         ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
463                                                         SCAN_eDebug("dropping this transponder, it's on another satellite.");
464                                                 else
465                                                 {
466                                                         addChannelToScan(
467                                                                         eDVBChannelID(ns, tsid, onid),
468                                                                         feparm);
469                                                 }
470                                                 break;
471                                         }
472                                         default:
473                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
474                                                 break;
475                                         }
476                                 }
477                                 
478                         }
479                 }
480                 m_ready &= ~validNIT;
481         }
482         
483         if ((m_ready  & m_ready_all) != m_ready_all)
484                 return;
485         SCAN_eDebug("channel done!");
486         
487                 /* if we had services on this channel, we declare
488                    this channels as "known good". add it.
489                    
490                    (TODO: not yet implemented)
491                    a NIT entry could have possible overridden
492                    our frontend data with more exact data.
493                    
494                    (TODO: not yet implemented)
495                    the tuning process could have lead to more
496                    exact data than the user entered.
497                    
498                    The channel id was probably corrected
499                    by the data written in the SDT. this is
500                    important, as "initial transponder lists"
501                    usually don't have valid CHIDs (and that's
502                    good).
503                    
504                    These are the reasons for adding the transponder
505                    here, and not before.
506                 */
507
508         if (!m_chid_current)
509                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
510         else
511         {
512                 addKnownGoodChannel(m_chid_current, m_ch_current);
513         
514                 m_ch_scanned.push_back(m_ch_current);
515
516                 for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
517                 {
518                         if (sameChannel(*i, m_ch_current))
519                         {
520                                 eDebug("remove dupe 2");
521                                 m_ch_toScan.erase(i++);
522                                 continue;
523                         }
524                         ++i;
525                 }
526         }
527
528         nextChannel();
529 }
530
531 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
532 {
533         m_flags = flags;
534         m_ch_toScan.clear();
535         m_ch_scanned.clear();
536         m_ch_unavailable.clear();
537         m_new_channels.clear();
538         m_new_services.clear();
539         m_last_service = m_new_services.end();
540
541         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
542         {
543                 bool exist=false;
544                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
545                 {
546                         if (sameChannel(*i, *ii, true))
547                         {
548                                 exist=true;
549                                 break;
550                         }
551                 }
552                 if (!exist)
553                         m_ch_toScan.push_back(*i);
554         }
555
556         nextChannel();
557 }
558
559 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
560 {
561         if (m_flags & scanRemoveServices)
562         {
563                 bool clearTerrestrial=false;
564                 bool clearCable=false;
565                 std::set<unsigned int> scanned_sat_positions;
566                 
567                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
568                 for (;it != m_ch_scanned.end(); ++it)
569                 {
570                         int system;
571                         (*it)->getSystem(system);
572                         switch(system)
573                         {
574                                 case iDVBFrontend::feSatellite:
575                                 {
576                                         eDVBFrontendParametersSatellite sat_parm;
577                                         (*it)->getDVBS(sat_parm);
578                                         scanned_sat_positions.insert(sat_parm.orbital_position);
579                                         break;
580                                 }
581                                 case iDVBFrontend::feTerrestrial:
582                                 {
583                                         clearTerrestrial=true;
584                                         break;
585                                 }
586                                 case iDVBFrontend::feCable:
587                                 {
588                                         clearCable=true;
589                                         break;
590                                 }
591                         }
592                 }
593
594                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
595                 {
596                         int system;
597                         (*it)->getSystem(system);
598                         switch(system)
599                         {
600                                 case iDVBFrontend::feSatellite:
601                                 {
602                                         eDVBFrontendParametersSatellite sat_parm;
603                                         (*it)->getDVBS(sat_parm);
604                                         scanned_sat_positions.insert(sat_parm.orbital_position);
605                                         break;
606                                 }
607                                 case iDVBFrontend::feTerrestrial:
608                                 {
609                                         clearTerrestrial=true;
610                                         break;
611                                 }
612                                 case iDVBFrontend::feCable:
613                                 {
614                                         clearCable=true;
615                                         break;
616                                 }
617                         }
618                 }
619
620                 if (clearTerrestrial)
621                 {
622                         eDVBChannelID chid;
623                         chid.dvbnamespace=0xEEEE0000;
624                         db->removeServices(chid);
625                 }
626                 if (clearCable)
627                 {
628                         eDVBChannelID chid;
629                         chid.dvbnamespace=0xFFFF0000;
630                         db->removeServices(chid);
631                 }
632                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
633                 {
634                         eDVBChannelID chid;
635                         if (m_flags & scanDontRemoveFeeds)
636                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
637 //                      eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
638                         db->removeServices(chid, *x);
639                 }
640         }
641
642         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
643                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
644                 db->addChannelToList(ch->first, ch->second);
645         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
646                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
647         {
648                 ePtr<eDVBService> dvb_service;
649                 if (!db->getService(service->first, dvb_service))
650                 {
651                         if (dvb_service->m_flags & eDVBService::dxNoSDT)
652                                 continue;
653                         if (!(dvb_service->m_flags & eDVBService::dxHoldName))
654                         {
655                                 dvb_service->m_service_name = service->second->m_service_name;
656                                 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
657                         }
658                         dvb_service->m_provider_name = service->second->m_provider_name;
659                         if (service->second->m_ca.size())
660                                 dvb_service->m_ca = service->second->m_ca;
661                         if (!dontRemoveOldFlags) // do not remove new found flags when not wished
662                                 dvb_service->m_flags &= ~eDVBService::dxNewFound;
663                 }
664                 else
665                 {
666                         db->addService(service->first, service->second);
667                         service->second->m_flags |= eDVBService::dxNewFound;
668                 }
669         }
670 }
671
672 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
673 {
674         const ServiceDescriptionList &services = *sdt.getDescriptions();
675         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
676         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
677         
678         /* save correct CHID for this channel */
679         m_chid_current = chid;
680
681         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
682         {
683                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
684
685                 eServiceReferenceDVB ref;
686                 ePtr<eDVBService> service = new eDVBService;
687                 
688                 ref.set(chid);
689                 ref.setServiceID((*s)->getServiceId());
690
691                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
692                                 desc != (*s)->getDescriptors()->end(); ++desc)
693                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
694                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
695                 
696                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
697                                 desc != (*s)->getDescriptors()->end(); ++desc)
698                 {
699                         switch ((*desc)->getTag())
700                         {
701                         case SERVICE_DESCRIPTOR:
702                         {
703                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
704                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
705                                 service->genSortName();
706
707                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
708                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
709                                 break;
710                         }
711                         case CA_IDENTIFIER_DESCRIPTOR:
712                         {
713                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
714                                 const CaSystemIdList &caids = *d.getCaSystemIds();
715                                 SCAN_eDebugNoNewLine("CA ");
716                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
717                                 {
718                                         SCAN_eDebugNoNewLine("%04x ", *i);
719                                         service->m_ca.push_front(*i);
720                                 }
721                                 SCAN_eDebug("");
722                                 break;
723                         }
724                         default:
725                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
726                                 break;
727                         }
728                 }
729                 
730                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
731                 
732                 if (i.second)
733                 {
734                         m_last_service = i.first;
735                         m_event(evtNewService);
736                 }
737         }
738         return 0;
739 }
740
741 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
742 {
743         connection = new eConnection(this, m_event.connect(event));
744         return 0;
745 }
746
747 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
748 {
749         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
750         transponders_total = m_ch_toScan.size() + transponders_done;
751         services = m_new_services.size();
752 }
753
754 void eDVBScan::getLastServiceName(std::string &last_service_name)
755 {
756         if (m_last_service == m_new_services.end())
757                 last_service_name = "";
758         else
759                 last_service_name = m_last_service->second->m_service_name;
760 }