2 Copyright 2008 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #ifndef VOMPSTANDALONE
24 #include <vdr/recording.h>
25 #include <vdr/channels.h>
26 #include <vdr/videodir.h>
27 #include <vdr/plugin.h>
28 #include <vdr/timers.h>
30 #include "recplayer.h"
31 #include "mvpreceiver.h"
34 #include "vompclientrrproc.h"
35 #include "vompclient.h"
38 #include "mediaplayer.h"
39 #include "servermediafile.h"
41 #include "vdrcommand.h"
43 VompClientRRProc::VompClientRRProc(VompClient& x)
46 log = Log::getInstance();
51 VompClientRRProc::~VompClientRRProc()
56 bool VompClientRRProc::init()
61 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
65 Now we have a queue system is used,
66 since on rare occasion the client fire two request at once
67 e.g. heavily channel switching
68 then processing only a single request would cause a deadlock in the client
73 req_queue.push(newRequest);
75 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
81 void VompClientRRProc::threadMethod()
84 log->log("RRProc", Log::DEBUG, "threadMethod startup");
86 if (req_queue.size() != 0)
88 log->log("RRProc", Log::ERR, "threadMethod err 1");
95 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
96 threadWaitForSignal(); // unlocks, waits, relocks
97 if (req_queue.size() == 0)
99 log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");
104 // signalled with something in queue
106 log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
108 while (req_queue.size())
110 //log->log("RRProc", Log::DEBUG, "thread while");
111 req = req_queue.front();
114 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
116 if (!processPacket())
118 log->log("RRProc", Log::ERR, "processPacket exited with fail");
125 // locked and run out of packets to process
129 bool VompClientRRProc::processPacket()
131 resp = new ResponsePacket();
132 if (!resp->init(req->requestID))
134 log->log("RRProc", Log::ERR, "response packet init fail");
137 if (req->data) free(req->data);
149 result = processLogin();
151 #ifndef VOMPSTANDALONE
153 result = processGetRecordingsList();
156 result = processDeleteRecording();
159 result = processGetChannelsList();
162 result = processStartStreamingChannel();
165 result = processGetBlock();
168 result = processStopStreaming();
171 result = processStartStreamingRecording();
174 result = processGetChannelSchedule();
178 result = processConfigSave();
181 result = processConfigLoad();
183 #ifndef VOMPSTANDALONE
185 result = processReScanRecording(); // FIXME obselete
188 result = processGetTimers();
191 result = processSetTimer();
194 result = processPositionFromFrameNumber();
197 result = processFrameNumberFromPosition();
200 result = processMoveRecording();
203 result = processGetIFrame();
206 result = processGetRecInfo();
209 result = processGetMarks();
212 result = processGetChannelPids();
215 result = processDeleteTimer();
218 case VDR_GETMEDIALIST:
219 result = processGetMediaList();
222 result = processOpenMedia();
224 case VDR_GETMEDIABLOCK:
225 result = processGetMediaBlock();
228 result = processGetLanguageList();
231 result = processGetLanguageContent();
233 case VDR_GETMEDIAINFO:
234 result= processGetMediaInfo();
236 case VDR_CLOSECHANNEL:
237 result= processCloseMediaChannel();
245 if (req->data) free(req->data);
249 if (result) return true;
253 int VompClientRRProc::processLogin()
255 if (req->dataLength != 6) return 0;
259 char configFileName[PATH_MAX];
260 snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", x.configDir, req->data[0], req->data[1], req->data[2], req->data[3], req->data[4], req->data[5]);
261 x.config.init(configFileName);
263 // Send the login reply
265 time_t timeNow = time(NULL);
266 struct tm* timeStruct = localtime(&timeNow);
267 int timeOffset = timeStruct->tm_gmtoff;
269 resp->addULONG(timeNow);
270 resp->addLONG(timeOffset);
272 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
273 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
279 int VompClientRRProc::processConfigSave()
281 char* section = (char*)req->data;
285 for (UINT k = 0; k < req->dataLength; k++)
287 if (req->data[k] == '\0')
291 key = (char*)&req->data[k+1];
295 value = (char*)&req->data[k+1];
301 // if the last string (value) doesnt have null terminator, give up
302 if (req->data[req->dataLength - 1] != '\0') return 0;
304 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
305 if (x.config.setValueString(section, key, value))
315 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
320 int VompClientRRProc::processConfigLoad()
322 char* section = (char*)req->data;
325 for (UINT k = 0; k < req->dataLength; k++)
327 if (req->data[k] == '\0')
329 key = (char*)&req->data[k+1];
334 char* value = x.config.getValueString(section, key);
338 resp->addString(value);
339 log->log("RRProc", Log::DEBUG, "Written config load packet");
345 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
349 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
355 //helper for sending from a serialize buffer
356 //insert the used len into the first 4 Bytes of the buffer
357 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
358 resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
360 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
364 * media List Request:
365 * Media List response:
368 #define MLISTBUF 500000
369 int VompClientRRProc::processGetMediaList()
371 SerializeBuffer buffer(req->data,req->dataLength);
372 MediaURI uri(0,NULL,NULL);
373 VDR_GetMediaListRequest request(&uri);
374 if (request.deserialize(&buffer) != 0) {
375 log->log("Client", Log::ERR, "getMediaList unable to deserialize");
378 const char *dirname=uri.getName();
379 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
382 if (dirname == NULL) {
383 ml=x.media->getRootList();
385 ml=x.media->getMediaList(&uri);
388 log->log("Client", Log::ERR, "getMediaList returned NULL");
391 SerializeBuffer rbuf(MLISTBUF,false,true);
392 ULONG flags=0; //TODO: real error handling by setting flags
393 VDR_GetMediaListResponse response(&flags,ml);
394 if (response.serialize(&rbuf) != 0) {
395 log->log("Client", Log::ERR, "getMediaList returned NULL");
399 log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size());
404 log->log("Client", Log::DEBUG, "Written Media list");
409 * openMedia response:
411 int VompClientRRProc::processOpenMedia()
413 SerializeBuffer buffer(req->data,req->dataLength);
414 MediaURI uri(0,NULL,NULL);
418 VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
419 if (request.deserialize(&buffer) != 0) {
420 log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
423 const char *name=uri.getName();
424 log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
426 int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
431 log->log("Client", Log::ERR, "openMediaRequest unable to open");
433 VDR_OpenMediumResponse response(&flags,&size);
434 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
435 if (response.serialize(&rbuf) != 0) {
436 log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
439 log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size);
446 * packet - no serialized response!
448 int VompClientRRProc::processGetMediaBlock()
450 SerializeBuffer buffer(req->data,req->dataLength);
454 VDR_GetMediaBlockRequest request(&channel,&position,&amount);
455 if (request.deserialize(&buffer) != 0) {
456 log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
459 log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
461 UCHAR sendBuffer[amount ];
462 ULONG amountReceived = 0;
463 UCHAR *rbuf=sendBuffer;
464 int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
465 if (!amountReceived || rt != 0)
467 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
471 if (rbuf != sendBuffer) {
472 //the provider did not use the optimized handling with using my buffer
473 resp->copyin(rbuf,amountReceived);
476 // the provider did not allocate a new buffer
477 resp->copyin(sendBuffer,amountReceived);
481 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
482 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
489 int VompClientRRProc::processGetMediaInfo()
491 SerializeBuffer buffer(req->data,req->dataLength);
493 VDR_GetMediaInfoRequest request(&channel);
494 if (request.deserialize(&buffer) != 0) {
495 log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
498 log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
501 int rt=x.media->getMediaInfo(channel,&mi);
504 log->log("Client", Log::ERR, "getMediaInfo unable to get");
506 VDR_GetMediaInfoResponse response(&flags,&mi);
507 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
508 if (response.serialize(&rbuf) != 0) {
509 log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
521 int VompClientRRProc::processCloseMediaChannel()
523 SerializeBuffer buffer(req->data,req->dataLength);
525 VDR_CloseMediaChannelRequest request(&channel);
526 if (request.deserialize(&buffer) != 0) {
527 log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
531 log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
532 int rt=x.media->closeMediaChannel(channel);
535 log->log("Client", Log::ERR, "closeMediaChannel unable to get");
537 VDR_CloseMediaChannelResponse response(&flags);
538 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
539 if (response.serialize(&rbuf) != 0) {
540 log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
549 int VompClientRRProc::processGetLanguageList()
551 x.i18n.findLanguages();
552 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
554 I18n::lang_code_list::const_iterator iter;
555 for (iter = languages.begin(); iter != languages.end(); ++iter)
557 resp->addString(iter->first.c_str());
558 resp->addString(iter->second.c_str());
561 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
565 int VompClientRRProc::processGetLanguageContent()
567 if (req->dataLength <= 0) return 0;
568 std::string code, result;
569 code.assign((char*)req->data, req->dataLength - 1);
570 x.i18n.findLanguages();
571 I18n::trans_table texts = x.i18n.getLanguageContent(code);
572 I18n::trans_table::const_iterator iter;
573 for (iter = texts.begin(); iter != texts.end(); ++iter)
575 resp->addString(iter->first.c_str());
576 resp->addString(iter->second.c_str());
579 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
583 #ifndef VOMPSTANDALONE
585 int VompClientRRProc::processGetRecordingsList()
588 int Percent = VideoDiskSpace(&FreeMB);
589 int Total = (FreeMB / (100 - Percent)) * 100;
591 resp->addULONG(Total);
592 resp->addULONG(FreeMB);
593 resp->addULONG(Percent);
595 cRecordings Recordings;
598 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
600 resp->addULONG(recording->start);
601 resp->addString(recording->Name());
602 resp->addString(recording->FileName());
606 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
608 log->log("RRProc", Log::DEBUG, "Written recordings list");
613 int VompClientRRProc::processDeleteRecording()
615 // data is a pointer to the fileName string
617 cRecordings Recordings;
618 Recordings.Load(); // probably have to do this
620 cRecording* recording = Recordings.GetByName((char*)req->data);
622 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
626 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
628 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
631 if (recording->Delete())
633 // Copy svdrp's way of doing this, see if it works
634 #if VDRVERSNUM > 10300
635 ::Recordings.DelByName(recording->FileName());
655 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
660 int VompClientRRProc::processMoveRecording()
662 log->log("RRProc", Log::DEBUG, "Process move recording");
663 char* fileName = (char*)req->data;
664 char* newPath = NULL;
666 for (UINT k = 0; k < req->dataLength; k++)
668 if (req->data[k] == '\0')
670 newPath = (char*)&req->data[k+1];
674 if (!newPath) return 0;
676 cRecordings Recordings;
677 Recordings.Load(); // probably have to do this
679 cRecording* recording = Recordings.GetByName((char*)fileName);
681 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
685 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
688 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
689 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
690 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
692 const char* t = recording->FileName();
694 char* dateDirName = NULL; int k;
695 char* titleDirName = NULL; int j;
697 // Find the datedirname
698 for(k = strlen(t) - 1; k >= 0; k--)
702 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
703 dateDirName = new char[strlen(&t[k+1]) + 1];
704 strcpy(dateDirName, &t[k+1]);
709 // Find the titledirname
711 for(j = k-1; j >= 0; j--)
715 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
716 titleDirName = new char[(k - j - 1) + 1];
717 memcpy(titleDirName, &t[j+1], k - j - 1);
718 titleDirName[k - j - 1] = '\0';
723 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
724 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
725 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
727 char* newPathConv = new char[strlen(newPath)+1];
728 strcpy(newPathConv, newPath);
729 ExchangeChars(newPathConv, true);
730 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
732 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
733 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
734 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
735 delete[] newPathConv;
737 log->log("RRProc", Log::DEBUG, "%s", newContainer);
740 int statret = stat(newContainer, &dstat);
741 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
743 log->log("RRProc", Log::DEBUG, "new dir does not exist");
744 int mkdirret = mkdir(newContainer, 0755);
747 delete[] dateDirName;
748 delete[] titleDirName;
749 delete[] newContainer;
753 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
757 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
759 delete[] dateDirName;
760 delete[] titleDirName;
761 delete[] newContainer;
765 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
769 // Ok, the directory container has been made, or it pre-existed.
771 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
772 sprintf(newDir, "%s/%s", newContainer, dateDirName);
774 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
775 int renameret = rename(t, newDir);
778 // Success. Test for remove old dir containter
779 char* oldTitleDir = new char[k+1];
780 memcpy(oldTitleDir, t, k);
781 oldTitleDir[k] = '\0';
782 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
783 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
784 delete[] oldTitleDir;
789 #if VDRVERSNUM > 10311
791 ::Recordings.Update();
793 // Success. Send a different packet from just a ulong
794 resp->addULONG(1); // success
795 resp->addString(newDir);
803 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
805 delete[] dateDirName;
806 delete[] titleDirName;
807 delete[] newContainer;
814 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
821 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
827 int VompClientRRProc::processGetChannelsList()
831 char* chanConfig = x.config.getValueString("General", "Channels");
833 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
835 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
837 #if VDRVERSNUM < 10300
838 if (!channel->GroupSep() && (!channel->Ca() || allChans))
840 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
843 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
845 if (channel->Vpid()) type = 1;
846 #if VDRVERSNUM < 10300
849 else if (channel->Apid(0)) type = 2;
853 resp->addULONG(channel->Number());
854 resp->addULONG(type);
855 resp->addString(channel->Name());
860 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
862 log->log("RRProc", Log::DEBUG, "Written channels list");
867 int VompClientRRProc::processGetChannelPids()
869 ULONG channelNumber = ntohl(*(ULONG*)req->data);
871 cChannel* channel = x.channelFromNumber(channelNumber);
876 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
885 #if VDRVERSNUM < 10300
887 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
888 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
890 if (channel->Apid2())
892 else if (channel->Apid1())
899 for (const int *Apid = channel->Apids(); *Apid; Apid++)
903 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
907 for (const int *Spid = channel->Spids(); *Spid; Spid++)
914 // Format of response
933 resp->addULONG(channel->Vpid());
934 resp->addULONG(numApids);
936 #if VDRVERSNUM < 10300
939 resp->addULONG(channel->Apid1());
944 resp->addULONG(channel->Apid2());
950 for (ULONG i = 0; i < numApids; i++)
952 resp->addULONG(channel->Apid(i));
953 resp->addString(channel->Alang(i));
955 resp->addULONG(numDpids);
956 for (ULONG i = 0; i < numDpids; i++)
958 resp->addULONG(channel->Dpid(i));
959 resp->addString(channel->Dlang(i));
961 resp->addULONG(numSpids);
962 for (ULONG i = 0; i < numSpids; i++)
964 resp->addULONG(channel->Spid(i));
965 resp->addString(channel->Slang(i));
968 resp->addULONG(channel->Tpid());
972 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
974 log->log("RRProc", Log::DEBUG, "Written channels pids");
979 int VompClientRRProc::processStartStreamingChannel()
983 log->log("RRProc", Log::ERR, "Client called start streaming twice");
987 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
988 ULONG channelNumber = ntohl(*(ULONG*)req->data);
990 cChannel* channel = x.channelFromNumber(channelNumber);
995 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
999 // get the priority we should use
1001 int priority = x.config.getValueLong("General", "Live priority", &fail);
1004 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1008 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1012 // a bit of sanity..
1013 if (priority < 0) priority = 0;
1014 if (priority > 99) priority = 99;
1016 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1017 x.lp = MVPReceiver::create(channel, priority);
1023 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1027 if (!x.lp->init(&x.tcp, req->requestID))
1033 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1039 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1043 int VompClientRRProc::processStopStreaming()
1045 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1051 else if (x.recplayer)
1053 x.writeResumeData();
1056 delete x.recordingManager;
1058 x.recordingManager = NULL;
1063 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1067 int VompClientRRProc::processGetBlock()
1071 log->log("RRProc", Log::ERR, "Get block called during live streaming");
1077 log->log("RRProc", Log::ERR, "Get block called when no recording open");
1081 UCHAR* data = req->data;
1083 ULLONG position = x.ntohll(*(ULLONG*)data);
1084 data += sizeof(ULLONG);
1085 ULONG amount = ntohl(*(ULONG*)data);
1087 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1089 UCHAR sendBuffer[amount];
1090 ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1092 if (!amountReceived)
1095 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1099 resp->copyin(sendBuffer, amountReceived);
1100 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1104 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1105 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1109 int VompClientRRProc::processStartStreamingRecording()
1111 // data is a pointer to the fileName string
1113 x.recordingManager = new cRecordings;
1114 x.recordingManager->Load();
1116 cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1118 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1122 x.recplayer = new RecPlayer(recording);
1124 resp->addULLONG(x.recplayer->getLengthBytes());
1125 resp->addULONG(x.recplayer->getLengthFrames());
1127 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1129 log->log("RRProc", Log::DEBUG, "written totalLength");
1133 delete x.recordingManager;
1134 x.recordingManager = NULL;
1139 int VompClientRRProc::processPositionFromFrameNumber()
1143 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1147 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1151 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1154 resp->addULLONG(retval);
1156 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1158 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1162 int VompClientRRProc::processFrameNumberFromPosition()
1166 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1170 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1174 retval = x.recplayer->frameNumberFromPosition(position);
1177 resp->addULONG(retval);
1179 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1181 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1185 int VompClientRRProc::processGetIFrame()
1187 bool success = false;
1189 ULONG* data = (ULONG*)req->data;
1191 ULONG frameNumber = ntohl(*data);
1193 ULONG direction = ntohl(*data);
1195 ULLONG rfilePosition = 0;
1196 ULONG rframeNumber = 0;
1197 ULONG rframeLength = 0;
1201 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1205 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1208 // returns file position, frame number, length
1212 resp->addULLONG(rfilePosition);
1213 resp->addULONG(rframeNumber);
1214 resp->addULONG(rframeLength);
1222 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1224 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1228 int VompClientRRProc::processGetChannelSchedule()
1230 ULONG* data = (ULONG*)req->data;
1232 ULONG channelNumber = ntohl(*data);
1234 ULONG startTime = ntohl(*data);
1236 ULONG duration = ntohl(*data);
1238 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1240 cChannel* channel = x.channelFromNumber(channelNumber);
1245 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1247 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1251 log->log("RRProc", Log::DEBUG, "Got channel");
1253 #if VDRVERSNUM < 10300
1254 cMutexLock MutexLock;
1255 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1257 cSchedulesLock MutexLock;
1258 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1264 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1266 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1270 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1272 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1277 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1279 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1283 log->log("RRProc", Log::DEBUG, "Got schedule object");
1285 const char* empty = "";
1286 bool atLeastOneEvent = false;
1289 ULONG thisEventTime;
1290 ULONG thisEventDuration;
1291 const char* thisEventTitle;
1292 const char* thisEventSubTitle;
1293 const char* thisEventDescription;
1295 #if VDRVERSNUM < 10300
1297 const cEventInfo *event;
1298 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1300 event = Schedule->GetEventNumber(eventNumber);
1302 thisEventID = event->GetEventID();
1303 thisEventTime = event->GetTime();
1304 thisEventDuration = event->GetDuration();
1305 thisEventTitle = event->GetTitle();
1306 thisEventSubTitle = event->GetSubtitle();
1307 thisEventDescription = event->GetExtendedDescription();
1311 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1313 thisEventID = event->EventID();
1314 thisEventTime = event->StartTime();
1315 thisEventDuration = event->Duration();
1316 thisEventTitle = event->Title();
1317 thisEventSubTitle = NULL;
1318 thisEventDescription = event->Description();
1322 //in the past filter
1323 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1326 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1329 if (thisEventTime >= (startTime + duration)) continue;
1331 if (!thisEventTitle) thisEventTitle = empty;
1332 if (!thisEventSubTitle) thisEventSubTitle = empty;
1333 if (!thisEventDescription) thisEventDescription = empty;
1335 resp->addULONG(thisEventID);
1336 resp->addULONG(thisEventTime);
1337 resp->addULONG(thisEventDuration);
1339 resp->addString(thisEventTitle);
1340 resp->addString(thisEventSubTitle);
1341 resp->addString(thisEventDescription);
1343 atLeastOneEvent = true;
1346 log->log("RRProc", Log::DEBUG, "Got all event data");
1348 if (!atLeastOneEvent)
1351 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1355 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1357 log->log("RRProc", Log::DEBUG, "written schedules packet");
1362 int VompClientRRProc::processGetTimers()
1365 int numTimers = Timers.Count();
1367 resp->addULONG(numTimers);
1369 for (int i = 0; i < numTimers; i++)
1371 timer = Timers.Get(i);
1373 #if VDRVERSNUM < 10300
1374 resp->addULONG(timer->Active());
1376 resp->addULONG(timer->HasFlags(tfActive));
1378 resp->addULONG(timer->Recording());
1379 resp->addULONG(timer->Pending());
1380 resp->addULONG(timer->Priority());
1381 resp->addULONG(timer->Lifetime());
1382 resp->addULONG(timer->Channel()->Number());
1383 resp->addULONG(timer->StartTime());
1384 resp->addULONG(timer->StopTime());
1385 resp->addULONG(timer->Day());
1386 resp->addULONG(timer->WeekDays());
1387 resp->addString(timer->File());
1391 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1393 log->log("RRProc", Log::DEBUG, "Written timers list");
1398 int VompClientRRProc::processSetTimer()
1400 char* timerString = new char[strlen((char*)req->data) + 1];
1401 strcpy(timerString, (char*)req->data);
1403 #if VDRVERSNUM < 10300
1405 // If this is VDR 1.2 the date part of the timer string must be reduced
1406 // to just DD rather than YYYY-MM-DD
1408 int s = 0; // source
1409 int d = 0; // destination
1411 while(c != 2) // copy up to date section, including the second ':'
1413 timerString[d] = req->data[s];
1414 if (req->data[s] == ':') c++;
1418 // now it has copied up to the date section
1420 while(c != 2) // waste YYYY-MM-
1422 if (req->data[s] == '-') c++;
1425 // now source is at the DD
1426 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1427 d += req->dataLength - s;
1428 timerString[d] = '\0';
1430 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1431 log->log("RRProc", Log::DEBUG, "%s", timerString);
1435 cTimer *timer = new cTimer;
1436 if (timer->Parse((char*)timerString))
1438 cTimer *t = Timers.GetTimer(timer);
1442 #if VDRVERSNUM < 10300
1445 Timers.SetModified();
1449 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1456 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1463 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1469 int VompClientRRProc::processDeleteTimer()
1471 log->log("RRProc", Log::DEBUG, "Delete timer called");
1476 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1477 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1478 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1479 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1480 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1483 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1485 if ( (ti->Channel()->Number() == delChannel)
1486 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1487 && (ti->StartTime() == delStart)
1488 && (ti->StopTime() == delStop) )
1496 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1500 if (!Timers.BeingEdited())
1502 if (!ti->Recording())
1505 Timers.SetModified();
1508 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1513 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1516 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1522 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1525 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1530 int VompClientRRProc::processGetRecInfo()
1532 // data is a pointer to the fileName string
1534 cRecordings Recordings;
1535 Recordings.Load(); // probably have to do this
1537 cRecording *recording = Recordings.GetByName((char*)req->data);
1539 time_t timerStart = 0;
1540 time_t timerStop = 0;
1541 char* summary = NULL;
1542 ULONG resumePoint = 0;
1546 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1549 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1554 4 bytes: start time for timer
1555 4 bytes: end time for timer
1556 4 bytes: resume point
1558 4 bytes: num components
1568 // Get current timer
1570 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1573 timerStart = rc->Timer()->StartTime();
1574 timerStop = rc->Timer()->StopTime();
1575 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1578 resp->addULONG(timerStart);
1579 resp->addULONG(timerStop);
1583 char* value = x.config.getValueString("ResumeData", (char*)req->data);
1586 resumePoint = strtoul(value, NULL, 10);
1589 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1591 resp->addULONG(resumePoint);
1596 #if VDRVERSNUM < 10300
1597 summary = (char*)recording->Summary();
1599 const cRecordingInfo *Info = recording->Info();
1600 summary = (char*)Info->ShortText();
1601 if (isempty(summary)) summary = (char*)Info->Description();
1603 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1606 resp->addString(summary);
1610 resp->addString("");
1615 #if VDRVERSNUM < 10300
1617 // Send 0 for numchannels - this signals the client this info is not available
1621 const cComponents* components = Info->Components();
1623 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1631 resp->addULONG(components->NumComponents());
1633 tComponent* component;
1634 for (int i = 0; i < components->NumComponents(); i++)
1636 component = components->Component(i);
1638 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1640 resp->addUCHAR(component->stream);
1641 resp->addUCHAR(component->type);
1643 if (component->language)
1645 resp->addString(component->language);
1649 resp->addString("");
1651 if (component->description)
1653 resp->addString(component->description);
1657 resp->addString("");
1667 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1669 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1679 int VompClientRRProc::processReScanRecording()
1683 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1687 x.recplayer->scan();
1689 resp->addULLONG(x.recplayer->getLengthBytes());
1690 resp->addULONG(x.recplayer->getLengthFrames());
1692 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1693 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1697 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1699 int VompClientRRProc::processGetMarks()
1701 // data is a pointer to the fileName string
1704 cRecordings Recordings;
1705 Recordings.Load(); // probably have to do this
1707 cRecording *recording = Recordings.GetByName((char*)req->data);
1709 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1713 Marks.Load(recording->FileName());
1716 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1718 log->log("RRProc", Log::DEBUG, "found Mark %i", m->position);
1720 resp->addULONG(m->position);
1725 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
1731 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1733 log->log("RRProc", Log::DEBUG, "Written Marks list");
1738 #endif // !VOMPSTANDALONE