51061c37d9902d592e74263a435db3836be1778b
[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         eDebug("DVB start (play)");
375 }
376
377 eDVBServicePlay::~eDVBServicePlay()
378 {
379         eDebug("DVB stop (play)");
380 }
381
382 void eDVBServicePlay::gotNewEvent()
383 {
384 #if 0
385                 // debug only
386         ePtr<eServiceEvent> m_event_now, m_event_next;
387         getEvent(m_event_now, 0);
388         getEvent(m_event_next, 1);
389
390         if (m_event_now)
391                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
392         if (m_event_next)
393                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
394 #endif
395         m_event((iPlayableService*)this, evUpdatedEventInfo);
396 }
397
398 void eDVBServicePlay::serviceEvent(int event)
399 {
400         eDebug("service event %d", event);
401         switch (event)
402         {
403         case eDVBServicePMTHandler::eventTuned:
404         {
405                 ePtr<iDVBDemux> m_demux;
406                 if (!m_service_handler.getDemux(m_demux))
407                 {
408 //                      eventStartedEventAcquisition
409                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
410                 } else
411                         eDebug("no event data available :( ");
412 //                      eventNoEvent
413                 break;
414         }
415         case eDVBServicePMTHandler::eventNewProgramInfo:
416         {
417                 int vpid = -1, apid = -1, pcrpid = -1;
418                 eDVBServicePMTHandler::program program;
419                 if (m_service_handler.getProgramInfo(program))
420                         eDebug("getting program info failed.");
421                 else
422                 {
423                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
424                         if (!program.videoStreams.empty())
425                         {
426                                 eDebugNoNewLine(" (");
427                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
428                                         i(program.videoStreams.begin()); 
429                                         i != program.videoStreams.end(); ++i)
430                                 {
431                                         if (vpid == -1)
432                                                 vpid = i->pid;
433                                         if (i != program.videoStreams.begin())
434                                                 eDebugNoNewLine(", ");
435                                         eDebugNoNewLine("%04x", i->pid);
436                                 }
437                                 eDebugNoNewLine(")");
438                         }
439                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
440                         if (!program.audioStreams.empty())
441                         {
442                                 eDebugNoNewLine(" (");
443                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
444                                         i(program.audioStreams.begin()); 
445                                         i != program.audioStreams.end(); ++i)
446                                 {
447                                         if (apid == -1)
448                                                 apid = i->pid;
449                                         if (i != program.audioStreams.begin())
450                                                 eDebugNoNewLine(", ");
451                                         eDebugNoNewLine("%04x", i->pid);
452                                 }
453                                 eDebugNoNewLine(")");
454                         }
455                         eDebug(", and the pcr pid is %04x", program.pcrPid);
456                         if (program.pcrPid != 0x1fff)
457                                 pcrpid = program.pcrPid;
458                 }
459                 
460                 if (!m_decoder)
461                 {
462                         ePtr<iDVBDemux> demux;
463                         m_service_handler.getDemux(demux);
464                         if (demux)
465                                 demux->getMPEGDecoder(m_decoder);
466                 }
467
468                 if (m_decoder)
469                 {
470                         m_decoder->setVideoPID(vpid);
471                         m_decoder->setAudioPID(apid, 0);
472                         if (!m_is_pvr)
473                                 m_decoder->setSyncPCR(pcrpid);
474                         else
475                                 m_decoder->setSyncPCR(-1);
476                         m_decoder->start();
477 // how we can do this better?
478 // update cache pid when the user changed the audio track or video track
479 // TODO handling of difference audio types.. default audio types..
480                                 
481                                 /* don't worry about non-existing services, nor pvr services */
482                         if (m_dvb_service && !m_is_pvr)
483                         {
484                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
485                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
486                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
487                         }
488                 }
489                 
490                 break;
491         }
492         }
493 }
494
495 RESULT eDVBServicePlay::start()
496 {
497         int r;
498         eDebug("starting DVB service");
499         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
500         m_event(this, evStart);
501         return 0;
502 }
503
504 RESULT eDVBServicePlay::stop()
505 {
506         eDebug("stopping..");
507         return 0;
508 }
509
510 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
511 {
512         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
513         return 0;
514 }
515
516 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
517 {
518                 // not yet possible, maybe later...
519         ptr = 0;
520         return -1;
521 }
522
523 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
524 {
525         if (m_is_pvr)
526         {
527                 ptr = this;
528                 return 0;
529         }
530         
531         ptr = 0;
532         return -1;
533 }
534
535 RESULT eDVBServicePlay::getLength(pts_t &len)
536 {
537         ePtr<iDVBPVRChannel> pvr_channel;
538         
539         if (m_service_handler.getPVRChannel(pvr_channel))
540         {
541                 eDebug("getPVRChannel failed!");
542                 return -1;
543         }
544         
545         return pvr_channel->getLength(len);
546 }
547
548 RESULT eDVBServicePlay::seekTo(pts_t to)
549 {
550         return -1;
551 }
552
553 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
554 {
555         ePtr<iDVBPVRChannel> pvr_channel;
556         
557         if (m_service_handler.getPVRChannel(pvr_channel))
558                 return -1;
559         
560         return pvr_channel->getCurrentPosition(pos);
561 }
562
563 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
564 {
565         ptr = this;
566         return 0;
567 }
568
569 RESULT eDVBServicePlay::getName(std::string &name)
570 {
571         if (m_dvb_service)
572         {
573                 m_dvb_service->getName(m_reference, name);
574                 if (name.empty())
575                         name = "(...)";
576         } else
577                 name = "DVB service";
578         return 0;
579 }
580
581 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
582 {
583         return m_event_handler.getEvent(evt, nownext);
584 }
585
586 DEFINE_REF(eDVBServicePlay)
587
588 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");