aboutsummaryrefslogtreecommitdiff
path: root/lib/service
diff options
context:
space:
mode:
authorFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:36:42 +0000
committerFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:36:42 +0000
commitd63d2c3c6cbbd574dda4f8b00ebe6c661735edd5 (patch)
tree84d0cacfd0b6c1241c236c7860f7cbd7f26901bb /lib/service
downloadenigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.tar.gz
enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.zip
import of enigma2
Diffstat (limited to 'lib/service')
-rw-r--r--lib/service/Makefile.am8
-rw-r--r--lib/service/Makefile.in0
-rw-r--r--lib/service/iservice.h173
-rw-r--r--lib/service/service.cpp94
-rw-r--r--lib/service/service.h29
-rw-r--r--lib/service/servicedvb.cpp154
-rw-r--r--lib/service/servicedvb.h45
-rw-r--r--lib/service/servicefs.cpp112
-rw-r--r--lib/service/servicefs.h33
-rw-r--r--lib/service/servicemp3.cpp89
-rw-r--r--lib/service/servicemp3.h42
11 files changed, 779 insertions, 0 deletions
diff --git a/lib/service/Makefile.am b/lib/service/Makefile.am
new file mode 100644
index 00000000..09ba4ce8
--- /dev/null
+++ b/lib/service/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = \
+ -I$(top_srcdir)/include
+
+noinst_LIBRARIES = libenigma_service.a
+
+libenigma_service_a_SOURCES = \
+ service.cpp servicemp3.cpp servicedvb.cpp servicefs.cpp
+
diff --git a/lib/service/Makefile.in b/lib/service/Makefile.in
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/service/Makefile.in
diff --git a/lib/service/iservice.h b/lib/service/iservice.h
new file mode 100644
index 00000000..bedb0d6f
--- /dev/null
+++ b/lib/service/iservice.h
@@ -0,0 +1,173 @@
+#ifndef __lib_dvb_iservice_h
+#define __lib_dvb_iservice_h
+
+#include <lib/base/object.h>
+#include <lib/base/estring.h>
+#include <list>
+
+class eServiceReference
+{
+public:
+ enum
+ {
+ idInvalid=-1,
+ idStructure, // service_id == 0 is root
+ idDVB,
+ idFile,
+ idUser=0x1000
+ };
+ int type;
+
+ int flags; // flags will NOT be compared.
+ enum
+ {
+ isDirectory=1, // SHOULD enter (implies mustDescent)
+ mustDescent=2, // cannot be played directly - often used with "isDirectory" (implies canDescent)
+ /*
+ for example:
+ normal services have none of them - they can be fed directly into the "play"-handler.
+ normal directories have both of them set - you cannot play a directory directly and the UI should descent into it.
+ playlists have "mustDescent", but not "isDirectory" - you don't want the user to browse inside the playlist (unless he really wants)
+ services with sub-services have none of them, instead the have the "canDecsent" flag (as all of the above)
+ */
+ canDescent=4, // supports enterDirectory/leaveDirectory
+ flagDirectory=isDirectory|mustDescent|canDescent,
+ shouldSort=8, // should be ASCII-sorted according to service_name. great for directories.
+ hasSortKey=16, // has a sort key in data[3]. not having a sort key implies 0.
+ sort1=32 // sort key is 1 instead of 0
+ };
+
+ inline int getSortKey() const { return (flags & hasSortKey) ? data[3] : ((flags & sort1) ? 1 : 0); }
+
+ int data[8];
+ eString path;
+
+ eServiceReference()
+ : type(idInvalid), flags(0)
+ {
+ }
+
+ eServiceReference(int type, int flags)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ }
+ eServiceReference(int type, int flags, int data0)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ data[0]=data0;
+ }
+ eServiceReference(int type, int flags, int data0, int data1)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ data[0]=data0;
+ data[1]=data1;
+ }
+ eServiceReference(int type, int flags, int data0, int data1, int data2)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ data[0]=data0;
+ data[1]=data1;
+ data[2]=data2;
+ }
+ eServiceReference(int type, int flags, int data0, int data1, int data2, int data3)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ data[0]=data0;
+ data[1]=data1;
+ data[2]=data2;
+ data[3]=data3;
+ }
+ eServiceReference(int type, int flags, int data0, int data1, int data2, int data3, int data4)
+ : type(type), flags(flags)
+ {
+ memset(data, 0, sizeof(data));
+ data[0]=data0;
+ data[1]=data1;
+ data[2]=data2;
+ data[3]=data3;
+ data[4]=data4;
+ }
+ eServiceReference(int type, int flags, const eString &path)
+ : type(type), flags(flags), path(path)
+ {
+ memset(data, 0, sizeof(data));
+ }
+ eServiceReference(const eString &string);
+ eString toString() const;
+ bool operator==(const eServiceReference &c) const
+ {
+ if (type != c.type)
+ return 0;
+ return /* (flags == c.flags) && */ (memcmp(data, c.data, sizeof(int)*8)==0) && (path == c.path);
+ }
+ bool operator!=(const eServiceReference &c) const
+ {
+ return !(*this == c);
+ }
+ bool operator<(const eServiceReference &c) const
+ {
+ if (type < c.type)
+ return 1;
+
+ if (type > c.type)
+ return 0;
+
+/* if (flags < c.flags)
+ return 1;
+ if (flags > c.flags)
+ return 0; */
+
+ int r=memcmp(data, c.data, sizeof(int)*8);
+ if (r)
+ return r < 0;
+ return path < c.path;
+ }
+ operator bool() const
+ {
+ return type != idInvalid;
+ }
+};
+
+class iPauseableService: public virtual iObject
+{
+public:
+ virtual RESULT pause()=0;
+ virtual RESULT unpause()=0;
+};
+
+class iPlayableService: public virtual iObject
+{
+ friend class iServiceHandler;
+public:
+ // it's PRIVATE to the class factory
+ virtual RESULT start()=0;
+ virtual RESULT getIPausableService(ePtr<iPauseableService> &ptr)=0;
+};
+
+class iRecordableService: public virtual iObject
+{
+public:
+ virtual RESULT start()=0;
+ virtual RESULT stop()=0;
+};
+
+class iListableService: public virtual iObject
+{
+public:
+ virtual RESULT getContent(std::list<eServiceReference> &list)=0;
+};
+
+class iServiceHandler: public virtual iObject
+{
+public:
+ virtual RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr)=0;
+ virtual RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr)=0;
+ virtual RESULT list(const eServiceReference &, ePtr<iListableService> &ptr)=0;
+};
+
+#endif
diff --git a/lib/service/service.cpp b/lib/service/service.cpp
new file mode 100644
index 00000000..99199aa9
--- /dev/null
+++ b/lib/service/service.cpp
@@ -0,0 +1,94 @@
+#include <lib/service/service.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+
+eServiceReference::eServiceReference(const eString &string)
+{
+ const char *c=string.c_str();
+ int pathl=-1;
+
+ if ( sscanf(c, "%d:%d:%x:%x:%x:%x:%x:%x:%x:%x:%n", &type, &flags, &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7], &pathl) < 8 )
+ {
+ memset( data, 0, sizeof(data) );
+ eDebug("find old format eServiceReference string");
+ sscanf(c, "%d:%d:%x:%x:%x:%x:%n", &type, &flags, &data[0], &data[1], &data[2], &data[3], &pathl);
+ }
+
+ if (pathl)
+ path=c+pathl;
+}
+
+eString eServiceReference::toString() const
+{
+ eString ret;
+ ret+=eString().sprintf("%d:", type);
+ ret+=eString().sprintf("%d", flags);
+ for (unsigned int i=0; i<sizeof(data)/sizeof(*data); ++i)
+ ret+=":"+eString().sprintf("%x", data[i]);
+ ret+=":"+path;
+ return ret;
+}
+
+
+eServiceCenter *eServiceCenter::instance;
+
+eServiceCenter::eServiceCenter()
+{
+ if (!instance)
+ instance = this;
+}
+
+eServiceCenter::~eServiceCenter()
+{
+ if (instance == this)
+ instance = 0;
+}
+
+DEFINE_REF(eServiceCenter);
+
+RESULT eServiceCenter::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+ std::map<int,ePtr<iServiceHandler> >::iterator i = handler.find(ref.type);
+ if (i == handler.end())
+ {
+ ptr = 0;
+ return -1;
+ }
+ return i->second->play(ref, ptr);
+}
+
+RESULT eServiceCenter::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
+{
+ std::map<int,ePtr<iServiceHandler> >::iterator i = handler.find(ref.type);
+ if (i == handler.end())
+ {
+ ptr = 0;
+ return -1;
+ }
+ return i->second->record(ref, ptr);
+}
+
+RESULT eServiceCenter::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
+{
+ std::map<int,ePtr<iServiceHandler> >::iterator i = handler.find(ref.type);
+ if (i == handler.end())
+ {
+ ptr = 0;
+ return -1;
+ }
+ return i->second->list(ref, ptr);
+}
+
+RESULT eServiceCenter::addServiceFactory(int id, iServiceHandler *hnd)
+{
+ handler.insert(std::pair<int,ePtr<iServiceHandler> >(id, hnd));
+ return 0;
+}
+
+RESULT eServiceCenter::removeServiceFactory(int id)
+{
+ handler.erase(id);
+ return 0;
+}
+
+eAutoInitP0<eServiceCenter> init_eServiceCenter(eAutoInitNumbers::service, "eServiceCenter");
diff --git a/lib/service/service.h b/lib/service/service.h
new file mode 100644
index 00000000..f32e23d9
--- /dev/null
+++ b/lib/service/service.h
@@ -0,0 +1,29 @@
+#ifndef __service_h
+#define __service_h
+
+#include <map>
+#include <lib/base/object.h>
+#include <lib/service/iservice.h>
+
+class eServiceCenter: public virtual iServiceHandler, public virtual iObject
+{
+DECLARE_REF;
+private:
+ std::map<int,ePtr<iServiceHandler> > handler;
+ static eServiceCenter *instance;
+public:
+ eServiceCenter();
+ virtual ~eServiceCenter();
+
+ // iServiceHandler
+ RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+ RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+ RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+
+ // eServiceCenter
+ static RESULT getInstance(ePtr<eServiceCenter> &ptr) { ptr = instance; return 0; }
+ RESULT addServiceFactory(int id, iServiceHandler *hnd);
+ RESULT removeServiceFactory(int id);
+};
+
+#endif
diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
new file mode 100644
index 00000000..fc48fa66
--- /dev/null
+++ b/lib/service/servicedvb.cpp
@@ -0,0 +1,154 @@
+#include <lib/base/eerror.h>
+#include <lib/base/object.h>
+#include <string>
+#include <lib/service/servicedvb.h>
+#include <lib/service/service.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+
+DEFINE_REF(eServiceFactoryDVB)
+
+eServiceFactoryDVB::eServiceFactoryDVB(): ref(0)
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->addServiceFactory(eServiceFactoryDVB::id, this);
+}
+
+eServiceFactoryDVB::~eServiceFactoryDVB()
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->removeServiceFactory(eServiceFactoryDVB::id);
+}
+
+RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+ RESULT res;
+ // check resources...
+ ptr = new eDVBServicePlay(ref);
+ res = ptr->start();
+ if (res)
+ {
+ ptr = 0;
+ return res;
+ }
+ return 0;
+}
+
+RESULT eServiceFactoryDVB::record(const eServiceReference &, ePtr<iRecordableService> &ptr)
+{
+ ptr = 0;
+ return -1;
+}
+
+RESULT eServiceFactoryDVB::list(const eServiceReference &, ePtr<iListableService> &ptr)
+{
+ ptr = 0;
+ return -1;
+}
+
+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref):
+ ref(0), m_reference(ref)
+{
+ CONNECT(m_serviceHandler.serviceEvent, eDVBServicePlay::serviceEvent);
+ eDebug("DVB start (play)");
+}
+
+eDVBServicePlay::~eDVBServicePlay()
+{
+ eDebug("DVB stop (play)");
+}
+
+void eDVBServicePlay::serviceEvent(int event)
+{
+ eDebug("service event %d", event);
+ switch (event)
+ {
+ case eDVBServicePMTHandler::eventNewProgramInfo:
+ {
+ int vpid = -1, apid = -1, pcrpid = -1;
+ eDVBServicePMTHandler::program program;
+ if (m_serviceHandler.getProgramInfo(program))
+ eDebug("getting program info failed.");
+ else
+ {
+ eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
+ if (!program.videoStreams.empty())
+ {
+ eDebugNoNewLine(" (");
+ for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
+ i(program.videoStreams.begin());
+ i != program.videoStreams.end(); ++i)
+ {
+ if (vpid == -1)
+ vpid = i->pid;
+ if (i != program.videoStreams.begin())
+ eDebugNoNewLine(", ");
+ eDebugNoNewLine("%04x", i->pid);
+ }
+ eDebugNoNewLine(")");
+ }
+ eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
+ if (!program.audioStreams.empty())
+ {
+ eDebugNoNewLine(" (");
+ for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
+ i(program.audioStreams.begin());
+ i != program.audioStreams.end(); ++i)
+ {
+ if (apid == -1)
+ apid = i->pid;
+ if (i != program.audioStreams.begin())
+ eDebugNoNewLine(", ");
+ eDebugNoNewLine("%04x", i->pid);
+ }
+ eDebugNoNewLine(")");
+ }
+ eDebug(", and the pcr pid is %04x", program.pcrPid);
+ if (program.pcrPid != 0x1fff)
+ pcrpid = program.pcrPid;
+ }
+
+ if (!m_decoder)
+ {
+ ePtr<iDVBDemux> demux;
+ m_serviceHandler.getDemux(demux);
+ if (demux)
+ demux->getMPEGDecoder(m_decoder);
+ }
+
+ if (m_decoder)
+ {
+ m_decoder->setVideoPID(vpid);
+ m_decoder->setAudioPID(apid, 0);
+ m_decoder->setSyncPCR(pcrpid);
+ m_decoder->start();
+ }
+
+ break;
+ }
+ }
+}
+
+RESULT eDVBServicePlay::start()
+{
+ eDebug("starting DVB service");
+ m_serviceHandler.tune((eServiceReferenceDVB&)m_reference);
+ return 0;
+}
+
+RESULT eDVBServicePlay::getIPausableService(ePtr<iPauseableService> &ptr)
+{
+ // not yet possible, maybe later...
+ ptr = 0;
+ return -1;
+}
+
+DEFINE_REF(eDVBServicePlay)
+
+eAutoInitP0<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");
diff --git a/lib/service/servicedvb.h b/lib/service/servicedvb.h
new file mode 100644
index 00000000..fac9edf2
--- /dev/null
+++ b/lib/service/servicedvb.h
@@ -0,0 +1,45 @@
+#ifndef __servicemp3_h
+#define __servicemp3_h
+
+#include <lib/service/iservice.h>
+#include <lib/dvb/idvb.h>
+
+#include <lib/dvb/pmt.h>
+
+class eServiceFactoryDVB: public virtual iServiceHandler, public virtual iObject
+{
+DECLARE_REF;
+public:
+ eServiceFactoryDVB();
+ virtual ~eServiceFactoryDVB();
+ enum { id = 0x1 };
+
+ // iServiceHandler
+ RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+ RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+ RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+};
+
+class eDVBServicePlay: public virtual iPlayableService, public virtual iObject, public Object
+{
+DECLARE_REF;
+private:
+ friend class eServiceFactoryDVB;
+ eServiceReference m_reference;
+
+ ePtr<iTSMPEGDecoder> m_decoder;
+
+ eDVBServicePMTHandler m_serviceHandler;
+
+ eDVBServicePlay(const eServiceReference &ref);
+
+ void serviceEvent(int event);
+public:
+ virtual ~eDVBServicePlay();
+
+ // iPlayableService
+ RESULT start();
+ RESULT getIPausableService(ePtr<iPauseableService> &ptr);
+};
+
+#endif
diff --git a/lib/service/servicefs.cpp b/lib/service/servicefs.cpp
new file mode 100644
index 00000000..ad40f0af
--- /dev/null
+++ b/lib/service/servicefs.cpp
@@ -0,0 +1,112 @@
+#include <lib/base/eerror.h>
+#include <lib/base/object.h>
+#include <string>
+#include <errno.h>
+#include <lib/service/servicefs.h>
+#include <lib/service/service.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// eServiceFactoryFS
+
+eServiceFactoryFS::eServiceFactoryFS(): ref(0)
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->addServiceFactory(eServiceFactoryFS::id, this);
+}
+
+eServiceFactoryFS::~eServiceFactoryFS()
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->removeServiceFactory(eServiceFactoryFS::id);
+}
+
+DEFINE_REF(eServiceFactoryFS)
+
+ // iServiceHandler
+RESULT eServiceFactoryFS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+ ptr=0;
+ return -1;
+}
+
+RESULT eServiceFactoryFS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
+{
+ ptr=0;
+ return -1;
+}
+
+RESULT eServiceFactoryFS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
+{
+ ptr = new eServiceFS(ref.path.c_str());
+ return 0;
+}
+
+// eServiceFS
+
+DEFINE_REF(eServiceFS);
+
+eServiceFS::eServiceFS(const char *path): ref(0), path(path)
+{
+}
+
+eServiceFS::~eServiceFS()
+{
+}
+
+RESULT eServiceFS::getContent(std::list<eServiceReference> &list)
+{
+ DIR *d=opendir(path.c_str());
+ if (!d)
+ return -errno;
+ while (dirent *e=readdir(d))
+ {
+ if (!(strcmp(e->d_name, ".") && strcmp(e->d_name, "..")))
+ continue;
+
+ eString filename;
+
+ filename = path;
+ filename += e->d_name;
+
+ struct stat s;
+ if (::stat(filename.c_str(), &s) < 0)
+ continue;
+
+ if (S_ISDIR(s.st_mode))
+ filename += "/";
+
+ if (S_ISDIR(s.st_mode))
+ {
+ eServiceReference service(eServiceFactoryFS::id,
+ eServiceReference::isDirectory|
+ eServiceReference::canDescent|eServiceReference::mustDescent|
+ eServiceReference::shouldSort|eServiceReference::sort1,
+ filename);
+ service.data[0] = 1;
+ list.push_back(service);
+ } else
+ {
+ eServiceReference service(eServiceFactoryFS::id,
+ eServiceReference::isDirectory|
+ eServiceReference::canDescent|eServiceReference::mustDescent|
+ eServiceReference::shouldSort|eServiceReference::sort1,
+ filename);
+ service.data[0] = 0;
+ list.push_back(service);
+ }
+ }
+ return 0;
+}
+
+eAutoInitP0<eServiceFactoryFS> init_eServiceFactoryFS(eAutoInitNumbers::service+1, "eServiceFactoryFS");
diff --git a/lib/service/servicefs.h b/lib/service/servicefs.h
new file mode 100644
index 00000000..9d49b42d
--- /dev/null
+++ b/lib/service/servicefs.h
@@ -0,0 +1,33 @@
+#ifndef __servicefs_h
+#define __servicefs_h
+
+#include <lib/service/iservice.h>
+
+class eServiceFactoryFS: public virtual iServiceHandler, public virtual iObject
+{
+DECLARE_REF;
+public:
+ eServiceFactoryFS();
+ virtual ~eServiceFactoryFS();
+ enum { id = 0x2 };
+
+ // iServiceHandler
+ RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+ RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+ RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+};
+
+class eServiceFS: public virtual iListableService, public virtual iObject
+{
+DECLARE_REF;
+private:
+ eString path;
+ friend class eServiceFactoryFS;
+ eServiceFS(const char *path);
+public:
+ virtual ~eServiceFS();
+
+ RESULT getContent(std::list<eServiceReference> &list);
+};
+
+#endif
diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp
new file mode 100644
index 00000000..fb5993e4
--- /dev/null
+++ b/lib/service/servicemp3.cpp
@@ -0,0 +1,89 @@
+#include <lib/base/eerror.h>
+#include <lib/base/object.h>
+#include <string>
+#include <lib/service/servicemp3.h>
+#include <lib/service/service.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+
+// eServiceFactoryMP3
+
+eServiceFactoryMP3::eServiceFactoryMP3(): ref(0)
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->addServiceFactory(eServiceFactoryMP3::id, this);
+}
+
+eServiceFactoryMP3::~eServiceFactoryMP3()
+{
+ ePtr<eServiceCenter> sc;
+
+ eServiceCenter::getInstance(sc);
+ if (sc)
+ sc->removeServiceFactory(eServiceFactoryMP3::id);
+}
+
+DEFINE_REF(eServiceFactoryMP3)
+
+ // iServiceHandler
+RESULT eServiceFactoryMP3::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+ RESULT res;
+ // check resources...
+ ptr = new eServiceMP3(ref.path.c_str());
+ res = ptr->start();
+ if (res)
+ {
+ ptr = 0;
+ return res;
+ }
+ return 0;
+}
+
+RESULT eServiceFactoryMP3::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
+{
+ ptr=0;
+ return -1;
+}
+
+RESULT eServiceFactoryMP3::list(const eServiceReference &, ePtr<iListableService> &ptr)
+{
+ ptr=0;
+ return -1;
+}
+
+// eServiceMP3
+
+eServiceMP3::eServiceMP3(const char *filename): filename(filename), ref(0)
+{
+ printf("MP3: %s start\n", filename);
+}
+
+eServiceMP3::~eServiceMP3()
+{
+ printf("MP3: %s stop\n", filename.c_str());
+}
+
+void eServiceMP3::AddRef()
+{
+ ++ref;
+}
+
+void eServiceMP3::Release()
+{
+ if (!--ref)
+ delete this;
+}
+
+RESULT eServiceMP3::start() { printf("mp3 starts\n"); return 0; }
+RESULT eServiceMP3::getIPausableService(ePtr<iPauseableService> &ptr) { ptr=this; return 0; }
+
+ // iPausableService
+RESULT eServiceMP3::pause() { printf("mp3 pauses!\n"); return 0; }
+RESULT eServiceMP3::unpause() { printf("mp3 unpauses!\n"); return 0; }
+
+
+eAutoInitP0<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
diff --git a/lib/service/servicemp3.h b/lib/service/servicemp3.h
new file mode 100644
index 00000000..0f2c074f
--- /dev/null
+++ b/lib/service/servicemp3.h
@@ -0,0 +1,42 @@
+#ifndef __servicemp3_h
+#define __servicemp3_h
+
+#include <lib/service/iservice.h>
+
+class eServiceFactoryMP3: public virtual iServiceHandler, public virtual iObject
+{
+DECLARE_REF;
+public:
+ eServiceFactoryMP3();
+ virtual ~eServiceFactoryMP3();
+ enum { id = 0x1001 };
+
+ // iServiceHandler
+ RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+ RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+ RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+};
+
+class eServiceMP3: public virtual iPlayableService, public virtual iPauseableService, public virtual iObject
+{
+ friend class eServiceFactoryMP3;
+ std::string filename;
+ eServiceMP3(const char *filename);
+ int ref;
+public:
+ virtual ~eServiceMP3();
+
+ // iObject
+ void AddRef();
+ void Release();
+
+ // iPlayableService
+ RESULT start();
+ RESULT getIPausableService(ePtr<iPauseableService> &ptr);
+
+ // iPausableService
+ RESULT pause();
+ RESULT unpause();
+};
+
+#endif