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