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