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