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()
63 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
67 Now we have a queue system is used,
68 since on rare occasion the client fire two request at once
69 e.g. heavily channel switching
70 then processing only a single request would cause a deadlock in the client
75 req_queue.push(newRequest);
77 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
83 void VompClientRRProc::threadMethod()
86 log->log("RRProc", Log::DEBUG, "threadMethod startup");
88 if (req_queue.size() != 0)
90 log->log("RRProc", Log::ERR, "threadMethod err 1");
97 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
98 threadWaitForSignal(); // unlocks, waits, relocks
99 if (req_queue.size() == 0)
101 log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");
106 // signalled with something in queue
108 log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
110 while (req_queue.size())
112 //log->log("RRProc", Log::DEBUG, "thread while");
113 req = req_queue.front();
116 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
118 if (!processPacket())
120 log->log("RRProc", Log::ERR, "processPacket exited with fail");
127 // locked and run out of packets to process
131 bool VompClientRRProc::processPacket()
133 resp = new ResponsePacket();
134 if (!resp->init(req->requestID))
136 log->log("RRProc", Log::ERR, "response packet init fail");
139 if (req->data) free(req->data);
151 result = processLogin();
153 #ifndef VOMPSTANDALONE
155 result = processGetRecordingsList();
158 result = processDeleteRecording();
161 result = processGetChannelsList();
164 result = processStartStreamingChannel();
167 result = processGetBlock();
170 result = processStopStreaming();
173 result = processStartStreamingRecording();
176 result = processGetChannelSchedule();
180 result = processConfigSave();
183 result = processConfigLoad();
185 #ifndef VOMPSTANDALONE
187 result = processReScanRecording(); // FIXME obselete
190 result = processGetTimers();
193 result = processSetTimer();
196 result = processPositionFromFrameNumber();
199 result = processFrameNumberFromPosition();
202 result = processMoveRecording();
205 result = processGetIFrame();
208 result = processGetRecInfo();
211 result = processGetMarks();
214 result = processGetChannelPids();
217 result = processDeleteTimer();
220 case VDR_GETMEDIALIST:
221 result = processGetMediaList();
224 result = processOpenMedia();
226 case VDR_GETMEDIABLOCK:
227 result = processGetMediaBlock();
230 result = processGetLanguageList();
233 result = processGetLanguageContent();
235 case VDR_GETMEDIAINFO:
236 result= processGetMediaInfo();
238 case VDR_CLOSECHANNEL:
239 result= processCloseMediaChannel();
247 if (req->data) free(req->data);
251 if (result) return true;
255 int VompClientRRProc::processLogin()
257 if (req->dataLength != 6) return 0;
261 char configFileName[PATH_MAX];
262 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]);
263 x.config.init(configFileName);
265 // Send the login reply
267 time_t timeNow = time(NULL);
268 struct tm* timeStruct = localtime(&timeNow);
269 int timeOffset = timeStruct->tm_gmtoff;
271 resp->addULONG(timeNow);
272 resp->addLONG(timeOffset);
274 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
275 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
278 x.netLog(); // safe to run here since the client won't start net logging for a while yet
283 int VompClientRRProc::processConfigSave()
285 char* section = (char*)req->data;
289 for (UINT k = 0; k < req->dataLength; k++)
291 if (req->data[k] == '\0')
295 key = (char*)&req->data[k+1];
299 value = (char*)&req->data[k+1];
305 // if the last string (value) doesnt have null terminator, give up
306 if (req->data[req->dataLength - 1] != '\0') return 0;
308 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
309 if (x.config.setValueString(section, key, value))
319 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
324 int VompClientRRProc::processConfigLoad()
326 char* section = (char*)req->data;
329 for (UINT k = 0; k < req->dataLength; k++)
331 if (req->data[k] == '\0')
333 key = (char*)&req->data[k+1];
338 char* value = x.config.getValueString(section, key);
342 resp->addString(value);
343 log->log("RRProc", Log::DEBUG, "Written config load packet");
349 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
353 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
359 //helper for sending from a serialize buffer
360 //insert the used len into the first 4 Bytes of the buffer
361 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
362 resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
364 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
368 * media List Request:
369 * Media List response:
372 #define MLISTBUF 500000
373 int VompClientRRProc::processGetMediaList()
375 SerializeBuffer buffer(req->data,req->dataLength);
376 MediaURI uri(0,NULL,NULL);
377 VDR_GetMediaListRequest request(&uri);
378 if (request.deserialize(&buffer) != 0) {
379 log->log("Client", Log::ERR, "getMediaList unable to deserialize");
382 const char *dirname=uri.getName();
383 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
386 if (dirname == NULL) {
387 ml=x.media->getRootList();
389 ml=x.media->getMediaList(&uri);
392 log->log("Client", Log::ERR, "getMediaList returned NULL");
395 SerializeBuffer rbuf(MLISTBUF,false,true);
396 ULONG flags=0; //TODO: real error handling by setting flags
397 VDR_GetMediaListResponse response(&flags,ml);
398 if (response.serialize(&rbuf) != 0) {
399 log->log("Client", Log::ERR, "getMediaList returned NULL");
403 log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size());
408 log->log("Client", Log::DEBUG, "Written Media list");
413 * openMedia response:
415 int VompClientRRProc::processOpenMedia()
417 SerializeBuffer buffer(req->data,req->dataLength);
418 MediaURI uri(0,NULL,NULL);
422 VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
423 if (request.deserialize(&buffer) != 0) {
424 log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
427 const char *name=uri.getName();
428 log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
430 int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
435 log->log("Client", Log::ERR, "openMediaRequest unable to open");
437 VDR_OpenMediumResponse response(&flags,&size);
438 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
439 if (response.serialize(&rbuf) != 0) {
440 log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
443 log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size);
450 * packet - no serialized response!
452 int VompClientRRProc::processGetMediaBlock()
454 SerializeBuffer buffer(req->data,req->dataLength);
458 VDR_GetMediaBlockRequest request(&channel,&position,&amount);
459 if (request.deserialize(&buffer) != 0) {
460 log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
463 log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
465 UCHAR sendBuffer[amount ];
466 ULONG amountReceived = 0;
467 UCHAR *rbuf=sendBuffer;
468 int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
469 if (!amountReceived || rt != 0)
471 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
475 if (rbuf != sendBuffer) {
476 //the provider did not use the optimized handling with using my buffer
477 resp->copyin(rbuf,amountReceived);
480 // the provider did not allocate a new buffer
481 resp->copyin(sendBuffer,amountReceived);
485 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
486 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
493 int VompClientRRProc::processGetMediaInfo()
495 SerializeBuffer buffer(req->data,req->dataLength);
497 VDR_GetMediaInfoRequest request(&channel);
498 if (request.deserialize(&buffer) != 0) {
499 log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
502 log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
505 int rt=x.media->getMediaInfo(channel,&mi);
508 log->log("Client", Log::ERR, "getMediaInfo unable to get");
510 VDR_GetMediaInfoResponse response(&flags,&mi);
511 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
512 if (response.serialize(&rbuf) != 0) {
513 log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
525 int VompClientRRProc::processCloseMediaChannel()
527 SerializeBuffer buffer(req->data,req->dataLength);
529 VDR_CloseMediaChannelRequest request(&channel);
530 if (request.deserialize(&buffer) != 0) {
531 log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
535 log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
536 int rt=x.media->closeMediaChannel(channel);
539 log->log("Client", Log::ERR, "closeMediaChannel unable to get");
541 VDR_CloseMediaChannelResponse response(&flags);
542 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
543 if (response.serialize(&rbuf) != 0) {
544 log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
553 int VompClientRRProc::processGetLanguageList()
555 x.i18n.findLanguages();
556 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
558 I18n::lang_code_list::const_iterator iter;
559 for (iter = languages.begin(); iter != languages.end(); ++iter)
561 resp->addString(iter->first.c_str());
562 resp->addString(iter->second.c_str());
565 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
569 int VompClientRRProc::processGetLanguageContent()
571 if (req->dataLength <= 0) return 0;
572 std::string code, result;
573 code.assign((char*)req->data, req->dataLength - 1);
574 x.i18n.findLanguages();
575 I18n::trans_table texts = x.i18n.getLanguageContent(code);
576 I18n::trans_table::const_iterator iter;
577 for (iter = texts.begin(); iter != texts.end(); ++iter)
579 resp->addString(iter->first.c_str());
580 resp->addString(iter->second.c_str());
583 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
587 #ifndef VOMPSTANDALONE
589 int VompClientRRProc::processGetRecordingsList()
592 int Percent = VideoDiskSpace(&FreeMB);
593 int Total = (FreeMB / (100 - Percent)) * 100;
595 resp->addULONG(Total);
596 resp->addULONG(FreeMB);
597 resp->addULONG(Percent);
599 cRecordings Recordings;
602 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
604 resp->addULONG(recording->start);
605 resp->addString(recording->Name());
606 resp->addString(recording->FileName());
610 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
612 log->log("RRProc", Log::DEBUG, "Written recordings list");
617 int VompClientRRProc::processDeleteRecording()
619 // data is a pointer to the fileName string
621 cRecordings Recordings;
622 Recordings.Load(); // probably have to do this
624 cRecording* recording = Recordings.GetByName((char*)req->data);
626 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
630 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
632 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
635 if (recording->Delete())
637 // Copy svdrdeveldevelp's way of doing this, see if it works
638 #if VDRVERSNUM > 10300
639 ::Recordings.DelByName(recording->FileName());
659 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
664 int VompClientRRProc::processMoveRecording()
666 log->log("RRProc", Log::DEBUG, "Process move recording");
667 char* fileName = (char*)req->data;
668 char* newPath = NULL;
670 for (UINT k = 0; k < req->dataLength; k++)
672 if (req->data[k] == '\0')
674 newPath = (char*)&req->data[k+1];
678 if (!newPath) return 0;
680 cRecordings Recordings;
681 Recordings.Load(); // probably have to do this
683 cRecording* recording = Recordings.GetByName((char*)fileName);
685 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
689 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
692 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
693 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
694 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
696 const char* t = recording->FileName();
698 char* dateDirName = NULL; int k;
699 char* titleDirName = NULL; int j;
701 // Find the datedirname
702 for(k = strlen(t) - 1; k >= 0; k--)
706 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
707 dateDirName = new char[strlen(&t[k+1]) + 1];
708 strcpy(dateDirName, &t[k+1]);
713 // Find the titledirname
715 for(j = k-1; j >= 0; j--)
719 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
720 titleDirName = new char[(k - j - 1) + 1];
721 memcpy(titleDirName, &t[j+1], k - j - 1);
722 titleDirName[k - j - 1] = '\0';
727 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
728 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
729 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
731 char* newPathConv = new char[strlen(newPath)+1];
732 strcpy(newPathConv, newPath);
733 ExchangeChars(newPathConv, true);
734 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
736 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
737 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
738 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
739 delete[] newPathConv;
741 log->log("RRProc", Log::DEBUG, "%s", newContainer);
744 int statret = stat(newContainer, &dstat);
745 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
747 log->log("RRProc", Log::DEBUG, "new dir does not exist");
748 int mkdirret = mkdir(newContainer, 0755);
751 delete[] dateDirName;
752 delete[] titleDirName;
753 delete[] newContainer;
757 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
761 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
763 delete[] dateDirName;
764 delete[] titleDirName;
765 delete[] newContainer;
769 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
773 // Ok, the directory container has been made, or it pre-existed.
775 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
776 sprintf(newDir, "%s/%s", newContainer, dateDirName);
778 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
779 int renameret = rename(t, newDir);
782 // Success. Test for remove old dir containter
783 char* oldTitleDir = new char[k+1];
784 memcpy(oldTitleDir, t, k);
785 oldTitleDir[k] = '\0';
786 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
787 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
788 delete[] oldTitleDir;
793 #if VDRVERSNUM > 10311
795 ::Recordings.Update();
797 // Success. Send a different packet from just a ulong
798 resp->addULONG(1); // success
799 resp->addString(newDir);
807 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
809 delete[] dateDirName;
810 delete[] titleDirName;
811 delete[] newContainer;
818 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
825 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
831 int VompClientRRProc::processGetChannelsList()
835 char* chanConfig = x.config.getValueString("General", "Channels");
837 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
839 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
841 #if VDRVERSNUM < 10300
842 if (!channel->GroupSep() && (!channel->Ca() || allChans))
844 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
847 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
849 if (channel->Vpid()) type = 1;
850 #if VDRVERSNUM < 10300
853 else if (channel->Apid(0)) type = 2;
857 resp->addULONG(channel->Number());
858 resp->addULONG(type);
859 resp->addString(channel->Name());
860 #if VDRVERSNUM < 10703
863 resp->addULONG(channel->Vtype());
869 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
871 log->log("RRProc", Log::DEBUG, "Written channels list");
876 int VompClientRRProc::processGetChannelPids()
878 ULONG channelNumber = ntohl(*(ULONG*)req->data);
880 cChannel* channel = x.channelFromNumber(channelNumber);
885 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
894 #if VDRVERSNUM < 10300
896 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
897 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
899 if (channel->Apid2())
901 else if (channel->Apid1())
908 for (const int *Apid = channel->Apids(); *Apid; Apid++)
912 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
916 for (const int *Spid = channel->Spids(); *Spid; Spid++)
923 // Format of response
942 resp->addULONG(channel->Vpid());
943 #if VDRVERSNUM < 10703
946 resp->addULONG(channel->Vtype());
948 resp->addULONG(numApids);
950 #if VDRVERSNUM < 10300
953 resp->addULONG(channel->Apid1());
958 resp->addULONG(channel->Apid2());
964 for (ULONG i = 0; i < numApids; i++)
966 resp->addULONG(channel->Apid(i));
967 resp->addString(channel->Alang(i));
969 resp->addULONG(numDpids);
970 for (ULONG i = 0; i < numDpids; i++)
972 resp->addULONG(channel->Dpid(i));
973 resp->addString(channel->Dlang(i));
975 resp->addULONG(numSpids);
976 for (ULONG i = 0; i < numSpids; i++)
978 resp->addULONG(channel->Spid(i));
979 resp->addString(channel->Slang(i));
982 resp->addULONG(channel->Tpid());
986 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
988 log->log("RRProc", Log::DEBUG, "Written channels pids");
993 int VompClientRRProc::processStartStreamingChannel()
997 log->log("RRProc", Log::ERR, "Client called start streaming twice");
1001 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
1002 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1004 cChannel* channel = x.channelFromNumber(channelNumber);
1009 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1013 // get the priority we should use
1015 int priority = x.config.getValueLong("General", "Live priority", &fail);
1018 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1022 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1026 // a bit of sanity..
1027 if (priority < 0) priority = 0;
1028 if (priority > 99) priority = 99;
1030 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1031 x.lp = MVPReceiver::create(channel, priority);
1037 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1041 if (!x.lp->init(&x.tcp, req->requestID))
1047 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1053 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1057 int VompClientRRProc::processStopStreaming()
1059 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1065 else if (x.recplayer)
1067 x.writeResumeData();
1070 delete x.recordingManager;
1072 x.recordingManager = NULL;
1077 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1081 int VompClientRRProc::processGetBlock()
1085 log->log("RRProc", Log::ERR, "Get block called during live streaming");
1091 log->log("RRProc", Log::ERR, "Get block called when no recording open");
1095 UCHAR* data = req->data;
1097 ULLONG position = x.ntohll(*(ULLONG*)data);
1098 data += sizeof(ULLONG);
1099 ULONG amount = ntohl(*(ULONG*)data);
1101 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1103 UCHAR sendBuffer[amount];
1104 ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1106 if (!amountReceived)
1109 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1113 resp->copyin(sendBuffer, amountReceived);
1114 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1118 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1119 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1123 int VompClientRRProc::processStartStreamingRecording()
1125 // data is a pointer to the fileName string
1127 x.recordingManager = new cRecordings;
1128 x.recordingManager->Load();
1130 cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1132 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1136 x.recplayer = new RecPlayer(recording);
1138 resp->addULLONG(x.recplayer->getLengthBytes());
1139 resp->addULONG(x.recplayer->getLengthFrames());
1141 #if VDRVERSNUM < 10703
1142 resp->addUCHAR(true);//added for TS
1144 resp->addUCHAR(recording->IsPesRecording());//added for TS
1148 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1150 log->log("RRProc", Log::DEBUG, "written totalLength");
1154 delete x.recordingManager;
1155 x.recordingManager = NULL;
1160 int VompClientRRProc::processPositionFromFrameNumber()
1164 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1168 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1172 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1175 resp->addULLONG(retval);
1177 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1179 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1183 int VompClientRRProc::processFrameNumberFromPosition()
1187 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1191 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1195 retval = x.recplayer->frameNumberFromPosition(position);
1198 resp->addULONG(retval);
1200 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1202 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1206 int VompClientRRProc::processGetIFrame()
1208 bool success = false;
1210 ULONG* data = (ULONG*)req->data;
1212 ULONG frameNumber = ntohl(*data);
1214 ULONG direction = ntohl(*data);
1216 ULLONG rfilePosition = 0;
1217 ULONG rframeNumber = 0;
1218 ULONG rframeLength = 0;
1222 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1226 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1229 // returns file position, frame number, length
1233 resp->addULLONG(rfilePosition);
1234 resp->addULONG(rframeNumber);
1235 resp->addULONG(rframeLength);
1243 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1245 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1249 int VompClientRRProc::processGetChannelSchedule()
1251 ULONG* data = (ULONG*)req->data;
1253 ULONG channelNumber = ntohl(*data);
1255 ULONG startTime = ntohl(*data);
1257 ULONG duration = ntohl(*data);
1259 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1261 cChannel* channel = x.channelFromNumber(channelNumber);
1266 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1268 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1272 log->log("RRProc", Log::DEBUG, "Got channel");
1274 #if VDRVERSNUM < 10300
1275 cMutexLock MutexLock;
1276 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1278 cSchedulesLock MutexLock;
1279 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1285 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1287 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1291 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1293 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1298 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1300 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1304 log->log("RRProc", Log::DEBUG, "Got schedule object");
1306 const char* empty = "";
1307 bool atLeastOneEvent = false;
1310 ULONG thisEventTime;
1311 ULONG thisEventDuration;
1312 const char* thisEventTitle;
1313 const char* thisEventSubTitle;
1314 const char* thisEventDescription;
1316 #if VDRVERSNUM < 10300
1318 const cEventInfo *event;
1319 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1321 event = Schedule->GetEventNumber(eventNumber);
1323 thisEventID = event->GetEventID();
1324 thisEventTime = event->GetTime();
1325 thisEventDuration = event->GetDuration();
1326 thisEventTitle = event->GetTitle();
1327 thisEventSubTitle = event->GetSubtitle();
1328 thisEventDescription = event->GetExtendedDescription();
1332 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1334 thisEventID = event->EventID();
1335 thisEventTime = event->StartTime();
1336 thisEventDuration = event->Duration();
1337 thisEventTitle = event->Title();
1338 thisEventSubTitle = NULL;
1339 thisEventDescription = event->Description();
1343 //in the past filter
1344 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1347 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1350 if (thisEventTime >= (startTime + duration)) continue;
1352 if (!thisEventTitle) thisEventTitle = empty;
1353 if (!thisEventSubTitle) thisEventSubTitle = empty;
1354 if (!thisEventDescription) thisEventDescription = empty;
1356 resp->addULONG(thisEventID);
1357 resp->addULONG(thisEventTime);
1358 resp->addULONG(thisEventDuration);
1360 resp->addString(thisEventTitle);
1361 resp->addString(thisEventSubTitle);
1362 resp->addString(thisEventDescription);
1364 atLeastOneEvent = true;
1367 log->log("RRProc", Log::DEBUG, "Got all event data");
1369 if (!atLeastOneEvent)
1372 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1376 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1378 log->log("RRProc", Log::DEBUG, "written schedules packet");
1383 int VompClientRRProc::processGetTimers()
1386 int numTimers = Timers.Count();
1388 resp->addULONG(numTimers);
1390 for (int i = 0; i < numTimers; i++)
1392 timer = Timers.Get(i);
1394 #if VDRVERSNUM < 10300
1395 resp->addULONG(timer->Active());
1397 resp->addULONG(timer->HasFlags(tfActive));
1399 resp->addULONG(timer->Recording());
1400 resp->addULONG(timer->Pending());
1401 resp->addULONG(timer->Priority());
1402 resp->addULONG(timer->Lifetime());
1403 resp->addULONG(timer->Channel()->Number());
1404 resp->addULONG(timer->StartTime());
1405 resp->addULONG(timer->StopTime());
1406 resp->addULONG(timer->Day());
1407 resp->addULONG(timer->WeekDays());
1408 resp->addString(timer->File());
1412 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1414 log->log("RRProc", Log::DEBUG, "Written timers list");
1419 int VompClientRRProc::processSetTimer()
1421 char* timerString = new char[strlen((char*)req->data) + 1];
1422 strcpy(timerString, (char*)req->data);
1424 #if VDRVERSNUM < 10300
1426 // If this is VDR 1.2 the date part of the timer string must be reduced
1427 // to just DD rather than YYYY-MM-DD
1429 int s = 0; // source
1430 int d = 0; // destination
1432 while(c != 2) // copy up to date section, including the second ':'
1434 timerString[d] = req->data[s];
1435 if (req->data[s] == ':') c++;
1439 // now it has copied up to the date section
1441 while(c != 2) // waste YYYY-MM-
1443 if (req->data[s] == '-') c++;
1446 // now source is at the DD
1447 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1448 d += req->dataLength - s;
1449 timerString[d] = '\0';
1451 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1452 log->log("RRProc", Log::DEBUG, "%s", timerString);
1456 cTimer *timer = new cTimer;
1457 if (timer->Parse((char*)timerString))
1459 cTimer *t = Timers.GetTimer(timer);
1463 #if VDRVERSNUM < 10300
1466 Timers.SetModified();
1470 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1477 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1484 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1490 int VompClientRRProc::processDeleteTimer()
1492 log->log("RRProc", Log::DEBUG, "Delete timer called");
1497 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1498 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1499 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1500 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1501 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1504 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1506 if ( (ti->Channel()->Number() == delChannel)
1507 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1508 && (ti->StartTime() == delStart)
1509 && (ti->StopTime() == delStop) )
1517 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1521 if (!Timers.BeingEdited())
1523 if (!ti->Recording())
1526 Timers.SetModified();
1529 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1534 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1537 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1543 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1546 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1551 int VompClientRRProc::processGetRecInfo()
1553 // data is a pointer to the fileName string
1555 cRecordings Recordings;
1556 Recordings.Load(); // probably have to do this
1558 cRecording *recording = Recordings.GetByName((char*)req->data);
1560 time_t timerStart = 0;
1561 time_t timerStop = 0;
1562 char* summary = NULL;
1563 ULONG resumePoint = 0;
1567 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1570 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1575 4 bytes: start time for timer
1576 4 bytes: end time for timer
1577 4 bytes: resume point
1579 4 bytes: num components
1586 8 bytes: frames per second
1589 // Get current timer
1591 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1594 timerStart = rc->Timer()->StartTime();
1595 timerStop = rc->Timer()->StopTime();
1596 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1599 resp->addULONG(timerStart);
1600 resp->addULONG(timerStop);
1604 /* char* value = x.config.getValueString("ResumeData", (char*)req->data);
1607 resumePoint = strtoul(value, NULL, 10);
1611 char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1614 ResumeId = atoi(ResumeIdC);
1618 ResumeId = 0; //default if not defined in vomp-MAC.conf
1620 while (ResumeIDLock)
1621 cCondWait::SleepMs(100);
1622 ResumeIDLock = true;
1623 int OldSetupResumeID = Setup.ResumeID;
1624 Setup.ResumeID = ResumeId; //UGLY: quickly change resumeid
1625 #if VDRVERSNUM < 10703
1626 cResumeFile ResumeFile(recording->FileName()); //get corresponding resume file
1628 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1630 Setup.ResumeID = OldSetupResumeID; //and restore it back
1631 ResumeIDLock = false;
1633 int resume = ResumeFile.Read();
1634 //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1636 resumePoint = ResumeFile.Read();
1638 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1640 resp->addULONG(resumePoint);
1644 #if VDRVERSNUM < 10300
1645 summary = (char*)recording->Summary();
1647 const cRecordingInfo *Info = recording->Info();
1648 summary = (char*)Info->ShortText();
1649 if (isempty(summary)) summary = (char*)Info->Description();
1651 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1654 resp->addString(summary);
1658 resp->addString("");
1663 #if VDRVERSNUM < 10300
1665 // Send 0 for numchannels - this signals the client this info is not available
1669 const cComponents* components = Info->Components();
1671 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1679 resp->addULONG(components->NumComponents());
1681 tComponent* component;
1682 for (int i = 0; i < components->NumComponents(); i++)
1684 component = components->Component(i);
1686 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1688 resp->addUCHAR(component->stream);
1689 resp->addUCHAR(component->type);
1691 if (component->language)
1693 resp->addString(component->language);
1697 resp->addString("");
1699 if (component->description)
1701 resp->addString(component->description);
1705 resp->addString("");
1711 double framespersec;
1712 #if VDRVERSNUM < 10703
1713 framespersec = FRAMESPERSEC;
1715 framespersec = Info->FramesPerSecond();
1717 resp->adddouble(framespersec);
1722 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1724 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1734 int VompClientRRProc::processReScanRecording()
1738 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1742 x.recplayer->scan();
1744 resp->addULLONG(x.recplayer->getLengthBytes());
1745 resp->addULONG(x.recplayer->getLengthFrames());
1747 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1748 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1752 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1754 int VompClientRRProc::processGetMarks()
1756 // data is a pointer to the fileName string
1759 cRecordings Recordings;
1760 Recordings.Load(); // probably have to do this
1762 cRecording *recording = Recordings.GetByName((char*)req->data);
1764 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1768 #if VDRVERSNUM < 10703
1769 Marks.Load(recording->FileName());
1771 Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
1775 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1777 log->log("RRProc", Log::DEBUG, "found Mark %i", m->position);
1779 resp->addULONG(m->position);
1784 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
1790 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1792 log->log("RRProc", Log::DEBUG, "Written Marks list");
1797 #endif // !VOMPSTANDALONE