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 <vdr/remote.h>
31 #include "recplayer.h"
32 #include "mvpreceiver.h"
33 #include "services/scraper2vdr.h"
36 #include "vompclientrrproc.h"
37 #include "vompclient.h"
40 #include "mediaplayer.h"
41 #include "servermediafile.h"
43 #include "vdrcommand.h"
44 #include "picturereader.h"
48 ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MIN = 0x00000301;
49 ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MAX = 0x00000400;
51 // cc is release protocol version, increase with every release, that changes protocol
52 // dd is development protocol version, set to zero at every release,
53 // increase for every protocol change in git
54 // bb not equal zero should indicate a non loggytronic protocol
55 // aa is reserved for future use
56 // VOMP_PROTOCOL_VERSION_MIN is the protocol version minimal supported by the server
57 // VOMP_PROTOCOL_VERSION_MAX is the protocol version maximal supported by the server
58 // This allows to run older clients from a new server
59 // Increase the minimal protocol version everytime you break compatibility for a certain
63 /* Locking information from VDR:
65 + Instead of directly accessing the global variables Timers, Channels or Recordings,
66 they need to set up a cStateKey variable and call the proper getter function,
69 if (const cTimers *Timers = cTimers::GetTimersRead(StateKey)) {
75 if (cTimers *Timers = cTimers::GetTimersWrite(StateKey)) {
79 See timers.h, thread.h and tools.h for details on this new locking mechanism.
80 + There are convenience macros for easily accessing these lists without having
81 to explicitly set up a cStateKey and calling its Remove() function. These macros
82 have the form LOCK_*_READ/WRITE (with '*' being TIMERS, CHANNELS, SCHEDULES or
83 RECORDINGS). Simply put such a macro before the point where you need to access
84 the respective list, and there will be a pointer named Timers, Channels, Schedules
85 or Recordings, respectively, which is valid until the end of the current block.
86 + If a plugin needs to access several of the global lists in parallel, locking must
87 always be done in the sequence Timers, Channels, Recordings, Schedules. This is
88 necessary to make sure that different threads that need to lock several lists at
89 the same time don't end up in a deadlock.
93 // TODO: Use VDRs recording->ChangeName(option)) for move recording ?
95 ULONG VompClientRRProc::getProtocolVersionMin()
97 return VOMP_PROTOCOL_VERSION_MIN;
100 ULONG VompClientRRProc::getProtocolVersionMax()
102 return VOMP_PROTOCOL_VERSION_MAX;
105 VompClientRRProc::VompClientRRProc(VompClient& x)
108 log = Log::getInstance();
113 VompClientRRProc::~VompClientRRProc()
118 bool VompClientRRProc::init()
120 int a = threadStart();
125 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
129 Now we have a queue system is used,
130 since on rare occasion the client fire two request at once
131 e.g. heavily channel switching
132 then processing only a single request would cause a deadlock in the client
136 log->log("RRProc", Log::DEBUG, "recvReq");
138 req_queue.push(newRequest);
139 threadSignalNoLock();
140 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
146 void VompClientRRProc::threadMethod()
149 log->log("RRProc", Log::DEBUG, "threadMethod startup");
151 if (req_queue.size() != 0)
154 - log->log("RRProc", Log::ERR, "threadMethod err 1");
158 That was how the code used to be.
160 TODO: Work out why this happens.
163 log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets");
164 while (req_queue.size())
166 //log->log("RRProc", Log::DEBUG, "thread while");
167 req = req_queue.front();
170 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
172 if (!processPacket())
174 log->log("RRProc", Log::ERR, "processPacket exited with fail");
180 log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets done.");
186 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
187 threadWaitForSignal(); // unlocks, waits, relocks
188 if (req_queue.size() == 0)
190 log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");
195 // signalled with something in queue
197 log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
199 while (req_queue.size())
201 //log->log("RRProc", Log::DEBUG, "thread while");
202 req = req_queue.front();
205 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
207 if (!processPacket())
209 log->log("RRProc", Log::ERR, "processPacket exited with fail");
216 // locked and run out of packets to process
220 bool VompClientRRProc::processPacket()
222 resp = new ResponsePacket();
223 if (!resp->init(req->requestID))
225 log->log("RRProc", Log::ERR, "response packet init fail");
228 if (req->data) free(req->data);
240 result = processLogin();
242 #ifndef VOMPSTANDALONE
244 result = processGetRecordingsList();
247 result = processDeleteRecording();
250 result = processGetChannelsList();
253 result = processStartStreamingChannel();
256 result = processGetBlock();
259 result = processStopStreaming();
262 result = processStartStreamingRecording();
265 result = processGetChannelSchedule();
269 result = processConfigSave();
272 result = processConfigLoad();
274 #ifndef VOMPSTANDALONE
276 result = processReScanRecording(); // FIXME obselete
279 result = processGetTimers();
282 result = processSetTimer();
285 result = processPositionFromFrameNumber();
288 result = processFrameNumberFromPosition();
291 result = processMoveRecording();
294 result = processGetIFrame();
297 result = processGetRecInfo();
300 result = processGetMarks();
303 result = processGetChannelPids();
306 result = processDeleteTimer();
309 result = processVDRShutdown();
311 case VDR_GETRECSCRAPEREVENTTYPE:
312 result = processGetRecScraperEventType();
314 case VDR_GETSCRAPERMOVIEINFO:
315 result = processGetScraperMovieInfo();
317 case VDR_GETSCRAPERSERIESINFO:
318 result = processGetScraperSeriesInfo();
320 case VDR_LOADTVMEDIA:
321 result = processLoadTvMedia();
323 case VDR_LOADTVMEDIARECTHUMB:
324 result = processLoadTvMediaRecThumb();
326 case VDR_GETEVENTSCRAPEREVENTTYPE:
327 result = processGetEventScraperEventType();
329 case VDR_LOADTVMEDIAEVENTTHUMB:
330 result = processLoadTvMediaEventThumb();
332 case VDR_LOADCHANNELLOGO:
333 result = processLoadChannelLogo();
336 case VDR_GETMEDIALIST:
337 result = processGetMediaList();
340 result = processOpenMedia();
342 case VDR_GETMEDIABLOCK:
343 result = processGetMediaBlock();
346 result = processGetLanguageList();
349 result = processGetLanguageContent();
351 case VDR_GETMEDIAINFO:
352 result = processGetMediaInfo();
354 case VDR_CLOSECHANNEL:
355 result = processCloseMediaChannel();
358 result = processSetCharset();
365 if (req->data) free(req->data);
369 if (result) return true;
374 int VompClientRRProc::processLogin()
376 if (req->dataLength != 6) return 0;
380 char configFileName[PATH_MAX];
381 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]);
382 x.config.init(configFileName);
384 // Send the login reply
386 time_t timeNow = time(NULL);
387 struct tm* timeStruct = localtime(&timeNow);
388 int timeOffset = timeStruct->tm_gmtoff;
390 resp->addULONG(timeNow);
391 resp->addLONG(timeOffset);
392 resp->addULONG(VOMP_PROTOCOL_VERSION_MIN);
393 resp->addULONG(VOMP_PROTOCOL_VERSION_MAX);
395 // also send information about languages
396 resp->addULONG(I18nLanguages()->Size());
397 resp->addLONG(Setup.DisplaySubtitles);
398 for (int i=0;i < I18nLanguages()->Size(); i++) {
399 resp->addLONG(Setup.AudioLanguages[i]);
400 resp->addLONG(Setup.SubtitleLanguages[i]);
401 resp->addString(I18nLanguageCode(i));
405 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
406 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
409 x.netLog(); // safe to run here since the client won't start net logging for a while yet
414 int VompClientRRProc::processSetCharset()
416 int charset = ntohl(*(ULONG*)req->data);
417 if (charset>0 && charset<3)
419 log->log("RRProc", Log::DEBUG, "Set charset to %d", charset);
420 x.setCharset(charset);
425 log->log("RRProc", Log::DEBUG, "Invalid charset %d", charset);
429 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
433 int VompClientRRProc::processConfigSave()
435 char* section = (char*)req->data;
439 for (UINT k = 0; k < req->dataLength; k++)
441 if (req->data[k] == '\0')
445 key = (char*)&req->data[k+1];
449 value = (char*)&req->data[k+1];
455 // if the last string (value) doesnt have null terminator, give up
456 if (req->data[req->dataLength - 1] != '\0') return 0;
458 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
459 if (x.config.setValueString(section, key, value))
469 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
474 int VompClientRRProc::processConfigLoad()
476 char* section = (char*)req->data;
479 for (UINT k = 0; k < req->dataLength; k++)
481 if (req->data[k] == '\0')
483 key = (char*)&req->data[k+1];
488 char* value = x.config.getValueString(section, key);
492 resp->addString(value);//client coding, do not touch
493 log->log("RRProc", Log::DEBUG, "Written config load packet");
499 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
503 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
509 //helper for sending from a serialize buffer
510 //insert the used len into the first 4 Bytes of the buffer
511 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
512 resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
514 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
518 * media List Request:
519 * Media List response:
522 #define MLISTBUF 500000
523 int VompClientRRProc::processGetMediaList()
525 SerializeBuffer buffer(req->data,req->dataLength);
526 MediaURI uri(0,NULL,NULL);
527 VDR_GetMediaListRequest request(&uri);
528 if (request.deserialize(&buffer) != 0) {
529 log->log("Client", Log::ERR, "getMediaList unable to deserialize");
532 const char *dirname=uri.getName();
533 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
536 if (dirname == NULL) {
537 ml=x.media->getRootList();
539 ml=x.media->getMediaList(&uri);
542 log->log("Client", Log::ERR, "getMediaList returned NULL");
545 SerializeBuffer rbuf(MLISTBUF,false,true);
546 ULONG flags=0; //TODO: real error handling by setting flags
547 VDR_GetMediaListResponse response(&flags,ml);
548 if (response.serialize(&rbuf) != 0) {
549 log->log("Client", Log::ERR, "getMediaList returned NULL");
553 log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size());
558 log->log("Client", Log::DEBUG, "Written Media list");
563 * openMedia response:
565 int VompClientRRProc::processOpenMedia()
567 SerializeBuffer buffer(req->data,req->dataLength);
568 MediaURI uri(0,NULL,NULL);
572 VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
573 if (request.deserialize(&buffer) != 0) {
574 log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
577 const char *name=uri.getName();
578 log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
580 int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
585 log->log("Client", Log::ERR, "openMediaRequest unable to open");
587 VDR_OpenMediumResponse response(&flags,&size);
588 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
589 if (response.serialize(&rbuf) != 0) {
590 log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
593 log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size);
600 * packet - no serialized response!
602 int VompClientRRProc::processGetMediaBlock()
604 SerializeBuffer buffer(req->data,req->dataLength);
608 VDR_GetMediaBlockRequest request(&channel,&position,&amount);
609 if (request.deserialize(&buffer) != 0) {
610 log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
613 log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
615 UCHAR sendBuffer[amount ];
616 ULONG amountReceived = 0;
617 UCHAR *rbuf=sendBuffer;
618 int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
619 if (!amountReceived || rt != 0)
621 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
625 if (rbuf != sendBuffer) {
626 //the provider did not use the optimized handling with using my buffer
627 resp->copyin(rbuf,amountReceived);
630 // the provider did not allocate a new buffer
631 resp->copyin(sendBuffer,amountReceived);
635 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
636 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
643 int VompClientRRProc::processGetMediaInfo()
645 SerializeBuffer buffer(req->data,req->dataLength);
647 VDR_GetMediaInfoRequest request(&channel);
648 if (request.deserialize(&buffer) != 0) {
649 log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
652 log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
655 int rt=x.media->getMediaInfo(channel,&mi);
658 log->log("Client", Log::ERR, "getMediaInfo unable to get");
660 VDR_GetMediaInfoResponse response(&flags,&mi);
661 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
662 if (response.serialize(&rbuf) != 0) {
663 log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
675 int VompClientRRProc::processCloseMediaChannel()
677 SerializeBuffer buffer(req->data,req->dataLength);
679 VDR_CloseMediaChannelRequest request(&channel);
680 if (request.deserialize(&buffer) != 0) {
681 log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
685 log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
686 int rt=x.media->closeMediaChannel(channel);
689 log->log("Client", Log::ERR, "closeMediaChannel unable to get");
691 VDR_CloseMediaChannelResponse response(&flags);
692 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
693 if (response.serialize(&rbuf) != 0) {
694 log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
703 int VompClientRRProc::processGetLanguageList()
705 x.i18n.findLanguages();
706 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
708 I18n::lang_code_list::const_iterator iter;
709 for (iter = languages.begin(); iter != languages.end(); ++iter)
711 resp->addString(iter->first.c_str()); // Source code is acsii
712 resp->addString(x.charconvutf8->Convert(iter->second.c_str())); //translate string can be any utf-8 character
715 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
719 int VompClientRRProc::processGetLanguageContent()
721 if (req->dataLength <= 0) return 0;
722 std::string code, result;
723 code.assign((char*)req->data, req->dataLength - 1);
724 x.i18n.findLanguages();
725 I18n::trans_table texts = x.i18n.getLanguageContent(code);
726 I18n::trans_table::const_iterator iter;
727 for (iter = texts.begin(); iter != texts.end(); ++iter)
729 resp->addString(iter->first.c_str());// source code is acsii since it is english
730 resp->addString(x.charconvutf8->Convert(iter->second.c_str())); // translate text can be any unicode string, it is stored as UTF-8
733 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
737 #ifndef VOMPSTANDALONE
739 int VompClientRRProc::processGetRecordingsList()
742 #if APIVERSNUM > 20101
743 int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB);
745 int Percent = VideoDiskSpace(&FreeMB);
747 int Total = (FreeMB / (100 - Percent)) * 100;
749 resp->addULONG(Total);
750 resp->addULONG(FreeMB);
751 resp->addULONG(Percent);
753 #if VDRVERSNUM >= 20301
754 LOCK_RECORDINGS_READ;
755 const cRecordings* tRecordings = Recordings;
757 cThreadLock RecordingsLock(&Recordings);
758 const cRecordings* tRecordings = &Recordings;
761 for (const cRecording *recording = tRecordings->First(); recording; recording = tRecordings->Next(recording))
763 #if VDRVERSNUM < 10721
764 resp->addULONG(recording->start);
766 resp->addULONG(recording->Start());
768 resp->addUCHAR(recording->IsNew() ? 1 : 0);
769 resp->addString(x.charconvsys->Convert(recording->Name())); //coding of recording name is system dependent
770 resp->addString(recording->FileName());//file name are not visible by user do not touch
774 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
776 log->log("RRProc", Log::DEBUG, "Written recordings list");
781 int VompClientRRProc::processDeleteRecording()
783 // data is a pointer to the fileName string
785 #if VDRVERSNUM >= 20301
786 LOCK_RECORDINGS_WRITE;
787 cRecordings* tRecordings = Recordings;
789 cThreadLock RecordingsLock(&Recordings);
790 cRecordings* tRecordings = &Recordings;
793 cRecording* recording = tRecordings->GetByName((char*)req->data);
795 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
799 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
801 // TODO: Switch to using: cRecording::IsInUse(void) const
802 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
805 if (recording->Delete())
807 #if VDRVERSNUM >= 20301
808 tRecordings->DelByName(recording->FileName());
809 tRecordings->SetModified();
810 #elif VDRVERSNUM > 10300
811 // Copy svdrp's way of doing this, see if it works
812 ::Recordings.DelByName(recording->FileName());
832 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
837 int VompClientRRProc::processMoveRecording()
839 log->log("RRProc", Log::DEBUG, "Process move recording");
840 char* fileName = (char*)req->data;
841 char* newPath = NULL;
843 for (UINT k = 0; k < req->dataLength; k++)
845 if (req->data[k] == '\0')
847 newPath = (char*)&req->data[k+1];
851 if (!newPath) return 0;
854 #if VDRVERSNUM >= 20301
855 LOCK_RECORDINGS_WRITE;
856 cRecordings* tRecordings = Recordings;
858 cThreadLock RecordingsLock(&Recordings);
859 cRecordings* tRecordings = &Recordings;
862 cRecording* recording = tRecordings->GetByName((char*)fileName);
864 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
868 // TODO: Switch to using: int cRecording::IsInUse(void) const
869 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
872 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
873 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
874 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
876 const char* t = recording->FileName();
878 char* dateDirName = NULL; int k;
879 char* titleDirName = NULL; int j;
881 // Find the datedirname
882 for(k = strlen(t) - 1; k >= 0; k--)
886 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
887 dateDirName = new char[strlen(&t[k+1]) + 1];
888 strcpy(dateDirName, &t[k+1]);
893 // Find the titledirname
895 for(j = k-1; j >= 0; j--)
899 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
900 titleDirName = new char[(k - j - 1) + 1];
901 memcpy(titleDirName, &t[j+1], k - j - 1);
902 titleDirName[k - j - 1] = '\0';
907 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
908 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
909 #if APIVERSNUM > 20101
910 log->log("RRProc", Log::DEBUG, "viddir: %s", cVideoDirectory::Name());
912 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
915 char* newPathConv = (char*)malloc(strlen(newPath)+1);
916 strcpy(newPathConv, newPath);
917 newPathConv = ExchangeChars(newPathConv, true);
918 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
920 #if APIVERSNUM > 20101
921 char* newContainer = new char[strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1];
922 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1);
923 sprintf(newContainer, "%s%s%s", cVideoDirectory::Name(), newPathConv, titleDirName);
925 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
926 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
927 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
931 log->log("RRProc", Log::DEBUG, "%s", newContainer);
934 int statret = stat(newContainer, &dstat);
935 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
937 log->log("RRProc", Log::DEBUG, "new dir does not exist");
938 int mkdirret = mkdir(newContainer, 0755);
941 delete[] dateDirName;
942 delete[] titleDirName;
943 delete[] newContainer;
947 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
951 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
953 delete[] dateDirName;
954 delete[] titleDirName;
955 delete[] newContainer;
959 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
964 // Ok, the directory container has been made, or it pre-existed.
966 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
967 sprintf(newDir, "%s/%s", newContainer, dateDirName);
969 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
970 int renameret = rename(t, newDir);
973 // Success. Test for remove old dir containter
974 char* oldTitleDir = new char[k+1];
975 memcpy(oldTitleDir, t, k);
976 oldTitleDir[k] = '\0';
977 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
978 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
979 delete[] oldTitleDir;
981 #if VDRVERSNUM >= 20301
982 tRecordings->SetModified();
983 #elif VDRVERSNUM > 10311
984 ::Recordings.Update();
986 // Success. Send a different packet from just a ulong
987 resp->addULONG(1); // success
988 resp->addString(newDir); //system depent do not convert
996 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
998 delete[] dateDirName;
999 delete[] titleDirName;
1000 delete[] newContainer;
1007 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1014 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1020 int VompClientRRProc::processGetChannelsList()
1024 char* chanConfig = x.config.getValueString("General", "Channels");
1026 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
1028 #if VDRVERSNUM >= 20301
1030 const cChannels* tChannels = Channels;
1032 const cChannels* tChannels = &Channels;
1035 for (const cChannel *channel = tChannels->First(); channel; channel = tChannels->Next(channel))
1037 #if VDRVERSNUM < 10300
1038 if (!channel->GroupSep() && (!channel->Ca() || allChans))
1040 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
1043 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
1045 if (channel->Vpid()) type = 1;
1046 #if VDRVERSNUM < 10300
1049 else if (channel->Apid(0)) type = 2;
1053 resp->addULONG(channel->Number());
1054 resp->addULONG(type);
1055 resp->addString(x.charconvsys->Convert(channel->Name()));
1056 #if VDRVERSNUM < 10703
1059 resp->addULONG(channel->Vtype());
1065 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1067 log->log("RRProc", Log::DEBUG, "Written channels list");
1072 int VompClientRRProc::processGetChannelPids()
1074 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1076 #if VDRVERSNUM >= 20301
1078 const cChannels* tChannels = Channels;
1080 cChannels* tChannels = &Channels;
1083 const cChannel* channel = tChannels->GetByNumber(channelNumber);
1088 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1097 #if VDRVERSNUM < 10300
1099 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
1100 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
1102 if (channel->Apid2())
1104 else if (channel->Apid1())
1111 for (const int *Apid = channel->Apids(); *Apid; Apid++)
1115 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
1119 for (const int *Spid = channel->Spids(); *Spid; Spid++)
1126 // Format of response
1145 resp->addULONG(channel->Vpid());
1146 #if VDRVERSNUM < 10703
1149 resp->addULONG(channel->Vtype());
1151 resp->addULONG(numApids);
1153 #if VDRVERSNUM < 10300
1156 resp->addULONG(channel->Apid1());
1157 resp->addString("");
1161 resp->addULONG(channel->Apid2());
1162 resp->addString("");
1167 for (ULONG i = 0; i < numApids; i++)
1169 resp->addULONG(channel->Apid(i));
1170 resp->addString(x.charconvsys->Convert(channel->Alang(i)));
1172 resp->addULONG(numDpids);
1173 for (ULONG i = 0; i < numDpids; i++)
1175 resp->addULONG(channel->Dpid(i));
1176 resp->addString(x.charconvsys->Convert(channel->Dlang(i)));
1178 resp->addULONG(numSpids);
1179 for (ULONG i = 0; i < numSpids; i++)
1181 resp->addULONG(channel->Spid(i));
1182 resp->addString(x.charconvsys->Convert(channel->Slang(i)));
1185 resp->addULONG(channel->Tpid());
1186 // Format of extended response, for compatibility with older client at the end
1198 #if VDRVERSNUM < 10300
1208 for (ULONG i = 0; i < numApids; i++)
1210 #if VDRVERSNUM < 10715
1213 resp->addULONG(channel->Atype(i));
1216 for (ULONG i = 0; i < numDpids; i++)
1218 #if VDRVERSNUM < 10715
1219 resp->addULONG(0x6A /*AC3*/);
1221 resp->addULONG(channel->Dtype(i));
1224 for (ULONG i = 0; i < numSpids; i++)
1226 #if VDRVERSNUM < 10715
1231 resp->addULONG(channel->SubtitlingType(i));
1232 resp->addULONG(channel->CompositionPageId(i));
1233 resp->addULONG(channel->AncillaryPageId(i));
1240 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1242 log->log("RRProc", Log::DEBUG, "Written channels pids");
1247 int VompClientRRProc::processStartStreamingChannel()
1251 log->log("RRProc", Log::ERR, "Client called start streaming twice");
1255 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
1256 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1258 #if VDRVERSNUM >= 20301
1260 const cChannels* tChannels = Channels;
1262 cChannels* tChannels = &Channels;
1265 const cChannel* channel = tChannels->GetByNumber(channelNumber);
1270 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1274 // get the priority we should use
1276 int priority = x.config.getValueLong("General", "Live priority", &fail);
1279 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1283 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1287 // a bit of sanity..
1288 #if VDRVERSNUM < 10725
1289 if (priority < 0) priority = 0;
1291 if (priority < -99) priority = -99;
1293 if (priority > 99) priority = 99;
1295 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1296 x.lp = MVPReceiver::create(channel, priority);
1302 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1306 if (!x.lp->init(&x.tcp, req->requestID))
1312 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1318 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1322 int VompClientRRProc::processStopStreaming()
1324 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1327 x.lp->detachMVPReceiver();
1331 else if (x.recplayer)
1333 x.writeResumeData();
1341 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1345 int VompClientRRProc::processGetBlock()
1349 log->log("RRProc", Log::ERR, "Get block called during live streaming");
1355 log->log("RRProc", Log::ERR, "Get block called when no recording open");
1359 UCHAR* data = req->data;
1361 ULLONG position = x.ntohll(*(ULLONG*)data);
1362 data += sizeof(ULLONG);
1363 ULONG amount = ntohl(*(ULONG*)data);
1365 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1367 UCHAR sendBuffer[amount];
1368 ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1370 if (!amountReceived)
1373 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1377 resp->copyin(sendBuffer, amountReceived);
1378 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1382 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1383 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1387 int VompClientRRProc::processStartStreamingRecording()
1389 // data is a pointer to the fileName string
1391 #if VDRVERSNUM >= 20301
1392 LOCK_RECORDINGS_READ;
1393 const cRecordings* tRecordings = Recordings;
1395 cThreadLock RecordingsLock(&Recordings);
1396 cRecordings* tRecordings = &Recordings;
1399 const cRecording* recording = tRecordings->GetByName((char*)req->data);
1401 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1405 x.recplayer = new RecPlayer(recording);
1407 resp->addULLONG(x.recplayer->getLengthBytes());
1408 resp->addULONG(x.recplayer->getLengthFrames());
1410 #if VDRVERSNUM < 10703
1411 resp->addUCHAR(true);//added for TS
1413 resp->addUCHAR(recording->IsPesRecording());//added for TS
1417 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1419 log->log("RRProc", Log::DEBUG, "written totalLength");
1425 int VompClientRRProc::processPositionFromFrameNumber()
1429 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1433 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1437 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1440 resp->addULLONG(retval);
1442 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1444 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1448 int VompClientRRProc::processFrameNumberFromPosition()
1452 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1456 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1460 retval = x.recplayer->frameNumberFromPosition(position);
1463 resp->addULONG(retval);
1465 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1467 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1471 int VompClientRRProc::processGetIFrame()
1473 bool success = false;
1475 ULONG* data = (ULONG*)req->data;
1477 ULONG frameNumber = ntohl(*data);
1479 ULONG direction = ntohl(*data);
1481 ULLONG rfilePosition = 0;
1482 ULONG rframeNumber = 0;
1483 ULONG rframeLength = 0;
1487 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1491 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1494 // returns file position, frame number, length
1498 resp->addULLONG(rfilePosition);
1499 resp->addULONG(rframeNumber);
1500 resp->addULONG(rframeLength);
1508 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1510 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1514 int VompClientRRProc::processGetChannelSchedule()
1516 ULONG* data = (ULONG*)req->data;
1518 ULONG channelNumber = ntohl(*data);
1520 ULONG startTime = ntohl(*data);
1522 ULONG duration = ntohl(*data);
1524 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1526 #if VDRVERSNUM >= 20301
1528 const cChannels* tChannels = Channels;
1530 cChannels* tChannels = &Channels;
1533 const cChannel* channel = tChannels->GetByNumber(channelNumber);
1538 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1540 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1544 log->log("RRProc", Log::DEBUG, "Got channel");
1546 #if VDRVERSNUM < 10300
1547 cMutexLock MutexLock;
1548 const cSchedules *tSchedules = cSIProcessor::Schedules(MutexLock);
1549 #elif VDRVERSNUM < 20301
1550 cSchedulesLock MutexLock;
1551 const cSchedules *tSchedules = cSchedules::Schedules(MutexLock);
1553 LOCK_SCHEDULES_READ;
1554 const cSchedules *tSchedules = Schedules;
1561 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1563 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1567 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1569 const cSchedule *Schedule = tSchedules->GetSchedule(channel->GetChannelID());
1574 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1576 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1580 log->log("RRProc", Log::DEBUG, "Got schedule object");
1582 const char* empty = "";
1583 bool atLeastOneEvent = false;
1586 ULONG thisEventTime;
1587 ULONG thisEventDuration;
1588 const char* thisEventTitle;
1589 const char* thisEventSubTitle;
1590 const char* thisEventDescription;
1592 #if VDRVERSNUM < 10300
1594 const cEventInfo *event;
1595 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1597 event = Schedule->GetEventNumber(eventNumber);
1599 thisEventID = event->GetEventID();
1600 thisEventTime = event->GetTime();
1601 thisEventDuration = event->GetDuration();
1602 thisEventTitle = event->GetTitle();
1603 thisEventSubTitle = event->GetSubtitle();
1604 thisEventDescription = event->GetExtendedDescription();
1608 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1610 thisEventID = event->EventID();
1611 thisEventTime = event->StartTime();
1612 thisEventDuration = event->Duration();
1613 thisEventTitle = event->Title();
1614 thisEventSubTitle = NULL;
1615 thisEventDescription = event->Description();
1619 //in the past filter
1620 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1623 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1626 if (thisEventTime >= (startTime + duration)) continue;
1628 if (!thisEventTitle) thisEventTitle = empty;
1629 if (!thisEventSubTitle) thisEventSubTitle = empty;
1630 if (!thisEventDescription) thisEventDescription = empty;
1632 resp->addULONG(thisEventID);
1633 resp->addULONG(thisEventTime);
1634 resp->addULONG(thisEventDuration);
1636 resp->addString(x.charconvsys->Convert(thisEventTitle));
1637 resp->addString(x.charconvsys->Convert(thisEventSubTitle));
1638 resp->addString(x.charconvsys->Convert(thisEventDescription));
1640 atLeastOneEvent = true;
1643 log->log("RRProc", Log::DEBUG, "Got all event data");
1645 if (!atLeastOneEvent)
1648 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1652 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1654 log->log("RRProc", Log::DEBUG, "written schedules packet");
1659 int VompClientRRProc::processGetTimers()
1661 #if VDRVERSNUM >= 20301
1663 const cTimers* tTimers = Timers;
1665 const cTimers* tTimers = &Timers;
1668 const cTimer *timer;
1669 int numTimers = tTimers->Count();
1671 resp->addULONG(numTimers);
1673 for (int i = 0; i < numTimers; i++)
1675 timer = tTimers->Get(i);
1677 #if VDRVERSNUM < 10300
1678 resp->addULONG(timer->Active());
1680 resp->addULONG(timer->HasFlags(tfActive));
1682 resp->addULONG(timer->Recording());
1683 resp->addULONG(timer->Pending());
1684 resp->addULONG(timer->Priority());
1685 resp->addULONG(timer->Lifetime());
1686 resp->addULONG(timer->Channel()->Number());
1687 resp->addULONG(timer->StartTime());
1688 resp->addULONG(timer->StopTime());
1689 resp->addULONG(timer->Day());
1690 resp->addULONG(timer->WeekDays());
1691 resp->addString(timer->File()); //Filename is system specific and not visible by user
1695 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1697 log->log("RRProc", Log::DEBUG, "Written timers list");
1702 int VompClientRRProc::processSetTimer()
1704 char* timerString = new char[strlen((char*)req->data) + 1];
1705 strcpy(timerString, (char*)req->data);
1707 #if VDRVERSNUM < 10300
1709 // If this is VDR 1.2 the date part of the timer string must be reduced
1710 // to just DD rather than YYYY-MM-DD
1712 int s = 0; // source
1713 int d = 0; // destination
1715 while(c != 2) // copy up to date section, including the second ':'
1717 timerString[d] = req->data[s];
1718 if (req->data[s] == ':') c++;
1722 // now it has copied up to the date section
1724 while(c != 2) // waste YYYY-MM-
1726 if (req->data[s] == '-') c++;
1729 // now source is at the DD
1730 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1731 d += req->dataLength - s;
1732 timerString[d] = '\0';
1734 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1737 log->log("RRProc", Log::DEBUG, "%s", timerString);
1739 cTimer *timer = new cTimer;
1740 if (!timer->Parse((char*)timerString))
1744 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1749 #if VDRVERSNUM >= 20301
1751 cTimers* tTimers = Timers;
1753 cTimers* tTimers = &Timers;
1756 cTimer *t = tTimers->GetTimer(timer);
1761 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1766 timer->ClrFlags(tfRecording);
1767 tTimers->Add(timer);
1768 #if VDRVERSNUM < 10300
1770 #elif VDRVERSNUM < 20301
1771 tTimers->SetModified();
1776 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1780 int VompClientRRProc::processDeleteTimer()
1782 log->log("RRProc", Log::DEBUG, "Delete timer called");
1787 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1788 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1789 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1790 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1791 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1793 #if VDRVERSNUM >= 20301
1795 cTimers* tTimers = Timers;
1797 cTimers* tTimers = &Timers;
1801 for (ti = tTimers->First(); ti; ti = tTimers->Next(ti))
1803 if ( (ti->Channel()->Number() == delChannel)
1804 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1805 && (ti->StartTime() == delStart)
1806 && (ti->StopTime() == delStop) )
1814 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1818 #if VDRVERSNUM < 20301
1819 // I suppose with the new locking this just can't happen
1820 if (tTimers->BeingEdited())
1822 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1825 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1830 if (ti->Recording())
1832 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1835 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1840 tTimers->SetModified();
1844 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1848 int VompClientRRProc::processGetRecInfo()
1850 // data is a pointer to the fileName string
1851 #if VDRVERSNUM >= 20301
1852 LOCK_RECORDINGS_READ;
1853 const cRecordings* tRecordings = Recordings;
1855 cThreadLock RecordingsLock(&Recordings);
1856 cRecordings* tRecordings = &Recordings;
1859 const cRecording *recording = tRecordings->GetByName((char*)req->data);
1861 time_t timerStart = 0;
1862 time_t timerStop = 0;
1863 char* summary = NULL;
1864 char* shorttext = NULL;
1865 char* description = NULL;
1867 bool newsummary=false;
1868 ULONG resumePoint = 0;
1872 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1875 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1880 4 bytes: start time for timer
1881 4 bytes: end time for timer
1882 4 bytes: resume point
1884 4 bytes: num components
1891 8 bytes: frames per second
1894 // Get current timer
1896 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1899 timerStart = rc->Timer()->StartTime();
1900 timerStop = rc->Timer()->StopTime();
1901 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1904 resp->addULONG(timerStart);
1905 resp->addULONG(timerStop);
1909 /* char* value = x.config.getValueString("ResumeData", (char*)req->data);
1912 resumePoint = strtoul(value, NULL, 10);
1916 char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1919 ResumeId = atoi(ResumeIdC);
1923 ResumeId = 0; //default if not defined in vomp-MAC.conf
1925 while (ResumeIDLock)
1926 cCondWait::SleepMs(100);
1927 ResumeIDLock = true;
1928 int OldSetupResumeID = Setup.ResumeID;
1929 Setup.ResumeID = ResumeId; //UGLY: quickly change resumeid
1930 #if VDRVERSNUM < 10703
1931 cResumeFile ResumeFile(recording->FileName()); //get corresponding resume file
1933 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1935 Setup.ResumeID = OldSetupResumeID; //and restore it back
1936 ResumeIDLock = false;
1938 int resume = ResumeFile.Read();
1939 //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1941 resumePoint = ResumeFile.Read();
1943 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1945 resp->addULONG(resumePoint);
1949 #if VDRVERSNUM < 10300
1950 summary = (char*)recording->Summary();
1952 const cRecordingInfo *Info = recording->Info();
1953 shorttext = (char*)Info->ShortText();
1954 description = (char*) (char*)Info->Description();
1955 if (isempty(shorttext)) summary=description;
1956 else if (isempty(description)) summary=shorttext;
1958 int length=strlen(description)+strlen(shorttext)+4;
1959 summary=new char[length];
1960 snprintf(summary,length,"%s\n\n%s",shorttext,description);
1964 if (isempty(summary)) summary = (char*)Info->Description();
1966 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1969 resp->addString(x.charconvsys->Convert(summary));
1970 if (newsummary) delete [] summary;
1974 resp->addString("");
1979 #if VDRVERSNUM < 10300
1981 // Send 0 for numchannels - this signals the client this info is not available
1985 const cComponents* components = Info->Components();
1987 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1995 resp->addULONG(components->NumComponents());
1997 tComponent* component;
1998 for (int i = 0; i < components->NumComponents(); i++)
2000 component = components->Component(i);
2002 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
2004 resp->addUCHAR(component->stream);
2005 resp->addUCHAR(component->type);
2007 if (component->language)
2009 resp->addString(x.charconvsys->Convert(component->language));
2013 resp->addString("");
2015 if (component->description)
2017 resp->addString(x.charconvsys->Convert(component->description));
2021 resp->addString("");
2027 double framespersec;
2028 #if VDRVERSNUM < 10703
2029 framespersec = FRAMESPERSEC;
2031 framespersec = Info->FramesPerSecond();
2033 resp->adddouble(framespersec);
2034 title = (char*)Info->Title();
2037 resp->addString(x.charconvsys->Convert(title));
2041 resp->addString(x.charconvsys->Convert(recording->Name()));
2047 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2049 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
2059 int VompClientRRProc::processReScanRecording()
2063 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
2067 x.recplayer->scan();
2069 resp->addULLONG(x.recplayer->getLengthBytes());
2070 resp->addULONG(x.recplayer->getLengthFrames());
2072 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2073 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
2077 // FIXME without client calling rescan, getblock wont work even tho more data is avail
2079 int VompClientRRProc::processGetMarks()
2081 // data is a pointer to the fileName string
2082 #if VDRVERSNUM >= 20301
2083 LOCK_RECORDINGS_READ;
2084 const cRecordings* tRecordings = Recordings;
2086 cThreadLock RecordingsLock(&Recordings);
2087 cRecordings* tRecordings = &Recordings;
2090 const cRecording *recording = tRecordings->GetByName((char*)req->data);
2091 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
2096 #if VDRVERSNUM < 10703
2097 Marks.Load(recording->FileName());
2099 Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
2103 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
2105 #if VDRVERSNUM < 10721
2106 ULLONG mposition = m->position;
2108 ULLONG mposition = m->Position();
2110 log->log("RRProc", Log::DEBUG, "found Mark %i", mposition);
2112 resp->addULONG(mposition);
2117 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
2123 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2125 log->log("RRProc", Log::DEBUG, "Written Marks list");
2130 int VompClientRRProc::processVDRShutdown()
2132 log->log("RRProc", Log::DEBUG, "Trying to shutdown VDR");
2133 VompClient::decClients(); // Temporarily make this client disappear
2134 cRemote::Put(kPower);
2135 VompClient::incClients();
2137 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2141 int VompClientRRProc::processGetRecScraperEventType()
2143 #if VDRVERSNUM >= 20301
2144 LOCK_RECORDINGS_READ;
2145 const cRecordings* tRecordings = Recordings;
2147 cThreadLock RecordingsLock(&Recordings);
2148 cRecordings* tRecordings = &Recordings;
2151 const cRecording *recording = tRecordings->GetByName((char*)req->data);
2152 ScraperGetEventType call;
2155 if (recording && x.scrapQuery())
2157 call.recording = recording;
2158 x.scraper->Service("GetEventType", &call);
2160 resp->addUCHAR(call.type);
2161 if (call.type == tMovie)
2163 resp->addLONG(call.movieId);
2165 else if (call.type == tSeries)
2167 resp->addLONG(call.seriesId);
2168 resp->addLONG(call.episodeId);
2171 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2176 int VompClientRRProc::processGetEventScraperEventType()
2178 ScraperGetEventType call;
2180 ULONG channelid = ntohl(*(ULONG*)req->data);
2181 ULONG eventid = ntohl(*(ULONG*)(req->data+4));
2182 const cEvent *event = NULL;
2184 #if VDRVERSNUM >= 20301
2186 const cChannels* tChannels = Channels;
2188 cChannels* tChannels = &Channels;
2191 const cChannel* channel = tChannels->GetByNumber(channelid);
2193 #if VDRVERSNUM < 10300
2194 cMutexLock MutexLock;
2195 const cSchedules *tSchedules = cSIProcessor::Schedules(MutexLock);
2196 #elif VDRVERSNUM < 20301
2197 cSchedulesLock MutexLock;
2198 const cSchedules *tSchedules = cSchedules::Schedules(MutexLock);
2200 LOCK_SCHEDULES_READ;
2201 const cSchedules *tSchedules = Schedules;
2204 if (tSchedules && channel)
2206 const cSchedule *Schedule = tSchedules->GetSchedule(channel->GetChannelID());
2208 event = Schedule->GetEvent(eventid);
2212 if (event && x.scrapQuery())
2215 x.scraper->Service("GetEventType",&call);
2217 resp->addUCHAR(call.type);
2218 if (call.type == tMovie)
2220 resp->addLONG(call.movieId);
2221 } else if (call.type == tSeries){
2222 resp->addLONG(call.seriesId);
2223 resp->addLONG(call.episodeId);
2225 if (x.pict->epgImageExists(eventid)) {
2232 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2237 #define ADDSTRING_TO_PAKET(y) if ((y)!=0) resp->addString(x.charconvutf8->Convert(y)); else resp->addString("");
2239 int VompClientRRProc::processGetScraperMovieInfo()
2243 movie.movieId = ntohl(*(ULONG*)req->data);
2244 if (!x.scrapQuery()) {
2245 log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2246 return 0; //stupid, I have no scraper why are you still asking
2248 x.scraper->Service("GetMovie",&movie);
2251 ADDSTRING_TO_PAKET(movie.title.c_str());
2252 ADDSTRING_TO_PAKET(movie.originalTitle.c_str());
2253 ADDSTRING_TO_PAKET(movie.tagline.c_str());
2254 ADDSTRING_TO_PAKET(movie.overview.c_str());
2255 resp->addUCHAR(movie.adult);
2256 ADDSTRING_TO_PAKET(movie.collectionName.c_str());
2258 resp->addLONG(movie.budget);
2259 resp->addLONG(movie.revenue);
2260 ADDSTRING_TO_PAKET(movie.genres.c_str());
2261 ADDSTRING_TO_PAKET(movie.homepage.c_str());
2262 ADDSTRING_TO_PAKET(movie.releaseDate.c_str());
2263 resp->addLONG(movie.runtime);
2264 resp->adddouble(movie.popularity);
2265 resp->adddouble(movie.voteAverage);
2266 resp->addULONG(movie.poster.width);
2267 resp->addULONG(movie.poster.height);
2268 resp->addULONG(movie.fanart.width);
2269 resp->addULONG(movie.fanart.height);
2270 resp->addULONG(movie.collectionPoster.width);
2271 resp->addULONG(movie.collectionPoster.height);
2272 resp->addULONG(movie.collectionFanart.width);
2273 resp->addULONG(movie.collectionFanart.height);
2274 resp->addULONG(movie.actors.size());
2275 for (ULONG acty=0; acty < movie.actors.size(); acty++) {
2276 ADDSTRING_TO_PAKET(movie.actors[acty].name.c_str());
2277 ADDSTRING_TO_PAKET(movie.actors[acty].role.c_str());
2278 resp->addULONG(movie.actors[acty].actorThumb.width);
2279 resp->addULONG(movie.actors[acty].actorThumb.height);
2283 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2290 int VompClientRRProc::processGetScraperSeriesInfo()
2293 series.seriesId = ntohl(*(ULONG*)req->data);
2294 series.episodeId = ntohl(*(ULONG*)(req->data+4));
2295 if (!x.scrapQuery()) {
2296 log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2297 return 0; //stupid, I have no scraper why are you still asking
2299 x.scraper->Service("GetSeries",&series);
2301 ADDSTRING_TO_PAKET(series.name.c_str());
2302 ADDSTRING_TO_PAKET(series.overview.c_str());
2303 ADDSTRING_TO_PAKET(series.firstAired.c_str());
2304 ADDSTRING_TO_PAKET(series.network.c_str());
2305 ADDSTRING_TO_PAKET(series.genre.c_str());
2306 resp->adddouble(series.rating);
2307 ADDSTRING_TO_PAKET(series.status.c_str());
2309 resp->addLONG(series.episode.number);
2310 resp->addLONG(series.episode.season);
2311 ADDSTRING_TO_PAKET(series.episode.name.c_str());
2312 ADDSTRING_TO_PAKET(series.episode.firstAired.c_str());
2313 ADDSTRING_TO_PAKET(series.episode.guestStars.c_str());
2314 ADDSTRING_TO_PAKET(series.episode.overview.c_str());
2315 resp->adddouble(series.episode.rating);
2316 resp->addULONG(series.episode.episodeImage.width);
2317 resp->addULONG(series.episode.episodeImage.height);
2319 ULONG num_actors = series.actors.size();
2320 resp->addULONG(num_actors);
2321 for (ULONG acty=0; acty < num_actors; acty++) {
2322 ADDSTRING_TO_PAKET(series.actors[acty].name.c_str());
2323 ADDSTRING_TO_PAKET(series.actors[acty].role.c_str());
2324 resp->addULONG(series.actors[acty].actorThumb.width);
2325 resp->addULONG(series.actors[acty].actorThumb.height);
2327 ULONG num_posters = series.posters.size();
2328 resp->addULONG(num_posters);
2329 for (ULONG medias = 0; medias < num_posters; medias++ ) {
2330 cTvMedia media=series.posters[medias];
2331 resp->addULONG(media.width);
2332 resp->addULONG(media.height);
2335 ULONG num_banners = series.banners.size();
2336 resp->addULONG(num_banners);
2337 for (ULONG medias = 0; medias < num_banners; medias++ ) {
2338 cTvMedia media=series.banners[medias];
2339 resp->addULONG(media.width);
2340 resp->addULONG(media.height);
2342 ULONG num_fanarts = series.fanarts.size();
2343 resp->addULONG(num_fanarts);
2344 for (ULONG medias = 0; medias < num_fanarts; medias++ ) {
2345 cTvMedia media=series.fanarts[medias];
2346 resp->addULONG(media.width);
2347 resp->addULONG(media.height);
2349 resp->addULONG(series.seasonPoster.width);
2350 resp->addULONG(series.seasonPoster.height);
2354 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2359 int VompClientRRProc::processLoadTvMedia()
2361 TVMediaRequest tvreq;
2362 tvreq.streamID = req->requestID;
2363 tvreq.type = ntohl(*(ULONG*)req->data);
2364 tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2365 tvreq.secondary_id = ntohl(*(ULONG*)(req->data+8));
2366 tvreq.type_pict = ntohl(*(ULONG*)(req->data+12));
2367 tvreq.container = ntohl(*(ULONG*)(req->data+16));
2368 tvreq.container_member = ntohl(*(ULONG*)(req->data+20));
2369 log->log("RRProc", Log::DEBUG, "TVMedia request %d",req->requestID);
2370 x.pict->addTVMediaRequest(tvreq);
2375 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2380 int VompClientRRProc::processLoadTvMediaRecThumb()
2382 TVMediaRequest tvreq;
2383 tvreq.streamID = req->requestID;
2384 tvreq.type = 3; // unknown but primary_name is set
2385 tvreq.primary_id = 0;
2386 tvreq.primary_name = std::string((const char*) req->data);
2387 tvreq.secondary_id = 0;
2388 tvreq.type_pict = 1;
2389 tvreq.container = 0;
2390 tvreq.container_member = 0;
2391 log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2392 x.pict->addTVMediaRequest(tvreq);
2397 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2402 int VompClientRRProc::processLoadTvMediaEventThumb()
2404 TVMediaRequest tvreq;
2405 tvreq.streamID = req->requestID;
2406 tvreq.type = 4; // unknown but primary_id is set
2407 UINT channelid = ntohl(*(ULONG*)req->data);
2408 tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2409 tvreq.secondary_id = 0;
2411 #if VDRVERSNUM >= 20301
2413 const cChannels* tChannels = Channels;
2415 cChannels* tChannels = &Channels;
2418 const cChannel* channel = tChannels->GetByNumber(channelid);
2420 if (channel) tvreq.primary_name = std::string((const char*)channel->GetChannelID().ToString());
2421 tvreq.type_pict = 1;
2422 tvreq.container = 0;
2423 tvreq.container_member = 0;
2424 log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2425 x.pict->addTVMediaRequest(tvreq);
2430 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2435 int VompClientRRProc::processLoadChannelLogo()
2437 TVMediaRequest tvreq;
2438 tvreq.streamID = req->requestID;
2439 tvreq.type = 5; // channel logo
2440 UINT channelid = ntohl(*(ULONG*)req->data);
2441 tvreq.primary_id = channelid;
2442 tvreq.secondary_id = 0;
2444 #if VDRVERSNUM >= 20301
2446 const cChannels* tChannels = Channels;
2448 cChannels* tChannels = &Channels;
2451 const cChannel* channel = tChannels->GetByNumber(channelid);
2453 if (channel) tvreq.primary_name = std::string((const char*)channel->Name());
2454 tvreq.type_pict = 1;
2455 tvreq.container = 0;
2456 tvreq.container_member = 0;
2457 if (channel) log->log("RRProc", Log::DEBUG, "TVMedia request %d %d %s",req->requestID,channelid, channel->Name());
2458 x.pict->addTVMediaRequest(tvreq);
2463 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2471 #endif // !VOMPSTANDALONE