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