]> git.vomp.tv Git - vompserver.git/commitdiff
Vogel Media Player 2008-11-28
authorChris Tallon <chris@vomp.tv>
Tue, 23 Dec 2008 17:27:32 +0000 (17:27 +0000)
committerChris Tallon <chris@vomp.tv>
Tue, 23 Dec 2008 17:27:32 +0000 (17:27 +0000)
20 files changed:
Makefile
media.c
media.h
mediafile.c [new file with mode: 0644]
mediafile.h [new file with mode: 0644]
medialauncher.c [new file with mode: 0644]
medialauncher.h [new file with mode: 0644]
mediaplayer.c [new file with mode: 0644]
mediaplayer.h [new file with mode: 0644]
mediaprovider.h [new file with mode: 0644]
mediaproviderids.h [new file with mode: 0644]
serialize.c [new file with mode: 0644]
serialize.h [new file with mode: 0644]
servermediafile.c [new file with mode: 0644]
servermediafile.h [new file with mode: 0644]
vdrcommand.h [new file with mode: 0644]
vompclient.c
vompclient.h
vompclientrrproc.c
vompclientrrproc.h

index 9b05004328ba1d8f02dcbb222eb16a869dbd2c9b..bb492ddc94fbe81926d86835e1d3cb1961912426 100644 (file)
--- 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 3b30baa7e1d6bcd56897fd6e3180b937abf14d18..50df6560afe5111103e8ea8875bbfcf4369790e5 100644 (file)
--- a/media.c
+++ b/media.c
 
     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 <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <iostream>
