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