]> git.vomp.tv Git - vompclient.git/blob - command.cc
WIP
[vompclient.git] / command.cc
1 /*
2     Copyright 2004-2020 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 #ifndef WIN32
21 #include <errno.h>
22 #endif
23
24 #include "command.h"
25
26 #ifdef WIN32
27 #include "remotewin.h"
28 #endif
29
30 #ifdef __ANDROID__
31 #include "remoteandroid.h"
32 #endif
33
34 #include "led.h"
35 #include "video.h"
36 #include "audio.h"
37 #include "vdr.h"
38 #include "vvolume.h"
39 #include "vserverselect.h"
40 #include "vwelcome.h"
41 #include "vmute.h"
42 #include "colour.h"
43 #include "osd.h"
44 #include "i18n.h"
45 #include "timerreceiver.h"
46 #include "timers.h"
47 #include "wol.h"
48 #include "vconnect.h"
49 #include "message.h"
50 #include "remote.h"
51 #include "vinfo.h"
52 #include "boxx.h"
53 #include "boxstack.h"
54 #include "log.h"
55 #include "vsleeptimer.h"
56 #include "wjpeg.h"
57 #include "osdvector.h"
58
59
60 Command* Command::instance = NULL;
61
62 Command::Command()
63 {
64   if (instance) return;
65   instance = this;
66 }
67
68 Command::~Command()
69 {
70   instance = NULL;
71 }
72
73 Command* Command::getInstance()
74 {
75   return instance;
76 }
77
78 int Command::init(bool tcrashed, char* tServer)
79 {
80   if (initted) return 0;
81   initted = true;
82   crashed = tcrashed;
83   server = tServer;
84
85   logger = Log::getInstance();
86   boxstack = BoxStack::getInstance();
87   remote = Remote::getInstance();
88   
89   remote->InitHWCListwithDefaults();
90   
91   if (!logger || !boxstack || !remote)
92   {
93     initted = false;
94     return 0;
95   }
96
97   SkinFactory::InitSkin(0);
98
99 #ifndef WIN32
100   pthread_mutex_init(&masterLock, NULL);
101 #else
102   masterLock = CreateMutex(NULL, FALSE, NULL);
103 #endif
104
105   return 1;
106 }
107
108 int Command::shutdown()
109 {
110   if (!initted) return 0;
111   initted = false;
112   return 1;
113 }
114
115 void Command::stop()
116 {
117   logger->log("Command", Log::NOTICE, "stop");
118   udp.shutdown();
119   irun = false;
120 }
121
122 void Command::doWallpaper()
123 {
124   Video* video = Video::getInstance();
125
126   // Blue background
127   Boxx* bbg = new Boxx();
128   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
129   bbg->createBuffer();
130   bbg->fillColour(DrawStyle::WALLPAPER);
131   boxstack->add(bbg);
132   boxstack->update(bbg);
133   boxstack->remove(bbg);
134
135   // Wallpaper
136   wallpaper = new Boxx();
137   wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight());
138   wallpaper->createBuffer();
139   wallpaper->setBackgroundColour(DrawStyle::WALLPAPER);
140
141   wallpaper_pict = new WJpegTYPE();
142   wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight());
143
144   if (video->getFormat() == Video::PAL)
145   {
146     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
147 #ifndef _MIPS_ARCH    
148     wallpaper_pict->init("/wallpaperPAL.jpg");
149 #else
150     wallpaper_pict->init("wallpaperPAL.jpg");
151 #endif
152   }
153   else
154   {
155     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
156     wallpaper_pict->init("/wallpaperNTSC.jpg");
157   }
158
159   if (DrawStyle::WALLPAPER.alpha)
160     wallpaper_pict->setVisible(true);
161   else
162     wallpaper_pict->setVisible(false);
163
164   wallpaper->add(wallpaper_pict);
165   wallpaper->draw();
166
167   boxstack->add(wallpaper);
168   boxstack->update(wallpaper);
169
170   OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
171   if (osdv) osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
172 }
173
174 void Command::run()
175 {
176   if (!initted) return;
177   irun = true;
178 #ifndef WIN32
179   mainPid = getpid();
180 #endif
181
182   // just in case
183   Video::getInstance()->signalOn();
184   Led::getInstance()->on();
185
186   doWallpaper();
187
188   // End of startup. Lock the mutex and put the first view up
189 #ifndef WIN32
190   pthread_mutex_lock(&masterLock);
191 #else
192   WaitForSingleObject(masterLock, INFINITE );
193 #endif
194
195   if (crashed)
196   {
197     buildCrashedBox();
198   }
199   else
200   {
201     VConnect* vconnect = new VConnect(server);
202     boxstack->add(vconnect);
203     vconnect->run();
204   }
205
206   // Start method 2 of getting commands in...
207   udp.run(this);
208
209   UCHAR button = 0;
210   while(irun)
211   {
212     // unlock and wait
213 #ifndef WIN32
214     pthread_mutex_unlock(&masterLock);
215 #else
216     ReleaseMutex(masterLock);
217 #endif
218     button = remote->getButtonPress(2);  // Don't block (0) in case a signal arrives after checking signals but before this line
219     // something happened, lock and process
220     if (signals) processSignals(); // If a signal arrived process now.
221
222 #ifndef WIN32
223     pthread_mutex_lock(&masterLock);
224 #else
225     WaitForSingleObject(masterLock, INFINITE );
226 #endif
227
228     if (button == Remote::NA_NONE) continue;
229
230     if (button != Remote::NA_SIGNAL) handleCommand(button);
231     processMessageQueue();
232   }
233
234 #ifndef WIN32
235   pthread_mutex_unlock(&masterLock);
236 #else
237   ReleaseMutex(masterLock);
238 #endif
239
240   boxstack->removeAllExceptWallpaper();
241   boxstack->remove(wallpaper);
242   delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
243 }
244
245 void Command::setSignal(int signalReceived)
246 {
247 #ifndef WIN32
248   if (signalReceived == SIGINT)
249     signals |= SIG_INT;
250   else if (signalReceived == SIGTERM)
251     signals |= SIG_TERM;
252   else if (signalReceived == SIGUSR1)
253     signals |= SIG_USR1;
254   else if (signalReceived == SIGUSR2)
255     signals |= SIG_USR2;
256   else if (signalReceived == SIGURG)
257     signals |= SIG_URG;
258 #endif
259 }
260
261 void Command::processSignals()
262 {
263 #ifndef WIN32
264   if (signals & SIG_INT)
265   {
266     signals = signals & ~SIG_INT;
267     logger->log("Command", Log::NOTICE, "INT signal, shutting down...");
268     stop();
269   }
270
271   if (signals & SIG_TERM)
272   {
273     signals = signals & ~SIG_TERM;
274     logger->log("Command", Log::NOTICE, "TERM signal, shutting down...");
275     stop();
276   }
277
278   if (signals & SIG_USR1)
279   {
280     logger->log("Command", Log::NOTICE, "USR1 signal");
281     signals = signals & ~SIG_USR1;
282   }
283
284   if (signals & SIG_USR2)
285   {
286     logger->log("Command", Log::NOTICE, "USR2 signal");
287     signals = signals & ~SIG_USR2;
288   }
289
290   if (signals & SIG_URG)
291   {
292     logger->log("Command", Log::NOTICE, "URG signal"); // This is used to break from getButtonPress to process the message queue
293     signals = signals & ~SIG_URG;
294   }
295 #endif
296 }
297
298 void Command::postMessage(Message* m)
299 {
300   // This is locked here in case the main loop is not waiting for an event, but is processing one
301   // it could be killed but then not react to it because the signal wouldn't cause
302   // remote->getButtonPress to break
303   // locking the mutex ensures that the master thread is waiting on getButtonPress
304
305 #ifndef WIN32
306   pthread_mutex_lock(&masterLock);
307 #else
308   WaitForSingleObject(masterLock, INFINITE );
309 #endif
310   MessageQueue::postMessage(m);
311
312 #ifndef WIN32
313 #ifndef __ANDROID__
314   kill(mainPid, SIGURG);
315 #else
316   ((RemoteAndroid*)Remote::getInstance())->Signal();
317 #endif
318   pthread_mutex_unlock(&masterLock);
319 #else
320   ((RemoteWin*)Remote::getInstance())->Signal();
321   ReleaseMutex(masterLock);
322 #endif
323 }
324
325 void Command::postMessageNoLock(Message* m) // FIXME - get rid of this if the sending-to-MessageQueue idea pans out
326 {
327   // As above but use this one if this message is being posted because of a button press
328   // the mutex is already locked, locking around postMessage is not needed as the
329   // queue is guaranteed to be run when the button has been processed
330   MessageQueue::postMessage(m);
331 }
332
333 bool Command::postMessageIfNotBusy(Message* m)
334 {
335   // Used for Windows mouse events
336
337 #ifndef WIN32
338   if (pthread_mutex_trylock(&masterLock) != EBUSY)
339   {
340     MessageQueue::postMessage(m);
341 #ifndef __ANDROID__
342     kill(mainPid, SIGURG);
343 #else
344     ((RemoteAndroid*)Remote::getInstance())->Signal();
345 #endif
346     pthread_mutex_unlock(&masterLock);
347     return true;
348   }
349   else
350   {
351     return false;
352   }
353 #else
354   switch (WaitForSingleObject(masterLock, 0 ))
355   { //FIXME this is not "if not busy" check
356     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
357     // case WAIT_ABANDONED:
358     MessageQueue::postMessage(m);
359     ((RemoteWin*)Remote::getInstance())->Signal();
360     ReleaseMutex(masterLock);
361     return true;
362
363     case WAIT_ABANDONED: return false;
364     case WAIT_TIMEOUT: return false;
365   }
366     return false;
367 #endif
368 }
369
370 void Command::postMessageFromOuterSpace(Message* m)
371 {
372   /*
373   Yet another way of getting messages into Command. This one is for events that
374   are not standard button presses (or UDP generated buttons). It is also not for
375   events that are generated as a result of other events (events that can safely
376   call postMessageNoLock and be guaranteed that the message will be processed
377   because it is known that the queue is currently being processed).
378   This is for events that come from outer space and can occur when the master
379   mutex is locked or not, they need to be queued and executed but it doesn't
380   matter when.
381   Actually so far it is for events caused by the video stream - aspect ratio
382   changes. These can occur when the master mutex is locked and so postMessage
383   doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
384   locked at the time then the message could be sat around a while before
385   being noticed.
386   The whole message system was at first supposed to prevent the problem of
387   calling a function on an object that had just been deleted, by ordering
388   messages such that all calls are done before object deletion. However,
389   because of the new centralised messaging system and the fact that BoxStack
390   locates the destination object before calling it, the messaging system now
391   allows the kind of sloppy calls it was supposed to stop. Weird huh. This
392   is mentioned here because the video stream might generate an event just as
393   the user hits stop. The mutex is locked, and by the time the message
394   is examined the vvideorec/live has been deleted. This doesn't matter because
395   boxstack will drop the message if it can't find the matching object to
396   deliver it to.
397   Finally, all this is fine and dandy, except that I'm not 100% sure that
398   this sloppy postMessage and hope a queued signal will force it to be processed
399   thingy will actually work. Hmmm.
400   Lastly <g>, I will consider making the naming system a little more sane
401   if this works.
402   */
403
404   logger->log("Command", Log::DEBUG, "PMFOS called");
405   MessageQueue::postMessage(m);
406
407 #ifndef WIN32
408 #ifndef __ANDROID__
409   kill(mainPid, SIGURG);
410 #else
411   ((RemoteAndroid*)Remote::getInstance())->Signal();
412 #endif
413 #else
414   ((RemoteWin*)Remote::getInstance())->Signal();
415 #endif
416 }
417
418 void Command::processMessage(Message* m)
419 {
420     // FIXME - a slight modification - how if messagereceivers were to register
421     // themselves as receivers to avoid the calling-a-deleted-object problem
422     // then only deliver/register/unregister would have to be protected
423
424   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
425
426
427   if (m->to == this)
428   {
429     switch(m->message)
430     {
431       // << FIXME OBSELETE
432       case Message::STOP_PLAYBACK:
433       {
434         handleCommand(Remote::STOP); // an odd way of doing it, but so simple
435         break;
436       }
437       // Also connection_lost comes from player - anywhere else?
438       // FIXME OBSELETE >>
439
440
441       case Message::VDR_CONNECTED:
442       {
443         doJustConnected(static_cast<VConnect*>(m->from));
444         break;
445       }
446       case Message::SCREENSHOT:
447       {
448         logger->log("Osd", Log::NOTICE, "Screenshot Message arrived");
449         Osd::getInstance()->screenShot("out.jpg");
450         break;
451       }
452       case Message::CONNECTION_LOST:
453       {
454         doFromTheTop(true);
455         break;
456       }
457       case Message::UDP_BUTTON:
458       {
459         handleCommand(m->parameter);
460         break;
461       }
462       case Message::CHANGE_LANGUAGE:
463       {
464         boxstack->removeAllExceptWallpaper();
465         boxstack->update(wallpaper);
466         I18n::initialize();
467         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
468         VWelcome* vw = new VWelcome();
469         vw->draw();
470         boxstack->add(vw);
471         boxstack->update(vw);
472         break;
473       }
474       case Message::LAST_VIEW_CLOSE:
475       {
476         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
477         if (crashed)
478         {
479           crashed = false;
480           doFromTheTop(false);        
481         }
482       
483 //        VWelcome* vw = new VWelcome();
484 //        vw->draw();
485 //        boxstack->add(vw);
486 //        boxstack->update(vw);
487
488         break;
489       }
490       case Message::NEW_PICTURE:
491       {
492         //Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE");
493         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
494         if (osdv) osdv->informPicture(m->tag, reinterpret_cast<ImageIndex>(m->data));
495         break;
496       }
497       case Message::NEW_PICTURE_STATIC:
498       {
499         //Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter);
500         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
501         if (osdv) osdv->informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<ImageIndex>(m->data));
502         break;
503       }
504     }
505   }
506   else
507   {
508     /* FIXME
509     
510     Instead of sending through the boxstack, implement a more generic MessageReceiver interface
511     and have potential receivers register with something
512     When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
513     This could all be done using the existing big command mutex to keep it simple
514     */
515   
516     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
517     boxstack->processMessage(m);
518   }
519 }
520
521 void Command::handleCommand(int button)
522 {
523   if (isStandby && (button != Remote::POWER) 
524                 && (button != Remote::POWERON)
525                 && (button != Remote::POWEROFF))  return;
526
527   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
528
529   // command was not handled
530
531   switch(button)
532   {
533     case Remote::DF_LEFT:
534     case Remote::DF_RIGHT:
535     case Remote::VOLUMEUP:
536     case Remote::VOLUMEDOWN:
537     {
538       if (remote->handlesVolume())
539       {
540         if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)
541           remote->volumeDown();
542         else
543           remote->volumeUp();
544       }
545       else
546       {
547         VVolume* v = new VVolume();
548         boxstack->add(v);
549         v->handleCommand(button); // this will draw+show
550       }
551       return;
552     }
553     case Remote::MUTE:
554     {
555       if (remote->handlesVolume())
556       {
557         remote->volumeMute();
558       }
559       else
560       {
561         VMute* v = new VMute();
562         v->draw();
563         boxstack->add(v);
564         boxstack->update(v);
565       }
566       return;
567     }
568     case Remote::POWER:
569     {
570       doStandby();
571       return;
572     }
573     case Remote::POWERON:
574     {
575       doPowerOn();
576       return;
577     }
578     case Remote::POWEROFF:
579     {
580       doPowerOff();
581       return;
582     }
583     case Remote::OK:
584     {
585       // FIXME
586       if (!connLost) return; // if connLost, handle Remote::OK
587       doFromTheTop(false);
588       return;
589     }
590     case Remote::GO:
591     {
592       VSleeptimer* sleep = new VSleeptimer();
593       boxstack->add(sleep);
594       sleep->handleCommand(button); // this will draw+show
595       return;
596     }
597   }
598 }
599
600 void Command::sig1()
601 {
602 #ifdef DEV
603   Message* m = new Message(); // break into master mutex
604   m->message = Message::SCREENSHOT;
605   m->to = this;
606   postMessage(m);
607 #endif
608 }
609
610 void Command::doStandby()
611 {
612   if (isStandby)
613   {
614     doPowerOn();
615   }
616   else
617   {
618     doPowerOff();
619   }
620 }
621
622
623 void Command::doPowerOn()
624 {
625   if (isStandby)
626   {
627     Video::getInstance()->signalOn();
628     Led::getInstance()->on();
629     Remote::getInstance()->changePowerState(true);
630     isStandby = false;
631
632     VConnect* vconnect = new VConnect(server);
633     boxstack->add(vconnect);
634     vconnect->run();
635   }
636 }
637
638 void Command::doPowerOff()
639 {
640   if (!isStandby)
641   {
642     VDR::getInstance()->shutdownVDR();
643     boxstack->removeAllExceptWallpaper();
644     Video::getInstance()->signalOff();
645     boxstack->update(wallpaper);
646
647     VDR::getInstance()->configSave("General", "Last Power State", "Off");
648     logger->unsetExternLogger();
649     VDR::getInstance()->disconnect();
650     Led::getInstance()->off();
651     Remote::getInstance()->changePowerState(false);
652     isStandby = true;
653     Sleeptimer::getInstance()->shutdown();
654 #ifdef WIN32
655     stop(); //different behavoiur on windows, we exit
656 #endif
657   }
658 }
659
660 void Command::doFromTheTop(bool which)
661 {
662   if (isStandby) return;
663   if (which)
664   {
665     if (connLost)
666     {
667       logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
668       return;
669     }
670   
671     logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
672     connLost = new VInfo();
673     connLost->setSize(360, 200);
674     connLost->createBuffer();
675     if (Video::getInstance()->getFormat() == Video::PAL)
676       connLost->setPosition(190, 170);
677     else
678       connLost->setPosition(180, 120);
679     connLost->setOneLiner(tr("Connection lost"));
680     connLost->setDropThrough();
681     connLost->setBorderOn(1);
682     connLost->setTitleBarColour(DrawStyle::DANGER);
683     connLost->okButton();
684     connLost->draw();
685     boxstack->add(connLost);
686     boxstack->update(connLost);
687     remote->clearBuffer();
688   }
689   else
690   {
691     logger->unsetExternLogger();
692     VDR::getInstance()->disconnect();
693     boxstack->removeAllExceptWallpaper();
694     boxstack->update(wallpaper);
695     connLost = NULL;
696     
697     flushMessageQueue();
698     remote->clearBuffer();
699     
700     // at this point, everything should be reset to first-go
701     
702     VConnect* vconnect = new VConnect(server);
703     boxstack->add(vconnect);
704     vconnect->run();
705   }
706 }
707
708 void Command::doReboot()
709 {
710
711   logger->unsetExternLogger();
712   VDR::getInstance()->disconnect();
713   // just kill it...
714   logger->log("Command", Log::NOTICE, "Reboot");
715 #ifndef WIN32
716 #ifndef VOMP_HAS_EXIT
717   // some plattforms, want a proper deinitialisation of their hardware before reboot
718   Osd::getInstance()->shutdown();
719   Audio::getInstance()->shutdown();
720   Video::getInstance()->shutdown();
721   Remote::getInstance()->shutdown();
722
723   reboot(LINUX_REBOOT_CMD_RESTART);
724   // if  reboot is not allowed -> stop
725   stop();
726
727
728 #else
729   stop();
730
731 #ifdef __ANDROID__
732   exit(0);
733 #endif
734
735 #endif
736 #endif //Would we support this on windows?
737 }
738
739 void Command::connectionLost()
740 {
741   logger->unsetExternLogger();
742   Message* m = new Message(); // break into master mutex
743   m->message = Message::CONNECTION_LOST;
744   m->to = this;
745   postMessageFromOuterSpace(m);
746 }
747
748 void Command::buildCrashedBox()
749 {
750   VInfo* crash = new VInfo();
751   crash->setSize(360, 250);
752   crash->createBuffer();
753   if (Video::getInstance()->getFormat() == Video::PAL)
754     crash->setPosition(190, 146);
755   else
756     crash->setPosition(180, 96);
757   crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
758   crash->setBorderOn(1);
759   crash->setTitleBarColour(DrawStyle::DANGER);
760   crash->okButton();
761   crash->setExitable();
762   crash->draw();
763   boxstack->add(crash);
764   boxstack->update(crash);
765 }
766
767 int Command::getLangPref(bool subtitle, const char* langcode)
768 {
769   std::vector<struct ASLPref>::iterator itty=langcodes.begin();
770   char templangcode[4];
771   templangcode[0] = langcode[0];
772   templangcode[1] = langcode[1];
773   templangcode[2] = langcode[2];
774   templangcode[3] = '\0';
775   int langpos = 0;
776   while (itty != langcodes.end())
777   {
778     size_t pos = (*itty).langcode.find(templangcode);
779     if (pos != std::string::npos)
780     {
781       //vector<struct ASLPref>::iterator itty2=langcodes.begin();
782       for (unsigned int i = 0; i < langcodes.size(); i++)
783       {
784         int pref = 0;
785         if (subtitle)
786           pref = langcodes[i].subtitlepref;
787         else
788           pref = langcodes[i].audiopref;
789         if (pref < 0) break;
790
791         if (subtitle)
792         {
793           if (langcodes[i].subtitlepref==langpos) return i;
794         }
795         else
796         {
797           if (langcodes[i].audiopref==langpos) return i;
798         }
799       }
800       break;
801     }
802     itty++;
803     langpos++;
804   }
805   return langcodes.size(); //neutral
806 }
807
808 void Command::doJustConnected(VConnect* vconnect)
809 {
810   I18n::initialize();
811   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
812   logger->log("Command", Log::INFO, "Entering doJustConnected");
813   
814   Video* video = Video::getInstance();
815   Audio* audio = Audio::getInstance();  
816   boxstack->remove(vconnect);
817
818   VInfo* vi = new VInfo();
819   vi->setSize(400, 200);
820   vi->createBuffer();
821   if (video->getFormat() == Video::PAL)
822     vi->setPosition(170, 200);
823   else
824     vi->setPosition(160, 150);
825   vi->setOneLiner(tr("Connected, loading config"));
826   vi->draw();
827   boxstack->add(vi);
828   boxstack->update(vi);
829
830   VDR* vdr = VDR::getInstance();
831   char* config;
832
833   // See if we're supposed to do network logging
834   config = vdr->configLoad("Advanced", "Network logging");
835   if (config && !STRCASECMP(config, "On"))
836   {
837     logger->log("Command", Log::INFO, "Turning on network logging");
838     logger->setExternLogger(vdr);
839   }  
840   else
841   {
842           logger->unsetExternLogger();
843     logger->log("Command", Log::INFO, "Turned off network logging");
844   }
845   if (config) delete[] config;
846
847   config = vdr->configLoad("Advanced", "Skin Name");
848   if (config)
849   {
850     const char **skinnames=SkinFactory::getSkinNames();
851     for (int i=0;i<SkinFactory::getNumberofSkins();i++)
852     {
853       if (!STRCASECMP(config, skinnames[i]))
854       {
855         SkinFactory::InitSkin(i);
856         break;
857       }
858     }
859     delete[] config;
860
861     if (wallpaper && wallpaper_pict)
862     {
863       if (DrawStyle::WALLPAPER.alpha)
864         wallpaper_pict->setVisible(true);
865       else
866         wallpaper_pict->setVisible(false);
867
868       wallpaper->draw();
869       boxstack->update(wallpaper);
870     }
871   }
872   else
873   {
874     SkinFactory::InitSkin(0);
875   }
876
877   // See if config says to override video format (PAL/NTSC)
878   config = vdr->configLoad("General", "Override Video Format");
879   if (config)
880   {
881     logger->log("Command", Log::DEBUG, "Override Video Format is present");
882
883     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
884         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
885         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
886         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
887         )
888     {
889       // Oh sheesh, need to switch format. Bye bye TV...
890
891       // Take everything down
892       boxstack->removeAllExceptWallpaper();
893       boxstack->remove(wallpaper);
894       delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
895
896       Osd* osd = Osd::getInstance();
897 #ifndef __ANDROID__
898       osd->shutdown();
899 #endif
900       video->shutdown();
901
902       remote->shutdown(); // need on raspberry shut not do any harm, hopefully
903       remote->init(RemoteStartDev);
904
905       // Get video and osd back up with the new mode
906       if (!strcmp(config, "PAL"))
907       {
908         logger->log("Command", Log::DEBUG, "Switching to PAL");
909         video->init(Video::PAL);
910       }
911       else if (!strcmp(config, "NTSC"))
912       {
913         logger->log("Command", Log::DEBUG, "Switching to NTSC");
914         video->init(Video::NTSC);
915       } else if (!strcmp(config, "PAL_M"))
916       {
917         logger->log("Command", Log::DEBUG, "Switching to PAL_M");
918         video->init(Video::PAL_M);
919       } else if (!strcmp(config, "NTSC_J"))
920       {
921         logger->log("Command", Log::DEBUG, "Switching to NTSC_J");
922         video->init(Video::NTSC_J);
923       }
924       delete[] config;
925
926 #ifndef __ANDROID__
927       //we do not init twice
928       osd->init();
929 #endif
930
931       // Put the wallpaper back
932       doWallpaper();
933
934       // Re add the vinfo
935       vi = new VInfo();
936       vi->setSize(400, 200);
937       vi->createBuffer();
938       if (video->getFormat() == Video::PAL)
939         vi->setPosition(170, 200);
940       else
941         vi->setPosition(160, 150);
942
943       vi->setOneLiner(tr("Connected, loading config"));
944       vi->draw();
945       boxstack->add(vi);
946       boxstack->update(vi);
947     }
948     else
949     {
950       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
951     }
952   }
953   else
954   {
955     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
956   }
957
958   // Power off if first boot and config says so
959   if (firstBoot)
960   {
961     firstBoot = false;
962
963     logger->log("Command", Log::DEBUG, "Load power after boot");
964
965     config = vdr->configLoad("General", "Power After Boot");
966
967     if (config)
968     {
969       if (!STRCASECMP(config, "On"))
970       {
971         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
972       }
973       else if (!STRCASECMP(config, "Off"))
974       {
975         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
976         doStandby();
977         delete[] config;
978         return; // quit here
979       }
980       else if (!STRCASECMP(config, "Last state"))
981       {
982         char* lastPowerState = vdr->configLoad("General", "Last Power State");
983         if (lastPowerState)
984         {
985           if (!STRCASECMP(lastPowerState, "On"))
986           {
987             logger->log("Command", Log::INFO, "Config says Last Power State = On");
988           }
989           else if (!STRCASECMP(lastPowerState, "Off"))
990           {
991             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
992             doStandby();
993             delete[] config;
994             return; // quit here
995           }
996           else
997           {
998             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
999           }
1000         }
1001         else
1002         {
1003           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
1004         }
1005       }
1006       else
1007       {
1008         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
1009       }
1010       delete[] config;
1011     }
1012     else
1013     {
1014       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
1015     }
1016   }
1017
1018
1019   // Go S-Video if config says so
1020
1021   config = vdr->configLoad("TV", "Connection");
1022
1023   if (config)
1024   {
1025     if (!STRCASECMP(config, "S-Video"))
1026     {
1027       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
1028       video->setConnection(Video::SVIDEO);
1029     } else  if (!STRCASECMP(config, "HDMI"))
1030     {
1031       logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);
1032       video->setConnection(Video::HDMI);
1033     } else  if (!STRCASECMP(config, "HDMI3D"))
1034     {
1035       logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);
1036       video->setConnection(Video::HDMI3D);
1037     }
1038     else
1039     {
1040       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
1041       video->setConnection(Video::COMPOSITERGB);
1042     }
1043     delete[] config;
1044   }
1045   else
1046   {
1047     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
1048   }
1049
1050   // Set to shutdown VDR if config says
1051   
1052   config = vdr->configLoad("General", "VDR shutdown");
1053   if (config)
1054   {
1055     if (!STRCASECMP(config, "On"))
1056     {
1057       logger->log("Command", Log::INFO, "Shutdown VDR when  shutting down vomp");
1058       vdr->setVDRShutdown(true);
1059     }
1060     else if (!STRCASECMP(config, "Off"))
1061     {
1062       logger->log("Command", Log::INFO, "Shutdown only vomp");
1063       vdr->setVDRShutdown(false);
1064     }
1065   }
1066   else
1067   {
1068     logger->log("Command", Log::INFO, "Default shutdown only vomp");
1069     vdr->setVDRShutdown(false); // Default
1070   }
1071           
1072   // Set remote type
1073
1074   config = vdr->configLoad("General", "Remote type");
1075
1076   if (config)
1077   {
1078     if (!STRCASECMP(config, "New"))
1079     {
1080       logger->log("Command", Log::INFO, "Switching to New remote type");
1081       remote->setRemoteType(Remote::NEWREMOTE);
1082     }
1083     else
1084     {
1085       logger->log("Command", Log::INFO, "Switching to Old remote type");
1086       remote->setRemoteType(Remote::OLDREMOTE);
1087     }
1088     delete[] config;
1089   }
1090   else
1091   {
1092     logger->log("Command", Log::INFO, "Config General/Remote type not found");
1093     remote->setRemoteType(Remote::OLDREMOTE);
1094   }
1095
1096
1097
1098   // Get TV aspect ratio
1099
1100   config = vdr->configLoad("TV", "Aspect");
1101   if (config)
1102   {
1103     if (!STRCASECMP(config, "16:9"))
1104     {
1105       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
1106       video->setTVsize(Video::ASPECT16X9);
1107     }
1108     else
1109     {
1110       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
1111       video->setTVsize(Video::ASPECT4X3);
1112     }
1113     delete[] config;
1114   }
1115   else
1116   {
1117     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
1118     video->setTVsize(Video::ASPECT4X3);
1119   }
1120
1121   config = vdr->configLoad("TV", "Widemode");
1122   if (config)
1123   {
1124     if (!STRCASECMP(config, "Letterbox"))
1125     {
1126       logger->log("Command", Log::INFO, "Setting letterbox mode");
1127       video->setMode(Video::LETTERBOX);
1128     }
1129     else
1130     {
1131       logger->log("Command", Log::INFO, "Setting chop-sides mode");
1132       video->setMode(Video::NORMAL);
1133     }
1134     delete[] config;
1135   }
1136   else
1137   {
1138 #ifdef __ANDROID__
1139          logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
1140          video->setMode(Video::LETTERBOX);
1141 #else
1142     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
1143     video->setMode(Video::NORMAL);
1144 #endif
1145   }
1146
1147   config = vdr->configLoad("Advanced", "TCP receive window");
1148   if (config)
1149   {
1150     size_t newTCPsize = atoi(config);
1151     delete[] config;
1152
1153     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
1154     vdr->setReceiveWindow(newTCPsize);
1155   }
1156   else
1157   {
1158     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
1159     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1160   }
1161
1162   config = vdr->configLoad("Advanced", "Font Name");
1163   if (config)
1164   {
1165         Osd::getInstance()->setFont(config);
1166     logger->log("Command", Log::INFO, "Setting Font to %s", config);
1167     delete[] config;
1168
1169   }
1170
1171
1172   // Set recording list type
1173
1174 #ifdef ADVANCED_MENUES
1175   config = vdr->configLoad("Advanced", "Menu type");
1176
1177   if (config)
1178   {
1179     if (!STRCASECMP(config, "Advanced"))
1180     {
1181       logger->log("Command", Log::INFO, "Switching to Advanced menu");
1182       advMenus = true;
1183     }
1184     else
1185     {
1186       logger->log("Command", Log::INFO, "Switching to Classic menu");
1187       advMenus = false;
1188     }
1189     delete[] config;
1190   }
1191   else
1192   {
1193     logger->log("Command", Log::INFO, "Config General/menu type not found");
1194     advMenus = true;
1195   }
1196 #endif
1197
1198   config = vdr->configLoad("Advanced", "Disable WOL");
1199   if (config)
1200   {
1201     if (!STRCASECMP(config, "Yes"))
1202     {
1203       logger->log("Command", Log::INFO, "Config says disable WOL");
1204       Wol::getInstance()->setEnabled(false);
1205     }
1206     else
1207     {
1208       logger->log("Command", Log::INFO, "Config says enable WOL");
1209       Wol::getInstance()->setEnabled(true);
1210     }
1211
1212     delete[] config;
1213   }
1214   else
1215   {
1216     logger->log("Command", Log::INFO, "By default, enable WOL");
1217     Wol::getInstance()->setEnabled(true);
1218   }
1219   /* device dependend config */
1220   audio->loadOptionsfromServer(vdr);
1221   video->loadOptionsfromServer(vdr);
1222   remote->loadOptionsfromServer(vdr);
1223
1224   video->executePendingModeChanges();
1225   // config done
1226
1227   // Save power state = on
1228
1229   vdr->configSave("General", "Last Power State", "On");
1230
1231   // Make sure connection didn't die
1232   if (!vdr->isConnected())
1233   {
1234     Command::getInstance()->connectionLost();
1235   }
1236   else
1237   {
1238     boxstack->remove(vi);
1239
1240     VWelcome* vw = new VWelcome();
1241     vw->draw();
1242     boxstack->add(vw);
1243     boxstack->update(vw);
1244
1245     // Enter pre-keys here
1246 //    handleCommand(Remote::OK);
1247 //    handleCommand(Remote::THREE);
1248 //    handleCommand(Remote::SIX);
1249 //    handleCommand(Remote::OK);
1250 //    handleCommand(Remote::UP);
1251 //    handleCommand(Remote::PLAY);
1252 //    handleCommand(Remote::DOWN);
1253 //    handleCommand(Remote::DOWN);
1254 //    handleCommand(Remote::DOWN);
1255  //   handleCommand(Remote::OK);
1256 //    handleCommand(Remote::RED);
1257   }
1258 }