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