start_time is now valid in eServiceEvent,
[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         return 0;
177 }
178
179
180
181 DEFINE_REF(eServiceFactoryDVB)
182
183 eServiceFactoryDVB::eServiceFactoryDVB()
184 {
185         ePtr<eServiceCenter> sc;
186         
187         eServiceCenter::getPrivInstance(sc);
188         if (sc)
189                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
190 }
191
192 eServiceFactoryDVB::~eServiceFactoryDVB()
193 {
194         ePtr<eServiceCenter> sc;
195         
196         eServiceCenter::getPrivInstance(sc);
197         if (sc)
198                 sc->removeServiceFactory(eServiceFactoryDVB::id);
199 }
200
201 DEFINE_REF(eDVBServiceList);
202
203 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
204 {
205 }
206
207 eDVBServiceList::~eDVBServiceList()
208 {
209 }
210
211 RESULT eDVBServiceList::startQuery()
212 {
213         ePtr<iDVBChannelList> db;
214         ePtr<eDVBResourceManager> res;
215         
216         int err;
217         if ((err = eDVBResourceManager::getInstance(res)) != 0)
218         {
219                 eDebug("no resource manager");
220                 return err;
221         }
222         if ((err = res->getChannelList(db)) != 0)
223         {
224                 eDebug("no channel list");
225                 return err;
226         }
227         
228         ePtr<eDVBChannelQuery> q;
229         
230         if (m_parent.path.size())
231         {
232                 eDVBChannelQuery::compile(q, m_parent.path);
233                 if (!q)
234                 {
235                         eDebug("compile query failed");
236                         return err;
237                 }
238         }
239         
240         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
241         {
242                 eDebug("startQuery failed");
243                 return err;
244         }
245
246         return 0;
247 }
248
249 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
250 {
251         eServiceReferenceDVB ref;
252         
253         if (!m_query)
254                 return -1;
255         
256         while (!m_query->getNextResult(ref))
257                 list.push_back(ref);
258         return 0;
259 }
260
261 RESULT eDVBServiceList::getNext(eServiceReference &ref)
262 {
263         if (!m_query)
264                 return -1;
265         
266         return m_query->getNextResult((eServiceReferenceDVB&)ref);
267 }
268
269 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
270 {
271         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
272 }
273
274 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
275 {
276         ePtr<eDVBService> service;
277         int r = lookupService(service, ref);
278         if (r)
279                 service = 0;
280                 // check resources...
281         ptr = new eDVBServicePlay(ref, service);
282         return 0;
283 }
284
285 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
286 {
287         ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
288         return 0;
289 }
290
291 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
292 {
293         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
294         if (list->startQuery())
295         {
296                 ptr = 0;
297                 return -1;
298         }
299         
300         ptr = list;
301         return 0;
302 }
303
304 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
305 {
306                 /* do we have a PVR service? */
307         if (ref.flags & eServiceReference::flagDirectory) // bouquet
308         {
309                 ptr = new eStaticServiceDVBBouquetInformation;
310                 return 0;
311         }
312         else if (ref.path.size())
313         {
314                 ptr = new eStaticServiceDVBPVRInformation(ref);
315                 return 0;
316         }
317         else
318         {
319                 ePtr<eDVBService> service;
320                 int r = lookupService(service, ref);
321                 if (r)
322                         ptr = new eStaticServiceDVBInformation;
323                 else
324                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
325                         ptr = service;
326                 return 0;
327         }
328 }
329
330 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
331 {
332         ptr = 0;
333         return -1;
334 }
335
336 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
337 {
338                         // TODO: handle the listing itself
339         // if (ref.... == -1) .. return "... bouquets ...";
340         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
341                         // TODO: cache
342         ePtr<iDVBChannelList> db;
343         ePtr<eDVBResourceManager> res;
344         
345         int err;
346         if ((err = eDVBResourceManager::getInstance(res)) != 0)
347         {
348                 eDebug("no resource manager");
349                 return err;
350         }
351         if ((err = res->getChannelList(db)) != 0)
352         {
353                 eDebug("no channel list");
354                 return err;
355         }
356         
357                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
358         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
359         {
360                 eDebug("getService failed!");
361                 return err;
362         }
363
364         return 0;
365 }
366
367 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
368         m_reference(ref), m_dvb_service(service), m_service_handler(0)
369 {
370         m_is_pvr = !ref.path.empty();
371         
372         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
373         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
374 }
375
376 eDVBServicePlay::~eDVBServicePlay()
377 {
378 }
379
380 void eDVBServicePlay::gotNewEvent()
381 {
382 #if 0
383                 // debug only
384         ePtr<eServiceEvent> m_event_now, m_event_next;
385         getEvent(m_event_now, 0);
386         getEvent(m_event_next, 1);
387
388         if (m_event_now)
389                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
390         if (m_event_next)
391                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
392 #endif
393         m_event((iPlayableService*)this, evUpdatedEventInfo);
394 }
395
396 void eDVBServicePlay::serviceEvent(int event)
397 {
398         switch (event)
399         {
400         case eDVBServicePMTHandler::eventTuned:
401         {
402                 ePtr<iDVBDemux> m_demux;
403                 if (!m_service_handler.getDemux(m_demux))
404                 {
405 //                      eventStartedEventAcquisition
406                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
407                 }
408 //                      eventNoEvent
409                 break;
410         }
411         case eDVBServicePMTHandler::eventNewProgramInfo:
412         {
413                 int vpid = -1, apid = -1, pcrpid = -1;
414                 eDVBServicePMTHandler::program program;
415                 if (m_service_handler.getProgramInfo(program))
416                         eDebug("getting program info failed.");
417                 else
418                 {
419                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
420                         if (!program.videoStreams.empty())
421                         {
422                                 eDebugNoNewLine(" (");
423                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
424                                         i(program.videoStreams.begin()); 
425                                         i != program.videoStreams.end(); ++i)
426                                 {
427                                         if (vpid == -1)
428                                                 vpid = i->pid;
429                                         if (i != program.videoStreams.begin())
430                                                 eDebugNoNewLine(", ");
431                                         eDebugNoNewLine("%04x", i->pid);
432                                 }
433                                 eDebugNoNewLine(")");
434                         }
435                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
436                         if (!program.audioStreams.empty())
437                         {
438                                 eDebugNoNewLine(" (");
439                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
440                                         i(program.audioStreams.begin()); 
441                                         i != program.audioStreams.end(); ++i)
442                                 {
443                                         if (apid == -1)
444                                                 apid = i->pid;
445                                         if (i != program.audioStreams.begin())
446                                                 eDebugNoNewLine(", ");
447                                         eDebugNoNewLine("%04x", i->pid);
448                                 }
449                                 eDebugNoNewLine(")");
450                         }
451                         eDebug(", and the pcr pid is %04x", program.pcrPid);
452                         if (program.pcrPid != 0x1fff)
453                                 pcrpid = program.pcrPid;
454                 }
455                 
456                 if (!m_decoder)
457                 {
458                         ePtr<iDVBDemux> demux;
459                         m_service_handler.getDemux(demux);
460                         if (demux)
461                                 demux->getMPEGDecoder(m_decoder);
462                 }
463
464                 if (m_decoder)
465                 {
466                         m_decoder->setVideoPID(vpid);
467                         m_decoder->setAudioPID(apid, 0);
468                         if (!m_is_pvr)
469                                 m_decoder->setSyncPCR(pcrpid);
470                         else
471                                 m_decoder->setSyncPCR(-1);
472                         m_decoder->start();
473 // how we can do this better?
474 // update cache pid when the user changed the audio track or video track
475 // TODO handling of difference audio types.. default audio types..
476                                 
477                                 /* don't worry about non-existing services, nor pvr services */
478                         if (m_dvb_service && !m_is_pvr)
479                         {
480                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
481                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
482                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
483                         }
484                 }
485                 
486                 break;
487         }
488         }
489 }
490
491 RESULT eDVBServicePlay::start()
492 {
493         int r;
494         eDebug("starting DVB service");
495         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
496         m_event(this, evStart);
497         return 0;
498 }
499
500 RESULT eDVBServicePlay::stop()
501 {
502         eDebug("stopping..");
503         return 0;
504 }
505
506 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
507 {
508         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
509         return 0;
510 }
511
512 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
513 {
514                 // not yet possible, maybe later...
515         ptr = 0;
516         return -1;
517 }
518
519 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
520 {
521         if (m_is_pvr)
522         {
523                 ptr = this;
524                 return 0;
525         }
526         
527         ptr = 0;
528         return -1;
529 }
530
531 RESULT eDVBServicePlay::getLength(pts_t &len)
532 {
533         ePtr<iDVBPVRChannel> pvr_channel;
534         
535         if (m_service_handler.getPVRChannel(pvr_channel))
536         {
537                 eDebug("getPVRChannel failed!");
538                 return -1;
539         }
540         
541         return pvr_channel->getLength(len);
542 }
543
544 RESULT eDVBServicePlay::seekTo(pts_t to)
545 {
546         return -1;
547 }
548
549 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
550 {
551         ePtr<iDVBPVRChannel> pvr_channel;
552         
553         if (m_service_handler.getPVRChannel(pvr_channel))
554                 return -1;
555         
556         return pvr_channel->getCurrentPosition(pos);
557 }
558
559 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
560 {
561         ptr = this;
562         return 0;
563 }
564
565 RESULT eDVBServicePlay::getName(std::string &name)
566 {
567         if (m_dvb_service)
568         {
569                 m_dvb_service->getName(m_reference, name);
570                 if (name.empty())
571                         name = "(...)";
572         } else
573                 name = "DVB service";
574         return 0;
575 }
576
577 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
578 {
579         return m_event_handler.getEvent(evt, nownext);
580 }
581
582 DEFINE_REF(eDVBServicePlay)
583
584 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");