OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o mvpclient.o tcp.o \
ringbuffer.o mvprelay.o \
- recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o
+ recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o \
+ media.o
### Implicit rules:
return 1;
}
+int Config::status()
+{
+ return initted;
+}
+
int Config::shutdown()
{
if (!initted) return 1;
--- /dev/null
+/*
+ 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 "media.h"
+//#include "tools.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+
+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;
+ };
+
+Media::~Media(){
+ delete _filename;
+ _filename=NULL;
+ };
+
+const char * Media::getFilename() {
+ return _filename;
+ }
+
+int Media::getType() {
+ return _type;
+ }
+int Media::getTime() {
+ return _time;
+ }
+
+
+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
+
+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->Add(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
+ cReadDir d(dirname);
+ struct dirent *e;
+ while ((e=d.Next()) != 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->Add(m);
+ Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,mtype);
+ }
+ }
+ }
+ //test
+ //Media *m=new Media(MEDIA_TYPE_DIR,"testMedia1",0);
+ //rt->Add(m);
+ return rt;
+ }
+
+
+
--- /dev/null
+/*
+ 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 MEDIA_H
+#define MEDIA_H
+
+#include <stdio.h>
+#include <pthread.h>
+#include <signal.h>
+#include <endian.h>
+
+#include <unistd.h> // sleep
+
+#include <vdr/tools.h>
+
+//#include "defines.h"
+//#include "tcp.h"
+//#include "mvpreceiver.h"
+//#include "recplayer.h"
+#include "config.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_ALL (1+2+4+8)
+
+class Media : public cListObject
+{
+ public:
+ /**
+ * create a media entry
+ * filename will get copied
+ */
+ Media(int type, const char * filename, int time);
+ ~Media();
+ const char * getFilename();
+ int getType();
+ int getTime();
+
+ private:
+ char * _filename;
+ int _type;
+ int _time;
+
+
+};
+
+class MediaList : public cList<Media> {
+ public:
+ static MediaList *readList(Config *cfg,const char * dirname,int type=MEDIA_TYPE_ALL);
+ };
+
+#endif
int MVPClient::nr_clients = 0;
-MVPClient::MVPClient(char* tconfigDirExtra, int tsocket)
+MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket)
: tcp(tsocket)
{
lp = NULL;
rp = NULL;
+ imageFile = 0;
recordingManager = NULL;
log = Log::getInstance();
loggedIn = false;
configDirExtra = tconfigDirExtra;
+ baseConfig = cfgBase;
incClients();
}
case 22:
result = processGetChannelPids(data, packetLength);
break;
+ case 30:
+ result = processGetMediaList(data, packetLength);
+ break;
+ case 31:
+ result = processGetPicture(data, packetLength);
+ break;
+ case 32:
+ result = processGetImageBlock(data, packetLength);
+ break;
}
free(buffer);
return 1;
}
+
+
+/**
+ * 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
+*/
+#define MLISTBUF 500000
+int MVPClient::processGetMediaList(UCHAR* data, int length)
+{
+ if (length < 4) {
+ log->log("Client", Log::ERR, "getMediaList packet too short %d", length);
+ return 0;
+ }
+ char * dirname=NULL;
+ if (length > 4) {
+ //we have a dirname provided
+ dirname=(char *)&data[4];
+ log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
+ }
+
+
+ UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough
+ int count = 4; // leave space for the header
+
+ MediaList * ml=MediaList::readList(baseConfig,dirname);
+ if (ml == NULL) {
+ log->log("Client", Log::ERR, "getMediaList returned NULL");
+ return 0;
+ }
+ //response code (not yet set)
+ *(ULONG*)&sendBuffer[count] = htonl(0);
+ count += 4;
+ //numentries
+ *(ULONG*)&sendBuffer[count] = htonl(ml->Count());
+ count += 4;
+ for (int nm=0;nm<ml->Count() && count < (MLISTBUF-1000);nm++) {
+ Media *m=ml->Get(nm);
+ log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType());
+ *(ULONG*)&sendBuffer[count] = htonl(m->getType());
+ count += 4;
+ //time stamp
+ *(ULONG*)&sendBuffer[count] = htonl(m->getTime());
+ count += 4;
+ //flags
+ *(ULONG*)&sendBuffer[count] = htonl(0);
+ count += 4;
+ int len=strlen(m->getFilename());
+ //strlen
+ *(ULONG*)&sendBuffer[count] = htonl(len+1);
+ count += 4;
+ //should have a check for strlen > 1000...
+ strcpy((char *)&sendBuffer[count],m->getFilename());
+ count+=len+1;
+ }
+ delete ml;
+
+ *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
+
+ log->log("Client", Log::DEBUG, "getMediaList size %u", ntohl(*(ULONG*)&sendBuffer[0]));
+
+ tcp.sendPacket(sendBuffer, count);
+ delete[] sendBuffer;
+ log->log("Client", Log::DEBUG, "Written Media list");
+
+ return 1;
+}
+
+/**
+ * get image Request:
+ * 4 length
+ * 4 VDR_GETIMAGE
+ * 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
+*/
+#define MLISTBUF 500000
+int MVPClient::processGetPicture(UCHAR* data, int length)
+{
+ if (length < 12) {
+ log->log("Client", Log::ERR, "getPicture packet too short %d", length);
+ return 0;
+ }
+ if (imageFile) {
+ fclose(imageFile);
+ imageFile=NULL;
+ }
+ char * filename=NULL;
+ if (length > 4) {
+ //we have a dirname provided
+ filename=(char *)&data[4];
+ log->log("Client", Log::DEBUG, "getPicture %s", filename);
+ }
+ else {
+ log->log("Client", Log::ERR, "getPicture empty filename");
+ }
+ if (filename) {
+ imageFile=fopen(filename,"r");
+ if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename);
+ }
+ int size=0;
+ if (imageFile) {
+ struct stat st;
+ if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size;
+ }
+ UCHAR* sendBuffer = new UCHAR[12];
+ int count = 4; // leave space for the header
+ //response code (not yet set)
+ *(ULONG*)&sendBuffer[count] = htonl(31);
+ count += 4;
+ //size
+ *(ULONG*)&sendBuffer[count] = htonl(size);
+ count += 4;
+ *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
+ log->log("Client", Log::DEBUG, "getPicture size %u", size);
+
+ tcp.sendPacket(sendBuffer, count);
+ delete[] sendBuffer;
+ log->log("Client", Log::DEBUG, "Written Media list");
+
+ return 1;
+}
+
+
+int MVPClient::processGetImageBlock(UCHAR* data, int length)
+{
+ if (!imageFile)
+ {
+ log->log("Client", Log::DEBUG, "Get image block called when no image active");
+ return 0;
+ }
+
+ ULLONG position = ntohll(*(ULLONG*)data);
+ data += sizeof(ULLONG);
+ ULONG amount = ntohl(*(ULONG*)data);
+
+ log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount);
+
+ UCHAR sendBuffer[amount + 4];
+ ULONG amountReceived = 0; // compiler moan.
+ ULLONG cpos=ftell(imageFile);
+ if (position != cpos) {
+ fseek(imageFile,position-cpos,SEEK_CUR);
+ }
+ if (position != (ULLONG)ftell(imageFile)) {
+ log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position);
+ }
+ else {
+ amountReceived=fread(&sendBuffer[4],1,amount,imageFile);
+ }
+
+ if (!amountReceived)
+ {
+ sendULONG(0);
+ log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
+ }
+ else
+ {
+ *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
+ tcp.sendPacket(sendBuffer, amountReceived + 4);
+ log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
+ }
+
+ return 1;
+}
+
+
#include "mvpreceiver.h"
#include "recplayer.h"
#include "config.h"
+#include "media.h"
class MVPClient
{
public:
- MVPClient(char* configDirExtra, int tsocket);
+ MVPClient(Config* baseConfig, char* configDirExtra, int tsocket);
~MVPClient();
int run();
int initted;
TCP tcp;
Config config;
+ Config* baseConfig;
MVPReceiver* lp;
bool loggedIn;
char* configDirExtra;
+ FILE* imageFile;
cRecordings* recordingManager;
int processGetRecInfo(UCHAR* data, int length);
int processGetMarks(UCHAR* data, int length);
int processGetChannelPids(UCHAR* data, int length);
+ int processGetMediaList(UCHAR* data, int length);
+ int processGetPicture(UCHAR* data, int length);
+ int processGetImageBlock(UCHAR* data, int length);
int processReScanRecording(UCHAR* data, int length); // FIXME obselete
while(1)
{
clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length);
- MVPClient* m = new MVPClient(configDirExtra, clientSocket);
+ MVPClient* m = new MVPClient(&config, configDirExtra, clientSocket);
m->run();
}
}
+