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