use cue sheets for seeking/skipping
[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/init_num.h>
7 #include <lib/base/init.h>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/service/servicedvbrecord.h>
14 #include <lib/dvb/metaparser.h>
15 #include <lib/dvb/tstools.h>
16 #include <lib/python/python.h>
17
18 class eStaticServiceDVBInformation: public iStaticServiceInformation
19 {
20         DECLARE_REF(eStaticServiceDVBInformation);
21 public:
22         RESULT getName(const eServiceReference &ref, std::string &name);
23         int getLength(const eServiceReference &ref);
24 };
25
26 DEFINE_REF(eStaticServiceDVBInformation);
27
28 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
29 {
30         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
31         if ( !ref.name.empty() )
32         {
33                 if (service.getParentTransportStreamID().get()) // linkage subservice
34                 {
35                         ePtr<iServiceHandler> service_center;
36                         if (!eServiceCenter::getInstance(service_center))
37                         {
38                                 eServiceReferenceDVB parent = service;
39                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
40                                 parent.setServiceID( service.getParentServiceID() );
41                                 parent.setParentTransportStreamID(eTransportStreamID(0));
42                                 parent.setParentServiceID(eServiceID(0));
43                                 parent.name="";
44                                 ePtr<iStaticServiceInformation> service_info;
45                                 if (!service_center->info(parent, service_info))
46                                 {
47                                         if (!service_info->getName(parent, name))
48                                         {
49                                                 // just show short name
50                                                 unsigned int pos = name.find("\xc2\x86");
51                                                 if ( pos != std::string::npos )
52                                                         name.erase(0, pos+2);
53                                                 pos = name.find("\xc2\x87");
54                                                 if ( pos != std::string::npos )
55                                                         name.erase(pos);
56                                                 name+=" - ";
57                                         }
58                                 }
59                         }
60                 }
61                 else
62                         name="";
63                 name += ref.name;
64                 return 0;
65         }
66         else
67                 return -1;
68 }
69
70 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
71 {
72         return -1;
73 }
74
75 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
76 {
77         DECLARE_REF(eStaticServiceDVBBouquetInformation);
78 public:
79         RESULT getName(const eServiceReference &ref, std::string &name);
80         int getLength(const eServiceReference &ref);
81 };
82
83 DEFINE_REF(eStaticServiceDVBBouquetInformation);
84
85 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
86 {
87         ePtr<iDVBChannelList> db;
88         ePtr<eDVBResourceManager> res;
89
90         int err;
91         if ((err = eDVBResourceManager::getInstance(res)) != 0)
92         {
93                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
94                 return err;
95         }
96         if ((err = res->getChannelList(db)) != 0)
97         {
98                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
99                 return err;
100         }
101
102         eBouquet *bouquet=0;
103         if ((err = db->getBouquet(ref, bouquet)) != 0)
104         {
105                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
106                 return -1;
107         }
108
109         if ( bouquet && bouquet->m_bouquet_name.length() )
110         {
111                 name = bouquet->m_bouquet_name;
112                 return 0;
113         }
114         else
115                 return -1;
116 }
117
118 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
119 {
120         return -1;
121 }
122
123 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
124 {
125         DECLARE_REF(eStaticServiceDVBPVRInformation);
126         eServiceReference m_ref;
127         eDVBMetaParser m_parser;
128 public:
129         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
130         RESULT getName(const eServiceReference &ref, std::string &name);
131         int getLength(const eServiceReference &ref);
132         
133         int getInfo(const eServiceReference &ref, int w);
134         std::string getInfoString(const eServiceReference &ref,int w);
135 };
136
137 DEFINE_REF(eStaticServiceDVBPVRInformation);
138
139 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
140 {
141         m_ref = ref;
142         m_parser.parseFile(ref.path);
143 }
144
145 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
146 {
147         ASSERT(ref == m_ref);
148         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
149         return 0;
150 }
151
152 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
153 {
154         ASSERT(ref == m_ref);
155         
156         eDVBTSTools tstools;
157         
158         if (tstools.openFile(ref.path.c_str()))
159                 return 0;
160
161         pts_t len;
162         if (tstools.calcLen(len))
163                 return 0;
164
165         return len / 90000;
166 }
167
168 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
169 {
170         switch (w)
171         {
172         case iServiceInformation::sDescription:
173                 return iServiceInformation::resIsString;
174         case iServiceInformation::sTimeCreate:
175                 if (m_parser.m_time_create)
176                         return m_parser.m_time_create;
177                 else
178                         return iServiceInformation::resNA;
179         default:
180                 return iServiceInformation::resNA;
181         }
182 }
183
184 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
185 {
186         switch (w)
187         {
188         case iServiceInformation::sDescription:
189                 return m_parser.m_description;
190         default:
191                 return "";
192         }
193 }
194
195 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
196 {
197         DECLARE_REF(eDVBPVRServiceOfflineOperations);
198         eServiceReferenceDVB m_ref;
199 public:
200         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
201         
202         RESULT deleteFromDisk(int simulate);
203         RESULT getListOfFilenames(std::list<std::string> &);
204 };
205
206 DEFINE_REF(eDVBPVRServiceOfflineOperations);
207
208 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
209 {
210 }
211
212 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
213 {
214         if (simulate)
215                 return 0;
216         else
217         {
218                 std::list<std::string> res;
219                 if (getListOfFilenames(res))
220                         return -1;
221                 
222                                 /* TODO: deferred removing.. */
223                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
224                 {
225                         eDebug("Removing %s...", i->c_str());
226                         ::unlink(i->c_str());
227                 }
228                 
229                 return 0;
230         }
231 }
232
233 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
234 {
235         res.clear();
236         res.push_back(m_ref.path);
237         res.push_back(m_ref.path + ".meta");
238         return 0;
239 }
240
241 DEFINE_REF(eServiceFactoryDVB)
242
243 eServiceFactoryDVB::eServiceFactoryDVB()
244 {
245         ePtr<eServiceCenter> sc;
246         
247         eServiceCenter::getPrivInstance(sc);
248         if (sc)
249                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
250 }
251
252 eServiceFactoryDVB::~eServiceFactoryDVB()
253 {
254         ePtr<eServiceCenter> sc;
255         
256         eServiceCenter::getPrivInstance(sc);
257         if (sc)
258                 sc->removeServiceFactory(eServiceFactoryDVB::id);
259 }
260
261 DEFINE_REF(eDVBServiceList);
262
263 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
264 {
265 }
266
267 eDVBServiceList::~eDVBServiceList()
268 {
269 }
270
271 RESULT eDVBServiceList::startQuery()
272 {
273         ePtr<iDVBChannelList> db;
274         ePtr<eDVBResourceManager> res;
275         
276         int err;
277         if ((err = eDVBResourceManager::getInstance(res)) != 0)
278         {
279                 eDebug("no resource manager");
280                 return err;
281         }
282         if ((err = res->getChannelList(db)) != 0)
283         {
284                 eDebug("no channel list");
285                 return err;
286         }
287         
288         ePtr<eDVBChannelQuery> q;
289         
290         if (!m_parent.path.empty())
291         {
292                 eDVBChannelQuery::compile(q, m_parent.path);
293                 if (!q)
294                 {
295                         eDebug("compile query failed");
296                         return err;
297                 }
298         }
299         
300         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
301         {
302                 eDebug("startQuery failed");
303                 return err;
304         }
305
306         return 0;
307 }
308
309 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
310 {
311         eServiceReferenceDVB ref;
312
313         if (!m_query || !list || !PyList_Check(list))
314                 return -1;
315
316         std::list<eServiceReferenceDVB> tmplist;
317
318         while (!m_query->getNextResult(ref))
319                 tmplist.push_back(ref);
320
321         if (sorted)
322                 tmplist.sort(iListableServiceCompare(this));
323
324         for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
325                 it != tmplist.end(); ++it)
326         {
327                 PyObject *refobj = New_eServiceReference(*it);
328                 PyList_Append(list, refobj);
329                 Py_DECREF(refobj);
330         }
331         return 0;
332 }
333
334 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
335 {
336         eServiceReferenceDVB ref;
337         
338         if (!m_query)
339                 return -1;
340         
341         while (!m_query->getNextResult(ref))
342                 list.push_back(ref);
343
344         if (sorted)
345                 list.sort(iListableServiceCompare(this));
346
347         return 0;
348 }
349
350 RESULT eDVBServiceList::getNext(eServiceReference &ref)
351 {
352         if (!m_query)
353                 return -1;
354         
355         return m_query->getNextResult((eServiceReferenceDVB&)ref);
356 }
357
358 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
359 {
360         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
361 }
362
363 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
364 {
365         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
366         {
367                 ePtr<iDVBChannelList> db;
368                 ePtr<eDVBResourceManager> resm;
369
370                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
371                         return -1;
372
373                 if (db->getBouquet(m_parent, m_bouquet) != 0)
374                         return -1;
375
376                 res = this;
377                 
378                 return 0;
379         }
380         res = 0;
381         return -1;
382 }
383
384 RESULT eDVBServiceList::addService(eServiceReference &ref)
385 {
386         if (!m_bouquet)
387                 return -1;
388         return m_bouquet->addService(ref);
389 }
390
391 RESULT eDVBServiceList::removeService(eServiceReference &ref)
392 {
393         if (!m_bouquet)
394                 return -1;
395         return m_bouquet->removeService(ref);
396 }
397
398 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
399 {
400         if (!m_bouquet)
401                 return -1;
402         return m_bouquet->moveService(ref, pos);
403 }
404
405 RESULT eDVBServiceList::flushChanges()
406 {
407         if (!m_bouquet)
408                 return -1;
409         return m_bouquet->flushChanges();
410 }
411
412 RESULT eDVBServiceList::setListName(const std::string &name)
413 {
414         if (!m_bouquet)
415                 return -1;
416         return m_bouquet->setListName(name);
417 }
418
419 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
420 {
421         ePtr<eDVBService> service;
422         int r = lookupService(service, ref);
423         if (r)
424                 service = 0;
425                 // check resources...
426         ptr = new eDVBServicePlay(ref, service);
427         return 0;
428 }
429
430 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
431 {
432         if (ref.path.empty())
433         {
434                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
435                 return 0;
436         } else
437         {
438                 ptr = 0;
439                 return -1;
440         }
441 }
442
443 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
444 {
445         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
446         if (list->startQuery())
447         {
448                 ptr = 0;
449                 return -1;
450         }
451         
452         ptr = list;
453         return 0;
454 }
455
456 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
457 {
458         /* is a listable service? */
459         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
460         {
461                 if ( !ref.name.empty() )  // satellites or providers list
462                         ptr = new eStaticServiceDVBInformation;
463                 else // a dvb bouquet
464                         ptr = new eStaticServiceDVBBouquetInformation;
465         }
466         else if (!ref.path.empty()) /* do we have a PVR service? */
467                 ptr = new eStaticServiceDVBPVRInformation(ref);
468         else // normal dvb service
469         {
470                 ePtr<eDVBService> service;
471                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
472                         ptr = new eStaticServiceDVBInformation;
473                 else
474                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
475                         ptr = service;
476         }
477         return 0;
478 }
479
480 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
481 {
482         if (ref.path.empty())
483         {
484                 ptr = 0;
485                 return -1;
486         } else
487         {
488                 ptr = new eDVBPVRServiceOfflineOperations(ref);
489                 return 0;
490         }
491 }
492
493 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
494 {
495                         // TODO: handle the listing itself
496         // if (ref.... == -1) .. return "... bouquets ...";
497         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
498                         // TODO: cache
499         ePtr<iDVBChannelList> db;
500         ePtr<eDVBResourceManager> res;
501         
502         int err;
503         if ((err = eDVBResourceManager::getInstance(res)) != 0)
504         {
505                 eDebug("no resource manager");
506                 return err;
507         }
508         if ((err = res->getChannelList(db)) != 0)
509         {
510                 eDebug("no channel list");
511                 return err;
512         }
513         
514                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
515         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
516         {
517                 eDebug("getService failed!");
518                 return err;
519         }
520
521         return 0;
522 }
523
524 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
525         m_reference(ref), m_dvb_service(service), m_is_paused(0)
526 {
527         m_is_pvr = !ref.path.empty();
528         m_timeshift_enabled = m_timeshift_active = 0;
529         m_skipmode = 0;
530         
531         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
532         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
533         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
534 }
535
536 eDVBServicePlay::~eDVBServicePlay()
537 {
538 }
539
540 void eDVBServicePlay::gotNewEvent()
541 {
542 #if 0
543                 // debug only
544         ePtr<eServiceEvent> m_event_now, m_event_next;
545         getEvent(m_event_now, 0);
546         getEvent(m_event_next, 1);
547
548         if (m_event_now)
549                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
550         if (m_event_next)
551                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
552 #endif
553         m_event((iPlayableService*)this, evUpdatedEventInfo);
554 }
555
556 void eDVBServicePlay::serviceEvent(int event)
557 {
558         switch (event)
559         {
560         case eDVBServicePMTHandler::eventTuned:
561         {
562                 ePtr<iDVBDemux> m_demux;
563                 if (!m_service_handler.getDataDemux(m_demux))
564                 {
565                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
566                         int sid = ref.getParentServiceID().get();
567                         if (!sid)
568                                 sid = ref.getServiceID().get();
569                         if ( ref.getParentTransportStreamID().get() &&
570                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
571                                 m_event_handler.startOther(m_demux, sid);
572                         else
573                                 m_event_handler.start(m_demux, sid);
574                 }
575                 break;
576         }
577         case eDVBServicePMTHandler::eventTuneFailed:
578         {
579                 eDebug("DVB service failed to tune");
580                 m_event((iPlayableService*)this, evTuneFailed);
581                 break;
582         }
583         case eDVBServicePMTHandler::eventNewProgramInfo:
584         {
585                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
586                 if (m_timeshift_enabled)
587                         updateTimeshiftPids();
588                 if (!m_timeshift_active)
589                         updateDecoder();
590                 m_event((iPlayableService*)this, evUpdatedInfo);
591                 break;
592         }
593         case eDVBServicePMTHandler::eventEOF:
594                 m_event((iPlayableService*)this, evEOF);
595                 break;
596         case eDVBServicePMTHandler::eventSOF:
597                 m_event((iPlayableService*)this, evSOF);
598                 break;
599         }
600 }
601
602 void eDVBServicePlay::serviceEventTimeshift(int event)
603 {
604         switch (event)
605         {
606         case eDVBServicePMTHandler::eventNewProgramInfo:
607                 if (m_timeshift_active)
608                         updateDecoder();
609                 break;
610         case eDVBServicePMTHandler::eventEOF:
611                 switchToLive();
612                 break;
613         }
614 }
615
616 RESULT eDVBServicePlay::start()
617 {
618         int r;
619                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
620                    two (one for decoding, one for data source), as we must be prepared
621                    to start recording from the data demux. */
622         m_cue = new eCueSheet();
623         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr, m_cue);
624         m_event(this, evStart);
625         m_event((iPlayableService*)this, evSeekableStatusChanged);
626         return 0;
627 }
628
629 RESULT eDVBServicePlay::stop()
630 {
631         eDebug("stop timeshift");
632         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
633         
634         eDebug("free ts handler");
635         m_service_handler_timeshift.free();
636         eDebug("stop service handler");
637         m_service_handler.free();
638         eDebug("ok");
639         
640         return 0;
641 }
642
643 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
644 {
645         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
646         return 0;
647 }
648
649 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
650 {
651                 /* note: we check for timeshift to be enabled,
652                    not neccessary active. if you pause when timeshift
653                    is not active, you should activate it when unpausing */
654         if ((!m_is_pvr) && (!m_timeshift_enabled))
655         {
656                 ptr = 0;
657                 return -1;
658         }
659
660         ptr = this;
661         return 0;
662 }
663
664 RESULT eDVBServicePlay::setSlowMotion(int ratio)
665 {
666         if (m_decoder)
667                 return m_decoder->setSlowMotion(ratio);
668         else
669                 return -1;
670 }
671
672 RESULT eDVBServicePlay::setFastForward(int ratio)
673 {
674         int skipmode, ffratio;
675         
676         if (ratio > 8)
677         {
678                 skipmode = ratio;
679                 ffratio = 1;
680         } else if (ratio > 0)
681         {
682                 skipmode = 0;
683                 ffratio = ratio;
684         } else if (!ratio)
685         {
686                 skipmode = 0;
687                 ffratio = 0;
688         } else if (ratio < 0)
689         {
690                 skipmode = ratio;
691                 ffratio = 1;
692         }
693
694         if (m_skipmode != skipmode)
695         {
696                 eDebug("setting cue skipmode to %d", skipmode);
697                 if (m_cue)
698                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
699         }
700         
701         m_skipmode = skipmode;
702         
703         if (!m_decoder)
704                 return -1;
705
706         return m_decoder->setFastForward(ffratio);
707 }
708     
709 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
710 {
711         if (m_is_pvr || m_timeshift_active)
712         {
713                 ptr = this;
714                 return 0;
715         }
716         
717         ptr = 0;
718         return -1;
719 }
720
721 RESULT eDVBServicePlay::getLength(pts_t &len)
722 {
723         ePtr<iDVBPVRChannel> pvr_channel;
724         
725         if (m_service_handler.getPVRChannel(pvr_channel))
726         {
727                 eDebug("getPVRChannel failed!");
728                 return -1;
729         }
730         
731         return pvr_channel->getLength(len);
732 }
733
734 RESULT eDVBServicePlay::pause()
735 {
736         if (!m_is_paused && m_decoder)
737         {
738                 m_is_paused = 1;
739                 return m_decoder->freeze(0);
740         } else
741                 return -1;
742 }
743
744 RESULT eDVBServicePlay::unpause()
745 {
746         if (m_is_paused && m_decoder)
747         {
748                 m_is_paused = 0;
749                 return m_decoder->unfreeze();
750         } else
751                 return -1;
752 }
753
754 RESULT eDVBServicePlay::seekTo(pts_t to)
755 {
756         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
757         
758         if (!m_decode_demux)
759                 return -1;
760
761         ePtr<iDVBPVRChannel> pvr_channel;
762         
763         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
764                 return -1;
765         
766         if (!m_cue)
767                 return -1;
768         
769         m_cue->seekTo(0, to);
770         return 0;
771 }
772
773 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
774 {
775         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
776         
777         if (!m_decode_demux)
778                 return -1;
779
780         ePtr<iDVBPVRChannel> pvr_channel;
781         
782         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
783                 return -1;
784         
785         to *= direction;
786         
787         if (!m_cue)
788                 return 0;
789         
790         m_cue->seekTo(1, to);
791         return 0;
792 }
793
794 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
795 {
796         ePtr<iDVBPVRChannel> pvr_channel;
797         
798         if (!m_decode_demux)
799                 return -1;
800         
801         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
802                 return -1;
803         
804         return pvr_channel->getCurrentPosition(m_decode_demux, pos, 1);
805 }
806
807 RESULT eDVBServicePlay::setTrickmode(int trick)
808 {
809         if (m_decoder)
810                 m_decoder->setTrickmode(trick);
811         return 0;
812 }
813
814 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
815 {
816         ptr = this;
817         return 0;
818 }
819
820 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
821 {
822         ptr = this;
823         return 0;
824 }
825
826 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
827 {
828         ptr = this;
829         return 0;
830 }
831
832 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
833 {
834         ptr = this;
835         return 0;
836 }
837
838 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
839 {
840         if (m_timeshift_enabled || !m_is_pvr)
841         {
842                 ptr = this;
843                 return 0;
844         }
845         ptr = 0;
846         return -1;
847 }
848
849 RESULT eDVBServicePlay::getName(std::string &name)
850 {
851         if (m_is_pvr)
852         {
853                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
854                 return i->getName(m_reference, name);
855         }
856         if (m_dvb_service)
857         {
858                 m_dvb_service->getName(m_reference, name);
859                 if (name.empty())
860                         name = "(...)";
861         }
862         else if (!m_reference.name.empty())
863                 eStaticServiceDVBInformation().getName(m_reference, name);
864         else
865                 name = "DVB service";
866         return 0;
867 }
868
869 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
870 {
871         return m_event_handler.getEvent(evt, nownext);
872 }
873
874 int eDVBServicePlay::getInfo(int w)
875 {
876         eDVBServicePMTHandler::program program;
877
878         if (m_service_handler.getProgramInfo(program))
879                 return -1;
880         
881         switch (w)
882         {
883         case sAspect:
884                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
885                 {
886                         ePtr<eServiceEvent> evt;
887                         if (!m_event_handler.getEvent(evt, 0))
888                         {
889                                 ePtr<eComponentData> data;
890                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
891                                 {
892                                         if ( data->getStreamContent() == 1 )
893                                         {
894                                                 switch(data->getComponentType())
895                                                 {
896                                                         // SD
897                                                         case 1: // 4:3 SD PAL
898                                                         case 2:
899                                                         case 3: // 16:9 SD PAL
900                                                         case 4: // > 16:9 PAL
901                                                         case 5: // 4:3 SD NTSC
902                                                         case 6: 
903                                                         case 7: // 16:9 SD NTSC
904                                                         case 8: // > 16:9 NTSC
905
906                                                         // HD
907                                                         case 9: // 4:3 HD PAL
908                                                         case 0xA:
909                                                         case 0xB: // 16:9 HD PAL
910                                                         case 0xC: // > 16:9 HD PAL
911                                                         case 0xD: // 4:3 HD NTSC
912                                                         case 0xE:
913                                                         case 0xF: // 16:9 HD NTSC
914                                                         case 0x10: // > 16:9 HD PAL
915                                                                 return data->getComponentType();
916                                                 }
917                                         }
918                                 }
919                         }
920                 }
921                 return -1;
922         case sIsCrypted: return program.isCrypted;
923         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
924         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
925         case sPCRPID: return program.pcrPid;
926         case sPMTPID: return program.pmtPid;
927         case sTXTPID: return program.textPid;
928         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
929         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
930         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
931         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
932         case sProvider: if (!m_dvb_service) return -1; return -2;
933         default:
934                 return -1;
935         }
936 }
937
938 std::string eDVBServicePlay::getInfoString(int w)
939 {       
940         switch (w)
941         {
942         case sProvider:
943                 if (!m_dvb_service) return "";
944                 return m_dvb_service->m_provider_name;
945         default:
946                 return "";
947         }
948 }
949
950 int eDVBServicePlay::getNumberOfTracks()
951 {
952         eDVBServicePMTHandler::program program;
953         if (m_service_handler.getProgramInfo(program))
954                 return 0;
955         return program.audioStreams.size();
956 }
957
958 RESULT eDVBServicePlay::selectTrack(unsigned int i)
959 {
960         int ret = selectAudioStream(i);
961
962         if (m_decoder->start())
963                 return -5;
964
965         return ret;
966 }
967
968 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
969 {
970         eDVBServicePMTHandler::program program;
971
972         if (m_service_handler.getProgramInfo(program))
973                 return -1;
974         
975         if (i >= program.audioStreams.size())
976                 return -2;
977         
978         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
979                 info.m_description = "MPEG";
980         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
981                 info.m_description = "AC3";
982         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
983                 info.m_description = "DTS";
984         else
985                 info.m_description = "???";
986
987         if (program.audioStreams[i].component_tag != -1)
988         {
989                 ePtr<eServiceEvent> evt;
990                 if (!m_event_handler.getEvent(evt, 0))
991                 {
992                         ePtr<eComponentData> data;
993                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
994                                 info.m_language = data->getText();
995                 }
996         }
997
998         if (info.m_language.empty())
999                 info.m_language = program.audioStreams[i].language_code;
1000         
1001         return 0;
1002 }
1003
1004 int eDVBServicePlay::selectAudioStream(int i)
1005 {
1006         eDVBServicePMTHandler::program program;
1007
1008         if (m_service_handler.getProgramInfo(program))
1009                 return -1;
1010         
1011         if ((unsigned int)i >= program.audioStreams.size())
1012                 return -2;
1013         
1014         if (!m_decoder)
1015                 return -3;
1016         
1017         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1018                 return -4;
1019
1020         if (m_dvb_service && !m_is_pvr)
1021         {
1022                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1023                 {
1024                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1025                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1026                 }       else
1027                 {
1028                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1029                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1030                 }
1031         }
1032
1033         m_current_audio_stream = i;
1034
1035         return 0;
1036 }
1037
1038 int eDVBServicePlay::getFrontendInfo(int w)
1039 {
1040         if (m_is_pvr)
1041                 return 0;
1042         eUsePtr<iDVBChannel> channel;
1043         if(m_service_handler.getChannel(channel))
1044                 return 0;
1045         ePtr<iDVBFrontend> fe;
1046         if(channel->getFrontend(fe))
1047                 return 0;
1048         return fe->readFrontendData(w);
1049 }
1050
1051 int eDVBServicePlay::getNumberOfSubservices()
1052 {
1053         ePtr<eServiceEvent> evt;
1054         if (!m_event_handler.getEvent(evt, 0))
1055                 return evt->getNumOfLinkageServices();
1056         return 0;
1057 }
1058
1059 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1060 {
1061         ePtr<eServiceEvent> evt;
1062         if (!m_event_handler.getEvent(evt, 0))
1063         {
1064                 if (!evt->getLinkageService(sub, m_reference, n))
1065                         return 0;
1066         }
1067         sub.type=eServiceReference::idInvalid;
1068         return -1;
1069 }
1070
1071 RESULT eDVBServicePlay::startTimeshift()
1072 {
1073         ePtr<iDVBDemux> demux;
1074         
1075         eDebug("Start timeshift!");
1076         
1077         if (m_timeshift_enabled)
1078                 return -1;
1079         
1080                 /* start recording with the data demux. */
1081         if (m_service_handler.getDataDemux(demux))
1082                 return -2;
1083
1084         demux->createTSRecorder(m_record);
1085         if (!m_record)
1086                 return -3;
1087
1088         char templ[]="/media/hdd/timeshift.XXXXXX";
1089         m_timeshift_fd = mkstemp(templ);
1090         m_timeshift_file = templ;
1091         
1092         eDebug("recording to %s", templ);
1093         
1094         if (m_timeshift_fd < 0)
1095         {
1096                 m_record = 0;
1097                 return -4;
1098         }
1099                 
1100         m_record->setTargetFD(m_timeshift_fd);
1101
1102         m_timeshift_enabled = 1;
1103         
1104         updateTimeshiftPids();
1105         m_record->start();
1106
1107         return 0;
1108 }
1109
1110 RESULT eDVBServicePlay::stopTimeshift()
1111 {
1112         if (!m_timeshift_enabled)
1113                 return -1;
1114         
1115         switchToLive();
1116         
1117         m_timeshift_enabled = 0;
1118         
1119         m_record->stop();
1120         m_record = 0;
1121         
1122         close(m_timeshift_fd);
1123         remove(m_timeshift_file.c_str());
1124         
1125         return 0;
1126 }
1127
1128 int eDVBServicePlay::isTimeshiftActive()
1129 {
1130         return m_timeshift_enabled && m_timeshift_active;
1131 }
1132
1133 RESULT eDVBServicePlay::activateTimeshift()
1134 {
1135         if (!m_timeshift_enabled)
1136                 return -1;
1137         
1138         if (!m_timeshift_active)
1139         {
1140                 switchToTimeshift();
1141                 return 0;
1142         }
1143         
1144         return -2;
1145 }
1146
1147 void eDVBServicePlay::updateTimeshiftPids()
1148 {
1149         if (!m_record)
1150                 return;
1151         
1152         eDVBServicePMTHandler::program program;
1153         if (m_service_handler.getProgramInfo(program))
1154                 return;
1155         else
1156         {
1157                 std::set<int> pids_to_record;
1158                 pids_to_record.insert(0); // PAT
1159                 if (program.pmtPid != -1)
1160                         pids_to_record.insert(program.pmtPid); // PMT
1161
1162                 if (program.textPid != -1)
1163                         pids_to_record.insert(program.textPid); // Videotext
1164
1165                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1166                         i(program.videoStreams.begin()); 
1167                         i != program.videoStreams.end(); ++i)
1168                         pids_to_record.insert(i->pid);
1169
1170                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1171                         i(program.audioStreams.begin()); 
1172                         i != program.audioStreams.end(); ++i)
1173                                 pids_to_record.insert(i->pid);
1174
1175                 std::set<int> new_pids, obsolete_pids;
1176                 
1177                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1178                                 m_pids_active.begin(), m_pids_active.end(),
1179                                 std::inserter(new_pids, new_pids.begin()));
1180                 
1181                 std::set_difference(
1182                                 m_pids_active.begin(), m_pids_active.end(),
1183                                 pids_to_record.begin(), pids_to_record.end(), 
1184                                 std::inserter(new_pids, new_pids.begin())
1185                                 );
1186
1187                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1188                         m_record->addPID(*i);
1189
1190                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1191                         m_record->removePID(*i);
1192         }
1193 }
1194
1195 void eDVBServicePlay::switchToLive()
1196 {
1197         if (!m_timeshift_active)
1198                 return;
1199         
1200         m_decoder = 0;
1201         m_decode_demux = 0;
1202                 /* free the timeshift service handler, we need the resources */
1203         m_service_handler_timeshift.free();
1204         m_timeshift_active = 0;
1205         
1206         m_event((iPlayableService*)this, evSeekableStatusChanged);
1207         
1208         updateDecoder();
1209 }
1210
1211 void eDVBServicePlay::switchToTimeshift()
1212 {
1213         if (m_timeshift_active)
1214                 return;
1215         
1216         m_decode_demux = 0;
1217         m_decoder = 0;
1218         
1219         m_timeshift_active = 1;
1220
1221         m_event((iPlayableService*)this, evSeekableStatusChanged);
1222         
1223         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1224         r.path = m_timeshift_file;
1225         
1226         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1227 }
1228
1229 void eDVBServicePlay::updateDecoder()
1230 {
1231         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1232         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1233
1234         eDVBServicePMTHandler::program program;
1235         if (h.getProgramInfo(program))
1236                 eDebug("getting program info failed.");
1237         else
1238         {
1239                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1240                 if (!program.videoStreams.empty())
1241                 {
1242                         eDebugNoNewLine(" (");
1243                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1244                                 i(program.videoStreams.begin()); 
1245                                 i != program.videoStreams.end(); ++i)
1246                         {
1247                                 if (vpid == -1)
1248                                         vpid = i->pid;
1249                                 if (i != program.videoStreams.begin())
1250                                         eDebugNoNewLine(", ");
1251                                 eDebugNoNewLine("%04x", i->pid);
1252                         }
1253                         eDebugNoNewLine(")");
1254                 }
1255                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1256                 if (!program.audioStreams.empty())
1257                 {
1258                         eDebugNoNewLine(" (");
1259                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1260                                 i(program.audioStreams.begin()); 
1261                                 i != program.audioStreams.end(); ++i)
1262                         {
1263                                 if (apid == -1)
1264                                 {
1265                                         apid = i->pid;
1266                                         apidtype = i->type;
1267                                 }
1268                                 if (i != program.audioStreams.begin())
1269                                         eDebugNoNewLine(", ");
1270                                 eDebugNoNewLine("%04x", i->pid);
1271                         }
1272                         eDebugNoNewLine(")");
1273                 }
1274                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1275                 pcrpid = program.pcrPid;
1276                 eDebug(", and the text pid is %04x", program.textPid);
1277                 tpid = program.textPid;
1278         }
1279
1280         if (!m_decoder)
1281         {
1282                 h.getDecodeDemux(m_decode_demux);
1283                 if (m_decode_demux)
1284                         m_decode_demux->getMPEGDecoder(m_decoder);
1285                 if (m_cue)
1286                         m_cue->setDecodingDemux(m_decode_demux);
1287         }
1288
1289         if (m_decoder)
1290         {
1291                 m_decoder->setVideoPID(vpid);
1292                 m_current_audio_stream = 0;
1293                 m_decoder->setAudioPID(apid, apidtype);
1294                 if (!(m_is_pvr || m_timeshift_active))
1295                         m_decoder->setSyncPCR(pcrpid);
1296                 else
1297                         m_decoder->setSyncPCR(-1);
1298                 m_decoder->setTextPID(tpid);
1299                 m_decoder->start();
1300 // how we can do this better?
1301 // update cache pid when the user changed the audio track or video track
1302 // TODO handling of difference audio types.. default audio types..
1303                                 
1304                 /* don't worry about non-existing services, nor pvr services */
1305                 if (m_dvb_service && !m_is_pvr)
1306                 {
1307                         if (apidtype == eDVBAudio::aMPEG)
1308                         {
1309                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1310                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1311                         }
1312                         else
1313                         {
1314                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1315                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1316                         }
1317                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1318                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1319                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1320                 }
1321         }
1322 }
1323
1324 DEFINE_REF(eDVBServicePlay)
1325
1326 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");