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