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