add support for listing satellites and providers
[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         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         res.push_back(m_ref.path + ".meta");
177         return 0;
178 }
179
180 DEFINE_REF(eServiceFactoryDVB)
181
182 eServiceFactoryDVB::eServiceFactoryDVB()
183 {
184         ePtr<eServiceCenter> sc;
185         
186         eServiceCenter::getPrivInstance(sc);
187         if (sc)
188                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
189 }
190
191 eServiceFactoryDVB::~eServiceFactoryDVB()
192 {
193         ePtr<eServiceCenter> sc;
194         
195         eServiceCenter::getPrivInstance(sc);
196         if (sc)
197                 sc->removeServiceFactory(eServiceFactoryDVB::id);
198 }
199
200 DEFINE_REF(eDVBServiceList);
201
202 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
203 {
204 }
205
206 eDVBServiceList::~eDVBServiceList()
207 {
208 }
209
210 RESULT eDVBServiceList::startQuery()
211 {
212         ePtr<iDVBChannelList> db;
213         ePtr<eDVBResourceManager> res;
214         
215         int err;
216         if ((err = eDVBResourceManager::getInstance(res)) != 0)
217         {
218                 eDebug("no resource manager");
219                 return err;
220         }
221         if ((err = res->getChannelList(db)) != 0)
222         {
223                 eDebug("no channel list");
224                 return err;
225         }
226         
227         ePtr<eDVBChannelQuery> q;
228         
229         if (!m_parent.path.empty())
230         {
231                 eDVBChannelQuery::compile(q, m_parent.path);
232                 if (!q)
233                 {
234                         eDebug("compile query failed");
235                         return err;
236                 }
237         }
238         
239         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
240         {
241                 eDebug("startQuery failed");
242                 return err;
243         }
244
245         return 0;
246 }
247
248 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list)
249 {
250         eServiceReferenceDVB ref;
251         
252         if (!m_query)
253                 return -1;
254         
255         while (!m_query->getNextResult(ref))
256                 list.push_back(ref);
257         return 0;
258 }
259
260 RESULT eDVBServiceList::getNext(eServiceReference &ref)
261 {
262         if (!m_query)
263                 return -1;
264         
265         return m_query->getNextResult((eServiceReferenceDVB&)ref);
266 }
267
268 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
269 {
270         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
271 }
272
273 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
274 {
275         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
276         {
277                 ePtr<iDVBChannelList> db;
278                 ePtr<eDVBResourceManager> resm;
279
280                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
281                         return -1;
282
283                 if (db->getBouquet(m_parent, m_bouquet) != 0)
284                         return -1;
285
286                 res = this;
287                 
288                 return 0;
289         }
290         res = 0;
291         return -1;
292 }
293
294 RESULT eDVBServiceList::addService(eServiceReference &ref)
295 {
296         if (!m_bouquet)
297                 return -1;
298         return m_bouquet->addService(ref);
299 }
300
301 RESULT eDVBServiceList::removeService(eServiceReference &ref)
302 {
303         if (!m_bouquet)
304                 return -1;
305         return m_bouquet->removeService(ref);
306 }
307
308 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
309 {
310         if (!m_bouquet)
311                 return -1;
312         return m_bouquet->moveService(ref, pos);
313 }
314
315 RESULT eDVBServiceList::flushChanges()
316 {
317         if (!m_bouquet)
318                 return -1;
319         return m_bouquet->flushChanges();
320 }
321
322 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
323 {
324         ePtr<eDVBService> service;
325         int r = lookupService(service, ref);
326         if (r)
327                 service = 0;
328                 // check resources...
329         ptr = new eDVBServicePlay(ref, service);
330         return 0;
331 }
332
333 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
334 {
335         if (ref.path.empty())
336         {
337                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
338                 return 0;
339         } else
340         {
341                 ptr = 0;
342                 return -1;
343         }
344 }
345
346 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
347 {
348         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
349         if (list->startQuery())
350         {
351                 ptr = 0;
352                 return -1;
353         }
354         
355         ptr = list;
356         return 0;
357 }
358
359 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
360 {
361                 /* do we have a PVR service? */
362         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
363         {
364                 if ( !ref.name.empty() )
365                         ptr = new eStaticServiceDVBInformation;
366                 else
367                         ptr = new eStaticServiceDVBBouquetInformation;
368                 return 0;
369         }
370         else if (!ref.path.empty())
371         {
372                 ptr = new eStaticServiceDVBPVRInformation(ref);
373                 return 0;
374         }
375         else
376         {
377                 ePtr<eDVBService> service;
378                 int r = lookupService(service, ref);
379                 if (r)
380                         ptr = new eStaticServiceDVBInformation;
381                 else
382                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
383                         ptr = service;
384                 return 0;
385         }
386 }
387
388 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
389 {
390         if (ref.path.empty())
391         {
392                 ptr = 0;
393                 return -1;
394         } else
395         {
396                 ptr = new eDVBPVRServiceOfflineOperations(ref);
397                 return 0;
398         }
399 }
400
401 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
402 {
403                         // TODO: handle the listing itself
404         // if (ref.... == -1) .. return "... bouquets ...";
405         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
406                         // TODO: cache
407         ePtr<iDVBChannelList> db;
408         ePtr<eDVBResourceManager> res;
409         
410         int err;
411         if ((err = eDVBResourceManager::getInstance(res)) != 0)
412         {
413                 eDebug("no resource manager");
414                 return err;
415         }
416         if ((err = res->getChannelList(db)) != 0)
417         {
418                 eDebug("no channel list");
419                 return err;
420         }
421         
422                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
423         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
424         {
425                 eDebug("getService failed!");
426                 return err;
427         }
428
429         return 0;
430 }
431
432 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
433         m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0)
434 {
435         m_is_pvr = !ref.path.empty();
436         
437         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
438         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
439 }
440
441 eDVBServicePlay::~eDVBServicePlay()
442 {
443 }
444
445 void eDVBServicePlay::gotNewEvent()
446 {
447 #if 0
448                 // debug only
449         ePtr<eServiceEvent> m_event_now, m_event_next;
450         getEvent(m_event_now, 0);
451         getEvent(m_event_next, 1);
452
453         if (m_event_now)
454                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
455         if (m_event_next)
456                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
457 #endif
458         m_event((iPlayableService*)this, evUpdatedEventInfo);
459 }
460
461 void eDVBServicePlay::serviceEvent(int event)
462 {
463         switch (event)
464         {
465         case eDVBServicePMTHandler::eventTuned:
466         {
467                 ePtr<iDVBDemux> m_demux;
468                 if (!m_service_handler.getDemux(m_demux))
469                 {
470 //                      eventStartedEventAcquisition
471                         m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get());
472                 }
473 //                      eventNoEvent
474                 break;
475         }
476         case eDVBServicePMTHandler::eventTuneFailed:
477         {
478                 eDebug("DVB service failed to tune");
479                 m_event((iPlayableService*)this, evTuneFailed);
480                 break;
481         }
482         case eDVBServicePMTHandler::eventNewProgramInfo:
483         {
484                 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1;
485                 eDVBServicePMTHandler::program program;
486                 if (m_service_handler.getProgramInfo(program))
487                         eDebug("getting program info failed.");
488                 else
489                 {
490                         eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
491                         if (!program.videoStreams.empty())
492                         {
493                                 eDebugNoNewLine(" (");
494                                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
495                                         i(program.videoStreams.begin()); 
496                                         i != program.videoStreams.end(); ++i)
497                                 {
498                                         if (vpid == -1)
499                                                 vpid = i->pid;
500                                         if (i != program.videoStreams.begin())
501                                                 eDebugNoNewLine(", ");
502                                         eDebugNoNewLine("%04x", i->pid);
503                                 }
504                                 eDebugNoNewLine(")");
505                         }
506                         eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
507                         if (!program.audioStreams.empty())
508                         {
509                                 eDebugNoNewLine(" (");
510                                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
511                                         i(program.audioStreams.begin()); 
512                                         i != program.audioStreams.end(); ++i)
513                                 {
514                                         if (apid == -1)
515                                         {
516                                                 apid = i->pid;
517                                                 apidtype = i->type;
518                                         }
519                                         if (i != program.audioStreams.begin())
520                                                 eDebugNoNewLine(", ");
521                                         eDebugNoNewLine("%04x", i->pid);
522                                 }
523                                 eDebugNoNewLine(")");
524                         }
525                         eDebug(", and the pcr pid is %04x", program.pcrPid);
526                         if (program.pcrPid != 0x1fff)
527                                 pcrpid = program.pcrPid;
528                 }
529                 
530                 if (!m_decoder)
531                 {
532                         ePtr<iDVBDemux> demux;
533                         m_service_handler.getDemux(demux);
534                         if (demux)
535                                 demux->getMPEGDecoder(m_decoder);
536                 }
537
538                 if (m_decoder)
539                 {
540                         m_decoder->setVideoPID(vpid);
541                         m_current_audio_stream = 0;
542                         m_decoder->setAudioPID(apid, apidtype);
543                         if (!m_is_pvr)
544                                 m_decoder->setSyncPCR(pcrpid);
545                         else
546                                 m_decoder->setSyncPCR(-1);
547                         m_decoder->start();
548 // how we can do this better?
549 // update cache pid when the user changed the audio track or video track
550 // TODO handling of difference audio types.. default audio types..
551                                 
552                                 /* don't worry about non-existing services, nor pvr services */
553                         if (m_dvb_service && !m_is_pvr)
554                         {
555                                 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
556                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
557                                 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
558                         }
559                 }
560                 
561                 break;
562         }
563         }
564 }
565
566 RESULT eDVBServicePlay::start()
567 {
568         int r;
569         eDebug("starting DVB service");
570         r = m_service_handler.tune((eServiceReferenceDVB&)m_reference);
571         eDebug("tune result: %d", r);
572         m_event(this, evStart);
573         return 0;
574 }
575
576 RESULT eDVBServicePlay::stop()
577 {
578         eDebug("stopping..");
579         return 0;
580 }
581
582 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
583 {
584         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
585         return 0;
586 }
587
588 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
589 {
590         if (m_is_pvr)
591         {
592                 ptr = this;
593                 return 0;
594         }
595
596         ptr = 0;
597         return -1;
598 }
599
600 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
601 {
602         if (m_is_pvr)
603         {
604                 ptr = this;
605                 return 0;
606         }
607         
608         ptr = 0;
609         return -1;
610 }
611
612 RESULT eDVBServicePlay::getLength(pts_t &len)
613 {
614         ePtr<iDVBPVRChannel> pvr_channel;
615         
616         if (m_service_handler.getPVRChannel(pvr_channel))
617         {
618                 eDebug("getPVRChannel failed!");
619                 return -1;
620         }
621         
622         return pvr_channel->getLength(len);
623 }
624
625 RESULT eDVBServicePlay::pause()
626 {
627         if (!m_is_paused && m_decoder)
628         {
629                 m_is_paused = 1;
630                 return m_decoder->freeze(0);
631         } else
632                 return -1;
633 }
634
635 RESULT eDVBServicePlay::unpause()
636 {
637         if (m_is_paused && m_decoder)
638         {
639                 m_is_paused = 0;
640                 return m_decoder->unfreeze();
641         } else
642                 return -1;
643 }
644
645 RESULT eDVBServicePlay::seekTo(pts_t to)
646 {
647         return -1;
648 }
649
650 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
651 {
652         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
653
654         ePtr<iDVBPVRChannel> pvr_channel;
655         
656         if (m_service_handler.getPVRChannel(pvr_channel))
657                 return -1;
658         
659         to *= direction;
660         
661         ePtr<iDVBDemux> demux;
662         m_service_handler.getDemux(demux);
663         if (!demux)
664                 return -1;
665         
666         return pvr_channel->seekTo(demux, 1, to);
667 }
668
669 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
670 {
671         ePtr<iDVBPVRChannel> pvr_channel;
672         
673         if (m_service_handler.getPVRChannel(pvr_channel))
674                 return -1;
675         
676         ePtr<iDVBDemux> demux;
677         m_service_handler.getDemux(demux);
678         if (!demux)
679                 return -1;
680         
681         return pvr_channel->getCurrentPosition(demux, pos);
682 }
683
684 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
685 {
686         ptr = this;
687         return 0;
688 }
689
690 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
691 {
692         ptr = this;
693         return 0;
694 }
695
696 RESULT eDVBServicePlay::getName(std::string &name)
697 {
698         if (m_dvb_service)
699         {
700                 m_dvb_service->getName(m_reference, name);
701                 if (name.empty())
702                         name = "(...)";
703         } else
704                 name = "DVB service";
705         return 0;
706 }
707
708 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
709 {
710         return m_event_handler.getEvent(evt, nownext);
711 }
712
713 int eDVBServicePlay::getInfo(int w)
714 {
715         eDVBServicePMTHandler::program program;
716
717         if (m_service_handler.getProgramInfo(program))
718                 return -1;
719         
720         switch (w)
721         {
722         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
723         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
724         case sPCRPID: return program.pcrPid;
725         case sPMTPID: return program.pmtPid;
726         case sTXTPID: return -1;
727                 
728         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
729         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
730         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
731         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
732         case sProvider: if (!m_dvb_service) return -1; return -2;
733         default:
734                 return -1;
735         }
736 }
737
738 std::string eDVBServicePlay::getInfoString(int w)
739 {       
740         switch (w)
741         {
742         case sProvider:
743                 if (!m_dvb_service) return "";
744                 return m_dvb_service->m_provider_name;
745         default:
746                 return "";
747         }
748 }
749
750 int eDVBServicePlay::getNumberOfTracks()
751 {
752         eDVBServicePMTHandler::program program;
753         if (m_service_handler.getProgramInfo(program))
754                 return 0;
755         return program.audioStreams.size();
756 }
757
758 RESULT eDVBServicePlay::selectTrack(unsigned int i)
759 {
760         int ret = selectAudioStream(i);
761
762         if (m_decoder->start())
763                 return -5;
764
765         return ret;
766 }
767
768 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
769 {
770         eDVBServicePMTHandler::program program;
771
772         if (m_service_handler.getProgramInfo(program))
773                 return -1;
774         
775         if (i >= program.audioStreams.size())
776                 return -2;
777         
778         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
779                 info.m_description = "MPEG";
780         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
781                 info.m_description = "AC3";
782         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
783                 info.m_description = "DTS";
784         else
785                 info.m_description = "???";
786         
787                 /* CHECK here for component tag override. */
788         info.m_language = program.audioStreams[i].language_code;
789         
790         return 0;
791 }
792
793 int eDVBServicePlay::selectAudioStream(int i)
794 {
795         eDVBServicePMTHandler::program program;
796
797         if (m_service_handler.getProgramInfo(program))
798                 return -1;
799         
800         if (i >= program.audioStreams.size())
801                 return -2;
802         
803         if (!m_decoder)
804                 return -3;
805         
806         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
807                 return -4;
808
809         m_current_audio_stream = i;
810
811         return 0;
812 }
813
814 DEFINE_REF(eDVBServicePlay)
815
816 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");