94c31b4f1ab787dfe6b89519a7f7e3157c3f631a
[vuplus_dvbapp] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/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                                 /* TODO: deferred removing.. */
246                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
247                 {
248                         eDebug("Removing %s...", i->c_str());
249                         if (eraser)
250                                 eraser->erase(i->c_str());
251                         else
252                                 ::unlink(i->c_str());
253                 }
254                 
255                 return 0;
256         }
257 }
258
259 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
260 {
261         res.clear();
262         res.push_back(m_ref.path);
263
264 // handling for old splitted recordings (enigma 1)
265         char buf[255];
266         int slice=1;
267         while(true)
268         {
269                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
270                 struct stat s;
271                 if (stat(buf, &s) < 0)
272                         break;
273                 res.push_back(buf);
274         }       
275
276         res.push_back(m_ref.path + ".meta");
277         res.push_back(m_ref.path + ".ap");
278         res.push_back(m_ref.path + ".cuts");
279         std::string tmp = m_ref.path;
280         tmp.erase(m_ref.path.length()-3);
281         res.push_back(tmp + ".eit");
282         return 0;
283 }
284
285 DEFINE_REF(eServiceFactoryDVB)
286
287 eServiceFactoryDVB::eServiceFactoryDVB()
288 {
289         ePtr<eServiceCenter> sc;
290         
291         eServiceCenter::getPrivInstance(sc);
292         if (sc)
293                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
294 }
295
296 eServiceFactoryDVB::~eServiceFactoryDVB()
297 {
298         ePtr<eServiceCenter> sc;
299         
300         eServiceCenter::getPrivInstance(sc);
301         if (sc)
302                 sc->removeServiceFactory(eServiceFactoryDVB::id);
303 }
304
305 DEFINE_REF(eDVBServiceList);
306
307 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
308 {
309 }
310
311 eDVBServiceList::~eDVBServiceList()
312 {
313 }
314
315 RESULT eDVBServiceList::startQuery()
316 {
317         ePtr<iDVBChannelList> db;
318         ePtr<eDVBResourceManager> res;
319         
320         int err;
321         if ((err = eDVBResourceManager::getInstance(res)) != 0)
322         {
323                 eDebug("no resource manager");
324                 return err;
325         }
326         if ((err = res->getChannelList(db)) != 0)
327         {
328                 eDebug("no channel list");
329                 return err;
330         }
331         
332         ePtr<eDVBChannelQuery> q;
333         
334         if (!m_parent.path.empty())
335         {
336                 eDVBChannelQuery::compile(q, m_parent.path);
337                 if (!q)
338                 {
339                         eDebug("compile query failed");
340                         return err;
341                 }
342         }
343         
344         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
345         {
346                 eDebug("startQuery failed");
347                 return err;
348         }
349
350         return 0;
351 }
352
353 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
354 {
355         eServiceReferenceDVB ref;
356
357         if (!m_query || !list || !PyList_Check(list))
358                 return -1;
359
360         std::list<eServiceReferenceDVB> tmplist;
361
362         while (!m_query->getNextResult(ref))
363                 tmplist.push_back(ref);
364
365         if (sorted)
366                 tmplist.sort(iListableServiceCompare(this));
367
368         for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
369                 it != tmplist.end(); ++it)
370         {
371                 PyObject *refobj = New_eServiceReference(*it);
372                 PyList_Append(list, refobj);
373                 Py_DECREF(refobj);
374         }
375         return 0;
376 }
377
378 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
379 {
380         eServiceReferenceDVB ref;
381         
382         if (!m_query)
383                 return -1;
384         
385         while (!m_query->getNextResult(ref))
386                 list.push_back(ref);
387
388         if (sorted)
389                 list.sort(iListableServiceCompare(this));
390
391         return 0;
392 }
393
394 RESULT eDVBServiceList::getNext(eServiceReference &ref)
395 {
396         if (!m_query)
397                 return -1;
398         
399         return m_query->getNextResult((eServiceReferenceDVB&)ref);
400 }
401
402 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
403 {
404         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
405 }
406
407 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
408 {
409         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
410         {
411                 ePtr<iDVBChannelList> db;
412                 ePtr<eDVBResourceManager> resm;
413
414                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
415                         return -1;
416
417                 if (db->getBouquet(m_parent, m_bouquet) != 0)
418                         return -1;
419
420                 res = this;
421                 
422                 return 0;
423         }
424         res = 0;
425         return -1;
426 }
427
428 RESULT eDVBServiceList::addService(eServiceReference &ref)
429 {
430         if (!m_bouquet)
431                 return -1;
432         return m_bouquet->addService(ref);
433 }
434
435 RESULT eDVBServiceList::removeService(eServiceReference &ref)
436 {
437         if (!m_bouquet)
438                 return -1;
439         return m_bouquet->removeService(ref);
440 }
441
442 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
443 {
444         if (!m_bouquet)
445                 return -1;
446         return m_bouquet->moveService(ref, pos);
447 }
448
449 RESULT eDVBServiceList::flushChanges()
450 {
451         if (!m_bouquet)
452                 return -1;
453         return m_bouquet->flushChanges();
454 }
455
456 RESULT eDVBServiceList::setListName(const std::string &name)
457 {
458         if (!m_bouquet)
459                 return -1;
460         return m_bouquet->setListName(name);
461 }
462
463 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
464 {
465         ePtr<eDVBService> service;
466         int r = lookupService(service, ref);
467         if (r)
468                 service = 0;
469                 // check resources...
470         ptr = new eDVBServicePlay(ref, service);
471         return 0;
472 }
473
474 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
475 {
476         if (ref.path.empty())
477         {
478                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
479                 return 0;
480         } else
481         {
482                 ptr = 0;
483                 return -1;
484         }
485 }
486
487 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
488 {
489         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
490         if (list->startQuery())
491         {
492                 ptr = 0;
493                 return -1;
494         }
495         
496         ptr = list;
497         return 0;
498 }
499
500 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
501 {
502         /* is a listable service? */
503         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
504         {
505                 if ( !ref.name.empty() )  // satellites or providers list
506                         ptr = new eStaticServiceDVBInformation;
507                 else // a dvb bouquet
508                         ptr = new eStaticServiceDVBBouquetInformation;
509         }
510         else if (!ref.path.empty()) /* do we have a PVR service? */
511                 ptr = new eStaticServiceDVBPVRInformation(ref);
512         else // normal dvb service
513         {
514                 ePtr<eDVBService> service;
515                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
516                         ptr = new eStaticServiceDVBInformation;
517                 else
518                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
519                         ptr = service;
520         }
521         return 0;
522 }
523
524 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
525 {
526         if (ref.path.empty())
527         {
528                 ptr = 0;
529                 return -1;
530         } else
531         {
532                 ptr = new eDVBPVRServiceOfflineOperations(ref);
533                 return 0;
534         }
535 }
536
537 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
538 {
539                         // TODO: handle the listing itself
540         // if (ref.... == -1) .. return "... bouquets ...";
541         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
542                         // TODO: cache
543         ePtr<iDVBChannelList> db;
544         ePtr<eDVBResourceManager> res;
545         
546         int err;
547         if ((err = eDVBResourceManager::getInstance(res)) != 0)
548         {
549                 eDebug("no resource manager");
550                 return err;
551         }
552         if ((err = res->getChannelList(db)) != 0)
553         {
554                 eDebug("no channel list");
555                 return err;
556         }
557         
558                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
559         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
560         {
561                 eDebug("getService failed!");
562                 return err;
563         }
564
565         return 0;
566 }
567
568 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
569         m_reference(ref), m_dvb_service(service), m_is_paused(0)
570 {
571         m_is_pvr = !ref.path.empty();
572         
573         m_timeshift_enabled = m_timeshift_active = 0;
574         m_skipmode = 0;
575         
576         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
577         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
578         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
579
580         m_cuesheet_changed = 0;
581         m_cutlist_enabled = 1;
582 }
583
584 eDVBServicePlay::~eDVBServicePlay()
585 {
586 }
587
588 void eDVBServicePlay::gotNewEvent()
589 {
590 #if 0
591                 // debug only
592         ePtr<eServiceEvent> m_event_now, m_event_next;
593         getEvent(m_event_now, 0);
594         getEvent(m_event_next, 1);
595
596         if (m_event_now)
597                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
598         if (m_event_next)
599                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
600 #endif
601         m_event((iPlayableService*)this, evUpdatedEventInfo);
602 }
603
604 void eDVBServicePlay::serviceEvent(int event)
605 {
606         switch (event)
607         {
608         case eDVBServicePMTHandler::eventTuned:
609         {
610                 ePtr<iDVBDemux> m_demux;
611                 if (!m_service_handler.getDataDemux(m_demux))
612                 {
613                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
614                         int sid = ref.getParentServiceID().get();
615                         if (!sid)
616                                 sid = ref.getServiceID().get();
617                         if ( ref.getParentTransportStreamID().get() &&
618                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
619                                 m_event_handler.startOther(m_demux, sid);
620                         else
621                                 m_event_handler.start(m_demux, sid);
622                 }
623                 break;
624         }
625         case eDVBServicePMTHandler::eventTuneFailed:
626         {
627                 eDebug("DVB service failed to tune");
628                 m_event((iPlayableService*)this, evTuneFailed);
629                 break;
630         }
631         case eDVBServicePMTHandler::eventNewProgramInfo:
632         {
633                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
634                 if (m_timeshift_enabled)
635                         updateTimeshiftPids();
636                 if (!m_timeshift_active)
637                         updateDecoder();
638                 if (m_first_program_info && m_is_pvr)
639                 {
640                         m_first_program_info = 0;
641                         seekTo(0);
642                 }
643                 m_event((iPlayableService*)this, evUpdatedInfo);
644                 break;
645         }
646         case eDVBServicePMTHandler::eventEOF:
647                 m_event((iPlayableService*)this, evEOF);
648                 break;
649         case eDVBServicePMTHandler::eventSOF:
650                 m_event((iPlayableService*)this, evSOF);
651                 break;
652         }
653 }
654
655 void eDVBServicePlay::serviceEventTimeshift(int event)
656 {
657         switch (event)
658         {
659         case eDVBServicePMTHandler::eventNewProgramInfo:
660                 if (m_timeshift_active)
661                         updateDecoder();
662                 break;
663         case eDVBServicePMTHandler::eventSOF:
664                 m_event((iPlayableService*)this, evSOF);
665                 break;
666         case eDVBServicePMTHandler::eventEOF:
667                 switchToLive();
668                 break;
669         }
670 }
671
672 RESULT eDVBServicePlay::start()
673 {
674         int r;
675                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
676                    two (one for decoding, one for data source), as we must be prepared
677                    to start recording from the data demux. */
678         m_cue = new eCueSheet();
679
680         m_first_program_info = 1;
681         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
682         r = m_service_handler.tune(service, m_is_pvr, m_cue);
683         
684                 /* inject EIT if there is a stored one */
685         if (m_is_pvr)
686         {
687                 std::string filename = service.path;
688                 filename.erase(filename.length()-2, 2);
689                 filename+="eit";
690                 int fd = ::open( filename.c_str(), O_RDONLY );
691                 if ( fd > -1 )
692                 {
693                         __u8 buf[4096];
694                         int rd = ::read(fd, buf, 4096);
695                         ::close(fd);
696                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
697                         {
698                                 Event ev(buf);
699                                 ePtr<eServiceEvent> event = new eServiceEvent;
700                                 ePtr<eServiceEvent> empty;
701                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
702                                 m_event_handler.inject(event, 0);
703                                 m_event_handler.inject(empty, 1);
704                                 eDebug("injected");
705                         }
706                 }
707         }
708         
709         if (m_is_pvr)
710                 loadCuesheet();
711
712         m_event(this, evStart);
713         m_event((iPlayableService*)this, evSeekableStatusChanged);
714         return 0;
715 }
716
717 RESULT eDVBServicePlay::stop()
718 {
719         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
720
721         m_service_handler_timeshift.free();
722         m_service_handler.free();
723         
724         if (m_is_pvr && m_cuesheet_changed)
725                 saveCuesheet();
726         
727         return 0;
728 }
729
730 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
731 {
732         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
733         return 0;
734 }
735
736 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
737 {
738                 /* note: we check for timeshift to be enabled,
739                    not neccessary active. if you pause when timeshift
740                    is not active, you should activate it when unpausing */
741         if ((!m_is_pvr) && (!m_timeshift_enabled))
742         {
743                 ptr = 0;
744                 return -1;
745         }
746
747         ptr = this;
748         return 0;
749 }
750
751 RESULT eDVBServicePlay::setSlowMotion(int ratio)
752 {
753         if (m_decoder)
754                 return m_decoder->setSlowMotion(ratio);
755         else
756                 return -1;
757 }
758
759 RESULT eDVBServicePlay::setFastForward(int ratio)
760 {
761         int skipmode, ffratio;
762         
763         if (ratio > 8)
764         {
765                 skipmode = ratio;
766                 ffratio = 1;
767         } else if (ratio > 0)
768         {
769                 skipmode = 0;
770                 ffratio = ratio;
771         } else if (!ratio)
772         {
773                 skipmode = 0;
774                 ffratio = 0;
775         } else // if (ratio < 0)
776         {
777                 skipmode = ratio;
778                 ffratio = 1;
779         }
780
781         if (m_skipmode != skipmode)
782         {
783                 eDebug("setting cue skipmode to %d", skipmode);
784                 if (m_cue)
785                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
786         }
787         
788         m_skipmode = skipmode;
789         
790         if (!m_decoder)
791                 return -1;
792
793         return m_decoder->setFastForward(ffratio);
794 }
795     
796 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
797 {
798         if (m_is_pvr || m_timeshift_enabled)
799         {
800                 ptr = this;
801                 return 0;
802         }
803         
804         ptr = 0;
805         return -1;
806 }
807
808         /* TODO: when timeshift is enabled but not active, this doesn't work. */
809 RESULT eDVBServicePlay::getLength(pts_t &len)
810 {
811         ePtr<iDVBPVRChannel> pvr_channel;
812         
813         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
814                 return -1;
815         
816         return pvr_channel->getLength(len);
817 }
818
819 RESULT eDVBServicePlay::pause()
820 {
821         if (!m_is_paused && m_decoder)
822         {
823                 m_is_paused = 1;
824                 return m_decoder->freeze(0);
825         } else
826                 return -1;
827 }
828
829 RESULT eDVBServicePlay::unpause()
830 {
831         if (m_is_paused && m_decoder)
832         {
833                 m_is_paused = 0;
834                 return m_decoder->unfreeze();
835         } else
836                 return -1;
837 }
838
839 RESULT eDVBServicePlay::seekTo(pts_t to)
840 {
841         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
842         
843         if (!m_decode_demux)
844                 return -1;
845
846         ePtr<iDVBPVRChannel> pvr_channel;
847         
848         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
849                 return -1;
850         
851         if (!m_cue)
852                 return -1;
853         
854         m_cue->seekTo(0, to);
855         return 0;
856 }
857
858 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
859 {
860         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
861         
862         if (!m_decode_demux)
863                 return -1;
864
865         ePtr<iDVBPVRChannel> pvr_channel;
866         
867         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
868                 return -1;
869         
870         int mode = 1;
871         
872                         /* HACK until we have skip-AP api */
873         if ((to > 0) && (to < 100))
874                 mode = 2;
875         
876         to *= direction;
877         
878         if (!m_cue)
879                 return 0;
880         
881         m_cue->seekTo(mode, to);
882         return 0;
883 }
884
885 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
886 {
887         ePtr<iDVBPVRChannel> pvr_channel;
888         
889         if (!m_decode_demux)
890                 return -1;
891         
892         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
893                 return -1;
894         
895         int r = 0;
896
897                 /* if there is a decoder, use audio or video PTS */
898         if (m_decoder)
899         {
900                 r = m_decoder->getPTS(0, pos);
901                 if (r)
902                         return r;
903         }
904         
905                 /* fixup */
906         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
907 }
908
909 RESULT eDVBServicePlay::setTrickmode(int trick)
910 {
911         if (m_decoder)
912                 m_decoder->setTrickmode(trick);
913         return 0;
914 }
915
916 RESULT eDVBServicePlay::isCurrentlySeekable()
917 {
918         return m_is_pvr || m_timeshift_active;
919 }
920
921 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
922 {
923         ptr = this;
924         return 0;
925 }
926
927 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
928 {
929         ptr = this;
930         return 0;
931 }
932
933 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
934 {
935         ptr = this;
936         return 0;
937 }
938
939 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
940 {
941         ptr = this;
942         return 0;
943 }
944
945 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
946 {
947         ptr = 0;
948         if (m_timeshift_enabled || !m_is_pvr)
949         {
950                 if (!m_timeshift_enabled)
951                 {
952                                 /* we need enough diskspace */
953                         struct statfs fs;
954                         if (statfs(TSPATH "/.", &fs) < 0)
955                         {
956                                 eDebug("statfs failed!");
957                                 return -2;
958                         }
959                 
960                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
961                         {
962                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
963                                 return -3;
964                         }
965                 }
966                 ptr = this;
967                 return 0;
968         }
969         return -1;
970 }
971
972 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
973 {
974         if (m_is_pvr)
975         {
976                 ptr = this;
977                 return 0;
978         }
979         ptr = 0;
980         return -1;
981 }
982
983 RESULT eDVBServicePlay::getName(std::string &name)
984 {
985         if (m_is_pvr)
986         {
987                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
988                 return i->getName(m_reference, name);
989         }
990         if (m_dvb_service)
991         {
992                 m_dvb_service->getName(m_reference, name);
993                 if (name.empty())
994                         name = "(...)";
995         }
996         else if (!m_reference.name.empty())
997                 eStaticServiceDVBInformation().getName(m_reference, name);
998         else
999                 name = "DVB service";
1000         return 0;
1001 }
1002
1003 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1004 {
1005         return m_event_handler.getEvent(evt, nownext);
1006 }
1007
1008 int eDVBServicePlay::getInfo(int w)
1009 {
1010         eDVBServicePMTHandler::program program;
1011
1012         if (m_service_handler.getProgramInfo(program))
1013                 return -1;
1014         
1015         switch (w)
1016         {
1017         case sAspect:
1018                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1019                 {
1020                         ePtr<eServiceEvent> evt;
1021                         if (!m_event_handler.getEvent(evt, 0))
1022                         {
1023                                 ePtr<eComponentData> data;
1024                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1025                                 {
1026                                         if ( data->getStreamContent() == 1 )
1027                                         {
1028                                                 switch(data->getComponentType())
1029                                                 {
1030                                                         // SD
1031                                                         case 1: // 4:3 SD PAL
1032                                                         case 2:
1033                                                         case 3: // 16:9 SD PAL
1034                                                         case 4: // > 16:9 PAL
1035                                                         case 5: // 4:3 SD NTSC
1036                                                         case 6: 
1037                                                         case 7: // 16:9 SD NTSC
1038                                                         case 8: // > 16:9 NTSC
1039
1040                                                         // HD
1041                                                         case 9: // 4:3 HD PAL
1042                                                         case 0xA:
1043                                                         case 0xB: // 16:9 HD PAL
1044                                                         case 0xC: // > 16:9 HD PAL
1045                                                         case 0xD: // 4:3 HD NTSC
1046                                                         case 0xE:
1047                                                         case 0xF: // 16:9 HD NTSC
1048                                                         case 0x10: // > 16:9 HD PAL
1049                                                                 return data->getComponentType();
1050                                                 }
1051                                         }
1052                                 }
1053                         }
1054                 }
1055                 return -1;
1056         case sIsCrypted: return program.isCrypted;
1057         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1058         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1059         case sPCRPID: return program.pcrPid;
1060         case sPMTPID: return program.pmtPid;
1061         case sTXTPID: return program.textPid;
1062         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1063         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1064         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1065         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1066         case sProvider: if (!m_dvb_service) return -1; return -2;
1067         default:
1068                 return -1;
1069         }
1070 }
1071
1072 std::string eDVBServicePlay::getInfoString(int w)
1073 {       
1074         switch (w)
1075         {
1076         case sProvider:
1077                 if (!m_dvb_service) return "";
1078                 return m_dvb_service->m_provider_name;
1079         default:
1080                 return "";
1081         }
1082 }
1083
1084 int eDVBServicePlay::getNumberOfTracks()
1085 {
1086         eDVBServicePMTHandler::program program;
1087         if (m_service_handler.getProgramInfo(program))
1088                 return 0;
1089         return program.audioStreams.size();
1090 }
1091
1092 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1093 {
1094         int ret = selectAudioStream(i);
1095
1096         if (m_decoder->start())
1097                 return -5;
1098
1099         return ret;
1100 }
1101
1102 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1103 {
1104         eDVBServicePMTHandler::program program;
1105
1106         if (m_service_handler.getProgramInfo(program))
1107                 return -1;
1108         
1109         if (i >= program.audioStreams.size())
1110                 return -2;
1111         
1112         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1113                 info.m_description = "MPEG";
1114         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1115                 info.m_description = "AC3";
1116         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1117                 info.m_description = "DTS";
1118         else
1119                 info.m_description = "???";
1120
1121         if (program.audioStreams[i].component_tag != -1)
1122         {
1123                 ePtr<eServiceEvent> evt;
1124                 if (!m_event_handler.getEvent(evt, 0))
1125                 {
1126                         ePtr<eComponentData> data;
1127                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1128                                 info.m_language = data->getText();
1129                 }
1130         }
1131
1132         if (info.m_language.empty())
1133                 info.m_language = program.audioStreams[i].language_code;
1134         
1135         return 0;
1136 }
1137
1138 int eDVBServicePlay::selectAudioStream(int i)
1139 {
1140         eDVBServicePMTHandler::program program;
1141
1142         if (m_service_handler.getProgramInfo(program))
1143                 return -1;
1144         
1145         if ((unsigned int)i >= program.audioStreams.size())
1146                 return -2;
1147         
1148         if (!m_decoder)
1149                 return -3;
1150         
1151         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1152                 return -4;
1153
1154         if (m_dvb_service && !m_is_pvr)
1155         {
1156                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1157                 {
1158                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1159                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1160                 }       else
1161                 {
1162                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1163                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1164                 }
1165         }
1166
1167         m_current_audio_stream = i;
1168
1169         return 0;
1170 }
1171
1172 int eDVBServicePlay::getFrontendInfo(int w)
1173 {
1174         if (m_is_pvr)
1175                 return 0;
1176         eUsePtr<iDVBChannel> channel;
1177         if(m_service_handler.getChannel(channel))
1178                 return 0;
1179         ePtr<iDVBFrontend> fe;
1180         if(channel->getFrontend(fe))
1181                 return 0;
1182         return fe->readFrontendData(w);
1183 }
1184
1185 PyObject *eDVBServicePlay::getFrontendData(bool original)
1186 {
1187         PyObject *ret=0;
1188
1189         eUsePtr<iDVBChannel> channel;
1190         if(!m_service_handler.getChannel(channel))
1191         {
1192                 ePtr<iDVBFrontend> fe;
1193                 if(!channel->getFrontend(fe))
1194                 {
1195                         ret = fe->readTransponderData(original);
1196                         if (ret)
1197                         {
1198                                 ePtr<iDVBFrontendParameters> feparm;
1199                                 channel->getCurrentFrontendParameters(feparm);
1200                                 if (feparm)
1201                                 {
1202                                         eDVBFrontendParametersSatellite osat;
1203                                         if (!feparm->getDVBS(osat))
1204                                         {
1205                                                 void PutToDict(PyObject *, const char*, long);
1206                                                 void PutToDict(PyObject *, const char*, const char*);
1207                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1208                                                 const char *tmp = "UNKNOWN";
1209                                                 switch(osat.polarisation)
1210                                                 {
1211                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1212                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1213                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1214                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1215                                                         default:break;
1216                                                 }
1217                                                 PutToDict(ret, "polarization", tmp);
1218                                         }
1219                                 }
1220                         }
1221                 }
1222         }
1223         if (!ret)
1224         {
1225                 ret = Py_None;
1226                 Py_INCREF(ret);
1227         }
1228         return ret;
1229 }
1230
1231 int eDVBServicePlay::getNumberOfSubservices()
1232 {
1233         ePtr<eServiceEvent> evt;
1234         if (!m_event_handler.getEvent(evt, 0))
1235                 return evt->getNumOfLinkageServices();
1236         return 0;
1237 }
1238
1239 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1240 {
1241         ePtr<eServiceEvent> evt;
1242         if (!m_event_handler.getEvent(evt, 0))
1243         {
1244                 if (!evt->getLinkageService(sub, m_reference, n))
1245                         return 0;
1246         }
1247         sub.type=eServiceReference::idInvalid;
1248         return -1;
1249 }
1250
1251 RESULT eDVBServicePlay::startTimeshift()
1252 {
1253         ePtr<iDVBDemux> demux;
1254         
1255         eDebug("Start timeshift!");
1256         
1257         if (m_timeshift_enabled)
1258                 return -1;
1259         
1260                 /* start recording with the data demux. */
1261         if (m_service_handler.getDataDemux(demux))
1262                 return -2;
1263
1264         demux->createTSRecorder(m_record);
1265         if (!m_record)
1266                 return -3;
1267
1268         char templ[]=TSPATH "/timeshift.XXXXXX";
1269         m_timeshift_fd = mkstemp(templ);
1270         m_timeshift_file = templ;
1271         
1272         eDebug("recording to %s", templ);
1273         
1274         if (m_timeshift_fd < 0)
1275         {
1276                 m_record = 0;
1277                 return -4;
1278         }
1279                 
1280         m_record->setTargetFD(m_timeshift_fd);
1281
1282         m_timeshift_enabled = 1;
1283         
1284         updateTimeshiftPids();
1285         m_record->start();
1286
1287         return 0;
1288 }
1289
1290 RESULT eDVBServicePlay::stopTimeshift()
1291 {
1292         if (!m_timeshift_enabled)
1293                 return -1;
1294         
1295         switchToLive();
1296         
1297         m_timeshift_enabled = 0;
1298         
1299         m_record->stop();
1300         m_record = 0;
1301         
1302         close(m_timeshift_fd);
1303         eDebug("remove timeshift file");
1304         remove(m_timeshift_file.c_str());
1305         
1306         return 0;
1307 }
1308
1309 int eDVBServicePlay::isTimeshiftActive()
1310 {
1311         return m_timeshift_enabled && m_timeshift_active;
1312 }
1313
1314 RESULT eDVBServicePlay::activateTimeshift()
1315 {
1316         if (!m_timeshift_enabled)
1317                 return -1;
1318         
1319         if (!m_timeshift_active)
1320         {
1321                 switchToTimeshift();
1322                 return 0;
1323         }
1324         
1325         return -2;
1326 }
1327
1328 PyObject *eDVBServicePlay::getCutList()
1329 {
1330         PyObject *list = PyList_New(0);
1331         
1332         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1333         {
1334                 PyObject *tuple = PyTuple_New(2);
1335                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1336                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1337                 PyList_Append(list, tuple);
1338                 Py_DECREF(tuple);
1339         }
1340         
1341         return list;
1342 }
1343
1344 void eDVBServicePlay::setCutList(PyObject *list)
1345 {
1346         if (!PyList_Check(list))
1347                 return;
1348         int size = PyList_Size(list);
1349         int i;
1350         
1351         m_cue_entries.clear();
1352         
1353         for (i=0; i<size; ++i)
1354         {
1355                 PyObject *tuple = PyList_GetItem(list, i);
1356                 if (!PyTuple_Check(tuple))
1357                 {
1358                         eDebug("non-tuple in cutlist");
1359                         continue;
1360                 }
1361                 if (PyTuple_Size(tuple) != 2)
1362                 {
1363                         eDebug("cutlist entries need to be a 2-tuple");
1364                         continue;
1365                 }
1366                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1367                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1368                 {
1369                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1370                         continue;
1371                 }
1372                 pts_t pts = PyLong_AsLongLong(ppts);
1373                 int type = PyInt_AsLong(ptype);
1374                 m_cue_entries.insert(cueEntry(pts, type));
1375                 eDebug("adding %08llx, %d", pts, type);
1376         }
1377         m_cuesheet_changed = 1;
1378         
1379         cutlistToCuesheet();
1380         m_event((iPlayableService*)this, evCuesheetChanged);
1381 }
1382
1383 void eDVBServicePlay::setCutListEnable(int enable)
1384 {
1385         m_cutlist_enabled = enable;
1386         cutlistToCuesheet();
1387 }
1388
1389 void eDVBServicePlay::updateTimeshiftPids()
1390 {
1391         if (!m_record)
1392                 return;
1393         
1394         eDVBServicePMTHandler::program program;
1395         if (m_service_handler.getProgramInfo(program))
1396                 return;
1397         else
1398         {
1399                 std::set<int> pids_to_record;
1400                 pids_to_record.insert(0); // PAT
1401                 if (program.pmtPid != -1)
1402                         pids_to_record.insert(program.pmtPid); // PMT
1403
1404                 if (program.textPid != -1)
1405                         pids_to_record.insert(program.textPid); // Videotext
1406
1407                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1408                         i(program.videoStreams.begin()); 
1409                         i != program.videoStreams.end(); ++i)
1410                         pids_to_record.insert(i->pid);
1411
1412                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1413                         i(program.audioStreams.begin()); 
1414                         i != program.audioStreams.end(); ++i)
1415                                 pids_to_record.insert(i->pid);
1416
1417                 std::set<int> new_pids, obsolete_pids;
1418                 
1419                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1420                                 m_pids_active.begin(), m_pids_active.end(),
1421                                 std::inserter(new_pids, new_pids.begin()));
1422                 
1423                 std::set_difference(
1424                                 m_pids_active.begin(), m_pids_active.end(),
1425                                 pids_to_record.begin(), pids_to_record.end(), 
1426                                 std::inserter(new_pids, new_pids.begin())
1427                                 );
1428
1429                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1430                         m_record->addPID(*i);
1431
1432                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1433                         m_record->removePID(*i);
1434         }
1435 }
1436
1437 void eDVBServicePlay::switchToLive()
1438 {
1439         if (!m_timeshift_active)
1440                 return;
1441         
1442         m_decoder = 0;
1443         m_decode_demux = 0;
1444                 /* free the timeshift service handler, we need the resources */
1445         m_service_handler_timeshift.free();
1446         m_timeshift_active = 0;
1447         
1448         m_event((iPlayableService*)this, evSeekableStatusChanged);
1449         
1450         updateDecoder();
1451 }
1452
1453 void eDVBServicePlay::switchToTimeshift()
1454 {
1455         if (m_timeshift_active)
1456                 return;
1457         
1458         m_decode_demux = 0;
1459         m_decoder = 0;
1460         
1461         m_timeshift_active = 1;
1462
1463         m_event((iPlayableService*)this, evSeekableStatusChanged);
1464         
1465         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1466         r.path = m_timeshift_file;
1467         
1468         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1469         updateDecoder(); /* mainly to switch off PCR */
1470 }
1471
1472 void eDVBServicePlay::updateDecoder()
1473 {
1474         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1475         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1476
1477         eDVBServicePMTHandler::program program;
1478         if (h.getProgramInfo(program))
1479                 eDebug("getting program info failed.");
1480         else
1481         {
1482                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1483                 if (!program.videoStreams.empty())
1484                 {
1485                         eDebugNoNewLine(" (");
1486                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1487                                 i(program.videoStreams.begin()); 
1488                                 i != program.videoStreams.end(); ++i)
1489                         {
1490                                 if (vpid == -1)
1491                                         vpid = i->pid;
1492                                 if (i != program.videoStreams.begin())
1493                                         eDebugNoNewLine(", ");
1494                                 eDebugNoNewLine("%04x", i->pid);
1495                         }
1496                         eDebugNoNewLine(")");
1497                 }
1498                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1499                 if (!program.audioStreams.empty())
1500                 {
1501                         eDebugNoNewLine(" (");
1502                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1503                                 i(program.audioStreams.begin()); 
1504                                 i != program.audioStreams.end(); ++i)
1505                         {
1506                                 if (apid == -1)
1507                                 {
1508                                         apid = i->pid;
1509                                         apidtype = i->type;
1510                                 }
1511                                 if (i != program.audioStreams.begin())
1512                                         eDebugNoNewLine(", ");
1513                                 eDebugNoNewLine("%04x", i->pid);
1514                         }
1515                         eDebugNoNewLine(")");
1516                 }
1517                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1518                 pcrpid = program.pcrPid;
1519                 eDebug(", and the text pid is %04x", program.textPid);
1520                 tpid = program.textPid;
1521         }
1522
1523         if (!m_decoder)
1524         {
1525                 h.getDecodeDemux(m_decode_demux);
1526                 if (m_decode_demux)
1527                         m_decode_demux->getMPEGDecoder(m_decoder);
1528                 if (m_cue)
1529                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1530         }
1531
1532         if (m_decoder)
1533         {
1534                 m_decoder->setVideoPID(vpid);
1535                 m_current_audio_stream = 0;
1536                 m_decoder->setAudioPID(apid, apidtype);
1537                 if (!(m_is_pvr || m_timeshift_active))
1538                         m_decoder->setSyncPCR(pcrpid);
1539                 else
1540                         m_decoder->setSyncPCR(-1);
1541                 m_decoder->setTextPID(tpid);
1542                 m_decoder->start();
1543 // how we can do this better?
1544 // update cache pid when the user changed the audio track or video track
1545 // TODO handling of difference audio types.. default audio types..
1546                                 
1547                 /* don't worry about non-existing services, nor pvr services */
1548                 if (m_dvb_service && !m_is_pvr)
1549                 {
1550                         if (apidtype == eDVBAudio::aMPEG)
1551                         {
1552                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1553                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1554                         }
1555                         else
1556                         {
1557                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1558                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1559                         }
1560                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1561                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1562                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1563                 }
1564         }
1565 }
1566
1567 void eDVBServicePlay::loadCuesheet()
1568 {
1569         std::string filename = m_reference.path + ".cuts";
1570         
1571         m_cue_entries.clear();
1572
1573         FILE *f = fopen(filename.c_str(), "rb");
1574
1575         if (f)
1576         {
1577                 eDebug("loading cuts..");
1578                 while (1)
1579                 {
1580                         unsigned long long where;
1581                         unsigned int what;
1582                         
1583                         if (!fread(&where, sizeof(where), 1, f))
1584                                 break;
1585                         if (!fread(&what, sizeof(what), 1, f))
1586                                 break;
1587                         
1588 #if BYTE_ORDER == LITTLE_ENDIAN
1589                         where = bswap_64(where);
1590 #endif
1591                         what = ntohl(what);
1592                         
1593                         if (what > 2)
1594                                 break;
1595                         
1596                         m_cue_entries.insert(cueEntry(where, what));
1597                 }
1598                 fclose(f);
1599                 eDebug("%d entries", m_cue_entries.size());
1600         } else
1601                 eDebug("cutfile not found!");
1602         
1603         m_cuesheet_changed = 0;
1604         cutlistToCuesheet();
1605         m_event((iPlayableService*)this, evCuesheetChanged);
1606 }
1607
1608 void eDVBServicePlay::saveCuesheet()
1609 {
1610         std::string filename = m_reference.path + ".cuts";
1611         
1612         FILE *f = fopen(filename.c_str(), "wb");
1613
1614         if (f)
1615         {
1616                 unsigned long long where;
1617                 int what;
1618
1619                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1620                 {
1621 #if BYTE_ORDER == BIG_ENDIAN
1622                         where = i->where;
1623 #else
1624                         where = bswap_64(i->where);
1625 #endif
1626                         what = htonl(i->what);
1627                         fwrite(&where, sizeof(where), 1, f);
1628                         fwrite(&what, sizeof(what), 1, f);
1629                         
1630                 }
1631                 fclose(f);
1632         }
1633         
1634         m_cuesheet_changed = 0;
1635 }
1636
1637 void eDVBServicePlay::cutlistToCuesheet()
1638 {
1639         if (!m_cue)
1640         {
1641                 eDebug("no cue sheet");
1642                 return;
1643         }       
1644         m_cue->clear();
1645         
1646         if (!m_cutlist_enabled)
1647         {
1648                 m_cue->commitSpans();
1649                 eDebug("cutlists where disabled");
1650                 return;
1651         }
1652
1653         pts_t in = 0, out = 0, length = 0;
1654         
1655         getLength(length);
1656                 
1657         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1658         
1659         while (1)
1660         {
1661                 if (i == m_cue_entries.end())
1662                         out = length;
1663                 else {
1664                         if (i->what == 0) /* in */
1665                         {
1666                                 in = i++->where;
1667                                 continue;
1668                         } else if (i->what == 1) /* out */
1669                                 out = i++->where;
1670                         else /* mark */
1671                         {
1672                                 i++;
1673                                 continue;
1674                         }
1675                 }
1676                 
1677                 if (in != out)
1678                         m_cue->addSourceSpan(in, out);
1679                 
1680                 in = length;
1681                 
1682                 if (i == m_cue_entries.end())
1683                         break;
1684         }
1685         m_cue->commitSpans();
1686 }
1687
1688 DEFINE_REF(eDVBServicePlay)
1689
1690 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");