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"
45 VompClientRRProc::VompClientRRProc(VompClient& x)
48 log = Log::getInstance();
53 VompClientRRProc::~VompClientRRProc()
58 bool VompClientRRProc::init()
60 int a = threadStart();
65 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
69 Now we have a queue system is used,
70 since on rare occasion the client fire two request at once
71 e.g. heavily channel switching
72 then processing only a single request would cause a deadlock in the client
76 log->log("RRProc", Log::DEBUG, "recvReq");
78 req_queue.push(newRequest);
80 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
86 void VompClientRRProc::threadMethod()
89 log->log("RRProc", Log::DEBUG, "threadMethod startup");
91 if (req_queue.size() != 0)
93 log->log("RRProc", Log::ERR, "threadMethod err 1");
100 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
101 threadWaitForSignal(); // unlocks, waits, relocks
102 if (req_queue.size() == 0)
104 log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");
109 // signalled with something in queue
111 log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
113 while (req_queue.size())
115 //log->log("RRProc", Log::DEBUG, "thread while");
116 req = req_queue.front();
119 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
121 if (!processPacket())
123 log->log("RRProc", Log::ERR, "processPacket exited with fail");
130 // locked and run out of packets to process
134 bool VompClientRRProc::processPacket()
136 resp = new ResponsePacket();
137 if (!resp->init(req->requestID))
139 log->log("RRProc", Log::ERR, "response packet init fail");
142 if (req->data) free(req->data);
154 result = processLogin();
156 #ifndef VOMPSTANDALONE
158 result = processGetRecordingsList();
161 result = processDeleteRecording();
164 result = processGetChannelsList();
167 result = processStartStreamingChannel();
170 result = processGetBlock();
173 result = processStopStreaming();
176 result = processStartStreamingRecording();
179 result = processGetChannelSchedule();
183 result = processConfigSave();
186 result = processConfigLoad();
188 #ifndef VOMPSTANDALONE
190 result = processReScanRecording(); // FIXME obselete
193 result = processGetTimers();
196 result = processSetTimer();
199 result = processPositionFromFrameNumber();
202 result = processFrameNumberFromPosition();
205 result = processMoveRecording();
208 result = processGetIFrame();
211 result = processGetRecInfo();
214 result = processGetMarks();
217 result = processGetChannelPids();
220 result = processDeleteTimer();
223 case VDR_GETMEDIALIST:
224 result = processGetMediaList();
227 result = processOpenMedia();
229 case VDR_GETMEDIABLOCK:
230 result = processGetMediaBlock();
233 result = processGetLanguageList();
236 result = processGetLanguageContent();
238 case VDR_GETMEDIAINFO:
239 result= processGetMediaInfo();
241 case VDR_CLOSECHANNEL:
242 result= processCloseMediaChannel();
250 if (req->data) free(req->data);
254 if (result) return true;
258 int VompClientRRProc::processLogin()
260 if (req->dataLength != 6) return 0;
264 char configFileName[PATH_MAX];
265 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]);
266 x.config.init(configFileName);
268 // Send the login reply
270 time_t timeNow = time(NULL);
271 struct tm* timeStruct = localtime(&timeNow);
272 int timeOffset = timeStruct->tm_gmtoff;
274 resp->addULONG(timeNow);
275 resp->addLONG(timeOffset);
277 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
278 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
281 x.netLog(); // safe to run here since the client won't start net logging for a while yet
286 int VompClientRRProc::processConfigSave()
288 char* section = (char*)req->data;
292 for (UINT k = 0; k < req->dataLength; k++)
294 if (req->data[k] == '\0')
298 key = (char*)&req->data[k+1];
302 value = (char*)&req->data[k+1];
308 // if the last string (value) doesnt have null terminator, give up
309 if (req->data[req->dataLength - 1] != '\0') return 0;
311 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
312 if (x.config.setValueString(section, key, value))
322 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
327 int VompClientRRProc::processConfigLoad()
329 char* section = (char*)req->data;
332 for (UINT k = 0; k < req->dataLength; k++)
334 if (req->data[k] == '\0')
336 key = (char*)&req->data[k+1];
341 char* value = x.config.getValueString(section, key);
345 resp->addString(value);
346 log->log("RRProc", Log::DEBUG, "Written config load packet");
352 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
356 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
362 //helper for sending from a serialize buffer
363 //insert the used len into the first 4 Bytes of the buffer
364 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
365 resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
367 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
371 * media List Request:
372 * Media List response:
375 #define MLISTBUF 500000
376 int VompClientRRProc::processGetMediaList()
378 SerializeBuffer buffer(req->data,req->dataLength);
379 MediaURI uri(0,NULL,NULL);
380 VDR_GetMediaListRequest request(&uri);
381 if (request.deserialize(&buffer) != 0) {
382 log->log("Client", Log::ERR, "getMediaList unable to deserialize");
385 const char *dirname=uri.getName();
386 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
389 if (dirname == NULL) {
390 ml=x.media->getRootList();
392 ml=x.media->getMediaList(&uri);
395 log->log("Client", Log::ERR, "getMediaList returned NULL");
398 SerializeBuffer rbuf(MLISTBUF,false,true);
399 ULONG flags=0; //TODO: real error handling by setting flags
400 VDR_GetMediaListResponse response(&flags,ml);
401 if (response.serialize(&rbuf) != 0) {
402 log->log("Client", Log::ERR, "getMediaList returned NULL");
406 log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size());
411 log->log("Client", Log::DEBUG, "Written Media list");
416 * openMedia response:
418 int VompClientRRProc::processOpenMedia()
420 SerializeBuffer buffer(req->data,req->dataLength);
421 MediaURI uri(0,NULL,NULL);
425 VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
426 if (request.deserialize(&buffer) != 0) {
427 log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
430 const char *name=uri.getName();
431 log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
433 int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
438 log->log("Client", Log::ERR, "openMediaRequest unable to open");
440 VDR_OpenMediumResponse response(&flags,&size);
441 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
442 if (response.serialize(&rbuf) != 0) {
443 log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
446 log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size);
453 * packet - no serialized response!
455 int VompClientRRProc::processGetMediaBlock()
457 SerializeBuffer buffer(req->data,req->dataLength);
461 VDR_GetMediaBlockRequest request(&channel,&position,&amount);
462 if (request.deserialize(&buffer) != 0) {
463 log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
466 log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
468 UCHAR sendBuffer[amount ];
469 ULONG amountReceived = 0;
470 UCHAR *rbuf=sendBuffer;
471 int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
472 if (!amountReceived || rt != 0)
474 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
478 if (rbuf != sendBuffer) {
479 //the provider did not use the optimized handling with using my buffer
480 resp->copyin(rbuf,amountReceived);
483 // the provider did not allocate a new buffer
484 resp->copyin(sendBuffer,amountReceived);
488 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
489 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
496 int VompClientRRProc::processGetMediaInfo()
498 SerializeBuffer buffer(req->data,req->dataLength);
500 VDR_GetMediaInfoRequest request(&channel);
501 if (request.deserialize(&buffer) != 0) {
502 log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
505 log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
508 int rt=x.media->getMediaInfo(channel,&mi);
511 log->log("Client", Log::ERR, "getMediaInfo unable to get");
513 VDR_GetMediaInfoResponse response(&flags,&mi);
514 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
515 if (response.serialize(&rbuf) != 0) {
516 log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
528 int VompClientRRProc::processCloseMediaChannel()
530 SerializeBuffer buffer(req->data,req->dataLength);
532 VDR_CloseMediaChannelRequest request(&channel);
533 if (request.deserialize(&buffer) != 0) {
534 log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
538 log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
539 int rt=x.media->closeMediaChannel(channel);
542 log->log("Client", Log::ERR, "closeMediaChannel unable to get");
544 VDR_CloseMediaChannelResponse response(&flags);
545 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
546 if (response.serialize(&rbuf) != 0) {
547 log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
556 int VompClientRRProc::processGetLanguageList()
558 x.i18n.findLanguages();
559 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
561 I18n::lang_code_list::const_iterator iter;
562 for (iter = languages.begin(); iter != languages.end(); ++iter)
564 resp->addString(iter->first.c_str());
565 resp->addString(iter->second.c_str());
568 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
572 int VompClientRRProc::processGetLanguageContent()
574 if (req->dataLength <= 0) return 0;
575 std::string code, result;
576 code.assign((char*)req->data, req->dataLength - 1);
577 x.i18n.findLanguages();
578 I18n::trans_table texts = x.i18n.getLanguageContent(code);
579 I18n::trans_table::const_iterator iter;
580 for (iter = texts.begin(); iter != texts.end(); ++iter)
582 resp->addString(iter->first.c_str());
583 resp->addString(iter->second.c_str());
586 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
590 #ifndef VOMPSTANDALONE
592 int VompClientRRProc::processGetRecordingsList()
595 int Percent = VideoDiskSpace(&FreeMB);
596 int Total = (FreeMB / (100 - Percent)) * 100;
598 resp->addULONG(Total);
599 resp->addULONG(FreeMB);
600 resp->addULONG(Percent);
602 cRecordings Recordings;
605 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
607 #if VDRVERSNUM < 10721
608 resp->addULONG(recording->start);
610 resp->addULONG(recording->Start());
612 resp->addString(recording->Name());
613 resp->addString(recording->FileName());
617 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
619 log->log("RRProc", Log::DEBUG, "Written recordings list");
624 int VompClientRRProc::processDeleteRecording()
626 // data is a pointer to the fileName string
628 cRecordings Recordings;
629 Recordings.Load(); // probably have to do this
631 cRecording* recording = Recordings.GetByName((char*)req->data);
633 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
637 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
639 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
642 if (recording->Delete())
644 // Copy svdrdeveldevelp's way of doing this, see if it works
645 #if VDRVERSNUM > 10300
646 ::Recordings.DelByName(recording->FileName());
666 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
671 int VompClientRRProc::processMoveRecording()
673 log->log("RRProc", Log::DEBUG, "Process move recording");
674 char* fileName = (char*)req->data;
675 char* newPath = NULL;
677 for (UINT k = 0; k < req->dataLength; k++)
679 if (req->data[k] == '\0')
681 newPath = (char*)&req->data[k+1];
685 if (!newPath) return 0;
687 cRecordings Recordings;
688 Recordings.Load(); // probably have to do this
690 cRecording* recording = Recordings.GetByName((char*)fileName);
692 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
696 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
699 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
700 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
701 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
703 const char* t = recording->FileName();
705 char* dateDirName = NULL; int k;
706 char* titleDirName = NULL; int j;
708 // Find the datedirname
709 for(k = strlen(t) - 1; k >= 0; k--)
713 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
714 dateDirName = new char[strlen(&t[k+1]) + 1];
715 strcpy(dateDirName, &t[k+1]);
720 // Find the titledirname
722 for(j = k-1; j >= 0; j--)
726 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
727 titleDirName = new char[(k - j - 1) + 1];
728 memcpy(titleDirName, &t[j+1], k - j - 1);
729 titleDirName[k - j - 1] = '\0';
734 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
735 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
736 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
738 char* newPathConv = new char[strlen(newPath)+1];
739 strcpy(newPathConv, newPath);
740 ExchangeChars(newPathConv, true);
741 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
743 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
744 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
745 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
746 delete[] newPathConv;
748 log->log("RRProc", Log::DEBUG, "%s", newContainer);
751 int statret = stat(newContainer, &dstat);
752 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
754 log->log("RRProc", Log::DEBUG, "new dir does not exist");
755 int mkdirret = mkdir(newContainer, 0755);
758 delete[] dateDirName;
759 delete[] titleDirName;
760 delete[] newContainer;
764 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
768 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
770 delete[] dateDirName;
771 delete[] titleDirName;
772 delete[] newContainer;
776 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
780 // Ok, the directory container has been made, or it pre-existed.
782 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
783 sprintf(newDir, "%s/%s", newContainer, dateDirName);
785 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
786 int renameret = rename(t, newDir);
789 // Success. Test for remove old dir containter
790 char* oldTitleDir = new char[k+1];
791 memcpy(oldTitleDir, t, k);
792 oldTitleDir[k] = '\0';
793 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
794 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
795 delete[] oldTitleDir;
800 #if VDRVERSNUM > 10311
802 ::Recordings.Update();
804 // Success. Send a different packet from just a ulong
805 resp->addULONG(1); // success
806 resp->addString(newDir);
814 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
816 delete[] dateDirName;
817 delete[] titleDirName;
818 delete[] newContainer;
825 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
832 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
838 int VompClientRRProc::processGetChannelsList()
842 char* chanConfig = x.config.getValueString("General", "Channels");
844 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
846 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
848 #if VDRVERSNUM < 10300
849 if (!channel->GroupSep() && (!channel->Ca() || allChans))
851 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
854 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
856 if (channel->Vpid()) type = 1;
857 #if VDRVERSNUM < 10300
860 else if (channel->Apid(0)) type = 2;
864 resp->addULONG(channel->Number());
865 resp->addULONG(type);
866 resp->addString(channel->Name());
867 #if VDRVERSNUM < 10703
870 resp->addULONG(channel->Vtype());
876 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
878 log->log("RRProc", Log::DEBUG, "Written channels list");
883 int VompClientRRProc::processGetChannelPids()
885 ULONG channelNumber = ntohl(*(ULONG*)req->data);
887 cChannel* channel = x.channelFromNumber(channelNumber);
892 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
901 #if VDRVERSNUM < 10300
903 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
904 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
906 if (channel->Apid2())
908 else if (channel->Apid1())
915 for (const int *Apid = channel->Apids(); *Apid; Apid++)
919 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
923 for (const int *Spid = channel->Spids(); *Spid; Spid++)
930 // Format of response
949 resp->addULONG(channel->Vpid());
950 #if VDRVERSNUM < 10703
953 resp->addULONG(channel->Vtype());
955 resp->addULONG(numApids);
957 #if VDRVERSNUM < 10300
960 resp->addULONG(channel->Apid1());
965 resp->addULONG(channel->Apid2());
971 for (ULONG i = 0; i < numApids; i++)
973 resp->addULONG(channel->Apid(i));
974 resp->addString(channel->Alang(i));
976 resp->addULONG(numDpids);
977 for (ULONG i = 0; i < numDpids; i++)
979 resp->addULONG(channel->Dpid(i));
980 resp->addString(channel->Dlang(i));
982 resp->addULONG(numSpids);
983 for (ULONG i = 0; i < numSpids; i++)
985 resp->addULONG(channel->Spid(i));
986 resp->addString(channel->Slang(i));
989 resp->addULONG(channel->Tpid());
993 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
995 log->log("RRProc", Log::DEBUG, "Written channels pids");
1000 int VompClientRRProc::processStartStreamingChannel()
1004 log->log("RRProc", Log::ERR, "Client called start streaming twice");
1008 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
1009 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1011 cChannel* channel = x.channelFromNumber(channelNumber);
1016 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1020 // get the priority we should use
1022 int priority = x.config.getValueLong("General", "Live priority", &fail);
1025 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1029 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1033 // a bit of sanity..
1034 if (priority < 0) priority = 0;
1035 if (priority > 99) priority = 99;
1037 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1038 x.lp = MVPReceiver::create(channel, priority);
1044 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1048 if (!x.lp->init(&x.tcp, req->requestID))
1054 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1060 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1064 int VompClientRRProc::processStopStreaming()
1066 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1072 else if (x.recplayer)
1074 x.writeResumeData();
1077 delete x.recordingManager;
1079 x.recordingManager = NULL;
1084 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1088 int VompClientRRProc::processGetBlock()
1092 log->log("RRProc", Log::ERR, "Get block called during live streaming");
1098 log->log("RRProc", Log::ERR, "Get block called when no recording open");
1102 UCHAR* data = req->data;
1104 ULLONG position = x.ntohll(*(ULLONG*)data);
1105 data += sizeof(ULLONG);
1106 ULONG amount = ntohl(*(ULONG*)data);
1108 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1110 UCHAR sendBuffer[amount];
1111 ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1113 if (!amountReceived)
1116 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1120 resp->copyin(sendBuffer, amountReceived);
1121 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1125 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1126 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1130 int VompClientRRProc::processStartStreamingRecording()
1132 // data is a pointer to the fileName string
1134 x.recordingManager = new cRecordings;
1135 x.recordingManager->Load();
1137 cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1139 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1143 x.recplayer = new RecPlayer(recording);
1145 resp->addULLONG(x.recplayer->getLengthBytes());
1146 resp->addULONG(x.recplayer->getLengthFrames());
1148 #if VDRVERSNUM < 10703
1149 resp->addUCHAR(true);//added for TS
1151 resp->addUCHAR(recording->IsPesRecording());//added for TS
1155 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1157 log->log("RRProc", Log::DEBUG, "written totalLength");
1161 delete x.recordingManager;
1162 x.recordingManager = NULL;
1167 int VompClientRRProc::processPositionFromFrameNumber()
1171 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1175 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1179 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1182 resp->addULLONG(retval);
1184 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1186 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1190 int VompClientRRProc::processFrameNumberFromPosition()
1194 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1198 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1202 retval = x.recplayer->frameNumberFromPosition(position);
1205 resp->addULONG(retval);
1207 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1209 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1213 int VompClientRRProc::processGetIFrame()
1215 bool success = false;
1217 ULONG* data = (ULONG*)req->data;
1219 ULONG frameNumber = ntohl(*data);
1221 ULONG direction = ntohl(*data);
1223 ULLONG rfilePosition = 0;
1224 ULONG rframeNumber = 0;
1225 ULONG rframeLength = 0;
1229 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1233 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1236 // returns file position, frame number, length
1240 resp->addULLONG(rfilePosition);
1241 resp->addULONG(rframeNumber);
1242 resp->addULONG(rframeLength);
1250 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1252 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1256 int VompClientRRProc::processGetChannelSchedule()
1258 ULONG* data = (ULONG*)req->data;
1260 ULONG channelNumber = ntohl(*data);
1262 ULONG startTime = ntohl(*data);
1264 ULONG duration = ntohl(*data);
1266 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1268 cChannel* channel = x.channelFromNumber(channelNumber);
1273 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1275 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1279 log->log("RRProc", Log::DEBUG, "Got channel");
1281 #if VDRVERSNUM < 10300
1282 cMutexLock MutexLock;
1283 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1285 cSchedulesLock MutexLock;
1286 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1292 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1294 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1298 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1300 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1305 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1307 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1311 log->log("RRProc", Log::DEBUG, "Got schedule object");
1313 const char* empty = "";
1314 bool atLeastOneEvent = false;
1317 ULONG thisEventTime;
1318 ULONG thisEventDuration;
1319 const char* thisEventTitle;
1320 const char* thisEventSubTitle;
1321 const char* thisEventDescription;
1323 #if VDRVERSNUM < 10300
1325 const cEventInfo *event;
1326 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1328 event = Schedule->GetEventNumber(eventNumber);
1330 thisEventID = event->GetEventID();
1331 thisEventTime = event->GetTime();
1332 thisEventDuration = event->GetDuration();
1333 thisEventTitle = event->GetTitle();
1334 thisEventSubTitle = event->GetSubtitle();
1335 thisEventDescription = event->GetExtendedDescription();
1339 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1341 thisEventID = event->EventID();
1342 thisEventTime = event->StartTime();
1343 thisEventDuration = event->Duration();
1344 thisEventTitle = event->Title();
1345 thisEventSubTitle = NULL;
1346 thisEventDescription = event->Description();
1350 //in the past filter
1351 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1354 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1357 if (thisEventTime >= (startTime + duration)) continue;
1359 if (!thisEventTitle) thisEventTitle = empty;
1360 if (!thisEventSubTitle) thisEventSubTitle = empty;
1361 if (!thisEventDescription) thisEventDescription = empty;
1363 resp->addULONG(thisEventID);
1364 resp->addULONG(thisEventTime);
1365 resp->addULONG(thisEventDuration);
1367 resp->addString(thisEventTitle);
1368 resp->addString(thisEventSubTitle);
1369 resp->addString(thisEventDescription);
1371 atLeastOneEvent = true;
1374 log->log("RRProc", Log::DEBUG, "Got all event data");
1376 if (!atLeastOneEvent)
1379 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1383 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1385 log->log("RRProc", Log::DEBUG, "written schedules packet");
1390 int VompClientRRProc::processGetTimers()
1393 int numTimers = Timers.Count();
1395 resp->addULONG(numTimers);
1397 for (int i = 0; i < numTimers; i++)
1399 timer = Timers.Get(i);
1401 #if VDRVERSNUM < 10300
1402 resp->addULONG(timer->Active());
1404 resp->addULONG(timer->HasFlags(tfActive));
1406 resp->addULONG(timer->Recording());
1407 resp->addULONG(timer->Pending());
1408 resp->addULONG(timer->Priority());
1409 resp->addULONG(timer->Lifetime());
1410 resp->addULONG(timer->Channel()->Number());
1411 resp->addULONG(timer->StartTime());
1412 resp->addULONG(timer->StopTime());
1413 resp->addULONG(timer->Day());
1414 resp->addULONG(timer->WeekDays());
1415 resp->addString(timer->File());
1419 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1421 log->log("RRProc", Log::DEBUG, "Written timers list");
1426 int VompClientRRProc::processSetTimer()
1428 char* timerString = new char[strlen((char*)req->data) + 1];
1429 strcpy(timerString, (char*)req->data);
1431 #if VDRVERSNUM < 10300
1433 // If this is VDR 1.2 the date part of the timer string must be reduced
1434 // to just DD rather than YYYY-MM-DD
1436 int s = 0; // source
1437 int d = 0; // destination
1439 while(c != 2) // copy up to date section, including the second ':'
1441 timerString[d] = req->data[s];
1442 if (req->data[s] == ':') c++;
1446 // now it has copied up to the date section
1448 while(c != 2) // waste YYYY-MM-
1450 if (req->data[s] == '-') c++;
1453 // now source is at the DD
1454 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1455 d += req->dataLength - s;
1456 timerString[d] = '\0';
1458 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1461 log->log("RRProc", Log::DEBUG, "%s", timerString);
1463 cTimer *timer = new cTimer;
1464 if (timer->Parse((char*)timerString))
1466 cTimer *t = Timers.GetTimer(timer);
1470 #if VDRVERSNUM < 10300
1473 Timers.SetModified();
1477 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1478 return 1; // FIXME - cTimer* timer is leaked here!
1484 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1491 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1497 int VompClientRRProc::processDeleteTimer()
1499 log->log("RRProc", Log::DEBUG, "Delete timer called");
1504 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1505 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1506 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1507 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1508 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1511 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1513 if ( (ti->Channel()->Number() == delChannel)
1514 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1515 && (ti->StartTime() == delStart)
1516 && (ti->StopTime() == delStop) )
1524 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1528 if (!Timers.BeingEdited())
1530 if (!ti->Recording())
1533 Timers.SetModified();
1536 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1541 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1544 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1550 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1553 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1558 int VompClientRRProc::processGetRecInfo()
1560 // data is a pointer to the fileName string
1562 cRecordings Recordings;
1563 Recordings.Load(); // probably have to do this
1565 cRecording *recording = Recordings.GetByName((char*)req->data);
1567 time_t timerStart = 0;
1568 time_t timerStop = 0;
1569 char* summary = NULL;
1570 ULONG resumePoint = 0;
1574 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1577 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1582 4 bytes: start time for timer
1583 4 bytes: end time for timer
1584 4 bytes: resume point
1586 4 bytes: num components
1593 8 bytes: frames per second
1596 // Get current timer
1598 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1601 timerStart = rc->Timer()->StartTime();
1602 timerStop = rc->Timer()->StopTime();
1603 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1606 resp->addULONG(timerStart);
1607 resp->addULONG(timerStop);
1611 /* char* value = x.config.getValueString("ResumeData", (char*)req->data);
1614 resumePoint = strtoul(value, NULL, 10);
1618 char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1621 ResumeId = atoi(ResumeIdC);
1625 ResumeId = 0; //default if not defined in vomp-MAC.conf
1627 while (ResumeIDLock)
1628 cCondWait::SleepMs(100);
1629 ResumeIDLock = true;
1630 int OldSetupResumeID = Setup.ResumeID;
1631 Setup.ResumeID = ResumeId; //UGLY: quickly change resumeid
1632 #if VDRVERSNUM < 10703
1633 cResumeFile ResumeFile(recording->FileName()); //get corresponding resume file
1635 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1637 Setup.ResumeID = OldSetupResumeID; //and restore it back
1638 ResumeIDLock = false;
1640 int resume = ResumeFile.Read();
1641 //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1643 resumePoint = ResumeFile.Read();
1645 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1647 resp->addULONG(resumePoint);
1651 #if VDRVERSNUM < 10300
1652 summary = (char*)recording->Summary();
1654 const cRecordingInfo *Info = recording->Info();
1655 summary = (char*)Info->ShortText();
1656 if (isempty(summary)) summary = (char*)Info->Description();
1658 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1661 resp->addString(summary);
1665 resp->addString("");
1670 #if VDRVERSNUM < 10300
1672 // Send 0 for numchannels - this signals the client this info is not available
1676 const cComponents* components = Info->Components();
1678 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1686 resp->addULONG(components->NumComponents());
1688 tComponent* component;
1689 for (int i = 0; i < components->NumComponents(); i++)
1691 component = components->Component(i);
1693 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1695 resp->addUCHAR(component->stream);
1696 resp->addUCHAR(component->type);
1698 if (component->language)
1700 resp->addString(component->language);
1704 resp->addString("");
1706 if (component->description)
1708 resp->addString(component->description);
1712 resp->addString("");
1718 double framespersec;
1719 #if VDRVERSNUM < 10703
1720 framespersec = FRAMESPERSEC;
1722 framespersec = Info->FramesPerSecond();
1724 resp->adddouble(framespersec);
1729 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1731 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1741 int VompClientRRProc::processReScanRecording()
1745 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1749 x.recplayer->scan();
1751 resp->addULLONG(x.recplayer->getLengthBytes());
1752 resp->addULONG(x.recplayer->getLengthFrames());
1754 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1755 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1759 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1761 int VompClientRRProc::processGetMarks()
1763 // data is a pointer to the fileName string
1766 cRecordings Recordings;
1767 Recordings.Load(); // probably have to do this
1769 cRecording *recording = Recordings.GetByName((char*)req->data);
1771 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1775 #if VDRVERSNUM < 10703
1776 Marks.Load(recording->FileName());
1778 Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
1782 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1784 #if VDRVERSNUM < 10721
1785 ULLONG mposition = m->position;
1787 ULLONG mposition = m->Position();
1789 log->log("RRProc", Log::DEBUG, "found Mark %i", mposition);
1791 resp->addULONG(mposition);
1796 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
1802 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1804 log->log("RRProc", Log::DEBUG, "Written Marks list");
1809 #endif // !VOMPSTANDALONE