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