238f838fa704385a0a1d09e3a621a67fc6b7b212
[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(bool original)
1774 {
1775         ePyObject ret;
1776
1777         eUsePtr<iDVBChannel> channel;
1778         if(!m_service_handler.getChannel(channel))
1779         {
1780                 ePtr<iDVBFrontend> fe;
1781                 if(!channel->getFrontend(fe))
1782                 {
1783                         ret = fe->readTransponderData(original);
1784                         if (ret)
1785                         {
1786                                 ePtr<iDVBFrontendParameters> feparm;
1787                                 channel->getCurrentFrontendParameters(feparm);
1788                                 if (feparm)
1789                                 {
1790                                         eDVBFrontendParametersSatellite osat;
1791                                         if (!feparm->getDVBS(osat))
1792                                         {
1793                                                 void PutToDict(ePyObject &, const char*, long);
1794                                                 void PutToDict(ePyObject &, const char*, const char*);
1795                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1796                                                 const char *tmp = "UNKNOWN";
1797                                                 switch(osat.polarisation)
1798                                                 {
1799                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1800                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1801                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1802                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1803                                                         default:break;
1804                                                 }
1805                                                 PutToDict(ret, "polarization", tmp);
1806                                         }
1807                                 }
1808                         }
1809                 }
1810         }
1811         if (!ret)
1812                 Py_RETURN_NONE;
1813         return ret;
1814 }
1815
1816 int eDVBServicePlay::getNumberOfSubservices()
1817 {
1818         ePtr<eServiceEvent> evt;
1819         if (!m_event_handler.getEvent(evt, 0))
1820                 return evt->getNumOfLinkageServices();
1821         return 0;
1822 }
1823
1824 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1825 {
1826         ePtr<eServiceEvent> evt;
1827         if (!m_event_handler.getEvent(evt, 0))
1828         {
1829                 if (!evt->getLinkageService(sub, m_reference, n))
1830                         return 0;
1831         }
1832         sub.type=eServiceReference::idInvalid;
1833         return -1;
1834 }
1835
1836 RESULT eDVBServicePlay::startTimeshift()
1837 {
1838         ePtr<iDVBDemux> demux;
1839         
1840         eDebug("Start timeshift!");
1841         
1842         if (m_timeshift_enabled)
1843                 return -1;
1844         
1845                 /* start recording with the data demux. */
1846         if (m_service_handler.getDataDemux(demux))
1847                 return -2;
1848
1849         demux->createTSRecorder(m_record);
1850         if (!m_record)
1851                 return -3;
1852
1853         char templ[]=TSPATH "/timeshift.XXXXXX";
1854         m_timeshift_fd = mkstemp(templ);
1855         m_timeshift_file = templ;
1856         
1857         eDebug("recording to %s", templ);
1858         
1859         if (m_timeshift_fd < 0)
1860         {
1861                 m_record = 0;
1862                 return -4;
1863         }
1864                 
1865         m_record->setTargetFD(m_timeshift_fd);
1866
1867         m_timeshift_enabled = 1;
1868         
1869         updateTimeshiftPids();
1870         m_record->start();
1871
1872         return 0;
1873 }
1874
1875 RESULT eDVBServicePlay::stopTimeshift()
1876 {
1877         if (!m_timeshift_enabled)
1878                 return -1;
1879         
1880         switchToLive();
1881         
1882         m_timeshift_enabled = 0;
1883         
1884         m_record->stop();
1885         m_record = 0;
1886         
1887         close(m_timeshift_fd);
1888         eDebug("remove timeshift file");
1889         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
1890         
1891         return 0;
1892 }
1893
1894 int eDVBServicePlay::isTimeshiftActive()
1895 {
1896         return m_timeshift_enabled && m_timeshift_active;
1897 }
1898
1899 RESULT eDVBServicePlay::activateTimeshift()
1900 {
1901         if (!m_timeshift_enabled)
1902                 return -1;
1903         
1904         if (!m_timeshift_active)
1905         {
1906                 switchToTimeshift();
1907                 return 0;
1908         }
1909         
1910         return -2;
1911 }
1912
1913 PyObject *eDVBServicePlay::getCutList()
1914 {
1915         ePyObject list = PyList_New(0);
1916         
1917         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1918         {
1919                 ePyObject tuple = PyTuple_New(2);
1920                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1921                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1922                 PyList_Append(list, tuple);
1923                 Py_DECREF(tuple);
1924         }
1925         
1926         return list;
1927 }
1928
1929 void eDVBServicePlay::setCutList(ePyObject list)
1930 {
1931         if (!PyList_Check(list))
1932                 return;
1933         int size = PyList_Size(list);
1934         int i;
1935         
1936         m_cue_entries.clear();
1937         
1938         for (i=0; i<size; ++i)
1939         {
1940                 ePyObject tuple = PyList_GET_ITEM(list, i);
1941                 if (!PyTuple_Check(tuple))
1942                 {
1943                         eDebug("non-tuple in cutlist");
1944                         continue;
1945                 }
1946                 if (PyTuple_Size(tuple) != 2)
1947                 {
1948                         eDebug("cutlist entries need to be a 2-tuple");
1949                         continue;
1950                 }
1951                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
1952                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1953                 {
1954                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1955                         continue;
1956                 }
1957                 pts_t pts = PyLong_AsLongLong(ppts);
1958                 int type = PyInt_AsLong(ptype);
1959                 m_cue_entries.insert(cueEntry(pts, type));
1960                 eDebug("adding %08llx, %d", pts, type);
1961         }
1962         m_cuesheet_changed = 1;
1963         
1964         cutlistToCuesheet();
1965         m_event((iPlayableService*)this, evCuesheetChanged);
1966 }
1967
1968 void eDVBServicePlay::setCutListEnable(int enable)
1969 {
1970         m_cutlist_enabled = enable;
1971         cutlistToCuesheet();
1972 }
1973
1974 void eDVBServicePlay::updateTimeshiftPids()
1975 {
1976         if (!m_record)
1977                 return;
1978         
1979         eDVBServicePMTHandler::program program;
1980         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1981
1982         if (h.getProgramInfo(program))
1983                 return;
1984         else
1985         {
1986                 std::set<int> pids_to_record;
1987                 pids_to_record.insert(0); // PAT
1988                 if (program.pmtPid != -1)
1989                         pids_to_record.insert(program.pmtPid); // PMT
1990
1991                 if (program.textPid != -1)
1992                         pids_to_record.insert(program.textPid); // Videotext
1993
1994                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1995                         i(program.videoStreams.begin()); 
1996                         i != program.videoStreams.end(); ++i)
1997                         pids_to_record.insert(i->pid);
1998
1999                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2000                         i(program.audioStreams.begin()); 
2001                         i != program.audioStreams.end(); ++i)
2002                                 pids_to_record.insert(i->pid);
2003
2004                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2005                         i(program.subtitleStreams.begin());
2006                         i != program.subtitleStreams.end(); ++i)
2007                                 pids_to_record.insert(i->pid);
2008
2009                 std::set<int> new_pids, obsolete_pids;
2010                 
2011                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2012                                 m_pids_active.begin(), m_pids_active.end(),
2013                                 std::inserter(new_pids, new_pids.begin()));
2014                 
2015                 std::set_difference(
2016                                 m_pids_active.begin(), m_pids_active.end(),
2017                                 pids_to_record.begin(), pids_to_record.end(), 
2018                                 std::inserter(new_pids, new_pids.begin())
2019                                 );
2020
2021                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2022                         m_record->addPID(*i);
2023
2024                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2025                         m_record->removePID(*i);
2026         }
2027 }
2028
2029 void eDVBServicePlay::switchToLive()
2030 {
2031         if (!m_timeshift_active)
2032                 return;
2033         
2034         m_cue = 0;
2035         m_decoder = 0;
2036         m_decode_demux = 0;
2037         m_teletext_parser = 0;
2038         m_radiotext_parser = 0;
2039         m_subtitle_parser = 0;
2040         m_new_dvb_subtitle_page_connection = 0;
2041         m_new_subtitle_page_connection = 0;
2042         m_radiotext_updated_connection = 0;
2043         m_video_event_connection = 0;
2044
2045                 /* free the timeshift service handler, we need the resources */
2046         m_service_handler_timeshift.free();
2047         m_timeshift_active = 0;
2048
2049         m_event((iPlayableService*)this, evSeekableStatusChanged);
2050
2051         updateDecoder();
2052 }
2053
2054 void eDVBServicePlay::switchToTimeshift()
2055 {
2056         if (m_timeshift_active)
2057                 return;
2058
2059         m_decode_demux = 0;
2060         m_decoder = 0;
2061         m_teletext_parser = 0;
2062         m_radiotext_parser = 0;
2063         m_subtitle_parser = 0;
2064         m_new_subtitle_page_connection = 0;
2065         m_new_dvb_subtitle_page_connection = 0;
2066         m_radiotext_updated_connection = 0;
2067         m_video_event_connection = 0;
2068
2069         m_timeshift_active = 1;
2070
2071         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2072         r.path = m_timeshift_file;
2073
2074         m_cue = new eCueSheet();
2075         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
2076         updateDecoder(); /* mainly to switch off PCR */
2077
2078         m_event((iPlayableService*)this, evSeekableStatusChanged);
2079 }
2080
2081 void eDVBServicePlay::updateDecoder()
2082 {
2083         int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2084
2085         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2086
2087         bool defaultac3=false;
2088         std::string default_ac3;
2089
2090         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
2091                 defaultac3 = default_ac3 == "True";
2092
2093         eDVBServicePMTHandler::program program;
2094         if (h.getProgramInfo(program))
2095                 eDebug("getting program info failed.");
2096         else
2097         {
2098                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
2099                 if (!program.videoStreams.empty())
2100                 {
2101                         eDebugNoNewLine(" (");
2102                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2103                                 i(program.videoStreams.begin());
2104                                 i != program.videoStreams.end(); ++i)
2105                         {
2106                                 if (vpid == -1)
2107                                 {
2108                                         vpid = i->pid;
2109                                         vpidtype = i->type;
2110                                 }
2111                                 if (i != program.videoStreams.begin())
2112                                         eDebugNoNewLine(", ");
2113                                 eDebugNoNewLine("%04x", i->pid);
2114                         }
2115                         eDebugNoNewLine(")");
2116                 }
2117                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
2118                 if (!program.audioStreams.empty())
2119                 {
2120                         eDebugNoNewLine(" (");
2121                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2122                                 i(program.audioStreams.begin());
2123                                 i != program.audioStreams.end(); ++i)
2124                         {
2125                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
2126                                 {
2127                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
2128                                         {
2129                                                 apid = i->pid;
2130                                                 apidtype = i->type;
2131                                         }
2132                                 }
2133                                 if (i != program.audioStreams.begin())
2134                                         eDebugNoNewLine(", ");
2135                                 eDebugNoNewLine("%04x", i->pid);
2136                         }
2137                         eDebugNoNewLine(")");
2138                 }
2139                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2140                 pcrpid = program.pcrPid;
2141                 eDebug(", and the text pid is %04x", program.textPid);
2142                 tpid = program.textPid;
2143         }
2144
2145         if (!m_decoder)
2146         {
2147                 h.getDecodeDemux(m_decode_demux);
2148                 if (m_decode_demux)
2149                 {
2150                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2151                         if (m_decoder)
2152                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2153                 }
2154                 if (m_cue)
2155                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2156                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2157                 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2158                 m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2159                 m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2160         }
2161
2162         if (m_decoder)
2163         {
2164                 if (m_dvb_service)
2165                 {
2166                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2167                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2168                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2169                 }
2170                 else // subservice or recording
2171                 {
2172                         eServiceReferenceDVB ref;
2173                         m_service_handler.getServiceReference(ref);
2174                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2175                         if (!parent)
2176                                 parent = ref;
2177                         if (parent)
2178                         {
2179                                 ePtr<eDVBResourceManager> res_mgr;
2180                                 if (!eDVBResourceManager::getInstance(res_mgr))
2181                                 {
2182                                         ePtr<iDVBChannelList> db;
2183                                         if (!res_mgr->getChannelList(db))
2184                                         {
2185                                                 ePtr<eDVBService> origService;
2186                                                 if (!db->getService(parent, origService))
2187                                                 {
2188                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2189                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2190                                                 }
2191                                         }
2192                                 }
2193                         }
2194                 }
2195                 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
2196                 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
2197
2198                 m_decoder->setVideoPID(vpid, vpidtype);
2199                 m_decoder->setAudioPID(apid, apidtype);
2200                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
2201                 {
2202                         m_decoder->setSyncPCR(pcrpid);
2203                         if (apid != -1)
2204                         {
2205                                 ePtr<iDVBDemux> data_demux;
2206                                 if (!h.getDataDemux(data_demux))
2207                                 {
2208                                         m_radiotext_parser = new eDVBRadioTextParser(data_demux);
2209                                         m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
2210                                         m_radiotext_parser->start(apid);
2211                                 }
2212                         }
2213                 }
2214                 else
2215                         m_decoder->setSyncPCR(-1);
2216
2217                 m_decoder->setTextPID(tpid);
2218
2219                 m_teletext_parser->start(program.textPid);
2220
2221                 if (!m_is_primary)
2222                         m_decoder->setTrickmode(1);
2223
2224                 m_decoder->start();
2225
2226                 if (vpid > 0 && vpid < 0x2000)
2227                         ;
2228                 else
2229                 {
2230                         std::string radio_pic;
2231                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2232                                 m_decoder->setRadioPic(radio_pic);
2233                 }
2234
2235                 m_decoder->setAudioChannel(achannel);
2236
2237 // how we can do this better?
2238 // update cache pid when the user changed the audio track or video track
2239 // TODO handling of difference audio types.. default audio types..
2240                                 
2241                 /* don't worry about non-existing services, nor pvr services */
2242                 if (m_dvb_service && !m_is_pvr)
2243                 {
2244                         if (apidtype == eDVBAudio::aMPEG)
2245                         {
2246                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
2247                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
2248                         }
2249                         else
2250                         {
2251                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
2252                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
2253                         }
2254                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2255                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2256                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2257                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2258                 }
2259         }       
2260         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2261 }
2262
2263 void eDVBServicePlay::loadCuesheet()
2264 {
2265         std::string filename = m_reference.path + ".cuts";
2266         
2267         m_cue_entries.clear();
2268
2269         FILE *f = fopen(filename.c_str(), "rb");
2270
2271         if (f)
2272         {
2273                 eDebug("loading cuts..");
2274                 while (1)
2275                 {
2276                         unsigned long long where;
2277                         unsigned int what;
2278                         
2279                         if (!fread(&where, sizeof(where), 1, f))
2280                                 break;
2281                         if (!fread(&what, sizeof(what), 1, f))
2282                                 break;
2283                         
2284 #if BYTE_ORDER == LITTLE_ENDIAN
2285                         where = bswap_64(where);
2286 #endif
2287                         what = ntohl(what);
2288                         
2289                         if (what > 3)
2290                                 break;
2291                         
2292                         m_cue_entries.insert(cueEntry(where, what));
2293                 }
2294                 fclose(f);
2295                 eDebug("%d entries", m_cue_entries.size());
2296         } else
2297                 eDebug("cutfile not found!");
2298         
2299         m_cuesheet_changed = 0;
2300         cutlistToCuesheet();
2301         m_event((iPlayableService*)this, evCuesheetChanged);
2302 }
2303
2304 void eDVBServicePlay::saveCuesheet()
2305 {
2306         std::string filename = m_reference.path + ".cuts";
2307         
2308         FILE *f = fopen(filename.c_str(), "wb");
2309
2310         if (f)
2311         {
2312                 unsigned long long where;
2313                 int what;
2314
2315                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2316                 {
2317 #if BYTE_ORDER == BIG_ENDIAN
2318                         where = i->where;
2319 #else
2320                         where = bswap_64(i->where);
2321 #endif
2322                         what = htonl(i->what);
2323                         fwrite(&where, sizeof(where), 1, f);
2324                         fwrite(&what, sizeof(what), 1, f);
2325                         
2326                 }
2327                 fclose(f);
2328         }
2329         
2330         m_cuesheet_changed = 0;
2331 }
2332
2333 void eDVBServicePlay::cutlistToCuesheet()
2334 {
2335         if (!m_cue)
2336         {
2337                 eDebug("no cue sheet");
2338                 return;
2339         }       
2340         m_cue->clear();
2341         
2342         if (!m_cutlist_enabled)
2343         {
2344                 m_cue->commitSpans();
2345                 eDebug("cutlists were disabled");
2346                 return;
2347         }
2348
2349         pts_t in = 0, out = 0, length = 0;
2350         
2351         getLength(length);
2352                 
2353         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2354         
2355         while (1)
2356         {
2357                 if (i == m_cue_entries.end())
2358                         out = length;
2359                 else {
2360                         if (i->what == 0) /* in */
2361                         {
2362                                 in = i++->where;
2363                                 continue;
2364                         } else if (i->what == 1) /* out */
2365                                 out = i++->where;
2366                         else /* mark (2) or last play position (3) */
2367                         {
2368                                 i++;
2369                                 continue;
2370                         }
2371                 }
2372                 
2373                 if (in != out)
2374                         m_cue->addSourceSpan(in, out);
2375                 
2376                 in = length;
2377                 
2378                 if (i == m_cue_entries.end())
2379                         break;
2380         }
2381         m_cue->commitSpans();
2382 }
2383
2384 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2385 {
2386         if (m_subtitle_widget)
2387                 disableSubtitles(parent);
2388
2389         ePyObject entry;
2390         int tuplesize = PyTuple_Size(tuple);
2391         int type = 0;
2392
2393         if (!PyTuple_Check(tuple))
2394                 goto error_out;
2395
2396         if (tuplesize < 1)
2397                 goto error_out;
2398
2399         entry = PyTuple_GET_ITEM(tuple, 0);
2400
2401         if (!PyInt_Check(entry))
2402                 goto error_out;
2403
2404         type = PyInt_AsLong(entry);
2405
2406         if (type == 1)  // teletext subtitles
2407         {
2408                 int page, magazine, pid;
2409                 if (tuplesize < 4)
2410                         goto error_out;
2411
2412                 if (!m_teletext_parser)
2413                 {
2414                         eDebug("enable teletext subtitles.. no parser !!!");
2415                         return -1;
2416                 }
2417
2418                 entry = PyTuple_GET_ITEM(tuple, 1);
2419                 if (!PyInt_Check(entry))
2420                         goto error_out;
2421                 pid = PyInt_AsLong(entry);
2422
2423                 entry = PyTuple_GET_ITEM(tuple, 2);
2424                 if (!PyInt_Check(entry))
2425                         goto error_out;
2426                 page = PyInt_AsLong(entry);
2427
2428                 entry = PyTuple_GET_ITEM(tuple, 3);
2429                 if (!PyInt_Check(entry))
2430                         goto error_out;
2431                 magazine = PyInt_AsLong(entry);
2432
2433                 m_subtitle_widget = new eSubtitleWidget(parent);
2434                 m_subtitle_widget->resize(parent->size()); /* full size */
2435                 m_teletext_parser->setPageAndMagazine(page, magazine);
2436                 if (m_dvb_service)
2437                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2438         }
2439         else if (type == 0)
2440         {
2441                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2442                 if (!m_subtitle_parser)
2443                 {
2444                         eDebug("enable dvb subtitles.. no parser !!!");
2445                         return -1;
2446                 }
2447                 if (tuplesize < 4)
2448                         goto error_out;
2449
2450                 entry = PyTuple_GET_ITEM(tuple, 1);
2451                 if (!PyInt_Check(entry))
2452                         goto error_out;
2453                 pid = PyInt_AsLong(entry);
2454
2455                 entry = PyTuple_GET_ITEM(tuple, 2);
2456                 if (!PyInt_Check(entry))
2457                         goto error_out;
2458                 composition_page_id = PyInt_AsLong(entry);
2459
2460                 entry = PyTuple_GET_ITEM(tuple, 3);
2461                 if (!PyInt_Check(entry))
2462                         goto error_out;
2463                 ancillary_page_id = PyInt_AsLong(entry);
2464
2465                 m_subtitle_widget = new eSubtitleWidget(parent);
2466                 m_subtitle_widget->resize(parent->size()); /* full size */
2467                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2468                 if (m_dvb_service)
2469                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2470         }
2471         else
2472                 goto error_out;
2473         return 0;
2474 error_out:
2475         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2476                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2477                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2478         return -1;
2479 }
2480
2481 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2482 {
2483         delete m_subtitle_widget;
2484         m_subtitle_widget = 0;
2485         if (m_subtitle_parser)
2486         {
2487                 m_subtitle_parser->stop();
2488                 m_dvb_subtitle_pages.clear();
2489         }
2490         if (m_teletext_parser)
2491         {
2492                 m_teletext_parser->setPageAndMagazine(-1, -1);
2493                 m_subtitle_pages.clear();
2494         }
2495         if (m_dvb_service)
2496                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2497         return 0;
2498 }
2499
2500 PyObject *eDVBServicePlay::getCachedSubtitle()
2501 {
2502         if (m_dvb_service)
2503         {
2504                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2505                 if (tmp != -1)
2506                 {
2507                         unsigned int data = (unsigned int)tmp;
2508                         int pid = (data&0xFFFF0000)>>16;
2509                         ePyObject tuple = PyTuple_New(4);
2510                         eDVBServicePMTHandler::program program;
2511                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2512                         if (!h.getProgramInfo(program))
2513                         {
2514                                 if (program.textPid==pid) // teletext
2515                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2516                                 else
2517                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2518                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
2519                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2520                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2521                                 return tuple;
2522                         }
2523                 }
2524         }
2525         Py_RETURN_NONE;
2526 }
2527
2528 PyObject *eDVBServicePlay::getSubtitleList()
2529 {
2530         if (!m_teletext_parser)
2531                 Py_RETURN_NONE;
2532         
2533         ePyObject l = PyList_New(0);
2534         std::set<int> added_ttx_pages;
2535
2536         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2537                 m_teletext_parser->m_found_subtitle_pages;
2538
2539         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2540         eDVBServicePMTHandler::program program;
2541         if (h.getProgramInfo(program))
2542                 eDebug("getting program info failed.");
2543         else
2544         {
2545                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2546                         it != program.subtitleStreams.end(); ++it)
2547                 {
2548                         switch(it->subtitling_type)
2549                         {
2550                                 case 0x01: // ebu teletext subtitles
2551                                 {
2552                                         int page_number = it->teletext_page_number & 0xFF;
2553                                         int magazine_number = it->teletext_magazine_number & 7;
2554                                         int hash = magazine_number << 8 | page_number;
2555                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2556                                         {
2557                                                 ePyObject tuple = PyTuple_New(5);
2558                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2559                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2560                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2561                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2562                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2563                                                 PyList_Append(l, tuple);
2564                                                 Py_DECREF(tuple);
2565                                                 added_ttx_pages.insert(hash);
2566                                         }
2567                                         break;
2568                                 }
2569                                 case 0x10 ... 0x13:
2570                                 case 0x20 ... 0x23: // dvb subtitles
2571                                 {
2572                                         ePyObject tuple = PyTuple_New(5);
2573                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2574                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2575                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2576                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2577                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2578                                         PyList_Insert(l, 0, tuple);
2579                                         Py_DECREF(tuple);
2580                                         break;
2581                                 }
2582                         }
2583                 }
2584         }
2585
2586         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2587                 it != subs.end(); ++it)
2588         {
2589                 int page_number = it->teletext_page_number & 0xFF;
2590                 int magazine_number = it->teletext_magazine_number & 7;
2591                 int hash = magazine_number << 8 | page_number;
2592                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2593                 {
2594                         ePyObject tuple = PyTuple_New(5);
2595                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2596                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2597                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2598                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2599                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2600                         PyList_Append(l, tuple);
2601                         Py_DECREF(tuple);
2602                 }
2603         }
2604
2605         return l;
2606 }
2607
2608 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2609 {
2610         if (m_subtitle_widget)
2611         {
2612                 m_subtitle_pages.push_back(page);
2613                 checkSubtitleTiming();
2614         }
2615 }
2616
2617 void eDVBServicePlay::checkSubtitleTiming()
2618 {
2619 //      eDebug("checkSubtitleTiming");
2620         if (!m_subtitle_widget)
2621                 return;
2622         while (1)
2623         {
2624                 enum { TELETEXT, DVB } type;
2625                 eDVBTeletextSubtitlePage page;
2626                 eDVBSubtitlePage dvb_page;
2627                 pts_t show_time;
2628                 if (!m_subtitle_pages.empty())
2629                 {
2630                         page = m_subtitle_pages.front();
2631                         type = TELETEXT;
2632                         show_time = page.m_pts;
2633                 }
2634                 else if (!m_dvb_subtitle_pages.empty())
2635                 {
2636                         dvb_page = m_dvb_subtitle_pages.front();
2637                         type = DVB;
2638                         show_time = dvb_page.m_show_time;
2639                 }
2640                 else
2641                         return;
2642         
2643                 pts_t pos = 0;
2644         
2645                 if (m_decoder)
2646                         m_decoder->getPTS(0, pos);
2647
2648 //              eDebug("%lld %lld", pos, show_time);
2649                 int diff =  show_time - pos;
2650                 if (diff < 0)
2651                 {
2652                         eDebug("[late (%d ms)]", -diff / 90);
2653                         diff = 0;
2654                 }
2655                 if (diff > 900000)
2656                 {
2657                         eDebug("[invalid]");
2658                         diff = 0;
2659                 }
2660         
2661                 if (!diff)
2662                 {
2663                         if (type == TELETEXT)
2664                         {
2665                                 eDebug("display teletext subtitle page");
2666                                 m_subtitle_widget->setPage(page);
2667                                 m_subtitle_pages.pop_front();
2668                         }
2669                         else
2670                         {
2671                                 eDebug("display dvb subtitle Page");
2672                                 m_subtitle_widget->setPage(dvb_page);
2673                                 m_dvb_subtitle_pages.pop_front();
2674                         }
2675                 } else
2676                 {
2677 //                      eDebug("start subtitle delay %d", diff / 90);
2678                         m_subtitle_sync_timer.start(diff / 90, 1);
2679                         break;
2680                 }
2681         }
2682 }
2683
2684 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2685 {
2686         if (m_subtitle_widget)
2687         {
2688                 m_dvb_subtitle_pages.push_back(p);
2689                 checkSubtitleTiming();
2690         }
2691 }
2692
2693 int eDVBServicePlay::getAC3Delay()
2694 {
2695         if (m_dvb_service)
2696                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2697         else if (m_decoder)
2698                 return m_decoder->getAC3Delay();
2699         else
2700                 return 0;
2701 }
2702
2703 int eDVBServicePlay::getPCMDelay()
2704 {
2705         if (m_dvb_service)
2706                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2707         else if (m_decoder)
2708                 return m_decoder->getPCMDelay();
2709         else
2710                 return 0;
2711 }
2712
2713 void eDVBServicePlay::setAC3Delay(int delay)
2714 {
2715         if (m_dvb_service)
2716                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2717         if (m_decoder)
2718                 m_decoder->setAC3Delay(delay);
2719 }
2720
2721 void eDVBServicePlay::setPCMDelay(int delay)
2722 {
2723         if (m_dvb_service)
2724                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2725         if (m_decoder)
2726                 m_decoder->setPCMDelay(delay);
2727 }
2728
2729 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
2730 {
2731         memcpy(&m_videoEventData, &event, sizeof(iTSMPEGDecoder::videoEvent));
2732         m_event((iPlayableService*)this, evVideoSizeChanged);
2733 }
2734
2735 DEFINE_REF(eDVBServicePlay)
2736
2737 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
2738 {
2739         switch (w)
2740         {
2741         case iServiceInformation::sTransponderData:
2742                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
2743         default:
2744                 break;
2745         }
2746         return iStaticServiceInformation::getInfoObject(ref, w);
2747 }
2748
2749 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");