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