add ServiceEventTracker
[enigma2.git] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/service/servicedvbrecord.h>
14 #include <lib/dvb/metaparser.h>
15 #include <lib/dvb/tstools.h>
16
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         case eDVBServicePMTHandler::eventEOF:
556                 m_event((iPlayableService*)this, evEnd);
557         }
558 }
559
560 void eDVBServicePlay::serviceEventTimeshift(int event)
561 {
562         switch (event)
563         {
564         case eDVBServicePMTHandler::eventNewProgramInfo:
565                 if (m_timeshift_active)
566                         updateDecoder();
567                 break;
568         }
569 }
570
571 RESULT eDVBServicePlay::start()
572 {
573         int r;
574                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
575                    two (one for decoding, one for data source), as we must be prepared
576                    to start recording from the data demux. */
577         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr);
578         m_event(this, evStart);
579         return 0;
580 }
581
582 RESULT eDVBServicePlay::stop()
583 {
584         return 0;
585 }
586
587 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
588 {
589         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
590         return 0;
591 }
592
593 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
594 {
595         if ((!m_is_pvr) && (!m_timeshift_enabled))
596         {
597                 ptr = 0;
598                 return -1;
599         }
600
601         ptr = this;
602         return 0;
603 }
604
605 RESULT eDVBServicePlay::setSlowMotion(int ratio)
606 {
607         if (m_decoder)
608                 return m_decoder->setSlowMotion(ratio);
609         else
610                 return -1;
611 }
612
613 RESULT eDVBServicePlay::setFastForward(int ratio)
614 {
615         if (m_decoder)
616                 return m_decoder->setFastForward(ratio);
617         else
618                 return -1;
619 }
620     
621 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
622 {
623         if (m_is_pvr || m_timeshift_enabled)
624         {
625                 ptr = this;
626                 return 0;
627         }
628         
629         ptr = 0;
630         return -1;
631 }
632
633 RESULT eDVBServicePlay::getLength(pts_t &len)
634 {
635         ePtr<iDVBPVRChannel> pvr_channel;
636         
637         if (m_service_handler.getPVRChannel(pvr_channel))
638         {
639                 eDebug("getPVRChannel failed!");
640                 return -1;
641         }
642         
643         return pvr_channel->getLength(len);
644 }
645
646 RESULT eDVBServicePlay::pause()
647 {
648         if (m_timeshift_enabled && !m_timeshift_active)
649         {
650                 switchToTimeshift();
651                 return 0;
652         }
653         if (!m_is_paused && m_decoder)
654         {
655                 m_is_paused = 1;
656                 return m_decoder->freeze(0);
657         } else
658                 return -1;
659 }
660
661 RESULT eDVBServicePlay::unpause()
662 {
663         if (m_is_paused && m_decoder)
664         {
665                 m_is_paused = 0;
666                 return m_decoder->unfreeze();
667         } else
668                 return -1;
669 }
670
671 RESULT eDVBServicePlay::seekTo(pts_t to)
672 {
673         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
674         
675         if (!m_decode_demux)
676                 return -1;
677
678         ePtr<iDVBPVRChannel> pvr_channel;
679         
680         if (m_service_handler.getPVRChannel(pvr_channel))
681                 return -1;
682         
683         return pvr_channel->seekTo(m_decode_demux, 0, to);
684 }
685
686 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
687 {
688         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
689         
690         if (!m_decode_demux)
691                 return -1;
692
693         ePtr<iDVBPVRChannel> pvr_channel;
694         
695         if (m_service_handler.getPVRChannel(pvr_channel))
696                 return -1;
697         
698         to *= direction;
699         
700         return pvr_channel->seekTo(m_decode_demux, 1, to);
701 }
702
703 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
704 {
705         ePtr<iDVBPVRChannel> pvr_channel;
706         
707         if (!m_decode_demux)
708                 return -1;
709         
710         if (m_service_handler.getPVRChannel(pvr_channel))
711                 return -1;
712         
713         return pvr_channel->getCurrentPosition(m_decode_demux, pos, 1);
714 }
715
716 RESULT eDVBServicePlay::setTrickmode(int trick)
717 {
718         if (m_decoder)
719                 m_decoder->setTrickmode(trick);
720         return 0;
721 }
722
723 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
724 {
725         ptr = this;
726         return 0;
727 }
728
729 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
730 {
731         ptr = this;
732         return 0;
733 }
734
735 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
736 {
737         ptr = this;
738         return 0;
739 }
740
741 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
742 {
743         ptr = this;
744         return 0;
745 }
746
747 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
748 {
749         if (m_timeshift_enabled || !m_is_pvr)
750         {
751                 ptr = this;
752                 return 0;
753         }
754         ptr = 0;
755         return -1;
756 }
757
758 RESULT eDVBServicePlay::getName(std::string &name)
759 {
760         if (m_dvb_service)
761         {
762                 m_dvb_service->getName(m_reference, name);
763                 if (name.empty())
764                         name = "(...)";
765         }
766         else if (!m_reference.name.empty())
767                 eStaticServiceDVBInformation().getName(m_reference, name);
768         else
769                 name = "DVB service";
770         return 0;
771 }
772
773 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
774 {
775         return m_event_handler.getEvent(evt, nownext);
776 }
777
778 int eDVBServicePlay::getInfo(int w)
779 {
780         eDVBServicePMTHandler::program program;
781
782         if (m_service_handler.getProgramInfo(program))
783                 return -1;
784         
785         switch (w)
786         {
787         case sAspect:
788                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
789                 {
790                         ePtr<eServiceEvent> evt;
791                         if (!m_event_handler.getEvent(evt, 0))
792                         {
793                                 ePtr<eComponentData> data;
794                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
795                                 {
796                                         if ( data->getStreamContent() == 1 )
797                                         {
798                                                 switch(data->getComponentType())
799                                                 {
800                                                         // SD
801                                                         case 1: // 4:3 SD PAL
802                                                         case 2:
803                                                         case 3: // 16:9 SD PAL
804                                                         case 4: // > 16:9 PAL
805                                                         case 5: // 4:3 SD NTSC
806                                                         case 6: 
807                                                         case 7: // 16:9 SD NTSC
808                                                         case 8: // > 16:9 NTSC
809
810                                                         // HD
811                                                         case 9: // 4:3 HD PAL
812                                                         case 0xA:
813                                                         case 0xB: // 16:9 HD PAL
814                                                         case 0xC: // > 16:9 HD PAL
815                                                         case 0xD: // 4:3 HD NTSC
816                                                         case 0xE:
817                                                         case 0xF: // 16:9 HD NTSC
818                                                         case 0x10: // > 16:9 HD PAL
819                                                                 return data->getComponentType();
820                                                 }
821                                         }
822                                 }
823                         }
824                 }
825                 return -1;
826         case sIsCrypted: return program.isCrypted;
827         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
828         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
829         case sPCRPID: return program.pcrPid;
830         case sPMTPID: return program.pmtPid;
831         case sTXTPID: return -1;
832         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
833         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
834         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
835         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
836         case sProvider: if (!m_dvb_service) return -1; return -2;
837         default:
838                 return -1;
839         }
840 }
841
842 std::string eDVBServicePlay::getInfoString(int w)
843 {       
844         switch (w)
845         {
846         case sProvider:
847                 if (!m_dvb_service) return "";
848                 return m_dvb_service->m_provider_name;
849         default:
850                 return "";
851         }
852 }
853
854 int eDVBServicePlay::getNumberOfTracks()
855 {
856         eDVBServicePMTHandler::program program;
857         if (m_service_handler.getProgramInfo(program))
858                 return 0;
859         return program.audioStreams.size();
860 }
861
862 RESULT eDVBServicePlay::selectTrack(unsigned int i)
863 {
864         int ret = selectAudioStream(i);
865
866         if (m_decoder->start())
867                 return -5;
868
869         return ret;
870 }
871
872 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
873 {
874         eDVBServicePMTHandler::program program;
875
876         if (m_service_handler.getProgramInfo(program))
877                 return -1;
878         
879         if (i >= program.audioStreams.size())
880                 return -2;
881         
882         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
883                 info.m_description = "MPEG";
884         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
885                 info.m_description = "AC3";
886         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
887                 info.m_description = "DTS";
888         else
889                 info.m_description = "???";
890
891         if (program.audioStreams[i].component_tag != -1)
892         {
893                 ePtr<eServiceEvent> evt;
894                 if (!m_event_handler.getEvent(evt, 0))
895                 {
896                         ePtr<eComponentData> data;
897                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
898                                 info.m_language = data->getText();
899                 }
900         }
901
902         if (info.m_language.empty())
903                 info.m_language = program.audioStreams[i].language_code;
904         
905         return 0;
906 }
907
908 int eDVBServicePlay::selectAudioStream(int i)
909 {
910         eDVBServicePMTHandler::program program;
911
912         if (m_service_handler.getProgramInfo(program))
913                 return -1;
914         
915         if ((unsigned int)i >= program.audioStreams.size())
916                 return -2;
917         
918         if (!m_decoder)
919                 return -3;
920         
921         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
922                 return -4;
923
924         if (m_dvb_service && !m_is_pvr)
925         {
926                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
927                 {
928                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
929                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
930                 }       else
931                 {
932                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
933                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
934                 }
935         }
936
937         m_current_audio_stream = i;
938
939         return 0;
940 }
941
942 int eDVBServicePlay::getFrontendInfo(int w)
943 {
944         if (m_is_pvr)
945                 return 0;
946         eUsePtr<iDVBChannel> channel;
947         if(m_service_handler.getChannel(channel))
948                 return 0;
949         ePtr<iDVBFrontend> fe;
950         if(channel->getFrontend(fe))
951                 return 0;
952         return fe->readFrontendData(w);
953 }
954
955 int eDVBServicePlay::getNumberOfSubservices()
956 {
957         ePtr<eServiceEvent> evt;
958         if (!m_event_handler.getEvent(evt, 0))
959                 return evt->getNumOfLinkageServices();
960         return 0;
961 }
962
963 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
964 {
965         ePtr<eServiceEvent> evt;
966         if (!m_event_handler.getEvent(evt, 0))
967         {
968                 if (!evt->getLinkageService(sub, m_reference, n))
969                         return 0;
970         }
971         sub.type=eServiceReference::idInvalid;
972         return -1;
973 }
974
975 RESULT eDVBServicePlay::startTimeshift()
976 {
977         ePtr<iDVBDemux> demux;
978         
979         eDebug("Start timeshift!");
980         
981         if (m_timeshift_enabled)
982                 return -1;
983         
984                 /* start recording with the data demux. */
985         if (m_service_handler.getDataDemux(demux))
986                 return -2;
987
988         demux->createTSRecorder(m_record);
989         if (!m_record)
990                 return -3;
991
992         char templ[]="/media/hdd/timeshift.XXXXXX";
993         m_timeshift_fd = mkstemp(templ);
994         m_timeshift_file = templ;
995         
996         eDebug("recording to %s", templ);
997         
998         if (m_timeshift_fd < 0)
999         {
1000                 delete m_record;
1001                 return -4;
1002         }
1003                 
1004         m_record->setTargetFD(m_timeshift_fd);
1005
1006         m_timeshift_enabled = 1;
1007         
1008         updateTimeshiftPids();
1009         m_record->start();
1010
1011         return 0;
1012 }
1013
1014 RESULT eDVBServicePlay::stopTimeshift()
1015 {
1016         if (!m_timeshift_enabled)
1017                 return -1;
1018         
1019         switchToLive();
1020         
1021         m_timeshift_enabled = 0;
1022         
1023         m_record->stop();
1024         delete m_record;
1025         
1026         close(m_timeshift_fd);
1027         remove(m_timeshift_file.c_str());
1028         
1029         eDebug("timeshift disabled");
1030         return 0;
1031 }
1032
1033 void eDVBServicePlay::updateTimeshiftPids()
1034 {
1035         if (!m_record)
1036                 return;
1037         
1038         eDVBServicePMTHandler::program program;
1039         if (m_service_handler.getProgramInfo(program))
1040                 return;
1041         else
1042         {
1043                 std::set<int> pids_to_record;
1044                 pids_to_record.insert(0); // PAT
1045                 if (program.pmtPid != -1)
1046                         pids_to_record.insert(program.pmtPid); // PMT
1047
1048                 if (program.textPid != -1)
1049                         pids_to_record.insert(program.textPid); // Videotext
1050
1051                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1052                         i(program.videoStreams.begin()); 
1053                         i != program.videoStreams.end(); ++i)
1054                         pids_to_record.insert(i->pid);
1055
1056                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1057                         i(program.audioStreams.begin()); 
1058                         i != program.audioStreams.end(); ++i)
1059                                 pids_to_record.insert(i->pid);
1060
1061                 std::set<int> new_pids, obsolete_pids;
1062                 
1063                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1064                                 m_pids_active.begin(), m_pids_active.end(),
1065                                 std::inserter(new_pids, new_pids.begin()));
1066                 
1067                 std::set_difference(
1068                                 m_pids_active.begin(), m_pids_active.end(),
1069                                 pids_to_record.begin(), pids_to_record.end(), 
1070                                 std::inserter(new_pids, new_pids.begin())
1071                                 );
1072
1073                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1074                         m_record->addPID(*i);
1075
1076                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1077                         m_record->removePID(*i);
1078         }
1079 }
1080
1081 void eDVBServicePlay::switchToLive()
1082 {
1083         eDebug("SwitchToLive");
1084         if (!m_timeshift_active)
1085                 return;
1086         
1087         m_decoder = 0;
1088         m_decode_demux = 0;
1089                 /* free the timeshift service handler, we need the resources */
1090         m_service_handler_timeshift.free();
1091         m_timeshift_active = 0;
1092         
1093         updateDecoder();
1094 }
1095
1096 void eDVBServicePlay::switchToTimeshift()
1097 {
1098         eDebug("SwitchToTimeshift");
1099         if (m_timeshift_active)
1100                 return;
1101         
1102         m_decode_demux = 0;
1103         m_decoder = 0;
1104         
1105         m_timeshift_active = 1;
1106         
1107         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1108         r.path = m_timeshift_file;
1109         
1110         eDebug("ok, re-tuning to %s", r.toString().c_str());
1111         m_service_handler_timeshift.tune(r, 1); /* use the decoder demux for everything */
1112 }
1113
1114 void eDVBServicePlay::updateDecoder()
1115 {
1116         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1117         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1118
1119         eDVBServicePMTHandler::program program;
1120         if (h.getProgramInfo(program))
1121                 eDebug("getting program info failed.");
1122         else
1123         {
1124                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1125                 if (!program.videoStreams.empty())
1126                 {
1127                         eDebugNoNewLine(" (");
1128                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1129                                 i(program.videoStreams.begin()); 
1130                                 i != program.videoStreams.end(); ++i)
1131                         {
1132                                 if (vpid == -1)
1133                                         vpid = i->pid;
1134                                 if (i != program.videoStreams.begin())
1135                                         eDebugNoNewLine(", ");
1136                                 eDebugNoNewLine("%04x", i->pid);
1137                         }
1138                         eDebugNoNewLine(")");
1139                 }
1140                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1141                 if (!program.audioStreams.empty())
1142                 {
1143                         eDebugNoNewLine(" (");
1144                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1145                                 i(program.audioStreams.begin()); 
1146                                 i != program.audioStreams.end(); ++i)
1147                         {
1148                                 if (apid == -1)
1149                                 {
1150                                         apid = i->pid;
1151                                         apidtype = i->type;
1152                                 }
1153                                 if (i != program.audioStreams.begin())
1154                                         eDebugNoNewLine(", ");
1155                                 eDebugNoNewLine("%04x", i->pid);
1156                         }
1157                         eDebugNoNewLine(")");
1158                 }
1159                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1160                 pcrpid = program.pcrPid;
1161                 eDebug(", and the text pid is %04x", program.textPid);
1162                 tpid = program.textPid;
1163         }
1164
1165         if (!m_decoder)
1166         {
1167                 h.getDecodeDemux(m_decode_demux);
1168                 if (m_decode_demux)
1169                         m_decode_demux->getMPEGDecoder(m_decoder);
1170         }
1171
1172         if (m_decoder)
1173         {
1174                 m_decoder->setVideoPID(vpid);
1175                 m_current_audio_stream = 0;
1176                 m_decoder->setAudioPID(apid, apidtype);
1177                 if (!(m_is_pvr || m_timeshift_active))
1178                         m_decoder->setSyncPCR(pcrpid);
1179                 else
1180                         m_decoder->setSyncPCR(-1);
1181                 m_decoder->setTextPID(tpid);
1182                 m_decoder->start();
1183 // how we can do this better?
1184 // update cache pid when the user changed the audio track or video track
1185 // TODO handling of difference audio types.. default audio types..
1186                                 
1187                 /* don't worry about non-existing services, nor pvr services */
1188                 if (m_dvb_service && !m_is_pvr)
1189                 {
1190                         if (apidtype == eDVBAudio::aMPEG)
1191                         {
1192                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1193                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1194                         }
1195                         else
1196                         {
1197                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1198                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1199                         }
1200                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1201                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1202                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1203                 }
1204         }
1205 }
1206
1207 DEFINE_REF(eDVBServicePlay)
1208
1209 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");