]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
IPv6 support for discovery protocol
[vompclient.git] / vdr.cc
1 /*
2     Copyright 2004-2019 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "vdr.h"
21
22 #include "recman.h"
23 #include "tcp.h"
24 #include "log.h"
25 #include "recinfo.h"
26 #include "dsock.h"
27 #include "channel.h"
28 #include "event.h"
29 #include "wol.h"
30 #include "vdrrequestpacket.h"
31 #include "vdrresponsepacket.h"
32 #include "command.h"
33 #include "vdp6.h"
34 #ifdef VOMP_MEDIAPLAYER
35 #include "media.h"
36 #include "mediaprovider.h"
37 #include "mediaproviderids.h"
38 #endif
39 #include "vdrcommand.h"
40 #include "video.h"
41 #include "osd.h"
42 #include "movieinfo.h"
43 #include "seriesinfo.h"
44 #include "osdvector.h"
45 #include "tvmedia.h"
46 #include <climits>
47
48 #define VOMP_PROTOCOLL_VERSION 0x00000402
49
50 VDR* VDR::instance = NULL;
51 #ifdef VOMP_MEDIAPLAYER
52 //prepare a request
53 //will create a request package from a command variable and fill this
54 //caller has to destroy buffer
55 static SerializeBuffer * prepareRequest(VDR_Command *cmd) {
56   SerializeBuffer *buf=new SerializeBuffer(512,false,true);
57   if (cmd->serialize(buf) != 0) {
58     delete buf;
59     return NULL;
60   }
61   return buf;
62 }
63
64 //handle request/response
65 //TODO avoid copy of buffer (needs extension of requestpacket)
66 //TODO avoid command 2x (needs some more restructuring)
67 SerializeBuffer * VDR::doRequestResponse(SerializeBuffer *rq,int cmd) {
68   VDR_RequestPacket *rt=new VDR_RequestPacket;
69   if (! rt) {
70     delete rq;
71     return NULL;
72   }
73   if (! rt->init(cmd,true,rq->getCurrent()-rq->getStart())) {
74     delete rq;
75     delete rt;
76     return NULL;
77   }
78   if (! rt->copyin(rq->getStart(),(ULONG)(rq->getCurrent()-rq->getStart()))) {
79     delete rq;
80     delete rt;
81     return NULL;
82   }
83   delete rq;
84   VDR_ResponsePacket *rp=RequestResponse(rt);
85   logger->log("doRequestResponse",Log::DEBUG,"got response %p",rp);
86   if ( !rp) {
87     delete rt;
88     return NULL;
89   }
90   SerializeBuffer *buf=new SerializeBuffer(rp->getUserData(),rp->getUserDataLength(),true,true,false);
91   delete rp;
92   return buf;
93 }
94
95
96
97 //deserialize a received response
98 //delete the package
99 //return !=0 on error
100 static int decodeResponse(SerializeBuffer *rp,VDR_Command *c) {
101   ULONG expected=c->command;
102   if (c->deserialize(rp) != 0) {
103     delete rp;
104     Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unable to deserialize for command %lu",expected);
105     return -1;
106   }
107   delete rp;
108   if (c->command != expected) {
109    Log::getInstance()->log("VDR", Log::ERR, "decodeResponse unexpected response received 0x%lx, expected 0x%lx",c->command,expected);
110     return -1;
111   }
112   Log::getInstance()->log("VDR", Log::DEBUG, "decodeResponse successfully decoded command 0x%lx",expected);
113   return 0;
114 }
115
116 #endif
117
118 VDR::VDR()
119 {
120   if (instance) return;
121   instance = this;
122   initted = 0;
123   findingServer = 0;
124   tcp = NULL;
125   connected = false;
126   maxChannelNumber = 0;
127   channelNumberWidth = 1;
128   doVDRShutdown = false;
129   TEMP_SINGLE_VDR_PR = NULL;
130 #ifdef VOMP_MEDIAPLAYER
131   providerId=MPROVIDERID_VDR;
132   subRange=MPROVIDERRANGE_VDR;
133   MediaPlayerRegister::getInstance()->registerMediaProvider(this,MPROVIDERID_VDR,MPROVIDERRANGE_VDR);
134 #endif
135 }
136
137 VDR::~VDR()
138 {
139   instance = NULL;
140   if (initted) shutdown();
141 }
142
143 VDR* VDR::getInstance()
144 {
145   return instance;
146 }
147
148 int VDR::init(int tport)
149 {
150   if (initted) return 0;
151   initted = 1;
152   port = tport;
153   logger = Log::getInstance();
154   return 1;
155 }
156
157 int VDR::shutdown()
158 {
159   if (!initted) return 0;
160   initted = 0;
161   disconnect();
162   return 1;
163 }
164
165 void VDR::findServers(vector<VDRServer>& servers)
166 {
167   Wol* wol = Wol::getInstance();
168   findingServer = 1;
169   char message[15];
170   memset(message, 0, 15);
171   strcpy(message, "VDP-0001");
172   /*tcp->getMAC(&message[9]); put mac here when TCP modified to do this*/
173
174 #if IPV6
175   // FIXME Horrible hack. Rewrite all this.
176   // Change away from relying on the dsock select to do the timing
177   // Do timing here and let UDP4 / UDP6 objects/threads just wait
178   // for responses
179   VDP6 vdp6;
180   vdp6.run();
181 #endif
182
183   DatagramSocket ds(0);
184   int haveAtLeastOne = 0;
185   int retval;
186   int waitType = 1;
187   bool firstloop = true;
188   while(findingServer)
189   {
190     if (waitType == 1)
191     {
192       ds.shutdown();
193       ds.init();
194       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
195       ds.send("255.255.255.255", 51051, message, 15);
196       ds.send("255.255.255.255", 51052, message, 15);
197       ds.send("255.255.255.255", 51053, message, 15);
198       ds.send("255.255.255.255", 51054, message, 15);
199       ds.send("255.255.255.255", 51055, message, 15);
200       if(!firstloop) wol->doWakeUp();
201     }
202     retval = ds.waitforMessage(waitType);
203
204     if (retval == 2) // we got a reply
205     {
206       waitType = 2;
207       
208       char* vdpreply = ds.getData();
209       if ((ds.getDataLength() >= 24) && !strncmp(vdpreply, "VDP-0002", 8))
210       {
211         VDRServer newServer;
212         // FIXME upgrade this to look for a return IP in the reply packet
213         newServer.ip = new char[16];
214         strcpy(newServer.ip, ds.getFromIPA());
215
216         USHORT newServerPort;
217         memcpy(&newServerPort, &vdpreply[26], 2);
218         newServer.port = ntohs(newServerPort);
219
220         ULONG newServerVersion;
221         memcpy(&newServerVersion, &vdpreply[28], 4);
222         newServer.version = ntohl(newServerVersion);
223
224         int newServerNameLength = ds.getDataLength() - 32;
225         newServer.name = new char[newServerNameLength];
226         strcpy(newServer.name, &vdpreply[32]);
227
228         servers.push_back(newServer);
229         haveAtLeastOne = 1;
230       }
231     }
232     else
233     {
234       if (haveAtLeastOne) break;
235 #if IPV6
236       if (vdp6.numFound()) break;
237 #endif
238
239       waitType = 1;
240       firstloop = false;
241 /* For DEBUGGING *
242       { VDRServer newServer;
243       newServer.ip = new char[16];
244       strcpy(newServer.ip, "192.168.1.7");
245       newServer.name = new char[6];
246       strcpy(newServer.name,"debug");
247       servers.push_back(newServer);
248       waitType = 2;
249       haveAtLeastOne = 1;}/ * */
250     }
251   }
252   logger->log("VDR", Log::NOTICE, "END loop");
253
254 #if IPV6
255   vdp6.stop();
256   vector<VDRServer>* servers6 = vdp6.getServers();
257   
258   // Add IPv6 found servers to servers vector, if not in servers already
259   // Free buffers from VDRServer objects if not taken. (Itching for that rewrite already).
260
261   for(auto i6 = servers6->begin(); i6 != servers6->end(); i6++)
262   {
263     bool found = false;
264
265     for(auto i4 = servers.begin(); i4 != servers.end(); i4++)
266     {
267       if (!strcmp(i4->name, i6->name)) { found = true; break; }
268     }
269
270     if (found)
271     {
272       delete[] i6->name;
273       delete[] i6->ip;
274     }
275     else
276     {
277       servers.push_back(*i6);
278     }
279   }
280
281 #endif
282
283   sort(servers.begin(), servers.end(), ServerSorter());
284 }
285
286 void VDR::cancelFindingServer()
287 {
288   findingServer = 0;
289 }
290
291 void VDR::setServerIP(char* newIP)
292 {
293   strcpy(serverIP, newIP);
294 }
295
296 void VDR::setServerPort(USHORT newPort)
297 {
298   serverPort = newPort;
299 }
300
301 int VDR::connect()
302 {
303   maxChannelNumber = 0;
304   channelNumberWidth = 1;
305
306   if (tcp) delete tcp;
307   tcp = new TCP();
308   if (tcp->connectTo(serverIP, serverPort))
309   {
310     connected = true;
311     threadStart();
312     return 1;
313   }
314   else
315   {
316     return 0;
317   }
318 }
319
320 void VDR::disconnect()
321 {
322   threadCancel();
323   if (tcp) delete tcp;
324   tcp = NULL;
325   connected = false;
326   logger->log("VDR", Log::DEBUG, "Disconnect");
327 }
328
329 void VDR::setReceiveWindow(size_t size)
330 {
331   if (connected && size) tcp->setReceiveWindow(size);
332 }
333
334 ///////////////////////////////////////////////////////
335
336 void VDR::threadMethod()
337 {
338   logger->log("VDR", Log::DEBUG, "VDR RUN");  
339
340   threadSetKillable(); // FIXME - change this to deal with the EDRs
341   
342   ULONG channelID;
343   
344   ULONG requestID;
345   ULONG userDataLength;
346   UCHAR* userData;
347
348   ULONG streamID;
349   ULONG flag;
350
351   VDR_ResponsePacket* vresp;
352   
353   ULONG timeNow = 0;
354   ULONG lastKAsent = 0;
355   ULONG lastKArecv = time(NULL);
356   int readSuccess;
357
358   while(1)
359   {
360     timeNow = time(NULL);
361     
362     readSuccess = tcp->readData((UCHAR*)&channelID, sizeof(ULONG));  // 2s timeout atm
363
364     if (!readSuccess)
365     {
366       //logger->log("VDR", Log::DEBUG, "Net read timeout");
367       if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread
368     }
369       
370     // Error or timeout.
371
372     if (!lastKAsent) // have not sent a KA
373     {
374       if (lastKArecv < (timeNow - 5))
375       {
376         logger->log("VDR", Log::DEBUG, "Sending KA packet");
377         if (!sendKA(timeNow))
378         {
379           logger->log("VDR", Log::DEBUG, "Could not send KA, calling connectionDied");
380           connectionDied();
381           return;
382         }
383         lastKAsent = timeNow;
384       }
385     }
386     else
387     {
388       if (lastKAsent <= (timeNow - 10))
389       {
390         logger->log("VDR", Log::DEBUG, "lastKA over 10s ago, calling connectionDied");
391         connectionDied();
392         return;
393       }    
394     }
395
396     if (!readSuccess) continue; // no data was read but the connection is ok.
397     
398     // Data was read
399             
400     channelID = ntohl(channelID);
401
402     if (channelID == CHANNEL_REQUEST_RESPONSE)
403     {
404       if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
405       requestID = ntohl(requestID);
406       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
407       userDataLength = ntohl(userDataLength);
408       if (userDataLength > 5000000) break; // how big can these packets get?
409       userData = NULL;
410       if (userDataLength > 0)
411       {
412         userData = (UCHAR*)malloc(userDataLength);
413         if (!userData) break;
414         if (!tcp->readData(userData, userDataLength)) break;
415       }
416
417       vresp = new VDR_ResponsePacket();  
418       vresp->setResponse(requestID, userData, userDataLength);
419       logger->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
420
421       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
422       {
423         // If edFindAndCall returns true, edr was called and vresp was handed off.
424         // else, delete vresp here.
425         delete vresp;
426       }
427     }
428     else if (channelID == CHANNEL_STREAM || channelID == CHANNEL_TVMEDIA)
429     {
430       if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
431       streamID = ntohl(streamID);
432
433       if (!tcp->readData((UCHAR*)&flag, sizeof(ULONG))) break;
434       flag = ntohl(flag);
435
436       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; 
437       userDataLength = ntohl(userDataLength);
438       userData = NULL;
439       if (userDataLength > 0)
440       {
441         userData = (UCHAR*)malloc(userDataLength);
442         if (!userData) break;
443         if (!tcp->readData(userData, userDataLength)) break;
444       }
445
446       vresp = new VDR_ResponsePacket();    
447       vresp->setStream(streamID, flag, userData, userDataLength, channelID);
448       //logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength);
449
450       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
451       {
452         // If edFindAndCall returns true, edr was called and vresp was handed off.
453         // else, delete vresp here.
454         delete vresp;
455       }
456     }
457     else if (channelID == CHANNEL_KEEPALIVE)
458     {
459       ULONG KAreply = 0;
460       if (!tcp->readData((UCHAR*)&KAreply, sizeof(ULONG))) break;
461       KAreply = (ULONG)ntohl(KAreply);
462       if (KAreply == lastKAsent) // successful KA response
463       {
464         lastKAsent = 0;
465         lastKArecv = KAreply;
466         logger->log("VDR", Log::DEBUG, "Rxd correct KA reply");
467       }
468     }
469     else
470     {
471       logger->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
472       break;
473     }
474     threadCheckExit();
475
476
477     // Who deletes vresp?
478     // If RR, the individual protocol functions must delete vresp.
479     // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
480   }
481  
482   connectionDied();
483 }
484
485 void VDR::connectionDied()
486 {
487   // Called from within threadMethod to do cleanup if it decides the connection has died
488
489   connected = false; // though actually it could still be connected until someone calls vdr->disconnect
490
491   // Need to wake up any waiting channel 1 request-response threads
492   // Normally this is done by a packet coming in with channelid and requestid      
493   // Instead, go through the list and for each channel 1 edr, make an empty vresp
494   // An empty vresp will have userData == NULL, which means vresp->noResponse() == true
495
496   // If it's a stream receiver, generate a stream packet with flag == connection_lost
497
498   edLock();
499   VDR_PacketReceiver* vdrpr;
500   VDR_ResponsePacket* vresp;
501   while(receivers.size())
502   {
503     vdrpr = (VDR_PacketReceiver*) *(receivers.begin());
504     if (vdrpr->receiverChannel == CHANNEL_REQUEST_RESPONSE)
505     {
506       vresp = new VDR_ResponsePacket();
507       vresp->setResponse(vdrpr->requestSerialNumber, NULL, 0);
508       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for request serial %lu", vdrpr->requestSerialNumber);
509       edUnlock();
510       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
511       {
512         // If edFindAndCall returns true, edr was called and vresp was handed off.
513         // else, delete vresp here.
514         logger->log("VDR", Log::ERR, "Timeouts: no waiting thread found for request serial %lu !!!", vdrpr->requestSerialNumber);
515         delete vresp;
516       }
517       edLock();
518     }
519     else if (vdrpr->receiverChannel == CHANNEL_STREAM || vdrpr->receiverChannel == CHANNEL_TVMEDIA)
520     {
521       vresp = new VDR_ResponsePacket();
522       vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0, vdrpr->receiverChannel);
523       logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID);
524       edUnlock();
525       if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
526       {
527         // If edFindAndCall returns true, edr was called and vresp was handed off.
528         // else, delete vresp here.
529         logger->log("VDR", Log::ERR, "Timeouts: no waiting stream receiver found for streamid %lu !!!", vdrpr->streamID);
530         delete vresp;
531       }
532       edLock();
533       
534       for(EDRL::iterator i = receivers.begin(); i != receivers.end(); i++)
535         if ((VDR_PacketReceiver*)*i == vdrpr) { receivers.erase(i); break; }
536     }
537   }
538   edUnlock();
539   // Ok, all event receviers should be dealt with. just in case there weren't any, inform command
540   logger->log("VDR", Log::DEBUG, "edUnlock at end of connectionDied");
541
542   Command::getInstance()->connectionLost();
543 }
544
545 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
546 {
547   // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
548   // userTag is a VDR_ResponsePacket made in threadMethod
549
550   VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
551   VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
552   
553   // Is vresp for vdrpr ?
554   
555   ULONG packetChannel = vresp->getChannelID();
556   //logger->log("VDR", Log::DEBUG, "TVMedia debug %d %d %x", vdrpr->receiverChannel,packetChannel,vdrpr);
557   if (vdrpr->receiverChannel != packetChannel) return false;
558
559   if (packetChannel == CHANNEL_REQUEST_RESPONSE)
560   {
561     if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
562   }
563   else if (packetChannel == CHANNEL_STREAM)
564   {
565     if (vdrpr->streamID == vresp->getStreamID()) return true;
566   }
567   else if (packetChannel == CHANNEL_TVMEDIA)
568   {
569     if (vdrpr->streamID == vresp->getStreamID()) return true;
570   }
571
572   return false;
573 }
574
575 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
576 {
577   //logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
578
579   if (!connected)
580   {
581     logger->log("VDR", Log::DEBUG, "RR when !connected");
582     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
583     return vresp; // "no-response" return
584   }
585
586   // ED make new VDR and register
587   // make a VDR_PacketReceiver
588   // - init with serial number of request packet
589
590   VDR_PacketReceiver vdrpr;
591 //  vdrpr.requestTime = time(NULL);
592   vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
593   vdrpr.requestSerialNumber = vrp->getSerial();
594
595   edRegister(&vdrpr);
596    
597   edLock();  
598
599   if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
600   {
601     edUnlock();
602     edUnregister(&vdrpr);
603     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
604     return vresp; // "no-response" return
605   }
606
607   // Sleep and block this thread. The sleep unlocks the mutex
608   logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());
609   edSleepThisReceiver(&vdrpr);
610   logger->log("VDR", Log::DEBUG, "RR unsleep");
611     
612   // Woken because a response packet has arrived, mutex will be locked
613   logger->log("VDR", Log::DEBUG, "Packet delivered to me, requestID: %lu", vdrpr.save_vresp->getRequestID());
614   
615   edUnlock();
616   return vdrpr.save_vresp;
617 }
618
619 bool VDR::sendKA(ULONG timeStamp)
620 {
621   char buffer[8];
622
623   int pos=0;
624   ULONG ul=CHANNEL_KEEPALIVE;
625   buffer[pos++]=(ul>>24)&0xff;
626   buffer[pos++]=(ul>>16)&0xff;
627   buffer[pos++]=(ul>>8)&0xff;
628   buffer[pos++]=ul &0xff;
629   ul=timeStamp;
630   buffer[pos++]=(ul>>24)&0xff;
631   buffer[pos++]=(ul>>16)&0xff;
632   buffer[pos++]=(ul>>8)&0xff;
633   buffer[pos++]=ul &0xff;
634   if ((ULONG)tcp->sendData(buffer, 8) != 8) return false;
635   return true;
636 }
637
638 /////////////////////////////////////////////////////////////////////////////
639
640 // Here VDR takes a break for the VDR_PacketReceiver helper class
641
642 void VDR_PacketReceiver::call(void* userTag, bool& r_deregisterEDR, bool& r_wakeThread, bool& r_deleteEDR)
643 {
644   if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
645   {
646     // It's a RR. Save vresp and, signal the waiting thread and return.
647     // VDR::RequestResponse will be blocking waiting for this to happen.
648     // That function has a pointer to this object and can read save_vresp.
649     save_vresp = (VDR_ResponsePacket*)userTag;
650
651     r_deregisterEDR = true;
652     r_wakeThread = true;
653     r_deleteEDR = false;
654   }
655   else if (receiverChannel == VDR::CHANNEL_STREAM)
656   {
657     // It's a stream packet. Pass off the stream data to streamReceiver,
658     // delete the vresp. Keep this PacketReceiver for the next stream packet.
659     VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
660     streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength());
661     delete vresp;
662
663     r_deregisterEDR = false;
664     r_wakeThread = false;
665     r_deleteEDR = false;
666   }
667   else if (receiverChannel == VDR::CHANNEL_TVMEDIA)
668   {
669     // It's TVMedia
670     // Pass off the vresp object to OSDVector
671     // This used to return true which would signal the cond (wake the thread)
672     // but am going to try setting this to false because I don't know that there is a thread to signal
673     // delete the EDR. It's made once per media requested and wasn't owned/deleted by anything before
674
675     VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
676     Log::getInstance()->log("VDR", Log::DEBUG, "TVMedia Pictures arrived VDR %x", vresp->getStreamID());
677     OsdVector *osd=dynamic_cast<OsdVector*>(Osd::getInstance());
678     if (osd) osd->getPictReader()->receivePicture(vresp);
679     // else delete vresp; //nonsense // only rpi does CHANNEL_TVMEDIA, rpi has osdvector. therefore, can't get here.
680
681     r_deregisterEDR = true;
682     r_wakeThread = false;
683     r_deleteEDR = true;
684   }
685   else abort(); // unknown receiverChannel, should not happen
686 }
687
688 /////////////////////////////////////////////////////////////////////////////
689
690 int VDR::doLogin(unsigned int* v_server_min, unsigned int* v_server_max, unsigned int* v_client,
691                 ASLPrefList& list, int &subtitles)
692 {
693   VDR_RequestPacket vrp;
694   if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
695
696   char* mactemp[6];
697   tcp->getMAC((char*)mactemp);
698   if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
699
700   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
701   if (vresp->noResponse()) { delete vresp; return 0; }
702
703   ULONG vdrTime = vresp->extractULONG();
704   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
705   long vdrTimeOffset = vresp->extractLONG();
706   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
707
708   unsigned int version_min=vresp->extractULONG();
709
710   *v_server_min=version_min;
711   unsigned int version_max=vresp->extractULONG();
712   *v_server_max=version_max;
713   *v_client=VOMP_PROTOCOLL_VERSION;
714
715   if (0x00000302 <= version_max) {
716           unsigned int numlangcodes = vresp->extractULONG();
717           subtitles = vresp->extractULONG();
718           list.clear();
719           for (unsigned int i=0; i<numlangcodes; i++) {
720                   ASLPref newpref;
721                   newpref.audiopref = vresp->extractLONG();
722                   newpref.subtitlepref = vresp->extractLONG();
723                   newpref.langcode = vresp->extractStdString();
724                   //logger->log("VDR", Log::DEBUG, "Langpref %s %d %d", newpref.langcode.c_str(),  newpref.audiopref,  newpref.subtitlepref);
725                   list.push_back(newpref);
726           }
727   }
728
729
730   delete vresp;
731
732   if ((version_min > VOMP_PROTOCOLL_VERSION)
733                   || (version_max < VOMP_PROTOCOLL_VERSION) ) {
734
735           return 0;
736
737   }
738
739   // Set the time and zone on the MVP only
740
741 #if !defined(WIN32) && !defined(__ANDROID__)
742   struct timespec currentTime;
743   currentTime.tv_sec = vdrTime;
744   currentTime.tv_nsec = 0;
745
746   int b = clock_settime(CLOCK_REALTIME, &currentTime);
747
748   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
749
750   // now make a TZ variable and set it
751   char sign;
752   int hours;
753   int minutes;
754   if (vdrTimeOffset > 0) sign = '-';
755   else sign = '+';
756
757   vdrTimeOffset = abs(vdrTimeOffset);
758
759   hours = (int)vdrTimeOffset / 3600;
760   minutes = vdrTimeOffset % 3600;
761
762   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
763
764   minutes = (int)minutes / 60;
765
766   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
767
768   char newTZ[30];
769   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
770   setenv("TZ", newTZ, 1);
771
772   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
773 #endif
774
775   setCharset(Osd::getInstance()->charSet());
776
777   return 1;
778 }
779
780 bool VDR::LogExtern(const char* logString)
781 {
782   if (!connected) return false;
783   int stringLength = strlen(logString);
784   int packetLength = stringLength + 8;
785   char *buffer=new char[packetLength + 1];
786   int pos=0;
787   ULONG ul=CHANNEL_NETLOG;
788   buffer[pos++]=(ul>>24)&0xff;
789   buffer[pos++]=(ul>>16)&0xff;
790   buffer[pos++]=(ul>>8)&0xff;
791   buffer[pos++]=ul &0xff;
792   ul=stringLength;
793   buffer[pos++]=(ul>>24)&0xff;
794   buffer[pos++]=(ul>>16)&0xff;
795   buffer[pos++]=(ul>>8)&0xff;
796   buffer[pos++]=ul &0xff;
797
798   strcpy(&buffer[8], logString);
799   
800   if (tcp->sendData(buffer, packetLength) != packetLength)
801   {
802     connected = false; // stop the rest of the connection  
803     delete [] buffer;
804     return false;
805   }
806   delete [] buffer;
807   return true;
808 }
809
810 bool VDR::setCharset(int charset)
811 {
812   VDR_RequestPacket vrp;
813   if (!vrp.init(VDR_SETCHARSET, true, sizeof(ULONG))) return false;
814   if (!vrp.addULONG(charset)) return false;
815
816   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
817   if (vresp->noResponse()) { delete vresp; return false; }
818
819   ULONG success = vresp->extractULONG();
820   delete vresp;
821
822   if (!success) return false;
823
824   return true;
825 }
826
827 bool VDR::getRecordingsList(RecMan* recman)
828 {
829   VDR_RequestPacket vrp;
830   if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
831
832   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
833   if (vresp->noResponse()) { delete vresp; return false; }
834
835   ULONG totalSpace = vresp->extractULONG();
836   ULONG freeSpace = vresp->extractULONG();
837   ULONG percent = vresp->extractULONG();
838
839   recman->setStats(totalSpace, freeSpace, percent);
840
841   ULONG start;
842   UCHAR isNew;
843   char* name;
844   char* fileName;
845
846   while (!vresp->end())
847   {
848     start = vresp->extractULONG();
849     isNew = vresp->extractUCHAR();
850     name = vresp->extractString();
851     fileName = vresp->extractString();
852     recman->addEntry(isNew, start, name, fileName);
853     delete[] name;
854     delete[] fileName;
855   }
856   delete vresp;
857
858   return true;
859 }
860
861 int VDR::deleteRecording(char* fileName)
862 {
863   VDR_RequestPacket vrp;
864   if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
865   if (!vrp.addString(fileName)) return 0;
866   
867   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
868   if (vresp->noResponse()) { delete vresp; return 0; }
869   
870   int toReturn = (int)vresp->extractULONG();
871   delete vresp;
872
873   return toReturn;
874 }
875
876 int VDR::deleteRecResume(char* fileName)
877 {
878   VDR_RequestPacket vrp;
879   if (!vrp.init(VDR_DELETERECRESUME, true, strlen(fileName) + 1)) return 0;
880   if (!vrp.addString(fileName)) return 0;
881
882   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
883   if (vresp->noResponse()) { delete vresp; return 0; }
884
885   int toReturn = (int)vresp->extractULONG();
886   delete vresp;
887
888   return toReturn;
889 }
890
891 char* VDR::moveRecording(char* fileName, char* newPath)
892 {
893   VDR_RequestPacket vrp;
894   if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
895   if (!vrp.addString(fileName)) return NULL;
896   if (!vrp.addString(newPath)) return NULL;
897   
898   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
899   if (vresp->noResponse()) { delete vresp; return NULL; }
900   
901   char* toReturn = NULL;
902   int success = (int)vresp->extractULONG();
903   if (success == 1)
904   {
905     toReturn = vresp->extractString();
906   }
907
908   delete vresp;
909
910   return toReturn;
911 }
912
913 ChannelList* VDR::getChannelsList(ULONG type)
914 {
915   VDR_RequestPacket vrp;
916   if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
917
918   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
919   if (vresp->noResponse()) { delete vresp; return NULL; }
920   
921   ChannelList* chanList = new ChannelList();
922
923   bool h264support=Video::getInstance()->supportsh264();
924   bool mpeg2support=Video::getInstance()->supportsmpeg2();
925
926   while (!vresp->end())
927   {
928     Channel* chan = new Channel();
929     chan->number = vresp->extractULONG();
930     chan->type = vresp->extractULONG();
931     chan->name = vresp->extractString();
932     chan->vstreamtype = vresp->extractULONG();
933
934     if (chan->type == type && ((chan->vstreamtype==0x1b && h264support)|| (chan->vstreamtype!=0x1b &&mpeg2support)) )
935     {
936       chanList->push_back(chan);
937       logger->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
938       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
939     }
940     else
941     {
942       delete chan;
943     }
944   }
945
946   delete vresp;
947
948   if (maxChannelNumber > 99999)
949     channelNumberWidth = 6;
950   else if (maxChannelNumber > 9999)
951     channelNumberWidth = 5;
952   else if (maxChannelNumber > 999)
953     channelNumberWidth = 4;
954   else if (maxChannelNumber > 99)
955     channelNumberWidth = 3;
956   else if (maxChannelNumber > 9)
957     channelNumberWidth = 2;
958   else
959     channelNumberWidth = 1;
960
961   return chanList;
962 }
963
964 int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
965 {
966   VDR_RequestPacket vrp;
967   if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
968   if (!vrp.addULONG(number)) return 0;
969   
970   
971   VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
972   vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
973   vdrpr->streamID = vrp.getSerial();
974   vdrpr->streamReceiver = tstreamReceiver;
975   edRegister(vdrpr);
976   TEMP_SINGLE_VDR_PR = vdrpr;
977   
978   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
979   if (vresp->noResponse())
980   {
981     delete vresp;
982     edUnregister(vdrpr);
983     delete vdrpr;
984     return 0;
985   }
986   
987   int toReturn = (int)vresp->extractULONG();
988   logger->log("VDR", Log::DEBUG, "VDR said %lu to start streaming request", toReturn);
989   delete vresp;
990
991   return toReturn;
992 }
993
994 int VDR::stopStreaming()
995 {
996   VDR_RequestPacket vrp;
997   if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
998
999   if (TEMP_SINGLE_VDR_PR) // this block only needs to be done if it was a live stream
1000                           // TEMP_SINGLE_VDR_PR will not be set unless we are streaming a channel
1001   {
1002     edUnregister(TEMP_SINGLE_VDR_PR);
1003     delete TEMP_SINGLE_VDR_PR;
1004     TEMP_SINGLE_VDR_PR = NULL;
1005   }
1006
1007   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1008   if (vresp->noResponse()) { delete vresp; return 0; }
1009   
1010   int toReturn = (int)vresp->extractULONG();
1011   delete vresp;
1012
1013   return toReturn;
1014 }
1015
1016 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
1017 {
1018   VDR_RequestPacket vrp;
1019   if (!vrp.init(VDR_GETBLOCK, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
1020   if (!vrp.addULLONG(position)) return NULL;
1021   if (!vrp.addULONG(maxAmount)) return NULL;
1022
1023   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1024   if (vresp->noResponse()) { delete vresp; return NULL; }
1025
1026   if (vresp->serverError())
1027   {
1028     logger->log("VDR", Log::DEBUG, "Detected getblock 0");
1029     *amountReceived = 0;
1030     delete vresp;
1031     return NULL;
1032   }
1033
1034   // Special handling for getblock
1035   UCHAR* toReturn = vresp->getUserData();
1036   *amountReceived = vresp->getUserDataLength();
1037   
1038   delete vresp;
1039   
1040   return toReturn;
1041 }
1042
1043 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording)
1044 {
1045   VDR_RequestPacket vrp;
1046   if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
1047   if (!vrp.addString(fileName)) return 0;
1048
1049   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1050   if (vresp->noResponse()) { delete vresp; return 0; }
1051   
1052   ULLONG lengthBytes = vresp->extractULLONG();
1053   ULONG lengthFrames = vresp->extractULONG();
1054   UCHAR isPesRecording = vresp->extractUCHAR();
1055   delete vresp;
1056
1057   *totalFrames = lengthFrames;
1058   *IsPesRecording = (isPesRecording);//convert Uchar to bool
1059
1060   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording);
1061
1062   return lengthBytes;
1063 }
1064
1065 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
1066 {
1067   VDR_RequestPacket vrp;
1068   if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
1069   if (!vrp.addULONG(frameNumber)) return 0;
1070
1071   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1072   if (vresp->noResponse()) { delete vresp; return 0; }
1073   
1074   ULLONG position = vresp->extractULLONG();
1075   delete vresp;
1076   
1077   logger->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
1078
1079   return position;
1080 }
1081
1082 ULONG VDR::frameNumberFromPosition(ULLONG position)
1083 {
1084   VDR_RequestPacket vrp;
1085   if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
1086   if (!vrp.addULLONG(position)) return 0;
1087
1088   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1089   if (vresp->noResponse()) { delete vresp; return 0; }
1090   
1091   ULONG framenumber = vresp->extractULONG();
1092   delete vresp;
1093   
1094   logger->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
1095
1096   return framenumber;
1097 }
1098
1099 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
1100 {
1101   VDR_RequestPacket vrp;
1102   if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
1103   if (!vrp.addULONG(frameNumber)) return false;
1104   if (!vrp.addULONG(direction)) return false;
1105
1106   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1107   if (vresp->noResponse()) { delete vresp; return false; }
1108   
1109   if (vresp->serverError())
1110   {
1111     logger->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
1112     delete vresp;
1113     return false;
1114   }
1115
1116   *rfilePosition = vresp->extractULLONG();
1117   *rframeNumber = vresp->extractULONG();
1118   *rframeLength = vresp->extractULONG();
1119
1120   delete vresp;
1121
1122   logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
1123
1124   return true;
1125 }
1126
1127 EventList* VDR::getChannelSchedule(ULONG number)
1128 {
1129   time_t now;
1130   time(&now);
1131   return getChannelSchedule(number, now, 24 * 60 * 60);
1132 }
1133
1134 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
1135 {
1136 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
1137
1138   VDR_RequestPacket vrp;
1139   if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
1140   if (!vrp.addULONG(number)) return NULL;
1141   if (!vrp.addULONG(start)) return NULL;
1142   if (!vrp.addULONG(duration)) return NULL;
1143
1144   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1145   if (vresp->noResponse()) { delete vresp; return NULL; }
1146
1147   // received a ulong(0) - schedules error in the plugin
1148   if (vresp->serverError())
1149   {
1150     delete vresp;
1151     return NULL;
1152   }
1153
1154   EventList* eventList = new EventList();
1155
1156   while (!vresp->end())
1157   {
1158     Event* event = new Event();
1159     event->id = vresp->extractULONG();
1160     event->time = vresp->extractULONG();
1161     event->duration = vresp->extractULONG();
1162     event->title = vresp->extractString();
1163     event->subtitle = vresp->extractString();
1164     event->description = vresp->extractString();
1165     eventList->push_back(event);
1166   }
1167
1168   delete vresp;
1169
1170   logger->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
1171   return eventList;
1172 }
1173
1174 int VDR::configSave(const char* section, const char* key, const char* value)
1175 {
1176   VDR_RequestPacket vrp;
1177   if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
1178   if (!vrp.addString(section)) return 0;
1179   if (!vrp.addString(key)) return 0;
1180   if (!vrp.addString(value)) return 0;
1181
1182   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1183   if (vresp->noResponse()) { delete vresp; return 0; }
1184
1185   int toReturn = (int)vresp->extractULONG();
1186   delete vresp;
1187
1188   return toReturn;
1189 }
1190
1191 char* VDR::configLoad(const char* section, const char* key)
1192 {
1193   VDR_RequestPacket vrp;
1194   if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
1195   if (!vrp.addString(section)) return NULL;
1196   if (!vrp.addString(key)) return NULL;
1197
1198   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1199   if (vresp->noResponse()) { delete vresp; return NULL; }
1200   
1201   char* toReturn = vresp->extractString();
1202   delete vresp;
1203
1204   return toReturn;
1205 }
1206
1207 RecTimerList* VDR::getRecTimersList()
1208 {
1209   VDR_RequestPacket vrp;
1210   if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
1211
1212   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1213   if (vresp->noResponse()) { delete vresp; return NULL; }
1214
1215   RecTimerList* recTimerList = new RecTimerList();
1216
1217   ULONG numTimers = vresp->extractULONG();
1218   if (numTimers > 0)
1219   {
1220     RecTimer* newRecTimer;
1221     char* tempString;
1222
1223     while (!vresp->end())
1224     {
1225       newRecTimer = new RecTimer();
1226       newRecTimer->active = vresp->extractULONG();
1227       newRecTimer->recording = vresp->extractULONG();
1228       newRecTimer->pending = vresp->extractULONG();
1229       newRecTimer->priority = vresp->extractULONG();
1230       newRecTimer->lifeTime = vresp->extractULONG();
1231       newRecTimer->channelNumber = vresp->extractULONG();
1232       newRecTimer->startTime = vresp->extractULONG();
1233       newRecTimer->stopTime = vresp->extractULONG();
1234       newRecTimer->day = vresp->extractULONG();
1235       newRecTimer->weekDays = vresp->extractULONG();
1236
1237       tempString = vresp->extractString();
1238       newRecTimer->setFile(tempString);
1239       delete[] tempString;
1240
1241       recTimerList->push_back(newRecTimer);
1242       logger->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1243         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1244         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1245     }
1246   }
1247
1248   delete vresp;
1249
1250   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1251
1252   return recTimerList;
1253 }
1254
1255 ULONG VDR::setEventTimer(char* timerString)
1256 {
1257   VDR_RequestPacket vrp;
1258   if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
1259   if (!vrp.addString(timerString)) return 0;
1260
1261   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1262   if (vresp->noResponse()) { delete vresp; return 0; }
1263   
1264   ULONG toReturn = vresp->extractULONG();
1265   delete vresp;
1266
1267   return toReturn;
1268 }
1269
1270 RecInfo* VDR::getRecInfo(char* fileName)
1271 {
1272   VDR_RequestPacket vrp;
1273   if (!vrp.init(VDR_GETRECINFO2, true, strlen(fileName) + 1)) return NULL;
1274   if (!vrp.addString(fileName)) return NULL;
1275   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1276
1277   if (vresp->noResponse()) { delete vresp; return NULL; }
1278
1279   if (vresp->serverError())
1280   {
1281     logger->log("VDR", Log::DEBUG, "Could not get rec info");
1282     delete vresp;
1283     return NULL;
1284   }
1285
1286   RecInfo* recInfo = new RecInfo();
1287
1288   recInfo->timerStart = vresp->extractULONG();
1289   recInfo->timerEnd = vresp->extractULONG();
1290   recInfo->resumePoint = vresp->extractULONG();
1291   recInfo->summary = vresp->extractString();
1292
1293   ULONG numComponents = vresp->extractULONG();
1294   if (numComponents)
1295   {
1296     recInfo->setNumComponents(numComponents);
1297     for (ULONG i = 0; i < numComponents; i++)
1298     {
1299       recInfo->streams[i] = vresp->extractUCHAR();
1300       recInfo->types[i] = vresp->extractUCHAR();
1301       recInfo->languages[i] = vresp->extractString();
1302       recInfo->descriptions[i] = vresp->extractString();
1303     }
1304   }
1305   recInfo->fps=vresp->extractdouble();
1306   recInfo->title=vresp->extractString();
1307   
1308   // New stuff
1309   recInfo->channelName = vresp->extractString();
1310   recInfo->duration = vresp->extractULONG();
1311   recInfo->fileSize = vresp->extractULONG();
1312   recInfo->priority = vresp->extractULONG();
1313   recInfo->lifetime = vresp->extractULONG();
1314
1315   recInfo->print();
1316
1317   delete vresp;
1318   return recInfo;
1319 }
1320
1321 // FIXME obselete
1322 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1323 {
1324   VDR_RequestPacket vrp;
1325   if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
1326
1327   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1328   if (vresp->noResponse()) { delete vresp; return 0; }
1329   
1330   ULLONG lengthBytes = vresp->extractULLONG();
1331   ULONG lengthFrames = vresp->extractULONG();
1332   delete vresp;
1333   
1334   logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1335
1336   *totalFrames = lengthFrames;
1337   return lengthBytes;
1338 }
1339
1340 MarkList* VDR::getMarks(char* fileName)
1341 {
1342   VDR_RequestPacket vrp;
1343   if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
1344   if (!vrp.addString(fileName)) return NULL;
1345
1346   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1347   if (vresp->noResponse()) { delete vresp; return NULL; }
1348   
1349   if (vresp->serverError())
1350   {
1351     delete vresp;
1352     return NULL;
1353   }
1354
1355   MarkList* markList = new MarkList();
1356
1357   while (!vresp->end())
1358   {
1359     Mark* mark = new Mark();
1360     mark->pos = vresp->extractULONG();
1361
1362     markList->push_back(mark);
1363     logger->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1364   }
1365
1366   delete vresp;
1367   
1368   return markList;
1369 }
1370
1371 void VDR::getChannelPids(Channel* channel)
1372 {
1373   VDR_RequestPacket vrp;
1374   if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
1375   if (!vrp.addULONG(channel->number)) return ;
1376
1377   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1378   if (vresp->noResponse()) { delete vresp; return ; }
1379   
1380   // Format of response
1381   // vpid
1382   // number of apids
1383   // {
1384   //    apid
1385   //    lang string
1386   // }
1387
1388   channel->vpid = vresp->extractULONG();
1389   channel->vstreamtype = vresp->extractULONG();
1390   channel->numAPids = vresp->extractULONG();
1391
1392   for (ULONG i = 0; i < channel->numAPids; i++)
1393   {
1394     apid newapid;
1395     newapid.pid = vresp->extractULONG();
1396     char * name=vresp->extractString();
1397     strncpy(newapid.desc,name,9);
1398     delete [] name;
1399     channel->apids.push_back(newapid);
1400   }
1401
1402   channel->numDPids = vresp->extractULONG();
1403
1404   for (ULONG i = 0; i < channel->numDPids; i++)
1405   {
1406     apid newdpid;
1407     newdpid.pid = vresp->extractULONG();
1408     char * name=vresp->extractString();
1409     strncpy(newdpid.desc,name,9);
1410     delete [] name;
1411     channel->dpids.push_back(newdpid);
1412   }
1413
1414   channel->numSPids = vresp->extractULONG();
1415
1416   for (ULONG i = 0; i < channel->numSPids; i++)
1417   {
1418     apid newspid;
1419     newspid.pid = vresp->extractULONG();
1420     char * name=vresp->extractString();
1421     strncpy(newspid.desc,name,9);
1422     delete [] name;
1423     channel->spids.push_back(newspid);
1424   }
1425   channel->tpid = vresp->extractULONG();
1426   // extension
1427   for (ULONG i = 0; i < channel->numAPids; i++)
1428   {
1429           channel->apids[i].type = vresp->extractULONG();
1430   }
1431   for (ULONG i = 0; i < channel->numDPids; i++)
1432   {
1433           channel->dpids[i].type = vresp->extractULONG();
1434   }
1435   for (ULONG i = 0; i < channel->numSPids; i++)
1436   {
1437           channel->spids[i].type = vresp->extractULONG();
1438           channel->spids[i].data1 = vresp->extractULONG();
1439           channel->spids[i].data2 = vresp->extractULONG();
1440   }
1441
1442   delete vresp;
1443   
1444   return ;
1445 }
1446
1447 #ifdef VOMP_MEDIAPLAYER
1448 MediaList * VDR::getRootList() {
1449   return getMediaList(NULL);
1450 }
1451 /**
1452   * media List Request:
1453   * mediaURI
1454   * Media List response:
1455   * mediaList
1456 */
1457 MediaList* VDR::getMediaList(const MediaURI * root)
1458 {
1459   logger->log("VDR", Log::DEBUG, "getMediaList %s,d=%s, prov=%d", (root?root->getName():"NULL"), 
1460       ((root && root->hasDisplayName())?root->getDisplayName():"NULL"),
1461       (root?root->getProvider():providerId));
1462   MediaURI remoteURI(root);
1463   VDR_GetMediaListRequest request(&remoteURI);
1464   SerializeBuffer *vrp=prepareRequest(&request);
1465   if (!vrp) {
1466     logger->log("VDR", Log::ERR, "getMediaList unable to create command");
1467     return NULL;
1468   }
1469     
1470   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1471   if (!vresp) {
1472     Command::getInstance()->connectionLost();
1473     return NULL;
1474   }
1475   
1476   MediaList *rt=new MediaList(NULL);
1477   ULONG rtflags=0;
1478   VDR_GetMediaListResponse resp(&rtflags,rt);
1479   if (decodeResponse(vresp,&resp) != 0) {
1480     return NULL;
1481   }
1482   return rt;
1483 }
1484
1485 /**
1486   * get image Request:
1487   * uri,x,y, channel
1488   * get media response:
1489   * 4 flags
1490   * 8 len of image
1491 */
1492 int VDR::openMedium(ULONG channel,const MediaURI *uri,  ULLONG * size, ULONG x, ULONG y)
1493 {
1494   MediaURI remoteURI(uri);
1495   VDR_OpenMediumRequest request(&channel,&remoteURI,&x,&y);
1496   *size=0;
1497   SerializeBuffer *vrp=prepareRequest(&request);
1498   if (!vrp) {
1499     logger->log("VDR", Log::ERR, "openMedium unable to create command");
1500     return -1;
1501   }
1502   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1503   if (!vresp) {
1504     Command::getInstance()->connectionLost();
1505     return -1;
1506   }
1507   ULONG flags=0;
1508   VDR_OpenMediumResponse response(&flags,size);
1509   if (decodeResponse(vresp,&response) != 0) {
1510     return -1;
1511   }
1512   logger->log("VDR", Log::DEBUG, "openMedia len=%llu", *size);
1513   return 0;
1514 }
1515
1516 /**
1517   * getMediaBlock - no separate response class - simple data block
1518   * resp
1519   * packet
1520   */
1521 int VDR::getMediaBlock(ULONG channel, ULLONG position, ULONG maxAmount, ULONG* amountReceived, unsigned char **buffer)
1522 {
1523   *amountReceived=0;
1524   VDR_GetMediaBlockRequest request(&channel,&position,&maxAmount);
1525   SerializeBuffer *vrp=prepareRequest(&request);
1526   if (!vrp) {
1527     logger->log("VDR", Log::ERR, "getMediaBlock unable to create command");
1528     return -1;
1529   }
1530   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1531   if (!vresp) {
1532     Command::getInstance()->connectionLost();
1533     return -1;
1534   }
1535   
1536   // Special handling for getblock
1537   *amountReceived = (ULONG)(vresp->getEnd()-vresp->getStart());
1538   *buffer = vresp->steelBuffer();
1539   delete vresp;
1540   return 0;
1541 }
1542
1543 /**
1544   * VDR_GETMEDIAINFO
1545   * channel
1546   * rt
1547   * flags
1548   * info
1549   */
1550
1551 int VDR::getMediaInfo(ULONG channel, MediaInfo * result) {
1552   if (! result) return -1;
1553   VDR_GetMediaInfoRequest request(&channel);
1554   SerializeBuffer *vrp=prepareRequest(&request);
1555   if (!vrp) {
1556     logger->log("VDR", Log::ERR, "getMediaInfo unable to create command");
1557     return -1;
1558   }
1559   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1560   if (!vresp) {
1561     Command::getInstance()->connectionLost();
1562     return -1;
1563   }
1564
1565   ULONG flags=0;
1566   VDR_GetMediaInfoResponse response(&flags,result);
1567   if (decodeResponse(vresp,&response) != 0) {
1568     return -1;
1569   }
1570   return 0;
1571 }
1572
1573 /**
1574   * VDR_CLOSECHANNEL
1575   * channel
1576   * rt
1577   * flags
1578   */
1579
1580 int VDR::closeMediaChannel(ULONG channel) {
1581   VDR_CloseMediaChannelRequest request(&channel);
1582   SerializeBuffer *vrp=prepareRequest(&request);
1583   if (!vrp) {
1584     logger->log("VDR", Log::ERR, "closeMediaChannel unable to create command");
1585     return -1;
1586   }
1587   SerializeBuffer* vresp = doRequestResponse(vrp,request.command);
1588   if (!vresp) {
1589     Command::getInstance()->connectionLost();
1590     return -1;
1591   }
1592   ULONG flags;
1593   VDR_CloseMediaChannelResponse response(&flags);
1594   if (decodeResponse(vresp,&response) != 0) return -1;
1595   return (flags != 0)?-1:0;
1596 }
1597
1598 #endif
1599
1600
1601 int VDR::deleteTimer(RecTimer* delTimer)
1602 {
1603   logger->log("VDR", Log::DEBUG, "Delete timer called");
1604   
1605   VDR_RequestPacket vrp;
1606   if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
1607   if (!vrp.addULONG(delTimer->channelNumber)) return 0;
1608   if (!vrp.addULONG(delTimer->weekDays)) return 0;    
1609   if (!vrp.addULONG(delTimer->day)) return 0;
1610   if (!vrp.addULONG(delTimer->startTime)) return 0;  
1611   if (!vrp.addULONG(delTimer->stopTime)) return 0; 
1612    
1613   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1614   if (vresp->noResponse()) { delete vresp; return 0; }
1615   
1616   int toReturn = (int)vresp->extractULONG();
1617   delete vresp;
1618
1619   return toReturn;
1620 }
1621
1622 I18n::lang_code_list VDR::getLanguageList()
1623 {
1624   I18n::lang_code_list CodeList;
1625   CodeList["en"] = "English"; // Default entry
1626   VDR_RequestPacket vrp;
1627   if (!vrp.init(VDR_GETLANGUAGELIST, false, 0)) return CodeList;
1628   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1629   if (vresp->noResponse() || vresp->end())
1630   {
1631     delete vresp;
1632     return CodeList;
1633   }
1634   CodeList.clear();
1635   while (!vresp->end())
1636   {
1637     char* c_code = vresp->extractString();
1638     char* c_name = vresp->extractString();
1639     string code = c_code;
1640     string name = c_name;
1641     CodeList[code] = name;
1642     delete[] c_code;
1643     delete[] c_name;
1644   }
1645   delete vresp;
1646   return CodeList;
1647 }
1648
1649 int VDR::getLanguageContent(const std::string code, I18n::trans_table& texts)
1650 {
1651   VDR_RequestPacket vrp;
1652   if (!vrp.init(VDR_GETLANGUAGECONTENT, false, 0)) return 0;
1653   if (!vrp.addString(code.c_str())) return 0;
1654   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1655   if (vresp->noResponse()) { delete vresp; return 0; }
1656   texts.clear();
1657   while (!vresp->end())
1658   {
1659     char* c_key = vresp->extractString();
1660     char* c_text = vresp->extractString();
1661     string key = c_key;
1662     string text = c_text;
1663     texts[key] = text;
1664     delete[] c_key;
1665     delete[] c_text;
1666   }
1667   delete vresp;
1668   return 1;
1669 }
1670
1671 void VDR::shutdownVDR()
1672 {
1673   if(doVDRShutdown)
1674     logger->log("VDR", Log::DEBUG, "Shutting down vdr");
1675   else
1676     logger->log("VDR", Log::DEBUG, "Shutting down vomp only");
1677
1678   if(!doVDRShutdown || !connected)
1679     return;
1680
1681   VDR_RequestPacket vrp;
1682   logger->log("VDR", Log::DEBUG, "Sending shutdown");
1683   if (!vrp.init(VDR_SHUTDOWN, false, 0)) return;
1684   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1685   delete vresp;
1686
1687   logger->log("VDR", Log::DEBUG, "VDR shutdown");
1688 }
1689
1690 void VDR::getScraperEventType(char * fileName, int & movieID,
1691                 int & seriesID, int & episodeID)
1692 {
1693         movieID = 0;
1694         seriesID = 0;
1695         episodeID = 0;
1696         VDR_RequestPacket vrp;
1697         if (!vrp.init(VDR_GETRECSCRAPEREVENTTYPE, true, strlen(fileName) + 1)) return;
1698         if (!vrp.addString(fileName)) return ;
1699         Log::getInstance()->log("Recording", Log::DEBUG, "Before Response ");
1700         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1701         Log::getInstance()->log("Recording", Log::DEBUG, "After Response ");
1702         if (vresp->noResponse()) { delete vresp; return ; }
1703         int type = vresp->extractUCHAR();
1704         if (type == 0) //serie
1705         {
1706                 seriesID = vresp->extractLONG();
1707                 episodeID = vresp->extractLONG();
1708         } else if (type == 1) //movie
1709         {
1710                 movieID = vresp->extractLONG();
1711         }
1712         delete vresp;
1713
1714 }
1715
1716 void VDR::getScraperEventType(UINT channelid, UINT eventid, int & movieID,
1717                 int & seriesID, int & episodeID, int & epgImage )
1718 {
1719         movieID = 0;
1720         seriesID = 0;
1721         episodeID = 0;
1722         epgImage = 0;
1723         VDR_RequestPacket vrp;
1724         if (!vrp.init(VDR_GETEVENTSCRAPEREVENTTYPE, false, 0)) return;
1725         if (!vrp.addULONG(channelid)) return ;
1726         if (!vrp.addULONG(eventid)) return ;
1727         Log::getInstance()->log("Recording", Log::DEBUG, "Before Response ");
1728         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1729         Log::getInstance()->log("Recording", Log::DEBUG, "After Response ");
1730         if (vresp->noResponse()) { delete vresp; return ; }
1731         int type = vresp->extractUCHAR();
1732         if (type == 0) //serie
1733         {
1734                 seriesID = vresp->extractLONG();
1735                 episodeID = vresp->extractLONG();
1736         } else if (type == 1) //movie
1737         {
1738                 movieID = vresp->extractLONG();
1739         }
1740         epgImage = vresp->extractLONG();
1741         delete vresp;
1742
1743 }
1744
1745 MovieInfo *VDR::getScraperMovieInfo(int movieID)
1746 {
1747         VDR_RequestPacket vrp;
1748         if (!vrp.init(VDR_GETSCRAPERMOVIEINFO, false, 0)) return NULL;
1749         if (!vrp.addULONG(movieID)) return NULL;
1750         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1751         if (vresp->noResponse()) { delete vresp; return NULL; }
1752         MovieInfo * movieinf= new MovieInfo();
1753
1754         movieinf->id=movieID;
1755         movieinf->title = vresp->extractStdString();
1756         movieinf->originalTitle = vresp->extractStdString();
1757         movieinf->tagline = vresp->extractStdString();
1758         movieinf->overview = vresp->extractStdString();
1759         movieinf->adult = vresp->extractUCHAR();
1760         movieinf->collectionName = vresp->extractStdString();
1761
1762         movieinf->budget = vresp->extractLONG();
1763         movieinf->revenue = vresp->extractLONG();
1764         movieinf->genres = vresp->extractStdString();
1765         movieinf->homepage = vresp->extractStdString();
1766         movieinf->releaseDate = vresp->extractStdString();
1767         movieinf->runtime = vresp->extractLONG();
1768         movieinf->popularity = vresp->extractdouble();
1769         movieinf->voteAverage = vresp->extractdouble();
1770         movieinf->poster.width = vresp->extractULONG();
1771         movieinf->poster.height = vresp->extractULONG();
1772         movieinf->poster.info.setMovieInfo(movieinf);
1773         movieinf->poster.info.setElement(0,0);
1774         movieinf->fanart.width = vresp->extractULONG();
1775         movieinf->fanart.height = vresp->extractULONG();
1776         movieinf->fanart.info.setMovieInfo(movieinf);
1777         movieinf->fanart.info.setElement(1,0);
1778         movieinf->collectionPoster.width = vresp->extractULONG();
1779         movieinf->collectionPoster.height = vresp->extractULONG();
1780         movieinf->collectionPoster.info.setMovieInfo(movieinf);
1781         movieinf->collectionPoster.info.setElement(2,0);
1782         movieinf->collectionFanart.width = vresp->extractULONG();
1783         movieinf->collectionFanart.height = vresp->extractULONG();
1784         movieinf->collectionFanart.info.setMovieInfo(movieinf);
1785         movieinf->collectionFanart.info.setElement(3,0);
1786         ULONG num_actors =  vresp->extractULONG();
1787         movieinf->actors.clear();
1788         movieinf->actors.reserve(num_actors);
1789         for (ULONG acty=0; acty < num_actors; acty++) {
1790                 Actor new_act;
1791                 new_act.name =  vresp->extractStdString();
1792                 new_act.role =  vresp->extractStdString();
1793                 new_act.thumb.width = vresp->extractULONG();
1794                 new_act.thumb.height = vresp->extractULONG();
1795                 new_act.thumb.info.setMovieInfo(movieinf);
1796                 new_act.thumb.info.setElement(4,acty);
1797                 movieinf->actors.push_back(new_act);
1798         }
1799
1800
1801         delete vresp;
1802         return movieinf;
1803
1804 }
1805
1806 SeriesInfo *VDR::getScraperSeriesInfo(int seriesID, int episodeID)
1807 {
1808         VDR_RequestPacket vrp;
1809         if (!vrp.init(VDR_GETSCRAPERSERIESINFO, false, 0)) return NULL;
1810         if (!vrp.addULONG(seriesID)) return NULL;
1811         if (!vrp.addULONG(episodeID)) return NULL;
1812
1813         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1814         if (vresp->noResponse()) { delete vresp; return 0; }
1815         SeriesInfo * seriesinf= new SeriesInfo();
1816
1817         seriesinf->id=seriesID;
1818
1819
1820         seriesinf->name = vresp->extractStdString();
1821         seriesinf->overview = vresp->extractStdString();
1822         seriesinf->firstAired = vresp->extractStdString();
1823         seriesinf->network = vresp->extractStdString();
1824         seriesinf->genre = vresp->extractStdString();
1825         seriesinf->rating =  vresp->extractdouble();
1826         seriesinf->status = vresp->extractStdString();
1827
1828
1829         seriesinf->episode.episodeid=episodeID;
1830         seriesinf->episode.number = vresp->extractLONG();
1831         seriesinf->episode.season = vresp->extractLONG();
1832         seriesinf->episode.name =  vresp->extractStdString();
1833         seriesinf->episode.firstAired =  vresp->extractStdString();
1834         seriesinf->episode.guestStars =  vresp->extractStdString();
1835         seriesinf->episode.overview =  vresp->extractStdString();
1836         seriesinf->episode.rating = vresp->extractdouble();
1837         seriesinf->episode.image.width =  vresp->extractULONG();
1838         seriesinf->episode.image.height =  vresp->extractULONG();
1839         seriesinf->episode.image.info.setSeriesInfo(seriesinf);
1840         seriesinf->episode.image.info.setElement(0,0);
1841
1842
1843         ULONG num_actors =  vresp->extractULONG();
1844         seriesinf->actors.clear();
1845         seriesinf->actors.reserve(num_actors);
1846         for (ULONG acty=0; acty < num_actors; acty++) {
1847                 Actor new_act;
1848                 new_act.name =  vresp->extractStdString();
1849                 new_act.role =  vresp->extractStdString();
1850                 new_act.thumb.width = vresp->extractULONG();
1851                 new_act.thumb.height = vresp->extractULONG();
1852                 new_act.thumb.info.setSeriesInfo(seriesinf);
1853                 new_act.thumb.info.setElement(1,acty);
1854                 seriesinf->actors.push_back(new_act);
1855         }
1856         ULONG num_posters =  vresp->extractULONG();
1857         for (ULONG medias = 0; medias < num_posters; medias++ ) {
1858                 TVMedia media;
1859                 media.info.setSeriesInfo(seriesinf);
1860                 media.info.setElement(2,medias);
1861                 media.width =  vresp->extractULONG();
1862                 media.height = vresp->extractULONG();
1863                 seriesinf->posters.push_back(media);
1864         }
1865
1866         ULONG num_banners =  vresp->extractULONG();
1867         for (ULONG medias = 0; medias < num_banners; medias++ ) {
1868                 TVMedia media;
1869                 media.info.setSeriesInfo(seriesinf);
1870                 media.info.setElement(3,medias);
1871                 media.width =  vresp->extractULONG();
1872                 media.height = vresp->extractULONG();
1873                 seriesinf->banners.push_back(media);
1874         }
1875         ULONG num_fanarts =  vresp->extractULONG();
1876         for (ULONG medias = 0; medias < num_fanarts; medias++ ) {
1877                 TVMedia media;
1878                 media.info.setSeriesInfo(seriesinf);
1879                 media.info.setElement(4,medias);
1880                 media.width =  vresp->extractULONG();
1881                 media.height = vresp->extractULONG();
1882                 seriesinf->fanart.push_back(media);
1883         }
1884         seriesinf->seasonposter.width = vresp->extractULONG();
1885         seriesinf->seasonposter.height = vresp->extractULONG();
1886         seriesinf->seasonposter.info.setSeriesInfo(seriesinf);
1887         seriesinf->seasonposter.info.setElement(5,0);
1888
1889         delete vresp;
1890         return seriesinf;
1891
1892 }
1893
1894 ULONG VDR::loadTVMedia(TVMediaInfo& tvmedia)
1895 {
1896         VDR_RequestPacket vrp;
1897
1898         if (!vrp.init(VDR_LOADTVMEDIA, false, 0)) return ULONG_MAX;
1899         if (!vrp.addULONG(tvmedia.type)) return ULONG_MAX;
1900         if (!vrp.addULONG(tvmedia.primary_id)) return ULONG_MAX;
1901         if (!vrp.addULONG(tvmedia.secondary_id)) return ULONG_MAX;
1902         if (!vrp.addULONG(tvmedia.type_pict)) return ULONG_MAX;
1903         if (!vrp.addULONG(tvmedia.container)) return ULONG_MAX;
1904         if (!vrp.addULONG(tvmedia.container_member)) return ULONG_MAX;
1905 /*      Log::getInstance()->log("VDR", Log::DEBUG, "TVMedia with ID %d %d; %d %d %d %d;%d",
1906                         tvmedia.primary_id,tvmedia.secondary_id,tvmedia.type,tvmedia.type_pict,
1907                         tvmedia.container,tvmedia.container_member,vrp.getSerial());*/
1908
1909
1910         VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1911         vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1912         vdrpr->streamID = vrp.getSerial();
1913         vdrpr->streamReceiver = NULL;
1914         edRegister(vdrpr);
1915
1916
1917         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1918         //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; }
1919         delete vresp;
1920
1921         return vrp.getSerial();
1922 }
1923
1924 ULONG VDR::loadTVMediaRecThumb(TVMediaInfo & media)
1925 {
1926
1927         VDR_RequestPacket vrp;
1928
1929         if (!vrp.init(VDR_LOADTVMEDIARECTHUMB, false, 0)) return ULONG_MAX;
1930         if (!vrp.addString(media.primary_name.c_str())) return ULONG_MAX;
1931
1932         VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1933         vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1934         vdrpr->streamID = vrp.getSerial();
1935         vdrpr->streamReceiver = NULL;
1936         edRegister(vdrpr);
1937
1938
1939         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1940         //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; }
1941         delete vresp;
1942
1943         return vrp.getSerial();
1944 }
1945
1946 ULONG VDR::loadTVMediaEventThumb(TVMediaInfo & media)
1947 {
1948
1949         VDR_RequestPacket vrp;
1950
1951         if (!vrp.init(VDR_LOADTVMEDIAEVENTTHUMB, false, 0)) return ULONG_MAX;
1952         if (!vrp.addULONG(media.primary_id)) return ULONG_MAX;
1953         if (!vrp.addULONG(media.secondary_id)) return ULONG_MAX;
1954
1955         VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1956         vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1957         vdrpr->streamID = vrp.getSerial();
1958         vdrpr->streamReceiver = NULL;
1959         edRegister(vdrpr);
1960
1961
1962         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1963         //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; }
1964         delete vresp;
1965
1966         return vrp.getSerial();
1967 }
1968
1969 ULONG VDR::loadChannelLogo(TVMediaInfo & media)
1970 {
1971
1972         VDR_RequestPacket vrp;
1973
1974         if (!vrp.init(VDR_LOADCHANNELLOGO, false, 0)) return ULONG_MAX;
1975         if (!vrp.addULONG(media.primary_id)) return ULONG_MAX;
1976
1977         VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver();
1978         vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA;
1979         vdrpr->streamID = vrp.getSerial();
1980         vdrpr->streamReceiver = NULL;
1981         edRegister(vdrpr);
1982
1983
1984         VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1985         //if (vresp->noResponse()) { delete vresp; return ULONG_MAX; }
1986         delete vresp;
1987
1988 //      Log::getInstance()->log("VDR", Log::DEBUG, "TVMedia Channel Logo %d %x",
1989 //                              media.primary_id,vrp.getSerial());
1990
1991         return vrp.getSerial();
1992 }