added getRunningStatus for event
[openblackhole/openblackhole-enigma2.git] / lib / service / event.cpp
1 #include <lib/service/event.h>
2 #include <lib/base/estring.h>
3 #include <lib/base/encoding.h>
4 #include <lib/dvb/dvbtime.h>
5 #include <lib/dvb/idvb.h>
6 #include <dvbsi++/event_information_section.h>
7 #include <dvbsi++/short_event_descriptor.h>
8 #include <dvbsi++/extended_event_descriptor.h>
9 #include <dvbsi++/linkage_descriptor.h>
10 #include <dvbsi++/component_descriptor.h>
11 #include <dvbsi++/content_descriptor.h>
12 #include <dvbsi++/parental_rating_descriptor.h>
13 #include <dvbsi++/descriptor_tag.h>
14 #include <dvbsi++/pdc_descriptor.h>
15
16 #include <sys/types.h>
17 #include <fcntl.h>
18
19 // static members / methods
20 std::string eServiceEvent::m_language = "---";
21 std::string eServiceEvent::m_language_alternative = "---";
22
23 ///////////////////////////
24
25 DEFINE_REF(eServiceEvent);
26 DEFINE_REF(eComponentData);
27 DEFINE_REF(eGenreData);
28 DEFINE_REF(eParentalData);
29
30 /* search for the presence of language from given EIT event descriptors*/
31 bool eServiceEvent::loadLanguage(Event *evt, const std::string &lang, int tsidonid)
32 {
33         bool retval=0;
34         std::string language = lang;
35         for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
36         {
37                 switch ((*desc)->getTag())
38                 {
39                         case LINKAGE_DESCRIPTOR:
40                                 m_linkage_services.clear();
41                                 break;
42                         case SHORT_EVENT_DESCRIPTOR:
43                         {
44                                 const ShortEventDescriptor *sed = (ShortEventDescriptor*)*desc;
45                                 std::string cc = sed->getIso639LanguageCode();
46                                 std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
47                                 int table=encodingHandler.getCountryCodeDefaultMapping(cc);
48                                 if (language == "---" || language.find(cc) != std::string::npos)
49                                 {
50                                         /* stick to this language, avoid merging or mixing descriptors of different languages */
51                                         language = cc;
52                                         m_event_name += replace_all(replace_all(convertDVBUTF8(sed->getEventName(), table, tsidonid), "\n", " "), "\t", " ");
53                                         m_short_description += convertDVBUTF8(sed->getText(), table, tsidonid);
54                                         retval=1;
55                                 }
56                                 break;
57                         }
58                         case EXTENDED_EVENT_DESCRIPTOR:
59                         {
60                                 const ExtendedEventDescriptor *eed = (ExtendedEventDescriptor*)*desc;
61                                 std::string cc = eed->getIso639LanguageCode();
62                                 std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
63                                 int table=encodingHandler.getCountryCodeDefaultMapping(cc);
64                                 if (language == "---" || language.find(cc) != std::string::npos)
65                                 {
66                                         /* stick to this language, avoid merging or mixing descriptors of different languages */
67                                         language = cc;
68                                         /*
69                                          * Bit of a hack, some providers put the event description partly in the short descriptor,
70                                          * and the remainder in extended event descriptors.
71                                          * In that case, we cannot really treat short/extended description as separate descriptions.
72                                          * Unfortunately we cannot recognise this, but we'll use the length of the short description
73                                          * to guess whether we should concatenate both descriptions (without any spaces)
74                                          */
75                                         if (m_extended_description.empty() && m_short_description.size() >= 180)
76                                         {
77                                                 m_extended_description = m_short_description;
78                                                 m_short_description = "";
79                                         }
80                                         m_extended_description += convertDVBUTF8(eed->getText(), table, tsidonid);
81                                         retval=1;
82                                 }
83 #if 0
84                                 const ExtendedEventList *itemlist = eed->getItems();
85                                 for (ExtendedEventConstIterator it = itemlist->begin(); it != itemlist->end(); ++it)
86                                 {
87                                         m_extended_description += '\n';
88                                         m_extended_description += convertDVBUTF8((*it)->getItemDescription());
89                                         m_extended_description += ' ';
90                                         m_extended_description += convertDVBUTF8((*it)->getItem());
91                                 }
92 #endif
93                                 break;
94                         }
95                         default:
96                                 break;
97                 }
98         }
99         if ( retval == 1 )
100         {
101                 for (DescriptorConstIterator desc = evt->getDescriptors()->begin(); desc != evt->getDescriptors()->end(); ++desc)
102                 {
103                         switch ((*desc)->getTag())
104                         {
105                                 case COMPONENT_DESCRIPTOR:
106                                 {
107                                         const ComponentDescriptor *cp = (ComponentDescriptor*)*desc;
108                                         eComponentData data;
109                                         data.m_streamContent = cp->getStreamContent();
110                                         data.m_componentType = cp->getComponentType();
111                                         data.m_componentTag = cp->getComponentTag();
112                                         data.m_iso639LanguageCode = cp->getIso639LanguageCode();
113                                         std::transform(data.m_iso639LanguageCode.begin(), data.m_iso639LanguageCode.end(), data.m_iso639LanguageCode.begin(), tolower);
114                                         int table=encodingHandler.getCountryCodeDefaultMapping(data.m_iso639LanguageCode);
115                                         data.m_text = convertDVBUTF8(cp->getText(),table,tsidonid);
116                                         m_component_data.push_back(data);
117                                         break;
118                                 }
119                                 case LINKAGE_DESCRIPTOR:
120                                 {
121                                         const LinkageDescriptor  *ld = (LinkageDescriptor*)*desc;
122                                         if ( ld->getLinkageType() == 0xB0 )
123                                         {
124                                                 eServiceReferenceDVB dvb_ref;
125                                                 dvb_ref.type = eServiceReference::idDVB;
126                                                 dvb_ref.setServiceType(1);
127                                                 dvb_ref.setTransportStreamID(ld->getTransportStreamId());
128                                                 dvb_ref.setOriginalNetworkID(ld->getOriginalNetworkId());
129                                                 dvb_ref.setServiceID(ld->getServiceId());
130                                                 const PrivateDataByteVector *privateData = ld->getPrivateDataBytes();
131                                                 dvb_ref.name = convertDVBUTF8((const unsigned char*)&((*privateData)[0]), privateData->size(), 1, tsidonid);
132                                                 m_linkage_services.push_back(dvb_ref);
133                                         }
134                                         break;
135                                 }
136                                 case CONTENT_DESCRIPTOR:
137                                 {
138                                         const ContentDescriptor *cd = (ContentDescriptor *)*desc;
139                                         const ContentClassificationList *con = cd->getClassifications();
140                                         for (ContentClassificationConstIterator it = con->begin(); it != con->end(); ++it)
141                                         {
142                                                 eGenreData data;
143                                                 data.m_level1 = (*it)->getContentNibbleLevel1();
144                                                 data.m_level2 = (*it)->getContentNibbleLevel2();
145                                                 data.m_user1  = (*it)->getUserNibble1();
146                                                 data.m_user2  = (*it)->getUserNibble2();
147                                                 m_genres.push_back(data);
148                                         }
149                                         break;
150                                 }
151                                 case PARENTAL_RATING_DESCRIPTOR:
152                                 {
153                                         const ParentalRatingDescriptor *prd = (ParentalRatingDescriptor *)*desc;
154                                         const ParentalRatingList *par = prd->getParentalRatings();
155                                         for (ParentalRatingConstIterator it = par->begin(); it != par->end(); ++it)
156                                         {
157                                                 eParentalData data;
158
159                                                 data.m_country_code = (*it)->getCountryCode();
160                                                 data.m_rating = (*it)->getRating();
161                                                 m_ratings.push_back(data);
162                                         }
163                                         break;
164                                 }
165                                 case PDC_DESCRIPTOR:
166                                 {
167                                         const PdcDescriptor *pdcd = (PdcDescriptor *)*desc;
168                                         m_pdc_pil = pdcd->getProgrammeIdentificationLabel();
169                                         break;
170                                 }
171                         }
172                 }
173         }
174         if ( m_extended_description.find(m_short_description) == 0 )
175                 m_short_description="";
176         return retval;
177 }
178
179 RESULT eServiceEvent::parseFrom(Event *evt, int tsidonid)
180 {
181         m_begin = parseDVBtime(evt->getStartTimeMjd(), evt->getStartTimeBcd());
182         m_event_id = evt->getEventId();
183         uint32_t duration = evt->getDuration();
184         m_duration = fromBCD(duration>>16)*3600+fromBCD(duration>>8)*60+fromBCD(duration);
185         uint8_t running_status = evt->getRunningStatus();
186         m_running_status = running_status;
187         if (m_language != "---" && loadLanguage(evt, m_language, tsidonid))
188                 return 0;
189         if (m_language_alternative != "---" && loadLanguage(evt, m_language_alternative, tsidonid))
190                 return 0;
191         if (loadLanguage(evt, "eng", tsidonid))
192                 return 0;
193         if (loadLanguage(evt, "---", tsidonid))
194                 return 0;
195         return 0;
196 }
197
198 RESULT eServiceEvent::parseFrom(const std::string& filename, int tsidonid)
199 {
200         if (!filename.empty())
201         {
202                 int fd = ::open( filename.c_str(), O_RDONLY );
203                 if ( fd > -1 )
204                 {
205                         uint8_t buf[4096];
206                         int rd = ::read(fd, buf, 4096);
207                         ::close(fd);
208                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
209                         {
210                                 Event ev(buf);
211                                 parseFrom(&ev, tsidonid);
212                                 return 0;
213                         }
214                 }
215         }
216         return -1;
217 }
218
219 std::string eServiceEvent::getBeginTimeString() const
220 {
221         tm t;
222         localtime_r(&m_begin, &t);
223         char tmp[13];
224         snprintf(tmp, 13, "%02d.%02d, %02d:%02d",
225                 t.tm_mday, t.tm_mon+1,
226                 t.tm_hour, t.tm_min);
227         return std::string(tmp, 12);
228 }
229
230 RESULT eServiceEvent::getGenreData(ePtr<eGenreData> &dest) const
231 {
232         std::list<eGenreData>::const_iterator it = m_genres.begin();
233         for(;it != m_genres.end(); ++it) {
234                 dest = new eGenreData(*it);
235                 //  for now just return the first item on the list
236                 return 0;
237         }
238         dest = 0;
239         return -1;
240 }
241
242 PyObject *eServiceEvent::getGenreData() const
243 {
244         ePyObject ret = PyList_New(m_genres.size());
245         int cnt=0;
246         for (std::list<eGenreData>::const_iterator it(m_genres.begin()); it != m_genres.end(); ++it)
247         {
248                 ePyObject tuple = PyTuple_New(4);
249                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getLevel1()));
250                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLevel2()));
251                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->getUser1()));
252                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->getUser2()));
253                 PyList_SET_ITEM(ret, cnt++, tuple);
254         }
255         return ret;
256 }
257
258 RESULT eServiceEvent::getParentalData(ePtr<eParentalData> &dest) const
259 {
260         std::list<eParentalData>::const_iterator it = m_ratings.begin();
261         for(;it != m_ratings.end(); ++it) {
262                 dest = new eParentalData(*it);
263                 //  for now just return the first item on the list
264                 return 0;
265         }
266         dest = 0;
267         return -1;
268 }
269
270 PyObject *eServiceEvent::getParentalData() const
271 {
272         ePyObject ret = PyList_New(m_ratings.size());
273         int cnt = 0;
274         for (std::list<eParentalData>::const_iterator it(m_ratings.begin()); it != m_ratings.end(); ++it)
275         {
276                 ePyObject tuple = PyTuple_New(2);
277                 PyTuple_SET_ITEM(tuple, 0, PyString_FromString(it->getCountryCode().c_str()));
278                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getRating()));
279                 PyList_SET_ITEM(ret, cnt++, tuple);
280         }
281         return ret;
282 }
283
284 RESULT eServiceEvent::getComponentData(ePtr<eComponentData> &dest, int tagnum) const
285 {
286         std::list<eComponentData>::const_iterator it =
287                 m_component_data.begin();
288         for(;it != m_component_data.end(); ++it)
289         {
290                 if ( it->m_componentTag == tagnum )
291                 {
292                         dest=new eComponentData(*it);
293                         return 0;
294                 }
295         }
296         dest = 0;
297         return -1;
298 }
299
300 PyObject *eServiceEvent::getComponentData() const
301 {
302         ePyObject ret = PyList_New(m_component_data.size());
303         int cnt = 0;
304         for (std::list<eComponentData>::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it)
305         {
306                 ePyObject tuple = PyTuple_New(5);
307                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->m_componentTag));
308                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->m_componentType));
309                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->m_streamContent));
310                 PyTuple_SET_ITEM(tuple, 3, PyString_FromString(it->m_iso639LanguageCode.c_str()));
311                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->m_text.c_str()));
312                 PyList_SET_ITEM(ret, cnt++, tuple);
313         }
314         return ret;
315 }
316
317 RESULT eServiceEvent::getLinkageService(eServiceReference &service, eServiceReference &parent, int num) const
318 {
319         std::list<eServiceReference>::const_iterator it =
320                 m_linkage_services.begin();
321         while( it != m_linkage_services.end() && num-- )
322                 ++it;
323         if ( it != m_linkage_services.end() )
324         {
325                 service = *it;
326                 eServiceReferenceDVB &subservice = (eServiceReferenceDVB&) service;
327                 eServiceReferenceDVB &current = (eServiceReferenceDVB&) parent;
328                 subservice.setDVBNamespace(current.getDVBNamespace());
329                 if ( current.getParentTransportStreamID().get() )
330                 {
331                         subservice.setParentTransportStreamID( current.getParentTransportStreamID() );
332                         subservice.setParentServiceID( current.getParentServiceID() );
333                 }
334                 else
335                 {
336                         subservice.setParentTransportStreamID( current.getTransportStreamID() );
337                         subservice.setParentServiceID( current.getServiceID() );
338                 }
339                 if ( subservice.getParentTransportStreamID() == subservice.getTransportStreamID() &&
340                         subservice.getParentServiceID() == subservice.getServiceID() )
341                 {
342                         subservice.setParentTransportStreamID( eTransportStreamID(0) );
343                         subservice.setParentServiceID( eServiceID(0) );
344                 }
345                 return 0;
346         }
347         service.type = eServiceReference::idInvalid;
348         return -1;
349 }
350
351 DEFINE_REF(eDebugClass);