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