add support for Linkage services ( Premiere Subservices )
[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         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
29         if ( !ref.name.empty() )
30         {
31                 if (service.getParentTransportStreamID().get()) // linkage subservice
32                 {
33                         ePtr<iServiceHandler> service_center;
34                         if (!eServiceCenter::getInstance(service_center))
35                         {
36                                 eServiceReferenceDVB parent = service;
37                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
38                                 parent.setServiceID( service.getParentServiceID() );
39                                 parent.setParentTransportStreamID(eTransportStreamID(0));
40                                 parent.setParentServiceID(eServiceID(0));
41                                 parent.name="";
42                                 ePtr<iStaticServiceInformation> service_info;
43                                 if (!service_center->info(parent, service_info))
44                                 {
45                                         if (!service_info->getName(parent, name))
46                                         {
47                                                 // just show short name
48                                                 unsigned int pos = name.find("\xc2\x86");
49                                                 if ( pos != std::string::npos )
50                                                         name.erase(0, pos+2);
51                                                 pos = name.find("\xc2\x87");
52                                                 if ( pos != std::string::npos )
53                                                         name.erase(pos);
54                                                 name+=" - ";
55                                         }
56                                 }
57                         }
58                 }
59                 else
60                         name="";
61                 name += ref.name;
62                 return 0;
63         }
64         else
65                 return -1;
66 }
67
68 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
69 {
70         return -1;
71 }
72
73 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
74 {
75         DECLARE_REF(eStaticServiceDVBBouquetInformation);
76 public:
77         RESULT getName(const eServiceReference &ref, std::string &name);
78         int getLength(const eServiceReference &ref);
79 };
80
81 DEFINE_REF(eStaticServiceDVBBouquetInformation);
82
83 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
84 {
85         ePtr<iDVBChannelList> db;
86         ePtr<eDVBResourceManager> res;
87
88         int err;
89         if ((err = eDVBResourceManager::getInstance(res)) != 0)
90         {
91                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
92                 return err;
93         }
94         if ((err = res->getChannelList(db)) != 0)
95         {
96                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
97                 return err;
98         }
99
100         eBouquet *bouquet=0;
101         if ((err = db->getBouquet(ref, bouquet)) != 0)
102         {
103                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
104                 return -1;
105         }
106
107         if ( bouquet && bouquet->m_bouquet_name.length() )
108         {
109                 name = "[Bouquet] " + bouquet->m_bouquet_name;
110                 return 0;
111         }
112         else
113                 return -1;
114 }
115
116 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
117 {
118         return -1;
119 }
120
121 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
122 {
123         DECLARE_REF(eStaticServiceDVBPVRInformation);
124         eServiceReference m_ref;
125         eDVBMetaParser m_parser;
126 public:
127         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
128         RESULT getName(const eServiceReference &ref, std::string &name);
129         int getLength(const eServiceReference &ref);
130 };
131
132 DEFINE_REF(eStaticServiceDVBPVRInformation);
133
134 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
135 {
136         m_ref = ref;
137         m_parser.parseFile(ref.path);
138 }
139
140 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
141 {
142         ASSERT(ref == m_ref);
143         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
144         return 0;
145 }
146
147 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
148 {
149         ASSERT(ref == m_ref);
150         
151         eDVBTSTools tstools;
152         
153         if (tstools.openFile(ref.path.c_str()))
154                 return 0;
155
156         pts_t len;
157         if (tstools.calcLen(len))
158                 return 0;
159
160         return len / 90000;
161 }
162
163
164
165 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
166 {
167         DECLARE_REF(eDVBPVRServiceOfflineOperations);
168         eServiceReferenceDVB m_ref;
169 public:
170         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
171         
172         RESULT deleteFromDisk(int simulate);
173         RESULT getListOfFilenames(std::list<std::string> &);
174 };
175
176 DEFINE_REF(eDVBPVRServiceOfflineOperations);
177
178 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
179 {
180 }
181
182 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
183 {
184         if (simulate)
185                 return 0;
186         else
187         {
188                 std::list<std::string> res;
189                 if (getListOfFilenames(res))
190                         return -1;
191                 
192                                 /* TODO: deferred removing.. */
193                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
194                 {
195                         eDebug("Removing %s...", i->c_str());
196                         ::unlink(i->c_str());
197                 }
198                 
199                 return 0;
200         }
201 }
202
203 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
204 {
205         res.clear();
206         res.push_back(m_ref.path);
207         res.push_back(m_ref.path + ".meta");
208         return 0;
209 }
210
211 DEFINE_REF(eServiceFactoryDVB)
212
213 eServiceFactoryDVB::eServiceFactoryDVB()
214 {
215         ePtr<eServiceCenter> sc;
216         
217         eServiceCenter::getPrivInstance(sc);
218         if (sc)
219                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
220 }
221
222 eServiceFactoryDVB::~eServiceFactoryDVB()
223 {
224         ePtr<eServiceCenter> sc;
225         
226         eServiceCenter::getPrivInstance(sc);
227         if (sc)
228                 sc->removeServiceFactory(eServiceFactoryDVB::id);
229 }
230
231 DEFINE_REF(eDVBServiceList);
232
233 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
234 {
235 }
236
237 eDVBServiceList::~eDVBServiceList()
238 {
239 }
240
241 RESULT eDVBServiceList::startQuery()
242 {
243         ePtr<iDVBChannelList> db;
244         ePtr<eDVBResourceManager> res;
245         
246         int err;
247         if ((err = eDVBResourceManager::getInstance(res)) != 0)
248         {
249                 eDebug("no resource manager");
250                 return err;
251         }
252         if ((err = res->getChannelList(db)) != 0)
253         {
254                 eDebug("no channel list");
255                 return err;
256         }
257         
258         ePtr<eDVBChannelQuery> q;
259         
260         if (!m_parent.path.empty())
261         {
262                 eDVBChannelQuery::compile(q, m_parent.path);
263                 if (!q)
264                 {
265                         eDebug("compile query failed");
266                         return err;
267                 }
268         }
269         
270         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
271         {
272                 eDebug("startQuery failed");
273                 return err;
274         }
275
276         return 0;
277 }
278
279 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
280 {
281         eServiceReferenceDVB ref;
282         
283         if (!m_query)
284                 return -1;
285         
286         while (!m_query->getNextResult(ref))
287                 list.push_back(ref);
288         return 0;
289 }
290
291 RESULT eDVBServiceList::getNext(eServiceReference &ref)
292 {
293         if (!m_query)
294                 return -1;
295         
296         return m_query->getNextResult((eServiceReferenceDVB&)ref);
297 }
298
299 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
300 {
301         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
302 }
303
304 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
305 {
306         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
307         {
308                 ePtr<iDVBChannelList> db;
309                 ePtr<eDVBResourceManager> resm;
310
311                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
312                         return -1;
313
314                 if (db->getBouquet(m_parent, m_bouquet) != 0)
315                         return -1;
316
317                 res = this;
318                 
319                 return 0;
320         }
321         res = 0;
322         return -1;
323 }
324
325 RESULT eDVBServiceList::addService(eServiceReference &ref)
326 {
327         if (!m_bouquet)
328                 return -1;
329         return m_bouquet->addService(ref);
330 }
331
332 RESULT eDVBServiceList::removeService(eServiceReference &ref)
333 {
334         if (!m_bouquet)
335                 return -1;
336         return m_bouquet->removeService(ref);
337 }
338
339 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
340 {
341         if (!m_bouquet)
342                 return -1;
343         return m_bouquet->moveService(ref, pos);
344 }
345
346 RESULT eDVBServiceList::flushChanges()
347 {
348         if (!m_bouquet)
349                 return -1;
350         return m_bouquet->flushChanges();
351 }
352
353 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
354 {
355         ePtr<eDVBService> service;
356         int r = lookupService(service, ref);
357         if (r)
358                 service = 0;
359                 // check resources...
360         ptr = new eDVBServicePlay(ref, service);
361         return 0;
362 }
363
364 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
365 {
366         if (ref.path.empty())
367         {
368                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
369                 return 0;
370         } else
371         {
372                 ptr = 0;
373                 return -1;
374         }
375 }
376
377 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
378 {
379         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
380         if (list->startQuery())
381         {
382                 ptr = 0;
383                 return -1;
384         }
385         
386         ptr = list;
387         return 0;
388 }
389
390 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
391 {
392         /* is a listable service? */
393         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
394         {
395                 if ( !ref.name.empty() )  // satellites or providers list
396                         ptr = new eStaticServiceDVBInformation;
397                 else // a dvb bouquet
398                         ptr = new eStaticServiceDVBBouquetInformation;
399         }
400         else if (!ref.path.empty()) /* do we have a PVR service? */
401                 ptr = new eStaticServiceDVBPVRInformation(ref);
402         else // normal dvb service
403         {
404                 ePtr<eDVBService> service;
405                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
406                         ptr = new eStaticServiceDVBInformation;
407                 else
408                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
409                         ptr = service;
410         }
411         return 0;
412 }
413
414 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
415 {
416         if (ref.path.empty())
417         {
418                 ptr = 0;
419                 return -1;
420         } else
421         {
422                 ptr = new eDVBPVRServiceOfflineOperations(ref);
423                 return 0;
424         }
425 }
426
427 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
428 {
429                         // TODO: handle the listing itself
430         // if (ref.... == -1) .. return "... bouquets ...";
431         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
432                         // TODO: cache
433         ePtr<iDVBChannelList> db;
434         ePtr<eDVBResourceManager> res;
435         
436         int err;
437         if ((err = eDVBResourceManager::getInstance(res)) != 0)
438         {
439                 eDebug("no resource manager");
440                 return err;
441         }
442         if ((err = res->getChannelList(db)) != 0)
443         {
444                 eDebug("no channel list");
445                 return err;
446         }
447         
448                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
449         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
450         {
451                 eDebug("getService failed!");
452                 return err;
453         }
454
455         return 0;
456 }
457
458 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
459         m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
460 {
461         m_is_pvr = !ref.path.empty();
462         
463         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
464         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
465 }
466
467 eDVBServicePlay::~eDVBServicePlay()
468 {
469 }
470
471 void eDVBServicePlay::gotNewEvent()
472 {
473 #if 0
474                 // debug only
475         ePtr<eServiceEvent> m_event_now, m_event_next;
476         getEvent(m_event_now, 0);
477         getEvent(m_event_next, 1);
478
479         if (m_event_now)
480                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
481         if (m_event_next)
482                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
483 #endif
484         m_event((iPlayableService*)this, evUpdatedEventInfo);
485 }
486
487 void eDVBServicePlay::serviceEvent(int event)
488 {
489         switch (event)
490         {
491         case eDVBServicePMTHandler::eventTuned:
492         {
493                 ePtr<iDVBDemux> m_demux;
494                 if (!m_service_handler.getDemux(m_demux))
495                 {
496                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
497                         int sid = ref.getParentServiceID().get();
498                         if (!sid)
499                                 sid = ref.getServiceID().get();
500                         if ( ref.getParentTransportStreamID().get() &&
501                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
502                                 m_event_handler.startOther(m_demux, sid);
503                         else
504                                 m_event_handler.start(m_demux, sid);
505                 }
506                 break;
507         }
508         case eDVBServicePMTHandler::eventTuneFailed:
509         {
510                 eDebug("DVB service failed to tune");
511                 m_event((iPlayableService*)this, evTuneFailed);
512                 break;
513         }
514         case eDVBServicePMTHandler::eventNewProgramInfo:
515         {
516                 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1;
517                 eDVBServicePMTHandler::program program;
518                 if (m_service_handler.getProgramInfo(program))
519                         eDebug("getting program info failed.");
520                 else
521                 {
522                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
523                         if (!program.videoStreams.empty())
524                         {
525                                 eDebugNoNewLine(" (");
526                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
527                                         i(program.videoStreams.begin()); 
528                                         i != program.videoStreams.end(); ++i)
529                                 {
530                                         if (vpid == -1)
531                                                 vpid = i->pid;
532                                         if (i != program.videoStreams.begin())
533                                                 eDebugNoNewLine(", ");
534                                         eDebugNoNewLine("%04x", i->pid);
535                                 }
536                                 eDebugNoNewLine(")");
537                         }
538                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
539                         if (!program.audioStreams.empty())
540                         {
541                                 eDebugNoNewLine(" (");
542                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
543                                         i(program.audioStreams.begin()); 
544                                         i != program.audioStreams.end(); ++i)
545                                 {
546                                         if (apid == -1)
547                                         {
548                                                 apid = i->pid;
549                                                 apidtype = i->type;
550                                         }
551                                         if (i != program.audioStreams.begin())
552                                                 eDebugNoNewLine(", ");
553                                         eDebugNoNewLine("%04x", i->pid);
554                                 }
555                                 eDebugNoNewLine(")");
556                         }
557                         eDebug(", and the pcr pid is %04x", program.pcrPid);
558                         if (program.pcrPid != 0x1fff)
559                                 pcrpid = program.pcrPid;
560                 }
561                 
562                 if (!m_decoder)
563                 {
564                         ePtr<iDVBDemux> demux;
565                         m_service_handler.getDemux(demux);
566                         if (demux)
567                                 demux->getMPEGDecoder(m_decoder);
568                 }
569
570                 if (m_decoder)
571                 {
572                         m_decoder->setVideoPID(vpid);
573                         m_current_audio_stream = 0;
574                         m_decoder->setAudioPID(apid, apidtype);
575                         if (!m_is_pvr)
576                                 m_decoder->setSyncPCR(pcrpid);
577                         else
578                                 m_decoder->setSyncPCR(-1);
579                         m_decoder->start();
580 // how we can do this better?
581 // update cache pid when the user changed the audio track or video track
582 // TODO handling of difference audio types.. default audio types..
583                                 
584                                 /* don't worry about non-existing services, nor pvr services */
585                         if (m_dvb_service && !m_is_pvr)
586                         {
587                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
588                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
589                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
590                         }
591                 }
592                 
593                 break;
594         }
595         }
596 }
597
598 RESULT eDVBServicePlay::start()
599 {
600         int r;
601         eDebug("starting DVB service");
602         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
603         eDebug("tune result: %d", r);
604         m_event(this, evStart);
605         return 0;
606 }
607
608 RESULT eDVBServicePlay::stop()
609 {
610         eDebug("stopping..");
611         return 0;
612 }
613
614 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
615 {
616         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
617         return 0;
618 }
619
620 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
621 {
622         if (m_is_pvr)
623         {
624                 ptr = this;
625                 return 0;
626         }
627
628         ptr = 0;
629         return -1;
630 }
631
632 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
633 {
634         if (m_is_pvr)
635         {
636                 ptr = this;
637                 return 0;
638         }
639         
640         ptr = 0;
641         return -1;
642 }
643
644 RESULT eDVBServicePlay::getLength(pts_t &len)
645 {
646         ePtr<iDVBPVRChannel> pvr_channel;
647         
648         if (m_service_handler.getPVRChannel(pvr_channel))
649         {
650                 eDebug("getPVRChannel failed!");
651                 return -1;
652         }
653         
654         return pvr_channel->getLength(len);
655 }
656
657 RESULT eDVBServicePlay::pause()
658 {
659         if (!m_is_paused && m_decoder)
660         {
661                 m_is_paused = 1;
662                 return m_decoder->freeze(0);
663         } else
664                 return -1;
665 }
666
667 RESULT eDVBServicePlay::unpause()
668 {
669         if (m_is_paused && m_decoder)
670         {
671                 m_is_paused = 0;
672                 return m_decoder->unfreeze();
673         } else
674                 return -1;
675 }
676
677 RESULT eDVBServicePlay::seekTo(pts_t to)
678 {
679         return -1;
680 }
681
682 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
683 {
684         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
685
686         ePtr<iDVBPVRChannel> pvr_channel;
687         
688         if (m_service_handler.getPVRChannel(pvr_channel))
689                 return -1;
690         
691         to *= direction;
692         
693         ePtr<iDVBDemux> demux;
694         m_service_handler.getDemux(demux);
695         if (!demux)
696                 return -1;
697         
698         return pvr_channel->seekTo(demux, 1, to);
699 }
700
701 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
702 {
703         ePtr<iDVBPVRChannel> pvr_channel;
704         
705         if (m_service_handler.getPVRChannel(pvr_channel))
706                 return -1;
707         
708         ePtr<iDVBDemux> demux;
709         m_service_handler.getDemux(demux);
710         if (!demux)
711                 return -1;
712         
713         return pvr_channel->getCurrentPosition(demux, pos);
714 }
715
716 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
717 {
718         ptr = this;
719         return 0;
720 }
721
722 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
723 {
724         ptr = this;
725         return 0;
726 }
727
728 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
729 {
730         ptr = this;
731         return 0;
732 }
733
734 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
735 {
736         ptr = this;
737         return 0;
738 }
739
740 RESULT eDVBServicePlay::getName(std::string &name)
741 {
742         if (m_dvb_service)
743         {
744                 m_dvb_service->getName(m_reference, name);
745                 if (name.empty())
746                         name = "(...)";
747         }
748         else if (!m_reference.name.empty())
749                 eStaticServiceDVBInformation().getName(m_reference, name);
750         else
751                 name = "DVB service";
752         return 0;
753 }
754
755 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
756 {
757         return m_event_handler.getEvent(evt, nownext);
758 }
759
760 int eDVBServicePlay::getInfo(int w)
761 {
762         eDVBServicePMTHandler::program program;
763
764         if (m_service_handler.getProgramInfo(program))
765                 return -1;
766         
767         switch (w)
768         {
769         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
770         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
771         case sPCRPID: return program.pcrPid;
772         case sPMTPID: return program.pmtPid;
773         case sTXTPID: return -1;
774                 
775         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
776         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
777         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
778         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
779         case sProvider: if (!m_dvb_service) return -1; return -2;
780         default:
781                 return -1;
782         }
783 }
784
785 std::string eDVBServicePlay::getInfoString(int w)
786 {       
787         switch (w)
788         {
789         case sProvider:
790                 if (!m_dvb_service) return "";
791                 return m_dvb_service->m_provider_name;
792         default:
793                 return "";
794         }
795 }
796
797 int eDVBServicePlay::getNumberOfTracks()
798 {
799         eDVBServicePMTHandler::program program;
800         if (m_service_handler.getProgramInfo(program))
801                 return 0;
802         return program.audioStreams.size();
803 }
804
805 RESULT eDVBServicePlay::selectTrack(unsigned int i)
806 {
807         int ret = selectAudioStream(i);
808
809         if (m_decoder->start())
810                 return -5;
811
812         return ret;
813 }
814
815 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
816 {
817         eDVBServicePMTHandler::program program;
818
819         if (m_service_handler.getProgramInfo(program))
820                 return -1;
821         
822         if (i >= program.audioStreams.size())
823                 return -2;
824         
825         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
826                 info.m_description = "MPEG";
827         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
828                 info.m_description = "AC3";
829         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
830                 info.m_description = "DTS";
831         else
832                 info.m_description = "???";
833
834         if (program.audioStreams[i].component_tag != -1)
835         {
836                 ePtr<eServiceEvent> evt;
837                 if (!m_event_handler.getEvent(evt, 0))
838                 {
839                         ePtr<eComponentData> data;
840                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
841                                 info.m_language = data->getText();
842                 }
843         }
844
845         if (info.m_language.empty())
846                 info.m_language = program.audioStreams[i].language_code;
847         
848         return 0;
849 }
850
851 int eDVBServicePlay::selectAudioStream(int i)
852 {
853         eDVBServicePMTHandler::program program;
854
855         if (m_service_handler.getProgramInfo(program))
856                 return -1;
857         
858         if ((unsigned int)i >= program.audioStreams.size())
859                 return -2;
860         
861         if (!m_decoder)
862                 return -3;
863         
864         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
865                 return -4;
866
867         m_current_audio_stream = i;
868
869         return 0;
870 }
871
872 int eDVBServicePlay::getFrontendInfo(int w)
873 {
874         if (m_is_pvr)
875                 return 0;
876         eUsePtr<iDVBChannel> channel;
877         if(m_service_handler.getChannel(channel))
878                 return 0;
879         ePtr<iDVBFrontend> fe;
880         if(channel->getFrontend(fe))
881                 return 0;
882         return fe->readFrontendData(w);
883 }
884
885 int eDVBServicePlay::getNumberOfSubservices()
886 {
887         ePtr<eServiceEvent> evt;
888         if (!m_event_handler.getEvent(evt, 0))
889                 return evt->getNumOfLinkageServices();
890         return 0;
891 }
892
893 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
894 {
895         ePtr<eServiceEvent> evt;
896         if (!m_event_handler.getEvent(evt, 0))
897         {
898                 if (!evt->getLinkageService(sub, n))
899                 {
900                         eServiceReferenceDVB &subservice = (eServiceReferenceDVB&) sub;
901                         eServiceReferenceDVB &current = (eServiceReferenceDVB&) m_reference;
902                         subservice.setDVBNamespace(current.getDVBNamespace());
903                         if ( current.getParentTransportStreamID().get() )
904                         {
905                                 subservice.setParentTransportStreamID( current.getParentTransportStreamID() );
906                                 subservice.setParentServiceID( current.getParentServiceID() );
907                         }
908                         else
909                         {
910                                 subservice.setParentTransportStreamID( current.getTransportStreamID() );
911                                 subservice.setParentServiceID( current.getServiceID() );
912                         }
913                         if ( subservice.getParentTransportStreamID() == subservice.getTransportStreamID() &&
914                                 subservice.getParentServiceID() == subservice.getServiceID() )
915                         {
916                                 subservice.setParentTransportStreamID( eTransportStreamID(0) );
917                                 subservice.setParentServiceID( eServiceID(0) );
918                         }
919                         return 0;
920                 }
921         }
922         sub.type=eServiceReference::idInvalid;
923         return -1;
924 }
925
926 DEFINE_REF(eDVBServicePlay)
927
928 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");