fix no more working extended event descriptions
[enigma2.git] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/estring.h>
7 #include <lib/base/init_num.h>
8 #include <lib/base/init.h>
9 #include <lib/base/nconfig.h> // access to python config
10 #include <lib/dvb/dvb.h>
11 #include <lib/dvb/db.h>
12 #include <lib/dvb/decoder.h>
13
14 #include <lib/components/file_eraser.h>
15 #include <lib/service/servicedvbrecord.h>
16 #include <lib/service/event.h>
17 #include <lib/dvb/metaparser.h>
18 #include <lib/dvb/tstools.h>
19 #include <lib/python/python.h>
20
21                 /* for subtitles */
22 #include <lib/gui/esubtitle.h>
23
24 #include <sys/vfs.h>
25 #include <sys/stat.h>
26
27 #include <byteswap.h>
28 #include <netinet/in.h>
29
30 #ifndef BYTE_ORDER
31 #error no byte order defined!
32 #endif
33
34 #define TSPATH "/media/hdd"
35
36 class eStaticServiceDVBInformation: public iStaticServiceInformation
37 {
38         DECLARE_REF(eStaticServiceDVBInformation);
39 public:
40         RESULT getName(const eServiceReference &ref, std::string &name);
41         int getLength(const eServiceReference &ref);
42         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
43         PyObject *getInfoObject(const eServiceReference &ref, int);
44 };
45
46 DEFINE_REF(eStaticServiceDVBInformation);
47
48 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
49 {
50         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
51         if ( !ref.name.empty() )
52         {
53                 if (service.getParentTransportStreamID().get()) // linkage subservice
54                 {
55                         ePtr<iServiceHandler> service_center;
56                         if (!eServiceCenter::getInstance(service_center))
57                         {
58                                 eServiceReferenceDVB parent = service;
59                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
60                                 parent.setServiceID( service.getParentServiceID() );
61                                 parent.setParentTransportStreamID(eTransportStreamID(0));
62                                 parent.setParentServiceID(eServiceID(0));
63                                 parent.name="";
64                                 ePtr<iStaticServiceInformation> service_info;
65                                 if (!service_center->info(parent, service_info))
66                                 {
67                                         if (!service_info->getName(parent, name))
68                                                 name=buildShortName(name) + " - ";
69                                 }
70                         }
71                 }
72                 else
73                         name="";
74                 name += ref.name;
75                 return 0;
76         }
77         else
78                 return -1;
79 }
80
81 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
82 {
83         return -1;
84 }
85
86 int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
87 {
88         ePtr<eDVBResourceManager> res_mgr;
89         if ( eDVBResourceManager::getInstance( res_mgr ) )
90                 eDebug("isPlayable... no res manager!!");
91         else
92         {
93                 eDVBChannelID chid, chid_ignore;
94                 ((const eServiceReferenceDVB&)ref).getChannelID(chid);
95                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
96                 return res_mgr->canAllocateChannel(chid, chid_ignore);
97         }
98         return false;
99 }
100
101 static void PutToDict(ePyObject &dict, const char*key, long value)
102 {
103         ePyObject item = PyString_FromFormat("%d", value);
104         if (item)
105         {
106                 if (PyDict_SetItemString(dict, key, item))
107                         eDebug("put %s to dict failed", key);
108                 Py_DECREF(item);
109         }
110         else
111                 eDebug("could not create PyObject for %s", key);
112 }
113
114 extern void PutToDict(ePyObject &dict, const char*key, const char *value);
115
116 void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
117 {
118         const char *tmp=0;
119         PutToDict(dict, "type", "Satellite");
120         PutToDict(dict, "frequency", feparm.frequency);
121         PutToDict(dict, "symbolrate", feparm.symbol_rate);
122         PutToDict(dict, "orbital position", feparm.orbital_position);
123         switch (feparm.inversion)
124         {
125                 case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
126                 case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
127                 default:
128                 case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
129         }
130         PutToDict(dict, "inversion", tmp);
131         switch (feparm.fec)
132         {
133                 case eDVBFrontendParametersSatellite::FEC::fNone: tmp="NONE"; break;
134                 case eDVBFrontendParametersSatellite::FEC::f1_2: tmp="1/2"; break;
135                 case eDVBFrontendParametersSatellite::FEC::f2_3: tmp="2/3"; break;
136                 case eDVBFrontendParametersSatellite::FEC::f3_4: tmp="3/4"; break;
137                 case eDVBFrontendParametersSatellite::FEC::f5_6: tmp="5/6"; break;
138                 case eDVBFrontendParametersSatellite::FEC::f7_8: tmp="7/8"; break;
139                 case eDVBFrontendParametersSatellite::FEC::f3_5: tmp="3/5"; break;
140                 case eDVBFrontendParametersSatellite::FEC::f4_5: tmp="4/5"; break;
141                 case eDVBFrontendParametersSatellite::FEC::f8_9: tmp="8/9"; break;
142                 case eDVBFrontendParametersSatellite::FEC::f9_10: tmp="9/10"; break;
143                 default:
144                 case eDVBFrontendParametersSatellite::FEC::fAuto: tmp="AUTO"; break;
145         }
146         PutToDict(dict, "fec inner", tmp);
147         switch (feparm.modulation)
148         {
149                 case eDVBFrontendParametersSatellite::Modulation::Auto: tmp="AUTO"; break;
150                 case eDVBFrontendParametersSatellite::Modulation::QPSK: tmp="QPSK"; break;
151                 case eDVBFrontendParametersSatellite::Modulation::M8PSK: tmp="8PSK"; break;
152                 case eDVBFrontendParametersSatellite::Modulation::QAM_16: tmp="QAM16"; break;
153         }
154         PutToDict(dict, "modulation", tmp);
155         switch(feparm.polarisation)
156         {
157                 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
158                 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
159                 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR LEFT"; break;
160                 default:
161                 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR RIGHT"; break;
162         }
163         PutToDict(dict, "polarization", tmp);
164         switch(feparm.system)
165         {
166                 default:
167                 case eDVBFrontendParametersSatellite::System::DVB_S: tmp="DVB-S"; break;
168                 case eDVBFrontendParametersSatellite::System::DVB_S2:
169                         switch(feparm.roll_off)
170                         {
171                                 case eDVBFrontendParametersSatellite::RollOff::alpha_0_35: tmp="0.35"; break;
172                                 case eDVBFrontendParametersSatellite::RollOff::alpha_0_25: tmp="0.25"; break;
173                                 case eDVBFrontendParametersSatellite::RollOff::alpha_0_20: tmp="0.20"; break;
174                                 default:
175                                 case eDVBFrontendParametersSatellite::RollOff::alpha_auto: tmp="AUTO"; break;
176                         }
177                         PutToDict(dict, "roll off", tmp);
178                         tmp="DVB-S2";
179                         break;
180         }
181         PutToDict(dict, "system", tmp);
182 }
183
184 void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
185 {
186         PutToDict(dict, "type", "Terrestrial");
187         PutToDict(dict, "frequency", feparm.frequency);
188         const char *tmp=0;
189         switch (feparm.bandwidth)
190         {
191         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz: tmp="8 MHz"; break;
192         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz: tmp="7 MHz"; break;
193         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz: tmp="6 MHz"; break;
194         default:
195         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto: tmp="AUTO"; break;
196         }
197         PutToDict(dict, "bandwidth", tmp);
198         switch (feparm.code_rate_LP)
199         {
200         case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
201         case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
202         case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
203         case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
204         case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
205         default:
206         case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
207         }
208         PutToDict(dict, "code rate lp", tmp);
209         switch (feparm.code_rate_HP)
210         {
211         case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
212         case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
213         case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
214         case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
215         case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
216         default:
217         case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
218         }
219         PutToDict(dict, "code rate hp", tmp);
220         switch (feparm.modulation)
221         {
222         case eDVBFrontendParametersTerrestrial::Modulation::QPSK: tmp="QPSK"; break;
223         case eDVBFrontendParametersTerrestrial::Modulation::QAM16: tmp="QAM16"; break;
224         case eDVBFrontendParametersTerrestrial::Modulation::QAM64: tmp="QAM64"; break;
225         default:
226         case eDVBFrontendParametersTerrestrial::Modulation::Auto: tmp="AUTO"; break;
227         }
228         PutToDict(dict, "constellation", tmp);
229         switch (feparm.transmission_mode)
230         {
231         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k: tmp="2k"; break;
232         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k: tmp="8k"; break;
233         default:
234         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto: tmp="AUTO"; break;
235         }
236         PutToDict(dict, "transmission mode", tmp);
237         switch (feparm.guard_interval)
238         {
239                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32: tmp="1/32"; break;
240                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16: tmp="1/16"; break;
241                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8: tmp="1/8"; break;
242                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4: tmp="1/4"; break;
243                 default:
244                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto: tmp="AUTO"; break;
245         }
246         PutToDict(dict, "guard interval", tmp);
247         switch (feparm.hierarchy)
248         {
249                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone: tmp="NONE"; break;
250                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1: tmp="1"; break;
251                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2: tmp="2"; break;
252                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4: tmp="4"; break;
253                 default:
254                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto: tmp="AUTO"; break;
255         }
256         PutToDict(dict, "hierarchy", tmp);
257         switch (feparm.inversion)
258         {
259                 case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
260                 case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
261                 default:
262                 case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
263         }
264         PutToDict(dict, "inversion", tmp);
265 }
266
267 void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
268 {
269         const char *tmp=0;
270         PutToDict(dict, "type", "Cable");
271         PutToDict(dict, "frequency", feparm.frequency);
272         PutToDict(dict, "symbolrate", feparm.symbol_rate);
273         switch (feparm.modulation)
274         {
275         case eDVBFrontendParametersCable::Modulation::QAM16: tmp="QAM16"; break;
276         case eDVBFrontendParametersCable::Modulation::QAM32: tmp="QAM32"; break;
277         case eDVBFrontendParametersCable::Modulation::QAM64: tmp="QAM64"; break;
278         case eDVBFrontendParametersCable::Modulation::QAM128: tmp="QAM128"; break;
279         case eDVBFrontendParametersCable::Modulation::QAM256: tmp="QAM256"; break;
280         default:
281         case eDVBFrontendParametersCable::Modulation::Auto: tmp="AUTO"; break;
282         }
283         PutToDict(dict, "modulation", tmp);
284         switch (feparm.inversion)
285         {
286         case eDVBFrontendParametersCable::Inversion::On: tmp="ON"; break;
287         case eDVBFrontendParametersCable::Inversion::Off: tmp="OFF"; break;
288         default:
289         case eDVBFrontendParametersCable::Inversion::Unknown: tmp="AUTO"; break;
290         }
291         PutToDict(dict, "inversion", tmp);
292         switch (feparm.fec_inner)
293         {
294         case eDVBFrontendParametersCable::FEC::fNone: tmp="NONE"; break;
295         case eDVBFrontendParametersCable::FEC::f1_2: tmp="1/2"; break;
296         case eDVBFrontendParametersCable::FEC::f2_3: tmp="2/3"; break;
297         case eDVBFrontendParametersCable::FEC::f3_4: tmp="3/4"; break;
298         case eDVBFrontendParametersCable::FEC::f5_6: tmp="5/6"; break;
299         case eDVBFrontendParametersCable::FEC::f7_8: tmp="7/8"; break;
300         case eDVBFrontendParametersCable::FEC::f8_9: tmp="8/9"; break;
301         default:
302         case eDVBFrontendParametersCable::FEC::fAuto: tmp="AUTO"; break;
303         }
304         PutToDict(dict, "fec inner", tmp);
305 }
306
307 PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
308 {
309         if (r.type == eServiceReference::idDVB)
310         {
311                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
312                 switch(what)
313                 {
314                         case iServiceInformation::sTransponderData:
315                         {
316                                 ePtr<eDVBResourceManager> res;
317                                 if (!eDVBResourceManager::getInstance(res))
318                                 {
319                                         ePtr<iDVBChannelList> db;
320                                         if (!res->getChannelList(db))
321                                         {
322                                                 eDVBChannelID chid;
323                                                 ref.getChannelID(chid);
324                                                 ePtr<iDVBFrontendParameters> feparm;
325                                                 if (!db->getChannelFrontendData(chid, feparm))
326                                                 {
327                                                         int system;
328                                                         if (!feparm->getSystem(system))
329                                                         {
330                                                                 ePyObject dict = PyDict_New();
331                                                                 switch(system)
332                                                                 {
333                                                                         case iDVBFrontend::feSatellite:
334                                                                         {
335                                                                                 eDVBFrontendParametersSatellite s;
336                                                                                 feparm->getDVBS(s);
337                                                                                 PutSatelliteDataToDict(dict, s);
338                                                                                 break;
339                                                                         }
340                                                                         case iDVBFrontend::feTerrestrial:
341                                                                         {
342                                                                                 eDVBFrontendParametersTerrestrial t;
343                                                                                 feparm->getDVBT(t);
344                                                                                 PutTerrestrialDataToDict(dict, t);
345                                                                                 break;
346                                                                         }
347                                                                         case iDVBFrontend::feCable:
348                                                                         {
349                                                                                 eDVBFrontendParametersCable c;
350                                                                                 feparm->getDVBC(c);
351                                                                                 PutCableDataToDict(dict, c);
352                                                                                 break;
353                                                                         }
354                                                                         default:
355                                                                                 eDebug("unknown frontend type %d", system);
356                                                                                 Py_DECREF(dict);
357                                                                                 break;
358                                                                 }
359                                                                 return dict;
360                                                         }
361                                                 }
362                                         }
363                                 }
364                         }
365                 }
366         }
367         Py_RETURN_NONE;
368 }
369
370 DEFINE_REF(eStaticServiceDVBBouquetInformation);
371
372 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
373 {
374         ePtr<iDVBChannelList> db;
375         ePtr<eDVBResourceManager> res;
376
377         int err;
378         if ((err = eDVBResourceManager::getInstance(res)) != 0)
379         {
380                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
381                 return err;
382         }
383         if ((err = res->getChannelList(db)) != 0)
384         {
385                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
386                 return err;
387         }
388
389         eBouquet *bouquet=0;
390         if ((err = db->getBouquet(ref, bouquet)) != 0)
391         {
392                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
393                 return -1;
394         }
395
396         if ( bouquet && bouquet->m_bouquet_name.length() )
397         {
398                 name = bouquet->m_bouquet_name;
399                 return 0;
400         }
401         else
402                 return -1;
403 }
404
405 int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
406 {
407         if (ref.flags & eServiceReference::isGroup)
408         {
409                 ePtr<iDVBChannelList> db;
410                 ePtr<eDVBResourceManager> res;
411
412                 if (eDVBResourceManager::getInstance(res))
413                 {
414                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
415                         return 0;
416                 }
417
418                 if (res->getChannelList(db))
419                 {
420                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
421                         return 0;
422                 }
423
424                 eBouquet *bouquet=0;
425                 if (db->getBouquet(ref, bouquet))
426                 {
427                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
428                         return 0;
429                 }
430
431                 int cur=0;
432                 eDVBChannelID chid, chid_ignore;
433                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
434                 for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
435                 {
436                         ((const eServiceReferenceDVB&)*it).getChannelID(chid);
437                         int tmp=res->canAllocateChannel(chid, chid_ignore);
438                         if (tmp > cur)
439                         {
440                                 m_playable_service = *it;
441                                 cur = tmp;
442                         }
443                 }
444                 if (cur)
445                         return cur;
446         }
447         m_playable_service = eServiceReference();
448         return 0;
449 }
450
451 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
452 {
453         return -1;
454 }
455
456 #include <lib/dvb/epgcache.h>
457
458 RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
459 {
460         return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
461 }
462
463 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
464 {
465         DECLARE_REF(eStaticServiceDVBPVRInformation);
466         eServiceReference m_ref;
467         eDVBMetaParser m_parser;
468 public:
469         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
470         RESULT getName(const eServiceReference &ref, std::string &name);
471         int getLength(const eServiceReference &ref);
472         RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
473         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
474         int getInfo(const eServiceReference &ref, int w);
475         std::string getInfoString(const eServiceReference &ref,int w);
476 };
477
478 DEFINE_REF(eStaticServiceDVBPVRInformation);
479
480 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
481 {
482         m_ref = ref;
483         m_parser.parseFile(ref.path);
484 }
485
486 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
487 {
488         ASSERT(ref == m_ref);
489         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
490         return 0;
491 }
492
493 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
494 {
495         ASSERT(ref == m_ref);
496         
497         eDVBTSTools tstools;
498         
499         if (tstools.openFile(ref.path.c_str()))
500                 return 0;
501
502         pts_t len;
503         if (tstools.calcLen(len))
504                 return 0;
505
506         return len / 90000;
507 }
508
509 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
510 {
511         switch (w)
512         {
513         case iServiceInformation::sDescription:
514                 return iServiceInformation::resIsString;
515         case iServiceInformation::sServiceref:
516                 return iServiceInformation::resIsString;
517         case iServiceInformation::sTimeCreate:
518                 if (m_parser.m_time_create)
519                         return m_parser.m_time_create;
520                 else
521                         return iServiceInformation::resNA;
522         default:
523                 return iServiceInformation::resNA;
524         }
525 }
526
527 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
528 {
529         switch (w)
530         {
531         case iServiceInformation::sDescription:
532                 return m_parser.m_description;
533         case iServiceInformation::sServiceref:
534                 return m_parser.m_ref.toString();
535         case iServiceInformation::sTags:
536                 return m_parser.m_tags;
537         default:
538                 return "";
539         }
540 }
541
542 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
543 {
544         if (!ref.path.empty())
545         {
546                 ePtr<eServiceEvent> event = new eServiceEvent;
547                 std::string filename = ref.path;
548                 filename.erase(filename.length()-2, 2);
549                 filename+="eit";
550                 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
551                 {
552                         evt = event;
553                         return 0;
554                 }
555         }
556         evt = 0;
557         return -1;
558 }
559
560 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
561 {
562         DECLARE_REF(eDVBPVRServiceOfflineOperations);
563         eServiceReferenceDVB m_ref;
564 public:
565         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
566         
567         RESULT deleteFromDisk(int simulate);
568         RESULT getListOfFilenames(std::list<std::string> &);
569 };
570
571 DEFINE_REF(eDVBPVRServiceOfflineOperations);
572
573 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
574 {
575 }
576
577 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
578 {
579         if (simulate)
580                 return 0;
581         else
582         {
583                 std::list<std::string> res;
584                 if (getListOfFilenames(res))
585                         return -1;
586                 
587                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
588                 if (!eraser)
589                         eDebug("FATAL !! can't get background file eraser");
590                 
591                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
592                 {
593                         eDebug("Removing %s...", i->c_str());
594                         if (eraser)
595                                 eraser->erase(i->c_str());
596                         else
597                                 ::unlink(i->c_str());
598                 }
599                 
600                 return 0;
601         }
602 }
603
604 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
605 {
606         res.clear();
607         res.push_back(m_ref.path);
608
609 // handling for old splitted recordings (enigma 1)
610         char buf[255];
611         int slice=1;
612         while(true)
613         {
614                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
615                 struct stat s;
616                 if (stat(buf, &s) < 0)
617                         break;
618                 res.push_back(buf);
619         }       
620
621         res.push_back(m_ref.path + ".meta");
622         res.push_back(m_ref.path + ".ap");
623         res.push_back(m_ref.path + ".cuts");
624         std::string tmp = m_ref.path;
625         tmp.erase(m_ref.path.length()-3);
626         res.push_back(tmp + ".eit");
627         return 0;
628 }
629
630 DEFINE_REF(eServiceFactoryDVB)
631
632 eServiceFactoryDVB::eServiceFactoryDVB()
633 {
634         ePtr<eServiceCenter> sc;
635         
636         eServiceCenter::getPrivInstance(sc);
637         if (sc)
638                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
639
640         m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
641         m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
642 }
643
644 eServiceFactoryDVB::~eServiceFactoryDVB()
645 {
646         ePtr<eServiceCenter> sc;
647         
648         eServiceCenter::getPrivInstance(sc);
649         if (sc)
650                 sc->removeServiceFactory(eServiceFactoryDVB::id);
651 }
652
653 DEFINE_REF(eDVBServiceList);
654
655 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
656 {
657 }
658
659 eDVBServiceList::~eDVBServiceList()
660 {
661 }
662
663 RESULT eDVBServiceList::startQuery()
664 {
665         ePtr<iDVBChannelList> db;
666         ePtr<eDVBResourceManager> res;
667         
668         int err;
669         if ((err = eDVBResourceManager::getInstance(res)) != 0)
670         {
671                 eDebug("no resource manager");
672                 return err;
673         }
674         if ((err = res->getChannelList(db)) != 0)
675         {
676                 eDebug("no channel list");
677                 return err;
678         }
679         
680         ePtr<eDVBChannelQuery> q;
681         
682         if (!m_parent.path.empty())
683         {
684                 eDVBChannelQuery::compile(q, m_parent.path);
685                 if (!q)
686                 {
687                         eDebug("compile query failed");
688                         return err;
689                 }
690         }
691         
692         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
693         {
694                 eDebug("startQuery failed");
695                 return err;
696         }
697
698         return 0;
699 }
700
701 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
702 {
703         eServiceReferenceDVB ref;
704         
705         if (!m_query)
706                 return -1;
707
708         while (!m_query->getNextResult(ref))
709                 list.push_back(ref);
710
711         if (sorted)
712                 list.sort(iListableServiceCompare(this));
713
714         return 0;
715 }
716
717 //   The first argument of this function is a format string to specify the order and
718 //   the content of the returned list
719 //   useable format options are
720 //   R = Service Reference (as swig object .. this is very slow)
721 //   S = Service Reference (as python string object .. same as ref.toString())
722 //   C = Service Reference (as python string object .. same as ref.toCompareString())
723 //   N = Service Name (as python string object)
724 //   n = Short Service Name (short name brakets used) (as python string object)
725 //   when exactly one return value per service is selected in the format string,
726 //   then each value is directly a list entry
727 //   when more than one value is returned per service, then the list is a list of
728 //   python tuples
729 //   unknown format string chars are returned as python None values !
730 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
731 {
732         ePyObject ret;
733         std::list<eServiceReference> tmplist;
734         int retcount=1;
735
736         if (!format || !(retcount=strlen(format)))
737                 format = "R"; // just return service reference swig object ...
738
739         if (!getContent(tmplist, sorted))
740         {
741                 int services=tmplist.size();
742                 ePtr<iStaticServiceInformation> sptr;
743                 eServiceCenterPtr service_center;
744
745                 if (strchr(format, 'N') || strchr(format, 'n'))
746                         eServiceCenter::getPrivInstance(service_center);
747
748                 ret = PyList_New(services);
749                 std::list<eServiceReference>::iterator it(tmplist.begin());
750
751                 for (int cnt=0; cnt < services; ++cnt)
752                 {
753                         eServiceReference &ref=*it++;
754                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
755                         for (int i=0; i < retcount; ++i)
756                         {
757                                 ePyObject tmp;
758                                 switch(format[i])
759                                 {
760                                 case 'R':  // service reference (swig)object
761                                         tmp = NEW_eServiceReference(ref);
762                                         break;
763                                 case 'C':  // service reference compare string
764                                         tmp = PyString_FromString(ref.toCompareString().c_str());
765                                         break;
766                                 case 'S':  // service reference string
767                                         tmp = PyString_FromString(ref.toString().c_str());
768                                         break;
769                                 case 'N':  // service name
770                                         if (service_center)
771                                         {
772                                                 service_center->info(ref, sptr);
773                                                 if (sptr)
774                                                 {
775                                                         std::string name;
776                                                         sptr->getName(ref, name);
777
778                                                         // filter short name brakets
779                                                         unsigned int pos;
780                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
781                                                                 name.erase(pos,2);
782                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
783                                                                 name.erase(pos,2);
784
785                                                         if (name.length())
786                                                                 tmp = PyString_FromString(name.c_str());
787                                                 }
788                                         }
789                                         if (!tmp)
790                                                 tmp = PyString_FromString("<n/a>");
791                                         break;
792                                 case 'n':  // short service name
793                                         if (service_center)
794                                         {
795                                                 service_center->info(ref, sptr);
796                                                 if (sptr)
797                                                 {
798                                                         std::string name;
799                                                         sptr->getName(ref, name);
800                                                         name = buildShortName(name);
801                                                         if (name.length())
802                                                                 tmp = PyString_FromString(name.c_str());
803                                                 }
804                                         }
805                                         if (!tmp)
806                                                 tmp = PyString_FromString("<n/a>");
807                                         break;
808                                 default:
809                                         if (tuple)
810                                         {
811                                                 tmp = Py_None;
812                                                 Py_INCREF(Py_None);
813                                         }
814                                         break;
815                                 }
816                                 if (tmp)
817                                 {
818                                         if (tuple)
819                                                 PyTuple_SET_ITEM(tuple, i, tmp);
820                                         else
821                                                 PyList_SET_ITEM(ret, cnt, tmp);
822                                 }
823                         }
824                         if (tuple)
825                                 PyList_SET_ITEM(ret, cnt, tuple);
826                 }
827         }
828         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
829 }
830
831 RESULT eDVBServiceList::getNext(eServiceReference &ref)
832 {
833         if (!m_query)
834                 return -1;
835         
836         return m_query->getNextResult((eServiceReferenceDVB&)ref);
837 }
838
839 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
840 {
841         if (m_parent.flags & eServiceReference::canDescent) // bouquet
842         {
843                 ePtr<iDVBChannelList> db;
844                 ePtr<eDVBResourceManager> resm;
845
846                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
847                         return -1;
848
849                 if (db->getBouquet(m_parent, m_bouquet) != 0)
850                         return -1;
851
852                 res = this;
853                 
854                 return 0;
855         }
856         res = 0;
857         return -1;
858 }
859
860 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
861 {
862         if (!m_bouquet)
863                 return -1;
864         return m_bouquet->addService(ref, before);
865 }
866
867 RESULT eDVBServiceList::removeService(eServiceReference &ref)
868 {
869         if (!m_bouquet)
870                 return -1;
871         return m_bouquet->removeService(ref);
872 }
873
874 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
875 {
876         if (!m_bouquet)
877                 return -1;
878         return m_bouquet->moveService(ref, pos);
879 }
880
881 RESULT eDVBServiceList::flushChanges()
882 {
883         if (!m_bouquet)
884                 return -1;
885         return m_bouquet->flushChanges();
886 }
887
888 RESULT eDVBServiceList::setListName(const std::string &name)
889 {
890         if (!m_bouquet)
891                 return -1;
892         return m_bouquet->setListName(name);
893 }
894
895 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
896 {
897         ePtr<eDVBService> service;
898         int r = lookupService(service, ref);
899         if (r)
900                 service = 0;
901                 // check resources...
902         ptr = new eDVBServicePlay(ref, service);
903         return 0;
904 }
905
906 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
907 {
908         if (ref.path.empty())
909         {
910                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
911                 return 0;
912         } else
913         {
914                 ptr = 0;
915                 return -1;
916         }
917 }
918
919 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
920 {
921         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
922         if (list->startQuery())
923         {
924                 ptr = 0;
925                 return -1;
926         }
927         
928         ptr = list;
929         return 0;
930 }
931
932 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
933 {
934         /* is a listable service? */
935         if (ref.flags & eServiceReference::canDescent) // bouquet
936         {
937                 if ( !ref.name.empty() )  // satellites or providers list
938                         ptr = m_StaticServiceDVBInfo;
939                 else // a dvb bouquet
940                         ptr = m_StaticServiceDVBBouquetInfo;
941         }
942         else if (!ref.path.empty()) /* do we have a PVR service? */
943                 ptr = new eStaticServiceDVBPVRInformation(ref);
944         else // normal dvb service
945         {
946                 ePtr<eDVBService> service;
947                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
948                         ptr = m_StaticServiceDVBInfo;
949                 else
950                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
951                         ptr = service;
952         }
953         return 0;
954 }
955
956 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
957 {
958         if (ref.path.empty())
959         {
960                 ptr = 0;
961                 return -1;
962         } else
963         {
964                 ptr = new eDVBPVRServiceOfflineOperations(ref);
965                 return 0;
966         }
967 }
968
969 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
970 {
971                         // TODO: handle the listing itself
972         // if (ref.... == -1) .. return "... bouquets ...";
973         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
974                         // TODO: cache
975         ePtr<iDVBChannelList> db;
976         ePtr<eDVBResourceManager> res;
977         
978         int err;
979         if ((err = eDVBResourceManager::getInstance(res)) != 0)
980         {
981                 eDebug("no resource manager");
982                 return err;
983         }
984         if ((err = res->getChannelList(db)) != 0)
985         {
986                 eDebug("no channel list");
987                 return err;
988         }
989         
990                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
991         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
992         {
993                 eDebug("getService failed!");
994                 return err;
995         }
996
997         return 0;
998 }
999
1000 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
1001         m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
1002 {
1003         memset(&m_videoEventData, 0, sizeof(struct iTSMPEGDecoder::videoEvent));
1004         m_is_primary = 1;
1005         m_is_pvr = !m_reference.path.empty();
1006         
1007         m_timeshift_enabled = m_timeshift_active = 0;
1008         m_skipmode = 0;
1009         
1010         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
1011         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
1012         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
1013
1014         m_cuesheet_changed = 0;
1015         m_cutlist_enabled = 1;
1016         
1017         m_subtitle_widget = 0;
1018         
1019         m_tune_state = -1;
1020         
1021         CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
1022 }
1023
1024 eDVBServicePlay::~eDVBServicePlay()
1025 {
1026         delete m_subtitle_widget;
1027 }
1028
1029 void eDVBServicePlay::gotNewEvent()
1030 {
1031 #if 0
1032                 // debug only
1033         ePtr<eServiceEvent> m_event_now, m_event_next;
1034         getEvent(m_event_now, 0);
1035         getEvent(m_event_next, 1);
1036
1037         if (m_event_now)
1038                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
1039         if (m_event_next)
1040                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
1041 #endif
1042         m_event((iPlayableService*)this, evUpdatedEventInfo);
1043 }
1044
1045 void eDVBServicePlay::serviceEvent(int event)
1046 {
1047         m_tune_state = event;
1048
1049         switch (event)
1050         {
1051         case eDVBServicePMTHandler::eventTuned:
1052         {
1053                 ePtr<iDVBDemux> m_demux;
1054                 if (!m_service_handler.getDataDemux(m_demux))
1055                 {
1056                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
1057                         int sid = ref.getParentServiceID().get();
1058                         if (!sid)
1059                                 sid = ref.getServiceID().get();
1060                         if ( ref.getParentTransportStreamID().get() &&
1061                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
1062                                 m_event_handler.startOther(m_demux, sid);
1063                         else
1064                                 m_event_handler.start(m_demux, sid);
1065                 }
1066                 break;
1067         }
1068         case eDVBServicePMTHandler::eventNoResources:
1069         case eDVBServicePMTHandler::eventNoPAT:
1070         case eDVBServicePMTHandler::eventNoPATEntry:
1071         case eDVBServicePMTHandler::eventNoPMT:
1072         case eDVBServicePMTHandler::eventTuneFailed:
1073         {
1074                 eDebug("DVB service failed to tune - error %d", event);
1075                 m_event((iPlayableService*)this, evTuneFailed);
1076                 break;
1077         }
1078         case eDVBServicePMTHandler::eventNewProgramInfo:
1079         {
1080                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
1081                 if (m_timeshift_enabled)
1082                         updateTimeshiftPids();
1083                 if (!m_timeshift_active)
1084                         updateDecoder();
1085                 if (m_first_program_info && m_is_pvr)
1086                 {
1087                         m_first_program_info = 0;
1088                         seekTo(0);
1089                 }
1090                 m_event((iPlayableService*)this, evUpdatedInfo);
1091                 break;
1092         }
1093         case eDVBServicePMTHandler::eventEOF:
1094                 m_event((iPlayableService*)this, evEOF);
1095                 break;
1096         case eDVBServicePMTHandler::eventSOF:
1097                 m_event((iPlayableService*)this, evSOF);
1098                 break;
1099         }
1100 }
1101
1102 void eDVBServicePlay::serviceEventTimeshift(int event)
1103 {
1104         switch (event)
1105         {
1106         case eDVBServicePMTHandler::eventNewProgramInfo:
1107                 if (m_timeshift_active)
1108                         updateDecoder();
1109                 break;
1110         case eDVBServicePMTHandler::eventSOF:
1111                 m_event((iPlayableService*)this, evSOF);
1112                 break;
1113         case eDVBServicePMTHandler::eventEOF:
1114                 switchToLive();
1115                 break;
1116         }
1117 }
1118
1119 RESULT eDVBServicePlay::start()
1120 {
1121         int r;
1122                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
1123                    two (one for decoding, one for data source), as we must be prepared
1124                    to start recording from the data demux. */
1125         if (m_is_pvr)
1126                 m_cue = new eCueSheet();
1127         else
1128                 m_event(this, evStart);
1129
1130         m_first_program_info = 1;
1131         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
1132         r = m_service_handler.tune(service, m_is_pvr, m_cue);
1133
1134                 /* inject EIT if there is a stored one */
1135         if (m_is_pvr)
1136         {
1137                 std::string filename = service.path;
1138                 filename.erase(filename.length()-2, 2);
1139                 filename+="eit";
1140                 ePtr<eServiceEvent> event = new eServiceEvent;
1141                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
1142                 {
1143                         ePtr<eServiceEvent> empty;
1144                         m_event_handler.inject(event, 0);
1145                         m_event_handler.inject(empty, 1);
1146                 }
1147         }
1148
1149         if (m_is_pvr)
1150         {
1151                 loadCuesheet();
1152                 m_event(this, evStart);
1153         }
1154
1155         m_event((iPlayableService*)this, evSeekableStatusChanged);
1156         return 0;
1157 }
1158
1159 RESULT eDVBServicePlay::stop()
1160 {
1161                 /* add bookmark for last play position */
1162         if (m_is_pvr)
1163         {
1164                 pts_t play_position;
1165                 if (!getPlayPosition(play_position))
1166                 {
1167                                 /* remove last position */
1168                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
1169                         {
1170                                 if (i->what == 3) /* current play position */
1171                                 {
1172                                         m_cue_entries.erase(i);
1173                                         i = m_cue_entries.begin();
1174                                         continue;
1175                                 } else
1176                                         ++i;
1177                         }
1178                         
1179                         m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
1180                         m_cuesheet_changed = 1;
1181                 }
1182         }
1183
1184         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
1185
1186         m_service_handler_timeshift.free();
1187         m_service_handler.free();
1188         
1189         if (m_is_pvr && m_cuesheet_changed)
1190         {
1191                 struct stat s;
1192                                 /* save cuesheet only when main file is accessible. */
1193                 if (!::stat(m_reference.path.c_str(), &s))
1194                         saveCuesheet();
1195         }
1196         m_event((iPlayableService*)this, evStopped);
1197         return 0;
1198 }
1199
1200 RESULT eDVBServicePlay::setTarget(int target)
1201 {
1202         m_is_primary = !target;
1203         return 0;
1204 }
1205
1206 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
1207 {
1208         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
1209         return 0;
1210 }
1211
1212 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
1213 {
1214                 /* note: we check for timeshift to be enabled,
1215                    not neccessary active. if you pause when timeshift
1216                    is not active, you should activate it when unpausing */
1217         if ((!m_is_pvr) && (!m_timeshift_enabled))
1218         {
1219                 ptr = 0;
1220                 return -1;
1221         }
1222
1223         ptr = this;
1224         return 0;
1225 }
1226
1227 RESULT eDVBServicePlay::setSlowMotion(int ratio)
1228 {
1229         if (m_decoder)
1230                 return m_decoder->setSlowMotion(ratio);
1231         else
1232                 return -1;
1233 }
1234
1235 RESULT eDVBServicePlay::setFastForward(int ratio)
1236 {
1237         int skipmode, ffratio;
1238         
1239         if (ratio > 8)
1240         {
1241                 skipmode = ratio;
1242                 ffratio = 1;
1243         } else if (ratio > 0)
1244         {
1245                 skipmode = 0;
1246                 ffratio = ratio;
1247         } else if (!ratio)
1248         {
1249                 skipmode = 0;
1250                 ffratio = 0;
1251         } else // if (ratio < 0)
1252         {
1253                 skipmode = ratio;
1254                 ffratio = 1;
1255         }
1256
1257         if (m_skipmode != skipmode)
1258         {
1259                 eDebug("setting cue skipmode to %d", skipmode);
1260                 if (m_cue)
1261                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
1262         }
1263         
1264         m_skipmode = skipmode;
1265         
1266         if (!m_decoder)
1267                 return -1;
1268
1269         return m_decoder->setFastForward(ffratio);
1270 }
1271     
1272 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
1273 {
1274         if (m_is_pvr || m_timeshift_enabled)
1275         {
1276                 ptr = this;
1277                 return 0;
1278         }
1279         
1280         ptr = 0;
1281         return -1;
1282 }
1283
1284         /* TODO: when timeshift is enabled but not active, this doesn't work. */
1285 RESULT eDVBServicePlay::getLength(pts_t &len)
1286 {
1287         ePtr<iDVBPVRChannel> pvr_channel;
1288         
1289         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1290                 return -1;
1291         
1292         return pvr_channel->getLength(len);
1293 }
1294
1295 RESULT eDVBServicePlay::pause()
1296 {
1297         if (!m_is_paused && m_decoder)
1298         {
1299                 m_is_paused = 1;
1300                 return m_decoder->freeze(0);
1301         } else
1302                 return -1;
1303 }
1304
1305 RESULT eDVBServicePlay::unpause()
1306 {
1307         if (m_is_paused && m_decoder)
1308         {
1309                 m_is_paused = 0;
1310                 return m_decoder->unfreeze();
1311         } else
1312                 return -1;
1313 }
1314
1315 RESULT eDVBServicePlay::seekTo(pts_t to)
1316 {
1317         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
1318         
1319         if (!m_decode_demux)
1320                 return -1;
1321
1322         ePtr<iDVBPVRChannel> pvr_channel;
1323         
1324         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1325                 return -1;
1326         
1327         if (!m_cue)
1328                 return -1;
1329         
1330         m_cue->seekTo(0, to);
1331         return 0;
1332 }
1333
1334 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
1335 {
1336         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
1337         
1338         if (!m_decode_demux)
1339                 return -1;
1340
1341         ePtr<iDVBPVRChannel> pvr_channel;
1342         
1343         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1344                 return -1;
1345         
1346         int mode = 1;
1347         
1348                         /* HACK until we have skip-AP api */
1349         if ((to > 0) && (to < 100))
1350                 mode = 2;
1351         
1352         to *= direction;
1353         
1354         if (!m_cue)
1355                 return 0;
1356         
1357         m_cue->seekTo(mode, to);
1358         return 0;
1359 }
1360
1361 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1362 {
1363         ePtr<iDVBPVRChannel> pvr_channel;
1364         
1365         if (!m_decode_demux)
1366                 return -1;
1367         
1368         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1369                 return -1;
1370         
1371         int r = 0;
1372
1373                 /* if there is a decoder, use audio or video PTS */
1374         if (m_decoder)
1375         {
1376                 r = m_decoder->getPTS(0, pos);
1377                 if (r)
1378                         return r;
1379         }
1380         
1381                 /* fixup */
1382         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1383 }
1384
1385 RESULT eDVBServicePlay::setTrickmode(int trick)
1386 {
1387         if (m_decoder)
1388                 m_decoder->setTrickmode(trick);
1389         return 0;
1390 }
1391
1392 RESULT eDVBServicePlay::isCurrentlySeekable()
1393 {
1394         return m_is_pvr || m_timeshift_active;
1395 }
1396
1397 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1398 {
1399         ptr = this;
1400         return 0;
1401 }
1402
1403 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1404 {
1405         ptr = this;
1406         return 0;
1407 }
1408
1409 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1410 {
1411         ptr = this;
1412         return 0;
1413 }
1414
1415 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1416 {
1417         ptr = this;
1418         return 0;
1419 }
1420
1421 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1422 {
1423         ptr = this;
1424         return 0;
1425 }
1426
1427 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1428 {
1429         ptr = 0;
1430         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1431                 (m_timeshift_enabled || !m_is_pvr))
1432         {
1433                 if (!m_timeshift_enabled)
1434                 {
1435                                 /* we need enough diskspace */
1436                         struct statfs fs;
1437                         if (statfs(TSPATH "/.", &fs) < 0)
1438                         {
1439                                 eDebug("statfs failed!");
1440                                 return -2;
1441                         }
1442                 
1443                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1444                         {
1445                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1446                                 return -3;
1447                         }
1448                 }
1449                 ptr = this;
1450                 return 0;
1451         }
1452         return -1;
1453 }
1454
1455 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1456 {
1457         if (m_is_pvr)
1458         {
1459                 ptr = this;
1460                 return 0;
1461         }
1462         ptr = 0;
1463         return -1;
1464 }
1465
1466 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1467 {
1468         ptr = this;
1469         return 0;
1470 }
1471
1472 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1473 {
1474         ptr = this;
1475         return 0;
1476 }
1477
1478 RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
1479 {
1480         ptr = this;
1481         return 0;
1482 }
1483
1484 RESULT eDVBServicePlay::getName(std::string &name)
1485 {
1486         if (m_is_pvr)
1487         {
1488                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1489                 return i->getName(m_reference, name);
1490         }
1491         if (m_dvb_service)
1492         {
1493                 m_dvb_service->getName(m_reference, name);
1494                 if (name.empty())
1495                         name = "(...)";
1496         }
1497         else if (!m_reference.name.empty())
1498                 eStaticServiceDVBInformation().getName(m_reference, name);
1499         else
1500                 name = "DVB service";
1501         return 0;
1502 }
1503
1504 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1505 {
1506         return m_event_handler.getEvent(evt, nownext);
1507 }
1508
1509 int eDVBServicePlay::getInfo(int w)
1510 {
1511         eDVBServicePMTHandler::program program;
1512         
1513         if (w == sCAIDs)
1514                 return resIsPyObject;
1515
1516         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1517         
1518         int no_program_info = 0;
1519         
1520         if (h.getProgramInfo(program))
1521                 no_program_info = 1;
1522         
1523         switch (w)
1524         {
1525 #if HAVE_DVB_API_VERSION >= 3
1526         case sVideoHeight:
1527                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1528                         return m_videoEventData.height;
1529                 return -1;
1530         case sVideoWidth:
1531                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1532                         return m_videoEventData.width;
1533                 return -1;
1534 #else
1535 #warning "FIXMEE implement sVideoHeight, sVideoWidth for old DVB API"
1536 #endif
1537         case sAspect:
1538 #if HAVE_DVB_API_VERSION >= 3
1539                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1540                         return m_videoEventData.aspect == VIDEO_FORMAT_4_3 ? 1 : 3;
1541                 else
1542 #else
1543 #warning "FIXMEE implement sAspect for old DVB API"
1544 #endif
1545                 if (no_program_info)
1546                         return -1; 
1547                 else if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1548                 {
1549                         ePtr<eServiceEvent> evt;
1550                         if (!m_event_handler.getEvent(evt, 0))
1551                         {
1552                                 ePtr<eComponentData> data;
1553                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1554                                 {
1555                                         if ( data->getStreamContent() == 1 )
1556                                         {
1557                                                 switch(data->getComponentType())
1558                                                 {
1559                                                         // SD
1560                                                         case 1: // 4:3 SD PAL
1561                                                         case 2:
1562                                                         case 3: // 16:9 SD PAL
1563                                                         case 4: // > 16:9 PAL
1564                                                         case 5: // 4:3 SD NTSC
1565                                                         case 6: 
1566                                                         case 7: // 16:9 SD NTSC
1567                                                         case 8: // > 16:9 NTSC
1568
1569                                                         // HD
1570                                                         case 9: // 4:3 HD PAL
1571                                                         case 0xA:
1572                                                         case 0xB: // 16:9 HD PAL
1573                                                         case 0xC: // > 16:9 HD PAL
1574                                                         case 0xD: // 4:3 HD NTSC
1575                                                         case 0xE:
1576                                                         case 0xF: // 16:9 HD NTSC
1577                                                         case 0x10: // > 16:9 HD PAL
1578                                                                 return data->getComponentType();
1579                                                 }
1580                                         }
1581                                 }
1582                         }
1583                 }
1584                 return -1;
1585         case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
1586         case sVideoPID: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1587         case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1588         case sAudioPID: if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1589         case sPCRPID: if (no_program_info) return -1; return program.pcrPid;
1590         case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
1591         case sTXTPID: if (no_program_info) return -1; return program.textPid;
1592         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1593         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1594         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1595         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1596         case sProvider: if (!m_dvb_service) return -1; return -2;
1597         case sServiceref: return resIsString;
1598         case sDVBState: return m_tune_state;
1599         default:
1600                 return -1;
1601         }
1602 }
1603
1604 std::string eDVBServicePlay::getInfoString(int w)
1605 {
1606         switch (w)
1607         {
1608         case sProvider:
1609                 if (!m_dvb_service) return "";
1610                 return m_dvb_service->m_provider_name;
1611         case sServiceref:
1612                 return m_reference.toString();
1613         default:
1614                 break;
1615         }
1616         return iServiceInformation::getInfoString(w);
1617 }
1618
1619 PyObject *eDVBServicePlay::getInfoObject(int w)
1620 {
1621         switch (w)
1622         {
1623         case sCAIDs:
1624                 return m_service_handler.getCaIds();
1625         case sTransponderData:
1626                 return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
1627         default:
1628                 break;
1629         }
1630         return iServiceInformation::getInfoObject(w);
1631 }
1632
1633 int eDVBServicePlay::getNumberOfTracks()
1634 {
1635         eDVBServicePMTHandler::program program;
1636         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1637         if (h.getProgramInfo(program))
1638                 return 0;
1639         return program.audioStreams.size();
1640 }
1641
1642 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1643 {
1644         int ret = selectAudioStream(i);
1645
1646         if (m_decoder->start())
1647                 return -5;
1648
1649         return ret;
1650 }
1651
1652 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1653 {
1654         eDVBServicePMTHandler::program program;
1655         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1656
1657         if (h.getProgramInfo(program))
1658                 return -1;
1659         
1660         if (i >= program.audioStreams.size())
1661                 return -2;
1662         
1663         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1664                 info.m_description = "MPEG";
1665         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1666                 info.m_description = "AC3";
1667         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1668                 info.m_description = "AAC";
1669         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1670                 info.m_description = "DTS";
1671         else
1672                 info.m_description = "???";
1673
1674         if (program.audioStreams[i].component_tag != -1)
1675         {
1676                 ePtr<eServiceEvent> evt;
1677                 if (!m_event_handler.getEvent(evt, 0))
1678                 {
1679                         ePtr<eComponentData> data;
1680                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1681                                 info.m_language = data->getText();
1682                 }
1683         }
1684
1685         if (info.m_language.empty())
1686                 info.m_language = program.audioStreams[i].language_code;
1687         
1688         return 0;
1689 }
1690
1691 int eDVBServicePlay::selectAudioStream(int i)
1692 {
1693         eDVBServicePMTHandler::program program;
1694         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1695
1696         if (h.getProgramInfo(program))
1697                 return -1;
1698         
1699         if ((unsigned int)i >= program.audioStreams.size())
1700                 return -2;
1701         
1702         if (!m_decoder)
1703                 return -3;
1704         
1705         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1706                 return -4;
1707
1708         if (m_radiotext_parser)
1709                 m_radiotext_parser->start(program.audioStreams[i].pid);
1710
1711         if (m_dvb_service && !m_is_pvr)
1712         {
1713                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1714                 {
1715                         m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1716                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1717                 }
1718                 else
1719                 {
1720                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1721                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1722                 }
1723         }
1724
1725         h.resetCachedProgram();
1726
1727         return 0;
1728 }
1729
1730 int eDVBServicePlay::getCurrentChannel()
1731 {
1732         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1733 }
1734
1735 RESULT eDVBServicePlay::selectChannel(int i)
1736 {
1737         if (i < LEFT || i > RIGHT || i == STEREO)
1738                 i = -1;  // Stereo
1739         if (m_dvb_service)
1740                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1741         if (m_decoder)
1742                 m_decoder->setAudioChannel(i);
1743         return 0;
1744 }
1745
1746 std::string eDVBServicePlay::getRadioText(int x)
1747 {
1748         if (m_radiotext_parser)
1749                 switch(x)
1750                 {
1751                         case 0:
1752                                 return convertLatin1UTF8(m_radiotext_parser->getCurrentText());
1753                 }
1754         return "";
1755 }
1756
1757 void eDVBServicePlay::radioTextUpdated()
1758 {
1759         m_event((iPlayableService*)this, evUpdatedRadioText);
1760 }
1761
1762 int eDVBServiceBase::getFrontendInfo(int w)
1763 {
1764         eUsePtr<iDVBChannel> channel;
1765         if(m_service_handler.getChannel(channel))
1766                 return 0;
1767         ePtr<iDVBFrontend> fe;
1768         if(channel->getFrontend(fe))
1769                 return 0;
1770         return fe->readFrontendData(w);
1771 }
1772
1773 PyObject *eDVBServiceBase::getFrontendData()
1774 {
1775         ePyObject ret = PyDict_New();
1776         if (ret)
1777         {
1778                 eUsePtr<iDVBChannel> channel;
1779                 if(!m_service_handler.getChannel(channel))
1780                 {
1781                         ePtr<iDVBFrontend> fe;
1782                         if(!channel->getFrontend(fe))
1783                                 fe->getFrontendData(ret);
1784                 }
1785         }
1786         else
1787                 Py_RETURN_NONE;
1788         return ret;
1789 }
1790
1791 PyObject *eDVBServiceBase::getFrontendStatus()
1792 {
1793         ePyObject ret = PyDict_New();
1794         if (ret)
1795         {
1796                 eUsePtr<iDVBChannel> channel;
1797                 if(!m_service_handler.getChannel(channel))
1798                 {
1799                         ePtr<iDVBFrontend> fe;
1800                         if(!channel->getFrontend(fe))
1801                                 fe->getFrontendStatus(ret);
1802                 }
1803         }
1804         else
1805                 Py_RETURN_NONE;
1806         return ret;
1807 }
1808
1809 PyObject *eDVBServiceBase::getTransponderData(bool original)
1810 {
1811         ePyObject ret = PyDict_New();
1812         if (ret)
1813         {
1814                 eUsePtr<iDVBChannel> channel;
1815                 if(!m_service_handler.getChannel(channel))
1816                 {
1817                         ePtr<iDVBFrontend> fe;
1818                         if(!channel->getFrontend(fe))
1819                         {
1820                                 fe->getTransponderData(ret, original);
1821                                 ePtr<iDVBFrontendParameters> feparm;
1822                                 channel->getCurrentFrontendParameters(feparm);
1823                                 if (feparm)
1824                                 {
1825                                         eDVBFrontendParametersSatellite osat;
1826                                         if (!feparm->getDVBS(osat))
1827                                         {
1828                                                 void PutToDict(ePyObject &, const char*, long);
1829                                                 void PutToDict(ePyObject &, const char*, const char*);
1830                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1831                                                 const char *tmp = "UNKNOWN";
1832                                                 switch(osat.polarisation)
1833                                                 {
1834                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1835                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1836                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1837                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1838                                                         default:break;
1839                                                 }
1840                                                 PutToDict(ret, "polarization", tmp);
1841                                         }
1842                                 }
1843                         }
1844                 }
1845         }
1846         else
1847                 Py_RETURN_NONE;
1848         return ret;
1849 }
1850
1851 PyObject *eDVBServiceBase::getAll(bool original)
1852 {
1853         ePyObject ret = getTransponderData(original);
1854         if (ret != Py_None)
1855         {
1856                 eUsePtr<iDVBChannel> channel;
1857                 if(!m_service_handler.getChannel(channel))
1858                 {
1859                         ePtr<iDVBFrontend> fe;
1860                         if(!channel->getFrontend(fe))
1861                         {
1862                                 fe->getFrontendData(ret);
1863                                 fe->getFrontendStatus(ret);
1864                         }
1865                 }
1866         }
1867         return ret;
1868 }
1869
1870 int eDVBServicePlay::getNumberOfSubservices()
1871 {
1872         ePtr<eServiceEvent> evt;
1873         if (!m_event_handler.getEvent(evt, 0))
1874                 return evt->getNumOfLinkageServices();
1875         return 0;
1876 }
1877
1878 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1879 {
1880         ePtr<eServiceEvent> evt;
1881         if (!m_event_handler.getEvent(evt, 0))
1882         {
1883                 if (!evt->getLinkageService(sub, m_reference, n))
1884                         return 0;
1885         }
1886         sub.type=eServiceReference::idInvalid;
1887         return -1;
1888 }
1889
1890 RESULT eDVBServicePlay::startTimeshift()
1891 {
1892         ePtr<iDVBDemux> demux;
1893         
1894         eDebug("Start timeshift!");
1895         
1896         if (m_timeshift_enabled)
1897                 return -1;
1898         
1899                 /* start recording with the data demux. */
1900         if (m_service_handler.getDataDemux(demux))
1901                 return -2;
1902
1903         demux->createTSRecorder(m_record);
1904         if (!m_record)
1905                 return -3;
1906
1907         char templ[]=TSPATH "/timeshift.XXXXXX";
1908         m_timeshift_fd = mkstemp(templ);
1909         m_timeshift_file = templ;
1910         
1911         eDebug("recording to %s", templ);
1912         
1913         if (m_timeshift_fd < 0)
1914         {
1915                 m_record = 0;
1916                 return -4;
1917         }
1918                 
1919         m_record->setTargetFD(m_timeshift_fd);
1920
1921         m_timeshift_enabled = 1;
1922         
1923         updateTimeshiftPids();
1924         m_record->start();
1925
1926         return 0;
1927 }
1928
1929 RESULT eDVBServicePlay::stopTimeshift()
1930 {
1931         if (!m_timeshift_enabled)
1932                 return -1;
1933         
1934         switchToLive();
1935         
1936         m_timeshift_enabled = 0;
1937         
1938         m_record->stop();
1939         m_record = 0;
1940         
1941         close(m_timeshift_fd);
1942         eDebug("remove timeshift file");
1943         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
1944         
1945         return 0;
1946 }
1947
1948 int eDVBServicePlay::isTimeshiftActive()
1949 {
1950         return m_timeshift_enabled && m_timeshift_active;
1951 }
1952
1953 RESULT eDVBServicePlay::activateTimeshift()
1954 {
1955         if (!m_timeshift_enabled)
1956                 return -1;
1957         
1958         if (!m_timeshift_active)
1959         {
1960                 switchToTimeshift();
1961                 return 0;
1962         }
1963         
1964         return -2;
1965 }
1966
1967 PyObject *eDVBServicePlay::getCutList()
1968 {
1969         ePyObject list = PyList_New(0);
1970         
1971         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1972         {
1973                 ePyObject tuple = PyTuple_New(2);
1974                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1975                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1976                 PyList_Append(list, tuple);
1977                 Py_DECREF(tuple);
1978         }
1979         
1980         return list;
1981 }
1982
1983 void eDVBServicePlay::setCutList(ePyObject list)
1984 {
1985         if (!PyList_Check(list))
1986                 return;
1987         int size = PyList_Size(list);
1988         int i;
1989         
1990         m_cue_entries.clear();
1991         
1992         for (i=0; i<size; ++i)
1993         {
1994                 ePyObject tuple = PyList_GET_ITEM(list, i);
1995                 if (!PyTuple_Check(tuple))
1996                 {
1997                         eDebug("non-tuple in cutlist");
1998                         continue;
1999                 }
2000                 if (PyTuple_Size(tuple) != 2)
2001                 {
2002                         eDebug("cutlist entries need to be a 2-tuple");
2003                         continue;
2004                 }
2005                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
2006                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
2007                 {
2008                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
2009                         continue;
2010                 }
2011                 pts_t pts = PyLong_AsLongLong(ppts);
2012                 int type = PyInt_AsLong(ptype);
2013                 m_cue_entries.insert(cueEntry(pts, type));
2014                 eDebug("adding %08llx, %d", pts, type);
2015         }
2016         m_cuesheet_changed = 1;
2017         
2018         cutlistToCuesheet();
2019         m_event((iPlayableService*)this, evCuesheetChanged);
2020 }
2021
2022 void eDVBServicePlay::setCutListEnable(int enable)
2023 {
2024         m_cutlist_enabled = enable;
2025         cutlistToCuesheet();
2026 }
2027
2028 void eDVBServicePlay::updateTimeshiftPids()
2029 {
2030         if (!m_record)
2031                 return;
2032         
2033         eDVBServicePMTHandler::program program;
2034         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2035
2036         if (h.getProgramInfo(program))
2037                 return;
2038         else
2039         {
2040                 std::set<int> pids_to_record;
2041                 pids_to_record.insert(0); // PAT
2042                 if (program.pmtPid != -1)
2043                         pids_to_record.insert(program.pmtPid); // PMT
2044
2045                 if (program.textPid != -1)
2046                         pids_to_record.insert(program.textPid); // Videotext
2047
2048                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2049                         i(program.videoStreams.begin()); 
2050                         i != program.videoStreams.end(); ++i)
2051                         pids_to_record.insert(i->pid);
2052
2053                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2054                         i(program.audioStreams.begin()); 
2055                         i != program.audioStreams.end(); ++i)
2056                                 pids_to_record.insert(i->pid);
2057
2058                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2059                         i(program.subtitleStreams.begin());
2060                         i != program.subtitleStreams.end(); ++i)
2061                                 pids_to_record.insert(i->pid);
2062
2063                 std::set<int> new_pids, obsolete_pids;
2064                 
2065                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2066                                 m_pids_active.begin(), m_pids_active.end(),
2067                                 std::inserter(new_pids, new_pids.begin()));
2068                 
2069                 std::set_difference(
2070                                 m_pids_active.begin(), m_pids_active.end(),
2071                                 pids_to_record.begin(), pids_to_record.end(), 
2072                                 std::inserter(new_pids, new_pids.begin())
2073                                 );
2074
2075                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2076                         m_record->addPID(*i);
2077
2078                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2079                         m_record->removePID(*i);
2080         }
2081 }
2082
2083 void eDVBServicePlay::switchToLive()
2084 {
2085         if (!m_timeshift_active)
2086                 return;
2087         
2088         m_cue = 0;
2089         m_decoder = 0;
2090         m_decode_demux = 0;
2091         m_teletext_parser = 0;
2092         m_radiotext_parser = 0;
2093         m_subtitle_parser = 0;
2094         m_new_dvb_subtitle_page_connection = 0;
2095         m_new_subtitle_page_connection = 0;
2096         m_radiotext_updated_connection = 0;
2097         m_video_event_connection = 0;
2098
2099                 /* free the timeshift service handler, we need the resources */
2100         m_service_handler_timeshift.free();
2101         m_timeshift_active = 0;
2102
2103         m_event((iPlayableService*)this, evSeekableStatusChanged);
2104
2105         updateDecoder();
2106 }
2107
2108 void eDVBServicePlay::switchToTimeshift()
2109 {
2110         if (m_timeshift_active)
2111                 return;
2112
2113         m_decode_demux = 0;
2114         m_decoder = 0;
2115         m_teletext_parser = 0;
2116         m_radiotext_parser = 0;
2117         m_subtitle_parser = 0;
2118         m_new_subtitle_page_connection = 0;
2119         m_new_dvb_subtitle_page_connection = 0;
2120         m_radiotext_updated_connection = 0;
2121         m_video_event_connection = 0;
2122
2123         m_timeshift_active = 1;
2124
2125         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2126         r.path = m_timeshift_file;
2127
2128         m_cue = new eCueSheet();
2129         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
2130         updateDecoder(); /* mainly to switch off PCR */
2131
2132         m_event((iPlayableService*)this, evSeekableStatusChanged);
2133 }
2134
2135 void eDVBServicePlay::updateDecoder()
2136 {
2137         int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2138
2139         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2140
2141         bool defaultac3=false;
2142         std::string default_ac3;
2143
2144         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
2145                 defaultac3 = default_ac3 == "True";
2146
2147         eDVBServicePMTHandler::program program;
2148         if (h.getProgramInfo(program))
2149                 eDebug("getting program info failed.");
2150         else
2151         {
2152                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
2153                 if (!program.videoStreams.empty())
2154                 {
2155                         eDebugNoNewLine(" (");
2156                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2157                                 i(program.videoStreams.begin());
2158                                 i != program.videoStreams.end(); ++i)
2159                         {
2160                                 if (vpid == -1)
2161                                 {
2162                                         vpid = i->pid;
2163                                         vpidtype = i->type;
2164                                 }
2165                                 if (i != program.videoStreams.begin())
2166                                         eDebugNoNewLine(", ");
2167                                 eDebugNoNewLine("%04x", i->pid);
2168                         }
2169                         eDebugNoNewLine(")");
2170                 }
2171                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
2172                 if (!program.audioStreams.empty())
2173                 {
2174                         eDebugNoNewLine(" (");
2175                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2176                                 i(program.audioStreams.begin());
2177                                 i != program.audioStreams.end(); ++i)
2178                         {
2179                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
2180                                 {
2181                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
2182                                         {
2183                                                 apid = i->pid;
2184                                                 apidtype = i->type;
2185                                         }
2186                                 }
2187                                 if (i != program.audioStreams.begin())
2188                                         eDebugNoNewLine(", ");
2189                                 eDebugNoNewLine("%04x", i->pid);
2190                         }
2191                         eDebugNoNewLine(")");
2192                 }
2193                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2194                 pcrpid = program.pcrPid;
2195                 eDebug(", and the text pid is %04x", program.textPid);
2196                 tpid = program.textPid;
2197         }
2198
2199         if (!m_decoder)
2200         {
2201                 h.getDecodeDemux(m_decode_demux);
2202                 if (m_decode_demux)
2203                 {
2204                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2205                         if (m_decoder)
2206                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2207                 }
2208                 if (m_cue)
2209                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2210                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2211                 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2212                 m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2213                 m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2214         }
2215
2216         if (m_decoder)
2217         {
2218                 if (m_dvb_service)
2219                 {
2220                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2221                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2222                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2223                 }
2224                 else // subservice or recording
2225                 {
2226                         eServiceReferenceDVB ref;
2227                         m_service_handler.getServiceReference(ref);
2228                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2229                         if (!parent)
2230                                 parent = ref;
2231                         if (parent)
2232                         {
2233                                 ePtr<eDVBResourceManager> res_mgr;
2234                                 if (!eDVBResourceManager::getInstance(res_mgr))
2235                                 {
2236                                         ePtr<iDVBChannelList> db;
2237                                         if (!res_mgr->getChannelList(db))
2238                                         {
2239                                                 ePtr<eDVBService> origService;
2240                                                 if (!db->getService(parent, origService))
2241                                                 {
2242                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2243                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2244                                                 }
2245                                         }
2246                                 }
2247                         }
2248                 }
2249                 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
2250                 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
2251
2252                 m_decoder->setVideoPID(vpid, vpidtype);
2253                 m_decoder->setAudioPID(apid, apidtype);
2254                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
2255                 {
2256                         m_decoder->setSyncPCR(pcrpid);
2257                         if (apid != -1)
2258                         {
2259                                 ePtr<iDVBDemux> data_demux;
2260                                 if (!h.getDataDemux(data_demux))
2261                                 {
2262                                         m_radiotext_parser = new eDVBRadioTextParser(data_demux);
2263                                         m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
2264                                         m_radiotext_parser->start(apid);
2265                                 }
2266                         }
2267                 }
2268                 else
2269                         m_decoder->setSyncPCR(-1);
2270
2271                 m_decoder->setTextPID(tpid);
2272
2273                 m_teletext_parser->start(program.textPid);
2274
2275                 if (!m_is_primary)
2276                         m_decoder->setTrickmode(1);
2277
2278                 m_decoder->start();
2279
2280                 if (vpid > 0 && vpid < 0x2000)
2281                         ;
2282                 else
2283                 {
2284                         std::string radio_pic;
2285                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2286                                 m_decoder->setRadioPic(radio_pic);
2287                 }
2288
2289                 m_decoder->setAudioChannel(achannel);
2290
2291 // how we can do this better?
2292 // update cache pid when the user changed the audio track or video track
2293 // TODO handling of difference audio types.. default audio types..
2294                                 
2295                 /* don't worry about non-existing services, nor pvr services */
2296                 if (m_dvb_service && !m_is_pvr)
2297                 {
2298                         if (apidtype == eDVBAudio::aMPEG)
2299                         {
2300                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
2301                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
2302                         }
2303                         else
2304                         {
2305                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
2306                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
2307                         }
2308                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2309                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2310                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2311                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2312                 }
2313         }       
2314         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2315 }
2316
2317 void eDVBServicePlay::loadCuesheet()
2318 {
2319         std::string filename = m_reference.path + ".cuts";
2320         
2321         m_cue_entries.clear();
2322
2323         FILE *f = fopen(filename.c_str(), "rb");
2324
2325         if (f)
2326         {
2327                 eDebug("loading cuts..");
2328                 while (1)
2329                 {
2330                         unsigned long long where;
2331                         unsigned int what;
2332                         
2333                         if (!fread(&where, sizeof(where), 1, f))
2334                                 break;
2335                         if (!fread(&what, sizeof(what), 1, f))
2336                                 break;
2337                         
2338 #if BYTE_ORDER == LITTLE_ENDIAN
2339                         where = bswap_64(where);
2340 #endif
2341                         what = ntohl(what);
2342                         
2343                         if (what > 3)
2344                                 break;
2345                         
2346                         m_cue_entries.insert(cueEntry(where, what));
2347                 }
2348                 fclose(f);
2349                 eDebug("%d entries", m_cue_entries.size());
2350         } else
2351                 eDebug("cutfile not found!");
2352         
2353         m_cuesheet_changed = 0;
2354         cutlistToCuesheet();
2355         m_event((iPlayableService*)this, evCuesheetChanged);
2356 }
2357
2358 void eDVBServicePlay::saveCuesheet()
2359 {
2360         std::string filename = m_reference.path + ".cuts";
2361         
2362         FILE *f = fopen(filename.c_str(), "wb");
2363
2364         if (f)
2365         {
2366                 unsigned long long where;
2367                 int what;
2368
2369                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2370                 {
2371 #if BYTE_ORDER == BIG_ENDIAN
2372                         where = i->where;
2373 #else
2374                         where = bswap_64(i->where);
2375 #endif
2376                         what = htonl(i->what);
2377                         fwrite(&where, sizeof(where), 1, f);
2378                         fwrite(&what, sizeof(what), 1, f);
2379                         
2380                 }
2381                 fclose(f);
2382         }
2383         
2384         m_cuesheet_changed = 0;
2385 }
2386
2387 void eDVBServicePlay::cutlistToCuesheet()
2388 {
2389         if (!m_cue)
2390         {
2391                 eDebug("no cue sheet");
2392                 return;
2393         }       
2394         m_cue->clear();
2395         
2396         if (!m_cutlist_enabled)
2397         {
2398                 m_cue->commitSpans();
2399                 eDebug("cutlists were disabled");
2400                 return;
2401         }
2402
2403         pts_t in = 0, out = 0, length = 0;
2404         
2405         getLength(length);
2406                 
2407         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2408         
2409         while (1)
2410         {
2411                 if (i == m_cue_entries.end())
2412                         out = length;
2413                 else {
2414                         if (i->what == 0) /* in */
2415                         {
2416                                 in = i++->where;
2417                                 continue;
2418                         } else if (i->what == 1) /* out */
2419                                 out = i++->where;
2420                         else /* mark (2) or last play position (3) */
2421                         {
2422                                 i++;
2423                                 continue;
2424                         }
2425                 }
2426                 
2427                 if (in != out)
2428                         m_cue->addSourceSpan(in, out);
2429                 
2430                 in = length;
2431                 
2432                 if (i == m_cue_entries.end())
2433                         break;
2434         }
2435         m_cue->commitSpans();
2436 }
2437
2438 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2439 {
2440         if (m_subtitle_widget)
2441                 disableSubtitles(parent);
2442
2443         ePyObject entry;
2444         int tuplesize = PyTuple_Size(tuple);
2445         int type = 0;
2446
2447         if (!PyTuple_Check(tuple))
2448                 goto error_out;
2449
2450         if (tuplesize < 1)
2451                 goto error_out;
2452
2453         entry = PyTuple_GET_ITEM(tuple, 0);
2454
2455         if (!PyInt_Check(entry))
2456                 goto error_out;
2457
2458         type = PyInt_AsLong(entry);
2459
2460         if (type == 1)  // teletext subtitles
2461         {
2462                 int page, magazine, pid;
2463                 if (tuplesize < 4)
2464                         goto error_out;
2465
2466                 if (!m_teletext_parser)
2467                 {
2468                         eDebug("enable teletext subtitles.. no parser !!!");
2469                         return -1;
2470                 }
2471
2472                 entry = PyTuple_GET_ITEM(tuple, 1);
2473                 if (!PyInt_Check(entry))
2474                         goto error_out;
2475                 pid = PyInt_AsLong(entry);
2476
2477                 entry = PyTuple_GET_ITEM(tuple, 2);
2478                 if (!PyInt_Check(entry))
2479                         goto error_out;
2480                 page = PyInt_AsLong(entry);
2481
2482                 entry = PyTuple_GET_ITEM(tuple, 3);
2483                 if (!PyInt_Check(entry))
2484                         goto error_out;
2485                 magazine = PyInt_AsLong(entry);
2486
2487                 m_subtitle_widget = new eSubtitleWidget(parent);
2488                 m_subtitle_widget->resize(parent->size()); /* full size */
2489                 m_teletext_parser->setPageAndMagazine(page, magazine);
2490                 if (m_dvb_service)
2491                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2492         }
2493         else if (type == 0)
2494         {
2495                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2496                 if (!m_subtitle_parser)
2497                 {
2498                         eDebug("enable dvb subtitles.. no parser !!!");
2499                         return -1;
2500                 }
2501                 if (tuplesize < 4)
2502                         goto error_out;
2503
2504                 entry = PyTuple_GET_ITEM(tuple, 1);
2505                 if (!PyInt_Check(entry))
2506                         goto error_out;
2507                 pid = PyInt_AsLong(entry);
2508
2509                 entry = PyTuple_GET_ITEM(tuple, 2);
2510                 if (!PyInt_Check(entry))
2511                         goto error_out;
2512                 composition_page_id = PyInt_AsLong(entry);
2513
2514                 entry = PyTuple_GET_ITEM(tuple, 3);
2515                 if (!PyInt_Check(entry))
2516                         goto error_out;
2517                 ancillary_page_id = PyInt_AsLong(entry);
2518
2519                 m_subtitle_widget = new eSubtitleWidget(parent);
2520                 m_subtitle_widget->resize(parent->size()); /* full size */
2521                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2522                 if (m_dvb_service)
2523                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2524         }
2525         else
2526                 goto error_out;
2527         return 0;
2528 error_out:
2529         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2530                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2531                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2532         return -1;
2533 }
2534
2535 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2536 {
2537         delete m_subtitle_widget;
2538         m_subtitle_widget = 0;
2539         if (m_subtitle_parser)
2540         {
2541                 m_subtitle_parser->stop();
2542                 m_dvb_subtitle_pages.clear();
2543         }
2544         if (m_teletext_parser)
2545         {
2546                 m_teletext_parser->setPageAndMagazine(-1, -1);
2547                 m_subtitle_pages.clear();
2548         }
2549         if (m_dvb_service)
2550                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2551         return 0;
2552 }
2553
2554 PyObject *eDVBServicePlay::getCachedSubtitle()
2555 {
2556         if (m_dvb_service)
2557         {
2558                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2559                 if (tmp != -1)
2560                 {
2561                         unsigned int data = (unsigned int)tmp;
2562                         int pid = (data&0xFFFF0000)>>16;
2563                         ePyObject tuple = PyTuple_New(4);
2564                         eDVBServicePMTHandler::program program;
2565                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2566                         if (!h.getProgramInfo(program))
2567                         {
2568                                 if (program.textPid==pid) // teletext
2569                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2570                                 else
2571                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2572                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
2573                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2574                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2575                                 return tuple;
2576                         }
2577                 }
2578         }
2579         Py_RETURN_NONE;
2580 }
2581
2582 PyObject *eDVBServicePlay::getSubtitleList()
2583 {
2584         if (!m_teletext_parser)
2585                 Py_RETURN_NONE;
2586         
2587         ePyObject l = PyList_New(0);
2588         std::set<int> added_ttx_pages;
2589
2590         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2591                 m_teletext_parser->m_found_subtitle_pages;
2592
2593         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2594         eDVBServicePMTHandler::program program;
2595         if (h.getProgramInfo(program))
2596                 eDebug("getting program info failed.");
2597         else
2598         {
2599                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2600                         it != program.subtitleStreams.end(); ++it)
2601                 {
2602                         switch(it->subtitling_type)
2603                         {
2604                                 case 0x01: // ebu teletext subtitles
2605                                 {
2606                                         int page_number = it->teletext_page_number & 0xFF;
2607                                         int magazine_number = it->teletext_magazine_number & 7;
2608                                         int hash = magazine_number << 8 | page_number;
2609                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2610                                         {
2611                                                 ePyObject tuple = PyTuple_New(5);
2612                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2613                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2614                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2615                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2616                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2617                                                 PyList_Append(l, tuple);
2618                                                 Py_DECREF(tuple);
2619                                                 added_ttx_pages.insert(hash);
2620                                         }
2621                                         break;
2622                                 }
2623                                 case 0x10 ... 0x13:
2624                                 case 0x20 ... 0x23: // dvb subtitles
2625                                 {
2626                                         ePyObject tuple = PyTuple_New(5);
2627                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2628                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2629                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2630                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2631                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2632                                         PyList_Insert(l, 0, tuple);
2633                                         Py_DECREF(tuple);
2634                                         break;
2635                                 }
2636                         }
2637                 }
2638         }
2639
2640         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2641                 it != subs.end(); ++it)
2642         {
2643                 int page_number = it->teletext_page_number & 0xFF;
2644                 int magazine_number = it->teletext_magazine_number & 7;
2645                 int hash = magazine_number << 8 | page_number;
2646                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2647                 {
2648                         ePyObject tuple = PyTuple_New(5);
2649                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2650                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2651                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2652                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2653                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2654                         PyList_Append(l, tuple);
2655                         Py_DECREF(tuple);
2656                 }
2657         }
2658
2659         return l;
2660 }
2661
2662 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2663 {
2664         if (m_subtitle_widget)
2665         {
2666                 m_subtitle_pages.push_back(page);
2667                 checkSubtitleTiming();
2668         }
2669 }
2670
2671 void eDVBServicePlay::checkSubtitleTiming()
2672 {
2673 //      eDebug("checkSubtitleTiming");
2674         if (!m_subtitle_widget)
2675                 return;
2676         while (1)
2677         {
2678                 enum { TELETEXT, DVB } type;
2679                 eDVBTeletextSubtitlePage page;
2680                 eDVBSubtitlePage dvb_page;
2681                 pts_t show_time;
2682                 if (!m_subtitle_pages.empty())
2683                 {
2684                         page = m_subtitle_pages.front();
2685                         type = TELETEXT;
2686                         show_time = page.m_pts;
2687                 }
2688                 else if (!m_dvb_subtitle_pages.empty())
2689                 {
2690                         dvb_page = m_dvb_subtitle_pages.front();
2691                         type = DVB;
2692                         show_time = dvb_page.m_show_time;
2693                 }
2694                 else
2695                         return;
2696         
2697                 pts_t pos = 0;
2698         
2699                 if (m_decoder)
2700                         m_decoder->getPTS(0, pos);
2701
2702 //              eDebug("%lld %lld", pos, show_time);
2703                 int diff =  show_time - pos;
2704                 if (diff < 0)
2705                 {
2706                         eDebug("[late (%d ms)]", -diff / 90);
2707                         diff = 0;
2708                 }
2709                 if (diff > 900000)
2710                 {
2711                         eDebug("[invalid]");
2712                         diff = 0;
2713                 }
2714         
2715                 if (!diff)
2716                 {
2717                         if (type == TELETEXT)
2718                         {
2719                                 eDebug("display teletext subtitle page");
2720                                 m_subtitle_widget->setPage(page);
2721                                 m_subtitle_pages.pop_front();
2722                         }
2723                         else
2724                         {
2725                                 eDebug("display dvb subtitle Page");
2726                                 m_subtitle_widget->setPage(dvb_page);
2727                                 m_dvb_subtitle_pages.pop_front();
2728                         }
2729                 } else
2730                 {
2731 //                      eDebug("start subtitle delay %d", diff / 90);
2732                         m_subtitle_sync_timer.start(diff / 90, 1);
2733                         break;
2734                 }
2735         }
2736 }
2737
2738 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2739 {
2740         if (m_subtitle_widget)
2741         {
2742                 m_dvb_subtitle_pages.push_back(p);
2743                 checkSubtitleTiming();
2744         }
2745 }
2746
2747 int eDVBServicePlay::getAC3Delay()
2748 {
2749         if (m_dvb_service)
2750                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2751         else if (m_decoder)
2752                 return m_decoder->getAC3Delay();
2753         else
2754                 return 0;
2755 }
2756
2757 int eDVBServicePlay::getPCMDelay()
2758 {
2759         if (m_dvb_service)
2760                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2761         else if (m_decoder)
2762                 return m_decoder->getPCMDelay();
2763         else
2764                 return 0;
2765 }
2766
2767 void eDVBServicePlay::setAC3Delay(int delay)
2768 {
2769         if (m_dvb_service)
2770                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2771         if (m_decoder)
2772                 m_decoder->setAC3Delay(delay);
2773 }
2774
2775 void eDVBServicePlay::setPCMDelay(int delay)
2776 {
2777         if (m_dvb_service)
2778                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2779         if (m_decoder)
2780                 m_decoder->setPCMDelay(delay);
2781 }
2782
2783 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
2784 {
2785         memcpy(&m_videoEventData, &event, sizeof(iTSMPEGDecoder::videoEvent));
2786         m_event((iPlayableService*)this, evVideoSizeChanged);
2787 }
2788
2789 DEFINE_REF(eDVBServicePlay)
2790
2791 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
2792 {
2793         switch (w)
2794         {
2795         case iServiceInformation::sTransponderData:
2796                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
2797         default:
2798                 break;
2799         }
2800         return iStaticServiceInformation::getInfoObject(ref, w);
2801 }
2802
2803 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");