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