2 Copyright 2004-2020 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, see <https://www.gnu.org/licenses/>.
26 #include "vdrrequestpacket.h"
27 #include "vdrresponsepacket.h"
29 #ifdef VOMP_MEDIAPLAYER
31 #include "mediaprovider.h"
32 #include "mediaproviderids.h"
34 #include "vdrcommand.h"
37 #include "movieinfo.h"
38 #include "seriesinfo.h"
39 #include "osdvector.h"
41 #include "imageloader.h"
45 static const char* TAG = "VDR";
47 #define VOMP_PROTOCOL_VERSION 0x00000500
49 VDR* VDR::instance = NULL;
50 #ifdef VOMP_MEDIAPLAYER
52 //will create a request package from a command variable and fill this
53 //caller has to destroy buffer
54 static SerializeBuffer * prepareRequest(VDR_Command *cmd) {
55 SerializeBuffer *buf=new SerializeBuffer(512,false,true);
56 if (cmd->serialize(buf) != 0) {
63 //handle request/response
64 //TODO avoid copy of buffer (needs extension of requestpacket)
65 //TODO avoid command 2x (needs some more restructuring)
66 SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {
67 VDR_RequestPacket *rt=new VDR_RequestPacket;
72 if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {
77 if (! rt->copyin(rq->getStart(),(u4)(rq->getCurrent()-rq->getStart()))) {
83 VDR_ResponsePacket *rp=RequestResponse(rt);
84 logger->debug(TAG, "Got response {}", (void*)rp);
89 SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);
94 //deserialize a received response
97 static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {
98 u4 expected=c->command;
99 if (c->deserialize(rp) != 0) {
101 Log::getInstance()->error(TAG, "decodeResponse unable to deserialize for command {}", expected);
105 if (c->command != expected) {
106 Log::getInstance()->error(TAG, "decodeResponse unexpected response received {:#x}, expected {:#x}", c->command, expected);
109 Log::getInstance()->error(TAG, "decodeResponse successfully decoded command {:#x}", expected);
117 if (instance) return;
120 TEMP_SINGLE_VDR_PR = NULL; // FIXME what is this
121 #ifdef VOMP_MEDIAPLAYER
122 providerId=MPROVIDERID_VDR;
123 subRange=MPROVIDERRANGE_VDR;
124 MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);
131 if (initted) shutdown();
134 VDR* VDR::getInstance()
141 if (initted) return 0;
143 logger = LogNT::getInstance();
150 if (!initted) return 0;
156 void VDR::setServerIP(const char* newIP)
158 strcpy(serverIP, newIP);
161 void VDR::setServerPort(USHORT newPort)
163 serverPort = newPort;
169 maxChannelNumber = 0;
170 channelNumberWidth = 1;
172 connectStateMutex.lock();
173 if (connecting || connected) return true;
175 connectStateMutex.unlock(); // now I have connecting
177 bool connectResult = tcp.connect(serverIP, serverPort);
179 connectStateMutex.lock(); // connected = false, connecting = true, babortConnect = ?
184 if (connectResult) tcp.shutdown();
185 babortConnect = false;
186 connectStateMutex.unlock();
194 threadStartProtect.lock();
195 vdrThread = std::thread( [this]
197 threadStartProtect.lock();
198 threadStartProtect.unlock();
201 threadStartProtect.unlock();
203 connectStateMutex.unlock();
208 connectStateMutex.unlock();
213 void VDR::abortConnect() // If there is one, force a running connect call to abort
215 connectStateMutex.lock();
219 babortConnect = true;
223 connectStateMutex.unlock();
226 void VDR::disconnect()
228 std::lock_guard<std::mutex> lg(connectStateMutex);
230 if (!connected) return;
232 if (vdrThread.joinable())
234 threadReqStop = true;
237 threadReqStop = false;
242 disconnecting = false;
244 logger->debug(TAG, "Disconnect");
247 void VDR::setReceiveWindow(size_t size)
249 //if (connected && size) tcpold->setReceiveWindow(size);
252 ///////////////////////////////////////////////////////
254 void VDR::threadMethod()
256 logger->debug(TAG, "VDR RUN");
267 VDR_ResponsePacket* vresp;
271 u4 lastKArecv = time(NULL);
276 readSuccess = tcp.read(&channelID, sizeof(u4));
277 if (threadReqStop) return;
278 timeNow = time(NULL);
282 //logger->debug(TAG, "Net read timeout");
283 if (!tcp.status()) { connectionDied(); return; } // return to stop this thread
286 if (!lastKAsent) // have not sent a KA
288 if (lastKArecv < (timeNow - 5))
290 //logger->debug(TAG, "Sending KA packet");
291 if (!sendKA(timeNow))
293 logger->debug(TAG, "Could not send KA, calling connectionDied");
297 lastKAsent = timeNow;
299 if (threadReqStop) return;
304 if (lastKAsent <= (timeNow - 10))
306 logger->debug(TAG, "lastKA over 10s ago, calling connectionDied");
312 if (!readSuccess) continue; // no data was read but the connection is ok.
316 channelID = ntohl(channelID);
318 if (channelID == CHANNEL_REQUEST_RESPONSE)
320 if (!tcp.read(&requestID, sizeof(u4))) break;
321 if (threadReqStop) return;
322 requestID = ntohl(requestID);
323 if (!tcp.read(&userDataLength, sizeof(u4))) break;
324 if (threadReqStop) return;
325 userDataLength = ntohl(userDataLength);
326 if (userDataLength > 5000000) break; // how big can these packets get?
328 if (userDataLength > 0)
330 userData = malloc(userDataLength);
331 if (!userData) break;
332 if (!tcp.read(userData, userDataLength))
345 vresp = new VDR_ResponsePacket();
346 vresp->setResponse(requestID, reinterpret_cast<UCHAR*>(userData), userDataLength);
347 // vresp now owns userData unless something calls vresp->getUserData()
348 // logger->debug(TAG, "Rxd a response packet, requestID={}, len={}", requestID, userDataLength);
350 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
352 // If edFindAndCall returns true, edr was called and vresp was handed off.
353 // else, delete vresp here.
356 if (threadReqStop) return;
358 else if (channelID == CHANNEL_STREAM || channelID == CHANNEL_TVMEDIA)
360 if (!tcp.read(&streamID, sizeof(u4))) break;
361 if (threadReqStop) return;
362 streamID = ntohl(streamID);
364 if (!tcp.read(&flag, sizeof(u4))) break;
365 if (threadReqStop) return;
368 if (!tcp.read(&userDataLength, sizeof(u4))) break;
369 if (threadReqStop) return;
370 userDataLength = ntohl(userDataLength);
372 if (userDataLength > 0)
374 userData = malloc(userDataLength);
375 if (!userData) break;
376 if (!tcp.read(userData, userDataLength))
389 vresp = new VDR_ResponsePacket();
390 vresp->setStream(streamID, flag, reinterpret_cast<UCHAR*>(userData), userDataLength, channelID);
391 //logger->debug(TAG, "Rxd a stream packet, streamID={}, flag={}, len={}", streamID, flag, userDataLength);
393 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
395 // If edFindAndCall returns true, edr was called and vresp was handed off.
396 // else, delete vresp here.
400 if (threadReqStop) return;
402 else if (channelID == CHANNEL_KEEPALIVE)
405 if (!tcp.read(&KAreply, sizeof(u4))) break;
406 if (threadReqStop) return;
407 KAreply = ntohl(KAreply);
408 if (KAreply == lastKAsent) // successful KA response
411 lastKArecv = KAreply;
412 //logger->debug(TAG, "Rxd correct KA reply");
417 logger->error(TAG, "Rxd a response packet on channel {} !!", channelID);
421 // Who deletes vresp?
422 // If RR, the individual protocol functions must delete vresp.
423 // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
429 void VDR::connectionDied()
431 // Called from within threadMethod to do cleanup if it decides the connection has died
433 disconnecting = true;
435 // Need to wake up any waiting channel 1 request-response threads
436 // Normally this is done by a packet coming in with channelid and requestid
437 // Instead, go through the list and for each channel 1 edr, make an empty vresp
438 // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
440 // If it's a stream receiver, generate a stream packet with flag == connection_lost
443 VDR_PacketReceiver* vdrpr;
444 VDR_ResponsePacket* vresp;
445 while(receivers.size())
447 vdrpr = dynamic_cast<VDR_PacketReceiver*>(*(receivers.begin()));
448 if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
450 vresp = new VDR_ResponsePacket();
451 vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
452 logger->debug(TAG, "Timeouts: created blank response packet for request serial {}", vdrpr->requestSerialNumber);
454 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
456 // If edFindAndCall returns true, edr was called and vresp was handed off.
457 // else, delete vresp here.
458 logger->error(TAG, "Timeouts: no waiting thread found for request serial {} !!!", vdrpr->requestSerialNumber);
463 else if (vdrpr->receiverChannel == CHANNEL_STREAM || vdrpr->receiverChannel == CHANNEL_TVMEDIA)
465 vresp = new VDR_ResponsePacket();
466 vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0, vdrpr->receiverChannel);
467 logger->debug(TAG, "Timeouts: created blank response packet for streamid {}", vdrpr->streamID);
469 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
471 // If edFindAndCall returns true, edr was called and vresp was handed off.
472 // else, delete vresp here.
473 logger->error(TAG, "Timeouts: no waiting stream receiver found for streamid {} !!!", vdrpr->streamID);
478 for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
479 if (dynamic_cast<VDR_PacketReceiver*>(*i) == vdrpr) { receivers.erase(i); break; }
483 // Ok, all event receviers should be dealt with. just in case there weren't any, inform control
484 logger->debug(TAG, "edUnlock at end of connectionDied");
486 Control::getInstance()->connectionLost();
489 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
491 // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
492 // userTag is a VDR_ResponsePacket made in threadMethod
494 VDR_PacketReceiver* vdrpr = dynamic_cast<VDR_PacketReceiver*>(edr);
495 VDR_ResponsePacket* vresp = reinterpret_cast<VDR_ResponsePacket*>(userTag);
497 // Is vresp for vdrpr ?
499 u4 packetChannel = vresp->getChannelID();
500 //logger->debug(TAG, "Image debug {} {} {:#x}", vdrpr->receiverChannel,packetChannel,vdrpr);
501 if (vdrpr->receiverChannel != packetChannel) return false;
503 if (packetChannel == CHANNEL_REQUEST_RESPONSE)
505 if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
507 else if (packetChannel == CHANNEL_STREAM)
509 if (vdrpr->streamID == vresp->getStreamID()) return true;
511 else if (packetChannel == CHANNEL_TVMEDIA)
513 if (vdrpr->streamID == vresp->getStreamID()) return true;
519 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
521 //logger->debug(TAG, "RR {}", vrp->getOpcode());
523 if (!connected || disconnecting)
525 logger->debug(TAG, "RR when !connected || disconnecting");
526 VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
527 return vresp; // "no-response" return
530 // ED make new VDR and register
531 // make a VDR_PacketReceiver
532 // - init with serial number of request packet
534 VDR_PacketReceiver vdrpr;
535 // vdrpr.requestTime = time(NULL);
536 vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
537 vdrpr.requestSerialNumber = vrp->getSerial();
544 if (!tcp.write(vrp->getPtr(), vrp->getLen()))
547 edUnregister(&vdrpr);
548 VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
549 return vresp; // "no-response" return
552 // Sleep and block this thread. The sleep unlocks the mutex
553 // logger->debug(TAG, "RR sleep - opcode {}", vrp->getOpcode());
554 edSleepThisReceiver(&vdrpr);
555 // logger->debug(TAG, "RR unsleep");
557 // Woken because a response packet has arrived, mutex will be locked
558 // logger->debug(TAG, "Packet delivered to me, requestID: {}", vdrpr.save_vresp->getRequestID());
561 return vdrpr.save_vresp;
564 bool VDR::sendKA(u4 timeStamp)
569 u4 ul=CHANNEL_KEEPALIVE;
570 buffer[pos++]=(ul>>24)&0xff;
571 buffer[pos++]=(ul>>16)&0xff;
572 buffer[pos++]=(ul>>8)&0xff;
573 buffer[pos++]=ul &0xff;
575 buffer[pos++]=(ul>>24)&0xff;
576 buffer[pos++]=(ul>>16)&0xff;
577 buffer[pos++]=(ul>>8)&0xff;
578 buffer[pos++]=ul &0xff;
579 return tcp.write(buffer, 8);
582 /////////////////////////////////////////////////////////////////////////////
584 // Here VDR takes a break for the VDR_PacketReceiver helper class
586 void VDR_PacketReceiver::call(void* userTag, bool& r_deregisterEDR, bool& r_wakeThread, bool& r_deleteEDR)
588 if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
590 // It's a RR. Save vresp and, signal the waiting thread and return.
591 // VDR::RequestResponse will be blocking waiting for this to happen.
592 // That function has a pointer to this object and can read save_vresp.
593 save_vresp = reinterpret_cast<VDR_ResponsePacket*>(userTag);
595 r_deregisterEDR = true;
599 else if (receiverChannel == VDR::CHANNEL_STREAM)
601 // It's a stream packet. Pass off the stream data to streamReceiver,
602 // delete the vresp. Keep this PacketReceiver for the next stream packet.
603 VDR_ResponsePacket* vresp = reinterpret_cast<VDR_ResponsePacket*>(userTag);
604 streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
607 r_deregisterEDR = false;
608 r_wakeThread = false;
611 else if (receiverChannel == VDR::CHANNEL_TVMEDIA)
614 // Pass off the vresp object to OSDVector
615 // This used to return true which would signal the cond (wake the thread)
616 // but am going to try setting this to false because I don't know that there is a thread to signal
617 // delete the EDR. It's made once per media requested and wasn't owned/deleted by anything before
619 VDR_ResponsePacket* vresp = reinterpret_cast<VDR_ResponsePacket*>(userTag);
620 LogNT::getInstance()->debug(TAG, "Image Pictures arrived VDR {:#x}", vresp->getStreamID());
621 ImageLoader::getInstance()->downloadDone(vresp);
622 //OsdVector *osd=dynamic_cast<OsdVector*>(Osd::getInstance());
623 //if (osd) osd->getPictReader()->receivePicture(vresp);
624 // else delete vresp; //nonsense // only rpi does CHANNEL_TVMEDIA, rpi has osdvector. therefore, can't get here.
626 r_deregisterEDR = true;
627 r_wakeThread = false;
630 else abort(); // unknown receiverChannel, should not happen
633 /////////////////////////////////////////////////////////////////////////////
635 bool VDR::doLogin(unsigned int* v_server_min, unsigned int* v_server_max, unsigned int* v_client,
636 ASLPrefList& list, int &subtitles)
638 VDR_RequestPacket vrp;
639 if (!vrp.init(VDR_LOGIN, true, 6)) return false;
641 MACAddress myMAC = tcp.getMAC();
642 if (!vrp.copyin(reinterpret_cast<UCHAR*>(&myMAC), 6)) return false;
644 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
645 if (vresp->noResponse()) { delete vresp; return false; }
647 u4 vdrTime = vresp->extractu4();
648 logger->debug(TAG, "vdrtime = {}", vdrTime);
649 long vdrTimeOffset = vresp->extractLONG();
650 logger->debug(TAG, "offset = {}", vdrTimeOffset);
652 unsigned int version_min=vresp->extractu4();
654 *v_server_min=version_min;
655 unsigned int version_max=vresp->extractu4();
656 *v_server_max=version_max;
657 *v_client=VOMP_PROTOCOL_VERSION;
659 if (0x00000302 <= version_max) {
660 unsigned int numlangcodes = vresp->extractu4();
661 subtitles = vresp->extractu4();
663 for (unsigned int i=0; i<numlangcodes; i++) {
665 newpref.audiopref = vresp->extractLONG();
666 newpref.subtitlepref = vresp->extractLONG();
667 newpref.langcode = vresp->extractStdString();
668 //logger->debug(TAG, "Langpref {} {} {} {}", subtitles, newpref.langcode, newpref.audiopref, newpref.subtitlepref);
669 list.push_back(newpref);
676 if ((version_min > VOMP_PROTOCOL_VERSION)
677 || (version_max < VOMP_PROTOCOL_VERSION) ) {
683 // Set the time and zone on the MVP only
685 #if !defined(WIN32) && !defined(__ANDROID__)
686 struct timespec currentTime;
687 currentTime.tv_sec = vdrTime;
688 currentTime.tv_nsec = 0;
690 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
692 logger->debug(TAG, "set clock = {}", b);
694 // now make a TZ variable and set it
698 if (vdrTimeOffset > 0) sign = '-';
701 vdrTimeOffset = abs(vdrTimeOffset);
703 hours = (int)vdrTimeOffset / 3600;
704 minutes = vdrTimeOffset % 3600;
706 logger->debug(TAG, "{} {} {}", sign, hours, minutes);
708 minutes = (int)minutes / 60;
710 logger->debug(TAG, "{} {} {}", sign, hours, minutes);
713 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
714 setenv("TZ", newTZ, 1);
716 logger->debug(TAG, "Timezone data: {}", newTZ);
719 setCharset(Osd::getInstance()->charSet());
724 bool VDR::LogExtern(const char* logString)
726 if (!connected || disconnecting) return false;
727 int stringLength = strlen(logString);
728 int packetLength = stringLength + 8;
729 char *buffer=new char[packetLength + 1];
731 u4 ul=CHANNEL_NETLOG;
732 buffer[pos++]=(ul>>24)&0xff;
733 buffer[pos++]=(ul>>16)&0xff;
734 buffer[pos++]=(ul>>8)&0xff;
735 buffer[pos++]=ul &0xff;
737 buffer[pos++]=(ul>>24)&0xff;
738 buffer[pos++]=(ul>>16)&0xff;
739 buffer[pos++]=(ul>>8)&0xff;
740 buffer[pos++]=ul &0xff;
742 strcpy(&buffer[8], logString);
744 if (!tcp.write(buffer, packetLength))
747 disconnecting = true; // stop the rest of the connection
748 Control::getInstance()->connectionLost();
755 bool VDR::setCharset(int charset)
757 VDR_RequestPacket vrp;
758 if (!vrp.init(VDR_SETCHARSET, true, sizeof(u4))) return false;
759 if (!vrp.addu4(charset)) return false;
761 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
762 if (vresp->noResponse()) { delete vresp; return false; }
764 u4 success = vresp->extractu4();
767 if (!success) return false;
772 bool VDR::getRecordingsList(RecMan* recman)
774 VDR_RequestPacket vrp;
775 if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
777 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
778 if (vresp->noResponse()) { delete vresp; return false; }
780 u4 totalSpace = vresp->extractu4();
781 u4 freeSpace = vresp->extractu4();
782 u4 percent = vresp->extractu4();
784 recman->setStats(totalSpace, freeSpace, percent);
791 while (!vresp->end())
793 start = vresp->extractu4();
794 isNew = vresp->extractUCHAR();
795 name = vresp->extractString();
796 fileName = vresp->extractString();
797 recman->addEntry(isNew, start, name, fileName);
806 int VDR::deleteRecording(char* fileName)
808 VDR_RequestPacket vrp;
809 if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
810 if (!vrp.addString(fileName)) return 0;
812 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
813 if (vresp->noResponse()) { delete vresp; return 0; }
815 int toReturn = toi4(vresp->extractu4());
821 int VDR::deleteRecResume(char* fileName)
823 VDR_RequestPacket vrp;
824 if (!vrp.init(VDR_DELETERECRESUME, true, strlen(fileName) + 1)) return 0;
825 if (!vrp.addString(fileName)) return 0;
827 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
828 if (vresp->noResponse()) { delete vresp; return 0; }
830 int toReturn = toi4(vresp->extractu4());
836 char* VDR::moveRecording(char* fileName, char* newPath)
838 VDR_RequestPacket vrp;
839 if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
840 if (!vrp.addString(fileName)) return NULL;
841 if (!vrp.addString(newPath)) return NULL;
843 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
844 if (vresp->noResponse()) { delete vresp; return NULL; }
846 char* toReturn = NULL;
847 int success = toi4(vresp->extractu4());
850 toReturn = vresp->extractString();
858 std::shared_ptr<ChannelList> VDR::getChannelsList(u4 type)
860 VDR_RequestPacket vrp;
861 if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
863 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
864 if (vresp->noResponse()) { delete vresp; return NULL; }
866 // shared_ptr for a ChannelList (std::vector<Channel*>) with custom deleter to delete all the Channel* objects
867 std::shared_ptr<ChannelList> chanList(new ChannelList(),
868 [] (ChannelList* cl) { for (Channel* p : *cl) delete p; });
870 bool h264support=Video::getInstance()->supportsh264();
871 bool mpeg2support=Video::getInstance()->supportsmpeg2();
873 while (!vresp->end())
875 Channel* chan = new Channel();
876 chan->number = vresp->extractu4();
877 chan->type = vresp->extractu4();
878 chan->name = vresp->extractString();
879 chan->vstreamtype = static_cast<UCHAR>(vresp->extractu4());
881 if (chan->type == type && ((chan->vstreamtype==0x1b && h264support)|| (chan->vstreamtype!=0x1b &&mpeg2support)) )
883 chanList->push_back(chan);
884 logger->debug(TAG, "Have added a channel to list. {} {} {}", chan->number, chan->type, chan->name);
885 if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
895 if (maxChannelNumber > 99999)
896 channelNumberWidth = 6;
897 else if (maxChannelNumber > 9999)
898 channelNumberWidth = 5;
899 else if (maxChannelNumber > 999)
900 channelNumberWidth = 4;
901 else if (maxChannelNumber > 99)
902 channelNumberWidth = 3;
903 else if (maxChannelNumber > 9)
904 channelNumberWidth = 2;
906 channelNumberWidth = 1;
911 int VDR::streamChannel(u4 number, StreamReceiver* tstreamReceiver)
913 VDR_RequestPacket vrp;
914 if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(u4))) return 0;
915 if (!vrp.addu4(number)) return 0;
918 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
919 vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
920 vdrpr->streamID = vrp.getSerial();
921 vdrpr->streamReceiver = tstreamReceiver;
923 TEMP_SINGLE_VDR_PR = vdrpr;
925 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
926 if (vresp->noResponse())
934 int toReturn = toi4(vresp->extractu4());
935 logger->debug(TAG, "VDR said {} to start streaming request", toReturn);
941 int VDR::stopStreaming()
943 VDR_RequestPacket vrp;
944 if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
946 if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
947 // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
949 edUnregister(TEMP_SINGLE_VDR_PR);
950 delete TEMP_SINGLE_VDR_PR;
951 TEMP_SINGLE_VDR_PR = NULL;
954 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
955 if (vresp->noResponse()) { delete vresp; return 0; }
957 int toReturn = toi4(vresp->extractu4());
963 UCHAR* VDR::getBlock(u8 position, u4 maxAmount, u4* amountReceived)
965 VDR_RequestPacket vrp;
966 if (!vrp.init(VDR_GETBLOCK, true, sizeof(u8) + sizeof(u4))) return NULL;
967 if (!vrp.addu8(position)) return NULL;
968 if (!vrp.addu4(maxAmount)) return NULL;
970 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
971 if (vresp->noResponse()) { delete vresp; return NULL; }
973 if (vresp->serverError())
975 logger->debug(TAG, "Detected getblock 0");
981 // Special handling for getblock
982 UCHAR* toReturn = vresp->getUserData();
983 *amountReceived = vresp->getUserDataLength();
990 u8 VDR::streamRecording(char* fileName, u4* totalFrames, bool* IsPesRecording)
992 VDR_RequestPacket vrp;
993 if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
994 if (!vrp.addString(fileName)) return 0;
996 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
997 if (vresp->noResponse()) { delete vresp; return 0; }
999 u8 lengthBytes = vresp->extractu8();
1000 u4 lengthFrames = vresp->extractu4();
1001 UCHAR isPesRecording = vresp->extractUCHAR();
1004 *totalFrames = lengthFrames;
1005 *IsPesRecording = (isPesRecording);//convert Uchar to bool
1007 logger->debug(TAG, "VDR said length is: {} {}, IsPesRecording {:#x}", lengthBytes, lengthFrames, *IsPesRecording);
1012 u8 VDR::positionFromFrameNumber(u4 frameNumber)
1014 VDR_RequestPacket vrp;
1015 if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(u4))) return 0;
1016 if (!vrp.addu4(frameNumber)) return 0;
1018 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1019 if (vresp->noResponse()) { delete vresp; return 0; }
1021 u8 position = vresp->extractu8();
1024 logger->debug(TAG, "VDR said new position is: {}", position);
1029 u4 VDR::frameNumberFromPosition(u8 position)
1031 VDR_RequestPacket vrp;
1032 if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(u8))) return 0;
1033 if (!vrp.addu8(position)) return 0;
1035 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1036 if (vresp->noResponse()) { delete vresp; return 0; }
1038 u4 framenumber = vresp->extractu4();
1041 logger->debug(TAG, "VDR said new framenumber is: {}", framenumber);
1046 bool VDR::getNextIFrame(u4 frameNumber, u4 direction, u8* rfilePosition, u4* rframeNumber, u4* rframeLength)
1048 VDR_RequestPacket vrp;
1049 if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(u4)*2)) return false;
1050 if (!vrp.addu4(frameNumber)) return false;
1051 if (!vrp.addu4(direction)) return false;
1053 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1054 if (vresp->noResponse()) { delete vresp; return false; }
1056 if (vresp->serverError())
1058 logger->debug(TAG, "Detected getNextIFrame error");
1063 *rfilePosition = vresp->extractu8();
1064 *rframeNumber = vresp->extractu4();
1065 *rframeLength = vresp->extractu4();
1069 logger->debug(TAG, "VDR GNIF said {} {} {}", *rfilePosition, *rframeNumber, *rframeLength);
1074 EventList* VDR::getChannelSchedule(u4 number)
1078 return getChannelSchedule(number, now, 24 * 60 * 60);
1081 EventList* VDR::getChannelSchedule(u4 number, time_t start, u4 duration)
1083 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
1085 VDR_RequestPacket vrp;
1086 if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(u4)*3)) return NULL;
1087 if (!vrp.addu4(number)) return NULL;
1088 if (!vrp.addu4(start)) return NULL;
1089 if (!vrp.addu4(duration)) return NULL;
1091 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1092 if (vresp->noResponse()) { delete vresp; return NULL; }
1094 // received a ulong(0) - schedules error in the plugin
1095 if (vresp->serverError())
1101 EventList* eventList = new EventList();
1103 while (!vresp->end())
1105 Event* event = new Event();
1106 event->id = vresp->extractu4();
1107 event->time = vresp->extractu4();
1108 event->duration = vresp->extractu4();
1109 event->title = vresp->extractString();
1110 event->subtitle = vresp->extractString();
1111 event->description = vresp->extractString();
1112 eventList->push_back(event);
1117 logger->debug(TAG, "Success got to end of getChannelSchedule");
1121 int VDR::configSave(const char* section, const char* key, const char* value)
1123 VDR_RequestPacket vrp;
1124 if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
1125 if (!vrp.addString(section)) return 0;
1126 if (!vrp.addString(key)) return 0;
1127 if (!vrp.addString(value)) return 0;
1129 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1130 if (vresp->noResponse()) { delete vresp; return 0; }
1132 int toReturn = toi4(vresp->extractu4());
1138 char* VDR::configLoad(const char* section, const char* key)
1140 VDR_RequestPacket vrp;
1141 if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
1142 if (!vrp.addString(section)) return NULL;
1143 if (!vrp.addString(key)) return NULL;
1145 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1146 if (vresp->noResponse()) { delete vresp; return NULL; }
1148 char* toReturn = vresp->extractString();
1154 RecTimerList* VDR::getRecTimersList()
1156 VDR_RequestPacket vrp;
1157 if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
1159 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1160 if (vresp->noResponse()) { delete vresp; return NULL; }
1162 RecTimerList* recTimerList = new RecTimerList();
1164 u4 numTimers = vresp->extractu4();
1167 RecTimer* newRecTimer;
1170 while (!vresp->end())
1172 newRecTimer = new RecTimer();
1173 newRecTimer->active = vresp->extractu4();
1174 newRecTimer->recording = vresp->extractu4();
1175 newRecTimer->pending = vresp->extractu4();
1176 newRecTimer->priority = vresp->extractu4();
1177 newRecTimer->lifeTime = vresp->extractu4();
1178 newRecTimer->channelNumber = vresp->extractu4();
1179 newRecTimer->startTime = vresp->extractu4();
1180 newRecTimer->stopTime = vresp->extractu4();
1181 newRecTimer->day = vresp->extractu4();
1182 newRecTimer->weekDays = vresp->extractu4();
1184 tempString = vresp->extractString();
1185 newRecTimer->setFile(tempString);
1186 delete[] tempString;
1188 recTimerList->push_back(newRecTimer);
1189 logger->debug(TAG, "TL: {} {} {} {} {} {} {} {} {}",
1190 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1191 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1197 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1199 return recTimerList;
1202 u4 VDR::setEventTimer(char* timerString)
1204 VDR_RequestPacket vrp;
1205 if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
1206 if (!vrp.addString(timerString)) return 0;
1208 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1209 if (vresp->noResponse()) { delete vresp; return 0; }
1211 u4 toReturn = vresp->extractu4();
1217 RecInfo* VDR::getRecInfo(char* fileName)
1219 VDR_RequestPacket vrp;
1220 if (!vrp.init(VDR_GETRECINFO2, true, strlen(fileName) + 1)) return NULL;
1221 if (!vrp.addString(fileName)) return NULL;
1222 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1224 if (vresp->noResponse()) { delete vresp; return NULL; }
1226 if (vresp->serverError())
1228 logger->debug(TAG, "Could not get rec info");
1233 RecInfo* recInfo = new RecInfo();
1235 recInfo->timerStart = vresp->extractu4();
1236 recInfo->timerEnd = vresp->extractu4();
1237 recInfo->resumePoint = vresp->extractu4();
1238 recInfo->summary = vresp->extractString();
1240 u4 numComponents = vresp->extractu4();
1243 recInfo->setNumComponents(numComponents);
1244 for (u4 i = 0; i < numComponents; i++)
1246 recInfo->streams[i] = vresp->extractUCHAR();
1247 recInfo->types[i] = vresp->extractUCHAR();
1248 recInfo->languages[i] = vresp->extractString();
1249 recInfo->descriptions[i] = vresp->extractString();
1252 recInfo->fps=vresp->extractdouble();
1253 recInfo->title=vresp->extractString();
1256 recInfo->channelName = vresp->extractString();
1257 recInfo->duration = vresp->extractu4();
1258 recInfo->fileSize = vresp->extractu4();
1259 recInfo->priority = vresp->extractu4();
1260 recInfo->lifetime = vresp->extractu4();
1269 u8 VDR::rescanRecording(u4* totalFrames)
1271 VDR_RequestPacket vrp;
1272 if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
1274 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1275 if (vresp->noResponse()) { delete vresp; return 0; }
1277 u8 lengthBytes = vresp->extractu8();
1278 u4 lengthFrames = vresp->extractu4();
1281 logger->debug(TAG, "VDR said length is: {} {}", lengthBytes, lengthFrames);
1283 *totalFrames = lengthFrames;
1287 MarkList* VDR::getMarks(char* fileName)
1289 VDR_RequestPacket vrp;
1290 if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
1291 if (!vrp.addString(fileName)) return NULL;
1293 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1294 if (vresp->noResponse()) { delete vresp; return NULL; }
1296 if (vresp->serverError())
1302 MarkList* markList = new MarkList();
1304 while (!vresp->end())
1306 Mark* mark = new Mark();
1307 mark->pos = vresp->extractu4();
1309 markList->push_back(mark);
1310 logger->debug(TAG, "Have added a mark to list. {}", mark->pos);
1318 void VDR::getChannelPids(Channel* channel)
1320 VDR_RequestPacket vrp;
1321 if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(u4))) return ;
1322 if (!vrp.addu4(channel->number)) return ;
1324 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1325 if (vresp->noResponse()) { delete vresp; return ; }
1327 // Format of response
1335 channel->vpid = vresp->extractu4();
1336 channel->vstreamtype = static_cast<UCHAR>(vresp->extractu4());
1337 channel->numAPids = vresp->extractu4();
1339 for (u4 i = 0; i < channel->numAPids; i++)
1342 newapid.pid = vresp->extractu4();
1343 char * name=vresp->extractString();
1344 strncpy(newapid.desc,name,9);
1346 channel->apids.push_back(newapid);
1349 channel->numDPids = vresp->extractu4();
1351 for (u4 i = 0; i < channel->numDPids; i++)
1354 newdpid.pid = vresp->extractu4();
1355 char * name=vresp->extractString();
1356 strncpy(newdpid.desc,name,9);
1358 channel->dpids.push_back(newdpid);
1361 channel->numSPids = vresp->extractu4();
1363 for (u4 i = 0; i < channel->numSPids; i++)
1366 newspid.pid = vresp->extractu4();
1367 char * name=vresp->extractString();
1368 strncpy(newspid.desc,name,9);
1370 channel->spids.push_back(newspid);
1372 channel->tpid = vresp->extractu4();
1374 for (u4 i = 0; i < channel->numAPids; i++)
1376 channel->apids[i].type = vresp->extractu4();
1378 for (u4 i = 0; i < channel->numDPids; i++)
1380 channel->dpids[i].type = vresp->extractu4();
1382 for (u4 i = 0; i < channel->numSPids; i++)
1384 channel->spids[i].type = vresp->extractu4();
1385 channel->spids[i].data1 = vresp->extractu4();
1386 channel->spids[i].data2 = vresp->extractu4();
1394 #ifdef VOMP_MEDIAPLAYER
1395 MediaList * VDR::getRootList() {
1396 return getMediaList(NULL);
1399 * media List Request:
1401 * Media List response:
1404 MediaList* VDR::getMediaList(const MediaURI * root)
1406 logger->debug(TAG, "getMediaList {},d={}, prov={}", (root?root->getName():"NULL"),
1407 ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),
1408 (root?root->getProvider():providerId));
1409 MediaURI remoteURI(root);
1410 VDR_GetMediaListRequest request(&remoteURI);
1411 SerializeBuffer *vrp=prepareRequest(&request);
1413 logger->log("VDR", Log::ERR, "getMediaList unable to create command");
1417 SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1419 Control::getInstance()->connectionLost();
1423 MediaList *rt=new MediaList(NULL);
1425 VDR_GetMediaListResponse resp(&rtflags,rt);
1426 if (decodeResponse(vresp,&resp) != 0) {
1433 * get image Request:
1435 * get media response:
1439 int VDR::openMedium(u4 channel,const MediaURI *uri, u8 * size, u4 x, u4 y)
1441 MediaURI remoteURI(uri);
1442 VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);
1444 SerializeBuffer *vrp=prepareRequest(&request);
1446 logger->log("VDR", Log::ERR, "openMedium unable to create command");
1449 SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1451 Control::getInstance()->connectionLost();
1455 VDR_OpenMediumResponse response(&flags,size);
1456 if (decodeResponse(vresp,&response) != 0) {
1459 logger->debug(TAG, "openMedia len={}", *size);
1464 * getMediaBlock - no separate response class - simple data block
1468 int VDR::getMediaBlock(u4 channel, u8 position, u4 maxAmount, u4* amountReceived, unsigned char **buffer)
1471 VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);
1472 SerializeBuffer *vrp=prepareRequest(&request);
1474 logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");
1477 SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1479 Control::getInstance()->connectionLost();
1483 // Special handling for getblock
1484 *amountReceived = (u4)(vresp->getEnd()-vresp->getStart());
1485 *buffer = vresp->steelBuffer();
1498 int VDR::getMediaInfo(u4 channel, MediaInfo * result) {
1499 if (! result) return -1;
1500 VDR_GetMediaInfoRequest request(&channel);
1501 SerializeBuffer *vrp=prepareRequest(&request);
1503 logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");
1506 SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1508 Control::getInstance()->connectionLost();
1513 VDR_GetMediaInfoResponse response(&flags,result);
1514 if (decodeResponse(vresp,&response) != 0) {
1527 int VDR::closeMediaChannel(u4 channel) {
1528 VDR_CloseMediaChannelRequest request(&channel);
1529 SerializeBuffer *vrp=prepareRequest(&request);
1531 logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");
1534 SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1536 Control::getInstance()->connectionLost();
1540 VDR_CloseMediaChannelResponse response(&flags);
1541 if (decodeResponse(vresp,&response) != 0) return -1;
1542 return (flags != 0)?-1:0;
1548 int VDR::deleteTimer(RecTimer* delTimer)
1550 logger->debug(TAG, "Delete timer called");
1552 VDR_RequestPacket vrp;
1553 if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
1554 if (!vrp.addu4(delTimer->channelNumber)) return 0;
1555 if (!vrp.addu4(delTimer->weekDays)) return 0;
1556 if (!vrp.addu4(delTimer->day)) return 0;
1557 if (!vrp.addu4(delTimer->startTime)) return 0;
1558 if (!vrp.addu4(delTimer->stopTime)) return 0;
1560 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1561 if (vresp->noResponse()) { delete vresp; return 0; }
1563 int toReturn = toi4(vresp->extractu4());
1569 I18n::lang_code_list VDR::getLanguageList()
1571 I18n::lang_code_list CodeList;
1572 CodeList["en"] = "English"; // Default entry
1573 VDR_RequestPacket vrp;
1574 if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
1575 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1576 if (vresp->noResponse() || vresp->end())
1582 while (!vresp->end())
1584 char* c_code = vresp->extractString();
1585 char* c_name = vresp->extractString();
1586 std::string code = c_code;
1587 std::string name = c_name;
1588 CodeList[code] = name;
1596 int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
1598 VDR_RequestPacket vrp;
1599 if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
1600 if (!vrp.addString(code.c_str())) return 0;
1601 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1602 if (vresp->noResponse()) { delete vresp; return 0; }
1604 while (!vresp->end())
1606 char* c_key = vresp->extractString();
1607 char* c_text = vresp->extractString();
1608 std::string key = c_key;
1609 std::string text = c_text;
1618 void VDR::shutdownVDR()
1621 logger->debug(TAG, "Shutting down vdr");
1623 logger->debug(TAG, "Shutting down vomp only");
1625 if(!doVDRShutdown || !connected || disconnecting)
1628 VDR_RequestPacket vrp;
1629 logger->debug(TAG, "Sending shutdown");
1630 if (!vrp.init(VDR_SHUTDOWN, false, 0)) return;
1631 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1634 logger->debug(TAG, "VDR shutdown");
1637 void VDR::getScraperEventType(char * fileName, int & movieID,
1638 int & seriesID, int & episodeID)
1643 VDR_RequestPacket vrp;
1644 if (!vrp.init(VDR_GETRECSCRAPEREVENTTYPE, true, strlen(fileName) + 1)) return;
1645 if (!vrp.addString(fileName)) return ;
1646 logger->debug(TAG, "Before response");
1647 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1648 logger->debug(TAG, "After response");
1649 if (vresp->noResponse()) { delete vresp; return ; }
1650 int type = vresp->extractUCHAR();
1651 if (type == 0) //serie
1653 seriesID = vresp->extractLONG();
1654 episodeID = vresp->extractLONG();
1655 } else if (type == 1) //movie
1657 movieID = vresp->extractLONG();
1663 void VDR::getScraperEventType(u4 channelid, u4 eventid, int & movieID,
1664 int & seriesID, int & episodeID, int & epgImage )
1670 VDR_RequestPacket vrp;
1671 if (!vrp.init(VDR_GETEVENTSCRAPEREVENTTYPE, false, 0)) return;
1672 if (!vrp.addu4(channelid)) return ;
1673 if (!vrp.addu4(eventid)) return ;
1674 logger->debug(TAG, "Before response");
1675 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1676 logger->debug(TAG, "After response");
1677 if (vresp->noResponse()) { delete vresp; return ; }
1678 int type = vresp->extractUCHAR();
1679 if (type == 0) //serie
1681 seriesID = vresp->extractLONG();
1682 episodeID = vresp->extractLONG();
1683 } else if (type == 1) //movie
1685 movieID = vresp->extractLONG();
1687 epgImage = vresp->extractLONG();
1692 MovieInfo *VDR::getScraperMovieInfo(int movieID)
1694 ImageLoader* imageLoader = ImageLoader::getInstance();
1696 VDR_RequestPacket vrp;
1697 if (!vrp.init(VDR_GETSCRAPERMOVIEINFO, false, 0)) return NULL;
1698 if (!vrp.addu4(movieID)) return NULL;
1699 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1700 if (vresp->noResponse()) { delete vresp; return NULL; }
1701 MovieInfo* movieinf = new MovieInfo;
1703 ImageGeneric imageGeneric1 = imageLoader->createGeneric();
1704 movieinf->poster.image = imageGeneric1;
1706 ImageGeneric imageGeneric2 = imageLoader->createGeneric();
1707 movieinf->fanart.image = imageGeneric2;
1709 ImageGeneric imageGeneric3 = imageLoader->createGeneric();
1710 movieinf->collectionPoster.image = imageGeneric3;
1712 ImageGeneric imageGeneric4 = imageLoader->createGeneric();
1713 movieinf->collectionFanart.image = imageGeneric4;
1715 movieinf->id=movieID;
1716 movieinf->title = vresp->extractStdString();
1717 movieinf->originalTitle = vresp->extractStdString();
1718 movieinf->tagline = vresp->extractStdString();
1719 movieinf->overview = vresp->extractStdString();
1720 movieinf->adult = vresp->extractUCHAR();
1721 movieinf->collectionName = vresp->extractStdString();
1723 movieinf->budget = vresp->extractLONG();
1724 movieinf->revenue = vresp->extractLONG();
1725 movieinf->genres = vresp->extractStdString();
1726 movieinf->homepage = vresp->extractStdString();
1727 movieinf->releaseDate = vresp->extractStdString();
1728 movieinf->runtime = vresp->extractLONG();
1729 movieinf->popularity = vresp->extractdouble();
1730 movieinf->voteAverage = vresp->extractdouble();
1731 movieinf->poster.width = vresp->extractu4();
1732 movieinf->poster.height = vresp->extractu4();
1733 imageGeneric1->setMovieInfo(movieinf);
1734 imageGeneric1->setElement(0,0);
1735 movieinf->fanart.width = vresp->extractu4();
1736 movieinf->fanart.height = vresp->extractu4();
1737 imageGeneric2->setMovieInfo(movieinf);
1738 imageGeneric2->setElement(1,0);
1739 movieinf->collectionPoster.width = vresp->extractu4();
1740 movieinf->collectionPoster.height = vresp->extractu4();
1741 imageGeneric3->setMovieInfo(movieinf);
1742 imageGeneric3->setElement(2,0);
1743 movieinf->collectionFanart.width = vresp->extractu4();
1744 movieinf->collectionFanart.height = vresp->extractu4();
1745 imageGeneric4->setMovieInfo(movieinf);
1746 imageGeneric4->setElement(3,0);
1747 u4 num_actors = vresp->extractu4();
1748 movieinf->actors.clear();
1749 movieinf->actors.reserve(num_actors);
1750 for (u4 acty=0; acty < num_actors; acty++)
1753 ImageGeneric newActImageGeneric = imageLoader->createGeneric();
1754 new_act.thumb.image = newActImageGeneric;
1756 new_act.name = vresp->extractStdString();
1757 new_act.role = vresp->extractStdString();
1758 new_act.thumb.width = vresp->extractu4();
1759 new_act.thumb.height = vresp->extractu4();
1760 newActImageGeneric->setMovieInfo(movieinf);
1761 newActImageGeneric->setElement(4,acty);
1762 movieinf->actors.push_back(new_act);
1763 imageLoader->ensureLoaded(newActImageGeneric);
1766 imageLoader->ensureLoaded(imageGeneric1);
1767 imageLoader->ensureLoaded(imageGeneric2);
1768 imageLoader->ensureLoaded(imageGeneric3);
1769 imageLoader->ensureLoaded(imageGeneric4);
1775 SeriesInfo* VDR::getScraperSeriesInfo(int seriesID, int episodeID)
1777 ImageLoader* imageLoader = ImageLoader::getInstance();
1779 VDR_RequestPacket vrp;
1780 if (!vrp.init(VDR_GETSCRAPERSERIESINFO, false, 0)) return NULL;
1781 if (!vrp.addu4(seriesID)) return NULL;
1782 if (!vrp.addu4(episodeID)) return NULL;
1784 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1785 if (vresp->noResponse()) { delete vresp; return 0; }
1786 SeriesInfo* seriesinf = new SeriesInfo();
1788 ImageGeneric imageGeneric1 = imageLoader->createGeneric();
1789 Image imageBase1 = imageGeneric1;
1790 seriesinf->episode.image.image = imageBase1;
1792 ImageGeneric imageGeneric2 = imageLoader->createGeneric();
1793 Image imageBase2 = imageGeneric2;
1794 seriesinf->seasonposter.image = imageBase2;
1796 seriesinf->id = seriesID;
1798 seriesinf->name = vresp->extractStdString();
1799 seriesinf->overview = vresp->extractStdString();
1800 seriesinf->firstAired = vresp->extractStdString();
1801 seriesinf->network = vresp->extractStdString();
1802 seriesinf->genre = vresp->extractStdString();
1803 seriesinf->rating = vresp->extractdouble();
1804 seriesinf->status = vresp->extractStdString();
1807 seriesinf->episode.episodeid=episodeID;
1808 seriesinf->episode.number = vresp->extractLONG();
1809 seriesinf->episode.season = vresp->extractLONG();
1810 seriesinf->episode.name = vresp->extractStdString();
1811 seriesinf->episode.firstAired = vresp->extractStdString();
1812 seriesinf->episode.guestStars = vresp->extractStdString();
1813 seriesinf->episode.overview = vresp->extractStdString();
1814 seriesinf->episode.rating = vresp->extractdouble();
1815 seriesinf->episode.image.width = vresp->extractu4();
1816 seriesinf->episode.image.height = vresp->extractu4();
1817 imageGeneric1->setSeriesInfo(seriesinf);
1818 imageGeneric1->setElement(0,0);
1821 u4 num_actors = vresp->extractu4();
1822 seriesinf->actors.clear();
1823 seriesinf->actors.reserve(num_actors);
1824 for (u4 acty=0; acty < num_actors; acty++) {
1826 new_act.name = vresp->extractStdString();
1827 new_act.role = vresp->extractStdString();
1828 new_act.thumb.width = vresp->extractu4();
1829 new_act.thumb.height = vresp->extractu4();
1831 ImageGeneric actorIG = imageLoader->createGeneric();
1832 new_act.thumb.image = actorIG;
1833 actorIG->setSeriesInfo(seriesinf);
1834 actorIG->setElement(1,acty);
1835 seriesinf->actors.push_back(new_act);
1837 imageLoader->ensureLoaded(actorIG);
1839 u4 num_posters = vresp->extractu4();
1840 for (u4 medias = 0; medias < num_posters; medias++ ) {
1841 TVMediaStruct media;
1842 ImageGeneric mediaIG = imageLoader->createGeneric();
1843 media.image = mediaIG;
1844 mediaIG->setSeriesInfo(seriesinf);
1845 mediaIG->setElement(2, medias);
1846 media.width = vresp->extractu4();
1847 media.height = vresp->extractu4();
1848 seriesinf->posters.push_back(media);
1850 imageLoader->ensureLoaded(mediaIG);
1853 u4 num_banners = vresp->extractu4();
1854 for (u4 medias = 0; medias < num_banners; medias++ ) {
1855 TVMediaStruct media;
1856 ImageGeneric mediaIG = imageLoader->createGeneric();
1857 media.image = mediaIG;
1858 mediaIG->setSeriesInfo(seriesinf);
1859 mediaIG->setElement(3,medias);
1860 media.width = vresp->extractu4();
1861 media.height = vresp->extractu4();
1862 seriesinf->banners.push_back(media);
1864 imageLoader->ensureLoaded(mediaIG);
1866 u4 num_fanarts = vresp->extractu4();
1867 for (u4 medias = 0; medias < num_fanarts; medias++ ) {
1868 TVMediaStruct media;
1869 ImageGeneric mediaIG = imageLoader->createGeneric();
1870 media.image = mediaIG;
1871 mediaIG->setSeriesInfo(seriesinf);
1872 mediaIG->setElement(4,medias);
1873 media.width = vresp->extractu4();
1874 media.height = vresp->extractu4();
1875 seriesinf->fanart.push_back(media);
1877 imageLoader->ensureLoaded(mediaIG);
1879 seriesinf->seasonposter.width = vresp->extractu4();
1880 seriesinf->seasonposter.height = vresp->extractu4();
1881 imageGeneric2->setSeriesInfo(seriesinf);
1882 imageGeneric2->setElement(5,0);
1884 imageLoader->ensureLoaded(imageGeneric1);
1885 imageLoader->ensureLoaded(imageGeneric2);
1891 bool VDR::loadImageGeneric(ImageGeneric& image)
1893 VDR_RequestPacket vrp;
1895 if (!vrp.init(VDR_LOADTVMEDIA, false, 0)) return false;
1896 if (!vrp.addu4(image->getType())) return false;
1897 if (!vrp.addu4(image->primary_id)) return false;
1898 if (!vrp.addu4(image->secondary_id)) return false;
1899 if (!vrp.addu4(image->type_pict)) return false;
1900 if (!vrp.addu4(image->container)) return false;
1901 if (!vrp.addu4(image->container_member)) return false;
1902 logger->debug(TAG, "Image with ID {} {}; {} {} {} {};{}",
1903 image->primary_id,image->secondary_id,image->type,image->type_pict,
1904 image->container,image->container_member,vrp.getSerial());
1906 // FIXME - ImageLoader should register itself as a permenant stream receiver instead of making temporary ones like this
1907 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1908 vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1909 vdrpr->streamID = vrp.getSerial();
1910 vdrpr->streamReceiver = NULL;
1913 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1914 bool ret = !vresp->noResponse();
1919 bool VDR::loadImageRecThumb(ImageRecThumb& image) // FIXME convert return to bool
1921 VDR_RequestPacket vrp;
1923 if (!vrp.init(VDR_LOADTVMEDIARECTHUMB, false, 0)) return false;
1924 if (!vrp.addString(image->getFileName())) return false;
1925 image->setServerLoadingRef(vrp.getSerial());
1927 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1928 vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1929 vdrpr->streamID = vrp.getSerial();
1930 vdrpr->streamReceiver = NULL;
1933 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1934 bool ret = !vresp->noResponse();
1939 bool VDR::loadImageEventThumb(ImageEventThumb& image)
1941 VDR_RequestPacket vrp;
1943 if (!vrp.init(VDR_LOADTVMEDIAEVENTTHUMB, false, 0)) return false;
1944 if (!vrp.addu4(image->getChannel())) return false;
1945 if (!vrp.addu4(image->getEvent())) return false;
1946 image->setServerLoadingRef(vrp.getSerial());
1948 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1949 vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1950 vdrpr->streamID = vrp.getSerial();
1951 vdrpr->streamReceiver = NULL;
1954 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1955 bool ret = !vresp->noResponse();
1960 bool VDR::loadImageChannelLogo(ImageChannelLogo& image)
1962 VDR_RequestPacket vrp;
1964 if (!vrp.init(VDR_LOADCHANNELLOGO, false, 0)) return false;
1965 if (!vrp.addu4(image->getChannelID())) return false;
1966 image->setServerLoadingRef(vrp.getSerial());
1968 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1969 vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1970 vdrpr->streamID = vrp.getSerial();
1971 vdrpr->streamReceiver = NULL;
1974 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1975 bool ret = !vresp->noResponse();