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 recman->setStats(extractULONG(), extractULONG(), extractULONG());
360 while (packetPos < packetLength)
362 start = extractULONG();
363 name = extractString();
364 fileName = extractString();
366 recman->addEntry(start, name, fileName);
373 MUTEX_UNLOCK(&mutex);
378 int VDR::deleteRecording(char* fileName)
380 unsigned long totalLength = 8 + strlen(fileName) + 1;
381 UCHAR* buffer = new UCHAR[totalLength];
383 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
384 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
385 strcpy((char*)&buffer[8], fileName);
388 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
390 unsigned int a = tcp->sendPacket(buffer, totalLength);
393 if (a != totalLength)
396 MUTEX_UNLOCK(&mutex);
402 MUTEX_UNLOCK(&mutex);
406 int toReturn = (int)extractULONG();
408 MUTEX_UNLOCK(&mutex);
413 char* VDR::getRecordingSummary(char* fileName)
415 unsigned long totalLength = 8 + strlen(fileName) + 1;
416 UCHAR* buffer = new UCHAR[totalLength];
418 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
419 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
420 strcpy((char*)&buffer[8], fileName);
423 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
425 unsigned int a = tcp->sendPacket(buffer, totalLength);
428 if (a != totalLength)
431 MUTEX_UNLOCK(&mutex);
437 MUTEX_UNLOCK(&mutex);
440 char* toReturn = extractString();
442 MUTEX_UNLOCK(&mutex);
447 ChannelList* VDR::getChannelsList(ULONG type)
451 *(unsigned long*)&buffer[0] = htonl(4);
452 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
455 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
457 int a = tcp->sendPacket(buffer, 8);
461 MUTEX_UNLOCK(&mutex);
469 MUTEX_UNLOCK(&mutex);
473 ChannelList* chanList = new ChannelList();
475 while (packetPos < packetLength)
477 Channel* chan = new Channel();
478 chan->number = extractULONG();
479 chan->type = extractULONG();
480 chan->name = extractString();
482 if (chan->type == type)
484 chanList->push_back(chan);
485 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
494 MUTEX_UNLOCK(&mutex);
499 int VDR::streamChannel(ULONG number)
503 *(unsigned long*)&buffer[0] = htonl(8);
504 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
505 *(unsigned long*)&buffer[8] = htonl(number);
508 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
510 int a = tcp->sendPacket(buffer, 12);
515 MUTEX_UNLOCK(&mutex);
521 MUTEX_UNLOCK(&mutex);
525 int toReturn = (int)extractULONG();
527 MUTEX_UNLOCK(&mutex);
532 int VDR::stopStreaming()
536 *(unsigned long*)&buffer[0] = htonl(4);
537 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
540 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
542 int a = tcp->sendPacket(buffer, 8);
547 MUTEX_UNLOCK(&mutex);
553 MUTEX_UNLOCK(&mutex);
557 int toReturn = (int)extractULONG();
559 MUTEX_UNLOCK(&mutex);
564 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
568 *(unsigned long*)&buffer[0] = htonl(16);
569 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
570 *(ULLONG*)&buffer[8] = htonll(position);
571 *(unsigned long*)&buffer[16] = htonl(maxAmount);
574 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
576 int a = tcp->sendPacket(buffer, 20);
580 MUTEX_UNLOCK(&mutex);
586 MUTEX_UNLOCK(&mutex);
592 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
594 MUTEX_UNLOCK(&mutex);
598 UCHAR* toReturn = packet;
599 *amountReceived = packetLength;
600 // Manually clean up instead of running freePacket to keep the block
604 MUTEX_UNLOCK(&mutex);
610 ULLONG VDR::streamRecording(char* fileName)
612 unsigned long totalLength = 8 + strlen(fileName) + 1;
613 UCHAR* buffer = new UCHAR[totalLength];
615 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
616 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
617 strcpy((char*)&buffer[8], fileName);
620 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
622 unsigned int a = tcp->sendPacket(buffer, totalLength);
625 if (a != totalLength)
628 MUTEX_UNLOCK(&mutex);
634 MUTEX_UNLOCK(&mutex);
638 ULLONG recordingLength = extractULLONG();
640 MUTEX_UNLOCK(&mutex);
642 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
644 return recordingLength;
647 ULLONG VDR::rescanRecording()
649 unsigned long totalLength = 8;
650 UCHAR* buffer = new UCHAR[totalLength];
652 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
653 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
656 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
658 unsigned int a = tcp->sendPacket(buffer, totalLength);
661 if (a != totalLength)
664 MUTEX_UNLOCK(&mutex);
670 MUTEX_UNLOCK(&mutex);
674 ULLONG recordingLength = extractULLONG();
676 MUTEX_UNLOCK(&mutex);
678 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
680 return recordingLength;
683 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
685 unsigned long totalLength = 12;
686 UCHAR* buffer = new UCHAR[totalLength];
688 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
689 *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
690 *(unsigned long*)&buffer[8] = htonl(frameNumber);
693 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
695 unsigned int a = tcp->sendPacket(buffer, totalLength);
698 if (a != totalLength)
701 MUTEX_UNLOCK(&mutex);
707 MUTEX_UNLOCK(&mutex);
711 ULLONG position = extractULLONG();
713 MUTEX_UNLOCK(&mutex);
715 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
720 ULONG VDR::frameNumberFromPosition(ULLONG position)
722 unsigned long totalLength = 16;
723 UCHAR* buffer = new UCHAR[totalLength];
725 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
726 *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
727 *(ULLONG*)&buffer[8] = htonll(position);
730 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
732 unsigned int a = tcp->sendPacket(buffer, totalLength);
735 if (a != totalLength)
738 MUTEX_UNLOCK(&mutex);
744 MUTEX_UNLOCK(&mutex);
748 ULONG framenumber = extractULONG();
750 MUTEX_UNLOCK(&mutex);
752 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
757 EventList* VDR::getChannelSchedule(ULONG number)
761 return getChannelSchedule(number, now, 24 * 60 * 60);
764 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
766 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
769 *(unsigned long*)&buffer[0] = htonl(16);
770 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
771 *(unsigned long*)&buffer[8] = htonl(number);
772 *(unsigned long*)&buffer[12] = htonl(start);
773 *(unsigned long*)&buffer[16] = htonl(duration);
776 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
778 int a = tcp->sendPacket(buffer, 20);
783 MUTEX_UNLOCK(&mutex);
789 MUTEX_UNLOCK(&mutex);
793 // received a ulong(0) - schedules error in the plugin
797 MUTEX_UNLOCK(&mutex);
801 EventList* eventList = new EventList();
803 while (packetPos < packetLength)
805 Event* event = new Event();
806 event->id = extractULONG();
807 event->time = extractULONG();
808 event->duration = extractULONG();
809 event->title = extractString();
810 event->subtitle = extractString();
811 event->description = extractString();
812 eventList->push_back(event);
813 // eventList->next();
817 MUTEX_UNLOCK(&mutex);
819 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
824 Log* l = Log::getInstance();
827 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
830 for(eventList->reset(); !eventList->eol(); eventList->next())
832 currentEvent = (Event*)eventList->getCurrent();
833 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
840 ULLONG VDR::getResumePoint(char* fileName)
842 if (!connected) return 0;
844 char* resumeString = configLoad("ResumeData", fileName);
845 if (!resumeString) return 0;
847 ULLONG toReturn = STRTOULL(resumeString, NULL, 10);
848 delete[] resumeString;
852 int VDR::configSave(char* section, char* key, const char* value)
854 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
855 UCHAR* buffer = new UCHAR[totalLength];
857 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
858 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
861 strcpy((char*)&buffer[position], section);
862 position += strlen(section) + 1;
863 strcpy((char*)&buffer[position], key);
864 position += strlen(key) + 1;
865 strcpy((char*)&buffer[position], value);
868 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
870 unsigned int a = tcp->sendPacket(buffer, totalLength);
873 if (a != totalLength)
876 MUTEX_UNLOCK(&mutex);
882 MUTEX_UNLOCK(&mutex);
886 int toReturn = (int)extractULONG();
888 MUTEX_UNLOCK(&mutex);
893 char* VDR::configLoad(char* section, char* key)
895 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
896 UCHAR* buffer = new UCHAR[totalLength];
898 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
899 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
902 strcpy((char*)&buffer[position], section);
903 position += strlen(section) + 1;
904 strcpy((char*)&buffer[position], key);
907 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
909 unsigned int a = tcp->sendPacket(buffer, totalLength);
912 if (a != totalLength)
915 MUTEX_UNLOCK(&mutex);
921 MUTEX_UNLOCK(&mutex);
924 char* toReturn = extractString();
926 MUTEX_UNLOCK(&mutex);
931 RecTimerList* VDR::getRecTimersList()
935 *(unsigned long*)&buffer[0] = htonl(4);
936 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
939 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
941 int a = tcp->sendPacket(buffer, 8);
945 MUTEX_UNLOCK(&mutex);
953 MUTEX_UNLOCK(&mutex);
957 RecTimerList* recTimerList = new RecTimerList();
959 ULONG numTimers = extractULONG();
962 RecTimer* newRecTimer;
965 while (packetPos < packetLength)
967 newRecTimer = new RecTimer();
968 newRecTimer->active = extractULONG();
969 newRecTimer->recording = extractULONG();
970 newRecTimer->pending = extractULONG();
971 newRecTimer->priority = extractULONG();
972 newRecTimer->lifeTime = extractULONG();
973 newRecTimer->channelNumber = extractULONG();
974 newRecTimer->startTime = extractULONG();
975 newRecTimer->stopTime = extractULONG();
977 tempString = extractString();
978 newRecTimer->setFile(tempString);
981 recTimerList->push_back(newRecTimer);
982 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
983 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
984 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
989 MUTEX_UNLOCK(&mutex);
993 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
998 ULONG VDR::setEventTimer(char* timerString)
1000 unsigned long totalLength = 8 + strlen(timerString) + 1;
1001 UCHAR* buffer = new UCHAR[totalLength];
1003 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1004 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1005 strcpy((char*)&buffer[8], timerString);
1008 if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1010 unsigned int a = tcp->sendPacket(buffer, totalLength);
1013 if (a != totalLength)
1016 MUTEX_UNLOCK(&mutex);
1022 MUTEX_UNLOCK(&mutex);
1026 ULONG toReturn = extractULONG();
1028 MUTEX_UNLOCK(&mutex);