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