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