2 Copyright 2004-2005 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.
31 #include "vdrrequestpacket.h"
32 #include "vdrresponsepacket.h"
35 VDR* VDR::instance = NULL;
46 channelNumberWidth = 1;
47 TEMP_SINGLE_VDR_PR = NULL;
53 if (initted) shutdown();
56 VDR* VDR::getInstance()
61 int VDR::init(int tport)
63 if (initted) return 0;
66 logger = Log::getInstance();
72 if (!initted) return 0;
78 void VDR::findServers(vector<VDRServer>& servers)
80 Wol* wol = Wol::getInstance();
82 char* message = "VOMP";
84 DatagramSocket ds(port);
85 int haveAtLeastOne = 0;
88 bool firstloop = true;
95 logger->log("VDR", Log::NOTICE, "Broadcasting for server");
96 ds.send("255.255.255.255", 3024, message, strlen(message));
97 if(!firstloop) wol->doWakeUp();
99 retval = ds.waitforMessage(waitType);
101 if (retval == 2) // we got a reply
103 if (!strcmp(ds.getData(), "VOMP")) // echo.....
110 newServer.ip = new char[16];
111 strcpy(newServer.ip, ds.getFromIPA());
113 if (ds.getDataLength() == 0)
115 newServer.name = new char[1];
116 newServer.name[0] = '\0';
120 newServer.name = new char[strlen(ds.getData())+1];
121 strcpy(newServer.name, ds.getData());
124 servers.push_back(newServer);
131 if (haveAtLeastOne) break;
136 sort(servers.begin(), servers.end(), ServerSorter());
139 void VDR::cancelFindingServer()
144 void VDR::setServerIP(char* newIP)
146 strcpy(serverIP, newIP);
151 maxChannelNumber = 0;
152 channelNumberWidth = 1;
156 if (tcp->connectTo(serverIP, 3024))
168 void VDR::disconnect()
174 logger->log("VDR", Log::DEBUG, "Disconnect");
177 void VDR::setReceiveWindow(size_t size)
179 if (connected) tcp->setReceiveWindow(size);
182 ///////////////////////////////////////////////////////
184 void VDR::threadMethod()
186 logger->log("VDR", Log::DEBUG, "VDR RUN");
188 threadSetKillable(); // FIXME - change this to deal with the EDRs
193 ULONG userDataLength;
199 VDR_ResponsePacket* vresp;
201 int timeoutCount = 0;
202 ULONG lastKAsent = 0;
207 if (!tcp->readData((UCHAR*)&channelID, sizeof(ULONG))) // 2s timeout atm
213 /* This is the simple version of timeout system until I work out how to make it better
214 e.g. different timeout lengths for different requests, a decent keepalive system
215 running in parallel etc etc.
217 Ignore the stream channel
218 Start with lastPacketReceived = 0
219 When a packet comes in, set lastPacketReceived = time(NULL)
222 if last packet is over 20s ago
224 if lastKAsent is less than 20s ago, continue
226 if lastKAsent = 0, send a KA, continue
228 if lastKAsent is over 20s ago, connection is dead, kill it
233 logger->log("VDR", Log::DEBUG, "Net read timeout %i", timeoutCount);
235 if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread
237 timeoutCount = 0; // disable it for now
239 if (timeoutCount >= 10) //20s
241 timeNow = (ULONG)time(NULL);
243 if (lastKAsent > (timeNow - 20)) continue;
247 if (!sendKA(timeNow)) { connectionDied(); return; }
248 lastKAsent = timeNow;
252 if (lastKAsent <= (timeNow - 20)) { connectionDied(); return; }
262 channelID = ntohl(channelID);
264 if (channelID == CHANNEL_REQUEST_RESPONSE)
266 if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
267 requestID = ntohl(requestID);
268 if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
269 userDataLength = ntohl(userDataLength);
270 if (userDataLength > 5000000) break; // how big can these packets get?
272 if (userDataLength > 0)
274 userData = (UCHAR*)malloc(userDataLength);
275 if (!userData) break;
276 if (!tcp->readData(userData, userDataLength)) break;
279 vresp = new VDR_ResponsePacket();
280 vresp->setResponse(requestID, userData, userDataLength);
281 logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
283 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
285 // If edFindAndCall returns true, edr was called and vresp was handed off.
286 // else, delete vresp here.
290 else if (channelID == CHANNEL_STREAM)
292 if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
293 streamID = ntohl(streamID);
295 if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;
298 if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
299 userDataLength = ntohl(userDataLength);
301 if (userDataLength > 0)
303 userData = (UCHAR*)malloc(userDataLength);
304 if (!userData) break;
305 if (!tcp->readData(userData, userDataLength)) break;
308 vresp = new VDR_ResponsePacket();
309 vresp->setStream(streamID, flag, userData, userDataLength);
310 // logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);
312 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
314 // If edFindAndCall returns true, edr was called and vresp was handed off.
315 // else, delete vresp here.
319 else if (channelID == CHANNEL_KEEPALIVE)
322 if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;
323 KAreply = (ULONG)ntohl(KAreply);
324 if (KAreply == lastKAsent) // successful KA response
332 logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
336 // Who deletes vresp?
337 // If RR, the individual protocol functions must delete vresp.
338 // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
342 void VDR::connectionDied()
344 // Called from within threadMethod to do cleanup if it decides the connection has died
346 connected = false; // though actually it could still be connected until someone calls vdr->disconnect
348 // Need to wake up any waiting channel 1 request-response threads
349 // Normally this is done by a packet coming in with channelid and requestid
350 // Instead, go through the list and for each channel 1 edr, make an empty vresp
351 // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
353 // If it's a stream receiver, generate a stream packet with flag == connection_lost
356 VDR_PacketReceiver* vdrpr;
357 VDR_ResponsePacket* vresp;
358 while(receivers.size())
360 vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
361 if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
363 vresp = new VDR_ResponsePacket();
364 vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
365 logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
367 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
369 // If edFindAndCall returns true, edr was called and vresp was handed off.
370 // else, delete vresp here.
371 logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
376 else if (vdrpr->receiverChannel == CHANNEL_STREAM)
378 vresp = new VDR_ResponsePacket();
379 vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);
380 logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
382 if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
384 // If edFindAndCall returns true, edr was called and vresp was handed off.
385 // else, delete vresp here.
386 logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
393 // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
395 Command::getInstance()->connectionLost();
398 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
400 // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
401 // userTag is a VDR_ResponsePacket made in threadMethod
403 VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
404 VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
406 // Is vresp for vdrpr ?
408 ULONG packetChannel = vresp->getChannelID();
409 if (vdrpr->receiverChannel != packetChannel) return false;
411 if (packetChannel == CHANNEL_REQUEST_RESPONSE)
413 if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
415 else if (packetChannel == CHANNEL_STREAM)
417 if (vdrpr->streamID == vresp->getStreamID()) return true;
423 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
425 logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
429 VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
430 return vresp; // "no-response" return
433 // ED make new VDR and register
434 // make a VDR_PacketReceiver
435 // - init with serial number of request packet
437 VDR_PacketReceiver vdrpr;
438 // vdrpr.requestTime = time(NULL);
439 vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
440 vdrpr.requestSerialNumber = vrp->getSerial();
444 if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
447 edUnregister(&vdrpr);
448 VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
449 return vresp; // "no-response" return
452 // Sleep and block this thread. The sleep unlocks the mutex
453 logger->log("VDR", Log::DEBUG, "RR sleep");
454 edSleepThisReceiver(&vdrpr);
455 logger->log("VDR", Log::DEBUG, "RR unsleep");
457 // Woken because a response packet has arrived, mutex will be locked
460 return vdrpr.save_vresp;
463 bool VDR::sendKA(ULONG timeStamp)
466 *(ULONG*)&buffer[0] = htonl(CHANNEL_KEEPALIVE);
467 *(ULONG*)&buffer[4] = htonl(timeStamp);
468 if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;
472 /////////////////////////////////////////////////////////////////////////////
474 // Here VDR takes a break for the VDR_PacketReceiver helper class
476 bool VDR_PacketReceiver::call(void* userTag)
478 if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
480 // It's a RR. Save vresp and, signal the waiting thread and return.
481 // VDR::RequestResponse will be blocking waiting for this to happen.
482 // That function has a pointer to this object and can read save_vresp.
483 save_vresp = (VDR_ResponsePacket*)userTag;
484 return true; // Signals ED to remove edr from receivers and wake up edr thread
487 if (receiverChannel == VDR::CHANNEL_STREAM)
489 // It's a stream packet.
490 VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
491 streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
496 abort(); // unknown receiverChannel, should not happen
499 /////////////////////////////////////////////////////////////////////////////
503 VDR_RequestPacket vrp;
504 if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
507 tcp->getMAC((char*)mactemp);
508 if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
510 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
511 if (vresp->noResponse()) { delete vresp; return 0; }
513 ULONG vdrTime = vresp->extractULONG();
514 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
515 long vdrTimeOffset = vresp->extractLONG();
516 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
520 // Set the time and zone on the MVP
523 struct timespec currentTime;
524 currentTime.tv_sec = vdrTime;
525 currentTime.tv_nsec = 0;
526 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
528 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
530 // now make a TZ variable and set it
534 if (vdrTimeOffset > 0) sign = '-';
537 vdrTimeOffset = abs(vdrTimeOffset);
539 hours = (int)vdrTimeOffset / 3600;
540 minutes = vdrTimeOffset % 3600;
542 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
544 minutes = (int)minutes / 60;
546 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
549 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
550 setenv("TZ", newTZ, 1);
552 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
558 bool VDR::getRecordingsList(RecMan* recman)
560 VDR_RequestPacket vrp;
561 if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
563 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
564 if (vresp->noResponse()) { delete vresp; return false; }
566 ULONG totalSpace = vresp->extractULONG();
567 ULONG freeSpace = vresp->extractULONG();
568 ULONG percent = vresp->extractULONG();
569 recman->setStats(totalSpace, freeSpace, percent);
575 while (!vresp->end())
577 start = vresp->extractULONG();
578 name = vresp->extractString();
579 fileName = vresp->extractString();
581 recman->addEntry(start, name, fileName);
592 int VDR::deleteRecording(char* fileName)
594 VDR_RequestPacket vrp;
595 if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
596 if (!vrp.addString(fileName)) return 0;
598 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
599 if (vresp->noResponse()) { delete vresp; return 0; }
601 int toReturn = (int)vresp->extractULONG();
607 char* VDR::moveRecording(char* fileName, char* newPath)
609 VDR_RequestPacket vrp;
610 if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
611 if (!vrp.addString(fileName)) return NULL;
612 if (!vrp.addString(newPath)) return NULL;
614 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
615 if (vresp->noResponse()) { delete vresp; return NULL; }
617 char* toReturn = NULL;
618 int success = (int)vresp->extractULONG();
621 toReturn = vresp->extractString();
629 ChannelList* VDR::getChannelsList(ULONG type)
631 VDR_RequestPacket vrp;
632 if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
634 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
635 if (vresp->noResponse()) { delete vresp; return NULL; }
637 ChannelList* chanList = new ChannelList();
639 while (!vresp->end())
641 Channel* chan = new Channel();
642 chan->number = vresp->extractULONG();
643 chan->type = vresp->extractULONG();
644 chan->name = vresp->extractString();
646 if (chan->type == type)
648 chanList->push_back(chan);
649 logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
650 if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
660 if (maxChannelNumber > 99999)
661 channelNumberWidth = 6;
662 else if (maxChannelNumber > 9999)
663 channelNumberWidth = 5;
664 else if (maxChannelNumber > 999)
665 channelNumberWidth = 4;
666 else if (maxChannelNumber > 99)
667 channelNumberWidth = 3;
668 else if (maxChannelNumber > 9)
669 channelNumberWidth = 2;
671 channelNumberWidth = 1;
677 int VDR::streamChannel(ULONG number)
683 int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
685 VDR_RequestPacket vrp;
686 if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
687 if (!vrp.addULONG(number)) return 0;
690 VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
691 vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
692 vdrpr->streamID = vrp.getSerial();
693 vdrpr->streamReceiver = tstreamReceiver;
695 TEMP_SINGLE_VDR_PR = vdrpr;
697 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
698 if (vresp->noResponse())
706 int toReturn = (int)vresp->extractULONG();
707 logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);
713 int VDR::stopStreaming()
715 VDR_RequestPacket vrp;
716 if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
718 if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
719 // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
721 edUnregister(TEMP_SINGLE_VDR_PR);
722 delete TEMP_SINGLE_VDR_PR;
723 TEMP_SINGLE_VDR_PR = NULL;
726 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
727 if (vresp->noResponse()) { delete vresp; return 0; }
729 int toReturn = (int)vresp->extractULONG();
735 UCHAR* VDR::getImageBlock(ULONG position, UINT maxAmount, UINT* amountReceived)
737 return getBlock(position, maxAmount, amountReceived, VDR_GETIMAGEBLOCK);
740 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
742 return getBlock(position, maxAmount, amountReceived, VDR_GETBLOCK);
745 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd)
747 VDR_RequestPacket vrp;
748 if (!vrp.init(cmd, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
749 if (!vrp.addULLONG(position)) return NULL;
750 if (!vrp.addULONG(maxAmount)) return NULL;
752 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
753 if (vresp->noResponse()) { delete vresp; return NULL; }
755 if (vresp->serverError())
757 logger->log("VDR", Log::DEBUG, "Detected getblock 0");
762 // Special handling for getblock
763 UCHAR* toReturn = vresp->getUserData();
764 *amountReceived = vresp->getUserDataLength();
771 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
773 VDR_RequestPacket vrp;
774 if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
775 if (!vrp.addString(fileName)) return 0;
777 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
778 if (vresp->noResponse()) { delete vresp; return 0; }
780 ULLONG lengthBytes = vresp->extractULLONG();
781 ULONG lengthFrames = vresp->extractULONG();
784 logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
786 *totalFrames = lengthFrames;
790 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
792 VDR_RequestPacket vrp;
793 if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
794 if (!vrp.addULONG(frameNumber)) return 0;
796 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
797 if (vresp->noResponse()) { delete vresp; return 0; }
799 ULLONG position = vresp->extractULLONG();
802 logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
807 ULONG VDR::frameNumberFromPosition(ULLONG position)
809 VDR_RequestPacket vrp;
810 if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
811 if (!vrp.addULLONG(position)) return 0;
813 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
814 if (vresp->noResponse()) { delete vresp; return 0; }
816 ULONG framenumber = vresp->extractULONG();
819 logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
824 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
826 VDR_RequestPacket vrp;
827 if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
828 if (!vrp.addULONG(frameNumber)) return false;
829 if (!vrp.addULONG(direction)) return false;
831 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
832 if (vresp->noResponse()) { delete vresp; return false; }
834 if (vresp->serverError())
836 logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
841 *rfilePosition = vresp->extractULLONG();
842 *rframeNumber = vresp->extractULONG();
843 *rframeLength = vresp->extractULONG();
847 // logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
852 EventList* VDR::getChannelSchedule(ULONG number)
856 return getChannelSchedule(number, now, 24 * 60 * 60);
859 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
861 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
863 VDR_RequestPacket vrp;
864 if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
865 if (!vrp.addULONG(number)) return NULL;
866 if (!vrp.addULONG(start)) return NULL;
867 if (!vrp.addULONG(duration)) return NULL;
869 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
870 if (vresp->noResponse()) { delete vresp; return NULL; }
872 // received a ulong(0) - schedules error in the plugin
873 if (vresp->serverError())
879 EventList* eventList = new EventList();
881 while (!vresp->end())
883 Event* event = new Event();
884 event->id = vresp->extractULONG();
885 event->time = vresp->extractULONG();
886 event->duration = vresp->extractULONG();
887 event->title = vresp->extractString();
888 event->subtitle = vresp->extractString();
889 event->description = vresp->extractString();
890 eventList->push_back(event);
895 logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
899 int VDR::configSave(const char* section, const char* key, const char* value)
901 VDR_RequestPacket vrp;
902 if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
903 if (!vrp.addString(section)) return 0;
904 if (!vrp.addString(key)) return 0;
905 if (!vrp.addString(value)) return 0;
907 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
908 if (vresp->noResponse()) { delete vresp; return 0; }
910 int toReturn = (int)vresp->extractULONG();
916 char* VDR::configLoad(const char* section, const char* key)
918 VDR_RequestPacket vrp;
919 if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
920 if (!vrp.addString(section)) return NULL;
921 if (!vrp.addString(key)) return NULL;
923 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
924 if (vresp->noResponse()) { delete vresp; return NULL; }
926 char* toReturn = vresp->extractString();
932 RecTimerList* VDR::getRecTimersList()
934 VDR_RequestPacket vrp;
935 if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
937 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
938 if (vresp->noResponse()) { delete vresp; return NULL; }
940 RecTimerList* recTimerList = new RecTimerList();
942 ULONG numTimers = vresp->extractULONG();
945 RecTimer* newRecTimer;
948 while (!vresp->end())
950 newRecTimer = new RecTimer();
951 newRecTimer->active = vresp->extractULONG();
952 newRecTimer->recording = vresp->extractULONG();
953 newRecTimer->pending = vresp->extractULONG();
954 newRecTimer->priority = vresp->extractULONG();
955 newRecTimer->lifeTime = vresp->extractULONG();
956 newRecTimer->channelNumber = vresp->extractULONG();
957 newRecTimer->startTime = vresp->extractULONG();
958 newRecTimer->stopTime = vresp->extractULONG();
959 newRecTimer->day = vresp->extractULONG();
960 newRecTimer->weekDays = vresp->extractULONG();
962 tempString = vresp->extractString();
963 newRecTimer->setFile(tempString);
966 recTimerList->push_back(newRecTimer);
967 logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
968 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
969 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
975 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
980 ULONG VDR::setEventTimer(char* timerString)
982 VDR_RequestPacket vrp;
983 if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
984 if (!vrp.addString(timerString)) return 0;
986 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
987 if (vresp->noResponse()) { delete vresp; return 0; }
989 ULONG toReturn = vresp->extractULONG();
995 RecInfo* VDR::getRecInfo(char* fileName)
997 VDR_RequestPacket vrp;
998 if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;
999 if (!vrp.addString(fileName)) return NULL;
1001 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1002 if (vresp->noResponse()) { delete vresp; return NULL; }
1004 if (vresp->serverError())
1006 logger->log("VDR", Log::DEBUG, "Could not get rec info");
1011 RecInfo* recInfo = new RecInfo();
1013 recInfo->timerStart = vresp->extractULONG();
1014 recInfo->timerEnd = vresp->extractULONG();
1015 recInfo->resumePoint = vresp->extractULONG();
1016 recInfo->summary = vresp->extractString();
1018 ULONG numComponents = vresp->extractULONG();
1021 recInfo->setNumComponents(numComponents);
1022 for (ULONG i = 0; i < numComponents; i++)
1024 recInfo->streams[i] = vresp->extractUCHAR();
1025 recInfo->types[i] = vresp->extractUCHAR();
1026 recInfo->languages[i] = vresp->extractString();
1027 recInfo->descriptions[i] = vresp->extractString();
1038 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1040 VDR_RequestPacket vrp;
1041 if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
1043 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1044 if (vresp->noResponse()) { delete vresp; return 0; }
1046 ULLONG lengthBytes = vresp->extractULLONG();
1047 ULONG lengthFrames = vresp->extractULONG();
1050 logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1052 *totalFrames = lengthFrames;
1056 MarkList* VDR::getMarks(char* fileName)
1058 VDR_RequestPacket vrp;
1059 if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
1060 if (!vrp.addString(fileName)) return NULL;
1062 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1063 if (vresp->noResponse()) { delete vresp; return NULL; }
1065 if (vresp->serverError())
1071 MarkList* markList = new MarkList();
1073 while (!vresp->end())
1075 Mark* mark = new Mark();
1076 mark->pos = vresp->extractULONG();
1078 markList->push_back(mark);
1079 logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1087 void VDR::getChannelPids(Channel* channel)
1089 VDR_RequestPacket vrp;
1090 if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
1091 if (!vrp.addULONG(channel->number)) return ;
1093 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1094 if (vresp->noResponse()) { delete vresp; return ; }
1096 // Format of response
1104 channel->vpid = vresp->extractULONG();
1105 channel->numAPids = vresp->extractULONG();
1107 for (ULONG i = 0; i < channel->numAPids; i++)
1110 newapid.pid = vresp->extractULONG();
1111 newapid.name = vresp->extractString();
1112 channel->apids.push_back(newapid);
1115 channel->numDPids = vresp->extractULONG();
1117 for (ULONG i = 0; i < channel->numDPids; i++)
1120 newdpid.pid = vresp->extractULONG();
1121 newdpid.name = vresp->extractString();
1122 channel->dpids.push_back(newdpid);
1125 channel->numSPids = vresp->extractULONG();
1127 for (ULONG i = 0; i < channel->numSPids; i++)
1130 newspid.pid = vresp->extractULONG();
1131 newspid.name = vresp->extractString();
1132 channel->spids.push_back(newspid);
1134 channel->tpid = vresp->extractULONG();
1142 * media List Request:
1143 * 4 flags (currently unused)
1146 * Media List response:
1154 * 4 strlen (incl. 0 Byte)
1158 MediaList* VDR::getMediaList(const char* parent,int mediaType)
1160 logger->log("VDR", Log::DEBUG, "getMediaList %s,type=%d", (parent?parent:"NULL"), mediaType);
1162 VDR_RequestPacket vrp;
1163 if (!vrp.init(VDR_GETMEDIALIST, false, 0)) return NULL;
1164 if (!vrp.addULONG(0)) return NULL; // unused flags
1168 if (!vrp.addString(parent)) return NULL;
1171 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1172 if (vresp->noResponse()) { delete vresp; return NULL; }
1174 if (vresp->serverError())
1180 if (vresp->getUserDataLength() < 12)
1182 logger->log("VDR", Log::ERR, "receiveMediaList packet too short, expected 12, got %d", vresp->getUserDataLength());
1187 MediaList* mediaList = new MediaList();
1189 code = vresp->extractULONG();
1190 ULONG numEntries = vresp->extractULONG();
1191 Log::getInstance()->log("VDR", Log::DEBUG, "receiveMediaList with %d entries",numEntries);
1192 while (!vresp->end() && numEntries >0)
1194 Media* m = new Media();
1195 ULONG mtype = vresp->extractULONG();
1196 ULONG mtime=vresp->extractULONG();
1198 flags=vresp->extractULONG();
1199 ULONG stsize=vresp->extractULONG();
1200 char * name=vresp->extractString();
1201 if (! name || stsize != (strlen(name)+1)) {
1202 Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList invalid packet entry, read size %d, strlen %d", stsize, strlen(name)+1);
1208 //ignore . and .. entries
1209 if (strcmp(name,".") == 0 || strcmp(name,"..")==0) {
1213 m->setFileName(name);
1215 m->setMediaType(mtype);
1216 mediaList->push_back(m);
1217 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a media to list. %s, type=%d, time=%d", name,mtype,mtime);
1226 * get image Request:
1227 * 4 flags (currently unused)
1232 * get image response:
1237 ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y)
1239 VDR_RequestPacket vrp;
1240 if (!vrp.init(VDR_GETIMAGE, false, 0)) return 0;
1241 if (!vrp.addULONG(0)) return 0; // unused flags
1242 if (!vrp.addULONG(x)) return 0;
1243 if (!vrp.addULONG(y)) return 0;
1244 if (!vrp.addString(fileName)) return 0;
1246 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1247 if (vresp->noResponse()) { delete vresp; return 0; }
1249 ULONG cmd = vresp->extractULONG();
1250 ULONG lengthBytes = vresp->extractULONG();
1253 Log::getInstance()->log("VDR", Log::DEBUG, "getImage %s: cmd=%lu len=%lu", fileName, cmd, lengthBytes);
1257 int VDR::deleteTimer(RecTimer* delTimer)
1259 Log::getInstance()->log("VDR", Log::DEBUG, "Delete timer called");
1261 VDR_RequestPacket vrp;
1262 if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
1263 if (!vrp.addULONG(delTimer->channelNumber)) return 0;
1264 if (!vrp.addULONG(delTimer->weekDays)) return 0;
1265 if (!vrp.addULONG(delTimer->day)) return 0;
1266 if (!vrp.addULONG(delTimer->startTime)) return 0;
1267 if (!vrp.addULONG(delTimer->stopTime)) return 0;
1269 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1270 if (vresp->noResponse()) { delete vresp; return 0; }
1272 int toReturn = (int)vresp->extractULONG();
1278 I18n::lang_code_list VDR::getLanguageList()
1280 I18n::lang_code_list CodeList;
1281 CodeList["en"] = "English"; // Default entry
1282 VDR_RequestPacket vrp;
1283 if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
1284 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1285 if (vresp->noResponse() || vresp->end())
1291 while (!vresp->end())
1293 char* c_code = vresp->extractString();
1294 char* c_name = vresp->extractString();
1295 string code = c_code;
1296 string name = c_name;
1297 CodeList[code] = name;
1305 int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
1307 VDR_RequestPacket vrp;
1308 if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
1309 if (!vrp.addString(code.c_str())) return 0;
1310 VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1311 if (vresp->noResponse()) { delete vresp; return 0; }
1313 while (!vresp->end())
1315 char* c_key = vresp->extractString();
1316 char* c_text = vresp->extractString();
1318 string text = c_text;