+#include <time.h>
+#include <arpa/inet.h>
+#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(&ltime,btime, sizeof(struct tm));
+  btime=&ltime;
+  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;i<NUMTYPES;i++) {
-            if (endswith(fname,mediatypes[i].extension)) {
-              mtype=mediatypes[i].type;
-              break;
-              }
-           }
-         }
-      }
-    free(buffer);
-    //only consider entries we accept by type here
-    if (mtype & type) {
-     Media * m =new Media(mtype,fname,(int)(st.st_mtime));
-     rt->push_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();it<end();it++) {
+    rt+=(*it)->getSerializedLen();
+  }
+  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();it<end();it++) {
+    if ((*it)->serialize(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;i<numelem;i++) {
+    Media *m=new Media();
+    if (m->deserialize(b) != 0) {
+      delete m;
+      return -1;
+    }
+    push_back(m);
+  }
+  return 0;
+}
+
+
 
diff --git a/media.h b/media.h
index e058d66a405510963356093ee9348580e6ccef3b..67e9e348f8c253e9bbc039d99893fe056a1406fd 100644 (file)
--- a/media.h
+++ b/media.h
 
     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 <stdio.h>
-#include <pthread.h>
-#include <signal.h>
-#include <endian.h>
-
-#include <unistd.h> // sleep
-#include <vector>
-
 using namespace std;
-//#include "defines.h"
-//#include "tcp.h"
-//#include "mvpreceiver.h"
-//#include "recplayer.h"
-#include "config.h"
+#include <vector>
+#include <stdio.h>
+#include <string.h>
+#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<Media*> {
+
+typedef vector<Media*> 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 (file)
index 0000000..0138cc3
--- /dev/null
@@ -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 <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iostream>
+#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;i<NUMTYPES;i++) {
+      if (endswith(filename,mediatypes[i].extension)) {
+        return mediatypes[i].type;
+        }
+     }
+ return MEDIA_TYPE_UNKNOWN;
+}
+
+
+Media * MediaFile::createMedia(const char * dirname, const char * filename, bool withURI) {
+  Media * rt=NULL;
+  char *buffer;
+  asprintf(&buffer, "%s/%s", dirname, filename);
+  struct stat st;
+  ULONG mtype=MEDIA_TYPE_UNKNOWN;
+  if (stat(buffer, &st) == 0) {
+    if (S_ISDIR(st.st_mode)) {
+       mtype=MEDIA_TYPE_DIR;
+    }
+    else {
+       mtype=getMediaType(filename);
+    }
+  }
+  //only consider entries we accept by type here
+  if (mtype != MEDIA_TYPE_UNKNOWN) {
+    rt =new Media();
+    rt->setMediaType(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 (file)
index 0000000..a83983d
--- /dev/null
@@ -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 (file)
index 0000000..45dfff6
--- /dev/null
@@ -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 <iostream>
+#include "log.h"
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+
+#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;i<numcommands;i++)
+      delete commands[i];
+    delete commands;
+  }
+  };
+
+MediaLauncher::MCommand::MCommand(const char *n,ULONG t,const char *ext) {
+  command=new char[strlen(n)+1];
+  strcpy(command,n);
+  mediaType=t;
+  extension=new char[strlen(ext)+1];
+  strcpy(extension,ext);
+}
+MediaLauncher::MCommand::~MCommand() {
+  delete command;
+  delete extension;
+}
+
+#define NUMTYPES 4
+
+static struct {
+  const char* mtypename;
+  ULONG mtypeid;
+} mediatypes[]= {
+  {"PICTURE",MEDIA_TYPE_PICTURE},
+  {"AUDIO",MEDIA_TYPE_AUDIO},
+  {"VIDEO",MEDIA_TYPE_VIDEO},
+  {"LIST",MEDIA_TYPE_DIR}
+};
+
+static ULONG typeIdFromName(const char *name) {
+  for(int i=0;i<NUMTYPES;i++){
+    if (strcasecmp(mediatypes[i].mtypename,name) == 0) return mediatypes[i].mtypeid;
+  }
+  return MEDIA_TYPE_UNKNOWN;
+}
+
+int MediaLauncher::init() {
+  Log::getInstance()->log("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;i<cp->numcommands;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;i<numcommands;i++) {
+    if (strcasecmp(ext,commands[i]->extension) == 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 (file)
index 0000000..0bf015f
--- /dev/null
@@ -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 (file)
index 0000000..1359010
--- /dev/null
@@ -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();it<plist.end();it++) {
+  delete *it;
+  }
+}
+
+/**
+  * get the root media list
+  * the returned list has to be destroyed by the caller
+  * if NULL is returned currently no media is available
+  */
+MediaList* MediaPlayer::getRootList(){
+  Log::getInstance()->log("MediaPlayer::getRootList",Log::DEBUG,"numproviders %d",plist.size());
+  MediaList * rt=new MediaList(new MediaURI(0,NULL,NULL));
+  for (Tplist::iterator it=plist.begin();it<plist.end();it++) {
+    MediaList *cur=(*it)->provider->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();mi<cur->end();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<plist.end();it++) {
+    MediaProviderHolder *h=*it;
+    if (id >= 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 (file)
index 0000000..de9bab1
--- /dev/null
@@ -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 <vector>
+#include <stdio.h>
+#include <string.h>
+#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<MediaProviderHolder *> 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 (file)
index 0000000..b8e6a92
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#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 (file)
index 0000000..1ee8954
--- /dev/null
@@ -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_<name>
+   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
+            |- <comm> - 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_<name>
+   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 (file)
index 0000000..7ab6b2c
--- /dev/null
@@ -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 <stdlib.h>
+#include <arpa/inet.h>
+#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<Pentry>::iterator it=list.begin();it<list.end();it++) {
+    if ( (*it).isEqual(p,t)) return &(*it);
+  }
+  return NULL;
+}
+bool SerializableList::isDeserialized(Serializable *p){
+  SerializableList::Pentry *e=findEntry(p,TSER);
+  if (!e) return false;
+  return e->isDeserialized;
+}
+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<Pentry>::iterator it=list.begin();it<list.end();it++) {
+    switch((*it).ptype){
+      case TUSHORT:
+        rt+=sizeof(USHORT);
+        break;
+      case TULONG:
+        rt+=sizeof(ULONG);
+        break;
+      case TULLONG:
+        rt+=sizeof(ULLONG);
+        break;
+      case TCHAR:
+        rt+=getSerializedStringLen(*((*it).ptr.pchar));
+        break;
+      case TSER:
+        rt+=(*it).ptr.pser->getSerializedLen();
+        break;
+      case TUNKNOWN:
+        break;
+    }
+  }
+  return rt;
+}
+
+int SerializableList::serializeImpl(SerializeBuffer *b){
+  for (vector<Pentry>::iterator it=list.begin();it<list.end();it++) {
+    switch((*it).ptype){
+      case TUSHORT:
+        if (b->encodeShort(*(*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<Pentry>::iterator it=list.begin();it<list.end();it++) {
+    if ((*it).version > 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 (file)
index 0000000..349c05b
--- /dev/null
@@ -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 <vector>
+using namespace std;
+#include <stdio.h>
+#include <string.h>
+#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);
+    } ;
+    vector<struct Pentry>list;
+    Pentry *findEntry(void *p,Ptypes t);
+};
+
+
+
+#endif
diff --git a/servermediafile.c b/servermediafile.c
new file mode 100644 (file)
index 0000000..a99c1d9
--- /dev/null
@@ -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 <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iostream>
+#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;i<NUMCHANNELS;i++) {
+    launchers[i]=new MediaLauncher(cfg);
+    launchers[i]->init(dirhandler);
+  }
+}
+
+ServerMediaFile::~ServerMediaFile(){
+  for (int i=0;i<NUMCHANNELS;i++) {
+    launchers[i]->closeStream();
+    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<ebpos;i++) {
+        if (entrybuf[i] == '#') {
+          entrybuf[i]=0;
+          break;
+        }
+        if (entrybuf[i] != ' ') break;
+      }
+      if (strlen(entrybuf) > 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 (file)
index 0000000..1fd0a67
--- /dev/null
@@ -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 (file)
index 0000000..76dde28
--- /dev/null
@@ -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
index 4a2692cf767a09758db097efa45b8a4f69a3ee2c..f4ddba4fba34c0e60ca5c1225e688e277fcb6534 100644 (file)
     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();
 }
index c728bf5325ba661ef6c34a3197c4aae97e0f521d..6906dd2cdab2ce168e434522ce8c9ea261e7bae1 100644 (file)
@@ -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
index 29d84b020223f715d6ec4c6919e79440eb277f44..0074b46c8c382d41717a5ec2650295947db4c7d4 100644 (file)
 #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(); nm<ml->end(); 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();
index 31d0a14d5378130d87c3b26b3b5fbfedc22d49a8..856bd9cf9ffc7260d8e59d25cc2f2b99512e42f4 100644 (file)
@@ -24,6 +24,7 @@
 #include "thread.h"
 #include "responsepacket.h"
 #include <queue>
+#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();