fix redraw-problem with NumericalTextInput in TimerEntry
[enigma2.git] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11
12 #include <lib/service/servicedvbrecord.h>
13 #include <lib/dvb/metaparser.h>
14 #include <lib/dvb/tstools.h>
15
16 class eStaticServiceDVBInformation: public iStaticServiceInformation
17 {
18         DECLARE_REF(eStaticServiceDVBInformation);
19 public:
20         RESULT getName(const eServiceReference &ref, std::string &name);
21         int getLength(const eServiceReference &ref);
22 };
23
24 DEFINE_REF(eStaticServiceDVBInformation);
25
26 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
27 {
28         if ( ref.name.length() )
29         {
30                 name = ref.name;
31                 return 0;
32         }
33         else
34                 return -1;
35 }
36
37 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
38 {
39         return -1;
40 }
41
42 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
43 {
44         DECLARE_REF(eStaticServiceDVBBouquetInformation);
45 public:
46         RESULT getName(const eServiceReference &ref, std::string &name);
47         int getLength(const eServiceReference &ref);
48 };
49
50 DEFINE_REF(eStaticServiceDVBBouquetInformation);
51
52 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
53 {
54         ePtr<iDVBChannelList> db;
55         ePtr<eDVBResourceManager> res;
56
57         int err;
58         if ((err = eDVBResourceManager::getInstance(res)) != 0)
59         {
60                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
61                 return err;
62         }
63         if ((err = res->getChannelList(db)) != 0)
64         {
65                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
66                 return err;
67         }
68
69         const eBouquet *bouquet=0;
70         if ((err = db->getBouquet(ref, bouquet)) != 0)
71         {
72                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
73                 return -1;
74         }
75
76         if ( bouquet && bouquet->m_bouquet_name.length() )
77         {
78                 name = "[Bouquet] " + bouquet->m_bouquet_name;
79                 return 0;
80         }
81         else
82                 return -1;
83 }
84
85 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
86 {
87         return -1;
88 }
89
90 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
91 {
92         DECLARE_REF(eStaticServiceDVBPVRInformation);
93         eServiceReference m_ref;
94         eDVBMetaParser m_parser;
95 public:
96         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
97         RESULT getName(const eServiceReference &ref, std::string &name);
98         int getLength(const eServiceReference &ref);
99 };
100
101 DEFINE_REF(eStaticServiceDVBPVRInformation);
102
103 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
104 {
105         m_ref = ref;
106         m_parser.parseFile(ref.path);
107 }
108
109 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
110 {
111         ASSERT(ref == m_ref);
112         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
113         return 0;
114 }
115
116 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
117 {
118         ASSERT(ref == m_ref);
119         
120         eDVBTSTools tstools;
121         
122         if (tstools.openFile(ref.path.c_str()))
123                 return 0;
124
125         pts_t len;
126         if (tstools.calcLen(len))
127                 return 0;
128
129         return len / 90000;
130 }
131
132
133
134 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
135 {
136         DECLARE_REF(eDVBPVRServiceOfflineOperations);
137         eServiceReferenceDVB m_ref;
138 public:
139         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
140         
141         RESULT deleteFromDisk(int simulate);
142         RESULT getListOfFilenames(std::list<std::string> &);
143 };
144
145 DEFINE_REF(eDVBPVRServiceOfflineOperations);
146
147 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
148 {
149 }
150
151 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
152 {
153         if (simulate)
154                 return 0;
155         else
156         {
157                 std::list<std::string> res;
158                 if (getListOfFilenames(res))
159                         return -1;
160                 
161                                 /* TODO: deferred removing.. */
162                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
163                 {
164                         eDebug("Removing %s...", i->c_str());
165                         ::unlink(i->c_str());
166                 }
167                 
168                 return 0;
169         }
170 }
171
172 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
173 {
174         res.clear();
175         res.push_back(m_ref.path);
176         res.push_back(m_ref.path + ".meta");
177         return 0;
178 }
179
180 DEFINE_REF(eServiceFactoryDVB)
181
182 eServiceFactoryDVB::eServiceFactoryDVB()
183 {
184         ePtr<eServiceCenter> sc;
185         
186         eServiceCenter::getPrivInstance(sc);
187         if (sc)
188                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
189 }
190
191 eServiceFactoryDVB::~eServiceFactoryDVB()
192 {
193         ePtr<eServiceCenter> sc;
194         
195         eServiceCenter::getPrivInstance(sc);
196         if (sc)
197                 sc->removeServiceFactory(eServiceFactoryDVB::id);
198 }
199
200 DEFINE_REF(eDVBServiceList);
201
202 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
203 {
204 }
205
206 eDVBServiceList::~eDVBServiceList()
207 {
208 }
209
210 RESULT eDVBServiceList::startQuery()
211 {
212         ePtr<iDVBChannelList> db;
213         ePtr<eDVBResourceManager> res;
214         
215         int err;
216         if ((err = eDVBResourceManager::getInstance(res)) != 0)
217         {
218                 eDebug("no resource manager");
219                 return err;
220         }
221         if ((err = res->getChannelList(db)) != 0)
222         {
223                 eDebug("no channel list");
224                 return err;
225         }
226         
227         ePtr<eDVBChannelQuery> q;
228         
229         if (!m_parent.path.empty())
230         {
231                 eDVBChannelQuery::compile(q, m_parent.path);
232                 if (!q)
233                 {
234                         eDebug("compile query failed");
235                         return err;
236                 }
237         }
238         
239         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
240         {
241                 eDebug("startQuery failed");
242                 return err;
243         }
244
245         return 0;
246 }
247
248 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
249 {
250         eServiceReferenceDVB ref;
251         
252         if (!m_query)
253                 return -1;
254         
255         while (!m_query->getNextResult(ref))
256                 list.push_back(ref);
257         return 0;
258 }
259
260 RESULT eDVBServiceList::getNext(eServiceReference &ref)
261 {
262         if (!m_query)
263                 return -1;
264         
265         return m_query->getNextResult((eServiceReferenceDVB&)ref);
266 }
267
268 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
269 {
270         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
271 }
272
273 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
274 {
275         ePtr<eDVBService> service;
276         int r = lookupService(service, ref);
277         if (r)
278                 service = 0;
279                 // check resources...
280         ptr = new eDVBServicePlay(ref, service);
281         return 0;
282 }
283
284 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
285 {
286         if (ref.path.empty())
287         {
288                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
289                 return 0;
290         } else
291         {
292                 ptr = 0;
293                 return -1;
294         }
295 }
296
297 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
298 {
299         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
300         if (list->startQuery())
301         {
302                 ptr = 0;
303                 return -1;
304         }
305         
306         ptr = list;
307         return 0;
308 }
309
310 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
311 {
312                 /* do we have a PVR service? */
313         if (ref.flags & eServiceReference::flagDirectory) // bouquet
314         {
315                 ptr = new eStaticServiceDVBBouquetInformation;
316                 return 0;
317         }
318         else if (!ref.path.empty())
319         {
320                 ptr = new eStaticServiceDVBPVRInformation(ref);
321                 return 0;
322         }
323         else
324         {
325                 ePtr<eDVBService> service;
326                 int r = lookupService(service, ref);
327                 if (r)
328                         ptr = new eStaticServiceDVBInformation;
329                 else
330                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
331                         ptr = service;
332                 return 0;
333         }
334 }
335
336 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
337 {
338         if (ref.path.empty())
339         {
340                 ptr = 0;
341                 return -1;
342         } else
343         {
344                 ptr = new eDVBPVRServiceOfflineOperations(ref);
345                 return 0;
346         }
347 }
348
349 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
350 {
351                         // TODO: handle the listing itself
352         // if (ref.... == -1) .. return "... bouquets ...";
353         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
354                         // TODO: cache
355         ePtr<iDVBChannelList> db;
356         ePtr<eDVBResourceManager> res;
357         
358         int err;
359         if ((err = eDVBResourceManager::getInstance(res)) != 0)
360         {
361                 eDebug("no resource manager");
362                 return err;
363         }
364         if ((err = res->getChannelList(db)) != 0)
365         {
366                 eDebug("no channel list");
367                 return err;
368         }
369         
370                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
371         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
372         {
373                 eDebug("getService failed!");
374                 return err;
375         }
376
377         return 0;
378 }
379
380 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
381         m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
382 {
383         m_is_pvr = !ref.path.empty();
384         
385         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
386         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
387 }
388
389 eDVBServicePlay::~eDVBServicePlay()
390 {
391 }
392
393 void eDVBServicePlay::gotNewEvent()
394 {
395 #if 0
396                 // debug only
397         ePtr<eServiceEvent> m_event_now, m_event_next;
398         getEvent(m_event_now, 0);
399         getEvent(m_event_next, 1);
400
401         if (m_event_now)
402                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
403         if (m_event_next)
404                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
405 #endif
406         m_event((iPlayableService*)this, evUpdatedEventInfo);
407 }
408
409 void eDVBServicePlay::serviceEvent(int event)
410 {
411         switch (event)
412         {
413         case eDVBServicePMTHandler::eventTuned:
414         {
415                 ePtr<iDVBDemux> m_demux;
416                 if (!m_service_handler.getDemux(m_demux))
417                 {
418 //                      eventStartedEventAcquisition
419                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
420                 }
421 //                      eventNoEvent
422                 break;
423         }
424         case eDVBServicePMTHandler::eventTuneFailed:
425         {
426                 eDebug("DVB service failed to tune");
427                 m_event((iPlayableService*)this, evTuneFailed);
428                 break;
429         }
430         case eDVBServicePMTHandler::eventNewProgramInfo:
431         {
432                 int vpid = -1, apid = -1, pcrpid = -1;
433                 eDVBServicePMTHandler::program program;
434                 if (m_service_handler.getProgramInfo(program))
435                         eDebug("getting program info failed.");
436                 else
437                 {
438                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
439                         if (!program.videoStreams.empty())
440                         {
441                                 eDebugNoNewLine(" (");
442                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
443                                         i(program.videoStreams.begin()); 
444                                         i != program.videoStreams.end(); ++i)
445                                 {
446                                         if (vpid == -1)
447                                                 vpid = i->pid;
448                                         if (i != program.videoStreams.begin())
449                                                 eDebugNoNewLine(", ");
450                                         eDebugNoNewLine("%04x", i->pid);
451                                 }
452                                 eDebugNoNewLine(")");
453                         }
454                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
455                         if (!program.audioStreams.empty())
456                         {
457                                 eDebugNoNewLine(" (");
458                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
459                                         i(program.audioStreams.begin()); 
460                                         i != program.audioStreams.end(); ++i)
461                                 {
462                                         if (apid == -1)
463                                                 apid = i->pid;
464                                         if (i != program.audioStreams.begin())
465                                                 eDebugNoNewLine(", ");
466                                         eDebugNoNewLine("%04x", i->pid);
467                                 }
468                                 eDebugNoNewLine(")");
469                         }
470                         eDebug(", and the pcr pid is %04x", program.pcrPid);
471                         if (program.pcrPid != 0x1fff)
472                                 pcrpid = program.pcrPid;
473                 }
474                 
475                 if (!m_decoder)
476                 {
477                         ePtr<iDVBDemux> demux;
478                         m_service_handler.getDemux(demux);
479                         if (demux)
480                                 demux->getMPEGDecoder(m_decoder);
481                 }
482
483                 if (m_decoder)
484                 {
485                         m_decoder->setVideoPID(vpid);
486                         m_decoder->setAudioPID(apid, 0);
487                         if (!m_is_pvr)
488                                 m_decoder->setSyncPCR(pcrpid);
489                         else
490                                 m_decoder->setSyncPCR(-1);
491                         m_decoder->start();
492 // how we can do this better?
493 // update cache pid when the user changed the audio track or video track
494 // TODO handling of difference audio types.. default audio types..
495                                 
496                                 /* don't worry about non-existing services, nor pvr services */
497                         if (m_dvb_service && !m_is_pvr)
498                         {
499                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
500                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
501                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
502                         }
503                 }
504                 
505                 break;
506         }
507         }
508 }
509
510 RESULT eDVBServicePlay::start()
511 {
512         int r;
513         eDebug("starting DVB service");
514         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
515         eDebug("tune result: %d", r);
516         m_event(this, evStart);
517         return 0;
518 }
519
520 RESULT eDVBServicePlay::stop()
521 {
522         eDebug("stopping..");
523         return 0;
524 }
525
526 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
527 {
528         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
529         return 0;
530 }
531
532 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
533 {
534         if (m_is_pvr)
535         {
536                 ptr = this;
537                 return 0;
538         }
539
540         ptr = 0;
541         return -1;
542 }
543
544 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
545 {
546         if (m_is_pvr)
547         {
548                 ptr = this;
549                 return 0;
550         }
551         
552         ptr = 0;
553         return -1;
554 }
555
556 RESULT eDVBServicePlay::getLength(pts_t &len)
557 {
558         ePtr<iDVBPVRChannel> pvr_channel;
559         
560         if (m_service_handler.getPVRChannel(pvr_channel))
561         {
562                 eDebug("getPVRChannel failed!");
563                 return -1;
564         }
565         
566         return pvr_channel->getLength(len);
567 }
568
569 RESULT eDVBServicePlay::pause()
570 {
571         if (!m_is_paused && m_decoder)
572         {
573                 m_is_paused = 1;
574                 return m_decoder->freeze(0);
575         } else
576                 return -1;
577 }
578
579 RESULT eDVBServicePlay::unpause()
580 {
581         if (m_is_paused && m_decoder)
582         {
583                 m_is_paused = 0;
584                 return m_decoder->unfreeze();
585         } else
586                 return -1;
587 }
588
589 RESULT eDVBServicePlay::seekTo(pts_t to)
590 {
591         return -1;
592 }
593
594 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
595 {
596         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
597
598         ePtr<iDVBPVRChannel> pvr_channel;
599         
600         if (m_service_handler.getPVRChannel(pvr_channel))
601                 return -1;
602         
603         return pvr_channel->seekToPosition(SEEK_CUR, to);
604 }
605
606 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
607 {
608         ePtr<iDVBPVRChannel> pvr_channel;
609         
610         if (m_service_handler.getPVRChannel(pvr_channel))
611                 return -1;
612         
613         return pvr_channel->getCurrentPosition(pos);
614 }
615
616 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
617 {
618         ptr = this;
619         return 0;
620 }
621
622 RESULT eDVBServicePlay::getName(std::string &name)
623 {
624         if (m_dvb_service)
625         {
626                 m_dvb_service->getName(m_reference, name);
627                 if (name.empty())
628                         name = "(...)";
629         } else
630                 name = "DVB service";
631         return 0;
632 }
633
634 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
635 {
636         return m_event_handler.getEvent(evt, nownext);
637 }
638
639 DEFINE_REF(eDVBServicePlay)
640
641 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");