- add getLength() call to iStaticServiceInformation
[openblackhole/openblackhole-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 }
40
41 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
42 {
43         ASSERT(ref == m_ref);
44         
45         eDVBTSTools tstools;
46         
47         if (tstools.openFile(ref.path.c_str()))
48                 return 0;
49
50         pts_t len;
51         if (tstools.calcLen(len))
52                 return 0;
53
54         return len / 90000;
55 }
56
57 DEFINE_REF(eServiceFactoryDVB)
58
59 eServiceFactoryDVB::eServiceFactoryDVB()
60 {
61         ePtr<eServiceCenter> sc;
62         
63         eServiceCenter::getInstance(sc);
64         if (sc)
65                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
66 }
67
68 eServiceFactoryDVB::~eServiceFactoryDVB()
69 {
70         ePtr<eServiceCenter> sc;
71         
72         eServiceCenter::getInstance(sc);
73         if (sc)
74                 sc->removeServiceFactory(eServiceFactoryDVB::id);
75 }
76
77 DEFINE_REF(eDVBServiceList);
78
79 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
80 {
81 }
82
83 eDVBServiceList::~eDVBServiceList()
84 {
85 }
86
87 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
88 {
89         ePtr<iDVBChannelList> db;
90         ePtr<eDVBResourceManager> res;
91         
92         int err;
93         if ((err = eDVBResourceManager::getInstance(res)) != 0)
94         {
95                 eDebug("no resource manager");
96                 return err;
97         }
98         if ((err = res->getChannelList(db)) != 0)
99         {
100                 eDebug("no channel list");
101                 return err;
102         }
103         
104         ePtr<iDVBChannelListQuery> query;
105         
106         ePtr<eDVBChannelQuery> q;
107         
108         if (m_parent.path.size())
109                 eDVBChannelQuery::compile(q, m_parent.path);
110         
111         if ((err = db->startQuery(query, q)) != 0)
112         {
113                 eDebug("startQuery failed");
114                 return err;
115         }
116         
117         eServiceReferenceDVB ref;
118         
119         while (!query->getNextResult(ref))
120                 list.push_back(ref);
121         return 0;
122 }
123
124 RESULT eDVBServiceList::getNext(eServiceReference &)
125 {
126                 /* implement me */
127         return -1;
128 }
129
130 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
131 {
132         ePtr<eDVBService> service;
133         int r = lookupService(service, ref);
134         if (r)
135                 service = 0;
136                 // check resources...
137         ptr = new eDVBServicePlay(ref, service);
138         return 0;
139 }
140
141 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
142 {
143         ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
144         return 0;
145 }
146
147 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
148 {
149         ptr = new eDVBServiceList(ref);
150         return 0;
151 }
152
153 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
154 {
155                 /* do we have a PVR service? */
156         if (ref.path.size())
157         {
158                 ptr = new eStaticServiceDVBPVRInformation(ref);
159                 return 0;
160         } else
161         {
162                 ePtr<eDVBService> service;
163                 int r = lookupService(service, ref);
164                 if (r)
165                         return r;
166                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
167                 ptr = service;
168                 return 0;
169         }
170 }
171
172 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
173 {
174                         // TODO: handle the listing itself
175         // if (ref.... == -1) .. return "... bouquets ...";
176         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
177                         // TODO: cache
178         ePtr<iDVBChannelList> db;
179         ePtr<eDVBResourceManager> res;
180         
181         int err;
182         if ((err = eDVBResourceManager::getInstance(res)) != 0)
183         {
184                 eDebug("no resource manager");
185                 return err;
186         }
187         if ((err = res->getChannelList(db)) != 0)
188         {
189                 eDebug("no channel list");
190                 return err;
191         }
192         
193                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
194         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
195         {
196                 eDebug("getService failed!");
197                 return err;
198         }
199
200         return 0;
201 }
202
203 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
204         m_reference(ref), m_dvb_service(service)
205 {
206         m_is_pvr = !ref.path.empty();
207         
208         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
209         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
210         eDebug("DVB start (play)");
211 }
212
213 eDVBServicePlay::~eDVBServicePlay()
214 {
215         eDebug("DVB stop (play)");
216 }
217
218 void eDVBServicePlay::gotNewEvent()
219 {
220 #if 0
221                 // debug only
222         ePtr<eServiceEvent> m_event_now, m_event_next;
223         getEvent(m_event_now, 0);
224         getEvent(m_event_next, 1);
225
226         if (m_event_now)
227                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
228         if (m_event_next)
229                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
230 #endif
231         m_event((iPlayableService*)this, evUpdatedEventInfo);
232 }
233
234 void eDVBServicePlay::serviceEvent(int event)
235 {
236         eDebug("service event %d", event);
237         switch (event)
238         {
239         case eDVBServicePMTHandler::eventTuned:
240         {
241                 ePtr<iDVBDemux> m_demux;
242                 if (!m_service_handler.getDemux(m_demux))
243                 {
244 //                      eventStartedEventAcquisition
245                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
246                 } else
247                         eDebug("no event data available :( ");
248 //                      eventNoEvent
249                 break;
250         }
251         case eDVBServicePMTHandler::eventNewProgramInfo:
252         {
253                 int vpid = -1, apid = -1, pcrpid = -1;
254                 eDVBServicePMTHandler::program program;
255                 if (m_service_handler.getProgramInfo(program))
256                         eDebug("getting program info failed.");
257                 else
258                 {
259                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
260                         if (!program.videoStreams.empty())
261                         {
262                                 eDebugNoNewLine(" (");
263                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
264                                         i(program.videoStreams.begin()); 
265                                         i != program.videoStreams.end(); ++i)
266                                 {
267                                         if (vpid == -1)
268                                                 vpid = i->pid;
269                                         if (i != program.videoStreams.begin())
270                                                 eDebugNoNewLine(", ");
271                                         eDebugNoNewLine("%04x", i->pid);
272                                 }
273                                 eDebugNoNewLine(")");
274                         }
275                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
276                         if (!program.audioStreams.empty())
277                         {
278                                 eDebugNoNewLine(" (");
279                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
280                                         i(program.audioStreams.begin()); 
281                                         i != program.audioStreams.end(); ++i)
282                                 {
283                                         if (apid == -1)
284                                                 apid = i->pid;
285                                         if (i != program.audioStreams.begin())
286                                                 eDebugNoNewLine(", ");
287                                         eDebugNoNewLine("%04x", i->pid);
288                                 }
289                                 eDebugNoNewLine(")");
290                         }
291                         eDebug(", and the pcr pid is %04x", program.pcrPid);
292                         if (program.pcrPid != 0x1fff)
293                                 pcrpid = program.pcrPid;
294                 }
295                 
296                 if (!m_decoder)
297                 {
298                         ePtr<iDVBDemux> demux;
299                         m_service_handler.getDemux(demux);
300                         if (demux)
301                                 demux->getMPEGDecoder(m_decoder);
302                 }
303
304                 if (m_decoder)
305                 {
306                         m_decoder->setVideoPID(vpid);
307                         m_decoder->setAudioPID(apid, 0);
308                         if (m_is_pvr)
309                                 m_decoder->setSyncPCR(pcrpid);
310                         else
311                                 m_decoder->setSyncPCR(-1);
312                         m_decoder->start();
313 // how we can do this better?
314 // update cache pid when the user changed the audio track or video track
315 // TODO handling of difference audio types.. default audio types..
316                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
317                         m_dvb_service->setCachePID(eDVBService::cAPID, apid);
318                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
319                 }
320                 
321                 break;
322         }
323         }
324 }
325
326 RESULT eDVBServicePlay::start()
327 {
328         eDebug("starting DVB service");
329         m_event(this, evStart);
330         return m_service_handler.tune((eServiceReferenceDVB&)m_reference);
331 }
332
333 RESULT eDVBServicePlay::stop()
334 {
335         eDebug("stopping..");
336         return 0;
337 }
338
339 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
340 {
341         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
342         return 0;
343 }
344
345 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
346 {
347                 // not yet possible, maybe later...
348         ptr = 0;
349         return -1;
350 }
351
352 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
353 {
354         ptr = this;
355         return 0;
356 }
357
358 RESULT eDVBServicePlay::getName(std::string &name)
359 {
360         if (m_dvb_service)
361                 m_dvb_service->getName(m_reference, name);
362         else
363                 name = "DVB service";
364         return 0;
365 }
366
367 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
368 {
369         return m_event_handler.getEvent(evt, nownext);
370 }
371
372 DEFINE_REF(eDVBServicePlay)
373
374 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");