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 = 0x00000302;
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
62 ULONG VompClientRRProc::getProtocolVersionMin()
64 return VOMP_PROTOCOL_VERSION_MIN;
67 ULONG VompClientRRProc::getProtocolVersionMax()
69 return VOMP_PROTOCOL_VERSION_MAX;
72 VompClientRRProc::VompClientRRProc(VompClient& x)
75 log = Log::getInstance();
80 VompClientRRProc::~VompClientRRProc()
85 bool VompClientRRProc::init()
87 int a = threadStart();
92 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
96 Now we have a queue system is used,
97 since on rare occasion the client fire two request at once
98 e.g. heavily channel switching
99 then processing only a single request would cause a deadlock in the client
103 log->log("RRProc", Log::DEBUG, "recvReq");
105 req_queue.push(newRequest);
106 threadSignalNoLock();
107 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
113 void VompClientRRProc::threadMethod()
116 log->log("RRProc", Log::DEBUG, "threadMethod startup");
118 if (req_queue.size() != 0)
121 - log->log("RRProc", Log::ERR, "threadMethod err 1");
125 That was how the code used to be.
127 TODO: Work out why this happens.
130 log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets");
131 while (req_queue.size())
133 //log->log("RRProc", Log::DEBUG, "thread while");
134 req = req_queue.front();
137 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
139 if (!processPacket())
141 log->log("RRProc", Log::ERR, "processPacket exited with fail");
147 log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets done.");
153 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
154 threadWaitForSignal(); // unlocks, waits, relocks
155 if (req_queue.size() == 0)
157 log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");
162 // signalled with something in queue
164 log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
166 while (req_queue.size())
168 //log->log("RRProc", Log::DEBUG, "thread while");
169 req = req_queue.front();
172 threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
174 if (!processPacket())
176 log->log("RRProc", Log::ERR, "processPacket exited with fail");
183 // locked and run out of packets to process
187 bool VompClientRRProc::processPacket()
189 resp = new ResponsePacket();
190 if (!resp->init(req->requestID))
192 log->log("RRProc", Log::ERR, "response packet init fail");
195 if (req->data) free(req->data);
207 result = processLogin();
209 #ifndef VOMPSTANDALONE
211 result = processGetRecordingsList();
214 result = processDeleteRecording();
217 result = processGetChannelsList();
220 result = processStartStreamingChannel();
223 result = processGetBlock();
226 result = processStopStreaming();
229 result = processStartStreamingRecording();
232 result = processGetChannelSchedule();
236 result = processConfigSave();
239 result = processConfigLoad();
241 #ifndef VOMPSTANDALONE
243 result = processReScanRecording(); // FIXME obselete
246 result = processGetTimers();
249 result = processSetTimer();
252 result = processPositionFromFrameNumber();
255 result = processFrameNumberFromPosition();
258 result = processMoveRecording();
261 result = processGetIFrame();
264 result = processGetRecInfo();
267 result = processGetMarks();
270 result = processGetChannelPids();
273 result = processDeleteTimer();
276 result = processVDRShutdown();
278 case VDR_GETRECSCRAPEREVENTTYPE:
279 result = processGetRecScraperEventType();
281 case VDR_GETSCRAPERMOVIEINFO:
282 result = processGetScraperMovieInfo();
284 case VDR_GETSCRAPERSERIESINFO:
285 result = processGetScraperSeriesInfo();
287 case VDR_LOADTVMEDIA:
288 result = processLoadTvMedia();
290 case VDR_LOADTVMEDIARECTHUMB:
291 result = processLoadTvMediaRecThumb();
293 case VDR_GETEVENTSCRAPEREVENTTYPE:
294 result = processGetEventScraperEventType();
296 case VDR_LOADTVMEDIAEVENTTHUMB:
297 result = processLoadTvMediaEventThumb();
299 case VDR_LOADCHANNELLOGO:
300 result = processLoadChannelLogo();
303 case VDR_GETMEDIALIST:
304 result = processGetMediaList();
307 result = processOpenMedia();
309 case VDR_GETMEDIABLOCK:
310 result = processGetMediaBlock();
313 result = processGetLanguageList();
316 result = processGetLanguageContent();
318 case VDR_GETMEDIAINFO:
319 result = processGetMediaInfo();
321 case VDR_CLOSECHANNEL:
322 result = processCloseMediaChannel();
325 result = processSetCharset();
332 if (req->data) free(req->data);
336 if (result) return true;
341 int VompClientRRProc::processLogin()
343 if (req->dataLength != 6) return 0;
347 char configFileName[PATH_MAX];
348 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]);
349 x.config.init(configFileName);
351 // Send the login reply
353 time_t timeNow = time(NULL);
354 struct tm* timeStruct = localtime(&timeNow);
355 int timeOffset = timeStruct->tm_gmtoff;
357 resp->addULONG(timeNow);
358 resp->addLONG(timeOffset);
359 resp->addULONG(VOMP_PROTOCOL_VERSION_MIN);
360 resp->addULONG(VOMP_PROTOCOL_VERSION_MAX);
362 // also send information about languages
363 resp->addULONG(I18nLanguages()->Size());
364 resp->addLONG(Setup.DisplaySubtitles);
365 for (int i=0;i < I18nLanguages()->Size(); i++) {
366 resp->addLONG(Setup.AudioLanguages[i]);
367 resp->addLONG(Setup.SubtitleLanguages[i]);
368 resp->addString(I18nLanguageCode(i));
372 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
373 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
376 x.netLog(); // safe to run here since the client won't start net logging for a while yet
381 int VompClientRRProc::processSetCharset()
383 int charset = ntohl(*(ULONG*)req->data);
384 if (charset>0 && charset<3)
386 log->log("RRProc", Log::DEBUG, "Set charset to %d", charset);
387 x.setCharset(charset);
392 log->log("RRProc", Log::DEBUG, "Invalid charset %d", charset);
396 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
400 int VompClientRRProc::processConfigSave()
402 char* section = (char*)req->data;
406 for (UINT k = 0; k < req->dataLength; k++)
408 if (req->data[k] == '\0')
412 key = (char*)&req->data[k+1];
416 value = (char*)&req->data[k+1];
422 // if the last string (value) doesnt have null terminator, give up
423 if (req->data[req->dataLength - 1] != '\0') return 0;
425 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
426 if (x.config.setValueString(section, key, value))
436 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
441 int VompClientRRProc::processConfigLoad()
443 char* section = (char*)req->data;
446 for (UINT k = 0; k < req->dataLength; k++)
448 if (req->data[k] == '\0')
450 key = (char*)&req->data[k+1];
455 char* value = x.config.getValueString(section, key);
459 resp->addString(value);//client coding, do not touch
460 log->log("RRProc", Log::DEBUG, "Written config load packet");
466 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
470 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
476 //helper for sending from a serialize buffer
477 //insert the used len into the first 4 Bytes of the buffer
478 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
479 resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
481 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
485 * media List Request:
486 * Media List response:
489 #define MLISTBUF 500000
490 int VompClientRRProc::processGetMediaList()
492 SerializeBuffer buffer(req->data,req->dataLength);
493 MediaURI uri(0,NULL,NULL);
494 VDR_GetMediaListRequest request(&uri);
495 if (request.deserialize(&buffer) != 0) {
496 log->log("Client", Log::ERR, "getMediaList unable to deserialize");
499 const char *dirname=uri.getName();
500 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
503 if (dirname == NULL) {
504 ml=x.media->getRootList();
506 ml=x.media->getMediaList(&uri);
509 log->log("Client", Log::ERR, "getMediaList returned NULL");
512 SerializeBuffer rbuf(MLISTBUF,false,true);
513 ULONG flags=0; //TODO: real error handling by setting flags
514 VDR_GetMediaListResponse response(&flags,ml);
515 if (response.serialize(&rbuf) != 0) {
516 log->log("Client", Log::ERR, "getMediaList returned NULL");
520 log->log("Client", Log::DEBUG, "getMediaList size %u", ml->size());
525 log->log("Client", Log::DEBUG, "Written Media list");
530 * openMedia response:
532 int VompClientRRProc::processOpenMedia()
534 SerializeBuffer buffer(req->data,req->dataLength);
535 MediaURI uri(0,NULL,NULL);
539 VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
540 if (request.deserialize(&buffer) != 0) {
541 log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
544 const char *name=uri.getName();
545 log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
547 int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
552 log->log("Client", Log::ERR, "openMediaRequest unable to open");
554 VDR_OpenMediumResponse response(&flags,&size);
555 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
556 if (response.serialize(&rbuf) != 0) {
557 log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
560 log->log("Client", Log::DEBUG, "openMediaRequest size %llu", size);
567 * packet - no serialized response!
569 int VompClientRRProc::processGetMediaBlock()
571 SerializeBuffer buffer(req->data,req->dataLength);
575 VDR_GetMediaBlockRequest request(&channel,&position,&amount);
576 if (request.deserialize(&buffer) != 0) {
577 log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
580 log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
582 UCHAR sendBuffer[amount ];
583 ULONG amountReceived = 0;
584 UCHAR *rbuf=sendBuffer;
585 int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
586 if (!amountReceived || rt != 0)
588 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
592 if (rbuf != sendBuffer) {
593 //the provider did not use the optimized handling with using my buffer
594 resp->copyin(rbuf,amountReceived);
597 // the provider did not allocate a new buffer
598 resp->copyin(sendBuffer,amountReceived);
602 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
603 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
610 int VompClientRRProc::processGetMediaInfo()
612 SerializeBuffer buffer(req->data,req->dataLength);
614 VDR_GetMediaInfoRequest request(&channel);
615 if (request.deserialize(&buffer) != 0) {
616 log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
619 log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
622 int rt=x.media->getMediaInfo(channel,&mi);
625 log->log("Client", Log::ERR, "getMediaInfo unable to get");
627 VDR_GetMediaInfoResponse response(&flags,&mi);
628 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
629 if (response.serialize(&rbuf) != 0) {
630 log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
642 int VompClientRRProc::processCloseMediaChannel()
644 SerializeBuffer buffer(req->data,req->dataLength);
646 VDR_CloseMediaChannelRequest request(&channel);
647 if (request.deserialize(&buffer) != 0) {
648 log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
652 log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
653 int rt=x.media->closeMediaChannel(channel);
656 log->log("Client", Log::ERR, "closeMediaChannel unable to get");
658 VDR_CloseMediaChannelResponse response(&flags);
659 SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
660 if (response.serialize(&rbuf) != 0) {
661 log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
670 int VompClientRRProc::processGetLanguageList()
672 x.i18n.findLanguages();
673 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
675 I18n::lang_code_list::const_iterator iter;
676 for (iter = languages.begin(); iter != languages.end(); ++iter)
678 resp->addString(iter->first.c_str()); // Source code is acsii
679 resp->addString(x.charconvutf8->Convert(iter->second.c_str())); //translate string can be any utf-8 character
682 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
686 int VompClientRRProc::processGetLanguageContent()
688 if (req->dataLength <= 0) return 0;
689 std::string code, result;
690 code.assign((char*)req->data, req->dataLength - 1);
691 x.i18n.findLanguages();
692 I18n::trans_table texts = x.i18n.getLanguageContent(code);
693 I18n::trans_table::const_iterator iter;
694 for (iter = texts.begin(); iter != texts.end(); ++iter)
696 resp->addString(iter->first.c_str());// source code is acsii since it is english
697 resp->addString(x.charconvutf8->Convert(iter->second.c_str())); // translate text can be any unicode string, it is stored as UTF-8
700 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
704 #ifndef VOMPSTANDALONE
706 int VompClientRRProc::processGetRecordingsList()
709 #if APIVERSNUM > 20101
710 int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB);
712 int Percent = VideoDiskSpace(&FreeMB);
714 int Total = (FreeMB / (100 - Percent)) * 100;
716 resp->addULONG(Total);
717 resp->addULONG(FreeMB);
718 resp->addULONG(Percent);
720 cRecordings Recordings;
723 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
725 #if VDRVERSNUM < 10721
726 resp->addULONG(recording->start);
728 resp->addULONG(recording->Start());
730 resp->addUCHAR(recording->IsNew() ? 1 : 0);
731 resp->addString(x.charconvsys->Convert(recording->Name())); //coding of recording name is system dependent
732 resp->addString(recording->FileName());//file name are not visible by user do not touch
736 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
738 log->log("RRProc", Log::DEBUG, "Written recordings list");
743 int VompClientRRProc::processDeleteRecording()
745 // data is a pointer to the fileName string
747 cRecordings Recordings;
748 Recordings.Load(); // probably have to do this
750 cRecording* recording = Recordings.GetByName((char*)req->data);
752 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
756 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
758 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
761 if (recording->Delete())
763 // Copy svdrp's way of doing this, see if it works
764 #if VDRVERSNUM > 10300
765 ::Recordings.DelByName(recording->FileName());
785 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
790 int VompClientRRProc::processMoveRecording()
792 log->log("RRProc", Log::DEBUG, "Process move recording");
793 char* fileName = (char*)req->data;
794 char* newPath = NULL;
796 for (UINT k = 0; k < req->dataLength; k++)
798 if (req->data[k] == '\0')
800 newPath = (char*)&req->data[k+1];
804 if (!newPath) return 0;
806 cRecordings Recordings;
807 Recordings.Load(); // probably have to do this
809 cRecording* recording = Recordings.GetByName((char*)fileName);
811 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
815 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
818 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
819 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
820 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
822 const char* t = recording->FileName();
824 char* dateDirName = NULL; int k;
825 char* titleDirName = NULL; int j;
827 // Find the datedirname
828 for(k = strlen(t) - 1; k >= 0; k--)
832 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
833 dateDirName = new char[strlen(&t[k+1]) + 1];
834 strcpy(dateDirName, &t[k+1]);
839 // Find the titledirname
841 for(j = k-1; j >= 0; j--)
845 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
846 titleDirName = new char[(k - j - 1) + 1];
847 memcpy(titleDirName, &t[j+1], k - j - 1);
848 titleDirName[k - j - 1] = '\0';
853 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
854 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
855 #if APIVERSNUM > 20101
856 log->log("RRProc", Log::DEBUG, "viddir: %s", cVideoDirectory::Name());
858 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
861 char* newPathConv = new char[strlen(newPath)+1];
862 strcpy(newPathConv, newPath);
863 ExchangeChars(newPathConv, true);
864 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
866 #if APIVERSNUM > 20101
867 char* newContainer = new char[strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1];
868 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1);
869 sprintf(newContainer, "%s%s%s", cVideoDirectory::Name(), newPathConv, titleDirName);
871 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
872 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
873 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
875 delete[] newPathConv;
877 log->log("RRProc", Log::DEBUG, "%s", newContainer);
880 int statret = stat(newContainer, &dstat);
881 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
883 log->log("RRProc", Log::DEBUG, "new dir does not exist");
884 int mkdirret = mkdir(newContainer, 0755);
887 delete[] dateDirName;
888 delete[] titleDirName;
889 delete[] newContainer;
893 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
897 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
899 delete[] dateDirName;
900 delete[] titleDirName;
901 delete[] newContainer;
905 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
909 // Ok, the directory container has been made, or it pre-existed.
911 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
912 sprintf(newDir, "%s/%s", newContainer, dateDirName);
914 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
915 int renameret = rename(t, newDir);
918 // Success. Test for remove old dir containter
919 char* oldTitleDir = new char[k+1];
920 memcpy(oldTitleDir, t, k);
921 oldTitleDir[k] = '\0';
922 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
923 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
924 delete[] oldTitleDir;
929 #if VDRVERSNUM > 10311
931 ::Recordings.Update();
933 // Success. Send a different packet from just a ulong
934 resp->addULONG(1); // success
935 resp->addString(newDir); //system depent do not convert
943 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
945 delete[] dateDirName;
946 delete[] titleDirName;
947 delete[] newContainer;
954 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
961 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
967 int VompClientRRProc::processGetChannelsList()
971 char* chanConfig = x.config.getValueString("General", "Channels");
973 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
975 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
977 #if VDRVERSNUM < 10300
978 if (!channel->GroupSep() && (!channel->Ca() || allChans))
980 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
983 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
985 if (channel->Vpid()) type = 1;
986 #if VDRVERSNUM < 10300
989 else if (channel->Apid(0)) type = 2;
993 resp->addULONG(channel->Number());
994 resp->addULONG(type);
995 resp->addString(x.charconvsys->Convert(channel->Name()));
996 #if VDRVERSNUM < 10703
999 resp->addULONG(channel->Vtype());
1005 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1007 log->log("RRProc", Log::DEBUG, "Written channels list");
1012 int VompClientRRProc::processGetChannelPids()
1014 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1016 const cChannel* channel = Channels.GetByNumber(channelNumber);
1021 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1030 #if VDRVERSNUM < 10300
1032 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
1033 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
1035 if (channel->Apid2())
1037 else if (channel->Apid1())
1044 for (const int *Apid = channel->Apids(); *Apid; Apid++)
1048 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
1052 for (const int *Spid = channel->Spids(); *Spid; Spid++)
1059 // Format of response
1078 resp->addULONG(channel->Vpid());
1079 #if VDRVERSNUM < 10703
1082 resp->addULONG(channel->Vtype());
1084 resp->addULONG(numApids);
1086 #if VDRVERSNUM < 10300
1089 resp->addULONG(channel->Apid1());
1090 resp->addString("");
1094 resp->addULONG(channel->Apid2());
1095 resp->addString("");
1100 for (ULONG i = 0; i < numApids; i++)
1102 resp->addULONG(channel->Apid(i));
1103 resp->addString(x.charconvsys->Convert(channel->Alang(i)));
1105 resp->addULONG(numDpids);
1106 for (ULONG i = 0; i < numDpids; i++)
1108 resp->addULONG(channel->Dpid(i));
1109 resp->addString(x.charconvsys->Convert(channel->Dlang(i)));
1111 resp->addULONG(numSpids);
1112 for (ULONG i = 0; i < numSpids; i++)
1114 resp->addULONG(channel->Spid(i));
1115 resp->addString(x.charconvsys->Convert(channel->Slang(i)));
1118 resp->addULONG(channel->Tpid());
1119 // Format of extended response, for compatibility with older client at the end
1131 #if VDRVERSNUM < 10300
1141 for (ULONG i = 0; i < numApids; i++)
1143 #if VDRVERSNUM < 10715
1146 resp->addULONG(channel->Atype(i));
1149 for (ULONG i = 0; i < numDpids; i++)
1151 #if VDRVERSNUM < 10715
1152 resp->addULONG(0x6A /*AC3*/);
1154 resp->addULONG(channel->Dtype(i));
1157 for (ULONG i = 0; i < numSpids; i++)
1159 #if VDRVERSNUM < 10715
1164 resp->addULONG(channel->SubtitlingType(i));
1165 resp->addULONG(channel->CompositionPageId(i));
1166 resp->addULONG(channel->AncillaryPageId(i));
1173 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1175 log->log("RRProc", Log::DEBUG, "Written channels pids");
1180 int VompClientRRProc::processStartStreamingChannel()
1184 log->log("RRProc", Log::ERR, "Client called start streaming twice");
1188 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
1189 ULONG channelNumber = ntohl(*(ULONG*)req->data);
1191 const cChannel* channel = Channels.GetByNumber(channelNumber);
1196 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1200 // get the priority we should use
1202 int priority = x.config.getValueLong("General", "Live priority", &fail);
1205 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1209 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1213 // a bit of sanity..
1214 #if VDRVERSNUM < 10725
1215 if (priority < 0) priority = 0;
1217 if (priority < -99) priority = -99;
1219 if (priority > 99) priority = 99;
1221 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1222 x.lp = MVPReceiver::create(channel, priority);
1228 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1232 if (!x.lp->init(&x.tcp, req->requestID))
1238 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1244 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1248 int VompClientRRProc::processStopStreaming()
1250 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1253 x.lp->detachMVPReceiver();
1257 else if (x.recplayer)
1259 x.writeResumeData();
1262 delete x.recordingManager;
1264 x.recordingManager = NULL;
1269 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1273 int VompClientRRProc::processGetBlock()
1277 log->log("RRProc", Log::ERR, "Get block called during live streaming");
1283 log->log("RRProc", Log::ERR, "Get block called when no recording open");
1287 UCHAR* data = req->data;
1289 ULLONG position = x.ntohll(*(ULLONG*)data);
1290 data += sizeof(ULLONG);
1291 ULONG amount = ntohl(*(ULONG*)data);
1293 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1295 UCHAR sendBuffer[amount];
1296 ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1298 if (!amountReceived)
1301 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1305 resp->copyin(sendBuffer, amountReceived);
1306 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1310 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1311 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1315 int VompClientRRProc::processStartStreamingRecording()
1317 // data is a pointer to the fileName string
1319 x.recordingManager = new cRecordings;
1320 x.recordingManager->Load();
1322 cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1324 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1328 x.recplayer = new RecPlayer(recording);
1330 resp->addULLONG(x.recplayer->getLengthBytes());
1331 resp->addULONG(x.recplayer->getLengthFrames());
1333 #if VDRVERSNUM < 10703
1334 resp->addUCHAR(true);//added for TS
1336 resp->addUCHAR(recording->IsPesRecording());//added for TS
1340 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1342 log->log("RRProc", Log::DEBUG, "written totalLength");
1346 delete x.recordingManager;
1347 x.recordingManager = NULL;
1352 int VompClientRRProc::processPositionFromFrameNumber()
1356 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1360 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1364 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1367 resp->addULLONG(retval);
1369 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1371 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1375 int VompClientRRProc::processFrameNumberFromPosition()
1379 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1383 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1387 retval = x.recplayer->frameNumberFromPosition(position);
1390 resp->addULONG(retval);
1392 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1394 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1398 int VompClientRRProc::processGetIFrame()
1400 bool success = false;
1402 ULONG* data = (ULONG*)req->data;
1404 ULONG frameNumber = ntohl(*data);
1406 ULONG direction = ntohl(*data);
1408 ULLONG rfilePosition = 0;
1409 ULONG rframeNumber = 0;
1410 ULONG rframeLength = 0;
1414 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1418 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1421 // returns file position, frame number, length
1425 resp->addULLONG(rfilePosition);
1426 resp->addULONG(rframeNumber);
1427 resp->addULONG(rframeLength);
1435 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1437 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1441 int VompClientRRProc::processGetChannelSchedule()
1443 ULONG* data = (ULONG*)req->data;
1445 ULONG channelNumber = ntohl(*data);
1447 ULONG startTime = ntohl(*data);
1449 ULONG duration = ntohl(*data);
1451 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1453 const cChannel* channel = Channels.GetByNumber(channelNumber);
1458 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1460 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1464 log->log("RRProc", Log::DEBUG, "Got channel");
1466 #if VDRVERSNUM < 10300
1467 cMutexLock MutexLock;
1468 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1470 cSchedulesLock MutexLock;
1471 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1477 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1479 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1483 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1485 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1490 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1492 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1496 log->log("RRProc", Log::DEBUG, "Got schedule object");
1498 const char* empty = "";
1499 bool atLeastOneEvent = false;
1502 ULONG thisEventTime;
1503 ULONG thisEventDuration;
1504 const char* thisEventTitle;
1505 const char* thisEventSubTitle;
1506 const char* thisEventDescription;
1508 #if VDRVERSNUM < 10300
1510 const cEventInfo *event;
1511 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1513 event = Schedule->GetEventNumber(eventNumber);
1515 thisEventID = event->GetEventID();
1516 thisEventTime = event->GetTime();
1517 thisEventDuration = event->GetDuration();
1518 thisEventTitle = event->GetTitle();
1519 thisEventSubTitle = event->GetSubtitle();
1520 thisEventDescription = event->GetExtendedDescription();
1524 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1526 thisEventID = event->EventID();
1527 thisEventTime = event->StartTime();
1528 thisEventDuration = event->Duration();
1529 thisEventTitle = event->Title();
1530 thisEventSubTitle = NULL;
1531 thisEventDescription = event->Description();
1535 //in the past filter
1536 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1539 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1542 if (thisEventTime >= (startTime + duration)) continue;
1544 if (!thisEventTitle) thisEventTitle = empty;
1545 if (!thisEventSubTitle) thisEventSubTitle = empty;
1546 if (!thisEventDescription) thisEventDescription = empty;
1548 resp->addULONG(thisEventID);
1549 resp->addULONG(thisEventTime);
1550 resp->addULONG(thisEventDuration);
1552 resp->addString(x.charconvsys->Convert(thisEventTitle));
1553 resp->addString(x.charconvsys->Convert(thisEventSubTitle));
1554 resp->addString(x.charconvsys->Convert(thisEventDescription));
1556 atLeastOneEvent = true;
1559 log->log("RRProc", Log::DEBUG, "Got all event data");
1561 if (!atLeastOneEvent)
1564 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1568 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1570 log->log("RRProc", Log::DEBUG, "written schedules packet");
1575 int VompClientRRProc::processGetTimers()
1578 int numTimers = Timers.Count();
1580 resp->addULONG(numTimers);
1582 for (int i = 0; i < numTimers; i++)
1584 timer = Timers.Get(i);
1586 #if VDRVERSNUM < 10300
1587 resp->addULONG(timer->Active());
1589 resp->addULONG(timer->HasFlags(tfActive));
1591 resp->addULONG(timer->Recording());
1592 resp->addULONG(timer->Pending());
1593 resp->addULONG(timer->Priority());
1594 resp->addULONG(timer->Lifetime());
1595 resp->addULONG(timer->Channel()->Number());
1596 resp->addULONG(timer->StartTime());
1597 resp->addULONG(timer->StopTime());
1598 resp->addULONG(timer->Day());
1599 resp->addULONG(timer->WeekDays());
1600 resp->addString(timer->File()); //Filename is system specific and not visible by user
1604 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1606 log->log("RRProc", Log::DEBUG, "Written timers list");
1611 int VompClientRRProc::processSetTimer()
1613 char* timerString = new char[strlen((char*)req->data) + 1];
1614 strcpy(timerString, (char*)req->data);
1616 #if VDRVERSNUM < 10300
1618 // If this is VDR 1.2 the date part of the timer string must be reduced
1619 // to just DD rather than YYYY-MM-DD
1621 int s = 0; // source
1622 int d = 0; // destination
1624 while(c != 2) // copy up to date section, including the second ':'
1626 timerString[d] = req->data[s];
1627 if (req->data[s] == ':') c++;
1631 // now it has copied up to the date section
1633 while(c != 2) // waste YYYY-MM-
1635 if (req->data[s] == '-') c++;
1638 // now source is at the DD
1639 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1640 d += req->dataLength - s;
1641 timerString[d] = '\0';
1643 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1646 log->log("RRProc", Log::DEBUG, "%s", timerString);
1648 cTimer *timer = new cTimer;
1649 if (timer->Parse((char*)timerString))
1651 cTimer *t = Timers.GetTimer(timer);
1655 #if VDRVERSNUM < 10300
1658 Timers.SetModified();
1662 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1663 return 1; // FIXME - cTimer* timer is leaked here!
1669 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1676 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1682 int VompClientRRProc::processDeleteTimer()
1684 log->log("RRProc", Log::DEBUG, "Delete timer called");
1689 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1690 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1691 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1692 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1693 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1696 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1698 if ( (ti->Channel()->Number() == delChannel)
1699 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1700 && (ti->StartTime() == delStart)
1701 && (ti->StopTime() == delStop) )
1709 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1713 if (!Timers.BeingEdited())
1715 if (!ti->Recording())
1718 Timers.SetModified();
1721 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1726 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1729 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1735 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1738 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1743 int VompClientRRProc::processGetRecInfo()
1745 // data is a pointer to the fileName string
1747 cRecordings Recordings;
1748 Recordings.Load(); // probably have to do this
1750 cRecording *recording = Recordings.GetByName((char*)req->data);
1752 time_t timerStart = 0;
1753 time_t timerStop = 0;
1754 char* summary = NULL;
1755 char* shorttext = NULL;
1756 char* description = NULL;
1758 bool newsummary=false;
1759 ULONG resumePoint = 0;
1763 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1766 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1771 4 bytes: start time for timer
1772 4 bytes: end time for timer
1773 4 bytes: resume point
1775 4 bytes: num components
1782 8 bytes: frames per second
1785 // Get current timer
1787 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1790 timerStart = rc->Timer()->StartTime();
1791 timerStop = rc->Timer()->StopTime();
1792 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1795 resp->addULONG(timerStart);
1796 resp->addULONG(timerStop);
1800 /* char* value = x.config.getValueString("ResumeData", (char*)req->data);
1803 resumePoint = strtoul(value, NULL, 10);
1807 char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1810 ResumeId = atoi(ResumeIdC);
1814 ResumeId = 0; //default if not defined in vomp-MAC.conf
1816 while (ResumeIDLock)
1817 cCondWait::SleepMs(100);
1818 ResumeIDLock = true;
1819 int OldSetupResumeID = Setup.ResumeID;
1820 Setup.ResumeID = ResumeId; //UGLY: quickly change resumeid
1821 #if VDRVERSNUM < 10703
1822 cResumeFile ResumeFile(recording->FileName()); //get corresponding resume file
1824 cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1826 Setup.ResumeID = OldSetupResumeID; //and restore it back
1827 ResumeIDLock = false;
1829 int resume = ResumeFile.Read();
1830 //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1832 resumePoint = ResumeFile.Read();
1834 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1836 resp->addULONG(resumePoint);
1840 #if VDRVERSNUM < 10300
1841 summary = (char*)recording->Summary();
1843 const cRecordingInfo *Info = recording->Info();
1844 shorttext = (char*)Info->ShortText();
1845 description = (char*) (char*)Info->Description();
1846 if (isempty(shorttext)) summary=description;
1847 else if (isempty(description)) summary=shorttext;
1849 int length=strlen(description)+strlen(shorttext)+4;
1850 summary=new char[length];
1851 snprintf(summary,length,"%s\n\n%s",shorttext,description);
1855 if (isempty(summary)) summary = (char*)Info->Description();
1857 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1860 resp->addString(x.charconvsys->Convert(summary));
1861 if (newsummary) delete [] summary;
1865 resp->addString("");
1870 #if VDRVERSNUM < 10300
1872 // Send 0 for numchannels - this signals the client this info is not available
1876 const cComponents* components = Info->Components();
1878 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1886 resp->addULONG(components->NumComponents());
1888 tComponent* component;
1889 for (int i = 0; i < components->NumComponents(); i++)
1891 component = components->Component(i);
1893 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1895 resp->addUCHAR(component->stream);
1896 resp->addUCHAR(component->type);
1898 if (component->language)
1900 resp->addString(x.charconvsys->Convert(component->language));
1904 resp->addString("");
1906 if (component->description)
1908 resp->addString(x.charconvsys->Convert(component->description));
1912 resp->addString("");
1918 double framespersec;
1919 #if VDRVERSNUM < 10703
1920 framespersec = FRAMESPERSEC;
1922 framespersec = Info->FramesPerSecond();
1924 resp->adddouble(framespersec);
1925 title = (char*)Info->Title();
1928 resp->addString(x.charconvsys->Convert(title));
1932 resp->addString(x.charconvsys->Convert(recording->Name()));
1938 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1940 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1950 int VompClientRRProc::processReScanRecording()
1954 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1958 x.recplayer->scan();
1960 resp->addULLONG(x.recplayer->getLengthBytes());
1961 resp->addULONG(x.recplayer->getLengthFrames());
1963 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1964 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1968 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1970 int VompClientRRProc::processGetMarks()
1972 // data is a pointer to the fileName string
1975 cRecordings Recordings;
1976 Recordings.Load(); // probably have to do this
1978 cRecording *recording = Recordings.GetByName((char*)req->data);
1980 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1984 #if VDRVERSNUM < 10703
1985 Marks.Load(recording->FileName());
1987 Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
1991 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1993 #if VDRVERSNUM < 10721
1994 ULLONG mposition = m->position;
1996 ULLONG mposition = m->Position();
1998 log->log("RRProc", Log::DEBUG, "found Mark %i", mposition);
2000 resp->addULONG(mposition);
2005 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
2011 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2013 log->log("RRProc", Log::DEBUG, "Written Marks list");
2018 int VompClientRRProc::processVDRShutdown()
2020 log->log("RRProc", Log::DEBUG, "Trying to shutdown VDR");
2021 VompClient::decClients(); // Temporarily make this client disappear
2022 cRemote::Put(kPower);
2023 VompClient::incClients();
2025 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2029 int VompClientRRProc::processGetRecScraperEventType()
2031 Recordings.Load(); // probably have to do this
2033 cRecording *recording = Recordings.GetByName((char*)req->data);
2034 ScraperGetEventType call;
2037 if (recording && x.scrapQuery())
2039 call.recording = recording;
2040 x.scraper->Service("GetEventType",&call);
2042 resp->addUCHAR(call.type);
2043 if (call.type == tMovie)
2045 resp->addLONG(call.movieId);
2046 } else if (call.type == tSeries){
2047 resp->addLONG(call.seriesId);
2048 resp->addLONG(call.episodeId);
2051 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2056 int VompClientRRProc::processGetEventScraperEventType()
2058 ScraperGetEventType call;
2060 ULONG channelid = ntohl(*(ULONG*)req->data);
2061 ULONG eventid = ntohl(*(ULONG*)(req->data+4));
2062 const cEvent *event = NULL;
2064 const cChannel* channel = Channels.GetByNumber(channelNumber);
2066 #if VDRVERSNUM < 10300
2067 cMutexLock MutexLock;
2068 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
2070 cSchedulesLock MutexLock;
2071 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
2073 if (Schedules && channel)
2075 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
2077 event = Schedule->GetEvent(eventid);
2081 if (event && x.scrapQuery())
2084 x.scraper->Service("GetEventType",&call);
2086 resp->addUCHAR(call.type);
2087 if (call.type == tMovie)
2089 resp->addLONG(call.movieId);
2090 } else if (call.type == tSeries){
2091 resp->addLONG(call.seriesId);
2092 resp->addLONG(call.episodeId);
2094 if (x.pict->epgImageExists(eventid)) {
2101 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2106 #define ADDSTRING_TO_PAKET(y) if ((y)!=0) resp->addString(x.charconvutf8->Convert(y)); else resp->addString("");
2108 int VompClientRRProc::processGetScraperMovieInfo()
2112 movie.movieId = ntohl(*(ULONG*)req->data);
2113 if (!x.scrapQuery()) {
2114 log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2115 return 0; //stupid, I have no scraper why are you still asking
2117 x.scraper->Service("GetMovie",&movie);
2120 ADDSTRING_TO_PAKET(movie.title.c_str());
2121 ADDSTRING_TO_PAKET(movie.originalTitle.c_str());
2122 ADDSTRING_TO_PAKET(movie.tagline.c_str());
2123 ADDSTRING_TO_PAKET(movie.overview.c_str());
2124 resp->addUCHAR(movie.adult);
2125 ADDSTRING_TO_PAKET(movie.collectionName.c_str());
2127 resp->addLONG(movie.budget);
2128 resp->addLONG(movie.revenue);
2129 ADDSTRING_TO_PAKET(movie.genres.c_str());
2130 ADDSTRING_TO_PAKET(movie.homepage.c_str());
2131 ADDSTRING_TO_PAKET(movie.releaseDate.c_str());
2132 resp->addLONG(movie.runtime);
2133 resp->adddouble(movie.popularity);
2134 resp->adddouble(movie.voteAverage);
2135 resp->addULONG(movie.poster.width);
2136 resp->addULONG(movie.poster.height);
2137 resp->addULONG(movie.fanart.width);
2138 resp->addULONG(movie.fanart.height);
2139 resp->addULONG(movie.collectionPoster.width);
2140 resp->addULONG(movie.collectionPoster.height);
2141 resp->addULONG(movie.collectionFanart.width);
2142 resp->addULONG(movie.collectionFanart.height);
2143 resp->addULONG(movie.actors.size());
2144 for (ULONG acty=0; acty < movie.actors.size(); acty++) {
2145 ADDSTRING_TO_PAKET(movie.actors[acty].name.c_str());
2146 ADDSTRING_TO_PAKET(movie.actors[acty].role.c_str());
2147 resp->addULONG(movie.actors[acty].actorThumb.width);
2148 resp->addULONG(movie.actors[acty].actorThumb.height);
2152 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2159 int VompClientRRProc::processGetScraperSeriesInfo()
2162 series.seriesId = ntohl(*(ULONG*)req->data);
2163 series.episodeId = ntohl(*(ULONG*)(req->data+4));
2164 if (!x.scrapQuery()) {
2165 log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2166 return 0; //stupid, I have no scraper why are you still asking
2168 x.scraper->Service("GetSeries",&series);
2170 ADDSTRING_TO_PAKET(series.name.c_str());
2171 ADDSTRING_TO_PAKET(series.overview.c_str());
2172 ADDSTRING_TO_PAKET(series.firstAired.c_str());
2173 ADDSTRING_TO_PAKET(series.network.c_str());
2174 ADDSTRING_TO_PAKET(series.genre.c_str());
2175 resp->adddouble(series.rating);
2176 ADDSTRING_TO_PAKET(series.status.c_str());
2178 resp->addLONG(series.episode.number);
2179 resp->addLONG(series.episode.season);
2180 ADDSTRING_TO_PAKET(series.episode.name.c_str());
2181 ADDSTRING_TO_PAKET(series.episode.firstAired.c_str());
2182 ADDSTRING_TO_PAKET(series.episode.guestStars.c_str());
2183 ADDSTRING_TO_PAKET(series.episode.overview.c_str());
2184 resp->adddouble(series.episode.rating);
2185 resp->addULONG(series.episode.episodeImage.width);
2186 resp->addULONG(series.episode.episodeImage.height);
2188 ULONG num_actors = series.actors.size();
2189 resp->addULONG(num_actors);
2190 for (ULONG acty=0; acty < num_actors; acty++) {
2191 ADDSTRING_TO_PAKET(series.actors[acty].name.c_str());
2192 ADDSTRING_TO_PAKET(series.actors[acty].role.c_str());
2193 resp->addULONG(series.actors[acty].actorThumb.width);
2194 resp->addULONG(series.actors[acty].actorThumb.height);
2196 ULONG num_posters = series.posters.size();
2197 resp->addULONG(num_posters);
2198 for (ULONG medias = 0; medias < num_posters; medias++ ) {
2199 cTvMedia media=series.posters[medias];
2200 resp->addULONG(media.width);
2201 resp->addULONG(media.height);
2204 ULONG num_banners = series.banners.size();
2205 resp->addULONG(num_banners);
2206 for (ULONG medias = 0; medias < num_banners; medias++ ) {
2207 cTvMedia media=series.banners[medias];
2208 resp->addULONG(media.width);
2209 resp->addULONG(media.height);
2211 ULONG num_fanarts = series.fanarts.size();
2212 resp->addULONG(num_fanarts);
2213 for (ULONG medias = 0; medias < num_fanarts; medias++ ) {
2214 cTvMedia media=series.fanarts[medias];
2215 resp->addULONG(media.width);
2216 resp->addULONG(media.height);
2218 resp->addULONG(series.seasonPoster.width);
2219 resp->addULONG(series.seasonPoster.height);
2223 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2228 int VompClientRRProc::processLoadTvMedia()
2230 TVMediaRequest tvreq;
2231 tvreq.streamID = req->requestID;
2232 tvreq.type = ntohl(*(ULONG*)req->data);
2233 tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2234 tvreq.secondary_id = ntohl(*(ULONG*)(req->data+8));
2235 tvreq.type_pict = ntohl(*(ULONG*)(req->data+12));
2236 tvreq.container = ntohl(*(ULONG*)(req->data+16));
2237 tvreq.container_member = ntohl(*(ULONG*)(req->data+20));
2238 log->log("RRProc", Log::DEBUG, "TVMedia request %d",req->requestID);
2239 x.pict->addTVMediaRequest(tvreq);
2244 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2249 int VompClientRRProc::processLoadTvMediaRecThumb()
2251 TVMediaRequest tvreq;
2252 tvreq.streamID = req->requestID;
2253 tvreq.type = 3; // unknown but primary_name is set
2254 tvreq.primary_id = 0;
2255 tvreq.primary_name = std::string((const char*) req->data);
2256 tvreq.secondary_id = 0;
2257 tvreq.type_pict = 1;
2258 tvreq.container = 0;
2259 tvreq.container_member = 0;
2260 log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2261 x.pict->addTVMediaRequest(tvreq);
2266 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2271 int VompClientRRProc::processLoadTvMediaEventThumb()
2273 TVMediaRequest tvreq;
2274 tvreq.streamID = req->requestID;
2275 tvreq.type = 4; // unknown but primary_id is set
2276 UINT channelid = ntohl(*(ULONG*)req->data);
2277 tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2278 tvreq.secondary_id = 0;
2279 const cChannel* channel = Channels.GetByNumber(channelNumber);
2281 if (channel) tvreq.primary_name = std::string((const char*)channel->GetChannelID().ToString());
2282 tvreq.type_pict = 1;
2283 tvreq.container = 0;
2284 tvreq.container_member = 0;
2285 log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2286 x.pict->addTVMediaRequest(tvreq);
2291 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2296 int VompClientRRProc::processLoadChannelLogo()
2298 TVMediaRequest tvreq;
2299 tvreq.streamID = req->requestID;
2300 tvreq.type = 5; // channel logo
2301 UINT channelid = ntohl(*(ULONG*)req->data);
2302 tvreq.primary_id = channelid;
2303 tvreq.secondary_id = 0;
2304 const cChannel* channel = Channels.GetByNumber(channelNumber);
2306 if (channel) tvreq.primary_name = std::string((const char*)channel->Name());
2307 tvreq.type_pict = 1;
2308 tvreq.container = 0;
2309 tvreq.container_member = 0;
2310 if (channel) log->log("RRProc", Log::DEBUG, "TVMedia request %d %d %s",req->requestID,channelid, channel->Name());
2311 x.pict->addTVMediaRequest(tvreq);
2316 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2325 #endif // !VOMPSTANDALONE