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