fix python refcounting
[enigma2.git] / lib / dvb / scan.cpp
1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/service_description_section.h>
3 #include <dvbsi++/network_information_section.h>
4 #include <dvbsi++/bouquet_association_section.h>
5 #include <dvbsi++/descriptor_tag.h>
6 #include <dvbsi++/service_descriptor.h>
7 #include <dvbsi++/satellite_delivery_system_descriptor.h>
8 #include <dvbsi++/ca_identifier_descriptor.h>
9 #include <lib/dvb/specs.h>
10 #include <lib/dvb/esection.h>
11 #include <lib/dvb/scan.h>
12 #include <lib/dvb/frontend.h>
13 #include <lib/base/eerror.h>
14 #include <lib/base/estring.h>
15 #include <errno.h>
16
17 #define SCAN_eDebug(x...) eDebug(x)
18 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
19
20 DEFINE_REF(eDVBScan);
21
22 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
23 {
24         if (m_channel->getDemux(m_demux))
25                 SCAN_eDebug("scan: failed to allocate demux!");
26         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
27 }
28
29 eDVBScan::~eDVBScan()
30 {
31 }
32
33 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
34 {
35         switch (onid.get())
36         {
37         case 0:
38         case 0x1111:
39                 return 0;
40         case 1:
41                 return orbital_position == 192;
42         case 0x00B1:
43                 return tsid != 0x00B0;
44         case 0x0002:
45                 return abs(orbital_position-282) < 6;
46         default:
47                 return onid.get() < 0xFF00;
48         }
49 }
50
51 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
52 {
53                 // on valid ONIDs, ignore frequency ("sub network") part
54         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
55                 hash &= ~0xFFFF;
56         return eDVBNamespace(hash);
57 }
58
59 void eDVBScan::stateChange(iDVBChannel *ch)
60 {
61         int state;
62         if (ch->getState(state))
63                 return;
64         if (m_channel_state == state)
65                 return;
66         
67         if (state == iDVBChannel::state_ok)
68         {
69                 startFilter();
70                 m_channel_state = state;
71         } else if (state == iDVBChannel::state_failed)
72         {
73                 m_ch_unavailable.push_back(m_ch_current);
74                 nextChannel();
75         }
76                         /* unavailable will timeout, anyway. */
77 }
78
79 RESULT eDVBScan::nextChannel()
80 {
81         ePtr<iDVBFrontend> fe;
82
83         m_SDT = 0; m_BAT = 0; m_NIT = 0;
84
85         m_ready = 0;
86         
87                 /* check what we need */
88         m_ready_all = readySDT;
89         
90         if (m_flags & scanNetworkSearch)
91                 m_ready_all |= readyNIT;
92         
93         if (m_flags & scanSearchBAT)
94                 m_ready_all |= readyBAT;
95         
96         if (m_ch_toScan.empty())
97         {
98                 eDebug("no channels left to scan.");
99                 eDebug("%d channels scanned, %d were unavailable.", 
100                                 m_ch_scanned.size(), m_ch_unavailable.size());
101                 eDebug("%d channels in database.", m_new_channels.size());
102                 m_event(evtFinish);
103                 return -ENOENT;
104         }
105         
106         m_ch_current = m_ch_toScan.front();
107         
108         m_ch_toScan.pop_front();
109         
110         if (m_channel->getFrontend(fe))
111         {
112                 m_event(evtFail);
113                 return -ENOTSUP;
114         }
115
116         int fetype;
117         fe->getFrontendType(fetype);
118         if ( fetype == iDVBFrontend::feSatellite)
119         {
120                 eDVBFrontendParametersSatellite p;
121                 m_ch_current->getDVBS(p);
122                 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
123         }
124         else
125                 m_chid_current = eDVBChannelID();
126
127         m_channel_state = iDVBChannel::state_idle;
128         if (fe->tune(*m_ch_current))
129         {
130                 return nextChannel();
131                 m_event(evtFail);
132                 return -EINVAL;
133         }
134                 
135         m_event(evtUpdate);
136         return 0;
137 }
138
139 RESULT eDVBScan::startFilter()
140 {
141         assert(m_demux);
142         
143                         /* only start required filters filter */
144         
145         m_SDT = 0;
146
147         if (m_ready_all & readySDT)
148         {
149                 m_SDT = new eTable<ServiceDescriptionSection>();
150                 if (m_SDT->start(m_demux, eDVBSDTSpec()))
151                         return -1;
152                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
153         }
154
155         m_NIT = 0;
156         if (m_ready_all & readyNIT)
157         {
158                 m_NIT = new eTable<NetworkInformationSection>();
159                 if (m_NIT->start(m_demux, eDVBNITSpec()))
160                         return -1;
161                 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
162         }
163
164         m_BAT = 0;
165         if (m_ready_all & readyBAT)
166         {
167                 m_BAT = new eTable<BouquetAssociationSection>();
168                 if (m_BAT->start(m_demux, eDVBBATSpec()))
169                         return -1;
170                 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
171         }
172         
173         return 0;
174 }
175
176 void eDVBScan::SDTready(int err)
177 {
178         SCAN_eDebug("got sdt");
179         m_ready |= readySDT;
180         if (!err)
181                 m_ready |= validSDT;
182         channelDone();
183 }
184
185 void eDVBScan::NITready(int err)
186 {
187         SCAN_eDebug("got nit, err %d", err);
188         m_ready |= readyNIT;
189         if (!err)
190                 m_ready |= validNIT;
191         channelDone();
192 }
193
194 void eDVBScan::BATready(int err)
195 {
196         SCAN_eDebug("got bat");
197         m_ready |= readyBAT;
198         if (!err)
199                 m_ready |= validBAT;
200         channelDone();
201 }
202
203 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
204 {
205                 /* add it to the list of known channels. */
206         if (chid)
207                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
208 }
209
210 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
211 {
212                 /* check if we don't already have that channel ... */
213                 
214                 /* ... in the list of channels to scan */
215         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
216                 if (sameChannel(*i, feparm))
217                         return;
218
219                 /* ... in the list of successfully scanned channels */
220         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
221                 if (sameChannel(*i, feparm))
222                         return;
223                 
224                 /* ... in the list of unavailable channels */
225         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
226                 if (sameChannel(*i, feparm))
227                         return;
228
229                 /* ... on the current channel */
230         if (sameChannel(m_ch_current, feparm))
231                 return;
232
233                 /* otherwise, add it to the todo list. */
234         m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
235 }
236
237 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
238 {
239         int diff;
240         if (ch1->calculateDifference(ch2, diff))
241                 return 0;
242         if (diff < 4000) // more than 4mhz difference?
243                 return 1;
244         return 0;
245 }
246
247 void eDVBScan::channelDone()
248 {
249         if (m_ready & validSDT)
250         {
251                 unsigned long hash = 0;
252                 m_ch_current->getHash(hash);
253                 
254                 eDVBNamespace dvbnamespace = buildNamespace(
255                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
256                         (**m_SDT->getSections().begin()).getTransportStreamId(),
257                         hash);
258                 
259                 SCAN_eDebug("SDT: ");
260                 std::vector<ServiceDescriptionSection*>::const_iterator i;
261                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
262                         processSDT(dvbnamespace, **i);
263                 m_ready &= ~validSDT;
264         }
265         
266         if (m_ready & validNIT)
267         {
268                 SCAN_eDebug("dumping NIT");
269                 std::vector<NetworkInformationSection*>::const_iterator i;
270                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
271                 {
272                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
273                         
274                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
275                                 tsinfo != tsinfovec.end(); ++tsinfo)
276                         {
277                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
278                                         (*tsinfo)->getOriginalNetworkId());
279                                 
280                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
281                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
282                                 
283                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
284                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
285                                 {
286                                         switch ((*desc)->getTag())
287                                         {
288 //                                      case SERVICE_LIST_DESCRIPTOR:
289                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
290                                         {
291                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
292                                                 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d", 
293                                                                 d.getFrequency(), 
294                                                                 (d.getOrbitalPosition()>>12)&0xF,
295                                                                 (d.getOrbitalPosition()>>8)&0xF,
296                                                                 (d.getOrbitalPosition()>>4)&0xF,
297                                                                 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
298                                                                 d.getPolarization() ? "hor" : "vert",
299                                                                 d.getModulation(), d.getSymbolRate(), d.getFecInner());
300                                                 
301                                                         /* some sanity checking: below 100MHz is invalid */
302                                                 if (d.getFrequency() < 10000)
303                                                         break;
304                                                 
305                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
306                                                 eDVBFrontendParametersSatellite sat;
307                                                 sat.set(d);
308                                                 feparm->setDVBS(sat);
309                                                 unsigned long hash=0;
310                                                 feparm->getHash(hash);
311                                                 
312                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
313                                                 
314                                                 if ( m_chid_current.dvbnamespace.get() != -1 &&
315                                                         ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
316                                                         eDebug("dropping this transponder, it's on another satellite.");
317                                                 else
318                                                 {
319                                                         addChannelToScan(
320                                                                         eDVBChannelID(ns, tsid, onid),
321                                                                         feparm);
322                                                 }
323                                                 break;
324                                         }
325                                         default:
326                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
327                                                 break;
328                                         }
329                                 }
330                                 
331                         }
332                 }
333                 m_ready &= ~validNIT;
334         }
335         
336         if ((m_ready  & m_ready_all) != m_ready_all)
337                 return;
338         SCAN_eDebug("channel done!");
339         
340                 /* if we had services on this channel, we declare
341                    this channels as "known good". add it.
342                    
343                    (TODO: not yet implemented)
344                    a NIT entry could have possible overridden
345                    our frontend data with more exact data.
346                    
347                    (TODO: not yet implemented)
348                    the tuning process could have lead to more
349                    exact data than the user entered.
350                    
351                    The channel id was probably corrected
352                    by the data written in the SDT. this is
353                    important, as "initial transponder lists"
354                    usually don't have valid CHIDs (and that's
355                    good).
356                    
357                    These are the reasons for adding the transponder
358                    here, and not before.
359                 */
360         
361         if (!m_chid_current)
362                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
363         else
364                 addKnownGoodChannel(m_chid_current, m_ch_current);
365         
366         m_ch_scanned.push_back(m_ch_current);
367         nextChannel();
368 }
369
370 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
371 {
372         m_flags = flags;
373         m_ch_toScan.clear();
374         m_ch_scanned.clear();
375         m_ch_unavailable.clear();
376         m_new_channels.clear();
377         m_new_services.clear();
378
379         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
380         {
381                 bool exist=false;
382                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
383                 {
384                         if (sameChannel(*i, *ii))
385                         {
386                                 exist=true;
387                                 break;
388                         }
389                 }
390                 if (!exist)
391                         m_ch_toScan.push_back(*i);
392         }
393
394         nextChannel();
395 }
396
397 void eDVBScan::insertInto(iDVBChannelList *db)
398 {
399         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
400                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
401                 db->addChannelToList(ch->first, ch->second);
402         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
403                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
404         {
405                 ePtr<eDVBService> dvb_service;
406                 if (!db->getService(service->first, dvb_service))
407                         *dvb_service = *service->second;
408                 else
409                         db->addService(service->first, service->second);
410         }
411 }
412
413 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
414 {
415         const ServiceDescriptionList &services = *sdt.getDescriptions();
416         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
417         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
418         
419                 /* save correct CHID for this channel if this is an ACTUAL_SDT */
420         if (sdt.getTableId() == TID_SDT_ACTUAL)
421                 m_chid_current = chid;
422         
423         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
424         {
425                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
426
427                 eServiceReferenceDVB ref;
428                 ePtr<eDVBService> service = new eDVBService;
429                 
430                 ref.set(chid);
431                 ref.setServiceID((*s)->getServiceId());
432
433                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
434                                 desc != (*s)->getDescriptors()->end(); ++desc)
435                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
436                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
437                 
438                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
439                                 desc != (*s)->getDescriptors()->end(); ++desc)
440                 {
441                         switch ((*desc)->getTag())
442                         {
443                         case SERVICE_DESCRIPTOR:
444                         {
445                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
446                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
447                                 service->genSortName();
448
449                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
450                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
451                                 break;
452                         }
453                         case CA_IDENTIFIER_DESCRIPTOR:
454                         {
455                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
456                                 const CaSystemIdList &caids = *d.getCaSystemIds();
457                                 SCAN_eDebugNoNewLine("CA ");
458                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
459                                 {
460                                         SCAN_eDebugNoNewLine("%04x ", *i);
461                                         service->m_ca.insert(*i);
462                                 }
463                                 SCAN_eDebug("");
464                                 break;
465                         }
466                         default:
467                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
468                                 break;
469                         }
470                 }
471                 
472                 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));               
473         }
474         return 0;
475 }
476
477 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
478 {
479         connection = new eConnection(this, m_event.connect(event));
480         return 0;
481 }
482
483 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
484 {
485         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
486         transponders_total = m_ch_toScan.size() + transponders_done;
487         services = m_new_services.size();
488 }