allow TS only if >1G of free space
[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_active)
716         {
717                 ptr = this;
718                 return 0;
719         }
720         
721         ptr = 0;
722         return -1;
723 }
724
725 RESULT eDVBServicePlay::getLength(pts_t &len)
726 {
727         ePtr<iDVBPVRChannel> pvr_channel;
728         
729         if (m_service_handler.getPVRChannel(pvr_channel))
730         {
731                 eDebug("getPVRChannel failed!");
732                 return -1;
733         }
734         
735         return pvr_channel->getLength(len);
736 }
737
738 RESULT eDVBServicePlay::pause()
739 {
740         if (!m_is_paused && m_decoder)
741         {
742                 m_is_paused = 1;
743                 return m_decoder->freeze(0);
744         } else
745                 return -1;
746 }
747
748 RESULT eDVBServicePlay::unpause()
749 {
750         if (m_is_paused && m_decoder)
751         {
752                 m_is_paused = 0;
753                 return m_decoder->unfreeze();
754         } else
755                 return -1;
756 }
757
758 RESULT eDVBServicePlay::seekTo(pts_t to)
759 {
760         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
761         
762         if (!m_decode_demux)
763                 return -1;
764
765         ePtr<iDVBPVRChannel> pvr_channel;
766         
767         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
768                 return -1;
769         
770         if (!m_cue)
771                 return -1;
772         
773         m_cue->seekTo(0, to);
774         return 0;
775 }
776
777 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
778 {
779         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
780         
781         if (!m_decode_demux)
782                 return -1;
783
784         ePtr<iDVBPVRChannel> pvr_channel;
785         
786         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
787                 return -1;
788         
789         to *= direction;
790         
791         if (!m_cue)
792                 return 0;
793         
794         m_cue->seekTo(1, to);
795         return 0;
796 }
797
798 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
799 {
800         ePtr<iDVBPVRChannel> pvr_channel;
801         
802         if (!m_decode_demux)
803                 return -1;
804         
805         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
806                 return -1;
807         
808         return pvr_channel->getCurrentPosition(m_decode_demux, pos, 1);
809 }
810
811 RESULT eDVBServicePlay::setTrickmode(int trick)
812 {
813         if (m_decoder)
814                 m_decoder->setTrickmode(trick);
815         return 0;
816 }
817
818 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
819 {
820         ptr = this;
821         return 0;
822 }
823
824 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
825 {
826         ptr = this;
827         return 0;
828 }
829
830 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
831 {
832         ptr = this;
833         return 0;
834 }
835
836 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
837 {
838         ptr = this;
839         return 0;
840 }
841
842 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
843 {
844         ptr = 0;
845         if (m_timeshift_enabled || !m_is_pvr)
846         {
847                 if (!m_timeshift_enabled)
848                 {
849                                 /* we need enough diskspace */
850                         struct statfs fs;
851                         if (statfs(TSPATH "/.", &fs) < 0)
852                         {
853                                 eDebug("statfs failed!");
854                                 return -2;
855                         }
856                 
857                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
858                         {
859                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
860                                 return -3;
861                         }
862                 }
863                 ptr = this;
864                 return 0;
865         }
866         return -1;
867 }
868
869 RESULT eDVBServicePlay::getName(std::string &name)
870 {
871         if (m_is_pvr)
872         {
873                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
874                 return i->getName(m_reference, name);
875         }
876         if (m_dvb_service)
877         {
878                 m_dvb_service->getName(m_reference, name);
879                 if (name.empty())
880                         name = "(...)";
881         }
882         else if (!m_reference.name.empty())
883                 eStaticServiceDVBInformation().getName(m_reference, name);
884         else
885                 name = "DVB service";
886         return 0;
887 }
888
889 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
890 {
891         return m_event_handler.getEvent(evt, nownext);
892 }
893
894 int eDVBServicePlay::getInfo(int w)
895 {
896         eDVBServicePMTHandler::program program;
897
898         if (m_service_handler.getProgramInfo(program))
899                 return -1;
900         
901         switch (w)
902         {
903         case sAspect:
904                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
905                 {
906                         ePtr<eServiceEvent> evt;
907                         if (!m_event_handler.getEvent(evt, 0))
908                         {
909                                 ePtr<eComponentData> data;
910                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
911                                 {
912                                         if ( data->getStreamContent() == 1 )
913                                         {
914                                                 switch(data->getComponentType())
915                                                 {
916                                                         // SD
917                                                         case 1: // 4:3 SD PAL
918                                                         case 2:
919                                                         case 3: // 16:9 SD PAL
920                                                         case 4: // > 16:9 PAL
921                                                         case 5: // 4:3 SD NTSC
922                                                         case 6: 
923                                                         case 7: // 16:9 SD NTSC
924                                                         case 8: // > 16:9 NTSC
925
926                                                         // HD
927                                                         case 9: // 4:3 HD PAL
928                                                         case 0xA:
929                                                         case 0xB: // 16:9 HD PAL
930                                                         case 0xC: // > 16:9 HD PAL
931                                                         case 0xD: // 4:3 HD NTSC
932                                                         case 0xE:
933                                                         case 0xF: // 16:9 HD NTSC
934                                                         case 0x10: // > 16:9 HD PAL
935                                                                 return data->getComponentType();
936                                                 }
937                                         }
938                                 }
939                         }
940                 }
941                 return -1;
942         case sIsCrypted: return program.isCrypted;
943         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
944         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
945         case sPCRPID: return program.pcrPid;
946         case sPMTPID: return program.pmtPid;
947         case sTXTPID: return program.textPid;
948         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
949         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
950         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
951         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
952         case sProvider: if (!m_dvb_service) return -1; return -2;
953         default:
954                 return -1;
955         }
956 }
957
958 std::string eDVBServicePlay::getInfoString(int w)
959 {       
960         switch (w)
961         {
962         case sProvider:
963                 if (!m_dvb_service) return "";
964                 return m_dvb_service->m_provider_name;
965         default:
966                 return "";
967         }
968 }
969
970 int eDVBServicePlay::getNumberOfTracks()
971 {
972         eDVBServicePMTHandler::program program;
973         if (m_service_handler.getProgramInfo(program))
974                 return 0;
975         return program.audioStreams.size();
976 }
977
978 RESULT eDVBServicePlay::selectTrack(unsigned int i)
979 {
980         int ret = selectAudioStream(i);
981
982         if (m_decoder->start())
983                 return -5;
984
985         return ret;
986 }
987
988 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
989 {
990         eDVBServicePMTHandler::program program;
991
992         if (m_service_handler.getProgramInfo(program))
993                 return -1;
994         
995         if (i >= program.audioStreams.size())
996                 return -2;
997         
998         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
999                 info.m_description = "MPEG";
1000         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1001                 info.m_description = "AC3";
1002         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1003                 info.m_description = "DTS";
1004         else
1005                 info.m_description = "???";
1006
1007         if (program.audioStreams[i].component_tag != -1)
1008         {
1009                 ePtr<eServiceEvent> evt;
1010                 if (!m_event_handler.getEvent(evt, 0))
1011                 {
1012                         ePtr<eComponentData> data;
1013                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1014                                 info.m_language = data->getText();
1015                 }
1016         }
1017
1018         if (info.m_language.empty())
1019                 info.m_language = program.audioStreams[i].language_code;
1020         
1021         return 0;
1022 }
1023
1024 int eDVBServicePlay::selectAudioStream(int i)
1025 {
1026         eDVBServicePMTHandler::program program;
1027
1028         if (m_service_handler.getProgramInfo(program))
1029                 return -1;
1030         
1031         if ((unsigned int)i >= program.audioStreams.size())
1032                 return -2;
1033         
1034         if (!m_decoder)
1035                 return -3;
1036         
1037         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1038                 return -4;
1039
1040         if (m_dvb_service && !m_is_pvr)
1041         {
1042                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1043                 {
1044                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1045                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1046                 }       else
1047                 {
1048                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1049                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1050                 }
1051         }
1052
1053         m_current_audio_stream = i;
1054
1055         return 0;
1056 }
1057
1058 int eDVBServicePlay::getFrontendInfo(int w)
1059 {
1060         if (m_is_pvr)
1061                 return 0;
1062         eUsePtr<iDVBChannel> channel;
1063         if(m_service_handler.getChannel(channel))
1064                 return 0;
1065         ePtr<iDVBFrontend> fe;
1066         if(channel->getFrontend(fe))
1067                 return 0;
1068         return fe->readFrontendData(w);
1069 }
1070
1071 int eDVBServicePlay::getNumberOfSubservices()
1072 {
1073         ePtr<eServiceEvent> evt;
1074         if (!m_event_handler.getEvent(evt, 0))
1075                 return evt->getNumOfLinkageServices();
1076         return 0;
1077 }
1078
1079 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1080 {
1081         ePtr<eServiceEvent> evt;
1082         if (!m_event_handler.getEvent(evt, 0))
1083         {
1084                 if (!evt->getLinkageService(sub, m_reference, n))
1085                         return 0;
1086         }
1087         sub.type=eServiceReference::idInvalid;
1088         return -1;
1089 }
1090
1091 RESULT eDVBServicePlay::startTimeshift()
1092 {
1093         ePtr<iDVBDemux> demux;
1094         
1095         eDebug("Start timeshift!");
1096         
1097         if (m_timeshift_enabled)
1098                 return -1;
1099         
1100                 /* start recording with the data demux. */
1101         if (m_service_handler.getDataDemux(demux))
1102                 return -2;
1103
1104         demux->createTSRecorder(m_record);
1105         if (!m_record)
1106                 return -3;
1107
1108         char templ[]=TSPATH "/timeshift.XXXXXX";
1109         m_timeshift_fd = mkstemp(templ);
1110         m_timeshift_file = templ;
1111         
1112         eDebug("recording to %s", templ);
1113         
1114         if (m_timeshift_fd < 0)
1115         {
1116                 m_record = 0;
1117                 return -4;
1118         }
1119                 
1120         m_record->setTargetFD(m_timeshift_fd);
1121
1122         m_timeshift_enabled = 1;
1123         
1124         updateTimeshiftPids();
1125         m_record->start();
1126
1127         return 0;
1128 }
1129
1130 RESULT eDVBServicePlay::stopTimeshift()
1131 {
1132         if (!m_timeshift_enabled)
1133                 return -1;
1134         
1135         switchToLive();
1136         
1137         m_timeshift_enabled = 0;
1138         
1139         m_record->stop();
1140         m_record = 0;
1141         
1142         close(m_timeshift_fd);
1143         remove(m_timeshift_file.c_str());
1144         
1145         return 0;
1146 }
1147
1148 int eDVBServicePlay::isTimeshiftActive()
1149 {
1150         return m_timeshift_enabled && m_timeshift_active;
1151 }
1152
1153 RESULT eDVBServicePlay::activateTimeshift()
1154 {
1155         if (!m_timeshift_enabled)
1156                 return -1;
1157         
1158         if (!m_timeshift_active)
1159         {
1160                 switchToTimeshift();
1161                 return 0;
1162         }
1163         
1164         return -2;
1165 }
1166
1167 void eDVBServicePlay::updateTimeshiftPids()
1168 {
1169         if (!m_record)
1170                 return;
1171         
1172         eDVBServicePMTHandler::program program;
1173         if (m_service_handler.getProgramInfo(program))
1174                 return;
1175         else
1176         {
1177                 std::set<int> pids_to_record;
1178                 pids_to_record.insert(0); // PAT
1179                 if (program.pmtPid != -1)
1180                         pids_to_record.insert(program.pmtPid); // PMT
1181
1182                 if (program.textPid != -1)
1183                         pids_to_record.insert(program.textPid); // Videotext
1184
1185                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1186                         i(program.videoStreams.begin()); 
1187                         i != program.videoStreams.end(); ++i)
1188                         pids_to_record.insert(i->pid);
1189
1190                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1191                         i(program.audioStreams.begin()); 
1192                         i != program.audioStreams.end(); ++i)
1193                                 pids_to_record.insert(i->pid);
1194
1195                 std::set<int> new_pids, obsolete_pids;
1196                 
1197                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1198                                 m_pids_active.begin(), m_pids_active.end(),
1199                                 std::inserter(new_pids, new_pids.begin()));
1200                 
1201                 std::set_difference(
1202                                 m_pids_active.begin(), m_pids_active.end(),
1203                                 pids_to_record.begin(), pids_to_record.end(), 
1204                                 std::inserter(new_pids, new_pids.begin())
1205                                 );
1206
1207                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1208                         m_record->addPID(*i);
1209
1210                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1211                         m_record->removePID(*i);
1212         }
1213 }
1214
1215 void eDVBServicePlay::switchToLive()
1216 {
1217         if (!m_timeshift_active)
1218                 return;
1219         
1220         m_decoder = 0;
1221         m_decode_demux = 0;
1222                 /* free the timeshift service handler, we need the resources */
1223         m_service_handler_timeshift.free();
1224         m_timeshift_active = 0;
1225         
1226         m_event((iPlayableService*)this, evSeekableStatusChanged);
1227         
1228         updateDecoder();
1229 }
1230
1231 void eDVBServicePlay::switchToTimeshift()
1232 {
1233         if (m_timeshift_active)
1234                 return;
1235         
1236         m_decode_demux = 0;
1237         m_decoder = 0;
1238         
1239         m_timeshift_active = 1;
1240
1241         m_event((iPlayableService*)this, evSeekableStatusChanged);
1242         
1243         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1244         r.path = m_timeshift_file;
1245         
1246         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1247 }
1248
1249 void eDVBServicePlay::updateDecoder()
1250 {
1251         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1252         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1253
1254         eDVBServicePMTHandler::program program;
1255         if (h.getProgramInfo(program))
1256                 eDebug("getting program info failed.");
1257         else
1258         {
1259                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1260                 if (!program.videoStreams.empty())
1261                 {
1262                         eDebugNoNewLine(" (");
1263                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1264                                 i(program.videoStreams.begin()); 
1265                                 i != program.videoStreams.end(); ++i)
1266                         {
1267                                 if (vpid == -1)
1268                                         vpid = i->pid;
1269                                 if (i != program.videoStreams.begin())
1270                                         eDebugNoNewLine(", ");
1271                                 eDebugNoNewLine("%04x", i->pid);
1272                         }
1273                         eDebugNoNewLine(")");
1274                 }
1275                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1276                 if (!program.audioStreams.empty())
1277                 {
1278                         eDebugNoNewLine(" (");
1279                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1280                                 i(program.audioStreams.begin()); 
1281                                 i != program.audioStreams.end(); ++i)
1282                         {
1283                                 if (apid == -1)
1284                                 {
1285                                         apid = i->pid;
1286                                         apidtype = i->type;
1287                                 }
1288                                 if (i != program.audioStreams.begin())
1289                                         eDebugNoNewLine(", ");
1290                                 eDebugNoNewLine("%04x", i->pid);
1291                         }
1292                         eDebugNoNewLine(")");
1293                 }
1294                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1295                 pcrpid = program.pcrPid;
1296                 eDebug(", and the text pid is %04x", program.textPid);
1297                 tpid = program.textPid;
1298         }
1299
1300         if (!m_decoder)
1301         {
1302                 h.getDecodeDemux(m_decode_demux);
1303                 if (m_decode_demux)
1304                         m_decode_demux->getMPEGDecoder(m_decoder);
1305                 if (m_cue)
1306                         m_cue->setDecodingDemux(m_decode_demux);
1307         }
1308
1309         if (m_decoder)
1310         {
1311                 m_decoder->setVideoPID(vpid);
1312                 m_current_audio_stream = 0;
1313                 m_decoder->setAudioPID(apid, apidtype);
1314                 if (!(m_is_pvr || m_timeshift_active))
1315                         m_decoder->setSyncPCR(pcrpid);
1316                 else
1317                         m_decoder->setSyncPCR(-1);
1318                 m_decoder->setTextPID(tpid);
1319                 m_decoder->start();
1320 // how we can do this better?
1321 // update cache pid when the user changed the audio track or video track
1322 // TODO handling of difference audio types.. default audio types..
1323                                 
1324                 /* don't worry about non-existing services, nor pvr services */
1325                 if (m_dvb_service && !m_is_pvr)
1326                 {
1327                         if (apidtype == eDVBAudio::aMPEG)
1328                         {
1329                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1330                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1331                         }
1332                         else
1333                         {
1334                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1335                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1336                         }
1337                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1338                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1339                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1340                 }
1341         }
1342 }
1343
1344 DEFINE_REF(eDVBServicePlay)
1345
1346 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");