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