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,TRUE,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";
87 DatagramSocket ds(port);
89 int haveAtLeastOne = 0;
96 logger->log("VDR", Log::NOTICE, "Broadcasting for server");
97 ds.send("255.255.255.255", 3024, message, strlen(message));
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;
135 sort(servers.begin(), servers.end(), ServerSorter());
138 void VDR::cancelFindingServer()
143 void VDR::setServerIP(char* newIP)
145 strcpy(serverIP, newIP);
152 if (tcp->connectTo(serverIP, 3024))
163 void VDR::disconnect()
168 Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
171 void VDR::setReceiveWindow(size_t size)
173 if (connected) tcp->setReceiveWindow(size);
176 ///////////////////////////////////////////////////////
180 packet = (UCHAR*)tcp->receivePacket();
186 packetLength = tcp->getDataLength();
190 void VDR::freePacket()
192 // Must be called if getPacket return 1, except in getBlock
199 int VDR::serverError()
201 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
205 char* VDR::extractString()
207 if (serverError()) return NULL;
209 int length = strlen((char*)&packet[packetPos]);
210 if ((packetPos + length) > packetLength) return NULL;
211 char* str = new char[length + 1];
212 strcpy(str, (char*)&packet[packetPos]);
213 packetPos += length + 1;
217 ULONG VDR::extractULONG()
219 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
220 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
221 packetPos += sizeof(ULONG);
225 ULLONG VDR::extractULLONG()
227 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
228 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
229 packetPos += sizeof(ULLONG);
233 long VDR::extractLONG()
235 if ((packetPos + sizeof(long)) > packetLength) return 0;
236 long l = ntohl(*(long*)&packet[packetPos]);
237 packetPos += sizeof(long);
241 /////////////////////////////////////////////////////////////////////////////
247 *(unsigned long*)&buffer[0] = htonl(10);
248 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
250 tcp->getMAC((char*)&buffer[8]);
256 MUTEX_UNLOCK(&mutex);
260 int a = tcp->sendPacket(buffer, 14);
264 MUTEX_UNLOCK(&mutex);
272 MUTEX_UNLOCK(&mutex);
276 ULONG vdrTime = extractULONG();
277 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
278 long vdrTimeOffset = extractLONG();
279 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
282 MUTEX_UNLOCK(&mutex);
284 // Set the time and zone on the MVP
287 struct timespec currentTime;
288 currentTime.tv_sec = vdrTime;
289 currentTime.tv_nsec = 0;
290 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
292 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
294 // now make a TZ variable and set it
298 if (vdrTimeOffset > 0) sign = '-';
301 vdrTimeOffset = abs(vdrTimeOffset);
303 hours = (int)vdrTimeOffset / 3600;
304 minutes = vdrTimeOffset % 3600;
306 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
308 minutes = (int)minutes / 60;
310 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
313 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
314 setenv("TZ", newTZ, 1);
316 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
322 Directory* VDR::getRecordingsList()
326 *(unsigned long*)&buffer[0] = htonl(4);
327 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
332 MUTEX_UNLOCK(&mutex);
336 int a = tcp->sendPacket(buffer, 8);
340 MUTEX_UNLOCK(&mutex);
348 MUTEX_UNLOCK(&mutex);
352 Directory* recDir = new Directory();
353 recDir->setName("/");
356 Directory::totalSpace = extractULONG();
357 Directory::freeSpace = extractULONG();
358 Directory::usedPercent = extractULONG();
362 while (packetPos < packetLength)
364 Recording* rec = new Recording();
366 rec->start = extractULONG();
368 string = extractString();
369 rec->setName(string);
372 rec->fileName = extractString();
376 char* dirName = rec->getDirName();
378 Directory* d = recDir->getDirByName(dirName);
383 // Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
384 recDir->dirList.push_back(d);
387 d->recList.push_back(rec);
391 recDir->recList.push_back(rec);
394 // Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
398 MUTEX_UNLOCK(&mutex);
399 // Sort the directory order
400 sort(recDir->dirList.begin(), recDir->dirList.end(), DirectorySorter());
402 // Sort all the sub lists
405 DirectoryList::iterator i;
406 for (i = recDir->dirList.begin(); i != recDir->dirList.end(); i++)
409 sort(sortDir->recList.begin(), sortDir->recList.end(), RecordingSorter());
412 // Sort the root level list
413 sort(recDir->recList.begin(), recDir->recList.end(), RecordingSorter());
418 int VDR::deleteRecording(char* fileName)
420 unsigned long totalLength = 8 + strlen(fileName) + 1;
421 UCHAR* buffer = new UCHAR[totalLength];
423 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
424 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
425 strcpy((char*)&buffer[8], fileName);
428 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
430 unsigned int a = tcp->sendPacket(buffer, totalLength);
433 if (a != totalLength)
436 MUTEX_UNLOCK(&mutex);
442 MUTEX_UNLOCK(&mutex);
446 int toReturn = (int)extractULONG();
448 MUTEX_UNLOCK(&mutex);
453 char* VDR::getRecordingSummary(char* fileName)
455 unsigned long totalLength = 8 + strlen(fileName) + 1;
456 UCHAR* buffer = new UCHAR[totalLength];
458 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
459 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
460 strcpy((char*)&buffer[8], fileName);
463 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
465 unsigned int a = tcp->sendPacket(buffer, totalLength);
468 if (a != totalLength)
471 MUTEX_UNLOCK(&mutex);
477 MUTEX_UNLOCK(&mutex);
480 char* toReturn = extractString();
482 MUTEX_UNLOCK(&mutex);
487 ChannelList* VDR::getChannelsList(ULONG type)
491 *(unsigned long*)&buffer[0] = htonl(4);
492 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
495 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
497 int a = tcp->sendPacket(buffer, 8);
501 MUTEX_UNLOCK(&mutex);
509 MUTEX_UNLOCK(&mutex);
513 ChannelList* chanList = new ChannelList();
515 while (packetPos < packetLength)
517 Channel* chan = new Channel();
518 chan->number = extractULONG();
519 chan->type = extractULONG();
520 chan->name = extractString();
522 if (chan->type == type)
524 chanList->push_back(chan);
525 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
534 MUTEX_UNLOCK(&mutex);
539 int VDR::streamChannel(ULONG number)
543 *(unsigned long*)&buffer[0] = htonl(8);
544 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
545 *(unsigned long*)&buffer[8] = htonl(number);
548 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
550 int a = tcp->sendPacket(buffer, 12);
555 MUTEX_UNLOCK(&mutex);
561 MUTEX_UNLOCK(&mutex);
565 int toReturn = (int)extractULONG();
567 MUTEX_UNLOCK(&mutex);
572 int VDR::stopStreaming()
576 *(unsigned long*)&buffer[0] = htonl(4);
577 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
580 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
582 int a = tcp->sendPacket(buffer, 8);
587 MUTEX_UNLOCK(&mutex);
593 MUTEX_UNLOCK(&mutex);
597 int toReturn = (int)extractULONG();
599 MUTEX_UNLOCK(&mutex);
604 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
608 *(unsigned long*)&buffer[0] = htonl(16);
609 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
610 *(ULLONG*)&buffer[8] = htonll(position);
611 *(unsigned long*)&buffer[16] = htonl(maxAmount);
614 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
616 int a = tcp->sendPacket(buffer, 20);
620 MUTEX_UNLOCK(&mutex);
626 MUTEX_UNLOCK(&mutex);
632 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
634 MUTEX_UNLOCK(&mutex);
638 UCHAR* toReturn = packet;
639 *amountReceived = packetLength;
640 // Manually clean up instead of running freePacket to keep the block
644 MUTEX_UNLOCK(&mutex);
650 ULLONG VDR::streamRecording(Recording* rec)
652 unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
653 UCHAR* buffer = new UCHAR[totalLength];
655 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
656 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
657 strcpy((char*)&buffer[8], rec->fileName);
660 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
662 unsigned int a = tcp->sendPacket(buffer, totalLength);
665 if (a != totalLength)
668 MUTEX_UNLOCK(&mutex);
674 MUTEX_UNLOCK(&mutex);
678 ULLONG recordingLength = extractULLONG();
680 MUTEX_UNLOCK(&mutex);
682 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
684 return recordingLength;
687 ULLONG VDR::rescanRecording()
689 unsigned long totalLength = 8;
690 UCHAR* buffer = new UCHAR[totalLength];
692 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
693 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
696 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
698 unsigned int a = tcp->sendPacket(buffer, totalLength);
701 if (a != totalLength)
704 MUTEX_UNLOCK(&mutex);
710 MUTEX_UNLOCK(&mutex);
714 ULLONG recordingLength = extractULLONG();
716 MUTEX_UNLOCK(&mutex);
718 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
720 return recordingLength;
723 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
725 unsigned long totalLength = 12;
726 UCHAR* buffer = new UCHAR[totalLength];
728 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
729 *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
730 *(unsigned long*)&buffer[8] = htonl(frameNumber);
733 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
735 unsigned int a = tcp->sendPacket(buffer, totalLength);
738 if (a != totalLength)
741 MUTEX_UNLOCK(&mutex);
747 MUTEX_UNLOCK(&mutex);
751 ULLONG position = extractULLONG();
753 MUTEX_UNLOCK(&mutex);
755 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
760 EventList* VDR::getChannelSchedule(ULONG number)
764 return getChannelSchedule(number, now, 24 * 60 * 60);
767 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
769 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
772 *(unsigned long*)&buffer[0] = htonl(16);
773 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
774 *(unsigned long*)&buffer[8] = htonl(number);
775 *(unsigned long*)&buffer[12] = htonl(start);
776 *(unsigned long*)&buffer[16] = htonl(duration);
779 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
781 int a = tcp->sendPacket(buffer, 20);
786 MUTEX_UNLOCK(&mutex);
792 MUTEX_UNLOCK(&mutex);
796 // received a ulong(0) - schedules error in the plugin
800 MUTEX_UNLOCK(&mutex);
804 EventList* eventList = new EventList();
806 while (packetPos < packetLength)
808 Event* event = new Event();
809 event->id = extractULONG();
810 event->time = extractULONG();
811 event->duration = extractULONG();
812 event->title = extractString();
813 event->subtitle = extractString();
814 event->description = extractString();
815 eventList->push_back(event);
816 // eventList->next();
820 MUTEX_UNLOCK(&mutex);
822 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
827 Log* l = Log::getInstance();
830 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
833 for(eventList->reset(); !eventList->eol(); eventList->next())
835 currentEvent = (Event*)eventList->getCurrent();
836 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
843 ULLONG VDR::getResumePoint(char* fileName)
845 if (!connected) return 0;
847 char* resumeString = configLoad("ResumeData", fileName);
848 if (!resumeString) return 0;
850 ULLONG toReturn = STRTOULL(resumeString, NULL, 10);
851 delete[] resumeString;
855 int VDR::configSave(char* section, char* key, const char* value)
857 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
858 UCHAR* buffer = new UCHAR[totalLength];
860 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
861 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
864 strcpy((char*)&buffer[position], section);
865 position += strlen(section) + 1;
866 strcpy((char*)&buffer[position], key);
867 position += strlen(key) + 1;
868 strcpy((char*)&buffer[position], value);
871 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
873 unsigned int a = tcp->sendPacket(buffer, totalLength);
876 if (a != totalLength)
879 MUTEX_UNLOCK(&mutex);
885 MUTEX_UNLOCK(&mutex);
889 int toReturn = (int)extractULONG();
891 MUTEX_UNLOCK(&mutex);
896 char* VDR::configLoad(char* section, char* key)
898 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
899 UCHAR* buffer = new UCHAR[totalLength];
901 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
902 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
905 strcpy((char*)&buffer[position], section);
906 position += strlen(section) + 1;
907 strcpy((char*)&buffer[position], key);
910 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
912 unsigned int a = tcp->sendPacket(buffer, totalLength);
915 if (a != totalLength)
918 MUTEX_UNLOCK(&mutex);
924 MUTEX_UNLOCK(&mutex);
927 char* toReturn = extractString();
929 MUTEX_UNLOCK(&mutex);
934 RecTimerList* VDR::getRecTimersList()
938 *(unsigned long*)&buffer[0] = htonl(4);
939 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
942 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
944 int a = tcp->sendPacket(buffer, 8);
948 MUTEX_UNLOCK(&mutex);
956 MUTEX_UNLOCK(&mutex);
960 RecTimerList* recTimerList = new RecTimerList();
962 ULONG numTimers = extractULONG();
965 RecTimer* newRecTimer;
968 while (packetPos < packetLength)
970 newRecTimer = new RecTimer();
971 newRecTimer->active = extractULONG();
972 newRecTimer->recording = extractULONG();
973 newRecTimer->pending = extractULONG();
974 newRecTimer->priority = extractULONG();
975 newRecTimer->lifeTime = extractULONG();
976 newRecTimer->channelNumber = extractULONG();
977 newRecTimer->startTime = extractULONG();
978 newRecTimer->stopTime = extractULONG();
980 tempString = extractString();
981 newRecTimer->setFile(tempString);
984 recTimerList->push_back(newRecTimer);
985 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
986 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
987 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
992 MUTEX_UNLOCK(&mutex);
996 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1001 ULONG VDR::setEventTimer(char* timerString)
1003 unsigned long totalLength = 8 + strlen(timerString) + 1;
1004 UCHAR* buffer = new UCHAR[totalLength];
1006 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1007 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1008 strcpy((char*)&buffer[8], timerString);
1011 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1013 unsigned int a = tcp->sendPacket(buffer, totalLength);
1016 if (a != totalLength)
1019 MUTEX_UNLOCK(&mutex);
1025 MUTEX_UNLOCK(&mutex);
1029 ULONG toReturn = extractULONG();
1031 MUTEX_UNLOCK(&mutex);