- record PAT and PMT
[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 eStaticServiceDVBPVRInformation: public iStaticServiceInformation
17 {
18         DECLARE_REF(eStaticServiceDVBPVRInformation);
19         eServiceReference m_ref;
20         eDVBMetaParser m_parser;
21 public:
22         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
23         RESULT getName(const eServiceReference &ref, std::string &name);
24         int getLength(const eServiceReference &ref);
25 };
26
27 DEFINE_REF(eStaticServiceDVBPVRInformation);
28
29 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
30 {
31         m_ref = ref;
32         m_parser.parseFile(ref.path);
33 }
34
35 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
36 {
37         ASSERT(ref == m_ref);
38         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
39         return 0;
40 }
41
42 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
43 {
44         ASSERT(ref == m_ref);
45         
46         eDVBTSTools tstools;
47         
48         if (tstools.openFile(ref.path.c_str()))
49                 return 0;
50
51         pts_t len;
52         if (tstools.calcLen(len))
53                 return 0;
54
55         return len / 90000;
56 }
57
58
59
60 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
61 {
62         DECLARE_REF(eDVBPVRServiceOfflineOperations);
63         eServiceReferenceDVB m_ref;
64 public:
65         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
66         
67         RESULT deleteFromDisk(int simulate);
68         RESULT getListOfFilenames(std::list<std::string> &);
69 };
70
71 DEFINE_REF(eDVBPVRServiceOfflineOperations);
72
73 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
74 {
75 }
76
77 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
78 {
79         if (simulate)
80                 return 0;
81         else
82         {
83                 std::list<std::string> res;
84                 if (getListOfFilenames(res))
85                         return -1;
86                 
87                                 /* TODO: deferred removing.. */
88                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
89                 {
90                         eDebug("Removing %s...", i->c_str());
91                         ::unlink(i->c_str());
92                 }
93                 
94                 return 0;
95         }
96 }
97
98 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
99 {
100         res.clear();
101         res.push_back(m_ref.path);
102         return 0;
103 }
104
105
106
107 DEFINE_REF(eServiceFactoryDVB)
108
109 eServiceFactoryDVB::eServiceFactoryDVB()
110 {
111         ePtr<eServiceCenter> sc;
112         
113         eServiceCenter::getPrivInstance(sc);
114         if (sc)
115                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
116 }
117
118 eServiceFactoryDVB::~eServiceFactoryDVB()
119 {
120         ePtr<eServiceCenter> sc;
121         
122         eServiceCenter::getPrivInstance(sc);
123         if (sc)
124                 sc->removeServiceFactory(eServiceFactoryDVB::id);
125 }
126
127 DEFINE_REF(eDVBServiceList);
128
129 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
130 {
131 }
132
133 eDVBServiceList::~eDVBServiceList()
134 {
135 }
136
137 RESULT eDVBServiceList::startQuery()
138 {
139         ePtr<iDVBChannelList> db;
140         ePtr<eDVBResourceManager> res;
141         
142         int err;
143         if ((err = eDVBResourceManager::getInstance(res)) != 0)
144         {
145                 eDebug("no resource manager");
146                 return err;
147         }
148         if ((err = res->getChannelList(db)) != 0)
149         {
150                 eDebug("no channel list");
151                 return err;
152         }
153         
154         ePtr<eDVBChannelQuery> q;
155         
156         if (m_parent.path.size())
157         {
158                 eDVBChannelQuery::compile(q, m_parent.path);
159                 if (!q)
160                 {
161                         eDebug("compile query failed");
162                         return err;
163                 }
164         }
165         
166         if ((err = db->startQuery(m_query, q)) != 0)
167         {
168                 eDebug("startQuery failed");
169                 return err;
170         }
171
172         return 0;
173 }
174
175 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
176 {
177         eServiceReferenceDVB ref;
178         
179         if (!m_query)
180                 return -1;
181         
182         while (!m_query->getNextResult(ref))
183                 list.push_back(ref);
184         return 0;
185 }
186
187 RESULT eDVBServiceList::getNext(eServiceReference &ref)
188 {
189         if (!m_query)
190                 return -1;
191         
192         return m_query->getNextResult((eServiceReferenceDVB&)ref);
193 }
194
195 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
196 {
197         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
198 }
199
200 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
201 {
202         ePtr<eDVBService> service;
203         int r = lookupService(service, ref);
204         if (r)
205                 service = 0;
206                 // check resources...
207         ptr = new eDVBServicePlay(ref, service);
208         return 0;
209 }
210
211 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
212 {
213         ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
214         return 0;
215 }
216
217 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
218 {
219         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
220         if (list->startQuery())
221         {
222                 ptr = 0;
223                 return -1;
224         }
225         
226         ptr = list;
227         return 0;
228 }
229
230 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
231 {
232                 /* do we have a PVR service? */
233         if (ref.path.size())
234         {
235                 ptr = new eStaticServiceDVBPVRInformation(ref);
236                 return 0;
237         } else
238         {
239                 ePtr<eDVBService> service;
240                 int r = lookupService(service, ref);
241                 if (r)
242                         return r;
243                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
244                 ptr = service;
245                 return 0;
246         }
247 }
248
249 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
250 {
251         ptr = 0;
252         return -1;
253 }
254
255 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
256 {
257                         // TODO: handle the listing itself
258         // if (ref.... == -1) .. return "... bouquets ...";
259         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
260                         // TODO: cache
261         ePtr<iDVBChannelList> db;
262         ePtr<eDVBResourceManager> res;
263         
264         int err;
265         if ((err = eDVBResourceManager::getInstance(res)) != 0)
266         {
267                 eDebug("no resource manager");
268                 return err;
269         }
270         if ((err = res->getChannelList(db)) != 0)
271         {
272                 eDebug("no channel list");
273                 return err;
274         }
275         
276                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
277         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
278         {
279                 eDebug("getService failed!");
280                 return err;
281         }
282
283         return 0;
284 }
285
286 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
287         m_reference(ref), m_dvb_service(service), m_service_handler(0)
288 {
289         m_is_pvr = !ref.path.empty();
290         
291         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
292         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
293         eDebug("DVB start (play)");
294 }
295
296 eDVBServicePlay::~eDVBServicePlay()
297 {
298         eDebug("DVB stop (play)");
299 }
300
301 void eDVBServicePlay::gotNewEvent()
302 {
303 #if 0
304                 // debug only
305         ePtr<eServiceEvent> m_event_now, m_event_next;
306         getEvent(m_event_now, 0);
307         getEvent(m_event_next, 1);
308
309         if (m_event_now)
310                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
311         if (m_event_next)
312                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
313 #endif
314         m_event((iPlayableService*)this, evUpdatedEventInfo);
315 }
316
317 void eDVBServicePlay::serviceEvent(int event)
318 {
319         eDebug("service event %d", event);
320         switch (event)
321         {
322         case eDVBServicePMTHandler::eventTuned:
323         {
324                 ePtr<iDVBDemux> m_demux;
325                 if (!m_service_handler.getDemux(m_demux))
326                 {
327 //                      eventStartedEventAcquisition
328                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
329                 } else
330                         eDebug("no event data available :( ");
331 //                      eventNoEvent
332                 break;
333         }
334         case eDVBServicePMTHandler::eventNewProgramInfo:
335         {
336                 int vpid = -1, apid = -1, pcrpid = -1;
337                 eDVBServicePMTHandler::program program;
338                 if (m_service_handler.getProgramInfo(program))
339                         eDebug("getting program info failed.");
340                 else
341                 {
342                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
343                         if (!program.videoStreams.empty())
344                         {
345                                 eDebugNoNewLine(" (");
346                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
347                                         i(program.videoStreams.begin()); 
348                                         i != program.videoStreams.end(); ++i)
349                                 {
350                                         if (vpid == -1)
351                                                 vpid = i->pid;
352                                         if (i != program.videoStreams.begin())
353                                                 eDebugNoNewLine(", ");
354                                         eDebugNoNewLine("%04x", i->pid);
355                                 }
356                                 eDebugNoNewLine(")");
357                         }
358                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
359                         if (!program.audioStreams.empty())
360                         {
361                                 eDebugNoNewLine(" (");
362                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
363                                         i(program.audioStreams.begin()); 
364                                         i != program.audioStreams.end(); ++i)
365                                 {
366                                         if (apid == -1)
367                                                 apid = i->pid;
368                                         if (i != program.audioStreams.begin())
369                                                 eDebugNoNewLine(", ");
370                                         eDebugNoNewLine("%04x", i->pid);
371                                 }
372                                 eDebugNoNewLine(")");
373                         }
374                         eDebug(", and the pcr pid is %04x", program.pcrPid);
375                         if (program.pcrPid != 0x1fff)
376                                 pcrpid = program.pcrPid;
377                 }
378                 
379                 if (!m_decoder)
380                 {
381                         ePtr<iDVBDemux> demux;
382                         m_service_handler.getDemux(demux);
383                         if (demux)
384                                 demux->getMPEGDecoder(m_decoder);
385                 }
386
387                 if (m_decoder)
388                 {
389                         m_decoder->setVideoPID(vpid);
390                         m_decoder->setAudioPID(apid, 0);
391                         if (!m_is_pvr)
392                                 m_decoder->setSyncPCR(pcrpid);
393                         else
394                                 m_decoder->setSyncPCR(-1);
395                         m_decoder->start();
396 // how we can do this better?
397 // update cache pid when the user changed the audio track or video track
398 // TODO handling of difference audio types.. default audio types..
399                                 
400                                 /* don't worry about non-existing services, nor pvr services */
401                         if (m_dvb_service && !m_is_pvr)
402                         {
403                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
404                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
405                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
406                         }
407                 }
408                 
409                 break;
410         }
411         }
412 }
413
414 RESULT eDVBServicePlay::start()
415 {
416         int r;
417         eDebug("starting DVB service");
418         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
419         m_event(this, evStart);
420         return 0;
421 }
422
423 RESULT eDVBServicePlay::stop()
424 {
425         eDebug("stopping..");
426         return 0;
427 }
428
429 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
430 {
431         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
432         return 0;
433 }
434
435 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
436 {
437                 // not yet possible, maybe later...
438         ptr = 0;
439         return -1;
440 }
441
442 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
443 {
444         if (m_is_pvr)
445         {
446                 ptr = this;
447                 return 0;
448         }
449         
450         ptr = 0;
451         return -1;
452 }
453
454 RESULT eDVBServicePlay::getLength(pts_t &len)
455 {
456         ePtr<iDVBPVRChannel> pvr_channel;
457         
458         if (m_service_handler.getPVRChannel(pvr_channel))
459         {
460                 eDebug("getPVRChannel failed!");
461                 return -1;
462         }
463         
464         return pvr_channel->getLength(len);
465 }
466
467 RESULT eDVBServicePlay::seekTo(pts_t to)
468 {
469         return -1;
470 }
471
472 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
473 {
474         ePtr<iDVBPVRChannel> pvr_channel;
475         
476         if (m_service_handler.getPVRChannel(pvr_channel))
477                 return -1;
478         
479         return pvr_channel->getCurrentPosition(pos);
480 }
481
482 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
483 {
484         ptr = this;
485         return 0;
486 }
487
488 RESULT eDVBServicePlay::getName(std::string &name)
489 {
490         if (m_dvb_service)
491         {
492                 m_dvb_service->getName(m_reference, name);
493                 if (name.empty())
494                         name = "(...)";
495         } else
496                 name = "DVB service";
497         return 0;
498 }
499
500 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
501 {
502         return m_event_handler.getEvent(evt, nownext);
503 }
504
505 DEFINE_REF(eDVBServicePlay)
506
507 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");