]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Another stab at radio support, fix for chasing playback
[vompclient.git] / vdr.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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
19 */
20
21 #include "vdr.h"
22
23 VDR* VDR::instance = NULL;
24
25 VDR::VDR()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   findingServer = 0;
31   tcp = NULL;
32   pthread_mutex_init(&mutex, NULL);
33 }
34
35 VDR::~VDR()
36 {
37   instance = NULL;
38   if (initted) shutdown();
39 }
40
41 VDR* VDR::getInstance()
42 {
43   return instance;
44 }
45
46 int VDR::init(int tport)
47 {
48   if (initted) return 0;
49   initted = 1;
50   port = tport;
51   logger = Log::getInstance();
52   return 1;
53 }
54
55 int VDR::shutdown()
56 {
57   if (!initted) return 0;
58   initted = 0;
59   disconnect();
60   return 1;
61 }
62
63 void VDR::findServers(std::vector<char*>& serverIPs)
64 {
65   findingServer = 1;
66   char* message = "VOMP CLIENT";
67   DatagramSocket ds(port);
68
69   int haveAtLeastOne = 0;
70   char* newIP;
71   int retval;
72   int waitType = 1;
73   while(findingServer)
74   {
75     if (waitType == 1)
76     {
77       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
78       ds.send("255.255.255.255", 3024, message, strlen(message));
79     }
80     retval = ds.waitforMessage(waitType);
81
82     if (retval == 2) // we got a reply
83     {
84       if (strcmp(ds.getData(), "VOMP SERVER")) // echo.....
85       {
86         waitType = 2;
87       }
88       else
89       {
90         newIP = new char[16];
91         strcpy(newIP, ds.getFromIPA());
92         serverIPs.push_back(newIP);
93         waitType = 2;
94         haveAtLeastOne = 1;
95       }
96     }
97     else
98     {
99       if (haveAtLeastOne) break;
100       waitType = 1;
101     }
102   }
103 }
104
105 void VDR::cancelFindingServer()
106 {
107   findingServer = 0;
108 }
109
110 void VDR::setServerIP(char* newIP)
111 {
112   strcpy(serverIP, newIP);
113 }
114
115 int VDR::connect()
116 {
117   if (tcp) delete tcp;
118   tcp = new TCP();
119   return tcp->connectTo(serverIP, 3024);
120 }
121
122 void VDR::disconnect()
123 {
124   if (tcp) delete tcp;
125   tcp = NULL;
126   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
127 }
128
129 long VDR::getSimpleReply()
130 {
131   unsigned char* p = (unsigned char*)tcp->receivePacket();
132   if (!p) return -1;
133
134   Log::getInstance()->log("VDR", Log::DEBUG, "tcp data length = %i", tcp->getDataLength());
135
136   if (tcp->getDataLength() != 4)
137   {
138     free(p);
139     return -1;
140   }
141
142   ULONG reply = ntohl(*(ULONG*)p);
143
144   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said %li", reply);
145
146   free(p);
147
148   return reply;
149 }
150
151 char* VDR::getStringReply()
152 {
153   unsigned char* p = (unsigned char*)tcp->receivePacket();
154   if (!p) return NULL;
155
156   int dataLength = tcp->getDataLength();
157
158   Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength);
159
160   int count = 0;
161
162   char* returnText;
163   int tLength;
164
165   tLength = strlen((char*)&p[count]);
166   returnText = new char[tLength + 1];
167   strcpy(returnText, (char*)&p[count]);
168   count += tLength + 1;
169
170   free(p);
171
172   return returnText;
173 }
174
175 /////////////////////////////////////////////////////////////////////////////
176
177 int VDR::doLogin()
178 {
179   UCHAR buffer[8];
180
181   *(unsigned long*)&buffer[0] = htonl(4);
182   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
183
184   pthread_mutex_lock(&mutex);
185   int a = tcp->sendPacket(buffer, 8);
186   if (a != 8)
187   {
188     pthread_mutex_unlock(&mutex);
189     return 0;
190   }
191
192   // reply
193
194   UCHAR* p = tcp->receivePacket();
195   pthread_mutex_unlock(&mutex);
196   if (!p) return 0;
197
198   int count = 0;
199
200   unsigned long vdrTime = ntohl(*(unsigned long*)&p[count]);
201   count += sizeof(unsigned long);
202   Log::getInstance()->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
203
204   struct timespec currentTime;
205   currentTime.tv_sec = vdrTime;
206   currentTime.tv_nsec = 0;
207   int b = clock_settime(CLOCK_REALTIME, &currentTime);
208
209   Log::getInstance()->log("VDR", Log::DEBUG, "set clock = %u", b);
210
211   // now make a TZ variable and set it
212   signed int vdrTimeOffset = ntohl(*(signed int*)&p[count]);
213   Log::getInstance()->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
214
215   char sign;
216   int hours;
217   int minutes;
218   if (vdrTimeOffset > 0) sign = '-';
219   else sign = '+';
220
221   vdrTimeOffset = abs(vdrTimeOffset);
222
223   hours = (int)vdrTimeOffset / 3600;
224   minutes = vdrTimeOffset % 3600;
225
226   Log::getInstance()->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
227
228   minutes = (int)minutes / 60;
229
230   Log::getInstance()->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
231
232   char newTZ[30];
233   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
234   setenv("TZ", newTZ, 1);
235
236   Log::getInstance()->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
237
238   free(p);
239   return 1;
240 }
241
242 Directory* VDR::getRecordingsList()
243 {
244   UCHAR buffer[8];
245
246   *(unsigned long*)&buffer[0] = htonl(4);
247   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
248
249   pthread_mutex_lock(&mutex);
250   int a = tcp->sendPacket(buffer, 8);
251   if (a != 8)
252   {
253     pthread_mutex_unlock(&mutex);
254     return NULL;
255   }
256
257   // reply
258
259   unsigned char* p = (unsigned char*)tcp->receivePacket();
260   pthread_mutex_unlock(&mutex);
261   if (!p) return 0;
262
263   Directory* recDir = new Directory();
264   recDir->setName("/");
265   recDir->isRoot = 1;
266
267   int dataLength = tcp->getDataLength();
268
269   Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength);
270
271   int count = 0;
272
273   Directory::totalSpace = (*(ULONG*)&p[count]);
274   count += sizeof(ULONG);
275   Directory::freeSpace = (*(ULONG*)&p[count]);
276   count += sizeof(ULONG);
277   Directory::usedPercent = (*(ULONG*)&p[count]);
278   count += sizeof(ULONG);
279
280   int tLength;
281
282   while (count < dataLength)
283   {
284     Recording* rec = new Recording();
285     rec->start = ntohl(*(unsigned long*)&p[count]);
286     count += 4;
287
288     tLength = strlen((char*)&p[count]);
289     rec->setName((char*)&p[count]);
290
291 //    rec->name = new char[tLength + 1];
292 //    strcpy(rec->name, (char*)&p[count]);
293     count += tLength + 1;
294
295     tLength = strlen((char*)&p[count]);
296     rec->fileName = new char[tLength + 1];
297     strcpy(rec->fileName, (char*)&p[count]);
298     count += tLength + 1;
299
300     if(rec->isInDir())
301     {
302       char* dirName = rec->getDirName();
303
304       Directory* d = recDir->getDirByName(dirName);
305       if (!d)
306       {
307         d = new Directory();
308         d->setName(dirName);
309         Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
310         recDir->dirList->add(d);
311       }
312
313       d->recList->add(rec);
314       d->recList->next();
315     }
316     else
317     {
318       recDir->recList->add(rec);
319       recDir->recList->next();
320     }
321
322     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a recording to list. %lu %s", rec->start, rec->getProgName());
323   }
324
325   free(p);
326
327   return recDir;
328 }
329
330 int VDR::deleteRecording(char* fileName)
331 {
332   unsigned long totalLength = 8 + strlen(fileName) + 1;
333   UCHAR buffer[totalLength];
334
335   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
336   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
337   strcpy((char*)&buffer[8], fileName);
338
339   pthread_mutex_lock(&mutex);
340   unsigned int a = tcp->sendPacket(buffer, totalLength);
341   if (a != totalLength)
342   {
343     pthread_mutex_unlock(&mutex);
344     return 0;
345   }
346
347   int toReturn = getSimpleReply();
348   pthread_mutex_unlock(&mutex);
349   return toReturn;
350 }
351
352 char* VDR::getRecordingSummary(char* fileName)
353 {
354   unsigned long totalLength = 8 + strlen(fileName) + 1;
355   UCHAR buffer[totalLength];
356
357   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
358   *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
359   strcpy((char*)&buffer[8], fileName);
360
361   pthread_mutex_lock(&mutex);
362   unsigned int a = tcp->sendPacket(buffer, totalLength);
363   if (a != totalLength)
364   {
365     pthread_mutex_unlock(&mutex);
366     return NULL;
367   }
368
369   char* toReturn = getStringReply();
370   pthread_mutex_unlock(&mutex);
371   return toReturn;
372 }
373
374 List* VDR::getChannelsList(ULONG type)
375 {
376   UCHAR buffer[8];
377
378   *(unsigned long*)&buffer[0] = htonl(4);
379   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
380
381   pthread_mutex_lock(&mutex);
382   int a = tcp->sendPacket(buffer, 8);
383   if (a != 8)
384   {
385     pthread_mutex_unlock(&mutex);
386     return NULL;
387   }
388
389   // reply
390
391   unsigned char* p = (unsigned char*)tcp->receivePacket();
392   pthread_mutex_unlock(&mutex);
393   if (!p) return NULL;
394
395   List* chanList = new List();
396
397   int dataLength = tcp->getDataLength();
398
399   Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength);
400
401   int count = 0;
402
403   int tLength;
404
405   while (count < dataLength)
406   {
407     Channel* chan = new Channel();
408     chan->number = ntohl(*(unsigned long*)&p[count]);
409     count += 4;
410     chan->type = ntohl(*(unsigned long*)&p[count]);
411     count += 4;
412
413     tLength = strlen((char*)&p[count]);
414     chan->name = new char[tLength + 1];
415     strcpy(chan->name, (char*)&p[count]);
416     count += tLength + 1;
417
418     if (chan->type == type)
419     {
420       chanList->add(chan);
421       chanList->next();
422       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
423     }
424     else
425     {
426       delete chan;
427     }
428   }
429
430   free(p);
431
432   return chanList;
433 }
434
435 int VDR::streamChannel(ULONG number)
436 {
437   UCHAR buffer[12];
438
439   *(unsigned long*)&buffer[0] = htonl(8);
440   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
441   *(unsigned long*)&buffer[8] = htonl(number);
442
443   pthread_mutex_lock(&mutex);
444   int a = tcp->sendPacket(buffer, 12);
445
446   if (a != 12)
447   {
448     pthread_mutex_unlock(&mutex);
449     return 0;
450   }
451
452   int toReturn = getSimpleReply();
453   pthread_mutex_unlock(&mutex);
454   return toReturn;
455 }
456
457 int VDR::stopStreaming()
458 {
459   UCHAR buffer[8];
460
461   *(unsigned long*)&buffer[0] = htonl(4);
462   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
463
464   pthread_mutex_lock(&mutex);
465   int a = tcp->sendPacket(buffer, 8);
466
467   if (a != 8)
468   {
469     pthread_mutex_unlock(&mutex);
470     return 0;
471   }
472
473   int toReturn = getSimpleReply();
474   pthread_mutex_unlock(&mutex);
475   return toReturn;
476 }
477
478 int VDR::getBlock(UCHAR* buf, ULLONG position, int amount)
479 {
480   UCHAR buffer[20];
481
482   *(unsigned long*)&buffer[0] = htonl(16);
483   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
484   *(ULLONG*)&buffer[8]        = htonll(position);
485   *(unsigned long*)&buffer[16] = htonl(amount);
486
487   pthread_mutex_lock(&mutex);
488   int a = tcp->sendPacket(buffer, 20);
489   if (a != 20)
490   {
491     pthread_mutex_unlock(&mutex);
492     return 0;
493   }
494
495   unsigned char* p = (unsigned char*)tcp->receivePacket();
496   pthread_mutex_unlock(&mutex);
497   if (!p) return 0;
498   int dataLength = tcp->getDataLength();
499
500   memcpy(buf, p, dataLength);
501   free(p);
502   return dataLength;
503 }
504
505 ULLONG VDR::streamRecording(Recording* rec)
506 {
507   unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
508   UCHAR buffer[totalLength];
509
510   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
511   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
512   strcpy((char*)&buffer[8], rec->fileName);
513
514   pthread_mutex_lock(&mutex);
515   unsigned int a = tcp->sendPacket(buffer, totalLength);
516   if (a != totalLength)
517   {
518     pthread_mutex_unlock(&mutex);
519     return 0;
520   }
521
522   unsigned char* p = (unsigned char*)tcp->receivePacket();
523   pthread_mutex_unlock(&mutex);
524   if (!p) return 0;
525
526   if (tcp->getDataLength() != 8)
527   {
528     free(p);
529     return 0;
530   }
531
532   ULLONG recordingLength = ntohll(*(ULLONG*)p);
533
534   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
535   free(p);
536
537   return recordingLength;
538 }
539
540 ULLONG VDR::rescanRecording()
541 {
542   unsigned long totalLength = 8;
543   UCHAR buffer[totalLength];
544
545   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
546   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
547
548   pthread_mutex_lock(&mutex);
549   unsigned int a = tcp->sendPacket(buffer, totalLength);
550   if (a != totalLength)
551   {
552     pthread_mutex_unlock(&mutex);
553     return 0;
554   }
555
556   unsigned char* p = (unsigned char*)tcp->receivePacket();
557   pthread_mutex_unlock(&mutex);
558   if (!p) return 0;
559
560   if (tcp->getDataLength() != 8)
561   {
562     free(p);
563     return 0;
564   }
565
566   ULLONG recordingLength = ntohll(*(ULLONG*)p);
567
568   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
569   free(p);
570
571   return recordingLength;
572 }
573
574 int VDR::getChannelSchedule(ULONG number)
575 {
576   UCHAR buffer[12];
577
578   *(unsigned long*)&buffer[0] = htonl(8);
579   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
580   *(unsigned long*)&buffer[8] = htonl(number);
581
582   pthread_mutex_lock(&mutex);
583   int a = tcp->sendPacket(buffer, 12);
584
585   if (a != 12)
586   {
587     pthread_mutex_unlock(&mutex);
588     return -1;
589   }
590
591   unsigned char* p = (unsigned char*)tcp->receivePacket();
592   pthread_mutex_unlock(&mutex);
593   if (!p) return -1;
594
595   int dataLength = tcp->getDataLength();
596
597   if (dataLength != 4)
598   {
599     free(p);
600     return -1;
601   }
602
603   ULONG data = ntohl(*(ULONG*)p);
604   free(p);
605
606   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule %lu", data);
607
608   return data;
609 }
610
611 ULLONG VDR::getResumePoint(char* fileName)
612 {
613   char* resumeString = configLoad("ResumeData", fileName);
614   if (!resumeString) return 0;
615
616   ULLONG toReturn = strtoull(resumeString, NULL, 10);
617   delete[] resumeString;
618   return toReturn;
619 }
620
621 int VDR::configSave(char* section, char* key, char* value)
622 {
623   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
624   UCHAR buffer[totalLength];
625
626   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
627   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
628
629   int position = 8;
630   strcpy((char*)&buffer[position], section);
631   position += strlen(section) + 1;
632   strcpy((char*)&buffer[position], key);
633   position += strlen(key) + 1;
634   strcpy((char*)&buffer[position], value);
635
636   pthread_mutex_lock(&mutex);
637   unsigned int a = tcp->sendPacket(buffer, totalLength);
638   if (a != totalLength)
639   {
640     pthread_mutex_unlock(&mutex);
641     return 0;
642   }
643
644   int toReturn = getSimpleReply();
645   pthread_mutex_unlock(&mutex);
646   return toReturn;
647 }
648
649 char* VDR::configLoad(char* section, char* key)
650 {
651   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
652   UCHAR buffer[totalLength];
653
654   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
655   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
656
657   int position = 8;
658   strcpy((char*)&buffer[position], section);
659   position += strlen(section) + 1;
660   strcpy((char*)&buffer[position], key);
661
662   pthread_mutex_lock(&mutex);
663   unsigned int a = tcp->sendPacket(buffer, totalLength);
664   if (a != totalLength)
665   {
666     pthread_mutex_unlock(&mutex);
667     return NULL;
668   }
669
670   char* toReturn = getStringReply();
671   pthread_mutex_unlock(&mutex);
672   return toReturn;
673 }