]> git.vomp.tv Git - vompclient.git/blob - src/control.cc
Tweaks to telemetry. Load IP/port from config
[vompclient.git] / src / control.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 // FIXME rename to Control and move stuff from main to here
21
22 #ifndef WIN32
23 #include <unistd.h> // for reboot
24 #include <linux/reboot.h>
25 #include <sys/reboot.h>
26 #endif
27
28 #include <time.h>
29
30 #ifdef WIN32
31 #include "inputwin.h"
32 #endif
33
34 #ifdef __ANDROID__
35 #include "inputandroid.h"
36 #endif
37
38 #include "telem.h"
39 #include "led.h"
40 #include "video.h"
41 #include "audio.h"
42 #include "vdr.h"
43 #include "vvolume.h"
44 #include "vserverselect.h"
45 #include "vwelcome.h"
46 #include "vmute.h"
47 #include "colour.h"
48 #include "osd.h"
49 #include "i18n.h"
50 #include "timers.h"
51 #include "wol.h"
52 #include "vconnect.h"
53 #include "message.h"
54 #include "inputman.h"
55 #include "input.h"
56 #include "vinfo.h"
57 #include "boxx.h"
58 #include "boxstack.h"
59 #include "log.h"
60 #include "sleeptimer.h"
61 #include "wjpeg.h"
62 #include "osdvector.h"
63 #include "config.h"
64 #include "vvideolivetv.h"
65 #include "channel.h"
66 #include "imageloader.h"
67
68
69 #ifdef VOMP_PLATFORM_RASPBERRY
70   #include "ledraspberry.h"
71   #include "osdopenvg.h"
72   #include "videoomx.h"
73   #include "audioomx.h"
74 #endif
75
76 #ifdef WIN32
77   #include "windowsosd.h"
78   #ifdef WINDOWS_LEGACY
79     #include "osdwinpixel.h"
80   #else
81     #include "osdwinvector.h"
82   #endif
83
84   #include "ledwin.h"
85   #include "videowin.h"
86   #include "audiowin.h"
87 #endif
88
89 #include "control.h"
90
91 static const char* TAG = "Control";
92
93 Control* Control::instance = NULL;
94
95 Control::Control()
96 {
97   if (instance) return;
98   instance = this;
99 }
100
101 Control::~Control()
102 {
103   flushMessageQueue();
104   instance = NULL;
105 }
106
107 Control* Control::getInstance()
108 {
109   return instance;
110 }
111
112 bool Control::init(bool tcrashed)
113 {
114   if (initted) return false;
115   crashed = tcrashed;
116   logger = LogNT::getInstance();
117
118   #if TELEM_ENABLED == 1
119   Telemetry::init();
120   #endif
121
122   SkinFactory::InitSkin(0);
123
124   // FIXME All constructors first which do very little & don't rely on presence of other objects.
125   // Then all inits. Inits retrieve pointers to other objects.
126
127   try
128   {
129     led = new Led_TYPE();                     if (!led) throw 10;
130     if (!led->init(-1))                       throw 11;  // FIXME init(0) on Win32
131
132     timers = new Timers();                    if (!timers) throw 20;
133     if (!timers->init())                      throw 21;
134
135     video = new Video_TYPE();                 if (!video) throw 30;
136     if (!video->init(Video::PAL))             throw 31;
137
138     audio = new Audio_TYPE();                 if (!audio) throw 40;
139     if (!audio->init(Audio::MPEG2_PES))       throw 41;
140
141     imageLoader = new ImageLoader();          if (!imageLoader) throw 50;
142     if (!imageLoader->init())                 throw 51;
143
144     osd = new Osd_TYPE();                     if (!osd) throw 60;
145     if (!osd->init())                         throw 61;
146
147     vdr = new VDR();                          if (!vdr) throw 70;
148     if (!vdr->init())                         throw 71;
149
150     boxstack = new BoxStack();                if (!boxstack) throw 80;
151     if (!boxstack->init())                    throw 81;
152
153     sleepTimer = new SleepTimer();            if (!sleepTimer) throw 90;
154
155     wol = new Wol();                          if (!wol) throw 100;
156
157     inputMan = new InputMan();                if (!inputMan) throw 110;
158     if (!inputMan->init())                    throw 111;
159
160   }
161   catch (int e)
162   {
163     if      (e == 10) logger->crit(TAG, "LED module failed to create");
164     else if (e == 11) logger->crit(TAG, "LED module failed to initialise");
165     else if (e == 20) logger->crit(TAG, "Timers module failed to create");
166     else if (e == 21) logger->crit(TAG, "Timers module failed to initialise");
167     else if (e == 30) logger->crit(TAG, "Video module failed to create");
168     else if (e == 31) logger->crit(TAG, "Video module failed to initialise");
169     else if (e == 40) logger->crit(TAG, "Audio module failed to create");
170     else if (e == 41) logger->crit(TAG, "Audio module failed to initialise");
171     else if (e == 50) logger->crit(TAG, "ImageLoader module failed to create");
172     else if (e == 51) logger->crit(TAG, "ImageLoader module failed to initialise");
173     else if (e == 60) logger->crit(TAG, "OSD module failed to create");
174     else if (e == 61) logger->crit(TAG, "OSD module failed to initialise");
175     else if (e == 70) logger->crit(TAG, "VDR module failed to create");
176     else if (e == 71) logger->crit(TAG, "VDR module failed to initialise");
177     else if (e == 80) logger->crit(TAG, "BoxStack module failed to create");
178     else if (e == 81) logger->crit(TAG, "BoxStack module failed to initialise");
179     else if (e == 90) logger->crit(TAG, "SleepTimer module failed to create");
180     else if (e == 100) logger->crit(TAG, "WOL module failed to create");
181     else if (e == 110) logger->crit(TAG, "InputMan module failed to create");
182     else if (e == 111) logger->crit(TAG, "InputMan module failed to initialise");
183
184     switch(e)
185     {
186       case 111:
187         delete inputMan;
188         inputMan = NULL;
189         FALLTHROUGH
190       case 110:
191         delete wol;
192         wol = NULL;
193         FALLTHROUGH
194       case 100:
195         delete sleepTimer;
196         sleepTimer = NULL;
197         FALLTHROUGH
198       case 90:
199         boxstack->shutdown();
200         FALLTHROUGH
201       case 81:
202         delete boxstack;
203         boxstack = NULL;
204         FALLTHROUGH
205       case 80:
206         vdr->shutdown();
207         FALLTHROUGH
208       case 71:
209         delete vdr;
210         vdr = NULL;
211         FALLTHROUGH
212       case 70:
213         osd->shutdown();
214         FALLTHROUGH
215       case 61:
216         delete osd;
217         osd = NULL;
218         FALLTHROUGH
219       case 60:
220         imageLoader->shutdown();
221         FALLTHROUGH
222       case 51:
223         delete imageLoader;
224         imageLoader = NULL;
225         FALLTHROUGH
226       case 50:
227         audio->shutdown();
228         FALLTHROUGH
229       case 41:
230         delete audio;
231         audio = NULL;
232         FALLTHROUGH
233       case 40:
234         video->shutdown();
235         FALLTHROUGH
236       case 31:
237         delete video;
238         video = NULL;
239         FALLTHROUGH
240       case 30:
241         timers->shutdown();
242         FALLTHROUGH
243       case 21:
244         delete timers;
245         timers = NULL;
246         FALLTHROUGH
247       case 20:
248         led->shutdown();
249         FALLTHROUGH
250       case 11:
251         delete led;
252         led = NULL;
253         FALLTHROUGH
254       case 10:
255         ;
256     }
257
258     return false;
259   }
260
261   initted = true;
262   return true;
263 }
264
265 void Control::shutdown()
266 {
267   if (!initted) return;
268   initted = false;
269
270   if (inputMan)
271   {
272     inputMan->shutdown();
273     delete inputMan;
274     inputMan = NULL;
275     logger->info(TAG, "InputMan module shut down");
276   }
277
278   if (wol)
279   {
280     delete wol;
281     logger->info(TAG, "WOL module shut down");
282   }
283
284   if (sleepTimer)
285   {
286     delete sleepTimer;
287     sleepTimer = NULL;
288     logger->info(TAG, "SleepTimer module shut down");
289   }
290
291   if (boxstack)
292   {
293     boxstack->shutdown();
294     delete boxstack;
295     boxstack = NULL;
296     logger->info(TAG, "BoxStack module shut down");
297   }
298
299   if (vdr)
300   {
301     vdr->shutdown();
302     delete vdr;
303     vdr = NULL;
304     logger->info(TAG, "VDR module shut down");
305   }
306
307   if (osd)
308   {
309     osd->shutdown();
310     delete osd;
311     osd = NULL;
312     logger->info(TAG, "OSD module shut down");
313   }
314
315   if (imageLoader)
316   {
317     imageLoader->shutdown();
318     delete imageLoader;
319     imageLoader = NULL;
320     logger->info(TAG, "ImageLoader shut down");
321   }
322
323   if (audio)
324   {
325     audio->shutdown();
326     delete audio;
327     audio = NULL;
328     logger->info(TAG, "Audio module shut down");
329   }
330
331   if (video)
332   {
333     video->shutdown();
334     delete video;
335     video = NULL;
336     logger->info(TAG, "Video module shut down");
337   }
338
339   if (timers)
340   {
341     timers->shutdown();
342     delete timers;
343     timers = NULL;
344     logger->info(TAG, "Timers module shut down");
345   }
346
347   if (led)
348   {
349     led->shutdown();
350     delete led;
351     led = NULL;
352     logger->info(TAG, "LED module shut down");
353   }
354 }
355
356 void Control::stop()
357 {
358   logger->info(TAG, "Request stop");
359
360   Message* m = new Message(); // break master loop
361   m->message = Message::SHUTDOWN;
362   m->p_to = Message::CONTROL;
363   postMessage(m);
364 }
365
366 void Control::doWallpaper()
367 {
368   // Blue background
369   Boxx* bbg = new Boxx();
370   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
371   bbg->createBuffer();
372   bbg->fillColour(DrawStyle::WALLPAPER);
373   boxstack->add(bbg);
374   boxstack->update(bbg);
375   boxstack->remove(bbg);
376
377   // Wallpaper
378   wallpaper = new Boxx();
379   wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight());
380   wallpaper->createBuffer();
381   wallpaper->setBackgroundColour(DrawStyle::WALLPAPER);
382
383   wallpaper_pict = new WJpegTYPE();
384   wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight());
385
386   if (video->getFormat() == Video::PAL)
387   {
388     logger->debug(TAG, "PAL wallpaper selected");
389 #ifndef _MIPS_ARCH    
390     wallpaper_pict->init("/wallpaperPAL.jpg");
391 #else
392     wallpaper_pict->init("wallpaperPAL.jpg");
393 #endif
394   }
395   else
396   {
397     logger->debug(TAG, "NTSC wallpaper selected");
398     wallpaper_pict->init("/wallpaperNTSC.jpg");
399   }
400
401   if (DrawStyle::WALLPAPER.alpha)
402     wallpaper_pict->setVisible(true);
403   else
404     wallpaper_pict->setVisible(false);
405
406   wallpaper->add(wallpaper_pict);
407   wallpaper->draw();
408
409   boxstack->add(wallpaper);
410   boxstack->update(wallpaper);
411
412   OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
413   if (osdv) osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
414 }
415
416 void Control::run()
417 {
418   if (!initted) return;
419
420   // just in case
421   Video::getInstance()->signalOn();
422   Led::getInstance()->on();
423
424   doWallpaper();
425
426   if (crashed)
427   {
428     buildCrashedBox();
429   }
430   else
431   {
432     VConnect* vconnect = new VConnect(); // Deleted when VConnect messages Control, and is boxstack->remove()'d
433     boxstack->add(vconnect);
434     vconnect->run();
435   }
436
437   inputMan->start();
438
439   //logger->debug(TAG, "Setting log trace only mode");
440   //logger->setTraceOnlyMode(false);
441
442   messageLoopRun = true;
443   messageLoop();
444
445   inputMan->stop();
446
447   boxstack->removeAllExceptWallpaper();
448   boxstack->remove(wallpaper);
449   delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
450 }
451
452 void Control::dispatchMessage(Message* m)
453 {
454   logger->debug(TAG, "processing message {}", m->message);
455
456   if (m->p_to == Message::CONTROL)
457   {
458     switch(m->message)
459     {
460       case Message::SHUTDOWN:
461       {
462         messageLoopRun = false;
463         break;
464       }
465       case Message::STOP_PLAYBACK:
466       {
467         handleCommand(Input::STOP); // an odd way of doing it, but so simple
468         break;
469       }
470       case Message::VDR_CONNECTED:
471       {
472         doJustConnected(static_cast<VConnect*>(m->from));
473         break;
474       }
475       case Message::SCREENSHOT:
476       {
477         logger->info(TAG, "Screenshot Message arrived");
478         Osd::getInstance()->screenShot("out.jpg");
479         break;
480       }
481       case Message::CONNECTION_LOST:
482       {
483         doFromTheTop(true);
484         break;
485       }
486       case Message::INPUT_EVENT:
487       {
488         logger->info(TAG, "INPUT_EVENT {}", m->parameter);
489
490         handleCommand(m->parameter);
491         break;
492       }
493       case Message::CHANGE_LANGUAGE:
494       {
495         boxstack->removeAllExceptWallpaper();
496         boxstack->update(wallpaper);
497         I18n::initialize();
498         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
499         VWelcome* vw = new VWelcome();
500         vw->draw();
501         boxstack->add(vw);
502         boxstack->update(vw);
503         break;
504       }
505       case Message::LAST_VIEW_CLOSE:
506       {
507         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
508         if (crashed)
509         {
510           crashed = false;
511           doFromTheTop(false);        
512         }
513       
514 //        VWelcome* vw = new VWelcome();
515 //        vw->draw();
516 //        boxstack->add(vw);
517 //        boxstack->update(vw);
518
519         break;
520       }
521     }
522   }
523   else if (m->p_to == Message::BOXSTACK)
524   {
525     boxstack->processMessage(m);
526   }
527   else if (m->p_to == Message::MOUSE_RECEIVER)
528   {
529     logger->debug(TAG, "Sending mouse message to boxstack for dispatch");
530     boxstack->processMessage(m);
531   }
532
533   else
534   {
535     m->to->processMessage(m);
536   }
537
538   logger->debug(TAG, "done processing message {}", m->message);
539 }
540
541 void Control::handleCommand(int button)
542 {
543   if (isStandby && (button != Input::POWER)
544                 && (button != Input::POWERON)
545                 && (button != Input::POWEROFF))  return;
546
547   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
548
549   // command was not handled
550
551   switch(button)
552   {
553     case Input::VOLUMEUP:
554     case Input::VOLUMEDOWN:
555     {
556       if (inputMan->handlesVolume()) // CEC volume handler?
557       {
558         if (button == Input::VOLUMEDOWN)
559           inputMan->volumeDown();
560         else
561           inputMan->volumeUp();
562       }
563       else
564       {
565         VVolume* v = new VVolume();
566         boxstack->add(v);
567         v->handleCommand(button); // this will draw+show
568       }
569       return;
570     }
571     case Input::MUTE:
572     {
573       if (inputMan->handlesVolume())
574       {
575         inputMan->volumeMute();
576       }
577       else
578       {
579         VMute* v = new VMute();
580         v->draw();
581         boxstack->add(v);
582         boxstack->update(v);
583       }
584       return;
585     }
586     case Input::POWER:
587     {
588       doStandby();
589       return;
590     }
591     case Input::POWERON:
592     {
593       doPowerOn();
594       return;
595     }
596     case Input::POWEROFF:
597     {
598       doPowerOff();
599       return;
600     }
601     case Input::OK:
602     {
603       // FIXME
604       if (!connLost) return; // if connLost, handle Input::OK
605       doFromTheTop(false);
606       return;
607     }
608     case Input::GO:
609     {
610       logger->debug(TAG, "Handling sleeptimer go");
611       sleepTimer->go();
612       return;
613     }
614   }
615 }
616
617 /*
618 void Control::sig1()
619 {
620 #ifdef DEV
621   Message* m = new Message(); // break into master mutex
622   m->message = Message::SCREENSHOT;
623   m->p_to = Message::CONTROL;
624   postMessage(m);
625 #endif
626 }
627 */
628
629 void Control::doStandby()
630 {
631   if (isStandby)
632   {
633     doPowerOn();
634   }
635   else
636   {
637     doPowerOff();
638   }
639 }
640
641
642 void Control::doPowerOn()
643 {
644   if (isStandby)
645   {
646     Video::getInstance()->signalOn();
647     Led::getInstance()->on();
648     InputMan::getInstance()->changePowerState(true);
649     isStandby = false;
650
651     VConnect* vconnect = new VConnect();
652     boxstack->add(vconnect);
653     vconnect->run();
654   }
655 }
656
657 void Control::doPowerOff()
658 {
659   if (!isStandby)
660   {
661     VDR::getInstance()->shutdownVDR();
662     boxstack->removeAllExceptWallpaper();
663     Video::getInstance()->signalOff();
664     boxstack->update(wallpaper);
665
666     VDR::getInstance()->configSave("General", "Last Power State", "Off");
667     logger->unsetExternLogger();
668     VDR::getInstance()->disconnect();
669     Led::getInstance()->off();
670     InputMan::getInstance()->changePowerState(false);
671     isStandby = true;
672     sleepTimer->shutdown();
673   }
674 }
675
676 void Control::doFromTheTop(bool which)
677 {
678   if (isStandby) return;
679   if (which)
680   {
681     if (connLost)
682     {
683       logger->info(TAG, "Connection lost dialog already present");
684       return;
685     }
686   
687     logger->info(TAG, "Doing connection lost dialog");
688     connLost = new VInfo();
689     connLost->setSize(360, 200);
690     connLost->createBuffer();
691     if (Video::getInstance()->getFormat() == Video::PAL)
692       connLost->setPosition(190, 170);
693     else
694       connLost->setPosition(180, 120);
695     connLost->setOneLiner(tr("Connection lost"));
696     connLost->setDropThrough();
697     connLost->setBorderOn(1);
698     connLost->setTitleBarColour(DrawStyle::DANGER);
699     connLost->okButton();
700     connLost->draw();
701     boxstack->add(connLost);
702     boxstack->update(connLost);
703
704     clearMQInputEvents();
705   }
706   else
707   {
708     logger->unsetExternLogger();
709     VDR::getInstance()->disconnect();
710     boxstack->removeAllExceptWallpaper();
711     boxstack->update(wallpaper);
712     connLost = NULL;
713     
714     flushMessageQueue();
715     
716     // at this point, everything should be reset to first-go
717     
718     VConnect* vconnect = new VConnect(); // deleted eventually in boxstack
719     boxstack->add(vconnect);
720     vconnect->run();
721   }
722 }
723
724 void Control::clearMQInputEvents()
725 {
726   std::lock_guard<std::mutex> lg(messageQueueMutex); // Get the lock
727
728   MQueueI i = messages.begin();
729   while(i != messages.end())
730   {
731     Message* m = *i;
732     if (m->message == Message::INPUT_EVENT)
733     {
734       delete m;
735       i = messages.erase(i);
736     }
737     else
738     {
739       ++i;
740     }
741   }
742 }
743
744 void Control::doReboot()
745 {
746
747   logger->unsetExternLogger();
748   VDR::getInstance()->disconnect();
749   // just kill it...
750   logger->info(TAG, "Reboot");
751 #ifndef WIN32
752 #ifndef VOMP_HAS_EXIT
753   // some plattforms, want a proper deinitialisation of their hardware before reboot
754   Osd::getInstance()->shutdown();
755   Audio::getInstance()->shutdown();
756   Video::getInstance()->shutdown();
757   InputMan::getInstance()->shutdown();
758
759   reboot(LINUX_REBOOT_CMD_RESTART);
760   // if  reboot is not allowed -> stop
761   stop();
762
763
764 #else
765   stop();
766
767 #ifdef __ANDROID__
768   exit(0);
769 #endif
770
771 #endif
772 #endif //Would we support this on windows?
773 }
774
775 void Control::connectionLost()
776 {
777   logger->unsetExternLogger();
778   Message* m = new Message(); // break into master mutex
779   m->message = Message::CONNECTION_LOST;
780   m->p_to = Message::CONTROL;
781   postMessage(m);
782 }
783
784 void Control::buildCrashedBox()
785 {
786   VInfo* crash = new VInfo();
787   crash->setSize(360, 250);
788   crash->createBuffer();
789   if (Video::getInstance()->getFormat() == Video::PAL)
790     crash->setPosition(190, 146);
791   else
792     crash->setPosition(180, 96);
793   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.");
794   crash->setBorderOn(1);
795   crash->setTitleBarColour(DrawStyle::DANGER);
796   crash->okButton();
797   crash->setExitable();
798   crash->draw();
799   boxstack->add(crash);
800   boxstack->update(crash);
801 }
802
803 int Control::getLangPref(bool subtitle, const char* langcode)
804 {
805   std::vector<struct ASLPref>::iterator itty=langcodes.begin();
806   char templangcode[4];
807   templangcode[0] = langcode[0];
808   templangcode[1] = langcode[1];
809   templangcode[2] = langcode[2];
810   templangcode[3] = '\0';
811   int langpos = 0;
812   while (itty != langcodes.end())
813   {
814     size_t pos = (*itty).langcode.find(templangcode);
815     if (pos != std::string::npos)
816     {
817       //vector<struct ASLPref>::iterator itty2=langcodes.begin();
818       for (unsigned int i = 0; i < langcodes.size(); i++)
819       {
820         int pref = 0;
821         if (subtitle)
822           pref = langcodes[i].subtitlepref;
823         else
824           pref = langcodes[i].audiopref;
825         if (pref < 0) break;
826
827         if (subtitle)
828         {
829           if (langcodes[i].subtitlepref==langpos) return i;
830         }
831         else
832         {
833           if (langcodes[i].audiopref==langpos) return i;
834         }
835       }
836       break;
837     }
838     itty++;
839     langpos++;
840   }
841   return langcodes.size(); //neutral
842 }
843
844 void Control::doJustConnected(VConnect* vconnect)
845 {
846   I18n::initialize();
847   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
848   logger->info(TAG, "Entering doJustConnected");
849   
850   boxstack->remove(vconnect);
851
852   VInfo* vi = new VInfo();
853   vi->setSize(400, 200);
854   vi->createBuffer();
855   if (video->getFormat() == Video::PAL)
856     vi->setPosition(170, 200);
857   else
858     vi->setPosition(160, 150);
859   vi->setOneLiner(tr("Connected, loading config"));
860   vi->draw();
861   boxstack->add(vi);
862   boxstack->update(vi);
863
864   // FIXME make config system
865
866   char* config;
867
868   // See if we're supposed to do network logging
869   config = vdr->configLoad("Advanced", "Network logging");
870   if (config && !STRCASECMP(config, "On"))
871   {
872     logger->info(TAG, "Turning on network logging");
873     logger->setExternLogger(vdr);
874   }  
875   else
876   {
877           logger->unsetExternLogger();
878     logger->info(TAG, "Turned off network logging");
879   }
880   if (config) delete[] config;
881
882   config = vdr->configLoad("Advanced", "Skin Name");
883   if (config)
884   {
885     const char **skinnames=SkinFactory::getSkinNames();
886     for (int i=0;i<SkinFactory::getNumberofSkins();i++)
887     {
888       if (!STRCASECMP(config, skinnames[i]))
889       {
890         SkinFactory::InitSkin(i);
891         break;
892       }
893     }
894     delete[] config;
895
896     if (wallpaper && wallpaper_pict)
897     {
898       if (DrawStyle::WALLPAPER.alpha)
899         wallpaper_pict->setVisible(true);
900       else
901         wallpaper_pict->setVisible(false);
902
903       wallpaper->draw();
904       boxstack->update(wallpaper);
905     }
906   }
907   else
908   {
909     SkinFactory::InitSkin(0);
910   }
911
912   // See if config says to override video format (PAL/NTSC)
913   config = vdr->configLoad("General", "Override Video Format");
914   if (config)
915   {
916     logger->debug(TAG, "Override Video Format is present");
917
918     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
919         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
920         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
921         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
922         )
923     {
924       // Oh sheesh, need to switch format. Bye bye TV...
925
926       // Take everything down
927       boxstack->removeAllExceptWallpaper();
928       boxstack->remove(wallpaper);
929       delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
930
931 #ifndef __ANDROID__
932       osd->shutdown();
933 #endif
934       video->shutdown();
935
936       // FIXME FIXME FIXME why do this?
937       inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
938       inputMan->init();
939
940       // Get video and osd back up with the new mode
941       if (!strcmp(config, "PAL"))
942       {
943         logger->debug(TAG, "Switching to PAL");
944         video->init(Video::PAL);
945       }
946       else if (!strcmp(config, "NTSC"))
947       {
948         logger->debug(TAG, "Switching to NTSC");
949         video->init(Video::NTSC);
950       } else if (!strcmp(config, "PAL_M"))
951       {
952         logger->debug(TAG, "Switching to PAL_M");
953         video->init(Video::PAL_M);
954       } else if (!strcmp(config, "NTSC_J"))
955       {
956         logger->debug(TAG, "Switching to NTSC_J");
957         video->init(Video::NTSC_J);
958       }
959       delete[] config;
960
961 #ifndef __ANDROID__
962       //we do not init twice
963       osd->init();
964 #endif
965
966       // Put the wallpaper back
967       doWallpaper();
968
969       // Re add the vinfo
970       vi = new VInfo();
971       vi->setSize(400, 200);
972       vi->createBuffer();
973       if (video->getFormat() == Video::PAL)
974         vi->setPosition(170, 200);
975       else
976         vi->setPosition(160, 150);
977
978       vi->setOneLiner(tr("Connected, loading config"));
979       vi->draw();
980       boxstack->add(vi);
981       boxstack->update(vi);
982     }
983     else
984     {
985       logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
986     }
987   }
988   else
989   {
990     logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
991   }
992
993   // Power off if first boot and config says so
994   if (firstBoot)
995   {
996     firstBoot = false;
997
998     logger->debug(TAG, "Load power after boot");
999
1000     config = vdr->configLoad("General", "Power After Boot");
1001
1002     if (config)
1003     {
1004       if (!STRCASECMP(config, "On"))
1005       {
1006         logger->info(TAG, "Config says Power After Boot = On");
1007       }
1008       else if (!STRCASECMP(config, "Off"))
1009       {
1010         logger->info(TAG, "Config says Power After Boot = Off");
1011         doStandby();
1012         delete[] config;
1013         return; // quit here
1014       }
1015       else if (!STRCASECMP(config, "Last state"))
1016       {
1017         char* lastPowerState = vdr->configLoad("General", "Last Power State");
1018         if (lastPowerState)
1019         {
1020           if (!STRCASECMP(lastPowerState, "On"))
1021           {
1022             logger->info(TAG, "Config says Last Power State = On");
1023           }
1024           else if (!STRCASECMP(lastPowerState, "Off"))
1025           {
1026             logger->info(TAG, "Config says Last Power State = Off");
1027             doStandby();
1028             delete[] config;
1029             return; // quit here
1030           }
1031           else
1032           {
1033             logger->info(TAG, "Config General/Last Power State not understood");
1034           }
1035         }
1036         else
1037         {
1038           logger->info(TAG, "Config General/Last Power State not found");
1039         }
1040       }
1041       else
1042       {
1043         logger->info(TAG, "Config/Power After Boot not understood");
1044       }
1045       delete[] config;
1046     }
1047     else
1048     {
1049       logger->info(TAG, "Config General/Power After Boot not found");
1050     }
1051   }
1052
1053
1054   // Go S-Video if config says so
1055
1056   config = vdr->configLoad("TV", "Connection");
1057
1058   if (config)
1059   {
1060     if (!STRCASECMP(config, "S-Video"))
1061     {
1062       logger->info(TAG, "Switching to S-Video as Connection={}", config);
1063       video->setConnection(Video::SVIDEO);
1064     } else  if (!STRCASECMP(config, "HDMI"))
1065     {
1066       logger->info(TAG, "Switching to HDMI as Connection={}", config);
1067       video->setConnection(Video::HDMI);
1068     } else  if (!STRCASECMP(config, "HDMI3D"))
1069     {
1070       logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1071       video->setConnection(Video::HDMI3D);
1072     }
1073     else
1074     {
1075       logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1076       video->setConnection(Video::COMPOSITERGB);
1077     }
1078     delete[] config;
1079   }
1080   else
1081   {
1082     logger->info(TAG, "Config TV/S-Video not found");
1083   }
1084
1085   // Set to shutdown VDR if config says
1086   
1087   config = vdr->configLoad("General", "VDR shutdown");
1088   if (config)
1089   {
1090     if (!STRCASECMP(config, "On"))
1091     {
1092       logger->info(TAG, "Shutdown VDR when shutting down vomp");
1093       vdr->setVDRShutdown(true);
1094     }
1095     else if (!STRCASECMP(config, "Off"))
1096     {
1097       logger->info(TAG, "Shutdown only vomp");
1098       vdr->setVDRShutdown(false);
1099     }
1100   }
1101   else
1102   {
1103     logger->info(TAG, "Default shutdown only vomp");
1104     vdr->setVDRShutdown(false); // Default
1105   }
1106           
1107   // Get TV aspect ratio
1108
1109   config = vdr->configLoad("TV", "Aspect");
1110   if (config)
1111   {
1112     if (!STRCASECMP(config, "16:9"))
1113     {
1114       logger->info(TAG, "/// Switching to TV aspect 16:9");
1115       video->setTVsize(Video::ASPECT16X9);
1116     }
1117     else
1118     {
1119       logger->info(TAG, "/// Switching to TV aspect 4:3");
1120       video->setTVsize(Video::ASPECT4X3);
1121     }
1122     delete[] config;
1123   }
1124   else
1125   {
1126     logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1127     video->setTVsize(Video::ASPECT4X3);
1128   }
1129
1130   config = vdr->configLoad("TV", "Widemode");
1131   if (config)
1132   {
1133     if (!STRCASECMP(config, "Letterbox"))
1134     {
1135       logger->info(TAG, "Setting letterbox mode");
1136       video->setMode(Video::LETTERBOX);
1137     }
1138     else
1139     {
1140       logger->info(TAG, "Setting chop-sides mode");
1141       video->setMode(Video::NORMAL);
1142     }
1143     delete[] config;
1144   }
1145   else
1146   {
1147 #ifdef __ANDROID__
1148          logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1149          video->setMode(Video::LETTERBOX);
1150 #else
1151     logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1152     video->setMode(Video::NORMAL);
1153 #endif
1154   }
1155
1156   config = vdr->configLoad("Advanced", "TCP receive window");
1157   if (config)
1158   {
1159     size_t newTCPsize = atoi(config);
1160     delete[] config;
1161
1162     logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1163     vdr->setReceiveWindow(newTCPsize);
1164   }
1165   else
1166   {
1167     logger->info(TAG, "TCP window size not found, setting 2048");
1168     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1169   }
1170
1171   config = vdr->configLoad("Advanced", "Font Name");
1172   if (config)
1173   {
1174         Osd::getInstance()->setFont(config);
1175     logger->info(TAG, "Setting Font to %s", config);
1176     delete[] config;
1177
1178   }
1179
1180
1181   // Set recording list type
1182
1183 #ifdef ADVANCED_MENUES
1184   config = vdr->configLoad("Advanced", "Menu type");
1185
1186   if (config)
1187   {
1188     if (!STRCASECMP(config, "Advanced"))
1189     {
1190       logger->info(TAG, "Switching to Advanced menu");
1191       advMenus = true;
1192     }
1193     else
1194     {
1195       logger->info(TAG, "Switching to Classic menu");
1196       advMenus = false;
1197     }
1198     delete[] config;
1199   }
1200   else
1201   {
1202     logger->info(TAG, "Config General/menu type not found");
1203     advMenus = true;
1204   }
1205 #endif
1206
1207   config = vdr->configLoad("Advanced", "Disable WOL");
1208   if (config)
1209   {
1210     if (!STRCASECMP(config, "Yes"))
1211     {
1212       logger->info(TAG, "Config says disable WOL");
1213       Wol::getInstance()->setEnabled(false);
1214     }
1215     else
1216     {
1217       logger->info(TAG, "Config says enable WOL");
1218       Wol::getInstance()->setEnabled(true);
1219     }
1220
1221     delete[] config;
1222   }
1223   else
1224   {
1225     logger->info(TAG, "By default, enable WOL");
1226     Wol::getInstance()->setEnabled(true);
1227   }
1228   /* device dependend config */
1229   audio->loadOptionsFromServer(vdr);
1230   video->loadOptionsFromServer(vdr);
1231   inputMan->loadOptionsFromServer(vdr);
1232
1233   video->executePendingModeChanges();
1234   // config done
1235
1236   // Save power state = on
1237
1238   vdr->configSave("General", "Last Power State", "On");
1239
1240   // Make sure connection didn't die
1241   if (!vdr->isConnected())
1242   {
1243     Control::getInstance()->connectionLost();
1244   }
1245   else
1246   {
1247     boxstack->remove(vi);
1248
1249     VWelcome* vw = new VWelcome();
1250     vw->draw();
1251     boxstack->add(vw);
1252     // No boxstack->update yet
1253
1254     Config* localConfig = Config::getInstance();
1255     int startToLiveTV{};
1256     localConfig->getInt("main", "start_to_live_tv", startToLiveTV);
1257     if (startToLiveTV)
1258     {
1259       std::shared_ptr<ChannelList> chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);
1260       if (chanList && chanList->size())
1261       {
1262         Channel* chan = NULL;
1263         for (u4 i = 0; i < chanList->size(); i++)
1264         {
1265           if ((*chanList)[i]->number == static_cast<u4>(startToLiveTV))
1266           {
1267             chan = (*chanList)[i];
1268             break;
1269           }
1270         }
1271         if (chan)
1272         {
1273           VVideoLiveTV* v = new VVideoLiveTV(chanList, chan->number, NULL);
1274           boxstack->add(v);
1275           v->go();
1276         }
1277         else
1278         {
1279           // Could not find channel, no VVideoLiveTV was made, update vw instead
1280           boxstack->update(vw);
1281         }
1282       }
1283       else
1284       {
1285         Control::getInstance()->connectionLost();
1286       }
1287     }
1288     else // Not starting to live TV
1289     {
1290       boxstack->update(vw);
1291     }
1292
1293     // Enter pre-keys here
1294 //    handleCommand(Input::OK);
1295 //    handleCommand(Input::THREE);
1296 //    handleCommand(Input::SIX);
1297 //    handleCommand(Input::UP);
1298 //    handleCommand(Input::OK);
1299 //    handleCommand(Input::OK);
1300 //    handleCommand(Input::PLAY);
1301 //    handleCommand(Input::DOWN);
1302 //    handleCommand(Input::DOWN);
1303 //    handleCommand(Input::DOWN);
1304 //    handleCommand(Input::RIGHT);
1305 //    handleCommand(Input::RED);
1306   }
1307 }