fix path to default plugin.png
[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/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
19 #include <lib/base/nconfig.h> // access to python config
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 prio_order = eDVBFrontend::getTypePriorityOrder();
432                 int cur=0;
433                 eDVBChannelID chid, chid_ignore;
434                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
435                 for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
436                 {
437                         static unsigned char prio_map[6][3] = {
438                                 { 3, 2, 1 }, // -S -C -T
439                                 { 3, 1, 2 }, // -S -T -C
440                                 { 2, 3, 1 }, // -C -S -T
441                                 { 1, 3, 2 }, // -C -T -S
442                                 { 1, 2, 3 }, // -T -C -S
443                                 { 2, 1, 3 }  // -T -S -C
444                         };
445                         ((const eServiceReferenceDVB&)*it).getChannelID(chid);
446                         int tmp=res->canAllocateChannel(chid, chid_ignore);
447                         switch(tmp)
448                         {
449                                 case 0:
450                                         break;
451                                 case 30000: // cached DVB-T channel
452                                 case 1: // DVB-T frontend
453                                         tmp = prio_map[prio_order][2];
454                                         break;
455                                 case 40000: // cached DVB-C channel
456                                 case 2:
457                                         tmp = prio_map[prio_order][1];
458                                         break;
459                                 default: // DVB-S
460                                         tmp = prio_map[prio_order][0];
461                                         break;
462                         }
463                         if (tmp > cur)
464                         {
465                                 m_playable_service = *it;
466                                 cur = tmp;
467                         }
468                 }
469                 if (cur)
470                         return cur;
471         }
472         m_playable_service = eServiceReference();
473         return 0;
474 }
475
476 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
477 {
478         return -1;
479 }
480
481 #include <lib/dvb/epgcache.h>
482
483 RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
484 {
485         return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
486 }
487
488 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
489 {
490         DECLARE_REF(eStaticServiceDVBPVRInformation);
491         eServiceReference m_ref;
492         eDVBMetaParser m_parser;
493 public:
494         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
495         RESULT getName(const eServiceReference &ref, std::string &name);
496         int getLength(const eServiceReference &ref);
497         RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
498         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
499         int getInfo(const eServiceReference &ref, int w);
500         std::string getInfoString(const eServiceReference &ref,int w);
501 };
502
503 DEFINE_REF(eStaticServiceDVBPVRInformation);
504
505 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
506 {
507         m_ref = ref;
508         m_parser.parseFile(ref.path);
509 }
510
511 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
512 {
513         ASSERT(ref == m_ref);
514         if (m_parser.m_name.size())
515                 name = m_parser.m_name;
516         else
517         {
518                 name = ref.path;
519                 size_t n = name.rfind('/');
520                 if (n != std::string::npos)
521                         name = name.substr(n + 1);
522         }
523         return 0;
524 }
525
526 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
527 {
528         ASSERT(ref == m_ref);
529         
530         eDVBTSTools tstools;
531         
532         if (tstools.openFile(ref.path.c_str()))
533                 return 0;
534
535         pts_t len;
536         if (tstools.calcLen(len))
537                 return 0;
538
539         return len / 90000;
540 }
541
542 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
543 {
544         switch (w)
545         {
546         case iServiceInformation::sDescription:
547                 return iServiceInformation::resIsString;
548         case iServiceInformation::sServiceref:
549                 return iServiceInformation::resIsString;
550         case iServiceInformation::sTimeCreate:
551                 if (m_parser.m_time_create)
552                         return m_parser.m_time_create;
553                 else
554                         return iServiceInformation::resNA;
555         default:
556                 return iServiceInformation::resNA;
557         }
558 }
559
560 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
561 {
562         switch (w)
563         {
564         case iServiceInformation::sDescription:
565                 return m_parser.m_description;
566         case iServiceInformation::sServiceref:
567                 return m_parser.m_ref.toString();
568         case iServiceInformation::sTags:
569                 return m_parser.m_tags;
570         default:
571                 return "";
572         }
573 }
574
575 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
576 {
577         if (!ref.path.empty())
578         {
579                 ePtr<eServiceEvent> event = new eServiceEvent;
580                 std::string filename = ref.path;
581                 filename.erase(filename.length()-2, 2);
582                 filename+="eit";
583                 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
584                 {
585                         evt = event;
586                         return 0;
587                 }
588         }
589         evt = 0;
590         return -1;
591 }
592
593 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
594 {
595         DECLARE_REF(eDVBPVRServiceOfflineOperations);
596         eServiceReferenceDVB m_ref;
597 public:
598         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
599         
600         RESULT deleteFromDisk(int simulate);
601         RESULT getListOfFilenames(std::list<std::string> &);
602 };
603
604 DEFINE_REF(eDVBPVRServiceOfflineOperations);
605
606 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
607 {
608 }
609
610 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
611 {
612         if (simulate)
613                 return 0;
614         else
615         {
616                 std::list<std::string> res;
617                 if (getListOfFilenames(res))
618                         return -1;
619                 
620                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
621                 if (!eraser)
622                         eDebug("FATAL !! can't get background file eraser");
623                 
624                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
625                 {
626                         eDebug("Removing %s...", i->c_str());
627                         if (eraser)
628                                 eraser->erase(i->c_str());
629                         else
630                                 ::unlink(i->c_str());
631                 }
632                 
633                 return 0;
634         }
635 }
636
637 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
638 {
639         res.clear();
640         res.push_back(m_ref.path);
641
642 // handling for old splitted recordings (enigma 1)
643         char buf[255];
644         int slice=1;
645         while(true)
646         {
647                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
648                 struct stat s;
649                 if (stat(buf, &s) < 0)
650                         break;
651                 res.push_back(buf);
652         }       
653
654         res.push_back(m_ref.path + ".meta");
655         res.push_back(m_ref.path + ".ap");
656         res.push_back(m_ref.path + ".cuts");
657         std::string tmp = m_ref.path;
658         tmp.erase(m_ref.path.length()-3);
659         res.push_back(tmp + ".eit");
660         return 0;
661 }
662
663 DEFINE_REF(eServiceFactoryDVB)
664
665 eServiceFactoryDVB::eServiceFactoryDVB()
666 {
667         ePtr<eServiceCenter> sc;
668         
669         eServiceCenter::getPrivInstance(sc);
670         if (sc)
671         {
672                 std::list<std::string> extensions;
673                 extensions.push_back("ts");
674                 sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
675         }
676
677         m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
678         m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
679 }
680
681 eServiceFactoryDVB::~eServiceFactoryDVB()
682 {
683         ePtr<eServiceCenter> sc;
684         
685         eServiceCenter::getPrivInstance(sc);
686         if (sc)
687                 sc->removeServiceFactory(eServiceFactoryDVB::id);
688 }
689
690 DEFINE_REF(eDVBServiceList);
691
692 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
693 {
694 }
695
696 eDVBServiceList::~eDVBServiceList()
697 {
698 }
699
700 RESULT eDVBServiceList::startQuery()
701 {
702         ePtr<iDVBChannelList> db;
703         ePtr<eDVBResourceManager> res;
704         
705         int err;
706         if ((err = eDVBResourceManager::getInstance(res)) != 0)
707         {
708                 eDebug("no resource manager");
709                 return err;
710         }
711         if ((err = res->getChannelList(db)) != 0)
712         {
713                 eDebug("no channel list");
714                 return err;
715         }
716         
717         ePtr<eDVBChannelQuery> q;
718         
719         if (!m_parent.path.empty())
720         {
721                 eDVBChannelQuery::compile(q, m_parent.path);
722                 if (!q)
723                 {
724                         eDebug("compile query failed");
725                         return err;
726                 }
727         }
728         
729         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
730         {
731                 eDebug("startQuery failed");
732                 return err;
733         }
734
735         return 0;
736 }
737
738 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
739 {
740         eServiceReferenceDVB ref;
741         
742         if (!m_query)
743                 return -1;
744
745         while (!m_query->getNextResult(ref))
746                 list.push_back(ref);
747
748         if (sorted)
749                 list.sort(iListableServiceCompare(this));
750
751         return 0;
752 }
753
754 //   The first argument of this function is a format string to specify the order and
755 //   the content of the returned list
756 //   useable format options are
757 //   R = Service Reference (as swig object .. this is very slow)
758 //   S = Service Reference (as python string object .. same as ref.toString())
759 //   C = Service Reference (as python string object .. same as ref.toCompareString())
760 //   N = Service Name (as python string object)
761 //   n = Short Service Name (short name brakets used) (as python string object)
762 //   when exactly one return value per service is selected in the format string,
763 //   then each value is directly a list entry
764 //   when more than one value is returned per service, then the list is a list of
765 //   python tuples
766 //   unknown format string chars are returned as python None values !
767 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
768 {
769         ePyObject ret;
770         std::list<eServiceReference> tmplist;
771         int retcount=1;
772
773         if (!format || !(retcount=strlen(format)))
774                 format = "R"; // just return service reference swig object ...
775
776         if (!getContent(tmplist, sorted))
777         {
778                 int services=tmplist.size();
779                 ePtr<iStaticServiceInformation> sptr;
780                 eServiceCenterPtr service_center;
781
782                 if (strchr(format, 'N') || strchr(format, 'n'))
783                         eServiceCenter::getPrivInstance(service_center);
784
785                 ret = PyList_New(services);
786                 std::list<eServiceReference>::iterator it(tmplist.begin());
787
788                 for (int cnt=0; cnt < services; ++cnt)
789                 {
790                         eServiceReference &ref=*it++;
791                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
792                         for (int i=0; i < retcount; ++i)
793                         {
794                                 ePyObject tmp;
795                                 switch(format[i])
796                                 {
797                                 case 'R':  // service reference (swig)object
798                                         tmp = NEW_eServiceReference(ref);
799                                         break;
800                                 case 'C':  // service reference compare string
801                                         tmp = PyString_FromString(ref.toCompareString().c_str());
802                                         break;
803                                 case 'S':  // service reference string
804                                         tmp = PyString_FromString(ref.toString().c_str());
805                                         break;
806                                 case 'N':  // service name
807                                         if (service_center)
808                                         {
809                                                 service_center->info(ref, sptr);
810                                                 if (sptr)
811                                                 {
812                                                         std::string name;
813                                                         sptr->getName(ref, name);
814
815                                                         // filter short name brakets
816                                                         size_t pos;
817                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
818                                                                 name.erase(pos,2);
819                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
820                                                                 name.erase(pos,2);
821
822                                                         if (name.length())
823                                                                 tmp = PyString_FromString(name.c_str());
824                                                 }
825                                         }
826                                         if (!tmp)
827                                                 tmp = PyString_FromString("<n/a>");
828                                         break;
829                                 case 'n':  // short service name
830                                         if (service_center)
831                                         {
832                                                 service_center->info(ref, sptr);
833                                                 if (sptr)
834                                                 {
835                                                         std::string name;
836                                                         sptr->getName(ref, name);
837                                                         name = buildShortName(name);
838                                                         if (name.length())
839                                                                 tmp = PyString_FromString(name.c_str());
840                                                 }
841                                         }
842                                         if (!tmp)
843                                                 tmp = PyString_FromString("<n/a>");
844                                         break;
845                                 default:
846                                         if (tuple)
847                                         {
848                                                 tmp = Py_None;
849                                                 Py_INCREF(Py_None);
850                                         }
851                                         break;
852                                 }
853                                 if (tmp)
854                                 {
855                                         if (tuple)
856                                                 PyTuple_SET_ITEM(tuple, i, tmp);
857                                         else
858                                                 PyList_SET_ITEM(ret, cnt, tmp);
859                                 }
860                         }
861                         if (tuple)
862                                 PyList_SET_ITEM(ret, cnt, tuple);
863                 }
864         }
865         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
866 }
867
868 RESULT eDVBServiceList::getNext(eServiceReference &ref)
869 {
870         if (!m_query)
871                 return -1;
872         
873         return m_query->getNextResult((eServiceReferenceDVB&)ref);
874 }
875
876 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
877 {
878         if (m_parent.flags & eServiceReference::canDescent) // bouquet
879         {
880                 ePtr<iDVBChannelList> db;
881                 ePtr<eDVBResourceManager> resm;
882
883                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
884                         return -1;
885
886                 if (db->getBouquet(m_parent, m_bouquet) != 0)
887                         return -1;
888
889                 res = this;
890                 
891                 return 0;
892         }
893         res = 0;
894         return -1;
895 }
896
897 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
898 {
899         if (!m_bouquet)
900                 return -1;
901         return m_bouquet->addService(ref, before);
902 }
903
904 RESULT eDVBServiceList::removeService(eServiceReference &ref)
905 {
906         if (!m_bouquet)
907                 return -1;
908         return m_bouquet->removeService(ref);
909 }
910
911 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
912 {
913         if (!m_bouquet)
914                 return -1;
915         return m_bouquet->moveService(ref, pos);
916 }
917
918 RESULT eDVBServiceList::flushChanges()
919 {
920         if (!m_bouquet)
921                 return -1;
922         return m_bouquet->flushChanges();
923 }
924
925 RESULT eDVBServiceList::setListName(const std::string &name)
926 {
927         if (!m_bouquet)
928                 return -1;
929         return m_bouquet->setListName(name);
930 }
931
932 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
933 {
934         ePtr<eDVBService> service;
935         int r = lookupService(service, ref);
936         if (r)
937                 service = 0;
938                 // check resources...
939         ptr = new eDVBServicePlay(ref, service);
940         return 0;
941 }
942
943 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
944 {
945         if (ref.path.empty())
946         {
947                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
948                 return 0;
949         } else
950         {
951                 ptr = 0;
952                 return -1;
953         }
954 }
955
956 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
957 {
958         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
959         if (list->startQuery())
960         {
961                 ptr = 0;
962                 return -1;
963         }
964         
965         ptr = list;
966         return 0;
967 }
968
969 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
970 {
971         /* is a listable service? */
972         if (ref.flags & eServiceReference::canDescent) // bouquet
973         {
974                 if ( !ref.name.empty() )  // satellites or providers list
975                         ptr = m_StaticServiceDVBInfo;
976                 else // a dvb bouquet
977                         ptr = m_StaticServiceDVBBouquetInfo;
978         }
979         else if (!ref.path.empty()) /* do we have a PVR service? */
980                 ptr = new eStaticServiceDVBPVRInformation(ref);
981         else // normal dvb service
982         {
983                 ePtr<eDVBService> service;
984                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
985                         ptr = m_StaticServiceDVBInfo;
986                 else
987                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
988                         ptr = service;
989         }
990         return 0;
991 }
992
993 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
994 {
995         if (ref.path.empty())
996         {
997                 ptr = 0;
998                 return -1;
999         } else
1000         {
1001                 ptr = new eDVBPVRServiceOfflineOperations(ref);
1002                 return 0;
1003         }
1004 }
1005
1006 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
1007 {
1008                         // TODO: handle the listing itself
1009         // if (ref.... == -1) .. return "... bouquets ...";
1010         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
1011                         // TODO: cache
1012         ePtr<iDVBChannelList> db;
1013         ePtr<eDVBResourceManager> res;
1014         
1015         int err;
1016         if ((err = eDVBResourceManager::getInstance(res)) != 0)
1017         {
1018                 eDebug("no resource manager");
1019                 return err;
1020         }
1021         if ((err = res->getChannelList(db)) != 0)
1022         {
1023                 eDebug("no channel list");
1024                 return err;
1025         }
1026         
1027                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
1028         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
1029         {
1030                 eDebug("getService failed!");
1031                 return err;
1032         }
1033
1034         return 0;
1035 }
1036
1037 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
1038         m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
1039 {
1040         memset(&m_videoEventData, 0, sizeof(struct iTSMPEGDecoder::videoEvent));
1041         m_is_primary = 1;
1042         m_is_pvr = !m_reference.path.empty();
1043         
1044         m_timeshift_enabled = m_timeshift_active = 0;
1045         m_skipmode = 0;
1046         
1047         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
1048         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
1049         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
1050
1051         m_cuesheet_changed = 0;
1052         m_cutlist_enabled = 1;
1053         
1054         m_subtitle_widget = 0;
1055         
1056         m_tune_state = -1;
1057
1058         CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
1059 }
1060
1061 eDVBServicePlay::~eDVBServicePlay()
1062 {
1063         delete m_subtitle_widget;
1064 }
1065
1066 void eDVBServicePlay::gotNewEvent()
1067 {
1068 #if 0
1069                 // debug only
1070         ePtr<eServiceEvent> m_event_now, m_event_next;
1071         getEvent(m_event_now, 0);
1072         getEvent(m_event_next, 1);
1073
1074         if (m_event_now)
1075                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
1076         if (m_event_next)
1077                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
1078 #endif
1079         m_event((iPlayableService*)this, evUpdatedEventInfo);
1080 }
1081
1082 void eDVBServicePlay::serviceEvent(int event)
1083 {
1084         m_tune_state = event;
1085
1086         switch (event)
1087         {
1088         case eDVBServicePMTHandler::eventTuned:
1089         {
1090                 ePtr<iDVBDemux> m_demux;
1091                 if (!m_service_handler.getDataDemux(m_demux))
1092                 {
1093                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
1094                         int sid = ref.getParentServiceID().get();
1095                         if (!sid)
1096                                 sid = ref.getServiceID().get();
1097                         if ( ref.getParentTransportStreamID().get() &&
1098                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
1099                                 m_event_handler.startOther(m_demux, sid);
1100                         else
1101                                 m_event_handler.start(m_demux, sid);
1102                 }
1103                 break;
1104         }
1105         case eDVBServicePMTHandler::eventNoResources:
1106         case eDVBServicePMTHandler::eventNoPAT:
1107         case eDVBServicePMTHandler::eventNoPATEntry:
1108         case eDVBServicePMTHandler::eventNoPMT:
1109         case eDVBServicePMTHandler::eventTuneFailed:
1110         case eDVBServicePMTHandler::eventMisconfiguration:
1111         {
1112                 eDebug("DVB service failed to tune - error %d", event);
1113                 m_event((iPlayableService*)this, evTuneFailed);
1114                 break;
1115         }
1116         case eDVBServicePMTHandler::eventNewProgramInfo:
1117         {
1118                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
1119                 if (m_timeshift_enabled)
1120                         updateTimeshiftPids();
1121                 if (!m_timeshift_active)
1122                         updateDecoder();
1123                 if (m_first_program_info && m_is_pvr)
1124                 {
1125                         m_first_program_info = 0;
1126                         seekTo(0);
1127                 }
1128                 m_event((iPlayableService*)this, evUpdatedInfo);
1129                 break;
1130         }
1131         case eDVBServicePMTHandler::eventEOF:
1132                 m_event((iPlayableService*)this, evEOF);
1133                 break;
1134         case eDVBServicePMTHandler::eventSOF:
1135                 m_event((iPlayableService*)this, evSOF);
1136                 break;
1137         }
1138 }
1139
1140 void eDVBServicePlay::serviceEventTimeshift(int event)
1141 {
1142         switch (event)
1143         {
1144         case eDVBServicePMTHandler::eventNewProgramInfo:
1145                 if (m_timeshift_active)
1146                         updateDecoder();
1147                 break;
1148         case eDVBServicePMTHandler::eventSOF:
1149                 m_event((iPlayableService*)this, evSOF);
1150                 break;
1151         case eDVBServicePMTHandler::eventEOF:
1152                 if ((!m_is_paused) && (m_skipmode >= 0))
1153                         switchToLive();
1154                 break;
1155         }
1156 }
1157
1158 RESULT eDVBServicePlay::start()
1159 {
1160         int r;
1161                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
1162                    two (one for decoding, one for data source), as we must be prepared
1163                    to start recording from the data demux. */
1164         if (m_is_pvr)
1165                 m_cue = new eCueSheet();
1166         else
1167                 m_event(this, evStart);
1168
1169         m_first_program_info = 1;
1170         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
1171         r = m_service_handler.tune(service, m_is_pvr, m_cue);
1172
1173                 /* inject EIT if there is a stored one */
1174         if (m_is_pvr)
1175         {
1176                 std::string filename = service.path;
1177                 filename.erase(filename.length()-2, 2);
1178                 filename+="eit";
1179                 ePtr<eServiceEvent> event = new eServiceEvent;
1180                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
1181                 {
1182                         ePtr<eServiceEvent> empty;
1183                         m_event_handler.inject(event, 0);
1184                         m_event_handler.inject(empty, 1);
1185                 }
1186         }
1187
1188         if (m_is_pvr)
1189         {
1190                 loadCuesheet();
1191                 m_event(this, evStart);
1192         }
1193         return 0;
1194 }
1195
1196 RESULT eDVBServicePlay::stop()
1197 {
1198                 /* add bookmark for last play position */
1199         if (m_is_pvr)
1200         {
1201                 pts_t play_position, length;
1202                 if (!getPlayPosition(play_position))
1203                 {
1204                                 /* remove last position */
1205                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
1206                         {
1207                                 if (i->what == 3) /* current play position */
1208                                 {
1209                                         m_cue_entries.erase(i);
1210                                         i = m_cue_entries.begin();
1211                                         continue;
1212                                 } else
1213                                         ++i;
1214                         }
1215                         
1216                         if (getLength(length))
1217                                 length = 0;
1218                         
1219                         if (length)
1220                         {
1221                                 int perc = play_position * 100LL / length;
1222                         
1223                                         /* only store last play position when between 5% and 95% */
1224                                 if ((5 < perc) && (perc < 95))
1225                                         m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
1226                         }
1227                         m_cuesheet_changed = 1;
1228                 }
1229         }
1230
1231         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
1232
1233         m_service_handler_timeshift.free();
1234         m_service_handler.free();
1235         
1236         if (m_is_pvr && m_cuesheet_changed)
1237         {
1238                 struct stat s;
1239                                 /* save cuesheet only when main file is accessible. */
1240                 if (!::stat(m_reference.path.c_str(), &s))
1241                         saveCuesheet();
1242         }
1243         m_event((iPlayableService*)this, evStopped);
1244         return 0;
1245 }
1246
1247 RESULT eDVBServicePlay::setTarget(int target)
1248 {
1249         m_is_primary = !target;
1250         return 0;
1251 }
1252
1253 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
1254 {
1255         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
1256         return 0;
1257 }
1258
1259 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
1260 {
1261                 /* note: we check for timeshift to be enabled,
1262                    not neccessary active. if you pause when timeshift
1263                    is not active, you should activate it when unpausing */
1264         if ((!m_is_pvr) && (!m_timeshift_enabled))
1265         {
1266                 ptr = 0;
1267                 return -1;
1268         }
1269
1270         ptr = this;
1271         return 0;
1272 }
1273
1274 RESULT eDVBServicePlay::setSlowMotion(int ratio)
1275 {
1276         if (m_decoder)
1277                 return m_decoder->setSlowMotion(ratio);
1278         else
1279                 return -1;
1280 }
1281
1282 RESULT eDVBServicePlay::setFastForward(int ratio)
1283 {
1284         int skipmode, ffratio;
1285         
1286         if (ratio > 8)
1287         {
1288                 skipmode = ratio;
1289                 ffratio = 1;
1290         } else if (ratio > 0)
1291         {
1292                 skipmode = 0;
1293                 ffratio = ratio;
1294         } else if (!ratio)
1295         {
1296                 skipmode = 0;
1297                 ffratio = 0;
1298         } else // if (ratio < 0)
1299         {
1300                 skipmode = ratio;
1301                 ffratio = 1;
1302         }
1303
1304         if (m_skipmode != skipmode)
1305         {
1306                 eDebug("setting cue skipmode to %d", skipmode);
1307                 if (m_cue)
1308                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
1309         }
1310         
1311         m_skipmode = skipmode;
1312         
1313         if (!m_decoder)
1314                 return -1;
1315
1316         return m_decoder->setFastForward(ffratio);
1317 }
1318
1319 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
1320 {
1321         if (m_is_pvr || m_timeshift_enabled)
1322         {
1323                 ptr = this;
1324                 return 0;
1325         }
1326         
1327         ptr = 0;
1328         return -1;
1329 }
1330
1331         /* TODO: when timeshift is enabled but not active, this doesn't work. */
1332 RESULT eDVBServicePlay::getLength(pts_t &len)
1333 {
1334         ePtr<iDVBPVRChannel> pvr_channel;
1335         
1336         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1337                 return -1;
1338         
1339         return pvr_channel->getLength(len);
1340 }
1341
1342 RESULT eDVBServicePlay::pause()
1343 {
1344         if (!m_is_paused && m_decoder)
1345         {
1346                 m_is_paused = 1;
1347                 return m_decoder->freeze(0);
1348         } else
1349                 return -1;
1350 }
1351
1352 RESULT eDVBServicePlay::unpause()
1353 {
1354         if (m_is_paused && m_decoder)
1355         {
1356                 m_is_paused = 0;
1357                 return m_decoder->unfreeze();
1358         } else
1359                 return -1;
1360 }
1361
1362 RESULT eDVBServicePlay::seekTo(pts_t to)
1363 {
1364         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
1365         
1366         if (!m_decode_demux)
1367                 return -1;
1368
1369         ePtr<iDVBPVRChannel> pvr_channel;
1370         
1371         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1372                 return -1;
1373         
1374         if (!m_cue)
1375                 return -1;
1376         
1377         m_cue->seekTo(0, to);
1378         m_dvb_subtitle_pages.clear();
1379         m_subtitle_pages.clear();
1380
1381         return 0;
1382 }
1383
1384 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
1385 {
1386         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
1387         
1388         if (!m_decode_demux)
1389                 return -1;
1390
1391         ePtr<iDVBPVRChannel> pvr_channel;
1392         
1393         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1394                 return -1;
1395         
1396         int mode = 1;
1397         
1398                         /* HACK until we have skip-AP api */
1399         if ((to > 0) && (to < 100))
1400                 mode = 2;
1401         
1402         to *= direction;
1403         
1404         if (!m_cue)
1405                 return 0;
1406         
1407         m_cue->seekTo(mode, to);
1408         m_dvb_subtitle_pages.clear();
1409         m_subtitle_pages.clear();
1410         return 0;
1411 }
1412
1413 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1414 {
1415         ePtr<iDVBPVRChannel> pvr_channel;
1416         
1417         if (!m_decode_demux)
1418                 return -1;
1419         
1420         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1421                 return -1;
1422         
1423         int r = 0;
1424
1425                 /* if there is a decoder, use audio or video PTS */
1426         if (m_decoder)
1427         {
1428                 r = m_decoder->getPTS(0, pos);
1429                 if (r)
1430                         return r;
1431         }
1432         
1433                 /* fixup */
1434         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1435 }
1436
1437 RESULT eDVBServicePlay::setTrickmode(int trick)
1438 {
1439         if (m_decoder)
1440                 m_decoder->setTrickmode(trick);
1441         return 0;
1442 }
1443
1444 RESULT eDVBServicePlay::isCurrentlySeekable()
1445 {
1446         return m_is_pvr || m_timeshift_active;
1447 }
1448
1449 RESULT eDVBServicePlay::seekChapter(int chapter)
1450 {
1451                 /* seekChapter N/I. */
1452         return -1;
1453 }
1454
1455 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1456 {
1457         ptr = this;
1458         return 0;
1459 }
1460
1461 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1462 {
1463         ptr = this;
1464         return 0;
1465 }
1466
1467 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1468 {
1469         ptr = this;
1470         return 0;
1471 }
1472
1473 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1474 {
1475         ptr = this;
1476         return 0;
1477 }
1478
1479 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1480 {
1481         ptr = this;
1482         return 0;
1483 }
1484
1485 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1486 {
1487         ptr = 0;
1488         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1489                 (m_timeshift_enabled || !m_is_pvr))
1490         {
1491                 if (!m_timeshift_enabled)
1492                 {
1493                                 /* we need enough diskspace */
1494                         struct statfs fs;
1495                         if (statfs(TSPATH "/.", &fs) < 0)
1496                         {
1497                                 eDebug("statfs failed!");
1498                                 return -2;
1499                         }
1500                 
1501                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1502                         {
1503                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1504                                 return -3;
1505                         }
1506                 }
1507                 ptr = this;
1508                 return 0;
1509         }
1510         return -1;
1511 }
1512
1513 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1514 {
1515         if (m_is_pvr)
1516         {
1517                 ptr = this;
1518                 return 0;
1519         }
1520         ptr = 0;
1521         return -1;
1522 }
1523
1524 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1525 {
1526         ptr = this;
1527         return 0;
1528 }
1529
1530 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1531 {
1532         ptr = this;
1533         return 0;
1534 }
1535
1536 RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
1537 {
1538         ptr = this;
1539         return 0;
1540 }
1541
1542 RESULT eDVBServicePlay::getName(std::string &name)
1543 {
1544         if (m_is_pvr)
1545         {
1546                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1547                 return i->getName(m_reference, name);
1548         }
1549         if (m_dvb_service)
1550         {
1551                 m_dvb_service->getName(m_reference, name);
1552                 if (name.empty())
1553                         name = "(...)";
1554         }
1555         else if (!m_reference.name.empty())
1556                 eStaticServiceDVBInformation().getName(m_reference, name);
1557         else
1558                 name = "DVB service";
1559         return 0;
1560 }
1561
1562 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1563 {
1564         return m_event_handler.getEvent(evt, nownext);
1565 }
1566
1567 int eDVBServicePlay::getInfo(int w)
1568 {
1569         eDVBServicePMTHandler::program program;
1570         
1571         if (w == sCAIDs)
1572                 return resIsPyObject;
1573
1574         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1575         
1576         int no_program_info = 0;
1577         
1578         if (h.getProgramInfo(program))
1579                 no_program_info = 1;
1580         
1581         switch (w)
1582         {
1583 #if HAVE_DVB_API_VERSION >= 3
1584         case sVideoHeight:
1585                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1586                         return m_videoEventData.height;
1587                 return -1;
1588         case sVideoWidth:
1589                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1590                         return m_videoEventData.width;
1591                 return -1;
1592 #else
1593 #warning "FIXMEE implement sVideoHeight, sVideoWidth for old DVB API"
1594 #endif
1595         case sAspect:
1596 #if HAVE_DVB_API_VERSION >= 3
1597                 if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
1598                         return m_videoEventData.aspect == VIDEO_FORMAT_4_3 ? 1 : 3;
1599                 else
1600 #else
1601 #warning "FIXMEE implement sAspect for old DVB API"
1602 #endif
1603                 if (no_program_info)
1604                         return -1; 
1605                 else if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1606                 {
1607                         ePtr<eServiceEvent> evt;
1608                         if (!m_event_handler.getEvent(evt, 0))
1609                         {
1610                                 ePtr<eComponentData> data;
1611                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1612                                 {
1613                                         if ( data->getStreamContent() == 1 )
1614                                         {
1615                                                 switch(data->getComponentType())
1616                                                 {
1617                                                         // SD
1618                                                         case 1: // 4:3 SD PAL
1619                                                         case 2:
1620                                                         case 3: // 16:9 SD PAL
1621                                                         case 4: // > 16:9 PAL
1622                                                         case 5: // 4:3 SD NTSC
1623                                                         case 6: 
1624                                                         case 7: // 16:9 SD NTSC
1625                                                         case 8: // > 16:9 NTSC
1626
1627                                                         // HD
1628                                                         case 9: // 4:3 HD PAL
1629                                                         case 0xA:
1630                                                         case 0xB: // 16:9 HD PAL
1631                                                         case 0xC: // > 16:9 HD PAL
1632                                                         case 0xD: // 4:3 HD NTSC
1633                                                         case 0xE:
1634                                                         case 0xF: // 16:9 HD NTSC
1635                                                         case 0x10: // > 16:9 HD PAL
1636                                                                 return data->getComponentType();
1637                                                 }
1638                                         }
1639                                 }
1640                         }
1641                 }
1642                 return -1;
1643         case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
1644         case sVideoPID: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1645         case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1646         case sAudioPID: if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1647         case sPCRPID: if (no_program_info) return -1; return program.pcrPid;
1648         case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
1649         case sTXTPID: if (no_program_info) return -1; return program.textPid;
1650         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1651         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1652         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1653         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1654         case sProvider: if (!m_dvb_service) return -1; return -2;
1655         case sServiceref: return resIsString;
1656         case sDVBState: return m_tune_state;
1657         default:
1658                 return -1;
1659         }
1660 }
1661
1662 std::string eDVBServicePlay::getInfoString(int w)
1663 {
1664         switch (w)
1665         {
1666         case sProvider:
1667                 if (!m_dvb_service) return "";
1668                 return m_dvb_service->m_provider_name;
1669         case sServiceref:
1670                 return m_reference.toString();
1671         default:
1672                 break;
1673         }
1674         return iServiceInformation::getInfoString(w);
1675 }
1676
1677 PyObject *eDVBServicePlay::getInfoObject(int w)
1678 {
1679         switch (w)
1680         {
1681         case sCAIDs:
1682                 return m_service_handler.getCaIds();
1683         case sTransponderData:
1684                 return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
1685         default:
1686                 break;
1687         }
1688         return iServiceInformation::getInfoObject(w);
1689 }
1690
1691 int eDVBServicePlay::getNumberOfTracks()
1692 {
1693         eDVBServicePMTHandler::program program;
1694         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1695         if (h.getProgramInfo(program))
1696                 return 0;
1697         return program.audioStreams.size();
1698 }
1699
1700 int eDVBServicePlay::getCurrentTrack()
1701 {
1702         eDVBServicePMTHandler::program program;
1703         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1704         if (h.getProgramInfo(program))
1705                 return 0;
1706
1707         int max = program.audioStreams.size();
1708         int i;
1709
1710         for (i = 0; i < max; ++i)
1711                 if (program.audioStreams[i].pid == m_current_audio_pid)
1712                         return i;
1713
1714         return 0;
1715 }
1716
1717 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1718 {
1719         int ret = selectAudioStream(i);
1720
1721         if (m_decoder->start())
1722                 return -5;
1723
1724         return ret;
1725 }
1726
1727 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1728 {
1729         eDVBServicePMTHandler::program program;
1730         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1731
1732         if (h.getProgramInfo(program))
1733                 return -1;
1734         
1735         if (i >= program.audioStreams.size())
1736                 return -2;
1737         
1738         info.m_pid = program.audioStreams[i].pid;
1739
1740         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1741                 info.m_description = "MPEG";
1742         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1743                 info.m_description = "AC3";
1744         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1745                 info.m_description = "AAC";
1746         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1747                 info.m_description = "DTS";
1748         else
1749                 info.m_description = "???";
1750
1751         if (program.audioStreams[i].component_tag != -1)
1752         {
1753                 ePtr<eServiceEvent> evt;
1754                 if (!m_event_handler.getEvent(evt, 0))
1755                 {
1756                         ePtr<eComponentData> data;
1757                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1758                                 info.m_language = data->getText();
1759                 }
1760         }
1761
1762         if (info.m_language.empty())
1763                 info.m_language = program.audioStreams[i].language_code;
1764         
1765         return 0;
1766 }
1767
1768 int eDVBServicePlay::selectAudioStream(int i)
1769 {
1770         eDVBServicePMTHandler::program program;
1771         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1772
1773         if (h.getProgramInfo(program))
1774                 return -1;
1775
1776         if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
1777                 return -2;
1778
1779         if (!m_decoder)
1780                 return -3;
1781
1782         int stream = i;
1783         if (stream == -1)
1784                 stream = program.defaultAudioStream;
1785
1786         int apid = -1, apidtype = -1;
1787
1788         if (((unsigned int)stream) < program.audioStreams.size())
1789         {
1790                 apid = program.audioStreams[stream].pid;
1791                 apidtype = program.audioStreams[stream].type;
1792         }
1793
1794         m_current_audio_pid = apid;
1795
1796         if (m_decoder->setAudioPID(apid, apidtype))
1797         {
1798                 eDebug("set audio pid failed");
1799                 return -4;
1800         }
1801
1802                 /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
1803         if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1804                 if (!m_rds_decoder)
1805                 {
1806                         ePtr<iDVBDemux> data_demux;
1807                         if (!h.getDataDemux(data_demux))
1808                         {
1809                                 m_rds_decoder = new eDVBRdsDecoder(data_demux);
1810                                 m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
1811                         }
1812                 }
1813
1814                 /* if we decided that we need one, update the pid */
1815         if (m_rds_decoder)
1816                 m_rds_decoder->start(apid);
1817
1818                         /* store new pid as default only when:
1819                                 a.) we have an entry in the service db for the current service,
1820                                 b.) we are not playing back something,
1821                                 c.) we are not selecting the default entry. (we wouldn't change 
1822                                     anything in the best case, or destroy the default setting in
1823                                     case the real default is not yet available.)
1824                         */
1825         if (m_dvb_service && !m_is_pvr && ((i != -1)
1826                 || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
1827         {
1828                 if (apidtype == eDVBAudio::aMPEG)
1829                 {
1830                         m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1831                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1832                 }
1833                 else
1834                 {
1835                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1836                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1837                 }
1838         }
1839
1840         h.resetCachedProgram();
1841
1842         return 0;
1843 }
1844
1845 int eDVBServicePlay::getCurrentChannel()
1846 {
1847         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1848 }
1849
1850 RESULT eDVBServicePlay::selectChannel(int i)
1851 {
1852         if (i < LEFT || i > RIGHT || i == STEREO)
1853                 i = -1;  // Stereo
1854         if (m_dvb_service)
1855                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1856         if (m_decoder)
1857                 m_decoder->setAudioChannel(i);
1858         return 0;
1859 }
1860
1861 std::string eDVBServicePlay::getText(int x)
1862 {
1863         if (m_rds_decoder)
1864                 switch(x)
1865                 {
1866                         case RadioText:
1867                                 return convertLatin1UTF8(m_rds_decoder->getRadioText());
1868                         case RtpText:
1869                                 return convertLatin1UTF8(m_rds_decoder->getRtpText());
1870                 }
1871         return "";
1872 }
1873
1874 void eDVBServicePlay::rdsDecoderEvent(int what)
1875 {
1876         switch(what)
1877         {
1878                 case eDVBRdsDecoder::RadioTextChanged:
1879                         m_event((iPlayableService*)this, evUpdatedRadioText);
1880                         break;
1881                 case eDVBRdsDecoder::RtpTextChanged:
1882                         m_event((iPlayableService*)this, evUpdatedRtpText);
1883                         break;
1884                 case eDVBRdsDecoder::RassInteractivePicMaskChanged:
1885                         m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
1886                         break;
1887                 case eDVBRdsDecoder::RecvRassSlidePic:
1888                         m_event((iPlayableService*)this, evUpdatedRassSlidePic);
1889                         break;
1890         }
1891 }
1892
1893 void eDVBServicePlay::showRassSlidePicture()
1894 {
1895         if (m_rds_decoder)
1896         {
1897                 if (m_decoder)
1898                 {
1899                         std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
1900                         if (rass_slide_pic.length())
1901                                 m_decoder->showSinglePic(rass_slide_pic.c_str());
1902                         else
1903                                 eDebug("empty filename for rass slide picture received!!");
1904                 }
1905                 else
1906                         eDebug("no MPEG Decoder to show iframes avail");
1907         }
1908         else
1909                 eDebug("showRassSlidePicture called.. but not decoder");
1910 }
1911
1912 void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
1913 {
1914         if (m_rds_decoder)
1915         {
1916                 if (m_decoder)
1917                 {
1918                         std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
1919                         if (rass_interactive_pic.length())
1920                                 m_decoder->showSinglePic(rass_interactive_pic.c_str());
1921                         else
1922                                 eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
1923                 }
1924                 else
1925                         eDebug("no MPEG Decoder to show iframes avail");
1926         }
1927         else
1928                 eDebug("showRassInteractivePic called.. but not decoder");
1929 }
1930
1931 ePyObject eDVBServicePlay::getRassInteractiveMask()
1932 {
1933         if (m_rds_decoder)
1934                 return m_rds_decoder->getRassPictureMask();
1935         Py_RETURN_NONE;
1936 }
1937
1938 int eDVBServiceBase::getFrontendInfo(int w)
1939 {
1940         eUsePtr<iDVBChannel> channel;
1941         if(m_service_handler.getChannel(channel))
1942                 return 0;
1943         ePtr<iDVBFrontend> fe;
1944         if(channel->getFrontend(fe))
1945                 return 0;
1946         return fe->readFrontendData(w);
1947 }
1948
1949 PyObject *eDVBServiceBase::getFrontendData()
1950 {
1951         ePyObject ret = PyDict_New();
1952         if (ret)
1953         {
1954                 eUsePtr<iDVBChannel> channel;
1955                 if(!m_service_handler.getChannel(channel))
1956                 {
1957                         ePtr<iDVBFrontend> fe;
1958                         if(!channel->getFrontend(fe))
1959                                 fe->getFrontendData(ret);
1960                 }
1961         }
1962         else
1963                 Py_RETURN_NONE;
1964         return ret;
1965 }
1966
1967 PyObject *eDVBServiceBase::getFrontendStatus()
1968 {
1969         ePyObject ret = PyDict_New();
1970         if (ret)
1971         {
1972                 eUsePtr<iDVBChannel> channel;
1973                 if(!m_service_handler.getChannel(channel))
1974                 {
1975                         ePtr<iDVBFrontend> fe;
1976                         if(!channel->getFrontend(fe))
1977                                 fe->getFrontendStatus(ret);
1978                 }
1979         }
1980         else
1981                 Py_RETURN_NONE;
1982         return ret;
1983 }
1984
1985 PyObject *eDVBServiceBase::getTransponderData(bool original)
1986 {
1987         ePyObject ret = PyDict_New();
1988         if (ret)
1989         {
1990                 eUsePtr<iDVBChannel> channel;
1991                 if(!m_service_handler.getChannel(channel))
1992                 {
1993                         ePtr<iDVBFrontend> fe;
1994                         if(!channel->getFrontend(fe))
1995                         {
1996                                 fe->getTransponderData(ret, original);
1997                                 ePtr<iDVBFrontendParameters> feparm;
1998                                 channel->getCurrentFrontendParameters(feparm);
1999                                 if (feparm)
2000                                 {
2001                                         eDVBFrontendParametersSatellite osat;
2002                                         if (!feparm->getDVBS(osat))
2003                                         {
2004                                                 void PutToDict(ePyObject &, const char*, long);
2005                                                 void PutToDict(ePyObject &, const char*, const char*);
2006                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
2007                                                 const char *tmp = "UNKNOWN";
2008                                                 switch(osat.polarisation)
2009                                                 {
2010                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
2011                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
2012                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
2013                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
2014                                                         default:break;
2015                                                 }
2016                                                 PutToDict(ret, "polarization", tmp);
2017                                         }
2018                                 }
2019                         }
2020                 }
2021         }
2022         else
2023                 Py_RETURN_NONE;
2024         return ret;
2025 }
2026
2027 PyObject *eDVBServiceBase::getAll(bool original)
2028 {
2029         ePyObject ret = getTransponderData(original);
2030         if (ret != Py_None)
2031         {
2032                 eUsePtr<iDVBChannel> channel;
2033                 if(!m_service_handler.getChannel(channel))
2034                 {
2035                         ePtr<iDVBFrontend> fe;
2036                         if(!channel->getFrontend(fe))
2037                         {
2038                                 fe->getFrontendData(ret);
2039                                 fe->getFrontendStatus(ret);
2040                         }
2041                 }
2042         }
2043         return ret;
2044 }
2045
2046 int eDVBServicePlay::getNumberOfSubservices()
2047 {
2048         ePtr<eServiceEvent> evt;
2049         if (!m_event_handler.getEvent(evt, 0))
2050                 return evt->getNumOfLinkageServices();
2051         return 0;
2052 }
2053
2054 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
2055 {
2056         ePtr<eServiceEvent> evt;
2057         if (!m_event_handler.getEvent(evt, 0))
2058         {
2059                 if (!evt->getLinkageService(sub, m_reference, n))
2060                         return 0;
2061         }
2062         sub.type=eServiceReference::idInvalid;
2063         return -1;
2064 }
2065
2066 RESULT eDVBServicePlay::startTimeshift()
2067 {
2068         ePtr<iDVBDemux> demux;
2069         
2070         eDebug("Start timeshift!");
2071         
2072         if (m_timeshift_enabled)
2073                 return -1;
2074         
2075                 /* start recording with the data demux. */
2076         if (m_service_handler.getDataDemux(demux))
2077                 return -2;
2078
2079         demux->createTSRecorder(m_record);
2080         if (!m_record)
2081                 return -3;
2082
2083         char templ[]=TSPATH "/timeshift.XXXXXX";
2084         m_timeshift_fd = mkstemp(templ);
2085         m_timeshift_file = templ;
2086         
2087         eDebug("recording to %s", templ);
2088         
2089         if (m_timeshift_fd < 0)
2090         {
2091                 m_record = 0;
2092                 return -4;
2093         }
2094                 
2095         m_record->setTargetFD(m_timeshift_fd);
2096
2097         m_timeshift_enabled = 1;
2098         
2099         updateTimeshiftPids();
2100         m_record->start();
2101
2102         return 0;
2103 }
2104
2105 RESULT eDVBServicePlay::stopTimeshift()
2106 {
2107         if (!m_timeshift_enabled)
2108                 return -1;
2109         
2110         switchToLive();
2111         
2112         m_timeshift_enabled = 0;
2113         
2114         m_record->stop();
2115         m_record = 0;
2116         
2117         close(m_timeshift_fd);
2118         eDebug("remove timeshift file");
2119         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
2120         
2121         return 0;
2122 }
2123
2124 int eDVBServicePlay::isTimeshiftActive()
2125 {
2126         return m_timeshift_enabled && m_timeshift_active;
2127 }
2128
2129 RESULT eDVBServicePlay::activateTimeshift()
2130 {
2131         if (!m_timeshift_enabled)
2132                 return -1;
2133         
2134         if (!m_timeshift_active)
2135         {
2136                 switchToTimeshift();
2137                 return 0;
2138         }
2139         
2140         return -2;
2141 }
2142
2143 PyObject *eDVBServicePlay::getCutList()
2144 {
2145         ePyObject list = PyList_New(0);
2146         
2147         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2148         {
2149                 ePyObject tuple = PyTuple_New(2);
2150                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
2151                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
2152                 PyList_Append(list, tuple);
2153                 Py_DECREF(tuple);
2154         }
2155         
2156         return list;
2157 }
2158
2159 void eDVBServicePlay::setCutList(ePyObject list)
2160 {
2161         if (!PyList_Check(list))
2162                 return;
2163         int size = PyList_Size(list);
2164         int i;
2165         
2166         m_cue_entries.clear();
2167         
2168         for (i=0; i<size; ++i)
2169         {
2170                 ePyObject tuple = PyList_GET_ITEM(list, i);
2171                 if (!PyTuple_Check(tuple))
2172                 {
2173                         eDebug("non-tuple in cutlist");
2174                         continue;
2175                 }
2176                 if (PyTuple_Size(tuple) != 2)
2177                 {
2178                         eDebug("cutlist entries need to be a 2-tuple");
2179                         continue;
2180                 }
2181                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
2182                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
2183                 {
2184                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
2185                         continue;
2186                 }
2187                 pts_t pts = PyLong_AsLongLong(ppts);
2188                 int type = PyInt_AsLong(ptype);
2189                 m_cue_entries.insert(cueEntry(pts, type));
2190                 eDebug("adding %08llx, %d", pts, type);
2191         }
2192         m_cuesheet_changed = 1;
2193         
2194         cutlistToCuesheet();
2195         m_event((iPlayableService*)this, evCuesheetChanged);
2196 }
2197
2198 void eDVBServicePlay::setCutListEnable(int enable)
2199 {
2200         m_cutlist_enabled = enable;
2201         cutlistToCuesheet();
2202 }
2203
2204 void eDVBServicePlay::updateTimeshiftPids()
2205 {
2206         if (!m_record)
2207                 return;
2208         
2209         eDVBServicePMTHandler::program program;
2210         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2211
2212         if (h.getProgramInfo(program))
2213                 return;
2214         else
2215         {
2216                 std::set<int> pids_to_record;
2217                 pids_to_record.insert(0); // PAT
2218                 if (program.pmtPid != -1)
2219                         pids_to_record.insert(program.pmtPid); // PMT
2220
2221                 if (program.textPid != -1)
2222                         pids_to_record.insert(program.textPid); // Videotext
2223
2224                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2225                         i(program.videoStreams.begin()); 
2226                         i != program.videoStreams.end(); ++i)
2227                         pids_to_record.insert(i->pid);
2228
2229                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2230                         i(program.audioStreams.begin()); 
2231                         i != program.audioStreams.end(); ++i)
2232                                 pids_to_record.insert(i->pid);
2233
2234                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2235                         i(program.subtitleStreams.begin());
2236                         i != program.subtitleStreams.end(); ++i)
2237                                 pids_to_record.insert(i->pid);
2238
2239                 std::set<int> new_pids, obsolete_pids;
2240                 
2241                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2242                                 m_pids_active.begin(), m_pids_active.end(),
2243                                 std::inserter(new_pids, new_pids.begin()));
2244                 
2245                 std::set_difference(
2246                                 m_pids_active.begin(), m_pids_active.end(),
2247                                 pids_to_record.begin(), pids_to_record.end(), 
2248                                 std::inserter(new_pids, new_pids.begin())
2249                                 );
2250
2251                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2252                         m_record->addPID(*i);
2253
2254                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2255                         m_record->removePID(*i);
2256         }
2257 }
2258
2259 void eDVBServicePlay::switchToLive()
2260 {
2261         if (!m_timeshift_active)
2262                 return;
2263         
2264         m_cue = 0;
2265         m_decoder = 0;
2266         m_decode_demux = 0;
2267         m_teletext_parser = 0;
2268         m_rds_decoder = 0;
2269         m_subtitle_parser = 0;
2270         m_new_dvb_subtitle_page_connection = 0;
2271         m_new_subtitle_page_connection = 0;
2272         m_rds_decoder_event_connection = 0;
2273         m_video_event_connection = 0;
2274
2275                 /* free the timeshift service handler, we need the resources */
2276         m_service_handler_timeshift.free();
2277         m_timeshift_active = 0;
2278
2279         m_event((iPlayableService*)this, evSeekableStatusChanged);
2280
2281         updateDecoder();
2282 }
2283
2284 void eDVBServicePlay::switchToTimeshift()
2285 {
2286         if (m_timeshift_active)
2287                 return;
2288
2289         m_decode_demux = 0;
2290         m_decoder = 0;
2291         m_teletext_parser = 0;
2292         m_rds_decoder = 0;
2293         m_subtitle_parser = 0;
2294         m_new_subtitle_page_connection = 0;
2295         m_new_dvb_subtitle_page_connection = 0;
2296         m_rds_decoder_event_connection = 0;
2297         m_video_event_connection = 0;
2298
2299         m_timeshift_active = 1;
2300
2301         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2302         r.path = m_timeshift_file;
2303
2304         m_cue = new eCueSheet();
2305         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
2306
2307         eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
2308         pause();
2309         updateDecoder(); /* mainly to switch off PCR, and to set pause */
2310         
2311         m_event((iPlayableService*)this, evSeekableStatusChanged);
2312 }
2313
2314 void eDVBServicePlay::updateDecoder()
2315 {
2316         int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2317
2318         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2319
2320         eDVBServicePMTHandler::program program;
2321         if (h.getProgramInfo(program))
2322                 eDebug("getting program info failed.");
2323         else
2324         {
2325                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
2326                 if (!program.videoStreams.empty())
2327                 {
2328                         eDebugNoNewLine(" (");
2329                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2330                                 i(program.videoStreams.begin());
2331                                 i != program.videoStreams.end(); ++i)
2332                         {
2333                                 if (vpid == -1)
2334                                 {
2335                                         vpid = i->pid;
2336                                         vpidtype = i->type;
2337                                 }
2338                                 if (i != program.videoStreams.begin())
2339                                         eDebugNoNewLine(", ");
2340                                 eDebugNoNewLine("%04x", i->pid);
2341                         }
2342                         eDebugNoNewLine(")");
2343                 }
2344                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
2345                 if (!program.audioStreams.empty())
2346                 {
2347                         eDebugNoNewLine(" (");
2348                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2349                                 i(program.audioStreams.begin());
2350                                 i != program.audioStreams.end(); ++i)
2351                         {
2352                                 if (i != program.audioStreams.begin())
2353                                         eDebugNoNewLine(", ");
2354                                 eDebugNoNewLine("%04x", i->pid);
2355                         }
2356                         eDebugNoNewLine(")");
2357                 }
2358                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2359                 pcrpid = program.pcrPid;
2360                 eDebug(", and the text pid is %04x", program.textPid);
2361                 tpid = program.textPid;
2362         }
2363
2364         if (!m_decoder)
2365         {
2366                 h.getDecodeDemux(m_decode_demux);
2367                 if (m_decode_demux)
2368                 {
2369                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2370                         if (m_decoder)
2371                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2372                         m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2373                         m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2374                         m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2375                         m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2376                 } else
2377                 {
2378                         m_teletext_parser = 0;
2379                         m_subtitle_parser = 0;
2380                 }
2381
2382                 if (m_cue)
2383                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2384         }
2385
2386         if (m_decoder)
2387         {
2388                 if (m_dvb_service)
2389                 {
2390                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2391                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2392                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2393                 }
2394                 else // subservice or recording
2395                 {
2396                         eServiceReferenceDVB ref;
2397                         m_service_handler.getServiceReference(ref);
2398                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2399                         if (!parent)
2400                                 parent = ref;
2401                         if (parent)
2402                         {
2403                                 ePtr<eDVBResourceManager> res_mgr;
2404                                 if (!eDVBResourceManager::getInstance(res_mgr))
2405                                 {
2406                                         ePtr<iDVBChannelList> db;
2407                                         if (!res_mgr->getChannelList(db))
2408                                         {
2409                                                 ePtr<eDVBService> origService;
2410                                                 if (!db->getService(parent, origService))
2411                                                 {
2412                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2413                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2414                                                 }
2415                                         }
2416                                 }
2417                         }
2418                 }
2419                 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
2420                 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
2421
2422                 m_decoder->setVideoPID(vpid, vpidtype);
2423                 selectAudioStream();
2424
2425                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
2426                         m_decoder->setSyncPCR(pcrpid);
2427                 else
2428                         m_decoder->setSyncPCR(-1);
2429
2430                 m_decoder->setTextPID(tpid);
2431
2432                 m_teletext_parser->start(program.textPid);
2433
2434                 if (!m_is_primary)
2435                         m_decoder->setTrickmode(1);
2436
2437                 if (m_is_paused)
2438                         m_decoder->preroll();
2439                 else
2440                         m_decoder->start();
2441
2442                 if (vpid > 0 && vpid < 0x2000)
2443                         ;
2444                 else
2445                 {
2446                         std::string radio_pic;
2447                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2448                                 m_decoder->setRadioPic(radio_pic);
2449                 }
2450
2451                 m_decoder->setAudioChannel(achannel);
2452
2453                 /* don't worry about non-existing services, nor pvr services */
2454                 if (m_dvb_service && !m_is_pvr)
2455                 {
2456                                 /* (audio pid will be set in selectAudioTrack */
2457                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2458                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2459                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2460                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2461                 }
2462         }       
2463         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2464 }
2465
2466 void eDVBServicePlay::loadCuesheet()
2467 {
2468         std::string filename = m_reference.path + ".cuts";
2469         
2470         m_cue_entries.clear();
2471
2472         FILE *f = fopen(filename.c_str(), "rb");
2473
2474         if (f)
2475         {
2476                 eDebug("loading cuts..");
2477                 while (1)
2478                 {
2479                         unsigned long long where;
2480                         unsigned int what;
2481                         
2482                         if (!fread(&where, sizeof(where), 1, f))
2483                                 break;
2484                         if (!fread(&what, sizeof(what), 1, f))
2485                                 break;
2486                         
2487 #if BYTE_ORDER == LITTLE_ENDIAN
2488                         where = bswap_64(where);
2489 #endif
2490                         what = ntohl(what);
2491                         
2492                         if (what > 3)
2493                                 break;
2494                         
2495                         m_cue_entries.insert(cueEntry(where, what));
2496                 }
2497                 fclose(f);
2498                 eDebug("%d entries", m_cue_entries.size());
2499         } else
2500                 eDebug("cutfile not found!");
2501         
2502         m_cuesheet_changed = 0;
2503         cutlistToCuesheet();
2504         m_event((iPlayableService*)this, evCuesheetChanged);
2505 }
2506
2507 void eDVBServicePlay::saveCuesheet()
2508 {
2509         std::string filename = m_reference.path + ".cuts";
2510         
2511         FILE *f = fopen(filename.c_str(), "wb");
2512
2513         if (f)
2514         {
2515                 unsigned long long where;
2516                 int what;
2517
2518                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2519                 {
2520 #if BYTE_ORDER == BIG_ENDIAN
2521                         where = i->where;
2522 #else
2523                         where = bswap_64(i->where);
2524 #endif
2525                         what = htonl(i->what);
2526                         fwrite(&where, sizeof(where), 1, f);
2527                         fwrite(&what, sizeof(what), 1, f);
2528                         
2529                 }
2530                 fclose(f);
2531         }
2532         
2533         m_cuesheet_changed = 0;
2534 }
2535
2536 void eDVBServicePlay::cutlistToCuesheet()
2537 {
2538         if (!m_cue)
2539         {
2540                 eDebug("no cue sheet");
2541                 return;
2542         }       
2543         m_cue->clear();
2544         
2545         if (!m_cutlist_enabled)
2546         {
2547                 m_cue->commitSpans();
2548                 eDebug("cutlists were disabled");
2549                 return;
2550         }
2551
2552         pts_t in = 0, out = 0, length = 0;
2553         
2554         getLength(length);
2555                 
2556         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2557         
2558         while (1)
2559         {
2560                 if (i == m_cue_entries.end())
2561                         out = length;
2562                 else {
2563                         if (i->what == 0) /* in */
2564                         {
2565                                 in = i++->where;
2566                                 continue;
2567                         } else if (i->what == 1) /* out */
2568                                 out = i++->where;
2569                         else /* mark (2) or last play position (3) */
2570                         {
2571                                 i++;
2572                                 continue;
2573                         }
2574                 }
2575                 
2576                 if (in < 0)
2577                         in = 0;
2578                 if (out < 0)
2579                         out = 0;
2580                 if (in > length)
2581                         in = length;
2582                 if (out > length)
2583                         out = length;
2584                 
2585                 if (in < out)
2586                         m_cue->addSourceSpan(in, out);
2587                 
2588                 in = length;
2589                 
2590                 if (i == m_cue_entries.end())
2591                         break;
2592         }
2593         m_cue->commitSpans();
2594 }
2595
2596 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2597 {
2598         if (m_subtitle_widget)
2599                 disableSubtitles(parent);
2600
2601         ePyObject entry;
2602         int tuplesize = PyTuple_Size(tuple);
2603         int type = 0;
2604
2605         if (!PyTuple_Check(tuple))
2606                 goto error_out;
2607
2608         if (tuplesize < 1)
2609                 goto error_out;
2610
2611         entry = PyTuple_GET_ITEM(tuple, 0);
2612
2613         if (!PyInt_Check(entry))
2614                 goto error_out;
2615
2616         type = PyInt_AsLong(entry);
2617
2618         if (type == 1)  // teletext subtitles
2619         {
2620                 int page, magazine, pid;
2621                 if (tuplesize < 4)
2622                         goto error_out;
2623
2624                 if (!m_teletext_parser)
2625                 {
2626                         eDebug("enable teletext subtitles.. no parser !!!");
2627                         return -1;
2628                 }
2629
2630                 entry = PyTuple_GET_ITEM(tuple, 1);
2631                 if (!PyInt_Check(entry))
2632                         goto error_out;
2633                 pid = PyInt_AsLong(entry);
2634
2635                 entry = PyTuple_GET_ITEM(tuple, 2);
2636                 if (!PyInt_Check(entry))
2637                         goto error_out;
2638                 page = PyInt_AsLong(entry);
2639
2640                 entry = PyTuple_GET_ITEM(tuple, 3);
2641                 if (!PyInt_Check(entry))
2642                         goto error_out;
2643                 magazine = PyInt_AsLong(entry);
2644
2645                 m_subtitle_widget = new eSubtitleWidget(parent);
2646                 m_subtitle_widget->resize(parent->size()); /* full size */
2647                 m_teletext_parser->setPageAndMagazine(page, magazine);
2648                 if (m_dvb_service)
2649                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2650         }
2651         else if (type == 0)
2652         {
2653                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2654                 if (!m_subtitle_parser)
2655                 {
2656                         eDebug("enable dvb subtitles.. no parser !!!");
2657                         return -1;
2658                 }
2659                 if (tuplesize < 4)
2660                         goto error_out;
2661
2662                 entry = PyTuple_GET_ITEM(tuple, 1);
2663                 if (!PyInt_Check(entry))
2664                         goto error_out;
2665                 pid = PyInt_AsLong(entry);
2666
2667                 entry = PyTuple_GET_ITEM(tuple, 2);
2668                 if (!PyInt_Check(entry))
2669                         goto error_out;
2670                 composition_page_id = PyInt_AsLong(entry);
2671
2672                 entry = PyTuple_GET_ITEM(tuple, 3);
2673                 if (!PyInt_Check(entry))
2674                         goto error_out;
2675                 ancillary_page_id = PyInt_AsLong(entry);
2676
2677                 m_subtitle_widget = new eSubtitleWidget(parent);
2678                 m_subtitle_widget->resize(parent->size()); /* full size */
2679                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2680                 if (m_dvb_service)
2681                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2682         }
2683         else
2684                 goto error_out;
2685         return 0;
2686 error_out:
2687         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2688                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2689                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2690         return -1;
2691 }
2692
2693 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2694 {
2695         delete m_subtitle_widget;
2696         m_subtitle_widget = 0;
2697         if (m_subtitle_parser)
2698         {
2699                 m_subtitle_parser->stop();
2700                 m_dvb_subtitle_pages.clear();
2701         }
2702         if (m_teletext_parser)
2703         {
2704                 m_teletext_parser->setPageAndMagazine(-1, -1);
2705                 m_subtitle_pages.clear();
2706         }
2707         if (m_dvb_service)
2708                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2709         return 0;
2710 }
2711
2712 PyObject *eDVBServicePlay::getCachedSubtitle()
2713 {
2714         if (m_dvb_service)
2715         {
2716                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2717                 if (tmp != -1)
2718                 {
2719                         unsigned int data = (unsigned int)tmp;
2720                         int pid = (data&0xFFFF0000)>>16;
2721                         ePyObject tuple = PyTuple_New(4);
2722                         eDVBServicePMTHandler::program program;
2723                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2724                         if (!h.getProgramInfo(program))
2725                         {
2726                                 if (program.textPid==pid) // teletext
2727                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2728                                 else
2729                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2730                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
2731                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2732                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2733                                 return tuple;
2734                         }
2735                 }
2736         }
2737         Py_RETURN_NONE;
2738 }
2739
2740 PyObject *eDVBServicePlay::getSubtitleList()
2741 {
2742         if (!m_teletext_parser)
2743                 Py_RETURN_NONE;
2744         
2745         ePyObject l = PyList_New(0);
2746         std::set<int> added_ttx_pages;
2747
2748         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2749                 m_teletext_parser->m_found_subtitle_pages;
2750
2751         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2752         eDVBServicePMTHandler::program program;
2753         if (h.getProgramInfo(program))
2754                 eDebug("getting program info failed.");
2755         else
2756         {
2757                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2758                         it != program.subtitleStreams.end(); ++it)
2759                 {
2760                         switch(it->subtitling_type)
2761                         {
2762                                 case 0x01: // ebu teletext subtitles
2763                                 {
2764                                         int page_number = it->teletext_page_number & 0xFF;
2765                                         int magazine_number = it->teletext_magazine_number & 7;
2766                                         int hash = magazine_number << 8 | page_number;
2767                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2768                                         {
2769                                                 ePyObject tuple = PyTuple_New(5);
2770                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2771                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2772                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2773                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2774                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2775                                                 PyList_Append(l, tuple);
2776                                                 Py_DECREF(tuple);
2777                                                 added_ttx_pages.insert(hash);
2778                                         }
2779                                         break;
2780                                 }
2781                                 case 0x10 ... 0x13:
2782                                 case 0x20 ... 0x23: // dvb subtitles
2783                                 {
2784                                         ePyObject tuple = PyTuple_New(5);
2785                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2786                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2787                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2788                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2789                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2790                                         PyList_Insert(l, 0, tuple);
2791                                         Py_DECREF(tuple);
2792                                         break;
2793                                 }
2794                         }
2795                 }
2796         }
2797
2798         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2799                 it != subs.end(); ++it)
2800         {
2801                 int page_number = it->teletext_page_number & 0xFF;
2802                 int magazine_number = it->teletext_magazine_number & 7;
2803                 int hash = magazine_number << 8 | page_number;
2804                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2805                 {
2806                         ePyObject tuple = PyTuple_New(5);
2807                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2808                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2809                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2810                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2811                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2812                         PyList_Append(l, tuple);
2813                         Py_DECREF(tuple);
2814                 }
2815         }
2816
2817         return l;
2818 }
2819
2820 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2821 {
2822         if (m_subtitle_widget)
2823         {
2824                 pts_t pos = 0;
2825                 if (m_decoder)
2826                         m_decoder->getPTS(0, pos);
2827                 eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
2828                 m_subtitle_pages.push_back(page);
2829                 checkSubtitleTiming();
2830         }
2831 }
2832
2833 void eDVBServicePlay::checkSubtitleTiming()
2834 {
2835         eDebug("checkSubtitleTiming");
2836         if (!m_subtitle_widget)
2837                 return;
2838         while (1)
2839         {
2840                 enum { TELETEXT, DVB } type;
2841                 eDVBTeletextSubtitlePage page;
2842                 eDVBSubtitlePage dvb_page;
2843                 pts_t show_time;
2844                 if (!m_subtitle_pages.empty())
2845                 {
2846                         page = m_subtitle_pages.front();
2847                         type = TELETEXT;
2848                         show_time = page.m_pts;
2849                 }
2850                 else if (!m_dvb_subtitle_pages.empty())
2851                 {
2852                         dvb_page = m_dvb_subtitle_pages.front();
2853                         type = DVB;
2854                         show_time = dvb_page.m_show_time;
2855                 }
2856                 else
2857                         return;
2858         
2859                 pts_t pos = 0;
2860         
2861                 if (m_decoder)
2862                         m_decoder->getPTS(0, pos);
2863
2864                 eDebug("%lld %lld", pos, show_time);
2865                 int diff =  show_time - pos;
2866                 if (diff < 0)
2867                 {
2868                         eDebug("[late (%d ms)]", -diff / 90);
2869                         diff = 0;
2870                 }
2871 //              if (diff > 900000)
2872 //              {
2873 //                      eDebug("[invalid]");
2874 //                      diff = 0;
2875 //              }
2876         
2877                 if ((diff/90)<20)
2878                 {
2879                         if (type == TELETEXT)
2880                         {
2881                                 eDebug("display teletext subtitle page %lld", show_time);
2882                                 m_subtitle_widget->setPage(page);
2883                                 m_subtitle_pages.pop_front();
2884                         }
2885                         else
2886                         {
2887                                 eDebug("display dvb subtitle Page %lld", show_time);
2888                                 m_subtitle_widget->setPage(dvb_page);
2889                                 m_dvb_subtitle_pages.pop_front();
2890                         }
2891                 } else
2892                 {
2893                         eDebug("start subtitle delay %d", diff / 90);
2894                         m_subtitle_sync_timer.start(diff / 90, 1);
2895                         break;
2896                 }
2897         }
2898 }
2899
2900 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2901 {
2902         if (m_subtitle_widget)
2903         {
2904                 pts_t pos = 0;
2905                 if (m_decoder)
2906                         m_decoder->getPTS(0, pos);
2907                 eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
2908                 m_dvb_subtitle_pages.push_back(p);
2909                 checkSubtitleTiming();
2910         }
2911 }
2912
2913 int eDVBServicePlay::getAC3Delay()
2914 {
2915         if (m_dvb_service)
2916                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2917         else if (m_decoder)
2918                 return m_decoder->getAC3Delay();
2919         else
2920                 return 0;
2921 }
2922
2923 int eDVBServicePlay::getPCMDelay()
2924 {
2925         if (m_dvb_service)
2926                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2927         else if (m_decoder)
2928                 return m_decoder->getPCMDelay();
2929         else
2930                 return 0;
2931 }
2932
2933 void eDVBServicePlay::setAC3Delay(int delay)
2934 {
2935         if (m_dvb_service)
2936                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2937         if (m_decoder)
2938                 m_decoder->setAC3Delay(delay);
2939 }
2940
2941 void eDVBServicePlay::setPCMDelay(int delay)
2942 {
2943         if (m_dvb_service)
2944                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2945         if (m_decoder)
2946                 m_decoder->setPCMDelay(delay);
2947 }
2948
2949 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
2950 {
2951         memcpy(&m_videoEventData, &event, sizeof(iTSMPEGDecoder::videoEvent));
2952         m_event((iPlayableService*)this, evVideoSizeChanged);
2953 }
2954
2955 RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
2956 {
2957         ptr = this;
2958         return 0;
2959 }
2960
2961 PyObject *eDVBServicePlay::getStreamingData()
2962 {
2963         eDVBServicePMTHandler::program program;
2964         if (m_service_handler.getProgramInfo(program))
2965         {
2966                 Py_INCREF(Py_None);
2967                 return Py_None;
2968         }
2969
2970         PyObject *r = program.createPythonObject();
2971         ePtr<iDVBDemux> demux;
2972         if (!m_service_handler.getDataDemux(demux))
2973         {
2974                 uint8_t demux_id;
2975                 demux->getCADemuxID(demux_id);
2976                 
2977                 PyDict_SetItemString(r, "demux", PyInt_FromLong(demux_id));
2978         }
2979
2980         return r;
2981 }
2982
2983
2984 DEFINE_REF(eDVBServicePlay)
2985
2986 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
2987 {
2988         switch (w)
2989         {
2990         case iServiceInformation::sTransponderData:
2991                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
2992         default:
2993                 break;
2994         }
2995         return iStaticServiceInformation::getInfoObject(ref, w);
2996 }
2997
2998 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");