From: Chris Tallon Date: Tue, 23 Dec 2008 17:27:32 +0000 (+0000) Subject: Vogel Media Player 2008-11-28 X-Git-Tag: r0-3-1~3 X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=bb32129d6e36f46f82218d167a6c363a30876eb9;p=vompserver.git Vogel Media Player 2008-11-28 --- 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();