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