]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Add some VT switching and locking
[vompclient.git] / vdr.cc
1 /*\r
2     Copyright 2004-2008 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include "vdr.h"\r
22 \r
23 #include "recman.h"\r
24 #include "tcp.h"\r
25 #include "log.h"\r
26 #include "recinfo.h"\r
27 #include "dsock.h"\r
28 #include "channel.h"\r
29 #include "event.h"\r
30 #include "wol.h"\r
31 #include "vdrrequestpacket.h"\r
32 #include "vdrresponsepacket.h"\r
33 #include "command.h"\r
34 #include "media.h"\r
35 #include "mediaprovider.h"\r
36 #include "mediaproviderids.h"\r
37 #include "vdrcommand.h"\r
38 #include "video.h"\r
39 #include "osd.h"\r
40 \r
41 VDR* VDR::instance = NULL;\r
42 //prepare a request\r
43 //will create a request package from a command variable and fill this\r
44 //caller has to destroy buffer\r
45 static SerializeBuffer * prepareRequest(VDR_Command *cmd) {\r
46   SerializeBuffer *buf=new SerializeBuffer(512,false,true);\r
47   if (cmd->serialize(buf) != 0) {\r
48     delete buf;\r
49     return NULL;\r
50   }\r
51   return buf;\r
52 }\r
53 \r
54 //handle request/response\r
55 //TODO avoid copy of buffer (needs extension of requestpacket)\r
56 //TODO avoid command 2x (needs some more restructuring)\r
57 SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {\r
58   VDR_RequestPacket *rt=new VDR_RequestPacket;\r
59   if (! rt) {\r
60     delete rq;\r
61     return NULL;\r
62   }\r
63   if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {\r
64     delete rq;\r
65     delete rt;\r
66     return NULL;\r
67   }\r
68   if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {\r
69     delete rq;\r
70     delete rt;\r
71     return NULL;\r
72   }\r
73   delete rq;\r
74   VDR_ResponsePacket *rp=RequestResponse(rt);\r
75   logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);\r
76   if ( !rp) {\r
77     delete rt;\r
78     return NULL;\r
79   }\r
80   SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);\r
81   delete rp;\r
82   return buf;\r
83 }\r
84 \r
85 \r
86 \r
87 //deserialize a received response\r
88 //delete the package\r
89 //return !=0 on error\r
90 static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {\r
91   ULONG expected=c->command;\r
92   if (c->deserialize(rp) != 0) {\r
93     delete rp;\r
94     Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);\r
95     return -1;\r
96   }\r
97   delete rp;\r
98   if (c->command != expected) {\r
99    Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);\r
100     return -1;\r
101   }\r
102   Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);\r
103   return 0;\r
104 }\r
105 \r
106 \r
107 \r
108 VDR::VDR()\r
109 {\r
110   if (instance) return;\r
111   instance = this;\r
112   initted = 0;\r
113   findingServer = 0;\r
114   tcp = NULL;\r
115   connected = false;\r
116   maxChannelNumber = 0;\r
117   channelNumberWidth = 1;\r
118   TEMP_SINGLE_VDR_PR = NULL;\r
119   providerId=MPROVIDERID_VDR;\r
120   subRange=MPROVIDERRANGE_VDR;\r
121   MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);\r
122 }\r
123 \r
124 VDR::~VDR()\r
125 {\r
126   instance = NULL;\r
127   if (initted) shutdown();\r
128 }\r
129 \r
130 VDR* VDR::getInstance()\r
131 {\r
132   return instance;\r
133 }\r
134 \r
135 int VDR::init(int tport)\r
136 {\r
137   if (initted) return 0;\r
138   initted = 1;\r
139   port = tport;\r
140   logger = Log::getInstance();\r
141   return 1;\r
142 }\r
143 \r
144 int VDR::shutdown()\r
145 {\r
146   if (!initted) return 0;\r
147   initted = 0;\r
148   disconnect();\r
149   return 1;\r
150 }\r
151 \r
152 void VDR::findServers(vector<VDRServer>& servers)\r
153 {\r
154   Wol* wol = Wol::getInstance();\r
155   findingServer = 1;\r
156   char* message = "VOMP";\r
157 \r
158   DatagramSocket ds(port);\r
159   int haveAtLeastOne = 0;\r
160   int retval;\r
161   int waitType = 1;\r
162   bool firstloop = true;\r
163   while(findingServer)\r
164   {\r
165     if (waitType == 1)\r
166     {\r
167       ds.shutdown();\r
168       ds.init();\r
169       logger->log("VDR", Log::NOTICE, "Broadcasting for server");\r
170       ds.send("255.255.255.255", 3024, message, strlen(message));\r
171       if(!firstloop) wol->doWakeUp();\r
172     }\r
173     retval = ds.waitforMessage(waitType);\r
174 \r
175     if (retval == 2) // we got a reply\r
176     {\r
177       if (!strcmp(ds.getData(), "VOMP")) // echo.....\r
178       {\r
179         waitType = 2;\r
180       }\r
181       else\r
182       {\r
183         VDRServer newServer;\r
184         newServer.ip = new char[16];\r
185         strcpy(newServer.ip, ds.getFromIPA());\r
186 \r
187         if (ds.getDataLength() == 0)\r
188         {\r
189           newServer.name = new char[1];\r
190           newServer.name[0] = '\0';\r
191         }\r
192         else\r
193         {\r
194           newServer.name = new char[strlen(ds.getData())+1];\r
195           strcpy(newServer.name, ds.getData());\r
196         }\r
197 \r
198         servers.push_back(newServer);\r
199         waitType = 2;\r
200         haveAtLeastOne = 1;\r
201       }\r
202     }\r
203     else\r
204     {\r
205       if (haveAtLeastOne) break;\r
206       waitType = 1;\r
207       firstloop = false;\r
208 /* For DEBUGGING *\r
209       { VDRServer newServer;\r
210       newServer.ip = new char[16];\r
211       strcpy(newServer.ip, "192.168.1.7");\r
212       newServer.name = new char[6];\r
213       strcpy(newServer.name,"debug");\r
214       servers.push_back(newServer);\r
215       waitType = 2;\r
216       haveAtLeastOne = 1;}/**/\r
217 \r
218 \r
219 \r
220     }\r
221   }\r
222   logger->log("VDR", Log::NOTICE, "END loop");\r
223   sort(servers.begin(), servers.end(), ServerSorter());\r
224 }\r
225 \r
226 void VDR::cancelFindingServer()\r
227 {\r
228   findingServer = 0;\r
229 }\r
230 \r
231 void VDR::setServerIP(char* newIP)\r
232 {\r
233   strcpy(serverIP, newIP);\r
234 }\r
235 \r
236 int VDR::connect()\r
237 {\r
238   maxChannelNumber = 0;\r
239   channelNumberWidth = 1;\r
240 \r
241   if (tcp) delete tcp;\r
242   tcp = new TCP();\r
243   if (tcp->connectTo(serverIP, 3024))\r
244   {\r
245     connected = true;\r
246     threadStart();\r
247     return 1;\r
248   }\r
249   else\r
250   {\r
251     return 0;\r
252   }\r
253 }\r
254 \r
255 void VDR::disconnect()\r
256 {\r
257   threadCancel();\r
258   if (tcp) delete tcp;\r
259   tcp = NULL;\r
260   connected = false;\r
261   logger->log("VDR", Log::DEBUG, "Disconnect");\r
262 }\r
263 \r
264 void VDR::setReceiveWindow(size_t size)\r
265 {\r
266   if (connected) tcp->setReceiveWindow(size);\r
267 }\r
268 \r
269 ///////////////////////////////////////////////////////\r
270 \r
271 void VDR::threadMethod()\r
272 {\r
273   logger->log("VDR", Log::DEBUG, "VDR RUN");  \r
274 \r
275   threadSetKillable(); // FIXME - change this to deal with the EDRs\r
276   \r
277   ULONG channelID;\r
278   \r
279   ULONG requestID;\r
280   ULONG userDataLength;\r
281   UCHAR* userData;\r
282 \r
283   ULONG streamID;\r
284   ULONG flag;\r
285 \r
286   VDR_ResponsePacket* vresp;\r
287   \r
288   ULONG timeNow = 0;\r
289   ULONG lastKAsent = 0;\r
290   ULONG lastKArecv = time(NULL);\r
291   int readSuccess;\r
292 \r
293   while(1)\r
294   {\r
295     timeNow = time(NULL);\r
296     \r
297     readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG));  // 2s timeout atm\r
298 \r
299     if (!readSuccess)\r
300     {\r
301       //logger->log("VDR", Log::DEBUG, "Net read timeout");\r
302       if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread\r
303     }\r
304       \r
305     // Error or timeout.\r
306 \r
307     if (!lastKAsent) // have not sent a KA\r
308     {\r
309       if (lastKArecv < (timeNow - 5))\r
310       {\r
311         logger->log("VDR", Log::DEBUG, "Sending KA packet");\r
312         if (!sendKA(timeNow))\r
313         {\r
314           logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");\r
315           connectionDied();\r
316           return;\r
317         }\r
318         lastKAsent = timeNow;\r
319       }\r
320     }\r
321     else\r
322     {\r
323       if (lastKAsent <= (timeNow - 10))\r
324       {\r
325         logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");\r
326         connectionDied();\r
327         return;\r
328       }    \r
329     }\r
330 \r
331     if (!readSuccess) continue; // no data was read but the connection is ok.\r
332     \r
333     // Data was read\r
334             \r
335     channelID = ntohl(channelID);\r
336    \r
337     if (channelID == CHANNEL_REQUEST_RESPONSE)\r
338     {\r
339       if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;\r
340       requestID = ntohl(requestID);\r
341       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;\r
342       userDataLength = ntohl(userDataLength);\r
343       if (userDataLength > 5000000) break; // how big can these packets get?\r
344       userData = NULL;\r
345       if (userDataLength > 0)\r
346       {\r
347         userData = (UCHAR*)malloc(userDataLength);\r
348         if (!userData) break;\r
349         if (!tcp->readData(userData, userDataLength)) break;\r
350       }\r
351 \r
352       vresp = new VDR_ResponsePacket();  \r
353       vresp->setResponse(requestID, userData, userDataLength);\r
354       logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);\r
355 \r
356       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
357       {\r
358         // If edFindAndCall returns true, edr was called and vresp was handed off.\r
359         // else, delete vresp here.\r
360         delete vresp;\r
361       }\r
362     }\r
363     else if (channelID == CHANNEL_STREAM)\r
364     {\r
365       if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;\r
366       streamID = ntohl(streamID);\r
367 \r
368       if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;\r
369       flag = ntohl(flag);\r
370 \r
371       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; \r
372       userDataLength = ntohl(userDataLength);\r
373       userData = NULL;\r
374       if (userDataLength > 0)\r
375       {\r
376         userData = (UCHAR*)malloc(userDataLength);\r
377         if (!userData) break;\r
378         if (!tcp->readData(userData, userDataLength)) break;\r
379       }\r
380 \r
381       vresp = new VDR_ResponsePacket();    \r
382       vresp->setStream(streamID, flag, userData, userDataLength);\r
383 //      logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);\r
384 \r
385       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
386       {\r
387         // If edFindAndCall returns true, edr was called and vresp was handed off.\r
388         // else, delete vresp here.\r
389         delete vresp;\r
390       }\r
391     }\r
392     else if (channelID == CHANNEL_KEEPALIVE)\r
393     {\r
394       ULONG KAreply = 0;\r
395       if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;\r
396       KAreply = (ULONG)ntohl(KAreply);\r
397       if (KAreply == lastKAsent) // successful KA response\r
398       {\r
399         lastKAsent = 0;\r
400         lastKArecv = KAreply;\r
401         logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");\r
402       }\r
403     }\r
404     else\r
405     {\r
406       logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);\r
407       break;\r
408     }\r
409     threadCheckExit();\r
410 \r
411 \r
412     // Who deletes vresp?\r
413     // If RR, the individual protocol functions must delete vresp.\r
414     // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.\r
415   }\r
416  \r
417   connectionDied();\r
418 }\r
419 \r
420 void VDR::connectionDied()\r
421 {\r
422   // Called from within threadMethod to do cleanup if it decides the connection has died\r
423 \r
424   connected = false; // though actually it could still be connected until someone calls vdr->disconnect\r
425 \r
426   // Need to wake up any waiting channel 1 request-response threads\r
427   // Normally this is done by a packet coming in with channelid and requestid      \r
428   // Instead, go through the list and for each channel 1 edr, make an empty vresp\r
429   // An empty vresp will have userData == NULL, which means vresp->noResponse() == true\r
430 \r
431   // If it's a stream receiver, generate a stream packet with flag == connection_lost\r
432 \r
433   edLock();\r
434   VDR_PacketReceiver* vdrpr;\r
435   VDR_ResponsePacket* vresp;\r
436   while(receivers.size())\r
437   {\r
438     vdrpr = (VDR_PacketReceiver*) *(receivers.begin());\r
439     if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)\r
440     {\r
441       vresp = new VDR_ResponsePacket();\r
442       vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);\r
443       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);\r
444       edUnlock();\r
445       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
446       {\r
447         // If edFindAndCall returns true, edr was called and vresp was handed off.\r
448         // else, delete vresp here.\r
449         logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);\r
450         delete vresp;\r
451       }\r
452       edLock();\r
453     }\r
454     else if (vdrpr->receiverChannel == CHANNEL_STREAM)\r
455     {\r
456       vresp = new VDR_ResponsePacket();\r
457       vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0);\r
458       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);\r
459       edUnlock();\r
460       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )\r
461       {\r
462         // If edFindAndCall returns true, edr was called and vresp was handed off.\r
463         // else, delete vresp here.\r
464         logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);\r
465         delete vresp;\r
466       }\r
467       edLock();\r
468       \r
469       for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)\r
470         if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }\r
471     }\r
472   }\r
473   edUnlock();\r
474   // Ok, all event receviers should be dealt with. just in case there weren't any, inform command\r
475   logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");\r
476 \r
477   Command::getInstance()->connectionLost();\r
478 }\r
479 \r
480 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)\r
481 {\r
482   // edr is a VDR_PacketReceiver object made in VDR::RequestResponse\r
483   // userTag is a VDR_ResponsePacket made in threadMethod\r
484 \r
485   VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;\r
486   VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
487   \r
488   // Is vresp for vdrpr ?\r
489   \r
490   ULONG packetChannel = vresp->getChannelID();\r
491   if (vdrpr->receiverChannel != packetChannel) return false;\r
492 \r
493   if (packetChannel == CHANNEL_REQUEST_RESPONSE)\r
494   {\r
495     if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;\r
496   }\r
497   else if (packetChannel == CHANNEL_STREAM)\r
498   {\r
499     if (vdrpr->streamID == vresp->getStreamID()) return true;\r
500   }\r
501  \r
502   return false;\r
503 }\r
504 \r
505 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)\r
506 {\r
507   //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());\r
508 \r
509   if (!connected)\r
510   {\r
511     logger->log("VDR", Log::DEBUG, "RR when !connected");\r
512     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
513     return vresp; // "no-response" return\r
514   }\r
515 \r
516   // ED make new VDR and register\r
517   // make a VDR_PacketReceiver\r
518   // - init with serial number of request packet\r
519 \r
520   VDR_PacketReceiver vdrpr;\r
521 //  vdrpr.requestTime = time(NULL);\r
522   vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;\r
523   vdrpr.requestSerialNumber = vrp->getSerial();\r
524 \r
525   edRegister(&vdrpr);\r
526    \r
527   edLock();  \r
528 \r
529   if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())\r
530   {\r
531     edUnlock();\r
532     edUnregister(&vdrpr);\r
533     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();\r
534     return vresp; // "no-response" return\r
535   }\r
536 \r
537   // Sleep and block this thread. The sleep unlocks the mutex\r
538   logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());\r
539   edSleepThisReceiver(&vdrpr);\r
540   logger->log("VDR", Log::DEBUG, "RR unsleep");\r
541     \r
542   // Woken because a response packet has arrived, mutex will be locked\r
543   \r
544   edUnlock();\r
545   return vdrpr.save_vresp;\r
546 }\r
547 \r
548 bool VDR::sendKA(ULONG timeStamp)\r
549 {\r
550   char buffer[8];\r
551 \r
552   int pos=0;\r
553   ULONG ul=CHANNEL_KEEPALIVE;\r
554   buffer[pos++]=(ul>>24)&0xff;\r
555   buffer[pos++]=(ul>>16)&0xff;\r
556   buffer[pos++]=(ul>>8)&0xff;\r
557   buffer[pos++]=ul &0xff;\r
558   ul=timeStamp;\r
559   buffer[pos++]=(ul>>24)&0xff;\r
560   buffer[pos++]=(ul>>16)&0xff;\r
561   buffer[pos++]=(ul>>8)&0xff;\r
562   buffer[pos++]=ul &0xff;\r
563   if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;\r
564   return true;\r
565 }\r
566 \r
567 /////////////////////////////////////////////////////////////////////////////\r
568 \r
569 // Here VDR takes a break for the VDR_PacketReceiver helper class\r
570 \r
571 bool VDR_PacketReceiver::call(void* userTag)\r
572 {\r
573   if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)\r
574   {\r
575     // It's a RR. Save vresp and, signal the waiting thread and return.\r
576     // VDR::RequestResponse will be blocking waiting for this to happen.\r
577     // That function has a pointer to this object and can read save_vresp.\r
578     save_vresp = (VDR_ResponsePacket*)userTag;\r
579     return true; // Signals ED to remove edr from receivers and wake up edr thread\r
580   }\r
581   \r
582   if (receiverChannel == VDR::CHANNEL_STREAM)\r
583   {\r
584     // It's a stream packet.\r
585     VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;\r
586     streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());\r
587     delete vresp;\r
588     return false;\r
589   }\r
590 \r
591   abort(); // unknown receiverChannel, should not happen\r
592 }\r
593 \r
594 /////////////////////////////////////////////////////////////////////////////\r
595 \r
596 int VDR::doLogin()\r
597 {\r
598   VDR_RequestPacket vrp;\r
599   if (!vrp.init(VDR_LOGIN, true, 6)) return 0;\r
600 \r
601   char* mactemp[6];\r
602   tcp->getMAC((char*)mactemp);\r
603   if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;\r
604 \r
605   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
606   if (vresp->noResponse()) { delete vresp; return 0; }\r
607 \r
608   ULONG vdrTime = vresp->extractULONG();\r
609   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);\r
610   long vdrTimeOffset = vresp->extractLONG();\r
611   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);\r
612 \r
613   delete vresp;\r
614 \r
615   // Set the time and zone on the MVP only\r
616 \r
617 #if !defined(WIN32) && !defined(__ANDROID__)\r
618   struct timespec currentTime;\r
619   currentTime.tv_sec = vdrTime;\r
620   currentTime.tv_nsec = 0;\r
621 \r
622   int b = clock_settime(CLOCK_REALTIME, &currentTime);\r
623 \r
624   logger->log("VDR", Log::DEBUG, "set clock = %u", b);\r
625 \r
626   // now make a TZ variable and set it\r
627   char sign;\r
628   int hours;\r
629   int minutes;\r
630   if (vdrTimeOffset > 0) sign = '-';\r
631   else sign = '+';\r
632 \r
633   vdrTimeOffset = abs(vdrTimeOffset);\r
634 \r
635   hours = (int)vdrTimeOffset / 3600;\r
636   minutes = vdrTimeOffset % 3600;\r
637 \r
638   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);\r
639 \r
640   minutes = (int)minutes / 60;\r
641 \r
642   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);\r
643 \r
644   char newTZ[30];\r
645   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);\r
646   setenv("TZ", newTZ, 1);\r
647 \r
648   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);\r
649 #endif\r
650 \r
651   setCharset(Osd::getInstance()->charSet());\r
652 \r
653   return 1;\r
654 }\r
655 \r
656 bool VDR::LogExtern(const char* logString)\r
657 {\r
658   if (!connected) return false;\r
659   int stringLength = strlen(logString);\r
660   int packetLength = stringLength + 8;\r
661   char *buffer=new char[packetLength + 1];\r
662   int pos=0;\r
663   ULONG ul=CHANNEL_NETLOG;\r
664   buffer[pos++]=(ul>>24)&0xff;\r
665   buffer[pos++]=(ul>>16)&0xff;\r
666   buffer[pos++]=(ul>>8)&0xff;\r
667   buffer[pos++]=ul &0xff;\r
668   ul=stringLength;\r
669   buffer[pos++]=(ul>>24)&0xff;\r
670   buffer[pos++]=(ul>>16)&0xff;\r
671   buffer[pos++]=(ul>>8)&0xff;\r
672   buffer[pos++]=ul &0xff;\r
673 \r
674   strcpy(&buffer[8], logString);\r
675   \r
676   if ((ULONG)tcp->sendData(buffer, packetLength) != packetLength) {\r
677           delete [] buffer;\r
678           return false;\r
679   }\r
680   delete [] buffer;\r
681   return true;\r
682 }\r
683 \r
684 bool VDR::setCharset(int charset)\r
685 {\r
686   VDR_RequestPacket vrp;\r
687   if (!vrp.init(VDR_SETCHARSET, true, sizeof(ULONG))) return false;\r
688   if (!vrp.addULONG(charset)) return false;\r
689 \r
690   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
691   if (vresp->noResponse()) { delete vresp; return false; }\r
692 \r
693   ULONG success = vresp->extractULONG();\r
694   delete vresp;\r
695 \r
696   if (!success) return false;\r
697 \r
698   return true;\r
699 }\r
700 \r
701 bool VDR::getRecordingsList(RecMan* recman)\r
702 {\r
703   VDR_RequestPacket vrp;\r
704   if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;\r
705 \r
706   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
707   if (vresp->noResponse()) { delete vresp; return false; }\r
708 \r
709   ULONG totalSpace = vresp->extractULONG();\r
710   ULONG freeSpace = vresp->extractULONG();\r
711   ULONG percent = vresp->extractULONG();\r
712 \r
713   recman->setStats(totalSpace, freeSpace, percent);\r
714 \r
715   ULONG start;\r
716   char* name;\r
717   char* fileName;\r
718 \r
719   while (!vresp->end())\r
720   {\r
721 \r
722     start = vresp->extractULONG();\r
723     name = vresp->extractString();\r
724     fileName = vresp->extractString();\r
725     recman->addEntry(start, name, fileName);\r
726     delete[] name;\r
727     delete[] fileName;\r
728   }\r
729   delete vresp;\r
730 \r
731   return true;\r
732 }\r
733 \r
734 int VDR::deleteRecording(char* fileName)\r
735 {\r
736   VDR_RequestPacket vrp;\r
737   if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;\r
738   if (!vrp.addString(fileName)) return 0;\r
739   \r
740   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
741   if (vresp->noResponse()) { delete vresp; return 0; }\r
742   \r
743   int toReturn = (int)vresp->extractULONG();\r
744   delete vresp;\r
745 \r
746   return toReturn;\r
747 }\r
748 \r
749 char* VDR::moveRecording(char* fileName, char* newPath)\r
750 {\r
751   VDR_RequestPacket vrp;\r
752   if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;\r
753   if (!vrp.addString(fileName)) return NULL;\r
754   if (!vrp.addString(newPath)) return NULL;\r
755   \r
756   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
757   if (vresp->noResponse()) { delete vresp; return NULL; }\r
758   \r
759   char* toReturn = NULL;\r
760   int success = (int)vresp->extractULONG();\r
761   if (success == 1)\r
762   {\r
763     toReturn = vresp->extractString();\r
764   }\r
765 \r
766   delete vresp;\r
767 \r
768   return toReturn;\r
769 }\r
770 \r
771 ChannelList* VDR::getChannelsList(ULONG type)\r
772 {\r
773   VDR_RequestPacket vrp;\r
774   if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;\r
775 \r
776   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
777   if (vresp->noResponse()) { delete vresp; return NULL; }\r
778   \r
779   ChannelList* chanList = new ChannelList();\r
780 \r
781   bool h264support=Video::getInstance()->supportsh264();\r
782 \r
783   while (!vresp->end())\r
784   {\r
785     Channel* chan = new Channel();\r
786     chan->number = vresp->extractULONG();\r
787     chan->type = vresp->extractULONG();\r
788     chan->name = vresp->extractString();\r
789     chan->vstreamtype = vresp->extractULONG();\r
790 \r
791     if (chan->type == type && (chan->vstreamtype!=0x1b || h264support))\r
792     {\r
793       chanList->push_back(chan);\r
794       logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);\r
795       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;\r
796     }\r
797     else\r
798     {\r
799       delete chan;\r
800     }\r
801   }\r
802 \r
803   delete vresp;\r
804 \r
805   if (maxChannelNumber > 99999)\r
806     channelNumberWidth = 6;\r
807   else if (maxChannelNumber > 9999)\r
808     channelNumberWidth = 5;\r
809   else if (maxChannelNumber > 999)\r
810     channelNumberWidth = 4;\r
811   else if (maxChannelNumber > 99)\r
812     channelNumberWidth = 3;\r
813   else if (maxChannelNumber > 9)\r
814     channelNumberWidth = 2;\r
815   else\r
816     channelNumberWidth = 1;\r
817 \r
818   return chanList;\r
819 }\r
820 \r
821 int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)\r
822 {\r
823   VDR_RequestPacket vrp;\r
824   if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;\r
825   if (!vrp.addULONG(number)) return 0;\r
826   \r
827   \r
828   VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();\r
829   vdrpr->receiverChannel = VDR::CHANNEL_STREAM;\r
830   vdrpr->streamID = vrp.getSerial();\r
831   vdrpr->streamReceiver = tstreamReceiver;\r
832   edRegister(vdrpr);\r
833   TEMP_SINGLE_VDR_PR = vdrpr;\r
834   \r
835   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
836   if (vresp->noResponse())\r
837   {\r
838     delete vresp;\r
839     edUnregister(vdrpr);\r
840     delete vdrpr;\r
841     return 0;\r
842   }\r
843   \r
844   int toReturn = (int)vresp->extractULONG();\r
845   logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);\r
846   delete vresp;\r
847 \r
848   return toReturn;\r
849 }\r
850 \r
851 int VDR::stopStreaming()\r
852 {\r
853   VDR_RequestPacket vrp;\r
854   if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;\r
855 \r
856   if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream\r
857                           // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel\r
858   {\r
859     edUnregister(TEMP_SINGLE_VDR_PR);\r
860     delete TEMP_SINGLE_VDR_PR;\r
861     TEMP_SINGLE_VDR_PR = NULL;\r
862   }\r
863 \r
864   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
865   if (vresp->noResponse()) { delete vresp; return 0; }\r
866   \r
867   int toReturn = (int)vresp->extractULONG();\r
868   delete vresp;\r
869 \r
870   return toReturn;\r
871 }\r
872 \r
873 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)\r
874 {\r
875   VDR_RequestPacket vrp;\r
876   if (!vrp.init(VDR_GETBLOCK, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;\r
877   if (!vrp.addULLONG(position)) return NULL;\r
878   if (!vrp.addULONG(maxAmount)) return NULL;\r
879 \r
880   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
881   if (vresp->noResponse()) { delete vresp; return NULL; }\r
882 \r
883   if (vresp->serverError())\r
884   {\r
885     logger->log("VDR", Log::DEBUG, "Detected getblock 0");\r
886     delete vresp;\r
887     return NULL;\r
888   }\r
889 \r
890   // Special handling for getblock\r
891   UCHAR* toReturn = vresp->getUserData();\r
892   *amountReceived = vresp->getUserDataLength();\r
893   \r
894   delete vresp;\r
895   \r
896   return toReturn;\r
897 }\r
898 \r
899 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording)\r
900 {\r
901   VDR_RequestPacket vrp;\r
902   if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;\r
903   if (!vrp.addString(fileName)) return 0;\r
904 \r
905   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
906   if (vresp->noResponse()) { delete vresp; return 0; }\r
907   \r
908   ULLONG lengthBytes = vresp->extractULLONG();\r
909   ULONG lengthFrames = vresp->extractULONG();\r
910   UCHAR isPesRecording = vresp->extractUCHAR();\r
911   delete vresp;\r
912 \r
913   *totalFrames = lengthFrames;\r
914   *IsPesRecording = (isPesRecording);//convert Uchar to bool\r
915 \r
916   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording);\r
917 \r
918   return lengthBytes;\r
919 }\r
920 \r
921 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)\r
922 {\r
923   VDR_RequestPacket vrp;\r
924   if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;\r
925   if (!vrp.addULONG(frameNumber)) return 0;\r
926 \r
927   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
928   if (vresp->noResponse()) { delete vresp; return 0; }\r
929   \r
930   ULLONG position = vresp->extractULLONG();\r
931   delete vresp;\r
932   \r
933   logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);\r
934 \r
935   return position;\r
936 }\r
937 \r
938 ULONG VDR::frameNumberFromPosition(ULLONG position)\r
939 {\r
940   VDR_RequestPacket vrp;\r
941   if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;\r
942   if (!vrp.addULLONG(position)) return 0;\r
943 \r
944   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
945   if (vresp->noResponse()) { delete vresp; return 0; }\r
946   \r
947   ULONG framenumber = vresp->extractULONG();\r
948   delete vresp;\r
949   \r
950   logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);\r
951 \r
952   return framenumber;\r
953 }\r
954 \r
955 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)\r
956 {\r
957   VDR_RequestPacket vrp;\r
958   if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;\r
959   if (!vrp.addULONG(frameNumber)) return false;\r
960   if (!vrp.addULONG(direction)) return false;\r
961 \r
962   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
963   if (vresp->noResponse()) { delete vresp; return false; }\r
964   \r
965   if (vresp->serverError())\r
966   {\r
967     logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");\r
968     delete vresp;\r
969     return false;\r
970   }\r
971 \r
972   *rfilePosition = vresp->extractULLONG();\r
973   *rframeNumber = vresp->extractULONG();\r
974   *rframeLength = vresp->extractULONG();\r
975 \r
976   delete vresp;\r
977 \r
978   logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);\r
979 \r
980   return true;\r
981 }\r
982 \r
983 EventList* VDR::getChannelSchedule(ULONG number)\r
984 {\r
985   time_t now;\r
986   time(&now);\r
987   return getChannelSchedule(number, now, 24 * 60 * 60);\r
988 }\r
989 \r
990 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)\r
991 {\r
992 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds\r
993 \r
994   VDR_RequestPacket vrp;\r
995   if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;\r
996   if (!vrp.addULONG(number)) return NULL;\r
997   if (!vrp.addULONG(start)) return NULL;\r
998   if (!vrp.addULONG(duration)) return NULL;\r
999 \r
1000   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1001   if (vresp->noResponse()) { delete vresp; return NULL; }\r
1002   \r
1003   // received a ulong(0) - schedules error in the plugin\r
1004   if (vresp->serverError())\r
1005   {\r
1006     delete vresp;\r
1007     return NULL;\r
1008   }\r
1009 \r
1010   EventList* eventList = new EventList();\r
1011 \r
1012   while (!vresp->end())\r
1013   {\r
1014     Event* event = new Event();\r
1015     event->id = vresp->extractULONG();\r
1016     event->time = vresp->extractULONG();\r
1017     event->duration = vresp->extractULONG();\r
1018     event->title = vresp->extractString();\r
1019     event->subtitle = vresp->extractString();\r
1020     event->description = vresp->extractString();\r
1021     eventList->push_back(event);\r
1022   }\r
1023 \r
1024   delete vresp;\r
1025 \r
1026   logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");\r
1027   return eventList;\r
1028 }\r
1029 \r
1030 int VDR::configSave(const char* section, const char* key, const char* value)\r
1031 {\r
1032   VDR_RequestPacket vrp;\r
1033   if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;\r
1034   if (!vrp.addString(section)) return 0;\r
1035   if (!vrp.addString(key)) return 0;\r
1036   if (!vrp.addString(value)) return 0;\r
1037 \r
1038   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1039   if (vresp->noResponse()) { delete vresp; return 0; }\r
1040   \r
1041   int toReturn = (int)vresp->extractULONG();\r
1042   delete vresp;\r
1043 \r
1044   return toReturn;\r
1045 }\r
1046 \r
1047 char* VDR::configLoad(const char* section, const char* key)\r
1048 {\r
1049   VDR_RequestPacket vrp;\r
1050   if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;\r
1051   if (!vrp.addString(section)) return NULL;\r
1052   if (!vrp.addString(key)) return NULL;\r
1053 \r
1054   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1055   if (vresp->noResponse()) { delete vresp; return NULL; }\r
1056   \r
1057   char* toReturn = vresp->extractString();\r
1058   delete vresp;\r
1059 \r
1060   return toReturn;\r
1061 }\r
1062 \r
1063 RecTimerList* VDR::getRecTimersList()\r
1064 {\r
1065   VDR_RequestPacket vrp;\r
1066   if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;\r
1067 \r
1068   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1069   if (vresp->noResponse()) { delete vresp; return NULL; }\r
1070 \r
1071   RecTimerList* recTimerList = new RecTimerList();\r
1072 \r
1073   ULONG numTimers = vresp->extractULONG();\r
1074   if (numTimers > 0)\r
1075   {\r
1076     RecTimer* newRecTimer;\r
1077     char* tempString;\r
1078 \r
1079     while (!vresp->end())\r
1080     {\r
1081       newRecTimer = new RecTimer();\r
1082       newRecTimer->active = vresp->extractULONG();\r
1083       newRecTimer->recording = vresp->extractULONG();\r
1084       newRecTimer->pending = vresp->extractULONG();\r
1085       newRecTimer->priority = vresp->extractULONG();\r
1086       newRecTimer->lifeTime = vresp->extractULONG();\r
1087       newRecTimer->channelNumber = vresp->extractULONG();\r
1088       newRecTimer->startTime = vresp->extractULONG();\r
1089       newRecTimer->stopTime = vresp->extractULONG();\r
1090       newRecTimer->day = vresp->extractULONG();\r
1091       newRecTimer->weekDays = vresp->extractULONG();\r
1092 \r
1093       tempString = vresp->extractString();\r
1094       newRecTimer->setFile(tempString);\r
1095       delete[] tempString;\r
1096 \r
1097       recTimerList->push_back(newRecTimer);\r
1098       logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",\r
1099         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,\r
1100         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());\r
1101     }\r
1102   }\r
1103 \r
1104   delete vresp;\r
1105 \r
1106   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());\r
1107 \r
1108   return recTimerList;\r
1109 }\r
1110 \r
1111 ULONG VDR::setEventTimer(char* timerString)\r
1112 {\r
1113   VDR_RequestPacket vrp;\r
1114   if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;\r
1115   if (!vrp.addString(timerString)) return 0;\r
1116 \r
1117   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1118   if (vresp->noResponse()) { delete vresp; return 0; }\r
1119   \r
1120   ULONG toReturn = vresp->extractULONG();\r
1121   delete vresp;\r
1122 \r
1123   return toReturn;\r
1124 }\r
1125 \r
1126 RecInfo* VDR::getRecInfo(char* fileName)\r
1127 {\r
1128   VDR_RequestPacket vrp;\r
1129   if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;\r
1130   if (!vrp.addString(fileName)) return NULL;\r
1131   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1132 \r
1133   if (vresp->noResponse()) { delete vresp; return NULL; }\r
1134 \r
1135   if (vresp->serverError())\r
1136   {\r
1137     logger->log("VDR", Log::DEBUG, "Could not get rec info");\r
1138     delete vresp;\r
1139     return NULL;\r
1140   }\r
1141 \r
1142   RecInfo* recInfo = new RecInfo();\r
1143 \r
1144   recInfo->timerStart = vresp->extractULONG();\r
1145   recInfo->timerEnd = vresp->extractULONG();\r
1146   recInfo->resumePoint = vresp->extractULONG();\r
1147   recInfo->summary = vresp->extractString();\r
1148 \r
1149   ULONG numComponents = vresp->extractULONG();\r
1150   if (numComponents)\r
1151   {\r
1152     recInfo->setNumComponents(numComponents);\r
1153     for (ULONG i = 0; i < numComponents; i++)\r
1154     {\r
1155       recInfo->streams[i] = vresp->extractUCHAR();\r
1156       recInfo->types[i] = vresp->extractUCHAR();\r
1157       recInfo->languages[i] = vresp->extractString();\r
1158       recInfo->descriptions[i] = vresp->extractString();\r
1159     }\r
1160   }\r
1161   recInfo->fps=vresp->extractdouble();\r
1162   \r
1163 \r
1164   recInfo->print();\r
1165 \r
1166   delete vresp;\r
1167   return recInfo;\r
1168 }\r
1169 \r
1170 // FIXME obselete\r
1171 ULLONG VDR::rescanRecording(ULONG* totalFrames)\r
1172 {\r
1173   VDR_RequestPacket vrp;\r
1174   if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;\r
1175 \r
1176   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1177   if (vresp->noResponse()) { delete vresp; return 0; }\r
1178   \r
1179   ULLONG lengthBytes = vresp->extractULLONG();\r
1180   ULONG lengthFrames = vresp->extractULONG();\r
1181   delete vresp;\r
1182   \r
1183   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);\r
1184 \r
1185   *totalFrames = lengthFrames;\r
1186   return lengthBytes;\r
1187 }\r
1188 \r
1189 MarkList* VDR::getMarks(char* fileName)\r
1190 {\r
1191   VDR_RequestPacket vrp;\r
1192   if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;\r
1193   if (!vrp.addString(fileName)) return NULL;\r
1194 \r
1195   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1196   if (vresp->noResponse()) { delete vresp; return NULL; }\r
1197   \r
1198   if (vresp->serverError())\r
1199   {\r
1200     delete vresp;\r
1201     return NULL;\r
1202   }\r
1203 \r
1204   MarkList* markList = new MarkList();\r
1205 \r
1206   while (!vresp->end())\r
1207   {\r
1208     Mark* mark = new Mark();\r
1209     mark->pos = vresp->extractULONG();\r
1210 \r
1211     markList->push_back(mark);\r
1212     logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);\r
1213   }\r
1214 \r
1215   delete vresp;\r
1216   \r
1217   return markList;\r
1218 }\r
1219 \r
1220 void VDR::getChannelPids(Channel* channel)\r
1221 {\r
1222   VDR_RequestPacket vrp;\r
1223   if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;\r
1224   if (!vrp.addULONG(channel->number)) return ;\r
1225 \r
1226   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1227   if (vresp->noResponse()) { delete vresp; return ; }\r
1228   \r
1229   // Format of response\r
1230   // vpid\r
1231   // number of apids\r
1232   // {\r
1233   //    apid\r
1234   //    lang string\r
1235   // }\r
1236 \r
1237   channel->vpid = vresp->extractULONG();\r
1238   channel->vstreamtype = vresp->extractULONG();\r
1239   channel->numAPids = vresp->extractULONG();\r
1240 \r
1241   for (ULONG i = 0; i < channel->numAPids; i++)\r
1242   {\r
1243     apid newapid;\r
1244     newapid.pid = vresp->extractULONG();\r
1245     newapid.name = vresp->extractString();\r
1246     channel->apids.push_back(newapid);\r
1247   }\r
1248 \r
1249   channel->numDPids = vresp->extractULONG();\r
1250 \r
1251   for (ULONG i = 0; i < channel->numDPids; i++)\r
1252   {\r
1253     apid newdpid;\r
1254     newdpid.pid = vresp->extractULONG();\r
1255     newdpid.name = vresp->extractString();\r
1256     channel->dpids.push_back(newdpid);\r
1257   }\r
1258 \r
1259   channel->numSPids = vresp->extractULONG();\r
1260 \r
1261   for (ULONG i = 0; i < channel->numSPids; i++)\r
1262   {\r
1263     apid newspid;\r
1264     newspid.pid = vresp->extractULONG();\r
1265     newspid.name = vresp->extractString();\r
1266     channel->spids.push_back(newspid);\r
1267   }\r
1268   channel->tpid = vresp->extractULONG();\r
1269 \r
1270   delete vresp;\r
1271   \r
1272   return ;\r
1273 }\r
1274 \r
1275 \r
1276 MediaList * VDR::getRootList() {\r
1277   return getMediaList(NULL);\r
1278 }\r
1279 /**\r
1280   * media List Request:\r
1281   * mediaURI\r
1282   * Media List response:\r
1283   * mediaList\r
1284 */\r
1285 MediaList* VDR::getMediaList(const MediaURI * root)\r
1286 {\r
1287   logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"), \r
1288       ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),\r
1289       (root?root->getProvider():providerId));\r
1290   MediaURI remoteURI(root);\r
1291   VDR_GetMediaListRequest request(&remoteURI);\r
1292   SerializeBuffer *vrp=prepareRequest(&request);\r
1293   if (!vrp) {\r
1294     logger->log("VDR", Log::ERR, "getMediaList unable to create command");\r
1295     return NULL;\r
1296   }\r
1297     \r
1298   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
1299   if (!vresp) {\r
1300     Command::getInstance()->connectionLost();\r
1301     return NULL;\r
1302   }\r
1303   \r
1304   MediaList *rt=new MediaList(NULL);\r
1305   ULONG rtflags=0;\r
1306   VDR_GetMediaListResponse resp(&rtflags,rt);\r
1307   if (decodeResponse(vresp,&resp) != 0) {\r
1308     return NULL;\r
1309   }\r
1310   return rt;\r
1311 }\r
1312 \r
1313 /**\r
1314   * get image Request:\r
1315   * uri,x,y, channel\r
1316   * get media response:\r
1317   * 4 flags\r
1318   * 8 len of image\r
1319 */\r
1320 int VDR::openMedium(ULONG channel,const MediaURI *uri,  ULLONG * size, ULONG x, ULONG y)\r
1321 {\r
1322   MediaURI remoteURI(uri);\r
1323   VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);\r
1324   *size=0;\r
1325   SerializeBuffer *vrp=prepareRequest(&request);\r
1326   if (!vrp) {\r
1327     logger->log("VDR", Log::ERR, "openMedium unable to create command");\r
1328     return -1;\r
1329   }\r
1330   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
1331   if (!vresp) {\r
1332     Command::getInstance()->connectionLost();\r
1333     return -1;\r
1334   }\r
1335   ULONG flags=0;\r
1336   VDR_OpenMediumResponse response(&flags,size);\r
1337   if (decodeResponse(vresp,&response) != 0) {\r
1338     return -1;\r
1339   }\r
1340   logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);\r
1341   return 0;\r
1342 }\r
1343 \r
1344 /**\r
1345   * getMediaBlock - no separate response class - simple data block\r
1346   * resp\r
1347   * packet\r
1348   */\r
1349 int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)\r
1350 {\r
1351   *amountReceived=0;\r
1352   VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);\r
1353   SerializeBuffer *vrp=prepareRequest(&request);\r
1354   if (!vrp) {\r
1355     logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");\r
1356     return -1;\r
1357   }\r
1358   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
1359   if (!vresp) {\r
1360     Command::getInstance()->connectionLost();\r
1361     return -1;\r
1362   }\r
1363   \r
1364   // Special handling for getblock\r
1365   *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());\r
1366   *buffer = vresp->steelBuffer();\r
1367   delete vresp;\r
1368   return 0;\r
1369 }\r
1370 \r
1371 /**\r
1372   * VDR_GETMEDIAINFO\r
1373   * channel\r
1374   * rt\r
1375   * flags\r
1376   * info\r
1377   */\r
1378 \r
1379 int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {\r
1380   if (! result) return -1;\r
1381   VDR_GetMediaInfoRequest request(&channel);\r
1382   SerializeBuffer *vrp=prepareRequest(&request);\r
1383   if (!vrp) {\r
1384     logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");\r
1385     return -1;\r
1386   }\r
1387   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
1388   if (!vresp) {\r
1389     Command::getInstance()->connectionLost();\r
1390     return -1;\r
1391   }\r
1392 \r
1393   ULONG flags=0;\r
1394   VDR_GetMediaInfoResponse response(&flags,result);\r
1395   if (decodeResponse(vresp,&response) != 0) {\r
1396     return -1;\r
1397   }\r
1398   return 0;\r
1399 }\r
1400 \r
1401 /**\r
1402   * VDR_CLOSECHANNEL\r
1403   * channel\r
1404   * rt\r
1405   * flags\r
1406   */\r
1407 \r
1408 int VDR::closeMediaChannel(ULONG channel) {\r
1409   VDR_CloseMediaChannelRequest request(&channel);\r
1410   SerializeBuffer *vrp=prepareRequest(&request);\r
1411   if (!vrp) {\r
1412     logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");\r
1413     return -1;\r
1414   }\r
1415   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);\r
1416   if (!vresp) {\r
1417     Command::getInstance()->connectionLost();\r
1418     return -1;\r
1419   }\r
1420   ULONG flags;\r
1421   VDR_CloseMediaChannelResponse response(&flags);\r
1422   if (decodeResponse(vresp,&response) != 0) return -1;\r
1423   return (flags != 0)?-1:0;\r
1424 }\r
1425 \r
1426 \r
1427 \r
1428 \r
1429 int VDR::deleteTimer(RecTimer* delTimer)\r
1430 {\r
1431   logger->log("VDR", Log::DEBUG, "Delete timer called");\r
1432   \r
1433   VDR_RequestPacket vrp;\r
1434   if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;\r
1435   if (!vrp.addULONG(delTimer->channelNumber)) return 0;\r
1436   if (!vrp.addULONG(delTimer->weekDays)) return 0;    \r
1437   if (!vrp.addULONG(delTimer->day)) return 0;\r
1438   if (!vrp.addULONG(delTimer->startTime)) return 0;  \r
1439   if (!vrp.addULONG(delTimer->stopTime)) return 0; \r
1440    \r
1441   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1442   if (vresp->noResponse()) { delete vresp; return 0; }\r
1443   \r
1444   int toReturn = (int)vresp->extractULONG();\r
1445   delete vresp;\r
1446 \r
1447   return toReturn;\r
1448 }\r
1449 \r
1450 I18n::lang_code_list VDR::getLanguageList()\r
1451 {\r
1452   I18n::lang_code_list CodeList;\r
1453   CodeList["en"] = "English"; // Default entry\r
1454   VDR_RequestPacket vrp;\r
1455   if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;\r
1456   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1457   if (vresp->noResponse() || vresp->end())\r
1458   {\r
1459     delete vresp;\r
1460     return CodeList;\r
1461   }\r
1462   CodeList.clear();\r
1463   while (!vresp->end())\r
1464   {\r
1465     char* c_code = vresp->extractString();\r
1466     char* c_name = vresp->extractString();\r
1467     string code = c_code;\r
1468     string name = c_name;\r
1469     CodeList[code] = name;\r
1470     delete[] c_code;\r
1471     delete[] c_name;\r
1472   }\r
1473   delete vresp;\r
1474   return CodeList;\r
1475 }\r
1476 \r
1477 int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)\r
1478 {\r
1479   VDR_RequestPacket vrp;\r
1480   if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;\r
1481   if (!vrp.addString(code.c_str())) return 0;\r
1482   VDR_ResponsePacket* vresp = RequestResponse(&vrp);\r
1483   if (vresp->noResponse()) { delete vresp; return 0; }\r
1484   texts.clear();\r
1485   while (!vresp->end())\r
1486   {\r
1487     char* c_key = vresp->extractString();\r
1488     char* c_text = vresp->extractString();\r
1489     string key = c_key;\r
1490     string text = c_text;\r
1491     texts[key] = text;\r
1492     delete[] c_key;\r
1493     delete[] c_text;\r
1494   }\r
1495   delete vresp;\r
1496   return 1;\r
1497 }\r