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