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