928690d0c2dd7430fb8082008858defd9f262bb4
[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 #include <lib/base/nconfig.h> // access to python config
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
19
20 #include <sys/vfs.h>
21
22 #include <byteswap.h>
23 #include <netinet/in.h>
24
25 #include <dvbsi++/event_information_section.h>
26
27 #ifndef BYTE_ORDER
28 #error no byte order defined!
29 #endif
30
31 #define TSPATH "/media/hdd"
32
33 class eStaticServiceDVBInformation: public iStaticServiceInformation
34 {
35         DECLARE_REF(eStaticServiceDVBInformation);
36 public:
37         RESULT getName(const eServiceReference &ref, std::string &name);
38         int getLength(const eServiceReference &ref);
39 };
40
41 DEFINE_REF(eStaticServiceDVBInformation);
42
43 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
44 {
45         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
46         if ( !ref.name.empty() )
47         {
48                 if (service.getParentTransportStreamID().get()) // linkage subservice
49                 {
50                         ePtr<iServiceHandler> service_center;
51                         if (!eServiceCenter::getInstance(service_center))
52                         {
53                                 eServiceReferenceDVB parent = service;
54                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
55                                 parent.setServiceID( service.getParentServiceID() );
56                                 parent.setParentTransportStreamID(eTransportStreamID(0));
57                                 parent.setParentServiceID(eServiceID(0));
58                                 parent.name="";
59                                 ePtr<iStaticServiceInformation> service_info;
60                                 if (!service_center->info(parent, service_info))
61                                 {
62                                         if (!service_info->getName(parent, name))
63                                         {
64                                                 // just show short name
65                                                 unsigned int pos = name.find("\xc2\x86");
66                                                 if ( pos != std::string::npos )
67                                                         name.erase(0, pos+2);
68                                                 pos = name.find("\xc2\x87");
69                                                 if ( pos != std::string::npos )
70                                                         name.erase(pos);
71                                                 name+=" - ";
72                                         }
73                                 }
74                         }
75                 }
76                 else
77                         name="";
78                 name += ref.name;
79                 return 0;
80         }
81         else
82                 return -1;
83 }
84
85 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
86 {
87         return -1;
88 }
89
90 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
91 {
92         DECLARE_REF(eStaticServiceDVBBouquetInformation);
93 public:
94         RESULT getName(const eServiceReference &ref, std::string &name);
95         int getLength(const eServiceReference &ref);
96 };
97
98 DEFINE_REF(eStaticServiceDVBBouquetInformation);
99
100 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
101 {
102         ePtr<iDVBChannelList> db;
103         ePtr<eDVBResourceManager> res;
104
105         int err;
106         if ((err = eDVBResourceManager::getInstance(res)) != 0)
107         {
108                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
109                 return err;
110         }
111         if ((err = res->getChannelList(db)) != 0)
112         {
113                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
114                 return err;
115         }
116
117         eBouquet *bouquet=0;
118         if ((err = db->getBouquet(ref, bouquet)) != 0)
119         {
120                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
121                 return -1;
122         }
123
124         if ( bouquet && bouquet->m_bouquet_name.length() )
125         {
126                 name = bouquet->m_bouquet_name;
127                 return 0;
128         }
129         else
130                 return -1;
131 }
132
133 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
134 {
135         return -1;
136 }
137
138 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
139 {
140         DECLARE_REF(eStaticServiceDVBPVRInformation);
141         eServiceReference m_ref;
142         eDVBMetaParser m_parser;
143 public:
144         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
145         RESULT getName(const eServiceReference &ref, std::string &name);
146         int getLength(const eServiceReference &ref);
147         
148         int getInfo(const eServiceReference &ref, int w);
149         std::string getInfoString(const eServiceReference &ref,int w);
150 };
151
152 DEFINE_REF(eStaticServiceDVBPVRInformation);
153
154 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
155 {
156         m_ref = ref;
157         m_parser.parseFile(ref.path);
158 }
159
160 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
161 {
162         ASSERT(ref == m_ref);
163         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
164         return 0;
165 }
166
167 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
168 {
169         ASSERT(ref == m_ref);
170         
171         eDVBTSTools tstools;
172         
173         if (tstools.openFile(ref.path.c_str()))
174                 return 0;
175
176         pts_t len;
177         if (tstools.calcLen(len))
178                 return 0;
179
180         return len / 90000;
181 }
182
183 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
184 {
185         switch (w)
186         {
187         case iServiceInformation::sDescription:
188                 return iServiceInformation::resIsString;
189         case iServiceInformation::sServiceref:
190                 return iServiceInformation::resIsString;
191         case iServiceInformation::sTimeCreate:
192                 if (m_parser.m_time_create)
193                         return m_parser.m_time_create;
194                 else
195                         return iServiceInformation::resNA;
196         default:
197                 return iServiceInformation::resNA;
198         }
199 }
200
201 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
202 {
203         switch (w)
204         {
205         case iServiceInformation::sDescription:
206                 return m_parser.m_description;
207         case iServiceInformation::sServiceref:
208                 return m_parser.m_ref.toString();
209         default:
210                 return "";
211         }
212 }
213
214 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
215 {
216         DECLARE_REF(eDVBPVRServiceOfflineOperations);
217         eServiceReferenceDVB m_ref;
218 public:
219         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
220         
221         RESULT deleteFromDisk(int simulate);
222         RESULT getListOfFilenames(std::list<std::string> &);
223 };
224
225 DEFINE_REF(eDVBPVRServiceOfflineOperations);
226
227 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
228 {
229 }
230
231 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
232 {
233         if (simulate)
234                 return 0;
235         else
236         {
237                 std::list<std::string> res;
238                 if (getListOfFilenames(res))
239                         return -1;
240                 
241                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
242                 if (!eraser)
243                         eDebug("FATAL !! can't get background file eraser");
244                 
245                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
246                 {
247                         eDebug("Removing %s...", i->c_str());
248                         if (eraser)
249                                 eraser->erase(i->c_str());
250                         else
251                                 ::unlink(i->c_str());
252                 }
253                 
254                 return 0;
255         }
256 }
257
258 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
259 {
260         res.clear();
261         res.push_back(m_ref.path);
262
263 // handling for old splitted recordings (enigma 1)
264         char buf[255];
265         int slice=1;
266         while(true)
267         {
268                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
269                 struct stat s;
270                 if (stat(buf, &s) < 0)
271                         break;
272                 res.push_back(buf);
273         }       
274
275         res.push_back(m_ref.path + ".meta");
276         res.push_back(m_ref.path + ".ap");
277         res.push_back(m_ref.path + ".cuts");
278         std::string tmp = m_ref.path;
279         tmp.erase(m_ref.path.length()-3);
280         res.push_back(tmp + ".eit");
281         return 0;
282 }
283
284 DEFINE_REF(eServiceFactoryDVB)
285
286 eServiceFactoryDVB::eServiceFactoryDVB()
287 {
288         ePtr<eServiceCenter> sc;
289         
290         eServiceCenter::getPrivInstance(sc);
291         if (sc)
292                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
293 }
294
295 eServiceFactoryDVB::~eServiceFactoryDVB()
296 {
297         ePtr<eServiceCenter> sc;
298         
299         eServiceCenter::getPrivInstance(sc);
300         if (sc)
301                 sc->removeServiceFactory(eServiceFactoryDVB::id);
302 }
303
304 DEFINE_REF(eDVBServiceList);
305
306 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
307 {
308 }
309
310 eDVBServiceList::~eDVBServiceList()
311 {
312 }
313
314 RESULT eDVBServiceList::startQuery()
315 {
316         ePtr<iDVBChannelList> db;
317         ePtr<eDVBResourceManager> res;
318         
319         int err;
320         if ((err = eDVBResourceManager::getInstance(res)) != 0)
321         {
322                 eDebug("no resource manager");
323                 return err;
324         }
325         if ((err = res->getChannelList(db)) != 0)
326         {
327                 eDebug("no channel list");
328                 return err;
329         }
330         
331         ePtr<eDVBChannelQuery> q;
332         
333         if (!m_parent.path.empty())
334         {
335                 eDVBChannelQuery::compile(q, m_parent.path);
336                 if (!q)
337                 {
338                         eDebug("compile query failed");
339                         return err;
340                 }
341         }
342         
343         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
344         {
345                 eDebug("startQuery failed");
346                 return err;
347         }
348
349         return 0;
350 }
351
352 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
353 {
354         eServiceReferenceDVB ref;
355         
356         if (!m_query)
357                 return -1;
358         
359         while (!m_query->getNextResult(ref))
360                 list.push_back(ref);
361
362         if (sorted)
363                 list.sort(iListableServiceCompare(this));
364
365         return 0;
366 }
367
368 //   The first argument of this function is a format string to specify the order and
369 //   the content of the returned list
370 //   useable format options are
371 //   R = Service Reference (as swig object .. this is very slow)
372 //   S = Service Reference (as python string object .. same as ref.toString())
373 //   N = Service Name (as python string object)
374 //   when exactly one return value per service is selected in the format string,
375 //   then each value is directly a list entry
376 //   when more than one value is returned per service, then the list is a list of
377 //   python tuples
378 //   unknown format string chars are returned as python None values !
379 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
380 {
381         PyObject *ret=0;
382         std::list<eServiceReference> tmplist;
383         int retcount=1;
384
385         if (!format || !(retcount=strlen(format)))
386                 format = "R"; // just return service reference swig object ...
387
388         if (!getContent(tmplist, sorted))
389         {
390                 int services=tmplist.size();
391                 ePtr<iStaticServiceInformation> sptr;
392                 eServiceCenterPtr service_center;
393
394                 if (strchr(format, 'N'))
395                         eServiceCenter::getPrivInstance(service_center);
396
397                 ret = PyList_New(services);
398                 std::list<eServiceReference>::iterator it(tmplist.begin());
399
400                 for (int cnt=0; cnt < services; ++cnt)
401                 {
402                         eServiceReference &ref=*it++;
403                         PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
404                         for (int i=0; i < retcount; ++i)
405                         {
406                                 PyObject *tmp=0;
407                                 switch(format[i])
408                                 {
409                                 case 'R':  // service reference (swig)object
410                                         tmp = New_eServiceReference(ref);
411                                         break;
412                                 case 'S':  // service reference string
413                                         tmp = PyString_FromString(ref.toString().c_str());
414                                         break;
415                                 case 'N':  // service name
416                                         if (service_center)
417                                         {
418                                                 service_center->info(ref, sptr);
419                                                 if (sptr)
420                                                 {
421                                                         std::string name;
422                                                         sptr->getName(ref, name);
423                                                         if (name.length())
424                                                                 tmp = PyString_FromString(name.c_str());
425                                                 }
426                                         }
427                                         if (!tmp)
428                                                 tmp = PyString_FromString("<n/a>");
429                                         break;
430                                 default:
431                                         if (tuple)
432                                         {
433                                                 tmp = Py_None;
434                                                 Py_INCREF(Py_None);
435                                         }
436                                         break;
437                                 }
438                                 if (tmp)
439                                 {
440                                         if (tuple)
441                                                 PyTuple_SET_ITEM(tuple, i, tmp);
442                                         else
443                                                 PyList_SET_ITEM(ret, cnt, tmp);
444                                 }
445                         }
446                         if (tuple)
447                                 PyList_SET_ITEM(ret, cnt, tuple);
448                 }
449         }
450         return ret ? ret : PyList_New(0);
451 }
452
453 RESULT eDVBServiceList::getNext(eServiceReference &ref)
454 {
455         if (!m_query)
456                 return -1;
457         
458         return m_query->getNextResult((eServiceReferenceDVB&)ref);
459 }
460
461 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
462 {
463         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
464 }
465
466 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
467 {
468         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
469         {
470                 ePtr<iDVBChannelList> db;
471                 ePtr<eDVBResourceManager> resm;
472
473                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
474                         return -1;
475
476                 if (db->getBouquet(m_parent, m_bouquet) != 0)
477                         return -1;
478
479                 res = this;
480                 
481                 return 0;
482         }
483         res = 0;
484         return -1;
485 }
486
487 RESULT eDVBServiceList::addService(eServiceReference &ref)
488 {
489         if (!m_bouquet)
490                 return -1;
491         return m_bouquet->addService(ref);
492 }
493
494 RESULT eDVBServiceList::removeService(eServiceReference &ref)
495 {
496         if (!m_bouquet)
497                 return -1;
498         return m_bouquet->removeService(ref);
499 }
500
501 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
502 {
503         if (!m_bouquet)
504                 return -1;
505         return m_bouquet->moveService(ref, pos);
506 }
507
508 RESULT eDVBServiceList::flushChanges()
509 {
510         if (!m_bouquet)
511                 return -1;
512         return m_bouquet->flushChanges();
513 }
514
515 RESULT eDVBServiceList::setListName(const std::string &name)
516 {
517         if (!m_bouquet)
518                 return -1;
519         return m_bouquet->setListName(name);
520 }
521
522 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
523 {
524         ePtr<eDVBService> service;
525         int r = lookupService(service, ref);
526         if (r)
527                 service = 0;
528                 // check resources...
529         ptr = new eDVBServicePlay(ref, service);
530         return 0;
531 }
532
533 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
534 {
535         if (ref.path.empty())
536         {
537                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
538                 return 0;
539         } else
540         {
541                 ptr = 0;
542                 return -1;
543         }
544 }
545
546 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
547 {
548         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
549         if (list->startQuery())
550         {
551                 ptr = 0;
552                 return -1;
553         }
554         
555         ptr = list;
556         return 0;
557 }
558
559 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
560 {
561         /* is a listable service? */
562         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
563         {
564                 if ( !ref.name.empty() )  // satellites or providers list
565                         ptr = new eStaticServiceDVBInformation;
566                 else // a dvb bouquet
567                         ptr = new eStaticServiceDVBBouquetInformation;
568         }
569         else if (!ref.path.empty()) /* do we have a PVR service? */
570                 ptr = new eStaticServiceDVBPVRInformation(ref);
571         else // normal dvb service
572         {
573                 ePtr<eDVBService> service;
574                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
575                         ptr = new eStaticServiceDVBInformation;
576                 else
577                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
578                         ptr = service;
579         }
580         return 0;
581 }
582
583 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
584 {
585         if (ref.path.empty())
586         {
587                 ptr = 0;
588                 return -1;
589         } else
590         {
591                 ptr = new eDVBPVRServiceOfflineOperations(ref);
592                 return 0;
593         }
594 }
595
596 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
597 {
598                         // TODO: handle the listing itself
599         // if (ref.... == -1) .. return "... bouquets ...";
600         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
601                         // TODO: cache
602         ePtr<iDVBChannelList> db;
603         ePtr<eDVBResourceManager> res;
604         
605         int err;
606         if ((err = eDVBResourceManager::getInstance(res)) != 0)
607         {
608                 eDebug("no resource manager");
609                 return err;
610         }
611         if ((err = res->getChannelList(db)) != 0)
612         {
613                 eDebug("no channel list");
614                 return err;
615         }
616         
617                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
618         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
619         {
620                 eDebug("getService failed!");
621                 return err;
622         }
623
624         return 0;
625 }
626
627 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
628         m_reference(ref), m_dvb_service(service), m_is_paused(0)
629 {
630         m_is_primary = 1;
631         m_is_pvr = !m_reference.path.empty();
632         
633         m_timeshift_enabled = m_timeshift_active = 0;
634         m_skipmode = 0;
635         
636         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
637         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
638         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
639
640         m_cuesheet_changed = 0;
641         m_cutlist_enabled = 1;
642 }
643
644 eDVBServicePlay::~eDVBServicePlay()
645 {
646 }
647
648 void eDVBServicePlay::gotNewEvent()
649 {
650 #if 0
651                 // debug only
652         ePtr<eServiceEvent> m_event_now, m_event_next;
653         getEvent(m_event_now, 0);
654         getEvent(m_event_next, 1);
655
656         if (m_event_now)
657                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
658         if (m_event_next)
659                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
660 #endif
661         m_event((iPlayableService*)this, evUpdatedEventInfo);
662 }
663
664 void eDVBServicePlay::serviceEvent(int event)
665 {
666         switch (event)
667         {
668         case eDVBServicePMTHandler::eventTuned:
669         {
670                 ePtr<iDVBDemux> m_demux;
671                 if (!m_service_handler.getDataDemux(m_demux))
672                 {
673                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
674                         int sid = ref.getParentServiceID().get();
675                         if (!sid)
676                                 sid = ref.getServiceID().get();
677                         if ( ref.getParentTransportStreamID().get() &&
678                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
679                                 m_event_handler.startOther(m_demux, sid);
680                         else
681                                 m_event_handler.start(m_demux, sid);
682                 }
683                 break;
684         }
685         case eDVBServicePMTHandler::eventTuneFailed:
686         {
687                 eDebug("DVB service failed to tune");
688                 m_event((iPlayableService*)this, evTuneFailed);
689                 break;
690         }
691         case eDVBServicePMTHandler::eventNewProgramInfo:
692         {
693                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
694                 if (m_timeshift_enabled)
695                         updateTimeshiftPids();
696                 if (!m_timeshift_active)
697                         updateDecoder();
698                 if (m_first_program_info && m_is_pvr)
699                 {
700                         m_first_program_info = 0;
701                         seekTo(0);
702                 }
703                 m_event((iPlayableService*)this, evUpdatedInfo);
704                 break;
705         }
706         case eDVBServicePMTHandler::eventEOF:
707                 m_event((iPlayableService*)this, evEOF);
708                 break;
709         case eDVBServicePMTHandler::eventSOF:
710                 m_event((iPlayableService*)this, evSOF);
711                 break;
712         }
713 }
714
715 void eDVBServicePlay::serviceEventTimeshift(int event)
716 {
717         switch (event)
718         {
719         case eDVBServicePMTHandler::eventNewProgramInfo:
720                 if (m_timeshift_active)
721                         updateDecoder();
722                 break;
723         case eDVBServicePMTHandler::eventSOF:
724                 m_event((iPlayableService*)this, evSOF);
725                 break;
726         case eDVBServicePMTHandler::eventEOF:
727                 switchToLive();
728                 break;
729         }
730 }
731
732 RESULT eDVBServicePlay::start()
733 {
734         int r;
735                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
736                    two (one for decoding, one for data source), as we must be prepared
737                    to start recording from the data demux. */
738         if (m_is_pvr)
739                 m_cue = new eCueSheet();
740
741         m_first_program_info = 1;
742         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
743         r = m_service_handler.tune(service, m_is_pvr, m_cue);
744         
745                 /* inject EIT if there is a stored one */
746         if (m_is_pvr)
747         {
748                 std::string filename = service.path;
749                 filename.erase(filename.length()-2, 2);
750                 filename+="eit";
751                 int fd = ::open( filename.c_str(), O_RDONLY );
752                 if ( fd > -1 )
753                 {
754                         __u8 buf[4096];
755                         int rd = ::read(fd, buf, 4096);
756                         ::close(fd);
757                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
758                         {
759                                 Event ev(buf);
760                                 ePtr<eServiceEvent> event = new eServiceEvent;
761                                 ePtr<eServiceEvent> empty;
762                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
763                                 m_event_handler.inject(event, 0);
764                                 m_event_handler.inject(empty, 1);
765                                 eDebug("injected");
766                         }
767                 }
768         }
769         
770         if (m_is_pvr)
771                 loadCuesheet();
772
773         m_event(this, evStart);
774         m_event((iPlayableService*)this, evSeekableStatusChanged);
775         return 0;
776 }
777
778 RESULT eDVBServicePlay::stop()
779 {
780         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
781
782         m_service_handler_timeshift.free();
783         m_service_handler.free();
784         
785         if (m_is_pvr && m_cuesheet_changed)
786                 saveCuesheet();
787         
788         return 0;
789 }
790
791 RESULT eDVBServicePlay::setTarget(int target)
792 {
793         m_is_primary = !target;
794         return 0;
795 }
796
797 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
798 {
799         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
800         return 0;
801 }
802
803 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
804 {
805                 /* note: we check for timeshift to be enabled,
806                    not neccessary active. if you pause when timeshift
807                    is not active, you should activate it when unpausing */
808         if ((!m_is_pvr) && (!m_timeshift_enabled))
809         {
810                 ptr = 0;
811                 return -1;
812         }
813
814         ptr = this;
815         return 0;
816 }
817
818 RESULT eDVBServicePlay::setSlowMotion(int ratio)
819 {
820         if (m_decoder)
821                 return m_decoder->setSlowMotion(ratio);
822         else
823                 return -1;
824 }
825
826 RESULT eDVBServicePlay::setFastForward(int ratio)
827 {
828         int skipmode, ffratio;
829         
830         if (ratio > 8)
831         {
832                 skipmode = ratio;
833                 ffratio = 1;
834         } else if (ratio > 0)
835         {
836                 skipmode = 0;
837                 ffratio = ratio;
838         } else if (!ratio)
839         {
840                 skipmode = 0;
841                 ffratio = 0;
842         } else // if (ratio < 0)
843         {
844                 skipmode = ratio;
845                 ffratio = 1;
846         }
847
848         if (m_skipmode != skipmode)
849         {
850                 eDebug("setting cue skipmode to %d", skipmode);
851                 if (m_cue)
852                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
853         }
854         
855         m_skipmode = skipmode;
856         
857         if (!m_decoder)
858                 return -1;
859
860         return m_decoder->setFastForward(ffratio);
861 }
862     
863 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
864 {
865         if (m_is_pvr || m_timeshift_enabled)
866         {
867                 ptr = this;
868                 return 0;
869         }
870         
871         ptr = 0;
872         return -1;
873 }
874
875         /* TODO: when timeshift is enabled but not active, this doesn't work. */
876 RESULT eDVBServicePlay::getLength(pts_t &len)
877 {
878         ePtr<iDVBPVRChannel> pvr_channel;
879         
880         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
881                 return -1;
882         
883         return pvr_channel->getLength(len);
884 }
885
886 RESULT eDVBServicePlay::pause()
887 {
888         if (!m_is_paused && m_decoder)
889         {
890                 m_is_paused = 1;
891                 return m_decoder->freeze(0);
892         } else
893                 return -1;
894 }
895
896 RESULT eDVBServicePlay::unpause()
897 {
898         if (m_is_paused && m_decoder)
899         {
900                 m_is_paused = 0;
901                 return m_decoder->unfreeze();
902         } else
903                 return -1;
904 }
905
906 RESULT eDVBServicePlay::seekTo(pts_t to)
907 {
908         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
909         
910         if (!m_decode_demux)
911                 return -1;
912
913         ePtr<iDVBPVRChannel> pvr_channel;
914         
915         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
916                 return -1;
917         
918         if (!m_cue)
919                 return -1;
920         
921         m_cue->seekTo(0, to);
922         return 0;
923 }
924
925 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
926 {
927         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
928         
929         if (!m_decode_demux)
930                 return -1;
931
932         ePtr<iDVBPVRChannel> pvr_channel;
933         
934         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
935                 return -1;
936         
937         int mode = 1;
938         
939                         /* HACK until we have skip-AP api */
940         if ((to > 0) && (to < 100))
941                 mode = 2;
942         
943         to *= direction;
944         
945         if (!m_cue)
946                 return 0;
947         
948         m_cue->seekTo(mode, to);
949         return 0;
950 }
951
952 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
953 {
954         ePtr<iDVBPVRChannel> pvr_channel;
955         
956         if (!m_decode_demux)
957                 return -1;
958         
959         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
960                 return -1;
961         
962         int r = 0;
963
964                 /* if there is a decoder, use audio or video PTS */
965         if (m_decoder)
966         {
967                 r = m_decoder->getPTS(0, pos);
968                 if (r)
969                         return r;
970         }
971         
972                 /* fixup */
973         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
974 }
975
976 RESULT eDVBServicePlay::setTrickmode(int trick)
977 {
978         if (m_decoder)
979                 m_decoder->setTrickmode(trick);
980         return 0;
981 }
982
983 RESULT eDVBServicePlay::isCurrentlySeekable()
984 {
985         return m_is_pvr || m_timeshift_active;
986 }
987
988 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
989 {
990         ptr = this;
991         return 0;
992 }
993
994 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
995 {
996         ptr = this;
997         return 0;
998 }
999
1000 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1001 {
1002         ptr = this;
1003         return 0;
1004 }
1005
1006 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1007 {
1008         ptr = this;
1009         return 0;
1010 }
1011
1012 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1013 {
1014         ptr = this;
1015         return 0;
1016 }
1017
1018 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1019 {
1020         ptr = 0;
1021         if (m_timeshift_enabled || !m_is_pvr)
1022         {
1023                 if (!m_timeshift_enabled)
1024                 {
1025                                 /* we need enough diskspace */
1026                         struct statfs fs;
1027                         if (statfs(TSPATH "/.", &fs) < 0)
1028                         {
1029                                 eDebug("statfs failed!");
1030                                 return -2;
1031                         }
1032                 
1033                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1034                         {
1035                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1036                                 return -3;
1037                         }
1038                 }
1039                 ptr = this;
1040                 return 0;
1041         }
1042         return -1;
1043 }
1044
1045 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1046 {
1047         if (m_is_pvr)
1048         {
1049                 ptr = this;
1050                 return 0;
1051         }
1052         ptr = 0;
1053         return -1;
1054 }
1055
1056 RESULT eDVBServicePlay::getName(std::string &name)
1057 {
1058         if (m_is_pvr)
1059         {
1060                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1061                 return i->getName(m_reference, name);
1062         }
1063         if (m_dvb_service)
1064         {
1065                 m_dvb_service->getName(m_reference, name);
1066                 if (name.empty())
1067                         name = "(...)";
1068         }
1069         else if (!m_reference.name.empty())
1070                 eStaticServiceDVBInformation().getName(m_reference, name);
1071         else
1072                 name = "DVB service";
1073         return 0;
1074 }
1075
1076 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1077 {
1078         return m_event_handler.getEvent(evt, nownext);
1079 }
1080
1081 int eDVBServicePlay::getInfo(int w)
1082 {
1083         eDVBServicePMTHandler::program program;
1084
1085         if (w == sCAIDs)
1086                 return resIsPyObject;
1087
1088         if (m_service_handler.getProgramInfo(program))
1089                 return -1;
1090         
1091         switch (w)
1092         {
1093         case sAspect:
1094                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1095                 {
1096                         ePtr<eServiceEvent> evt;
1097                         if (!m_event_handler.getEvent(evt, 0))
1098                         {
1099                                 ePtr<eComponentData> data;
1100                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1101                                 {
1102                                         if ( data->getStreamContent() == 1 )
1103                                         {
1104                                                 switch(data->getComponentType())
1105                                                 {
1106                                                         // SD
1107                                                         case 1: // 4:3 SD PAL
1108                                                         case 2:
1109                                                         case 3: // 16:9 SD PAL
1110                                                         case 4: // > 16:9 PAL
1111                                                         case 5: // 4:3 SD NTSC
1112                                                         case 6: 
1113                                                         case 7: // 16:9 SD NTSC
1114                                                         case 8: // > 16:9 NTSC
1115
1116                                                         // HD
1117                                                         case 9: // 4:3 HD PAL
1118                                                         case 0xA:
1119                                                         case 0xB: // 16:9 HD PAL
1120                                                         case 0xC: // > 16:9 HD PAL
1121                                                         case 0xD: // 4:3 HD NTSC
1122                                                         case 0xE:
1123                                                         case 0xF: // 16:9 HD NTSC
1124                                                         case 0x10: // > 16:9 HD PAL
1125                                                                 return data->getComponentType();
1126                                                 }
1127                                         }
1128                                 }
1129                         }
1130                 }
1131                 return -1;
1132         case sIsCrypted: return program.isCrypted;
1133         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1134         case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1135         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1136         case sPCRPID: return program.pcrPid;
1137         case sPMTPID: return program.pmtPid;
1138         case sTXTPID: return program.textPid;
1139         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1140         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1141         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1142         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1143         case sProvider: if (!m_dvb_service) return -1; return -2;
1144         default:
1145                 return -1;
1146         }
1147 }
1148
1149 std::string eDVBServicePlay::getInfoString(int w)
1150 {
1151         switch (w)
1152         {
1153         case sProvider:
1154                 if (!m_dvb_service) return "";
1155                 return m_dvb_service->m_provider_name;
1156         default:
1157                 break;
1158         }
1159         return iServiceInformation::getInfoString(w);
1160 }
1161
1162 PyObject *eDVBServicePlay::getInfoObject(int w)
1163 {
1164         switch (w)
1165         {
1166         case sCAIDs:
1167                 return m_service_handler.getCaIds();
1168         default:
1169                 break;
1170         }
1171         return iServiceInformation::getInfoObject(w);
1172 }
1173
1174 int eDVBServicePlay::getNumberOfTracks()
1175 {
1176         eDVBServicePMTHandler::program program;
1177         if (m_service_handler.getProgramInfo(program))
1178                 return 0;
1179         return program.audioStreams.size();
1180 }
1181
1182 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1183 {
1184         int ret = selectAudioStream(i);
1185
1186         if (m_decoder->start())
1187                 return -5;
1188
1189         return ret;
1190 }
1191
1192 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1193 {
1194         eDVBServicePMTHandler::program program;
1195
1196         if (m_service_handler.getProgramInfo(program))
1197                 return -1;
1198         
1199         if (i >= program.audioStreams.size())
1200                 return -2;
1201         
1202         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1203                 info.m_description = "MPEG";
1204         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1205                 info.m_description = "AC3";
1206         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1207                 info.m_description = "AAC";
1208         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1209                 info.m_description = "DTS";
1210         else
1211                 info.m_description = "???";
1212
1213         if (program.audioStreams[i].component_tag != -1)
1214         {
1215                 ePtr<eServiceEvent> evt;
1216                 if (!m_event_handler.getEvent(evt, 0))
1217                 {
1218                         ePtr<eComponentData> data;
1219                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1220                                 info.m_language = data->getText();
1221                 }
1222         }
1223
1224         if (info.m_language.empty())
1225                 info.m_language = program.audioStreams[i].language_code;
1226         
1227         return 0;
1228 }
1229
1230 int eDVBServicePlay::selectAudioStream(int i)
1231 {
1232         eDVBServicePMTHandler::program program;
1233
1234         if (m_service_handler.getProgramInfo(program))
1235                 return -1;
1236         
1237         if ((unsigned int)i >= program.audioStreams.size())
1238                 return -2;
1239         
1240         if (!m_decoder)
1241                 return -3;
1242         
1243         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1244                 return -4;
1245
1246         if (m_dvb_service && !m_is_pvr)
1247         {
1248                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1249                 {
1250                         m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1251                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1252                 }       else
1253                 {
1254                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1255                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1256                 }
1257         }
1258
1259         m_current_audio_stream = i;
1260
1261         return 0;
1262 }
1263
1264 int eDVBServicePlay::getCurrentChannel()
1265 {
1266         int curChannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1267         return curChannel == -1 ? STEREO : curChannel;
1268 }
1269
1270 RESULT eDVBServicePlay::selectChannel(int i)
1271 {
1272         if (i < iAudioChannelSelection::LEFT || i > iAudioChannelSelection::RIGHT)
1273                 i = -1;  // Stereo
1274         if (m_dvb_service->getCacheEntry(eDVBService::cACHANNEL) != i)
1275         {
1276                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1277                 if (m_decoder)
1278                         m_decoder->setAudioChannel(i);
1279         }
1280 }
1281
1282 int eDVBServiceBase::getFrontendInfo(int w)
1283 {
1284         eUsePtr<iDVBChannel> channel;
1285         if(m_service_handler.getChannel(channel))
1286                 return 0;
1287         ePtr<iDVBFrontend> fe;
1288         if(channel->getFrontend(fe))
1289                 return 0;
1290         return fe->readFrontendData(w);
1291 }
1292
1293 PyObject *eDVBServiceBase::getFrontendData(bool original)
1294 {
1295         PyObject *ret=0;
1296
1297         eUsePtr<iDVBChannel> channel;
1298         if(!m_service_handler.getChannel(channel))
1299         {
1300                 ePtr<iDVBFrontend> fe;
1301                 if(!channel->getFrontend(fe))
1302                 {
1303                         ret = fe->readTransponderData(original);
1304                         if (ret)
1305                         {
1306                                 ePtr<iDVBFrontendParameters> feparm;
1307                                 channel->getCurrentFrontendParameters(feparm);
1308                                 if (feparm)
1309                                 {
1310                                         eDVBFrontendParametersSatellite osat;
1311                                         if (!feparm->getDVBS(osat))
1312                                         {
1313                                                 void PutToDict(PyObject *, const char*, long);
1314                                                 void PutToDict(PyObject *, const char*, const char*);
1315                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1316                                                 const char *tmp = "UNKNOWN";
1317                                                 switch(osat.polarisation)
1318                                                 {
1319                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1320                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1321                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1322                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1323                                                         default:break;
1324                                                 }
1325                                                 PutToDict(ret, "polarization", tmp);
1326                                         }
1327                                 }
1328                         }
1329                 }
1330         }
1331         if (!ret)
1332         {
1333                 ret = Py_None;
1334                 Py_INCREF(ret);
1335         }
1336         return ret;
1337 }
1338
1339 int eDVBServicePlay::getNumberOfSubservices()
1340 {
1341         ePtr<eServiceEvent> evt;
1342         if (!m_event_handler.getEvent(evt, 0))
1343                 return evt->getNumOfLinkageServices();
1344         return 0;
1345 }
1346
1347 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1348 {
1349         ePtr<eServiceEvent> evt;
1350         if (!m_event_handler.getEvent(evt, 0))
1351         {
1352                 if (!evt->getLinkageService(sub, m_reference, n))
1353                         return 0;
1354         }
1355         sub.type=eServiceReference::idInvalid;
1356         return -1;
1357 }
1358
1359 RESULT eDVBServicePlay::startTimeshift()
1360 {
1361         ePtr<iDVBDemux> demux;
1362         
1363         eDebug("Start timeshift!");
1364         
1365         if (m_timeshift_enabled)
1366                 return -1;
1367         
1368                 /* start recording with the data demux. */
1369         if (m_service_handler.getDataDemux(demux))
1370                 return -2;
1371
1372         demux->createTSRecorder(m_record);
1373         if (!m_record)
1374                 return -3;
1375
1376         char templ[]=TSPATH "/timeshift.XXXXXX";
1377         m_timeshift_fd = mkstemp(templ);
1378         m_timeshift_file = templ;
1379         
1380         eDebug("recording to %s", templ);
1381         
1382         if (m_timeshift_fd < 0)
1383         {
1384                 m_record = 0;
1385                 return -4;
1386         }
1387                 
1388         m_record->setTargetFD(m_timeshift_fd);
1389
1390         m_timeshift_enabled = 1;
1391         
1392         updateTimeshiftPids();
1393         m_record->start();
1394
1395         return 0;
1396 }
1397
1398 RESULT eDVBServicePlay::stopTimeshift()
1399 {
1400         if (!m_timeshift_enabled)
1401                 return -1;
1402         
1403         switchToLive();
1404         
1405         m_timeshift_enabled = 0;
1406         
1407         m_record->stop();
1408         m_record = 0;
1409         
1410         close(m_timeshift_fd);
1411         eDebug("remove timeshift file");
1412         remove(m_timeshift_file.c_str());
1413         
1414         return 0;
1415 }
1416
1417 int eDVBServicePlay::isTimeshiftActive()
1418 {
1419         return m_timeshift_enabled && m_timeshift_active;
1420 }
1421
1422 RESULT eDVBServicePlay::activateTimeshift()
1423 {
1424         if (!m_timeshift_enabled)
1425                 return -1;
1426         
1427         if (!m_timeshift_active)
1428         {
1429                 switchToTimeshift();
1430                 return 0;
1431         }
1432         
1433         return -2;
1434 }
1435
1436 PyObject *eDVBServicePlay::getCutList()
1437 {
1438         PyObject *list = PyList_New(0);
1439         
1440         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1441         {
1442                 PyObject *tuple = PyTuple_New(2);
1443                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1444                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1445                 PyList_Append(list, tuple);
1446                 Py_DECREF(tuple);
1447         }
1448         
1449         return list;
1450 }
1451
1452 void eDVBServicePlay::setCutList(PyObject *list)
1453 {
1454         if (!PyList_Check(list))
1455                 return;
1456         int size = PyList_Size(list);
1457         int i;
1458         
1459         m_cue_entries.clear();
1460         
1461         for (i=0; i<size; ++i)
1462         {
1463                 PyObject *tuple = PyList_GetItem(list, i);
1464                 if (!PyTuple_Check(tuple))
1465                 {
1466                         eDebug("non-tuple in cutlist");
1467                         continue;
1468                 }
1469                 if (PyTuple_Size(tuple) != 2)
1470                 {
1471                         eDebug("cutlist entries need to be a 2-tuple");
1472                         continue;
1473                 }
1474                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1475                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1476                 {
1477                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1478                         continue;
1479                 }
1480                 pts_t pts = PyLong_AsLongLong(ppts);
1481                 int type = PyInt_AsLong(ptype);
1482                 m_cue_entries.insert(cueEntry(pts, type));
1483                 eDebug("adding %08llx, %d", pts, type);
1484         }
1485         m_cuesheet_changed = 1;
1486         
1487         cutlistToCuesheet();
1488         m_event((iPlayableService*)this, evCuesheetChanged);
1489 }
1490
1491 void eDVBServicePlay::setCutListEnable(int enable)
1492 {
1493         m_cutlist_enabled = enable;
1494         cutlistToCuesheet();
1495 }
1496
1497 void eDVBServicePlay::updateTimeshiftPids()
1498 {
1499         if (!m_record)
1500                 return;
1501         
1502         eDVBServicePMTHandler::program program;
1503         if (m_service_handler.getProgramInfo(program))
1504                 return;
1505         else
1506         {
1507                 std::set<int> pids_to_record;
1508                 pids_to_record.insert(0); // PAT
1509                 if (program.pmtPid != -1)
1510                         pids_to_record.insert(program.pmtPid); // PMT
1511
1512                 if (program.textPid != -1)
1513                         pids_to_record.insert(program.textPid); // Videotext
1514
1515                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1516                         i(program.videoStreams.begin()); 
1517                         i != program.videoStreams.end(); ++i)
1518                         pids_to_record.insert(i->pid);
1519
1520                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1521                         i(program.audioStreams.begin()); 
1522                         i != program.audioStreams.end(); ++i)
1523                                 pids_to_record.insert(i->pid);
1524
1525                 std::set<int> new_pids, obsolete_pids;
1526                 
1527                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1528                                 m_pids_active.begin(), m_pids_active.end(),
1529                                 std::inserter(new_pids, new_pids.begin()));
1530                 
1531                 std::set_difference(
1532                                 m_pids_active.begin(), m_pids_active.end(),
1533                                 pids_to_record.begin(), pids_to_record.end(), 
1534                                 std::inserter(new_pids, new_pids.begin())
1535                                 );
1536
1537                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1538                         m_record->addPID(*i);
1539
1540                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1541                         m_record->removePID(*i);
1542         }
1543 }
1544
1545 void eDVBServicePlay::switchToLive()
1546 {
1547         if (!m_timeshift_active)
1548                 return;
1549         
1550         m_cue = 0;
1551         m_decoder = 0;
1552         m_decode_demux = 0;
1553         m_teletext_parser = 0;
1554         
1555                 /* free the timeshift service handler, we need the resources */
1556         m_service_handler_timeshift.free();
1557         m_timeshift_active = 0;
1558         
1559         m_event((iPlayableService*)this, evSeekableStatusChanged);
1560         
1561         updateDecoder();
1562 }
1563
1564 void eDVBServicePlay::switchToTimeshift()
1565 {
1566         if (m_timeshift_active)
1567                 return;
1568         
1569         m_decode_demux = 0;
1570         m_decoder = 0;
1571         m_teletext_parser = 0;
1572         
1573         m_timeshift_active = 1;
1574
1575         m_event((iPlayableService*)this, evSeekableStatusChanged);
1576         
1577         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1578         r.path = m_timeshift_file;
1579         
1580         m_cue = new eCueSheet();
1581         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1582         updateDecoder(); /* mainly to switch off PCR */
1583 }
1584
1585 void eDVBServicePlay::updateDecoder()
1586 {
1587         int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1;
1588         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1589
1590         bool defaultac3=false;
1591         std::string default_ac3;
1592
1593         if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1594                 defaultac3 = default_ac3 == "enable";
1595
1596         eDVBServicePMTHandler::program program;
1597         if (h.getProgramInfo(program))
1598                 eDebug("getting program info failed.");
1599         else
1600         {
1601                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1602                 if (!program.videoStreams.empty())
1603                 {
1604                         eDebugNoNewLine(" (");
1605                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1606                                 i(program.videoStreams.begin()); 
1607                                 i != program.videoStreams.end(); ++i)
1608                         {
1609                                 if (vpid == -1)
1610                                 {
1611                                         vpid = i->pid;
1612                                         vpidtype = i->type;
1613                                 }
1614                                 if (i != program.videoStreams.begin())
1615                                         eDebugNoNewLine(", ");
1616                                 eDebugNoNewLine("%04x", i->pid);
1617                         }
1618                         eDebugNoNewLine(")");
1619                 }
1620                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1621                 if (!program.audioStreams.empty())
1622                 {
1623                         eDebugNoNewLine(" (");
1624                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1625                                 i(program.audioStreams.begin()); 
1626                                 i != program.audioStreams.end(); ++i)
1627                         {
1628                                 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1629                                 {
1630                                         if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1631                                         {
1632                                                 apid = i->pid;
1633                                                 apidtype = i->type;
1634                                         }
1635                                 }
1636                                 if (i != program.audioStreams.begin())
1637                                         eDebugNoNewLine(", ");
1638                                 eDebugNoNewLine("%04x", i->pid);
1639                         }
1640                         eDebugNoNewLine(")");
1641                 }
1642                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1643                 pcrpid = program.pcrPid;
1644                 eDebug(", and the text pid is %04x", program.textPid);
1645                 tpid = program.textPid;
1646                 achannel = program.audioChannel;
1647         }
1648
1649         if (!m_decoder)
1650         {
1651                 h.getDecodeDemux(m_decode_demux);
1652                 if (m_decode_demux)
1653                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1654                 if (m_cue)
1655                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1656 #ifdef INTERNAL_TELETEXT
1657                 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1658 #endif
1659         }
1660
1661         if (m_decoder)
1662         {
1663                 m_decoder->setVideoPID(vpid, vpidtype);
1664                 m_current_audio_stream = 0;
1665                 m_decoder->setAudioPID(apid, apidtype);
1666                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1667                         m_decoder->setSyncPCR(pcrpid);
1668                 else
1669                         m_decoder->setSyncPCR(-1);
1670 #ifndef INTERNAL_TELETEXT
1671                 m_decoder->setTextPID(tpid);
1672 #else
1673                 if (m_teletext_parser)
1674                         m_teletext_parser->start(tpid);
1675 #endif
1676
1677                 if (!m_is_primary)
1678                         m_decoder->setTrickmode(1);
1679
1680                 m_decoder->start();
1681
1682                 m_decoder->setAudioChannel(achannel);
1683
1684 // how we can do this better?
1685 // update cache pid when the user changed the audio track or video track
1686 // TODO handling of difference audio types.. default audio types..
1687                                 
1688                 /* don't worry about non-existing services, nor pvr services */
1689                 if (m_dvb_service && !m_is_pvr)
1690                 {
1691                         if (apidtype == eDVBAudio::aMPEG)
1692                         {
1693                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1694                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1695                         }
1696                         else
1697                         {
1698                                 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1699                                 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1700                         }
1701                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1702                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1703                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1704                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1705                 }
1706         }
1707 }
1708
1709 void eDVBServicePlay::loadCuesheet()
1710 {
1711         std::string filename = m_reference.path + ".cuts";
1712         
1713         m_cue_entries.clear();
1714
1715         FILE *f = fopen(filename.c_str(), "rb");
1716
1717         if (f)
1718         {
1719                 eDebug("loading cuts..");
1720                 while (1)
1721                 {
1722                         unsigned long long where;
1723                         unsigned int what;
1724                         
1725                         if (!fread(&where, sizeof(where), 1, f))
1726                                 break;
1727                         if (!fread(&what, sizeof(what), 1, f))
1728                                 break;
1729                         
1730 #if BYTE_ORDER == LITTLE_ENDIAN
1731                         where = bswap_64(where);
1732 #endif
1733                         what = ntohl(what);
1734                         
1735                         if (what > 2)
1736                                 break;
1737                         
1738                         m_cue_entries.insert(cueEntry(where, what));
1739                 }
1740                 fclose(f);
1741                 eDebug("%d entries", m_cue_entries.size());
1742         } else
1743                 eDebug("cutfile not found!");
1744         
1745         m_cuesheet_changed = 0;
1746         cutlistToCuesheet();
1747         m_event((iPlayableService*)this, evCuesheetChanged);
1748 }
1749
1750 void eDVBServicePlay::saveCuesheet()
1751 {
1752         std::string filename = m_reference.path + ".cuts";
1753         
1754         FILE *f = fopen(filename.c_str(), "wb");
1755
1756         if (f)
1757         {
1758                 unsigned long long where;
1759                 int what;
1760
1761                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1762                 {
1763 #if BYTE_ORDER == BIG_ENDIAN
1764                         where = i->where;
1765 #else
1766                         where = bswap_64(i->where);
1767 #endif
1768                         what = htonl(i->what);
1769                         fwrite(&where, sizeof(where), 1, f);
1770                         fwrite(&what, sizeof(what), 1, f);
1771                         
1772                 }
1773                 fclose(f);
1774         }
1775         
1776         m_cuesheet_changed = 0;
1777 }
1778
1779 void eDVBServicePlay::cutlistToCuesheet()
1780 {
1781         if (!m_cue)
1782         {
1783                 eDebug("no cue sheet");
1784                 return;
1785         }       
1786         m_cue->clear();
1787         
1788         if (!m_cutlist_enabled)
1789         {
1790                 m_cue->commitSpans();
1791                 eDebug("cutlists where disabled");
1792                 return;
1793         }
1794
1795         pts_t in = 0, out = 0, length = 0;
1796         
1797         getLength(length);
1798                 
1799         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1800         
1801         while (1)
1802         {
1803                 if (i == m_cue_entries.end())
1804                         out = length;
1805                 else {
1806                         if (i->what == 0) /* in */
1807                         {
1808                                 in = i++->where;
1809                                 continue;
1810                         } else if (i->what == 1) /* out */
1811                                 out = i++->where;
1812                         else /* mark */
1813                         {
1814                                 i++;
1815                                 continue;
1816                         }
1817                 }
1818                 
1819                 if (in != out)
1820                         m_cue->addSourceSpan(in, out);
1821                 
1822                 in = length;
1823                 
1824                 if (i == m_cue_entries.end())
1825                         break;
1826         }
1827         m_cue->commitSpans();
1828 }
1829
1830 DEFINE_REF(eDVBServicePlay)
1831
1832 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");