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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 VDR* VDR::instance = NULL;
26 #define MUTEX_LOCK(mutex) pthread_mutex_lock(mutex)
27 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(mutex)
29 #define MUTEX_LOCK(mutex) WaitForSingleObject(*(mutex), INFINITE )
30 #define MUTEX_UNLOCK(mutex) ReleaseMutex(*(mutex))
42 pthread_mutex_init(&mutex, NULL);
44 mutex=CreateMutex(NULL,FALSE,NULL);
58 if (initted) shutdown();
61 VDR* VDR::getInstance()
66 int VDR::init(int tport)
68 if (initted) return 0;
71 logger = Log::getInstance();
77 if (!initted) return 0;
83 void VDR::findServers(vector<VDRServer>& servers)
86 char* message = "VOMP";
88 DatagramSocket ds(port);
89 int haveAtLeastOne = 0;
98 logger->log("VDR", Log::NOTICE, "Broadcasting for server");
99 ds.send("255.255.255.255", 3024, message, strlen(message));
101 retval = ds.waitforMessage(waitType);
103 if (retval == 2) // we got a reply
105 if (!strcmp(ds.getData(), "VOMP")) // echo.....
112 newServer.ip = new char[16];
113 strcpy(newServer.ip, ds.getFromIPA());
115 if (ds.getDataLength() == 0)
117 newServer.name = new char[1];
118 newServer.name[0] = '\0';
122 newServer.name = new char[strlen(ds.getData())+1];
123 strcpy(newServer.name, ds.getData());
126 servers.push_back(newServer);
133 if (haveAtLeastOne) break;
137 sort(servers.begin(), servers.end(), ServerSorter());
140 void VDR::cancelFindingServer()
145 void VDR::setServerIP(char* newIP)
147 strcpy(serverIP, newIP);
154 if (tcp->connectTo(serverIP, 3024))
165 void VDR::disconnect()
170 Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
173 void VDR::setReceiveWindow(size_t size)
175 if (connected) tcp->setReceiveWindow(size);
178 ///////////////////////////////////////////////////////
182 packet = (UCHAR*)tcp->receivePacket();
188 packetLength = tcp->getDataLength();
192 void VDR::freePacket()
194 // Must be called if getPacket return 1, except in getBlock
201 int VDR::serverError()
203 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
207 char* VDR::extractString()
209 if (serverError()) return NULL;
211 int length = strlen((char*)&packet[packetPos]);
212 if ((packetPos + length) > packetLength) return NULL;
213 char* str = new char[length + 1];
214 strcpy(str, (char*)&packet[packetPos]);
215 packetPos += length + 1;
219 ULONG VDR::extractULONG()
221 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
222 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
223 packetPos += sizeof(ULONG);
227 ULLONG VDR::extractULLONG()
229 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
230 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
231 packetPos += sizeof(ULLONG);
235 long VDR::extractLONG()
237 if ((packetPos + sizeof(long)) > packetLength) return 0;
238 long l = ntohl(*(long*)&packet[packetPos]);
239 packetPos += sizeof(long);
243 /////////////////////////////////////////////////////////////////////////////
249 *(unsigned long*)&buffer[0] = htonl(10);
250 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
252 tcp->getMAC((char*)&buffer[8]);
258 MUTEX_UNLOCK(&mutex);
262 int a = tcp->sendPacket(buffer, 14);
266 MUTEX_UNLOCK(&mutex);
274 MUTEX_UNLOCK(&mutex);
278 ULONG vdrTime = extractULONG();
279 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
280 long vdrTimeOffset = extractLONG();
281 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
284 MUTEX_UNLOCK(&mutex);
286 // Set the time and zone on the MVP
289 struct timespec currentTime;
290 currentTime.tv_sec = vdrTime;
291 currentTime.tv_nsec = 0;
292 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
294 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
296 // now make a TZ variable and set it
300 if (vdrTimeOffset > 0) sign = '-';
303 vdrTimeOffset = abs(vdrTimeOffset);
305 hours = (int)vdrTimeOffset / 3600;
306 minutes = vdrTimeOffset % 3600;
308 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
310 minutes = (int)minutes / 60;
312 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
315 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
316 setenv("TZ", newTZ, 1);
318 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
324 bool VDR::getRecordingsList(RecMan* recman)
328 *(unsigned long*)&buffer[0] = htonl(4);
329 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
334 MUTEX_UNLOCK(&mutex);
338 int a = tcp->sendPacket(buffer, 8);
342 MUTEX_UNLOCK(&mutex);
350 MUTEX_UNLOCK(&mutex);
354 ULONG totalSpace = extractULONG();
355 ULONG freeSpace = extractULONG();
356 ULONG percent = extractULONG();
357 recman->setStats(totalSpace, freeSpace, percent);
363 while (packetPos < packetLength)
365 start = extractULONG();
366 name = extractString();
367 fileName = extractString();
369 recman->addEntry(start, name, fileName);
376 MUTEX_UNLOCK(&mutex);
381 int VDR::deleteRecording(char* fileName)
383 unsigned long totalLength = 8 + strlen(fileName) + 1;
384 UCHAR* buffer = new UCHAR[totalLength];
386 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
387 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
388 strcpy((char*)&buffer[8], fileName);
391 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
393 unsigned int a = tcp->sendPacket(buffer, totalLength);
396 if (a != totalLength)
399 MUTEX_UNLOCK(&mutex);
405 MUTEX_UNLOCK(&mutex);
409 int toReturn = (int)extractULONG();
411 MUTEX_UNLOCK(&mutex);
416 char* VDR::moveRecording(char* fileName, char* newPath)
418 unsigned long totalLength = 8 + strlen(fileName) + 1 + strlen(newPath) + 1;
419 UCHAR* buffer = new UCHAR[totalLength];
421 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
422 *(unsigned long*)&buffer[4] = htonl(VDR_MOVERECORDING);
423 strcpy((char*)&buffer[8], fileName);
424 strcpy((char*)&buffer[8 + strlen(fileName) + 1], newPath);
427 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
429 unsigned int a = tcp->sendPacket(buffer, totalLength);
432 if (a != totalLength)
435 MUTEX_UNLOCK(&mutex);
441 MUTEX_UNLOCK(&mutex);
445 char* toReturn = NULL;
446 int success = (int)extractULONG();
449 toReturn = extractString();
453 MUTEX_UNLOCK(&mutex);
458 char* VDR::getRecordingSummary(char* fileName)
460 unsigned long totalLength = 8 + strlen(fileName) + 1;
461 UCHAR* buffer = new UCHAR[totalLength];
463 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
464 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
465 strcpy((char*)&buffer[8], fileName);
468 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
470 unsigned int a = tcp->sendPacket(buffer, totalLength);
473 if (a != totalLength)
476 MUTEX_UNLOCK(&mutex);
482 MUTEX_UNLOCK(&mutex);
485 char* toReturn = extractString();
487 MUTEX_UNLOCK(&mutex);
492 ChannelList* VDR::getChannelsList(ULONG type)
496 *(unsigned long*)&buffer[0] = htonl(4);
497 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
500 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
502 int a = tcp->sendPacket(buffer, 8);
506 MUTEX_UNLOCK(&mutex);
514 MUTEX_UNLOCK(&mutex);
518 ChannelList* chanList = new ChannelList();
520 while (packetPos < packetLength)
522 Channel* chan = new Channel();
523 chan->number = extractULONG();
524 chan->type = extractULONG();
525 chan->name = extractString();
527 if (chan->type == type)
529 chanList->push_back(chan);
530 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
539 MUTEX_UNLOCK(&mutex);
544 int VDR::streamChannel(ULONG number)
548 *(unsigned long*)&buffer[0] = htonl(8);
549 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
550 *(unsigned long*)&buffer[8] = htonl(number);
553 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
555 int a = tcp->sendPacket(buffer, 12);
560 MUTEX_UNLOCK(&mutex);
566 MUTEX_UNLOCK(&mutex);
570 int toReturn = (int)extractULONG();
572 MUTEX_UNLOCK(&mutex);
577 int VDR::stopStreaming()
581 *(unsigned long*)&buffer[0] = htonl(4);
582 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
585 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
587 int a = tcp->sendPacket(buffer, 8);
592 MUTEX_UNLOCK(&mutex);
598 MUTEX_UNLOCK(&mutex);
602 int toReturn = (int)extractULONG();
604 MUTEX_UNLOCK(&mutex);
609 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
613 *(unsigned long*)&buffer[0] = htonl(16);
614 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
615 *(ULLONG*)&buffer[8] = htonll(position);
616 *(unsigned long*)&buffer[16] = htonl(maxAmount);
619 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
621 int a = tcp->sendPacket(buffer, 20);
625 MUTEX_UNLOCK(&mutex);
631 MUTEX_UNLOCK(&mutex);
637 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
639 MUTEX_UNLOCK(&mutex);
643 UCHAR* toReturn = packet;
644 *amountReceived = packetLength;
645 // Manually clean up instead of running freePacket to keep the block
649 MUTEX_UNLOCK(&mutex);
655 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
657 unsigned long totalLength = 8 + strlen(fileName) + 1;
658 UCHAR* buffer = new UCHAR[totalLength];
660 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
661 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
662 strcpy((char*)&buffer[8], fileName);
665 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
667 unsigned int a = tcp->sendPacket(buffer, totalLength);
670 if (a != totalLength)
673 MUTEX_UNLOCK(&mutex);
679 MUTEX_UNLOCK(&mutex);
683 ULLONG lengthBytes = extractULLONG();
684 ULONG lengthFrames = extractULONG();
686 MUTEX_UNLOCK(&mutex);
688 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
690 *totalFrames = lengthFrames;
694 ULLONG VDR::rescanRecording(ULONG* totalFrames)
696 unsigned long totalLength = 8;
697 UCHAR* buffer = new UCHAR[totalLength];
699 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
700 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
703 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
705 unsigned int a = tcp->sendPacket(buffer, totalLength);
708 if (a != totalLength)
711 MUTEX_UNLOCK(&mutex);
717 MUTEX_UNLOCK(&mutex);
721 ULLONG lengthBytes = extractULLONG();
722 ULONG lengthFrames = extractULONG();
724 MUTEX_UNLOCK(&mutex);
726 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
728 *totalFrames = lengthFrames;
732 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
734 unsigned long totalLength = 12;
735 UCHAR* buffer = new UCHAR[totalLength];
737 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
738 *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
739 *(unsigned long*)&buffer[8] = htonl(frameNumber);
742 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
744 unsigned int a = tcp->sendPacket(buffer, totalLength);
747 if (a != totalLength)
750 MUTEX_UNLOCK(&mutex);
756 MUTEX_UNLOCK(&mutex);
760 ULLONG position = extractULLONG();
762 MUTEX_UNLOCK(&mutex);
764 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
769 ULONG VDR::frameNumberFromPosition(ULLONG position)
771 unsigned long totalLength = 16;
772 UCHAR* buffer = new UCHAR[totalLength];
774 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
775 *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
776 *(ULLONG*)&buffer[8] = htonll(position);
779 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
781 unsigned int a = tcp->sendPacket(buffer, totalLength);
784 if (a != totalLength)
787 MUTEX_UNLOCK(&mutex);
793 MUTEX_UNLOCK(&mutex);
797 ULONG framenumber = extractULONG();
799 MUTEX_UNLOCK(&mutex);
801 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
806 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
808 unsigned long totalLength = 16;
809 UCHAR* buffer = new UCHAR[totalLength];
811 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
812 *(unsigned long*)&buffer[4] = htonl(VDR_GETNEXTIFRAME);
813 *(unsigned long*)&buffer[8] = htonl(frameNumber);
814 *(unsigned long*)&buffer[12] = htonl(direction);
817 if (!connected) { MUTEX_UNLOCK(&mutex); return false; }
819 unsigned int a = tcp->sendPacket(buffer, totalLength);
822 if (a != totalLength)
825 MUTEX_UNLOCK(&mutex);
831 MUTEX_UNLOCK(&mutex);
837 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
839 MUTEX_UNLOCK(&mutex);
843 *rfilePosition = extractULLONG();
844 *rframeNumber = extractULONG();
845 *rframeLength = extractULONG();
848 MUTEX_UNLOCK(&mutex);
850 Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
855 EventList* VDR::getChannelSchedule(ULONG number)
859 return getChannelSchedule(number, now, 24 * 60 * 60);
862 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
864 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
867 *(unsigned long*)&buffer[0] = htonl(16);
868 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
869 *(unsigned long*)&buffer[8] = htonl(number);
870 *(unsigned long*)&buffer[12] = htonl(start);
871 *(unsigned long*)&buffer[16] = htonl(duration);
874 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
876 int a = tcp->sendPacket(buffer, 20);
881 MUTEX_UNLOCK(&mutex);
887 MUTEX_UNLOCK(&mutex);
891 // received a ulong(0) - schedules error in the plugin
895 MUTEX_UNLOCK(&mutex);
899 EventList* eventList = new EventList();
901 while (packetPos < packetLength)
903 Event* event = new Event();
904 event->id = extractULONG();
905 event->time = extractULONG();
906 event->duration = extractULONG();
907 event->title = extractString();
908 event->subtitle = extractString();
909 event->description = extractString();
910 eventList->push_back(event);
911 // eventList->next();
915 MUTEX_UNLOCK(&mutex);
917 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
922 Log* l = Log::getInstance();
925 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
928 for(eventList->reset(); !eventList->eol(); eventList->next())
930 currentEvent = (Event*)eventList->getCurrent();
931 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
938 ULONG VDR::getResumePoint(char* fileName)
940 if (!connected) return 0;
942 char* resumeString = configLoad("ResumeData", fileName);
943 if (!resumeString) return 0;
945 ULONG toReturn = STRTOUL(resumeString, NULL, 10);
946 delete[] resumeString;
950 int VDR::configSave(char* section, char* key, const char* value)
952 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
953 UCHAR* buffer = new UCHAR[totalLength];
955 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
956 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
959 strcpy((char*)&buffer[position], section);
960 position += strlen(section) + 1;
961 strcpy((char*)&buffer[position], key);
962 position += strlen(key) + 1;
963 strcpy((char*)&buffer[position], value);
966 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
968 unsigned int a = tcp->sendPacket(buffer, totalLength);
971 if (a != totalLength)
974 MUTEX_UNLOCK(&mutex);
980 MUTEX_UNLOCK(&mutex);
984 int toReturn = (int)extractULONG();
986 MUTEX_UNLOCK(&mutex);
991 char* VDR::configLoad(char* section, char* key)
993 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
994 UCHAR* buffer = new UCHAR[totalLength];
996 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
997 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
1000 strcpy((char*)&buffer[position], section);
1001 position += strlen(section) + 1;
1002 strcpy((char*)&buffer[position], key);
1005 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1007 unsigned int a = tcp->sendPacket(buffer, totalLength);
1010 if (a != totalLength)
1013 MUTEX_UNLOCK(&mutex);
1019 MUTEX_UNLOCK(&mutex);
1022 char* toReturn = extractString();
1024 MUTEX_UNLOCK(&mutex);
1029 RecTimerList* VDR::getRecTimersList()
1033 *(unsigned long*)&buffer[0] = htonl(4);
1034 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
1037 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1039 int a = tcp->sendPacket(buffer, 8);
1043 MUTEX_UNLOCK(&mutex);
1051 MUTEX_UNLOCK(&mutex);
1055 RecTimerList* recTimerList = new RecTimerList();
1057 ULONG numTimers = extractULONG();
1060 RecTimer* newRecTimer;
1063 while (packetPos < packetLength)
1065 newRecTimer = new RecTimer();
1066 newRecTimer->active = extractULONG();
1067 newRecTimer->recording = extractULONG();
1068 newRecTimer->pending = extractULONG();
1069 newRecTimer->priority = extractULONG();
1070 newRecTimer->lifeTime = extractULONG();
1071 newRecTimer->channelNumber = extractULONG();
1072 newRecTimer->startTime = extractULONG();
1073 newRecTimer->stopTime = extractULONG();
1075 tempString = extractString();
1076 newRecTimer->setFile(tempString);
1077 delete[] tempString;
1079 recTimerList->push_back(newRecTimer);
1080 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1081 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1082 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1087 MUTEX_UNLOCK(&mutex);
1091 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1093 return recTimerList;
1096 ULONG VDR::setEventTimer(char* timerString)
1098 unsigned long totalLength = 8 + strlen(timerString) + 1;
1099 UCHAR* buffer = new UCHAR[totalLength];
1101 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1102 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1103 strcpy((char*)&buffer[8], timerString);
1106 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1108 unsigned int a = tcp->sendPacket(buffer, totalLength);
1111 if (a != totalLength)
1114 MUTEX_UNLOCK(&mutex);
1120 MUTEX_UNLOCK(&mutex);
1124 ULONG toReturn = extractULONG();
1126 MUTEX_UNLOCK(&mutex);