From bb32129d6e36f46f82218d167a6c363a30876eb9 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 23 Dec 2008 17:27:32 +0000 Subject: [PATCH] Vogel Media Player 2008-11-28 --- Makefile | 40 +++- media.c | 536 +++++++++++++++++++++++++++++++++++---------- media.h | 230 ++++++++++++++++--- mediafile.c | 223 +++++++++++++++++++ mediafile.h | 129 +++++++++++ medialauncher.c | 288 ++++++++++++++++++++++++ medialauncher.h | 71 ++++++ mediaplayer.c | 197 +++++++++++++++++ mediaplayer.h | 116 ++++++++++ mediaprovider.h | 129 +++++++++++ mediaproviderids.h | 59 +++++ serialize.c | 441 +++++++++++++++++++++++++++++++++++++ serialize.h | 238 ++++++++++++++++++++ servermediafile.c | 268 +++++++++++++++++++++++ servermediafile.h | 57 +++++ vdrcommand.h | 163 ++++++++++++++ vompclient.c | 7 +- vompclient.h | 9 +- vompclientrrproc.c | 303 +++++++++++++------------ vompclientrrproc.h | 8 +- 20 files changed, 3219 insertions(+), 293 deletions(-) create mode 100644 mediafile.c create mode 100644 mediafile.h create mode 100644 medialauncher.c create mode 100644 medialauncher.h create mode 100644 mediaplayer.c create mode 100644 mediaplayer.h create mode 100644 mediaprovider.h create mode 100644 mediaproviderids.h create mode 100644 serialize.c create mode 100644 serialize.h create mode 100644 servermediafile.c create mode 100644 servermediafile.h create mode 100644 vdrcommand.h diff --git a/Makefile b/Makefile index 9b05004..bb492dd 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,11 @@ VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ pri ### The C++ compiler and options: CXX ?= g++ -CXXFLAGS ?= -O2 -fPIC -Wall -Woverloaded-virtual -Werror +ifdef DEBUG +CXXFLAGS ?= -g -fPIC -Wall -Woverloaded-virtual #-Werror +else +CXXFLAGS ?= -O2 -fPIC -Wall -Woverloaded-virtual #-Werror +endif ### The directory environment: @@ -28,6 +32,9 @@ TMPDIR = /tmp -include $(VDRDIR)/Make.config +### read standlone settings if there +-include .standalone + ### The version number of VDR (taken from VDR's "config.h"): VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') @@ -42,14 +49,17 @@ PACKAGE = vdr-$(ARCHIVE) INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DVOMPSERVER ### The object files (add further files here): OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o i18n.o vompclient.o tcp.o \ ringbuffer.o mvprelay.o vompclientrrproc.o \ - recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o \ - media.o responsepacket.o + config.o log.o thread.o tftpclient.o \ + media.o responsepacket.o \ + mediafile.o mediaplayer.o servermediafile.o serialize.o medialauncher.o + +OBJS2 = recplayer.o mvpreceiver.o ### Implicit rules: @@ -67,12 +77,25 @@ $(DEPFILE): Makefile ### Targets: -all: libvdr-$(PLUGIN).so +all: allbase libvdr-$(PLUGIN).so +standalone: standalonebase vompserver-standalone + +objectsstandalone: $(OBJS) +objects: $(OBJS) $(OBJS2) -libvdr-$(PLUGIN).so: $(OBJS) - $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ +allbase: + ( if [ -f .standalone ] ; then ( rm -f .standalone; make clean ; make objects ) ; else exit 0 ;fi ) +standalonebase: + ( if [ ! -f .standalone ] ; then ( make clean; echo "DEFINES+=-DVOMPSTANDALONE" > .standalone; echo "DEFINES+=-D_FILE_OFFSET_BITS=64" >> .standalone; make objectsstandalone ) ; else exit 0 ;fi ) + +libvdr-$(PLUGIN).so: objects + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(OBJS2) -o $@ @cp $@ $(LIBDIR)/$@.$(APIVERSION) +vompserver-standalone: objectsstandalone + $(CXX) $(CXXFLAGS) $(OBJS) -lpthread -o $@ + chmod u+x $@ + dist: clean @-rm -rf $(TMPDIR)/$(ARCHIVE) @mkdir $(TMPDIR)/$(ARCHIVE) @@ -82,4 +105,5 @@ dist: clean @echo Distribution package created as $(PACKAGE).tgz clean: - rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ + rm -f $(OBJS) $(OBJS2) $(DEPFILE) libvdr*.so.* *.tgz core* *~ .standalone vompserver-standalone + diff --git a/media.c b/media.c index 3b30baa..50df656 100644 --- a/media.c +++ b/media.c @@ -15,143 +15,451 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "media.h" -#include -#include -#include -#include +#include +#include +#ifndef SNPRINTF +#define SNPRINTF snprintf +#endif +MediaURI::MediaURI(const MediaURI *cp) { + if ( ! cp) { + _providerId=0; + _name=NULL; + _display=NULL; + _allowedTypes=MEDIA_TYPE_ALL; + } + else { + _providerId=cp->_providerId; + _allowedTypes=cp->_allowedTypes; + _name=NULL; + if (cp->_name) { + _name=new char[strlen(cp->_name)+1]; + strcpy(_name,cp->_name); + } + _display=NULL; + if (cp->_display) { + _display=new char[strlen(cp->_display)+1]; + strcpy(_display,cp->_display); + } + } +} +MediaURI::MediaURI(ULONG p, const char * n, const char * dp) { + _allowedTypes=MEDIA_TYPE_ALL; + _providerId=p; + if (n) { + _name=new char[strlen(n)+1]; + strcpy(_name,n); + } else { + _name=NULL; + } + _display=NULL; + if (dp) { + _display=new char[strlen(dp)+1]; + strcpy(_display,dp); + } +} -Media::Media(int type, const char * filename, int time){ - _filename=NULL; - if (filename) { - int len=strlen(filename)+1; - _filename=new char[len]; - strcpy(_filename,filename); - } - _type=type; - _time=time; - }; +int MediaURI::getSerializedLenImpl() { + int rt=4+4; //provider+allowedType + rt+=getSerializedStringLen(_name); + rt+=getSerializedStringLen(_display); + return rt; +} +/** + * 4 provider + * 4 allowedType + * 4 namelen (incl. 0) + * name+0 + * 4 displaylen (incl. 0) + * display+0 + */ +int MediaURI::serializeImpl(SerializeBuffer *b) { + version=1; + if (b->encodeLong(_providerId) != 0) return -1; + if (b->encodeLong(_allowedTypes) != 0) return -1; + if (b->encodeString(_name) != 0) return -1; + if (b->encodeString(_display) != 0) return -1; + return 0; +} + +int MediaURI::deserializeImpl(SerializeBuffer *b) { + if (_name) delete _name; + _name=NULL; + if (_display) delete _display; + _display=NULL; + if (b->decodeLong(_providerId) != 0) return -1; + if (b->decodeLong(_allowedTypes) != 0) return -1; + ULONG nlen=0; + if (b->decodeString(nlen,_name) != 0) return -1; + if (b->decodeString(nlen,_display) != 0) return -1; + //if (version > 1) ... + return 0; +} + + + + +int MediaInfo::getSerializedLenImpl() { + int rt=8+1+4+4; //8len+1canPos+4type+4subtype + return rt; +} + + +/** + * serialize to buffer + * 8 len + * 1 canPos + * 4 type + * 4 subtype + */ +int MediaInfo::serializeImpl(SerializeBuffer *b) { + if (b->encodeLongLong(size) != 0) return -1; + if (b->encodeByte(canPosition?1:0) != 0) return -1; + if (b->encodeLong(type) != 0) return -1; + if (b->encodeLong(subtype) != 0) return -1; + return 0; +} +/** + * deserialize + * should be compatible to older serialize functions + */ +int MediaInfo::deserializeImpl(SerializeBuffer *b) { + if (b->decodeLongLong(size) != 0) return -1; + UCHAR cp=0; + if (b->decodeByte(cp) != 0) return -1; + canPosition=cp!=0; + if (b->decodeLong(type) != 0) return -1; + if (b->decodeLong(subtype) != 0) return -1; + return 0; +} + + + +Media::Media() +{ + mtime = 0; + displayName = NULL; + fileName = NULL; + mediaType=MEDIA_TYPE_UNKNOWN; + uri=NULL; + index=0; +} -Media::~Media(){ - delete _filename; - _filename=NULL; - }; +Media::Media(const Media *m) { + Media(); + if (! m) return; + mtime=m->mtime; + mediaType=m->mediaType; + uri=NULL; + fileName=NULL; + displayName=NULL; + if (m->uri) uri=new MediaURI(m->uri); + setFileName(m->fileName); + setDisplayName(m->displayName); + index=m->index; +} + +Media::~Media() +{ + if (displayName) { delete[] displayName; displayName = NULL; } + if (fileName) { delete[] fileName; fileName = NULL; } + if (uri) delete uri; + index = -1; // just in case +} + +ULONG Media::getTime() const +{ + return mtime; +} + +const char* Media::getDisplayName() const +{ + if (displayName) return displayName; + return fileName; +} + +const char* Media::getFileName() const +{ + return fileName; +} + +void Media::setTime(ULONG tstartTime) +{ + mtime = tstartTime; +} + +void Media::setMediaType(ULONG mtype) +{ + mediaType=mtype; +} + +ULONG Media::getMediaType() const +{ + return mediaType; +} + +void Media::setDisplayName(const char* tDisplayName) +{ + if (displayName) delete[] displayName; + displayName=NULL; + if (! tDisplayName) return; + displayName = new char[strlen(tDisplayName) + 1]; + if (displayName) strcpy(displayName, tDisplayName); +} + +void Media::setFileName(const char* tFileName) +{ + if (fileName) delete[] fileName; + fileName=NULL; + if (! tFileName) return; + fileName = new char[strlen(tFileName) + 1]; + if (fileName) strcpy(fileName, tFileName); +} -const char * Media::getFilename() { - return _filename; +bool Media::hasDisplayName() const { + return (displayName != NULL); +} + +char * Media::getTimeString(char * buffer) const { + if (! buffer) buffer=new char[TIMEBUFLEN]; + struct tm ltime; + time_t tTime = (time_t)getTime(); + struct tm *btime = localtime(&tTime); + memcpy(<ime,btime, sizeof(struct tm)); + btime=<ime; + if (btime && tTime != 0) { +#ifndef _MSC_VER + strftime(buffer,TIMEBUFLEN, "%0g/%0m/%0d %0H:%0M ", btime); +#else + strftime(buffer, TIMEBUFLEN, "%g/%m/%d %H:%M ", btime); +#endif } + else { + SNPRINTF(buffer,TIMEBUFLEN,"00/00/00 00:00 "); + } + return buffer; +} + +const MediaURI * Media::getURI() const { + return uri; +} + +void Media::setURI(const MediaURI *u) { + if (uri) delete uri; + uri=new MediaURI(u); +} + +int Media::getSerializedLenImpl() { + int rt=4+4+1; //type,time,hasURI + rt+=getSerializedStringLen(fileName); + rt+=getSerializedStringLen(displayName); + if (uri) rt+=uri->getSerializedLen(); + return rt; +} +/** + * 4 type + * 4 time + * 4 namelen (incl. 0) + * name+0 + * 4 displaylen (incl. 0) + * display+0 + * 1 hasURI + * URI + */ +int Media::serializeImpl(SerializeBuffer *b) { + if (b->encodeLong(mediaType) != 0) return -1; + if (b->encodeLong(mtime) != 0) return -1; + if (b->encodeString(fileName) != 0) return -1; + if (b->encodeString(displayName) != 0) return -1; -int Media::getType() { - return _type; + if (b->encodeByte(uri?1:0) != 0) return -1; + if (uri) { + if (uri->serialize(b) != 0) return -1; } -int Media::getTime() { - return _time; + return 0; +} + +int Media::deserializeImpl(SerializeBuffer *b) { + if (fileName) delete fileName; + fileName=NULL; + if (displayName) delete displayName; + displayName=NULL; + if (uri) delete uri; + uri=NULL; + if (b->decodeLong(mediaType) != 0) return -1; + if (b->decodeLong(mtime) != 0) return -1; + ULONG nlen=0; + if (b->decodeString(nlen,fileName) != 0) return -1; + if (b->decodeString(nlen,displayName) != 0) return -1; + UCHAR hasURI=0; + if (b->decodeByte(hasURI) != 0) return -1; + if (hasURI!=0) { + uri=new MediaURI(); + if (uri->deserialize(b) != 0) return -1; } + return 0; +} -static struct mtype{ - const char* extension; - int type; - } mediatypes[]= { - {".mp3",MEDIA_TYPE_AUDIO}, - {".MP3",MEDIA_TYPE_AUDIO}, - {".jpg",MEDIA_TYPE_PICTURE}, - {".JPG",MEDIA_TYPE_PICTURE}, - {".jpeg",MEDIA_TYPE_PICTURE}, - {".JPEG",MEDIA_TYPE_PICTURE} - }; -//#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype)) -#define NUMTYPES 6 -//helper from vdr tools.c -bool endswith(const char *s, const char *p) -{ - const char *se = s + strlen(s) - 1; - const char *pe = p + strlen(p) - 1; - while (pe >= p) { - if (*pe-- != *se-- || (se < s && pe >= p)) - return false; - } - return true; -} - - -MediaList * MediaList::readList(Config * cfg,const char * dirname, int type) { - MediaList *rt=NULL; - if (dirname == NULL) { - //the configured Media List - //for the moment up to 10 entries [Media] Dir.1 ...Dir.10 - for (int nr=1;nr<=10;nr++){ - char buffer[20]; - sprintf(buffer,"Dir.%d",nr); - const char * dn=cfg->getValueString("Media",buffer); - if (dn != NULL) { - if (rt == NULL) rt=new MediaList(); - Media *m=new Media(MEDIA_TYPE_DIR,dn,0); - rt->push_back(m); - Log::getInstance()->log("Media",Log::DEBUG,"added base dir %s",dn); - } - } - } - if (rt != NULL) return rt; - //if nothing is configured, we start at / - if (dirname == NULL) dirname="/"; - rt=new MediaList(); - //open the directory and read out the entries - DIR *d=opendir(dirname); - struct dirent *e; - union { // according to "The GNU C Library Reference Manual" - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - - while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) { - { - const char * fname=e->d_name; - if ( fname == NULL) continue; - if (strcmp(fname,".") == 0) continue; - char *buffer; - asprintf(&buffer, "%s/%s", dirname, e->d_name); - struct stat st; - int mtype=MEDIA_TYPE_UNKNOWN; - if (stat(buffer, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - mtype=MEDIA_TYPE_DIR; - } - else { - for (int i=0;ipush_back(m); - Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,mtype); - } +MediaURI * MediaList::getURI(Media * m) { + if (! m) return NULL; + const MediaURI *rtc=m->getURI(); + if (rtc) return new MediaURI(rtc); + if (!_root) return NULL; + if (! m->getFileName()) return NULL; + int len=strlen(m->getFileName()); + if (_root->getName()) len+=strlen(_root->getName())+1; + MediaURI *rt=new MediaURI(); + rt->_name=new char[len+1]; + const char *fn=m->getFileName(); + if (_root->getName()) { + while (*fn=='/') fn++; + sprintf(rt->_name,"%s/%s",_root->getName(),fn); + } + else { + sprintf(rt->_name,"%s",fn); + } + if (m->hasDisplayName() || _root->hasDisplayName()) { + len=strlen(m->getDisplayName())+1; + if (_root->hasDisplayName()) { + len+=strlen(_root->getDisplayName())+2; + } + rt->_display=new char[len]; + if (_root->hasDisplayName()) { + const char *sp=m->getDisplayName(); + if (*sp=='/')sp++; + sprintf(rt->_display,"%s/%s",_root->getDisplayName(),sp); + } + else { + sprintf(rt->_display,"%s",m->getDisplayName()); } } - if (d != NULL) closedir(d); + rt->_providerId=_root->_providerId; + rt->_allowedTypes=_root->_allowedTypes; return rt; +} + +MediaURI * MediaList::getParent(MediaURI *c) { + MediaURI * rt=new MediaURI(); + rt->_providerId=c->_providerId; + rt->_allowedTypes=c->_allowedTypes; + ULONG nlen=0; + if (c->_name) { + char * ls=strrchr(c->_name,'/'); + if (ls) { + nlen=ls-c->_name; + rt->_name=new char[nlen+1]; + strncpy(rt->_name,c->_name,nlen); + rt->_name[nlen]=0; + } + } + if (c->_display) { + char * ls=strrchr(c->_display,'/'); + if (ls) { + nlen=ls-c->_display; + rt->_display=new char[nlen+1]; + strncpy(rt->_display,c->_display,nlen); + rt->_display[nlen]=0; + } } + return rt; +} + + +MediaList::MediaList(const MediaURI *root) { + _root=new MediaURI(root); + _owning=true; +} + MediaList::~MediaList() { - MediaList::iterator it=this->begin(); - while (it < this->end()) { - delete *it; - it++; + emptyList(); +} +void MediaList::emptyList(){ + if (_owning) { + for (UINT i = 0; i < size(); i++) + { + delete (*this)[i]; + } } + clear(); + if (_root) delete _root; + _root=NULL; + _owning=true; +} + + +MediaURI * MediaList::getRootURI() { + if ( ! _root) return NULL; + return new MediaURI(_root); +} + +ULONG MediaList::getProvider() { + if (! _root) return 0; + return _root->getProvider(); } +void MediaList::setOwning(bool owning) { + _owning=owning; +} + + + +int MediaList::getSerializedLenImpl() { + int rt=4+1; //numelem+hasRoot + if (_root) rt+=_root->getSerializedLen(); + for (MediaList::iterator it=begin();itgetSerializedLen(); + } + return rt; +} + +/** + * 4 numelem + * 1 hasRoot + * URI root + * nx Media elements + * + */ +int MediaList::serializeImpl(SerializeBuffer *b) { + if (b->encodeLong(size()) != 0) return -1; + if (b->encodeByte(_root?1:0) != 0) return -1; + if (_root) { + if (_root->serialize(b) != 0) return -1; + } + for (MediaList::iterator it=begin();itserialize(b) !=0) return -1; + } + return 0; +} + +int MediaList::deserializeImpl(SerializeBuffer *b) { + emptyList(); + ULONG numelem; + if (b->decodeLong(numelem) != 0) return -1; + UCHAR hasRoot=0; + if (b->decodeByte(hasRoot) != 0) return -1; + if (hasRoot!=0) { + _root=new MediaURI(); + if (_root->deserialize(b) != 0) return -1; + } + for (ULONG i=0;ideserialize(b) != 0) { + delete m; + return -1; + } + push_back(m); + } + return 0; +} + + diff --git a/media.h b/media.h index e058d66..67e9e34 100644 --- a/media.h +++ b/media.h @@ -15,63 +15,229 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MEDIA_H #define MEDIA_H -#include -#include -#include -#include - -#include // sleep -#include - using namespace std; -//#include "defines.h" -//#include "tcp.h" -//#include "mvpreceiver.h" -//#include "recplayer.h" -#include "config.h" +#include +#include +#include +#include "defines.h" +#include "serialize.h" -//the following defines must be consisten to the client side /* media types form a bitmask so you can add them to have > 1*/ #define MEDIA_TYPE_DIR 1 #define MEDIA_TYPE_AUDIO 2 #define MEDIA_TYPE_VIDEO 4 #define MEDIA_TYPE_PICTURE 8 -#define MEDIA_TYPE_UNKNOWN 256 +#define MEDIA_TYPE_UNKNOWN 0 #define MEDIA_TYPE_ALL (1+2+4+8) -class Media -{ +/** + * MediaURI - a data holder for the complete path to a media + * depending on the provider there is an internal name and a display name + * by providing own MediaList implementations the provider can control + * how URIs are concatenated + */ +class MediaURI : public Serializable{ + //to be able to access private members + friend class MediaList; + private: + char * _name; + char * _display; + ULONG _providerId; + ULONG _allowedTypes; public: + MediaURI() { + _name=NULL; + _display=NULL; + _providerId=0; + _allowedTypes=MEDIA_TYPE_ALL; + } + //constructor copying params + MediaURI(ULONG provider, const char * name, const char * display); + virtual ~MediaURI() { + if (_name) delete _name; + if (_display) delete _display; + } + MediaURI(const MediaURI *cp) ; + const char * getName() const { return _name;} + const char * getDisplayName() const { + if (_display) return _display; + return _name; + } + ULONG getProvider() const { + return _providerId; + } + void setProvider(ULONG pid) { + _providerId=pid; + } + ULONG getAllowedTypes() const { + return _allowedTypes; + } + void setAllowedTypes(ULONG allowedTypes) { + _allowedTypes=allowedTypes; + } + bool hasDisplayName() const { + return _display!=NULL; + } + + //serialize functions + //get the #of bytes needed to serialize + virtual int getSerializedLenImpl(); + //serialize + //advance buffer, check if >= end + //return 0 if OK + virtual int serializeImpl(SerializeBuffer *b); + //deserialize + //advance buffer, check if >= end + //return 0 if OK + virtual int deserializeImpl(SerializeBuffer *b); + +}; + +/** + * a class providing additional info for a medium + */ +class MediaInfo : public Serializable{ + public: + ULLONG size; + bool canPosition; + ULONG type; //a media type + ULONG subtype; //TODO /** - * create a media entry - * filename will get copied + * return any info item contained within this info */ - Media(int type, const char * filename, int time); - ~Media(); - const char * getFilename(); - int getType(); - int getTime(); + virtual const char * getInfo(ULONG infoId) { return NULL;} + virtual ULLONG getIntegerInfo(ULONG infoId) { return 0;} + virtual const char * getInfoName(ULONG infoId) { return NULL;} + virtual bool hasInfo(ULONG infoId) { return false;} + MediaInfo() { + size=0; + canPosition=true; + type=MEDIA_TYPE_UNKNOWN; + subtype=0; + } + virtual ~MediaInfo(){}; + //serialize functions + //get the #of bytes needed to serialize + virtual int getSerializedLenImpl(); + //serialize + //advance buffer, check if >= end + //return 0 if OK + virtual int serializeImpl(SerializeBuffer *b); + //deserialize + //advance buffer, check if >= end + //return 0 if OK + virtual int deserializeImpl(SerializeBuffer *b); +}; + +/** + * the Media class - a data holder describing a single media + * WITHOUT the complete path + * to retrieve an URI you need the list where this media is contained + * this has the root URI and can construct the URI for this media + * optional the media can contain an UIR by itself - then this is used + */ + +class Media : public Serializable +{ + friend class MediaList; + public: + Media(); + Media(const Media *m); + virtual ~Media(); + + void setTime(ULONG mtimeTime); + void setDisplayName(const char* displayName); + void setFileName(const char* fileName); + void setMediaType(ULONG mtype); + + ULONG getTime() const; + const char* getDisplayName() const; + const char* getFileName() const; + //return the time as a string + //if the user provides a buffer, this one is used, if NULL + //is given a new buffer is allocated + //caller must delete the buffer after usage! + char * getTimeString(char *buffer) const; + //length for the time display buffer + const static int TIMEBUFLEN=100; + int index; + ULONG getMediaType() const; + bool hasDisplayName() const; + //optionally the media can contain an URI + //in this case the filename is not considered + //but the data from the URI is taken + //this enables having another providerId set in the media... + //returns URI without copy + const MediaURI * getURI() const; + void setURI(const MediaURI *uri); + + //serialize functions + //get the #of bytes needed to serialize + virtual int getSerializedLenImpl(); + //serialize + //advance buffer, check if >= end + //return 0 if OK + virtual int serializeImpl(SerializeBuffer *b); + //deserialize + //advance buffer, check if >= end + //return 0 if OK + virtual int deserializeImpl(SerializeBuffer *b); + private: - char * _filename; - int _type; - int _time; + ULONG mtime; + char* displayName; + char* fileName; + ULONG mediaType; + MediaURI *uri; }; -class MediaList : public vector { + +typedef vector MediaListI; + +/** + * the MediaList - containing a root URI and + * all the Media entries + * providers can provide derived classes to overwrite the URI-Methods + */ +class MediaList : public MediaListI , public Serializable{ + private: + MediaURI *_root; + bool _owning; + void emptyList(); public: - static MediaList *readList(Config *cfg,const char * dirname,int type=MEDIA_TYPE_ALL); - ~MediaList(); - }; + MediaList(const MediaURI *root); //root is copied + virtual ~MediaList(); + //no copy root UIR + virtual MediaURI * getRoot() {return _root;} + //all methods return a copy of the URI + //so the caller has to destroy this + virtual MediaURI * getRootURI(); + virtual MediaURI * getParent(MediaURI *c) ; + virtual MediaURI * getURI(Media *m); + virtual ULONG getProvider(); + virtual void setOwning(bool owning); + //serialize functions + //get the #of bytes needed to serialize + virtual int getSerializedLenImpl(); + //serialize + //advance buffer, check if >= end + //return 0 if OK + virtual int serializeImpl(SerializeBuffer *b); + //deserialize + //advance buffer, check if >= end + //return 0 if OK + virtual int deserializeImpl(SerializeBuffer *b); + }; #endif diff --git a/mediafile.c b/mediafile.c new file mode 100644 index 0000000..0138cc3 --- /dev/null +++ b/mediafile.c @@ -0,0 +1,223 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mediafile.h" +#include "media.h" +#include +#include +#include +#include +#include +#include "log.h" + + + + +MediaFile::MediaFile(ULONG pid){ + providerid=pid; +} + +MediaFile::~MediaFile(){ + }; + + + +static struct mtype{ + const char* extension; + ULONG type; + } mediatypes[]= { + {".mp3",MEDIA_TYPE_AUDIO}, + {".MP3",MEDIA_TYPE_AUDIO}, + {".jpg",MEDIA_TYPE_PICTURE}, + {".JPG",MEDIA_TYPE_PICTURE}, + {".jpeg",MEDIA_TYPE_PICTURE}, + {".JPEG",MEDIA_TYPE_PICTURE}, + {".mpg",MEDIA_TYPE_VIDEO}, + {".MPG",MEDIA_TYPE_VIDEO} + }; +//#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype)) +#define NUMTYPES 8 + +//helper from vdr tools.c +bool endswith(const char *s, const char *p) +{ + const char *se = s + strlen(s) - 1; + const char *pe = p + strlen(p) - 1; + while (pe >= p) { + if (*pe-- != *se-- || (se < s && pe >= p)) + return false; + } + return true; +} + +MediaList* MediaFile::getRootList() { + //has to be implemented in the derived class + return NULL; +} + +ULONG MediaFile::getMediaType(const char * filename) { + for (ULONG i=0;isetMediaType(mtype); + rt->setFileName(filename); + rt->setTime(st.st_mtime); + Log::getInstance()->log("Media",Log::DEBUG,"created Media %s, type=%d",filename,mtype); + if (withURI) { + MediaURI u(providerid,buffer,NULL); + rt->setURI(&u); + } + } + free(buffer); + return rt; +} + +MediaList* MediaFile::getMediaList(const MediaURI * parent){ + ULONG mediaType=parent->getAllowedTypes(); + Log::getInstance()->log("MediaFile::getMediaList",Log::DEBUG,"parent %s,types=0x%0lx",parent->getName(),mediaType); + MediaList *rt=NULL; + rt=new MediaList(parent); + const char *dirname=parent->getName(); + //open the directory and read out the entries + DIR *d=opendir(dirname); + struct dirent *e; + union { // according to "The GNU C Library Reference Manual" + struct dirent d; + char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; + } u; + + while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) { + const char * fname=e->d_name; + if ( fname == NULL) continue; + if (strcmp(fname,".") == 0) continue; + if (strcmp(fname,"..") == 0) continue; + Media *m=createMedia(dirname,fname); + if (m && ( m->getMediaType() & mediaType)) { + Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,m->getMediaType()); + rt->push_back(m); + } + else { + if (m) delete m; + } + } + if (d != NULL) closedir(d); + return rt; + } + + +int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) { + Log::getInstance()->log("Media::openMedium",Log::DEBUG,"fn=%s,chan=%u",uri->getName(),channel); + *size=0; + if (channel <0 || channel >= NUMCHANNELS) return -1; + struct ChannelInfo *info=&channels[channel]; + if (info->file) info->reset(); + FILE *fp=fopen(uri->getName(),"r"); + if (! fp) { + Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel); + return -1; + } + struct stat st; + ULLONG mysize=0; + if ( fstat(fileno(fp),&st) == 0) mysize=st.st_size; + if (mysize == 0) { + Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel); + fclose(fp); + return -1; + } + info->setFilename(uri->getName()); + info->file=fp; + info->size=mysize; + *size=mysize; + info->provider=providerid; + return 0; +} + + +int MediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer) { + Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"chan=%u,offset=%llu,len=%lu",channel,offset,len); + *outlen=0; + if (channel <0 || channel >= NUMCHANNELS) return -1; + struct ChannelInfo *info=&channels[channel]; + if (! info->file) { + Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"not open chan=%u",channel); + return -1; + } + ULLONG cpos=ftell(info->file); + if (offset != cpos) { + fseek(info->file,offset-cpos,SEEK_CUR); + } + if (offset != (ULLONG)ftell(info->file)) { + Log::getInstance()->log("Client", Log::DEBUG, "getMediaBlock pos = %llu not available", offset); + return -1; + } + if (*buffer == NULL) *buffer=(UCHAR *)malloc(len); + if (*buffer == NULL) { + Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"uanble to allocate buffer"); + return -1; + } + ULONG amount=fread(*buffer,1,len,info->file); + Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"readlen=%lu",amount); + *outlen=amount; + return 0; +} + + +int MediaFile::closeMediaChannel(ULONG channel){ + Log::getInstance()->log("Media::closeMediaChannel",Log::DEBUG,"chan=%u",channel); + if (channel <0 || channel >= NUMCHANNELS) return -1; + struct ChannelInfo *info=&channels[channel]; + info->reset(); + return 0; +} + +//TODO: fill in more info +int MediaFile::getMediaInfo(ULONG channel, MediaInfo * result){ + Log::getInstance()->log("Media::getMediaInfo",Log::DEBUG,"chan=%u",channel); + if (channel <0 || channel >= NUMCHANNELS) return -1; + struct ChannelInfo *info=&channels[channel]; + if (! info->file) return -1; + result->size=info->size; + result->canPosition=true; + return 0; +} diff --git a/mediafile.h b/mediafile.h new file mode 100644 index 0000000..a83983d --- /dev/null +++ b/mediafile.h @@ -0,0 +1,129 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIAFILE_H +#define MEDIAFILE_H + +#include "defines.h" +#include "mediaprovider.h" + + +class MediaFile : public MediaProvider +{ + public: + MediaFile(ULONG providerId); + virtual ~MediaFile(); + /** + * get the root media list + * the returned list has to be destroyed by the caller + * if NULL is returned currently no media is available + */ + virtual MediaList* getRootList(); + + /** + * get a medialist for a given parent + * the returned list has to be destroyed by the caller + * NULL if no entries found + */ + virtual MediaList* getMediaList(const MediaURI * parent); + + /** + * open a media uri + * afterwards getBlock or other functions must be possible + * currently only one medium is open at the same time + * for a given channel + * @param channel: channel id, NUMCHANNELS must be supported + * @param xsize,ysize: size of the screen + * @param size out: the size of the medium + * @return != 0 in case of error + * + */ + virtual int openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize); + + /** + * get a block for a channel + * @param offset - the offset + * @param len - the required len + * @param outlen out - the read len if 0 this is EOF + * @param buffer out the allocated buffer (must be freed with free!) + * @return != 0 in case of error + */ + virtual int getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer); + + /** + * close a media channel + */ + virtual int closeMediaChannel(ULONG channel); + + /** + * return the media info for a given channel + * return != 0 on error + * the caller has to provide a pointer to an existing media info + */ + virtual int getMediaInfo(ULONG channel, MediaInfo * result); + + + protected: + /** + * create a Media out of a given file + * the Media object ha sto be deleted by the caller + * return NULL if not there or no matching type + */ + Media * createMedia(const char * dirname, const char * filename, bool withURI=false); + struct ChannelInfo { + public: + FILE *file; + ULONG provider; + char *filename; + ULLONG size; + ChannelInfo(){ + file=NULL; + provider=0; + filename=NULL; + size=0; + } + ~ChannelInfo(){ + if (filename) delete[]filename; + if (file) fclose(file); + } + void setFilename(const char *f) { + if (filename) delete[] filename; + filename=NULL; + if (f) { + filename=new char[strlen(f)+1]; + strcpy(filename,f); + } + } + void reset() { + if (file) fclose(file); + file=NULL; + if (filename) delete [] filename; + filename=NULL; + } + }; + struct ChannelInfo channels[NUMCHANNELS]; + ULONG providerid; + + virtual ULONG getMediaType(const char *filename); + +}; + +#endif diff --git a/medialauncher.c b/medialauncher.c new file mode 100644 index 0000000..45dfff6 --- /dev/null +++ b/medialauncher.c @@ -0,0 +1,288 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "medialauncher.h" +#include "media.h" +#include +#include "log.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAXCMD 50 + +MediaLauncher::MediaLauncher(Config *c) { + cfg=c; + numcommands=0; + commands=NULL; + pnum=-1; + child=-1; +} + +MediaLauncher::~MediaLauncher(){ + if (commands) { + for (int i=0;ilog("MediaLauncher",Log::DEBUG,"init"); + + commands=new Pcmd[MAXCMD]; + char buf[100]; + for(int i=1;i<=MAXCMD;i++){ + sprintf(buf,"Command.Name.%d",i); + const char *cmname=cfg->getValueString("Media",buf); + if (!cmname) continue; + sprintf(buf,"Command.Extension.%d",i); + const char *cmext=cfg->getValueString("Media",buf); + if (!cmext) continue; + sprintf(buf,"Command.Type.%d",i); + const char *cmtype=cfg->getValueString("Media",buf); + if (! cmtype) continue; + ULONG cmtypeid=typeIdFromName(cmtype); + if (cmtypeid == MEDIA_TYPE_UNKNOWN) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unknown media type %s",cmtype); + continue; + } + commands[numcommands]=new MCommand(cmname,cmtypeid,cmext); + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found command %s for ext %s, type %s",cmname,cmext,cmtype); + //check the command + char cbuf[strlen(cmname)+40]; + sprintf(cbuf,"%s check",cmname); + int rt=system(cbuf); + if (rt != 0) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"testting command %s failed, ignore",cmname); + continue; + } + numcommands++; + } + + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found %d commands",numcommands); + return 0; +} + +int MediaLauncher::init(MediaLauncher *cp) { + commands=new Pcmd[MAXCMD]; + for (int i=0;inumcommands;i++) { + commands[i]=new MCommand(cp->commands[i]->command,cp->commands[i]->mediaType,cp->commands[i]->extension); + } + numcommands=cp->numcommands; + return 0; +} + + + +int MediaLauncher::findCommand(const char *name){ + const char *ext=name+strlen(name); + while (*ext != '.' && ext > name) ext--; + if (*ext == '.') ext++; + //Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found extension %s for name %s",ext,name); + for (int i=0;iextension) == 0) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"found command %s to handle name %s",commands[i]->command,name); + return i; + } + } + return -1; +} + +ULONG MediaLauncher::getTypeForName(const char *name) { + int rt=findCommand(name); + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"getTypeForName %s entry %d",name,rt); + if (rt>=0) return commands[rt]->mediaType; + return MEDIA_TYPE_UNKNOWN; +} + +int MediaLauncher::openStream(const char *fname,ULONG xsize,ULONG ysize,const char * command) { + if (command == NULL) command="play"; + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"open stream for %s command %s",fname,command); + int cmnum=findCommand(fname); + if (cmnum < 0) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to find command for %s",fname); + return -1; + } + if (pnum >= 0) closeStream(); + int pfd[2]; + if (pipe(pfd) == -1) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to create pipe"); + return -1; + } + pnum=pfd[0]; + child=fork(); + if (child == -1) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to fork"); + return -1; + } + if (child == 0) { + //we are the child + close(pfd[0]); + dup2(pfd[1],fileno(stdout)); + close(fileno(stdin)); + dup2(pfd[1],fileno(stderr)); + //try to close all open FDs + for (int i=0;i<=sysconf(_SC_OPEN_MAX);i++) { + if (i != fileno(stderr) && i != fileno(stdout)) close(i); + } + char buf1[30]; + char buf2[30]; + sprintf(buf1,"%u",xsize); + sprintf(buf2,"%u",ysize); + execlp(commands[cmnum]->command,commands[cmnum]->command,command,fname,buf1,buf2,NULL); + //no chance for logging here after close... Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to execlp %s",commands[cmnum]->command); + exit(-1); + } + if (fcntl(pnum,F_SETFL,fcntl(pnum,F_GETFL)|O_NONBLOCK) != 0) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to set to nonblocking"); + closeStream(); + return -1; + } + //the parent + return child; +} + + +int MediaLauncher::closeStream() { + if (child <= 0) return -1; + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"close stream for child %d",child); + close(pnum); + if (kill(child,0) == 0) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"trying to kill child %d",child); + kill(child,SIGINT); + } + waitpid(child,NULL,WNOHANG); + for (int i=0;i< 150;i++) { + if (kill(child,0) == 0) { + usleep(10000); + waitpid(child,NULL,WNOHANG); + } + } + if (kill(child,0) == 0) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"child %d aktive after wait, kill -9",child); + kill(child,SIGKILL); + } + for (int i=0;i< 100;i++) { + if (kill(child,0) == 0) { + usleep(10000); + } + } + waitpid(child,NULL,WNOHANG); + child=-1; + pnum=-1; + return 0; +} + +int MediaLauncher::getNextBlock(ULONG size,unsigned char **buffer,ULONG *readLen) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"get Block buf %p, len %lu",*buffer,size); + if (pnum <= 0) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"stream not open in getnextBlock"); + return -1; + } + *readLen=0; + struct timeval to; + to.tv_sec=0; + to.tv_usec=100000; //100ms + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(pnum,&readfds); + int rt=select(pnum+1,&readfds,NULL,NULL,&to); + if (rt < 0) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"error in select"); + return -1; + } + if (rt == 0) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"read 0 bytes (no data within 100ms)"); + waitpid(child,NULL,WNOHANG); + if (kill(child,0) != 0) { + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"child is dead, returning EOF"); + return 1; + } + return 0; + } + if (! FD_ISSET(pnum,&readfds)) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"error in select - nothing read"); + return -1; + } + if (! *buffer) { + *buffer=(UCHAR *)malloc(size); + } + if (! *buffer) { + Log::getInstance()->log("MediaLauncher",Log::ERR,"unable to allocate buffer"); + return -1; + } + ssize_t rdsz=read(pnum,*buffer,size); + *readLen=(ULONG)rdsz; + Log::getInstance()->log("MediaLauncher",Log::DEBUG,"read %lu bytes",*readLen); + if (rdsz == 0) return 1; //EOF + return 0; +} + +bool MediaLauncher::isOpen() { + return pnum > 0; +} + + + + + + + + + + diff --git a/medialauncher.h b/medialauncher.h new file mode 100644 index 0000000..0bf015f --- /dev/null +++ b/medialauncher.h @@ -0,0 +1,71 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIALAUNCHER_H +#define MEDIALAUNCHER_H + +#include "media.h" +#include "config.h" + + +class MediaLauncher +{ + public: + MediaLauncher(Config *c); + ~MediaLauncher(); + //let the launcher read it's config + //return != 0 if nothing handled + int init(); + //init as a copy of another launcher + int init(MediaLauncher *cp); + //get the type for a file (if the launcher can handle it) + //return MEDIA_TYPE_UNKNOWN if it cannot be handled + ULONG getTypeForName(const char *name); + //open a stream, return PID of child , <0 on error + int openStream(const char *filename,ULONG xsize, ULONG ysize,const char * command=NULL); + //get the next chunk + //if *buffer!= NULL - use this one, else allocate an own (with malloc!) + //return read len (can be 0!) + //return <0 on error, >0 on stream end,0 on OK + int getNextBlock(ULONG size,unsigned char **buffer,ULONG *readLen); + int closeStream(); + bool isOpen(); + + private: + Config *cfg; + class MCommand{ + public: + char *command; + ULONG mediaType; + char *extension; + MCommand(const char *name,ULONG type,const char *ext); + ~MCommand(); + } ; + typedef MCommand *Pcmd; + Pcmd *commands; + int numcommands; + int pnum; + pid_t child; + int findCommand(const char *name); //return -1 if not found + + +}; + +#endif diff --git a/mediaplayer.c b/mediaplayer.c new file mode 100644 index 0000000..1359010 --- /dev/null +++ b/mediaplayer.c @@ -0,0 +1,197 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mediaplayer.h" +#include "media.h" +#include "log.h" + +class MediaProviderHolder { + public: + MediaProvider *provider; + ULONG id; + ULONG range; + MediaProviderHolder(MediaProvider *p,ULONG i, ULONG r=1) { + provider=p; + range=r; + id=i; + } +}; + + + +MediaPlayer::MediaPlayer(){} +MediaPlayer::~MediaPlayer(){ + for (Tplist::iterator it=plist.begin();itlog("MediaPlayer::getRootList",Log::DEBUG,"numproviders %d",plist.size()); + MediaList * rt=new MediaList(new MediaURI(0,NULL,NULL)); + for (Tplist::iterator it=plist.begin();itprovider->getRootList(); + if (cur) { + //we take the entries away from the list - so don't delete them with the list + cur->setOwning(false); + Log::getInstance()->log("MediaPlayer::getRootList",Log::DEBUG,"got list for provider %p with %d items",(*it),cur->size()); + for (MediaList::iterator mi=cur->begin();miend();mi++) { + Media *m=*mi; + //always set the URI in the root list because we combine entries + //from different lists + if (! m->getURI()) { + MediaURI *u=cur->getURI(m); + m->setURI(u); + Log::getInstance()->log("MediaPlayer::getRootList",Log::DEBUG,"set uri n=%s,d=%s",u->getName(),u->getDisplayName()); + delete u; + } + rt->push_back(m); + Log::getInstance()->log("MediaPlayer::getRootList",Log::DEBUG,"added item to list name=%s",m->getFileName()); + } + } + delete cur; + } + return rt; +} + +/** + * get a medialist for a given parent + * the returned list has to be destroyed by the caller + * NULL if no entries found + */ +MediaList* MediaPlayer::getMediaList(const MediaURI * parent){ + Log::getInstance()->log("MediaPlayer::getMediaList",Log::DEBUG,"numproviders %d,parent=%p",plist.size(),parent); + MediaProvider *p=providerById(parent->getProvider()); + if (! p) { + return NULL; + } + return p->getMediaList(parent); +} + +/** + * open a media uri + * afterwards getBlock or other functions must be possible + * currently only one medium is open at the same time + * for a given channel + * @param channel: channel id, NUMCHANNELS must be supported + * @param xsize,ysize: size of the screen + * @param size out: the size of the medium + * @return != 0 in case of error + * + */ +int MediaPlayer::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize){ + if ( channel >= NUMCHANNELS) return -1; + info[channel].provider=NULL; + *size= 0; + MediaProvider *p=providerById(uri->getProvider()); + if (!p) { + return -1; + } + int rt=p->openMedium(channel,uri,size,xsize,ysize); + if (rt == 0) { + info[channel].providerId=uri->getProvider(); + info[channel].provider=p; + } + return rt; + +} + +/** + * get a block for a channel + * @param offset - the offset + * @param len - the required len + * @param outlen out - the read len if 0 this is EOF + * @param buffer out the allocated buffer (must be freed with free!) + * @return != 0 in case of error + */ +int MediaPlayer::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer) { + if ( channel >= NUMCHANNELS) return -1; + if ( info[channel].provider == NULL) return -1; + return info[channel].provider->getMediaBlock(channel,offset,len,outlen,buffer); +} + + +/** + * close a media channel + */ +int MediaPlayer::closeMediaChannel(ULONG channel){ + if ( channel >= NUMCHANNELS) return -1; + if ( info[channel].provider == NULL) return -1; + int rt=info[channel].provider->closeMediaChannel(channel); + info[channel].provider=NULL; + info[channel].providerId=0; + return rt; +} + +/** + * return the media info for a given channel + * return != 0 on error + * the caller has to provide a pointer to an existing media info + */ +int MediaPlayer::getMediaInfo(ULONG channel, struct MediaInfo * result){ + if ( channel >= NUMCHANNELS) return -1; + if ( info[channel].provider == NULL) return -1; + return info[channel].provider->getMediaInfo(channel,result); +} + + + +void MediaPlayer::registerMediaProvider(MediaProvider *p,ULONG providerId,ULONG range) { + if (! p) return; + MediaProviderHolder *h=new MediaProviderHolder(p,providerId,range); + Log::getInstance()->log("MediaPlayer::registerMediaProvider",Log::DEBUG,"p=%p",p); + plist.push_back(h); +} + +MediaProvider * MediaPlayer::providerById(ULONG id) { + MediaProvider *rt=NULL; + for (Tplist::iterator it=plist.begin();it= h->id && id < (h->id+h->range)) { + rt=h->provider; + break; + } + } + Log::getInstance()->log("MediaPlayer::providerById",Log::DEBUG,"id=%d,p=%p",id,rt); + return rt; +} + +MediaPlayer* MediaPlayer::getInstance() { + return (MediaPlayer *) MediaPlayerRegister::getInstance(); +} + +MediaPlayerRegister* MediaPlayerRegister::getInstance() { + if ( ! instance) { + instance=new MediaPlayer(); + } + return instance; +} +MediaPlayerRegister *MediaPlayerRegister::instance=NULL; + + + + + diff --git a/mediaplayer.h b/mediaplayer.h new file mode 100644 index 0000000..de9bab1 --- /dev/null +++ b/mediaplayer.h @@ -0,0 +1,116 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIAPLAYER +#define MEDIAPLAYER + +using namespace std; +#include +#include +#include +#include "mediaprovider.h" + +class MediaProviderHolder; + + +class MediaPlayer : public MediaPlayerRegister, public MediaProvider +{ + public: + MediaPlayer(); + virtual ~MediaPlayer(); + + /** + * get the root media list + * the returned list has to be destroyed by the caller + * if NULL is returned currently no media is available + */ + virtual MediaList* getRootList(); + + /** + * get a medialist for a given parent + * the returned list has to be destroyed by the caller + * NULL if no entries found + */ + virtual MediaList* getMediaList(const MediaURI * parent); + + /** + * open a media uri + * afterwards getBlock or other functions must be possible + * currently only one medium is open at the same time + * for a given channel + * @param channel: channel id, NUMCHANNELS must be supported + * @param xsize,ysize: size of the screen + * @param size out: the size of the medium + * @return != 0 in case of error + * + */ + virtual int openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize); + + /** + * get a block for a channel + * @param offset - the offset + * @param len - the required len + * @param outlen out - the read len if 0 this is EOF + * @param buffer out the allocated buffer (must be freed with free!) + * @return != 0 in case of error + */ + virtual int getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer); + + /** + * close a media channel + */ + virtual int closeMediaChannel(ULONG channel); + + /** + * return the media info for a given channel + * return != 0 on error + * the caller has to provide a pointer to an existing media info + */ + virtual int getMediaInfo(ULONG channel, struct MediaInfo * result); + + /** + * from MediaPlayerRegister + */ + virtual void registerMediaProvider(MediaProvider *p,ULONG providerID,ULONG range); + + /** + * the instance + */ + static MediaPlayer * getInstance(); + + private: + MediaProvider * providerById(ULONG id); + typedef vector Tplist; + Tplist plist; + struct channelInfo { + ULONG providerId; + MediaProvider *provider; + channelInfo() { + provider=NULL; + providerId=0; + } + }; + struct channelInfo info[NUMCHANNELS]; + +}; + + +#endif diff --git a/mediaprovider.h b/mediaprovider.h new file mode 100644 index 0000000..b8e6a92 --- /dev/null +++ b/mediaprovider.h @@ -0,0 +1,129 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIAPROVIDER_H +#define MEDIAPROVIDER_H + +#include +#include +#include +#include "defines.h" + +class Media; +class MediaURI; +class MediaInfo; +class MediaList; + + +/** + this interface has to be implemented by + any provider of media data. + In all URIs the provider has to insert providerIds out of its range. + threading issues: + all operations to one channel are not thread save - so users have to ensure + that at most one thread at a time is accesing operations to one channel. + Implementers have to ensure that other operations are thread safe. + Exception: registering providers is not thread safe (at least at the moment). + **/ + +//the max number of media channels used in parallel +#define NUMCHANNELS 3 +//name of a media file +#define NAMESIZE 255 + +class MediaProvider +{ + public: + MediaProvider(){} + virtual ~MediaProvider(){} + + /** + * get the root media list + * the returned list has to be destroyed by the caller + * if NULL is returned currently no media is available + */ + virtual MediaList* getRootList()=0; + + /** + * get a medialist for a given parent + * the returned list has to be destroyed by the caller + * NULL if no entries found + */ + virtual MediaList* getMediaList(const MediaURI * parent)=0; + + /** + * open a media uri + * afterwards getBlock or other functions must be possible + * currently only one medium is open at the same time + * for a given channel + * @param channel: channel id, NUMCHANNELS must be supported + * @param xsize,ysize: size of the screen + * @param size out: the size of the medium + * @return != 0 in case of error + * + */ + virtual int openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize)=0; + + /** + * get a block for a channel + * @param offset - the offset + * @param len - the required len + * @param outlen out - the read len if 0 this is EOF + * @param buffer out the allocated buffer (must be freed with free!) + * if buffer is set at input the implementation CAN use + * this buffer - it is up to the caller to test if the buffer + * is at the same value when the method returns. + * it is assumed that there is enough room in the buffer if it set + * when calling + * @return != 0 in case of error + */ + virtual int getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer)=0; + + /** + * close a media channel + */ + virtual int closeMediaChannel(ULONG channel)=0; + + /** + * return the media info for a given channel + * return != 0 on error + * the caller has to provide a pointer to an existing media info + */ + virtual int getMediaInfo(ULONG channel, MediaInfo * result)=0; + +}; + + +/** + * the mediaplayer to register providers at + * can be static ctor's + */ +class MediaPlayerRegister { + public: + virtual void registerMediaProvider(MediaProvider *pi,ULONG id,ULONG range=1)=0; + virtual ~MediaPlayerRegister(){} + static MediaPlayerRegister* getInstance(); + protected: + static MediaPlayerRegister *instance; +}; + + +#endif diff --git a/mediaproviderids.h b/mediaproviderids.h new file mode 100644 index 0000000..1ee8954 --- /dev/null +++ b/mediaproviderids.h @@ -0,0 +1,59 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + This file contaisn the IDs for mediaproviders + Each provider should have it's ID defined here. + They should follow the name pattern: + MPROVIDERID_ + This is the ID a provider has ro use to register at it's local MediaProviderRegister + As the mediaprovider architecture is hierarchical there are distributors on each level, that + forward requests to their children. + Currently it looks like follows: + + MediaPlayer client + - LocalMediaFile client + - VDR (distributor) client + |- - MediaPlayer server + - ServerFileMediaProvider server + + As a distributor must forward multiple requests, it must register with a range of Ids. + This range includes it's own Id + a range for all its children. + This Range should be defined here as + MPROVIDERRANGE_ + If no range is defined here, the range is 1 - so no distribution. + +*/ + +//we reserve the range 1...999 for client side providers +static const ULONG MPROVIDERID_LOCALMEDIAFILE=1; +static const ULONG MPROVIDERID_VDR=1000; +static const ULONG MPROVIDERRANGE_VDR=10000; //so it has the IDs 1000..10999 + //all providers on the server side + //must fit into this range + +static const ULONG MPROVIDERID_SERVERMEDIAFILE=1001; + +#ifndef MEDIAPROVIDERIDS_H +#define MEDIAPROVIDERIDS_H + +#include "defines.h" + +#endif diff --git a/serialize.c b/serialize.c new file mode 100644 index 0000000..7ab6b2c --- /dev/null +++ b/serialize.c @@ -0,0 +1,441 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "serialize.h" +#include +#include +#ifndef SNPRINTF +#define SNPRINTF snprintf +#endif + +#define BUFFERINCREASE 1024 + +int SerializeBuffer::seek(int amount) { + UCHAR *np=current+amount; + if (np < start || np > end) return -1; + current=np; + return 0; +} + +void SerializeBuffer::rewind() { + current=start; +} + +int SerializeBuffer::checkSpace(int amount) { + if ((current+amount) <= end) return 0; + if (owning && autoincrease) { + if (start+size > current+amount) { + end=start+size; + return 0; + } + UCHAR *ns=new UCHAR[size+BUFFERINCREASE]; + if (!ns) return -1; + memcpy(ns,start,end-start); + size=size+BUFFERINCREASE; + end=ns+size; + if (useMalloc) free( start); + else delete [] start; + start=ns; + return 0; + } + return -1; +} + +SerializeBuffer::~SerializeBuffer() { + if (owning) { + if (useMalloc) free(start); + else delete[] start; + start=NULL; + } +} +SerializeBuffer::SerializeBuffer(ULONG sz,bool isMalloc,bool ai){ + autoincrease=ai; + useMalloc=isMalloc; + if (isMalloc) { + start=(UCHAR *)malloc(sz); + } + else { + start=new UCHAR[sz]; + } + end=start; + current=start; + size=sz; + owning=true; +} + //constructor for SerializeBuffers with external buffers +SerializeBuffer::SerializeBuffer(UCHAR *buffer,ULONG sz,bool ow,bool isMalloc,bool ai) { + useMalloc=isMalloc; + autoincrease=ai; + owning=ow; + size=sz; + start=buffer; + current=start; + end=start+size; +} +/** + * helper for serialize and deserialize + * always return != if no space + * advance buffer pointer + */ + +int SerializeBuffer::encodeLong(ULONG data) { + if (checkSpace( (int)sizeof(ULONG))!=0) return -1; + *((ULONG *)(current))=htonl(data); + current+=sizeof(ULONG); + return 0; +} +int SerializeBuffer::encodeShort(USHORT data) { + if (checkSpace( (int)sizeof(USHORT))!=0) return -1; + *((USHORT *)(current))=htons(data); + current+=sizeof(USHORT); + return 0; +} +int SerializeBuffer::encodeByte(UCHAR data) { + if (checkSpace( (int)sizeof(UCHAR))!=0) return -1; + *((UCHAR *)(current))=data; + current+=sizeof(UCHAR); + return 0; +} +int SerializeBuffer::encodeLongLong(ULLONG data) { + if (checkSpace( (int)sizeof(ULLONG))!=0) return -1; + *((ULONG *)(current))=htonl((data>>32) & 0xffffffff); + current+=sizeof(ULONG); + *((ULONG *)(current))=htonl(data & 0xffffffff); + current+=sizeof(ULONG); + return 0; +} +//string: 4 len, string with 0 +int SerializeBuffer::encodeString(const char *str) { + if (checkSpace( (int)sizeof(ULONG))!=0) return -1; + ULONG len=0; + if (str) len=strlen(str)+1; + *((ULONG *)(current))=htonl(len); + current+=sizeof(ULONG); + if (len == 0) return 0; + if (checkSpace((int)len)!=0) return -1; + strcpy((char *) current,str); + current+=len; + return 0; +} +int SerializeBuffer::decodeLong( int &data) { + if (checkSpace( (int)sizeof(ULONG))!=0) return -1; + data=(int)ntohl(*((ULONG *)(current))); + current+=sizeof(ULONG); + return 0; +} +int SerializeBuffer::decodeLong(ULONG &data) { + if (checkSpace( (int)sizeof(ULONG))!=0) return -1; + data=ntohl(*((ULONG *)(current))); + current+=sizeof(ULONG); + return 0; +} +int SerializeBuffer::decodeShort(USHORT &data) { + if (checkSpace( (int)sizeof(USHORT))!=0) return -1; + data=ntohs(*((USHORT *)(current))); + current+=sizeof(USHORT); + return 0; +} +int SerializeBuffer::decodeByte(UCHAR &data) { + if (checkSpace( (int)sizeof(UCHAR))!=0) return -1; + data=*((UCHAR *)current); + current+=sizeof(UCHAR); + return 0; +} +int SerializeBuffer::decodeLongLong(ULLONG &data) { + if (checkSpace( (int)sizeof(ULLONG))!=0) return -1; + ULLONG hd=ntohl(*((ULONG *)(current))); + current+=sizeof(ULONG); + ULLONG ld=ntohl(*((ULONG *)(current))); + current+=sizeof(ULONG); + data=(hd << 32) | ld; + return 0; +} +//string: 4 len, string with 0 +int SerializeBuffer::decodeString(ULONG &len, char *&strbuf) { + strbuf=NULL; + len=0; + if (checkSpace( (int)sizeof(ULONG))!=0) return -1; + len=ntohl(*((ULONG *)(current))); + current+=sizeof(ULONG); + if (len == 0) return 0; + if (checkSpace((int)len)!=0) return -1; + strbuf=new char[len]; + strncpy(strbuf,(char *)current,len); + *(strbuf+len-1)=0; + current+=len; + return 0; +} + + +UCHAR * SerializeBuffer::steelBuffer() { + UCHAR *rt=start; + owning=false; + autoincrease=false; + return rt; +} + +int Serializable::getSerializedStringLen(const char * str) { + int rt=4; + if (str) rt+=strlen(str)+1; + return rt; +} + +USHORT Serializable::getVersion() { + return version; +} + + +Serializable::Serializable() { + version=1; +} +Serializable::~Serializable(){} + +int Serializable::getSerializedLen() { + //2version+4len + return 6 + getSerializedLenImpl(); +} +int Serializable::serialize(SerializeBuffer *b) { + UCHAR *ptr=b->getCurrent(); + if (b->encodeShort(version) != 0) return -1; + if (b->encodeLong(0) != 0) return -1; //dummy len + if (serializeImpl(b) != 0) return -1; + UCHAR *ep=b->getCurrent(); + //now write the len + int len=ep-ptr-6; + if (len < 0) return -1 ; //internal error + b->seek(ptr-ep+2); //to len field + if (b->encodeLong(len) != 0) return -1; + b->seek(ep-b->getCurrent()); //back to end + return 0; +} + +int Serializable::deserialize(SerializeBuffer *b) { + USHORT vers=0; + if (b->decodeShort(vers) != 0) return -1; + ULONG len=0; + if (b->decodeLong(len) != 0) return -1; + UCHAR *data=b->getCurrent(); + if (data+len > b->getEnd()) return -1; + //TODO: set end temp. to current+len + //for better error handling in deserializeImpl + if (deserializeImpl(b) != 0) return -1; + //ensure we go to end of this element regardless of the things we know + b->seek(data+len-b->getCurrent()); + return 0; +} + +SerializableList::SerializableList() { + version=1; + encodeOnly=false; +} +SerializableList::~SerializableList(){} + +int SerializableList::addParam(Serializable *p,USHORT v) { + if (v < version || p == NULL) return -1; + Pentry entry; + entry.ptype=TSER; + entry.ptr.pser=p; + entry.version=v; + list.push_back(entry); + version=v; + return 0; +} +int SerializableList::addParam(USHORT *p,USHORT v) { + if (v < version || p == NULL) return -1; + Pentry entry; + entry.ptype=TUSHORT; + entry.ptr.pshort=p; + entry.version=v; + list.push_back(entry); + version=v; + return 0; +} +int SerializableList::addParam(ULONG *p,USHORT v) { + if (v < version || p == NULL) return -1; + Pentry entry; + entry.ptype=TULONG; + entry.ptr.plong=p; + entry.version=v; + list.push_back(entry); + version=v; + return 0; +} +int SerializableList::addParam(ULLONG *p,USHORT v) { + if (v < version || p == NULL) return -1; + Pentry entry; + entry.ptype=TULLONG; + entry.ptr.pllong=p; + entry.version=v; + list.push_back(entry); + version=v; + return 0; +} +int SerializableList::addParam(char **p,USHORT v) { + if (v < version || p == NULL) return -1; + Pentry entry; + entry.ptype=TCHAR; + entry.ptr.pchar=p; + entry.version=v; + list.push_back(entry); + version=v; + return 0; +} + +bool SerializableList::Pentry::isEqual(void *p,SerializableList::Ptypes t) { + void *cmp=NULL; + switch(t) { + case TUSHORT: + cmp=(void *)ptr.pshort; + break; + case TULONG: + cmp=(void *)ptr.plong; + break; + case TULLONG: + cmp=(void *)ptr.pllong; + break; + case TSER: + cmp=(void *)ptr.pser; + break; + case TCHAR: + cmp=(void *)ptr.pchar; + break; + case TUNKNOWN: + break; + } + return p==cmp; +} + +SerializableList::Pentry *SerializableList::findEntry(void *p,SerializableList::Ptypes t) { + for (vector::iterator it=list.begin();itisDeserialized; +} +bool SerializableList::isDeserialized(USHORT *p){ + SerializableList::Pentry *e=findEntry(p,TUSHORT); + if (!e) return false; + return e->isDeserialized; +} +bool SerializableList::isDeserialized(ULONG *p){ + SerializableList::Pentry *e=findEntry(p,TULONG); + if (!e) return false; + return e->isDeserialized; +} + +bool SerializableList::isDeserialized(ULLONG *p){ + SerializableList::Pentry *e=findEntry(p,TULLONG); + if (!e) return false; + return e->isDeserialized; +} + +bool SerializableList::isDeserialized(char **p){ + SerializableList::Pentry *e=findEntry(p,TCHAR); + if (!e) return false; + return e->isDeserialized; +} + +int SerializableList::getSerializedLenImpl(){ + int rt=0; + for (vector::iterator it=list.begin();itgetSerializedLen(); + break; + case TUNKNOWN: + break; + } + } + return rt; +} + +int SerializableList::serializeImpl(SerializeBuffer *b){ + for (vector::iterator it=list.begin();itencodeShort(*(*it).ptr.pshort) != 0) return -1; + break; + case TULONG: + if (b->encodeLong(*(*it).ptr.plong) != 0) return -1; + break; + case TULLONG: + if (b->encodeLongLong(*(*it).ptr.pllong) != 0) return -1; + break; + case TCHAR: + if (b->encodeString(*(*it).ptr.pchar) != 0) return -1; + break; + case TSER: + if ((*it).ptr.pser->serialize(b) != 0) return -1; + break; + case TUNKNOWN: + break; + } + } + return 0; +} + +int SerializableList::deserializeImpl(SerializeBuffer *b){ + ULONG dlen=0; + for (vector::iterator it=list.begin();it version) { + //OK - we received an older version - stop here + break; + } + switch((*it).ptype){ + case TUSHORT: + if (b->decodeShort(*(*it).ptr.pshort) != 0) return -1; + break; + case TULONG: + if (b->decodeLong(*(*it).ptr.plong) != 0) return -1; + break; + case TULLONG: + if (b->decodeLongLong(*(*it).ptr.pllong) != 0) return -1; + break; + case TCHAR: + if (b->decodeString(dlen,*(*it).ptr.pchar) != 0) return -1; + break; + case TSER: + if ((*it).ptr.pser->deserialize(b) != 0) return -1; + break; + case TUNKNOWN: + break; + } + (*it).isDeserialized=true; + } + return 0; +} + + diff --git a/serialize.h b/serialize.h new file mode 100644 index 0000000..349c05b --- /dev/null +++ b/serialize.h @@ -0,0 +1,238 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SERIALIZE_H +#define SERIALIZE_H +#include +using namespace std; +#include +#include +#include "defines.h" + +class SerializeBuffer { + public: + //constructor for send buffers + SerializeBuffer(ULONG size,bool isMalloc=false,bool autoincrease=false); + //constructor for SerializeBuffers with external buffers + SerializeBuffer(UCHAR *buffer,ULONG size,bool owning=false,bool isMalloc=true,bool autoincrease=false); + ~SerializeBuffer(); + //access to bufferpointer + UCHAR * getStart(){ return start;} + UCHAR * getCurrent(){ return current;} + UCHAR * getEnd(){ return end;} + //get the buffer and take it away from this object + UCHAR * steelBuffer(); + //seek relative to current + int seek(int amount); + void rewind(); + + //encode/decode functions + //always return != 0 on error + int encodeLong(ULONG data); + int encodeLongLong(ULLONG data); + int encodeShort(USHORT data); + int encodeString(const char *data); + int encodeByte(UCHAR data); + + int decodeLong(ULONG & data); + int decodeLong(int & data); + int decodeLongLong(ULLONG & data); + int decodeShort(USHORT & data); + int decodeString(ULONG &len,char * &data); + int decodeByte(UCHAR &data); + + private: + UCHAR * start; + UCHAR * end; + UCHAR * current; + ULONG size; + bool useMalloc; + bool owning; + bool autoincrease; + + //check buffer space and enlarge if allowed + int checkSpace(int size); + +}; + +class Serializable { + public: + Serializable(); + virtual ~Serializable(); + //serialize functions + //get the #of bytes needed to serialize + int getSerializedLen(); + //serialize + //advance buffer, check if >= end + //return 0 if OK + int serialize(SerializeBuffer *b); + //deserialize + //advance buffer, check if >= end + //return 0 if OK + int deserialize(SerializeBuffer *b); + //or the received version after deserialize + //can be queried with deserializeImpl + USHORT getVersion(); + //helper + static int getSerializedStringLen(const char *str); + protected: + //methods to be overwritten by impl + //those methods can use the version info + //the length and version is automatically encoded and decoded by the base class + virtual int getSerializedLenImpl()=0; + virtual int serializeImpl(SerializeBuffer *b)=0; + virtual int deserializeImpl(SerializeBuffer *b)=0; + USHORT version; + }; + +/** + * a class for creating a list of serializable parameters + * by including a version handling this automatically maintains compatibility + * by correct usage. + * usage example: + * 1. version + * USHORT myP1=0; + * ULONG myP2=0; + * SerializableList myList(); + * myList.addParam(&myP1); + * myList.addParam(&myP2); + * //now serialize/deserialize... + * //later - second version: + * USHORT myP1=0; + * ULONG myP2=0; + * char *myString=NULL; + * SerializableList myList(); + * myList.addParam(&myP1); + * myList.addParam(&myP2); + * myList.addParam(&myString,2); //this parameter is new in version 2 + * myList.deserialize(buffer); + * if (!myList.isDeserialized(&myString)) { + * //we got a version 1 message + * myString=strcpy(new char[22],"default-for-myString"); + * } + * + */ +class SerializableList : public Serializable{ + public: + SerializableList(); + virtual ~SerializableList(); + /** + * addParam + * add a parameter to the list + * no life cycle handling included + * params should be initialized before! + * when adding new params after having released a version + * add them to the end with a new version - this will automatically maintain + * compatibility + * will return !=0 if adding is not possible (e.g. adding with a smaller version) + */ + int addParam(Serializable *p,USHORT version=1); + int addParam(USHORT *p,USHORT version=1); + int addParam(ULONG *p,USHORT version=1); + int addParam(ULLONG *p,USHORT version=1); + int addParam(char **p,USHORT version=1); + + /** + * for lists only intended for encoding also + * const members will be added + * this is fully compatible to non const addParams on the other side + * so on the sender side you can use the addParam(const ... ) methods, on the receiver + * the non-const + * After having called one of this methods deserialize will always fail! + */ + int addParam(const Serializable *p,USHORT vs=1){ + encodeOnly=true; + return addParam((Serializable *)p,vs); + } + int addParam(const USHORT *p,USHORT vs=1){ + encodeOnly=true; + return addParam((USHORT *)p,vs); + } + int addParam(const ULONG *p,USHORT vs=1){ + encodeOnly=true; + return addParam((ULONG *)p,vs); + } + int addParam(const int *p,USHORT vs=1){ + encodeOnly=true; + return addParam((ULONG *)p,vs); + } + int addParam(const ULLONG *p,USHORT vs=1){ + encodeOnly=true; + return addParam((ULLONG *)p,vs); + } + int addParam(const char **p,USHORT vs=1){ + encodeOnly=true; + return addParam((char **)p,vs); + } + + + /** + * check functions to test if a certain parameter has been filled + * during deserialize + */ + bool isDeserialized(Serializable *p); + bool isDeserialized(USHORT *p); + bool isDeserialized(ULONG *p); + bool isDeserialized(ULLONG *p); + bool isDeserialized(char **p); + + //return the highest version after adding params + + + protected: + virtual int getSerializedLenImpl(); + virtual int serializeImpl(SerializeBuffer *b); + virtual int deserializeImpl(SerializeBuffer *b); + bool encodeOnly; //if any addParam(const ...) is called this will be set + + private: + typedef enum{ + TUNKNOWN, + TSER, + TUSHORT, + TULONG, + TULLONG, + TCHAR } Ptypes; + struct Pentry{ + Ptypes ptype; + bool isDeserialized; + USHORT version; + union { + Serializable *pser; + USHORT *pshort; + ULONG *plong; + ULLONG *pllong; + char **pchar; + } ptr; + Pentry() { + ptype=TUNKNOWN; + version=1; + isDeserialized=false; + ptr.pser=NULL; + } + bool isEqual(void *p,Ptypes t); + } ; + vectorlist; + Pentry *findEntry(void *p,Ptypes t); +}; + + + +#endif diff --git a/servermediafile.c b/servermediafile.c new file mode 100644 index 0000000..a99c1d9 --- /dev/null +++ b/servermediafile.c @@ -0,0 +1,268 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "servermediafile.h" +#include "mediaproviderids.h" +#include "media.h" +#include "medialauncher.h" +#include +#include +#include +#include +#include "log.h" + + +/* input buffer for reading dir */ +#define BUFSIZE 2048 +/* how long to wait until a list has to be finished (100ms units)*/ +#define MAXWAIT 50 + +ServerMediaFile::ServerMediaFile(Config *c,MediaPlayerRegister *distributor):MediaFile(MPROVIDERID_SERVERMEDIAFILE){ + cfg=c; + distributor->registerMediaProvider(this,MPROVIDERID_SERVERMEDIAFILE); + dirhandler=new MediaLauncher(cfg); + dirhandler->init(); + for (int i=0;iinit(dirhandler); + } +} + +ServerMediaFile::~ServerMediaFile(){ + for (int i=0;icloseStream(); + delete launchers[i]; + } + delete dirhandler; + } + +MediaList* ServerMediaFile::getRootList() { + Log::getInstance()->log("MediaFile::getRootList",Log::DEBUG,""); + MediaURI *ru=new MediaURI(providerid,NULL,NULL); + MediaList *rt=new MediaList(ru); + delete ru; + //the configured Media List + //for the moment up to 50 entries [Media] Dir.1 ...Dir.10 + struct stat st; + for (int nr=1;nr<=50;nr++){ + char buffer[30]; + sprintf(buffer,"Dir.%d",nr); + const char * dn=cfg->getValueString("Media",buffer); + if (dn != NULL) { + if (stat(dn,&st) != 0 || ! S_ISDIR(st.st_mode)) { + Log::getInstance()->log("MediaFile::getRootList",Log::ERR,"unable to open basedir %s",dn); + } + else { + Media *m=new Media(); + m->setFileName(dn); + m->setMediaType(MEDIA_TYPE_DIR); + m->setTime(st.st_mtime); + sprintf(buffer,"Dir.Name.%d",nr); + m->setDisplayName(cfg->getValueString("Media",buffer)); + rt->push_back(m); + Log::getInstance()->log("Media",Log::DEBUG,"added base dir %s",dn); + } + } + } + return rt; +} + +ULONG ServerMediaFile::getMediaType(const char *filename) { + ULONG rt=dirhandler->getTypeForName(filename); + if (rt != MEDIA_TYPE_UNKNOWN) return rt; + return MediaFile::getMediaType(filename); +} + +int ServerMediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize){ + if (channel >= NUMCHANNELS) return -1; + launchers[channel]->closeStream(); + ULONG rt=launchers[channel]->getTypeForName(uri->getName()); + if (rt != MEDIA_TYPE_UNKNOWN) { + *size=0; + channels[channel].reset(); + int rtstat=launchers[channel]->openStream(uri->getName(),xsize,ysize); + channels[channel].setFilename(uri->getName()); + return rtstat>=0?0:1; + } + return MediaFile::openMedium(channel,uri,size,xsize,ysize); +} + +int ServerMediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer) +{ + if (channel >= NUMCHANNELS) return -1; + if (launchers[channel]->isOpen()) { + return launchers[channel]->getNextBlock(len,buffer,outlen); + } + return MediaFile::getMediaBlock(channel,offset,len,outlen,buffer); +} +int ServerMediaFile::closeMediaChannel(ULONG channel){ + if (channel >= NUMCHANNELS) return -1; + if (launchers[channel]->isOpen()) { + return launchers[channel]->closeStream(); + } + return MediaFile::closeMediaChannel(channel); +} +int ServerMediaFile::getMediaInfo(ULONG channel, MediaInfo * result){ + if (channel >= NUMCHANNELS) return -1; + if (launchers[channel]->isOpen()) { + result->canPosition=false; + result->type=launchers[channel]->getTypeForName(channels[channel].filename); + return 0; + } + return MediaFile::getMediaInfo(channel,result); +} + + +MediaList* ServerMediaFile::getMediaList(const MediaURI *parent) { + ULONG rt=dirhandler->getTypeForName(parent->getName()); + if (rt == MEDIA_TYPE_UNKNOWN) return MediaFile::getMediaList(parent); + int op=dirhandler->openStream(parent->getName(),0,0); + if (op < 0) { + Log::getInstance()->log("Media",Log::ERR,"unable to open handler for %s",parent->getName()); + dirhandler->closeStream(); + return NULL; + } + int maxtries=0; + unsigned char *inbuf=NULL; + unsigned char linebuf[2*BUFSIZE]; + unsigned char *wrp=linebuf; + ULONG outlen=0; + MediaList *ml=new MediaList(parent); + while (maxtries < MAXWAIT) { + int ert=dirhandler->getNextBlock(BUFSIZE,&inbuf,&outlen); + if (ert != 0) break; + if (outlen == 0) { + if (inbuf != NULL) free(inbuf); + inbuf=NULL; + maxtries++; + continue; + } + maxtries=0; + if (outlen > BUFSIZE) { + Log::getInstance()->log("Media",Log::ERR,"invalid read len %llu in getBlock for list %s",outlen,parent->getName()); + free(inbuf); + inbuf=NULL; + continue; + } + memcpy(wrp,inbuf,outlen); + free(inbuf); + inbuf=NULL; + ULONG handledBytes=addDataToList(linebuf,outlen+(wrp-linebuf),ml,true); + memcpy(linebuf,wrp+outlen-handledBytes,wrp-linebuf+outlen-handledBytes); + if (handledBytes > outlen) wrp-=handledBytes-outlen; + if (wrp >= linebuf+BUFSIZE) { + Log::getInstance()->log("Media",Log::ERR,"line to long in getBlock for list %s",parent->getName()); + wrp=linebuf; + } + } + dirhandler->closeStream(); + return ml; +} + + +ULONG ServerMediaFile::addDataToList(unsigned char * buf, ULONG buflen,MediaList *list,bool extendedFormat) { + ULONG handledBytes=0; + char entrybuf[BUFSIZE+1]; + char display[BUFSIZE+1]; + int ebpos=0; + while (handledBytes < buflen) { + unsigned char c=buf[handledBytes]; + if (c == '\n') { + entrybuf[ebpos]=0; + /* complete line */ + /* handle # lines */ + for (int i=0;i 0) { + Log::getInstance()->log("Media",Log::DEBUG,"handle list line %s",entrybuf); + char *uriptr=entrybuf; + if (extendedFormat) { + /* search for a delimiter */ + while (*uriptr != ';' && *uriptr != 0) uriptr++; + if (*uriptr == ';') uriptr++; + if (*uriptr == 0) uriptr=entrybuf; + } + ULONG mt=getMediaType(uriptr); + if (mt != MEDIA_TYPE_UNKNOWN) { + if (uriptr != entrybuf) { + memcpy(display,entrybuf,uriptr-entrybuf-1); + display[uriptr-entrybuf-1]=0; + } + else { + int i=strlen(entrybuf)-1; + int len=i+1; + for(;i>=0;i--) { + if (entrybuf[i]=='/') break; + } + i++; + if (entrybuf[i] != 0) { + memcpy(display,&entrybuf[i],len-i); + display[len-i]=0; + } + else { + memcpy(display,entrybuf,len); + display[len]=0; + } + } + Media *m=new Media(); + MediaURI *u=NULL; + if (*uriptr != '/') { + /* add the directory of the list in front */ + MediaURI *p=list->getParent(list->getRoot()); + char ubuf[strlen(p->getName())+strlen(uriptr)+2]; + sprintf(ubuf,"%s/%s",p->getName(),uriptr); + u=new MediaURI(providerid,ubuf,display); + delete p; + } + else { + u=new MediaURI(providerid,uriptr,display); + } + m->setFileName(display); + m->setURI(u); + delete u; + m->setMediaType(mt); + list->push_back(m); + Log::getInstance()->log("Media",Log::DEBUG,"added media display %s, type %lu",display,mt); + } + } + + + //do handling + ebpos=0; + } + else if (c != '\r') { + entrybuf[ebpos]=c; + ebpos++; + if (ebpos >= BUFSIZE) { + /* line too long - ignore */ + Log::getInstance()->log("Media",Log::ERR,"line to long in add data"); + ebpos=0; + } + } + handledBytes++; + } + return handledBytes-ebpos; +} diff --git a/servermediafile.h b/servermediafile.h new file mode 100644 index 0000000..1fd0a67 --- /dev/null +++ b/servermediafile.h @@ -0,0 +1,57 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SERVERMEDIAFILE_H +#define SERVERMEDIAFILE_H + +#include "mediafile.h" +#include "config.h" + +class MediaLauncher; + + +class ServerMediaFile : public MediaFile +{ + public: + ServerMediaFile(Config *c,MediaPlayerRegister *distributor); + virtual ~ServerMediaFile(); + virtual MediaList* getRootList(); + virtual int openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize); + virtual int getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen, + unsigned char ** buffer); + virtual int closeMediaChannel(ULONG channel); + virtual int getMediaInfo(ULONG channel, MediaInfo * result); + virtual MediaList* getMediaList(const MediaURI *parent); + + + + protected: + virtual ULONG getMediaType(const char *fname); + MediaLauncher * launchers[NUMCHANNELS]; + MediaLauncher * dirhandler; + + private: + Config *cfg; + ULONG addDataToList(unsigned char * buf, ULONG buflen,MediaList *list,bool extendedFormat) ; + + +}; + +#endif diff --git a/vdrcommand.h b/vdrcommand.h new file mode 100644 index 0000000..76dde28 --- /dev/null +++ b/vdrcommand.h @@ -0,0 +1,163 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VDRCOMMAND_H +#define VDRCOMMAND_H + +#include "defines.h" +#include "serialize.h" +#include "media.h" + +/** + * data holder for VDR commands + * it's only important to add serializable objects + * in the same order on both sides + */ + +//until we really have response - commands we simply take +//the request+this flag for responses +//not really necessary but for checks it's better to have a command ID at least in some responses +const static ULONG VDR_RESPONSE_FLAG =0x1000000; + +//as this header is only included by vdr.cc the constants are this way private +//but can easily be used on the server side as well + +const static ULONG VDR_LOGIN = 1; +const static ULONG VDR_GETRECORDINGLIST = 2; +const static ULONG VDR_DELETERECORDING = 3; +const static ULONG VDR_GETCHANNELLIST = 5; +const static ULONG VDR_STREAMCHANNEL = 6; +const static ULONG VDR_GETBLOCK = 7; +const static ULONG VDR_STOPSTREAMING = 8; +const static ULONG VDR_STREAMRECORDING = 9; +const static ULONG VDR_GETCHANNELSCHEDULE = 10; +const static ULONG VDR_CONFIGSAVE = 11; +const static ULONG VDR_CONFIGLOAD = 12; +const static ULONG VDR_RESCANRECORDING = 13; // FIXME obselete +const static ULONG VDR_GETTIMERS = 14; +const static ULONG VDR_SETTIMER = 15; +const static ULONG VDR_POSFROMFRAME = 16; +const static ULONG VDR_FRAMEFROMPOS = 17; +const static ULONG VDR_MOVERECORDING = 18; +const static ULONG VDR_GETNEXTIFRAME = 19; +const static ULONG VDR_GETRECINFO = 20; +const static ULONG VDR_GETMARKS = 21; +const static ULONG VDR_GETCHANNELPIDS = 22; +const static ULONG VDR_DELETETIMER = 23; +const static ULONG VDR_GETLANGUAGELIST = 33; +const static ULONG VDR_GETLANGUAGECONTENT = 34; +const static ULONG VDR_GETMEDIALIST = 30; +const static ULONG VDR_OPENMEDIA = 31; +const static ULONG VDR_GETMEDIABLOCK = 32; +const static ULONG VDR_GETMEDIAINFO = 35; +const static ULONG VDR_CLOSECHANNEL = 36; + +class VDR_Command : public SerializableList { + public: + VDR_Command(const ULONG cmd) { + command=cmd; + addParam(&command); + } + virtual ~VDR_Command(){} + ULONG command; +}; + +class VDR_GetMediaListRequest : public VDR_Command { + public: + VDR_GetMediaListRequest(MediaURI *root) :VDR_Command(VDR_GETMEDIALIST) { + addParam(root); + } +}; + +class VDR_GetMediaListResponse : public VDR_Command { + public: + VDR_GetMediaListResponse(ULONG *flags,MediaList *m) : VDR_Command(VDR_GETMEDIALIST|VDR_RESPONSE_FLAG){ + addParam(flags); + addParam(m); + } +}; + +class VDR_OpenMediumRequest : public VDR_Command { + public: + VDR_OpenMediumRequest(ULONG *channel,MediaURI *u,ULONG *xsize, ULONG *ysize) : + VDR_Command(VDR_OPENMEDIA) { + addParam(channel); + addParam(u); + addParam(xsize); + addParam(ysize); + } +}; +class VDR_OpenMediumResponse : public VDR_Command { + public: + VDR_OpenMediumResponse(ULONG *flags,ULLONG *size) : + VDR_Command(VDR_OPENMEDIA|VDR_RESPONSE_FLAG) { + addParam(flags); + addParam(size); + } +}; +class VDR_GetMediaBlockRequest : public VDR_Command { + public: + VDR_GetMediaBlockRequest(ULONG * channel, ULLONG *pos, ULONG *max): + VDR_Command(VDR_GETMEDIABLOCK) { + addParam(channel); + addParam(pos); + addParam(max); + } +}; + +//no response class for GetMediaBlock + + +class VDR_CloseMediaChannelRequest : public VDR_Command { + public: + VDR_CloseMediaChannelRequest(ULONG * channel): + VDR_Command(VDR_CLOSECHANNEL) { + addParam(channel); + } +}; + +class VDR_CloseMediaChannelResponse : public VDR_Command { + public: + VDR_CloseMediaChannelResponse(ULONG * flags): + VDR_Command(VDR_CLOSECHANNEL|VDR_RESPONSE_FLAG) { + addParam(flags); + } +}; + +class VDR_GetMediaInfoRequest : public VDR_Command { + public: + VDR_GetMediaInfoRequest(ULONG * channel): + VDR_Command(VDR_GETMEDIAINFO) { + addParam(channel); + } +}; +class VDR_GetMediaInfoResponse : public VDR_Command { + public: + VDR_GetMediaInfoResponse(ULONG * flags,MediaInfo *info): + VDR_Command(VDR_GETMEDIAINFO|VDR_RESPONSE_FLAG) { + addParam(flags); + addParam(info); + } +}; + + + + +#endif diff --git a/vompclient.c b/vompclient.c index 4a2692c..f4ddba4 100644 --- a/vompclient.c +++ b/vompclient.c @@ -18,6 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "mediaplayer.h" +#include "media.h" +#include "servermediafile.h" +#include "vdrcommand.h" #include "vompclient.h" #include "responsepacket.h" @@ -43,13 +47,14 @@ VompClient::VompClient(Config* cfgBase, char* tconfigDir, int tsocket) recplayer = NULL; recordingManager = NULL; #endif - imageFile = 0; log = Log::getInstance(); loggedIn = false; configDir = tconfigDir; log->log("Client", Log::DEBUG, "Config dir: %s", configDir); baseConfig = cfgBase; incClients(); + media=new MediaPlayer(); + mediaprovider=new ServerMediaFile(cfgBase,media); rrproc.init(); } diff --git a/vompclient.h b/vompclient.h index c728bf5..6906dd2 100644 --- a/vompclient.h +++ b/vompclient.h @@ -54,9 +54,15 @@ class cRecordings; #include "defines.h" #include "tcp.h" #include "config.h" +#include "media.h" #include "i18n.h" #include "vompclientrrproc.h" +class ResponsePacket; +class ServerMediaFile; +class SerializeBuffer; +class MediaPlayer; + class VompClient { friend class VompClientRRProc; @@ -88,7 +94,6 @@ class VompClient I18n i18n; bool loggedIn; char* configDir; - FILE* imageFile; void cleanConfig(); @@ -100,6 +105,8 @@ class VompClient cRecordings* recordingManager; RecPlayer* recplayer; #endif + MediaPlayer *media; + ServerMediaFile *mediaprovider; }; #endif diff --git a/vompclientrrproc.c b/vompclientrrproc.c index 29d84b0..0074b46 100644 --- a/vompclientrrproc.c +++ b/vompclientrrproc.c @@ -35,7 +35,10 @@ #include "vompclient.h" #include "log.h" #include "media.h" +#include "mediaplayer.h" +#include "servermediafile.h" #include "i18n.h" +#include "vdrcommand.h" VompClientRRProc::VompClientRRProc(VompClient& x) : x(x) @@ -167,10 +170,10 @@ bool VompClientRRProc::processPacket() case 9: result = processStartStreamingRecording(); break; -#endif case 10: result = processGetChannelSchedule(); break; +#endif case 11: result = processConfigSave(); break; @@ -212,14 +215,14 @@ bool VompClientRRProc::processPacket() result = processDeleteTimer(); break; #endif - case 30: + case VDR_GETMEDIALIST: result = processGetMediaList(); break; - case 31: - result = processGetPicture(); + case VDR_OPENMEDIA: + result = processOpenMedia(); break; - case 32: - result = processGetImageBlock(); + case VDR_GETMEDIABLOCK: + result = processGetMediaBlock(); break; case 33: result = processGetLanguageList(); @@ -227,6 +230,13 @@ bool VompClientRRProc::processPacket() case 34: result = processGetLanguageContent(); break; + case VDR_GETMEDIAINFO: + result= processGetMediaInfo(); + break; + case VDR_CLOSECHANNEL: + result= processCloseMediaChannel(); + break; + } delete resp; @@ -341,178 +351,201 @@ int VompClientRRProc::processConfigLoad() return 1; } + +//helper for sending from a serialize buffer +//insert the used len into the first 4 Bytes of the buffer +void VompClientRRProc::sendPacket(SerializeBuffer *b) { + resp->copyin(b->getStart(),b->getCurrent()-b->getStart()); + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); +} + /** * media List Request: - * 4 length - * 4 VDR_GETMEDIALIST - * 4 flags (currently unused) - * n dirname - * n+1 0 * Media List response: - * 4 length - * 4 VDR_ - * 4 numentries - * per entry: - * 4 media type - * 4 time stamp - * 4 flags - * 4 strlen (incl. 0 Byte) - * string - * 0 + * flags, mediaList */ - +#define MLISTBUF 500000 int VompClientRRProc::processGetMediaList() { - if (req->dataLength < 4) { - log->log("RRProc", Log::ERR, "getMediaList packet too short %d", req->dataLength); + SerializeBuffer buffer(req->data,req->dataLength); + MediaURI uri(0,NULL,NULL); + VDR_GetMediaListRequest request(&uri); + if (request.deserialize(&buffer) != 0) { + log->log("Client", Log::ERR, "getMediaList unable to deserialize"); return 0; } - char * dirname=NULL; - if (req->dataLength > 4) { - //we have a dirname provided - dirname=(char *)&req->data[4]; - log->log("RRProc", Log::DEBUG, "getMediaList for %s", dirname); - } + const char *dirname=uri.getName(); + log->log("Client", Log::DEBUG, "getMediaList for %s", dirname); - MediaList * ml=MediaList::readList(x.baseConfig, dirname); + MediaList * ml=NULL; + if (dirname == NULL) { + ml=x.media->getRootList(); + } else { + ml=x.media->getMediaList(&uri); + } if (ml == NULL) { - log->log("RRProc", Log::ERR, "getMediaList returned NULL"); + log->log("Client", Log::ERR, "getMediaList returned NULL"); return 0; } - - //response code (not yet set) - resp->addULONG(0); - - //numentries - resp->addULONG(ml->size()); - - for (MediaList::iterator nm=ml->begin(); nmend(); nm++) - { - Media *m=*nm; - log->log("RRProc", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType()); - resp->addULONG(m->getType()); - //time stamp - resp->addULONG(m->getTime()); - //flags - resp->addULONG(0); - int len=strlen(m->getFilename()); - //strlen - resp->addULONG(len+1); - resp->addString(m->getFilename()); + SerializeBuffer rbuf(MLISTBUF,false,true); + ULONG flags=0; //TODO: real error handling by setting flags + VDR_GetMediaListResponse response(&flags,ml); + if (response.serialize(&rbuf) != 0) { + log->log("Client", Log::ERR, "getMediaList returned NULL"); + delete ml; + return 0; } + log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size()); delete ml; - - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - log->log("RRProc", Log::DEBUG, "Written Media list"); + + sendPacket(&rbuf); + log->log("Client", Log::DEBUG, "Written Media list"); return 1; } - /** - * get image Request: - * 4 flags (currently unused) - * 4 x size - * 4 y size - * n filename - * n+1 0 - * get image response: - * 4 length - * 4 VDR_GETIMAGE - * 4 len of image + * openMedia Request: + * openMedia response: */ - -int VompClientRRProc::processGetPicture() +int VompClientRRProc::processOpenMedia() { - if (req->dataLength < 12) { - log->log("RRProc", Log::ERR, "getPicture packet too short %d", req->dataLength); + SerializeBuffer buffer(req->data,req->dataLength); + MediaURI uri(0,NULL,NULL); + ULONG channel=0; + ULONG xs=0; + ULONG ys=0; + VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys); + if (request.deserialize(&buffer) != 0) { + log->log("Client", Log::ERR, "openMediaRequest unable to deserialize"); return 0; } - if (x.imageFile) { - fclose(x.imageFile); - x.imageFile=NULL; - } - char * filename=NULL; - if (req->dataLength > 12) { - //we have a dirname provided - filename=(char *)&req->data[12]; - log->log("RRProc", Log::DEBUG, "getPicture %s", filename); + const char *name=uri.getName(); + log->log("Client", Log::DEBUG, "openMediaRequest for %s", name); + ULLONG size=0; + int rt=x.media->openMedium(channel,&uri,&size,xs,ys); + ULONG flags=0; + if (rt != 0) { + size=0; + flags=1; + log->log("Client", Log::ERR, "openMediaRequest unable to open"); + } + VDR_OpenMediumResponse response(&flags,&size); + SerializeBuffer rbuf(response.getSerializedLen()+4,false,true); + if (response.serialize(&rbuf) != 0) { + log->log("Client", Log::ERR, "openMediaRequest cannot serialize"); + return 0; } - else { - log->log("RRProc", Log::ERR, "getPicture empty filename"); + log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size); + sendPacket(&rbuf); + return 1; +} +/** + * VDR_GETMEDIABLOCK + * resp + * packet - no serialized response! + */ +int VompClientRRProc::processGetMediaBlock() +{ + SerializeBuffer buffer(req->data,req->dataLength); + ULLONG position = 0; + ULONG amount = 0; + ULONG channel = 0; + VDR_GetMediaBlockRequest request(&channel,&position,&amount); + if (request.deserialize(&buffer) != 0) { + log->log("Client", Log::ERR, "getMediaBlock unable to deserialize"); + return 0; } - if (filename) { - x.imageFile=fopen(filename,"r"); - if (!x.imageFile) log->log("RRProc", Log::ERR, "getPicture unable to open %s",filename); + log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel); + + UCHAR sendBuffer[amount ]; + ULONG amountReceived = 0; + UCHAR *rbuf=sendBuffer; + int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf); + if (!amountReceived || rt != 0) + { + log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0"); } - int size=0; - if (x.imageFile) { - struct stat st; - if ( fstat(fileno(x.imageFile),&st) == 0) size=st.st_size; + else + { + if (rbuf != sendBuffer) { + //the provider did not use the optimized handling with using my buffer + resp->copyin(rbuf,amountReceived); + free(rbuf); + } else { + // the provider did not allocate a new buffer + resp->copyin(sendBuffer,amountReceived); + } } - //response code (not yet set) - resp->addULONG(31); - //size - resp->addULONG(size); - - log->log("RRProc", Log::DEBUG, "getPicture size %u", size); - resp->finalise(); x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - - log->log("RRProc", Log::DEBUG, "Written getPicture"); - + log->log("Client", Log::DEBUG, "written ok %lu", amountReceived); return 1; } +/** + * VDR_GETMEDIAINFO + */ - -int VompClientRRProc::processGetImageBlock() +int VompClientRRProc::processGetMediaInfo() { - if (!x.imageFile) - { - log->log("RRProc", Log::DEBUG, "Get image block called when no image active"); + SerializeBuffer buffer(req->data,req->dataLength); + ULONG channel=0; + VDR_GetMediaInfoRequest request(&channel); + if (request.deserialize(&buffer) != 0) { + log->log("Client", Log::ERR, "getMediaInfo unable to deserialize"); return 0; } + log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel); + ULONG flags=0; + MediaInfo mi; + int rt=x.media->getMediaInfo(channel,&mi); + if (rt != 0) { + flags=1; + log->log("Client", Log::ERR, "getMediaInfo unable to get"); + } + VDR_GetMediaInfoResponse response(&flags,&mi); + SerializeBuffer rbuf(response.getSerializedLen()+4,false,true); + if (response.serialize(&rbuf) != 0) { + log->log("Client", Log::ERR, "getMediaInfo cannot serialize"); + return 0; + } + sendPacket(&rbuf); + return 1; +} - UCHAR* data = req->data; - - ULLONG position = x.ntohll(*(ULLONG*)data); - data += sizeof(ULLONG); - ULONG amount = ntohl(*(ULONG*)data); - - log->log("RRProc", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount); +/** + * VDR_CLOSECHANNEL + */ - UCHAR sendBuffer[amount]; - ULONG amountReceived = 0; // compiler moan. - ULLONG cpos=ftell(x.imageFile); - if (position != cpos) { - fseek(x.imageFile,position-cpos,SEEK_CUR); - } - if (position != (ULLONG)ftell(x.imageFile)) { - log->log("RRProc", Log::DEBUG, "getImageblock pos = %llu not available", position); - } - else { - amountReceived=fread(&sendBuffer[0],1,amount,x.imageFile); - } - if (!amountReceived) - { - resp->addULONG(0); - log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0"); +int VompClientRRProc::processCloseMediaChannel() +{ + SerializeBuffer buffer(req->data,req->dataLength); + ULONG channel=0; + VDR_CloseMediaChannelRequest request(&channel); + if (request.deserialize(&buffer) != 0) { + log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize"); + return 0; } - else - { - resp->copyin(sendBuffer, amount); - log->log("RRProc", Log::DEBUG, "written %lu", amountReceived); + ULONG flags=0; + log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel); + int rt=x.media->closeMediaChannel(channel); + if (rt != 0) { + flags=1; + log->log("Client", Log::ERR, "closeMediaChannel unable to get"); + } + VDR_CloseMediaChannelResponse response(&flags); + SerializeBuffer rbuf(response.getSerializedLen()+4,false,true); + if (response.serialize(&rbuf) != 0) { + log->log("Client", Log::ERR, "closeMediaChannel cannot serialize"); + return 0; } - - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - + sendPacket(&rbuf); return 1; } + int VompClientRRProc::processGetLanguageList() { x.i18n.findLanguages(); diff --git a/vompclientrrproc.h b/vompclientrrproc.h index 31d0a14..856bd9c 100644 --- a/vompclientrrproc.h +++ b/vompclientrrproc.h @@ -24,6 +24,7 @@ #include "thread.h" #include "responsepacket.h" #include +#include "serialize.h" using namespace std; @@ -55,6 +56,7 @@ class VompClientRRProc : public Thread private: bool processPacket(); + void sendPacket(SerializeBuffer *b); #ifndef VOMPSTANDALONE int processGetRecordingsList(); @@ -81,8 +83,10 @@ class VompClientRRProc : public Thread int processConfigSave(); int processConfigLoad(); int processGetMediaList(); - int processGetPicture(); - int processGetImageBlock(); + int processOpenMedia(); + int processGetMediaBlock(); + int processGetMediaInfo(); + int processCloseMediaChannel(); int processGetLanguageList(); int processGetLanguageContent(); -- 2.39.2