650b609e16713d6fd4784cbe3748e0a588857d39
[openblackhole/openblackhole-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 #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::getName(std::string &name)
873 {
874         if (m_is_pvr)
875         {
876                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
877                 return i->getName(m_reference, name);
878         }
879         if (m_dvb_service)
880         {
881                 m_dvb_service->getName(m_reference, name);
882                 if (name.empty())
883                         name = "(...)";
884         }
885         else if (!m_reference.name.empty())
886                 eStaticServiceDVBInformation().getName(m_reference, name);
887         else
888                 name = "DVB service";
889         return 0;
890 }
891
892 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
893 {
894         return m_event_handler.getEvent(evt, nownext);
895 }
896
897 int eDVBServicePlay::getInfo(int w)
898 {
899         eDVBServicePMTHandler::program program;
900
901         if (m_service_handler.getProgramInfo(program))
902                 return -1;
903         
904         switch (w)
905         {
906         case sAspect:
907                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
908                 {
909                         ePtr<eServiceEvent> evt;
910                         if (!m_event_handler.getEvent(evt, 0))
911                         {
912                                 ePtr<eComponentData> data;
913                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
914                                 {
915                                         if ( data->getStreamContent() == 1 )
916                                         {
917                                                 switch(data->getComponentType())
918                                                 {
919                                                         // SD
920                                                         case 1: // 4:3 SD PAL
921                                                         case 2:
922                                                         case 3: // 16:9 SD PAL
923                                                         case 4: // > 16:9 PAL
924                                                         case 5: // 4:3 SD NTSC
925                                                         case 6: 
926                                                         case 7: // 16:9 SD NTSC
927                                                         case 8: // > 16:9 NTSC
928
929                                                         // HD
930                                                         case 9: // 4:3 HD PAL
931                                                         case 0xA:
932                                                         case 0xB: // 16:9 HD PAL
933                                                         case 0xC: // > 16:9 HD PAL
934                                                         case 0xD: // 4:3 HD NTSC
935                                                         case 0xE:
936                                                         case 0xF: // 16:9 HD NTSC
937                                                         case 0x10: // > 16:9 HD PAL
938                                                                 return data->getComponentType();
939                                                 }
940                                         }
941                                 }
942                         }
943                 }
944                 return -1;
945         case sIsCrypted: return program.isCrypted;
946         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
947         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
948         case sPCRPID: return program.pcrPid;
949         case sPMTPID: return program.pmtPid;
950         case sTXTPID: return program.textPid;
951         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
952         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
953         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
954         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
955         case sProvider: if (!m_dvb_service) return -1; return -2;
956         default:
957                 return -1;
958         }
959 }
960
961 std::string eDVBServicePlay::getInfoString(int w)
962 {       
963         switch (w)
964         {
965         case sProvider:
966                 if (!m_dvb_service) return "";
967                 return m_dvb_service->m_provider_name;
968         default:
969                 return "";
970         }
971 }
972
973 int eDVBServicePlay::getNumberOfTracks()
974 {
975         eDVBServicePMTHandler::program program;
976         if (m_service_handler.getProgramInfo(program))
977                 return 0;
978         return program.audioStreams.size();
979 }
980
981 RESULT eDVBServicePlay::selectTrack(unsigned int i)
982 {
983         int ret = selectAudioStream(i);
984
985         if (m_decoder->start())
986                 return -5;
987
988         return ret;
989 }
990
991 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
992 {
993         eDVBServicePMTHandler::program program;
994
995         if (m_service_handler.getProgramInfo(program))
996                 return -1;
997         
998         if (i >= program.audioStreams.size())
999                 return -2;
1000         
1001         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1002                 info.m_description = "MPEG";
1003         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1004                 info.m_description = "AC3";
1005         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1006                 info.m_description = "DTS";
1007         else
1008                 info.m_description = "???";
1009
1010         if (program.audioStreams[i].component_tag != -1)
1011         {
1012                 ePtr<eServiceEvent> evt;
1013                 if (!m_event_handler.getEvent(evt, 0))
1014                 {
1015                         ePtr<eComponentData> data;
1016                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1017                                 info.m_language = data->getText();
1018                 }
1019         }
1020
1021         if (info.m_language.empty())
1022                 info.m_language = program.audioStreams[i].language_code;
1023         
1024         return 0;
1025 }
1026
1027 int eDVBServicePlay::selectAudioStream(int i)
1028 {
1029         eDVBServicePMTHandler::program program;
1030
1031         if (m_service_handler.getProgramInfo(program))
1032                 return -1;
1033         
1034         if ((unsigned int)i >= program.audioStreams.size())
1035                 return -2;
1036         
1037         if (!m_decoder)
1038                 return -3;
1039         
1040         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1041                 return -4;
1042
1043         if (m_dvb_service && !m_is_pvr)
1044         {
1045                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1046                 {
1047                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1048                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1049                 }       else
1050                 {
1051                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1052                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1053                 }
1054         }
1055
1056         m_current_audio_stream = i;
1057
1058         return 0;
1059 }
1060
1061 int eDVBServicePlay::getFrontendInfo(int w)
1062 {
1063         if (m_is_pvr)
1064                 return 0;
1065         eUsePtr<iDVBChannel> channel;
1066         if(m_service_handler.getChannel(channel))
1067                 return 0;
1068         ePtr<iDVBFrontend> fe;
1069         if(channel->getFrontend(fe))
1070                 return 0;
1071         return fe->readFrontendData(w);
1072 }
1073
1074 int eDVBServicePlay::getNumberOfSubservices()
1075 {
1076         ePtr<eServiceEvent> evt;
1077         if (!m_event_handler.getEvent(evt, 0))
1078                 return evt->getNumOfLinkageServices();
1079         return 0;
1080 }
1081
1082 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1083 {
1084         ePtr<eServiceEvent> evt;
1085         if (!m_event_handler.getEvent(evt, 0))
1086         {
1087                 if (!evt->getLinkageService(sub, m_reference, n))
1088                         return 0;
1089         }
1090         sub.type=eServiceReference::idInvalid;
1091         return -1;
1092 }
1093
1094 RESULT eDVBServicePlay::startTimeshift()
1095 {
1096         ePtr<iDVBDemux> demux;
1097         
1098         eDebug("Start timeshift!");
1099         
1100         if (m_timeshift_enabled)
1101                 return -1;
1102         
1103                 /* start recording with the data demux. */
1104         if (m_service_handler.getDataDemux(demux))
1105                 return -2;
1106
1107         demux->createTSRecorder(m_record);
1108         if (!m_record)
1109                 return -3;
1110
1111         char templ[]=TSPATH "/timeshift.XXXXXX";
1112         m_timeshift_fd = mkstemp(templ);
1113         m_timeshift_file = templ;
1114         
1115         eDebug("recording to %s", templ);
1116         
1117         if (m_timeshift_fd < 0)
1118         {
1119                 m_record = 0;
1120                 return -4;
1121         }
1122                 
1123         m_record->setTargetFD(m_timeshift_fd);
1124
1125         m_timeshift_enabled = 1;
1126         
1127         updateTimeshiftPids();
1128         m_record->start();
1129
1130         return 0;
1131 }
1132
1133 RESULT eDVBServicePlay::stopTimeshift()
1134 {
1135         if (!m_timeshift_enabled)
1136                 return -1;
1137         
1138         switchToLive();
1139         
1140         m_timeshift_enabled = 0;
1141         
1142         m_record->stop();
1143         m_record = 0;
1144         
1145         close(m_timeshift_fd);
1146         eDebug("remove timeshift file");
1147         remove(m_timeshift_file.c_str());
1148         
1149         return 0;
1150 }
1151
1152 int eDVBServicePlay::isTimeshiftActive()
1153 {
1154         return m_timeshift_enabled && m_timeshift_active;
1155 }
1156
1157 RESULT eDVBServicePlay::activateTimeshift()
1158 {
1159         if (!m_timeshift_enabled)
1160                 return -1;
1161         
1162         if (!m_timeshift_active)
1163         {
1164                 switchToTimeshift();
1165                 return 0;
1166         }
1167         
1168         return -2;
1169 }
1170
1171 void eDVBServicePlay::updateTimeshiftPids()
1172 {
1173         if (!m_record)
1174                 return;
1175         
1176         eDVBServicePMTHandler::program program;
1177         if (m_service_handler.getProgramInfo(program))
1178                 return;
1179         else
1180         {
1181                 std::set<int> pids_to_record;
1182                 pids_to_record.insert(0); // PAT
1183                 if (program.pmtPid != -1)
1184                         pids_to_record.insert(program.pmtPid); // PMT
1185
1186                 if (program.textPid != -1)
1187                         pids_to_record.insert(program.textPid); // Videotext
1188
1189                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1190                         i(program.videoStreams.begin()); 
1191                         i != program.videoStreams.end(); ++i)
1192                         pids_to_record.insert(i->pid);
1193
1194                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1195                         i(program.audioStreams.begin()); 
1196                         i != program.audioStreams.end(); ++i)
1197                                 pids_to_record.insert(i->pid);
1198
1199                 std::set<int> new_pids, obsolete_pids;
1200                 
1201                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1202                                 m_pids_active.begin(), m_pids_active.end(),
1203                                 std::inserter(new_pids, new_pids.begin()));
1204                 
1205                 std::set_difference(
1206                                 m_pids_active.begin(), m_pids_active.end(),
1207                                 pids_to_record.begin(), pids_to_record.end(), 
1208                                 std::inserter(new_pids, new_pids.begin())
1209                                 );
1210
1211                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1212                         m_record->addPID(*i);
1213
1214                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1215                         m_record->removePID(*i);
1216         }
1217 }
1218
1219 void eDVBServicePlay::switchToLive()
1220 {
1221         if (!m_timeshift_active)
1222                 return;
1223         
1224         m_decoder = 0;
1225         m_decode_demux = 0;
1226                 /* free the timeshift service handler, we need the resources */
1227         m_service_handler_timeshift.free();
1228         m_timeshift_active = 0;
1229         
1230         m_event((iPlayableService*)this, evSeekableStatusChanged);
1231         
1232         updateDecoder();
1233 }
1234
1235 void eDVBServicePlay::switchToTimeshift()
1236 {
1237         if (m_timeshift_active)
1238                 return;
1239         
1240         m_decode_demux = 0;
1241         m_decoder = 0;
1242         
1243         m_timeshift_active = 1;
1244
1245         m_event((iPlayableService*)this, evSeekableStatusChanged);
1246         
1247         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1248         r.path = m_timeshift_file;
1249         
1250         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1251 }
1252
1253 void eDVBServicePlay::updateDecoder()
1254 {
1255         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1256         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1257
1258         eDVBServicePMTHandler::program program;
1259         if (h.getProgramInfo(program))
1260                 eDebug("getting program info failed.");
1261         else
1262         {
1263                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1264                 if (!program.videoStreams.empty())
1265                 {
1266                         eDebugNoNewLine(" (");
1267                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1268                                 i(program.videoStreams.begin()); 
1269                                 i != program.videoStreams.end(); ++i)
1270                         {
1271                                 if (vpid == -1)
1272                                         vpid = i->pid;
1273                                 if (i != program.videoStreams.begin())
1274                                         eDebugNoNewLine(", ");
1275                                 eDebugNoNewLine("%04x", i->pid);
1276                         }
1277                         eDebugNoNewLine(")");
1278                 }
1279                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1280                 if (!program.audioStreams.empty())
1281                 {
1282                         eDebugNoNewLine(" (");
1283                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1284                                 i(program.audioStreams.begin()); 
1285                                 i != program.audioStreams.end(); ++i)
1286                         {
1287                                 if (apid == -1)
1288                                 {
1289                                         apid = i->pid;
1290                                         apidtype = i->type;
1291                                 }
1292                                 if (i != program.audioStreams.begin())
1293                                         eDebugNoNewLine(", ");
1294                                 eDebugNoNewLine("%04x", i->pid);
1295                         }
1296                         eDebugNoNewLine(")");
1297                 }
1298                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1299                 pcrpid = program.pcrPid;
1300                 eDebug(", and the text pid is %04x", program.textPid);
1301                 tpid = program.textPid;
1302         }
1303
1304         if (!m_decoder)
1305         {
1306                 h.getDecodeDemux(m_decode_demux);
1307                 if (m_decode_demux)
1308                         m_decode_demux->getMPEGDecoder(m_decoder);
1309                 if (m_cue)
1310                         m_cue->setDecodingDemux(m_decode_demux);
1311         }
1312
1313         if (m_decoder)
1314         {
1315                 m_decoder->setVideoPID(vpid);
1316                 m_current_audio_stream = 0;
1317                 m_decoder->setAudioPID(apid, apidtype);
1318                 if (!(m_is_pvr || m_timeshift_active))
1319                         m_decoder->setSyncPCR(pcrpid);
1320                 else
1321                         m_decoder->setSyncPCR(-1);
1322                 m_decoder->setTextPID(tpid);
1323                 m_decoder->start();
1324 // how we can do this better?
1325 // update cache pid when the user changed the audio track or video track
1326 // TODO handling of difference audio types.. default audio types..
1327                                 
1328                 /* don't worry about non-existing services, nor pvr services */
1329                 if (m_dvb_service && !m_is_pvr)
1330                 {
1331                         if (apidtype == eDVBAudio::aMPEG)
1332                         {
1333                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1334                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1335                         }
1336                         else
1337                         {
1338                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1339                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1340                         }
1341                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1342                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1343                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1344                 }
1345         }
1346 }
1347
1348 DEFINE_REF(eDVBServicePlay)
1349
1350 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");