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