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;
97 logger->log("VDR", Log::NOTICE, "Broadcasting for server");
98 ds.send("255.255.255.255", 3024, message, strlen(message));
100 retval = ds.waitforMessage(waitType);
102 if (retval == 2) // we got a reply
104 if (!strcmp(ds.getData(), "VOMP")) // echo.....
111 newServer.ip = new char[16];
112 strcpy(newServer.ip, ds.getFromIPA());
114 if (ds.getDataLength() == 0)
116 newServer.name = new char[1];
117 newServer.name[0] = '\0';
121 newServer.name = new char[strlen(ds.getData())+1];
122 strcpy(newServer.name, ds.getData());
125 servers.push_back(newServer);
132 if (haveAtLeastOne) break;
136 sort(servers.begin(), servers.end(), ServerSorter());
139 void VDR::cancelFindingServer()
144 void VDR::setServerIP(char* newIP)
146 strcpy(serverIP, newIP);
153 if (tcp->connectTo(serverIP, 3024))
164 void VDR::disconnect()
169 Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
172 void VDR::setReceiveWindow(size_t size)
174 if (connected) tcp->setReceiveWindow(size);
177 ///////////////////////////////////////////////////////
181 packet = (UCHAR*)tcp->receivePacket();
187 packetLength = tcp->getDataLength();
191 void VDR::freePacket()
193 // Must be called if getPacket return 1, except in getBlock
200 int VDR::serverError()
202 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
206 char* VDR::extractString()
208 if (serverError()) return NULL;
210 int length = strlen((char*)&packet[packetPos]);
211 if ((packetPos + length) > packetLength) return NULL;
212 char* str = new char[length + 1];
213 strcpy(str, (char*)&packet[packetPos]);
214 packetPos += length + 1;
218 ULONG VDR::extractULONG()
220 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
221 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
222 packetPos += sizeof(ULONG);
226 ULLONG VDR::extractULLONG()
228 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
229 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
230 packetPos += sizeof(ULLONG);
234 long VDR::extractLONG()
236 if ((packetPos + sizeof(long)) > packetLength) return 0;
237 long l = ntohl(*(long*)&packet[packetPos]);
238 packetPos += sizeof(long);
242 /////////////////////////////////////////////////////////////////////////////
248 *(unsigned long*)&buffer[0] = htonl(10);
249 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
251 tcp->getMAC((char*)&buffer[8]);
257 MUTEX_UNLOCK(&mutex);
261 int a = tcp->sendPacket(buffer, 14);
265 MUTEX_UNLOCK(&mutex);
273 MUTEX_UNLOCK(&mutex);
277 ULONG vdrTime = extractULONG();
278 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
279 long vdrTimeOffset = extractLONG();
280 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
283 MUTEX_UNLOCK(&mutex);
285 // Set the time and zone on the MVP
288 struct timespec currentTime;
289 currentTime.tv_sec = vdrTime;
290 currentTime.tv_nsec = 0;
291 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
293 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
295 // now make a TZ variable and set it
299 if (vdrTimeOffset > 0) sign = '-';
302 vdrTimeOffset = abs(vdrTimeOffset);
304 hours = (int)vdrTimeOffset / 3600;
305 minutes = vdrTimeOffset % 3600;
307 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
309 minutes = (int)minutes / 60;
311 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
314 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
315 setenv("TZ", newTZ, 1);
317 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
323 Directory* VDR::getRecordingsList()
327 *(unsigned long*)&buffer[0] = htonl(4);
328 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
333 MUTEX_UNLOCK(&mutex);
337 int a = tcp->sendPacket(buffer, 8);
341 MUTEX_UNLOCK(&mutex);
349 MUTEX_UNLOCK(&mutex);
353 Directory* recDir = new Directory();
354 recDir->setName("/");
357 Directory::totalSpace = extractULONG();
358 Directory::freeSpace = extractULONG();
359 Directory::usedPercent = extractULONG();
363 while (packetPos < packetLength)
365 Recording* rec = new Recording();
367 rec->start = extractULONG();
369 string = extractString();
370 rec->setName(string);
373 rec->fileName = extractString();
377 char* dirName = rec->getDirName();
379 Directory* d = recDir->getDirByName(dirName);
384 // Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
385 recDir->dirList.push_back(d);
388 d->recList.push_back(rec);
392 recDir->recList.push_back(rec);
395 // Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
399 MUTEX_UNLOCK(&mutex);
400 // Sort the directory order
401 sort(recDir->dirList.begin(), recDir->dirList.end(), DirectorySorter());
403 // Sort all the sub lists
406 DirectoryList::iterator i;
407 for (i = recDir->dirList.begin(); i != recDir->dirList.end(); i++)
410 sort(sortDir->recList.begin(), sortDir->recList.end(), RecordingSorter());
413 // Sort the root level list
414 sort(recDir->recList.begin(), recDir->recList.end(), RecordingSorter());
419 int VDR::deleteRecording(char* fileName)
421 unsigned long totalLength = 8 + strlen(fileName) + 1;
422 UCHAR* buffer = new UCHAR[totalLength];
424 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
425 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
426 strcpy((char*)&buffer[8], fileName);
429 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
431 unsigned int a = tcp->sendPacket(buffer, totalLength);
434 if (a != totalLength)
437 MUTEX_UNLOCK(&mutex);
443 MUTEX_UNLOCK(&mutex);
447 int toReturn = (int)extractULONG();
449 MUTEX_UNLOCK(&mutex);
454 char* VDR::getRecordingSummary(char* fileName)
456 unsigned long totalLength = 8 + strlen(fileName) + 1;
457 UCHAR* buffer = new UCHAR[totalLength];
459 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
460 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
461 strcpy((char*)&buffer[8], fileName);
464 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
466 unsigned int a = tcp->sendPacket(buffer, totalLength);
469 if (a != totalLength)
472 MUTEX_UNLOCK(&mutex);
478 MUTEX_UNLOCK(&mutex);
481 char* toReturn = extractString();
483 MUTEX_UNLOCK(&mutex);
488 ChannelList* VDR::getChannelsList(ULONG type)
492 *(unsigned long*)&buffer[0] = htonl(4);
493 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
496 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
498 int a = tcp->sendPacket(buffer, 8);
502 MUTEX_UNLOCK(&mutex);
510 MUTEX_UNLOCK(&mutex);
514 ChannelList* chanList = new ChannelList();
516 while (packetPos < packetLength)
518 Channel* chan = new Channel();
519 chan->number = extractULONG();
520 chan->type = extractULONG();
521 chan->name = extractString();
523 if (chan->type == type)
525 chanList->push_back(chan);
526 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
535 MUTEX_UNLOCK(&mutex);
540 int VDR::streamChannel(ULONG number)
544 *(unsigned long*)&buffer[0] = htonl(8);
545 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
546 *(unsigned long*)&buffer[8] = htonl(number);
549 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
551 int a = tcp->sendPacket(buffer, 12);
556 MUTEX_UNLOCK(&mutex);
562 MUTEX_UNLOCK(&mutex);
566 int toReturn = (int)extractULONG();
568 MUTEX_UNLOCK(&mutex);
573 int VDR::stopStreaming()
577 *(unsigned long*)&buffer[0] = htonl(4);
578 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
581 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
583 int a = tcp->sendPacket(buffer, 8);
588 MUTEX_UNLOCK(&mutex);
594 MUTEX_UNLOCK(&mutex);
598 int toReturn = (int)extractULONG();
600 MUTEX_UNLOCK(&mutex);
605 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
609 *(unsigned long*)&buffer[0] = htonl(16);
610 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
611 *(ULLONG*)&buffer[8] = htonll(position);
612 *(unsigned long*)&buffer[16] = htonl(maxAmount);
615 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
617 int a = tcp->sendPacket(buffer, 20);
621 MUTEX_UNLOCK(&mutex);
627 MUTEX_UNLOCK(&mutex);
633 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
635 MUTEX_UNLOCK(&mutex);
639 UCHAR* toReturn = packet;
640 *amountReceived = packetLength;
641 // Manually clean up instead of running freePacket to keep the block
645 MUTEX_UNLOCK(&mutex);
651 ULLONG VDR::streamRecording(Recording* rec)
653 unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
654 UCHAR* buffer = new UCHAR[totalLength];
656 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
657 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
658 strcpy((char*)&buffer[8], rec->fileName);
661 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
663 unsigned int a = tcp->sendPacket(buffer, totalLength);
666 if (a != totalLength)
669 MUTEX_UNLOCK(&mutex);
675 MUTEX_UNLOCK(&mutex);
679 ULLONG recordingLength = extractULLONG();
681 MUTEX_UNLOCK(&mutex);
683 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
685 return recordingLength;
688 ULLONG VDR::rescanRecording()
690 unsigned long totalLength = 8;
691 UCHAR* buffer = new UCHAR[totalLength];
693 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
694 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
697 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
699 unsigned int a = tcp->sendPacket(buffer, totalLength);
702 if (a != totalLength)
705 MUTEX_UNLOCK(&mutex);
711 MUTEX_UNLOCK(&mutex);
715 ULLONG recordingLength = extractULLONG();
717 MUTEX_UNLOCK(&mutex);
719 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
721 return recordingLength;
724 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
726 unsigned long totalLength = 12;
727 UCHAR* buffer = new UCHAR[totalLength];
729 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
730 *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
731 *(unsigned long*)&buffer[8] = htonl(frameNumber);
734 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
736 unsigned int a = tcp->sendPacket(buffer, totalLength);
739 if (a != totalLength)
742 MUTEX_UNLOCK(&mutex);
748 MUTEX_UNLOCK(&mutex);
752 ULLONG position = extractULLONG();
754 MUTEX_UNLOCK(&mutex);
756 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
761 ULONG VDR::frameNumberFromPosition(ULLONG position)
763 unsigned long totalLength = 16;
764 UCHAR* buffer = new UCHAR[totalLength];
766 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
767 *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
768 *(ULLONG*)&buffer[8] = htonll(position);
771 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
773 unsigned int a = tcp->sendPacket(buffer, totalLength);
776 if (a != totalLength)
779 MUTEX_UNLOCK(&mutex);
785 MUTEX_UNLOCK(&mutex);
789 ULONG framenumber = extractULONG();
791 MUTEX_UNLOCK(&mutex);
793 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
798 EventList* VDR::getChannelSchedule(ULONG number)
802 return getChannelSchedule(number, now, 24 * 60 * 60);
805 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
807 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
810 *(unsigned long*)&buffer[0] = htonl(16);
811 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
812 *(unsigned long*)&buffer[8] = htonl(number);
813 *(unsigned long*)&buffer[12] = htonl(start);
814 *(unsigned long*)&buffer[16] = htonl(duration);
817 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
819 int a = tcp->sendPacket(buffer, 20);
824 MUTEX_UNLOCK(&mutex);
830 MUTEX_UNLOCK(&mutex);
834 // received a ulong(0) - schedules error in the plugin
838 MUTEX_UNLOCK(&mutex);
842 EventList* eventList = new EventList();
844 while (packetPos < packetLength)
846 Event* event = new Event();
847 event->id = extractULONG();
848 event->time = extractULONG();
849 event->duration = extractULONG();
850 event->title = extractString();
851 event->subtitle = extractString();
852 event->description = extractString();
853 eventList->push_back(event);
854 // eventList->next();
858 MUTEX_UNLOCK(&mutex);
860 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
865 Log* l = Log::getInstance();
868 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
871 for(eventList->reset(); !eventList->eol(); eventList->next())
873 currentEvent = (Event*)eventList->getCurrent();
874 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
881 ULLONG VDR::getResumePoint(char* fileName)
883 if (!connected) return 0;
885 char* resumeString = configLoad("ResumeData", fileName);
886 if (!resumeString) return 0;
888 ULLONG toReturn = STRTOULL(resumeString, NULL, 10);
889 delete[] resumeString;
893 int VDR::configSave(char* section, char* key, const char* value)
895 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
896 UCHAR* buffer = new UCHAR[totalLength];
898 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
899 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
902 strcpy((char*)&buffer[position], section);
903 position += strlen(section) + 1;
904 strcpy((char*)&buffer[position], key);
905 position += strlen(key) + 1;
906 strcpy((char*)&buffer[position], value);
909 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
911 unsigned int a = tcp->sendPacket(buffer, totalLength);
914 if (a != totalLength)
917 MUTEX_UNLOCK(&mutex);
923 MUTEX_UNLOCK(&mutex);
927 int toReturn = (int)extractULONG();
929 MUTEX_UNLOCK(&mutex);
934 char* VDR::configLoad(char* section, char* key)
936 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
937 UCHAR* buffer = new UCHAR[totalLength];
939 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
940 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
943 strcpy((char*)&buffer[position], section);
944 position += strlen(section) + 1;
945 strcpy((char*)&buffer[position], key);
948 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
950 unsigned int a = tcp->sendPacket(buffer, totalLength);
953 if (a != totalLength)
956 MUTEX_UNLOCK(&mutex);
962 MUTEX_UNLOCK(&mutex);
965 char* toReturn = extractString();
967 MUTEX_UNLOCK(&mutex);
972 RecTimerList* VDR::getRecTimersList()
976 *(unsigned long*)&buffer[0] = htonl(4);
977 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
980 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
982 int a = tcp->sendPacket(buffer, 8);
986 MUTEX_UNLOCK(&mutex);
994 MUTEX_UNLOCK(&mutex);
998 RecTimerList* recTimerList = new RecTimerList();
1000 ULONG numTimers = extractULONG();
1003 RecTimer* newRecTimer;
1006 while (packetPos < packetLength)
1008 newRecTimer = new RecTimer();
1009 newRecTimer->active = extractULONG();
1010 newRecTimer->recording = extractULONG();
1011 newRecTimer->pending = extractULONG();
1012 newRecTimer->priority = extractULONG();
1013 newRecTimer->lifeTime = extractULONG();
1014 newRecTimer->channelNumber = extractULONG();
1015 newRecTimer->startTime = extractULONG();
1016 newRecTimer->stopTime = extractULONG();
1018 tempString = extractString();
1019 newRecTimer->setFile(tempString);
1020 delete[] tempString;
1022 recTimerList->push_back(newRecTimer);
1023 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1024 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1025 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1030 MUTEX_UNLOCK(&mutex);
1034 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1036 return recTimerList;
1039 ULONG VDR::setEventTimer(char* timerString)
1041 unsigned long totalLength = 8 + strlen(timerString) + 1;
1042 UCHAR* buffer = new UCHAR[totalLength];
1044 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1045 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1046 strcpy((char*)&buffer[8], timerString);
1049 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1051 unsigned int a = tcp->sendPacket(buffer, totalLength);
1054 if (a != totalLength)
1057 MUTEX_UNLOCK(&mutex);
1063 MUTEX_UNLOCK(&mutex);
1067 ULONG toReturn = extractULONG();
1069 MUTEX_UNLOCK(&mutex);