]> git.vomp.tv Git - vompclient.git/blob - control.cc
Implement startup-to-live-TV
[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       inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
906       inputMan->init(); // FIXME this breaks badly now
907
908       // Get video and osd back up with the new mode
909       if (!strcmp(config, "PAL"))
910       {
911         logger->debug(TAG, "Switching to PAL");
912         video->init(Video::PAL);
913       }
914       else if (!strcmp(config, "NTSC"))
915       {
916         logger->debug(TAG, "Switching to NTSC");
917         video->init(Video::NTSC);
918       } else if (!strcmp(config, "PAL_M"))
919       {
920         logger->debug(TAG, "Switching to PAL_M");
921         video->init(Video::PAL_M);
922       } else if (!strcmp(config, "NTSC_J"))
923       {
924         logger->debug(TAG, "Switching to NTSC_J");
925         video->init(Video::NTSC_J);
926       }
927       delete[] config;
928
929 #ifndef __ANDROID__
930       //we do not init twice
931       osd->init();
932 #endif
933
934       // Put the wallpaper back
935       doWallpaper();
936
937       // Re add the vinfo
938       vi = new VInfo();
939       vi->setSize(400, 200);
940       vi->createBuffer();
941       if (video->getFormat() == Video::PAL)
942         vi->setPosition(170, 200);
943       else
944         vi->setPosition(160, 150);
945
946       vi->setOneLiner(tr("Connected, loading config"));
947       vi->draw();
948       boxstack->add(vi);
949       boxstack->update(vi);
950     }
951     else
952     {
953       logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
954     }
955   }
956   else
957   {
958     logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
959   }
960
961   // Power off if first boot and config says so
962   if (firstBoot)
963   {
964     firstBoot = false;
965
966     logger->debug(TAG, "Load power after boot");
967
968     config = vdr->configLoad("General", "Power After Boot");
969
970     if (config)
971     {
972       if (!STRCASECMP(config, "On"))
973       {
974         logger->info(TAG, "Config says Power After Boot = On");
975       }
976       else if (!STRCASECMP(config, "Off"))
977       {
978         logger->info(TAG, "Config says Power After Boot = Off");
979         doStandby();
980         delete[] config;
981         return; // quit here
982       }
983       else if (!STRCASECMP(config, "Last state"))
984       {
985         char* lastPowerState = vdr->configLoad("General", "Last Power State");
986         if (lastPowerState)
987         {
988           if (!STRCASECMP(lastPowerState, "On"))
989           {
990             logger->info(TAG, "Config says Last Power State = On");
991           }
992           else if (!STRCASECMP(lastPowerState, "Off"))
993           {
994             logger->info(TAG, "Config says Last Power State = Off");
995             doStandby();
996             delete[] config;
997             return; // quit here
998           }
999           else
1000           {
1001             logger->info(TAG, "Config General/Last Power State not understood");
1002           }
1003         }
1004         else
1005         {
1006           logger->info(TAG, "Config General/Last Power State not found");
1007         }
1008       }
1009       else
1010       {
1011         logger->info(TAG, "Config/Power After Boot not understood");
1012       }
1013       delete[] config;
1014     }
1015     else
1016     {
1017       logger->info(TAG, "Config General/Power After Boot not found");
1018     }
1019   }
1020
1021
1022   // Go S-Video if config says so
1023
1024   config = vdr->configLoad("TV", "Connection");
1025
1026   if (config)
1027   {
1028     if (!STRCASECMP(config, "S-Video"))
1029     {
1030       logger->info(TAG, "Switching to S-Video as Connection={}", config);
1031       video->setConnection(Video::SVIDEO);
1032     } else  if (!STRCASECMP(config, "HDMI"))
1033     {
1034       logger->info(TAG, "Switching to HDMI as Connection={}", config);
1035       video->setConnection(Video::HDMI);
1036     } else  if (!STRCASECMP(config, "HDMI3D"))
1037     {
1038       logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1039       video->setConnection(Video::HDMI3D);
1040     }
1041     else
1042     {
1043       logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1044       video->setConnection(Video::COMPOSITERGB);
1045     }
1046     delete[] config;
1047   }
1048   else
1049   {
1050     logger->info(TAG, "Config TV/S-Video not found");
1051   }
1052
1053   // Set to shutdown VDR if config says
1054   
1055   config = vdr->configLoad("General", "VDR shutdown");
1056   if (config)
1057   {
1058     if (!STRCASECMP(config, "On"))
1059     {
1060       logger->info(TAG, "Shutdown VDR when shutting down vomp");
1061       vdr->setVDRShutdown(true);
1062     }
1063     else if (!STRCASECMP(config, "Off"))
1064     {
1065       logger->info(TAG, "Shutdown only vomp");
1066       vdr->setVDRShutdown(false);
1067     }
1068   }
1069   else
1070   {
1071     logger->info(TAG, "Default shutdown only vomp");
1072     vdr->setVDRShutdown(false); // Default
1073   }
1074           
1075   // Get TV aspect ratio
1076
1077   config = vdr->configLoad("TV", "Aspect");
1078   if (config)
1079   {
1080     if (!STRCASECMP(config, "16:9"))
1081     {
1082       logger->info(TAG, "/// Switching to TV aspect 16:9");
1083       video->setTVsize(Video::ASPECT16X9);
1084     }
1085     else
1086     {
1087       logger->info(TAG, "/// Switching to TV aspect 4:3");
1088       video->setTVsize(Video::ASPECT4X3);
1089     }
1090     delete[] config;
1091   }
1092   else
1093   {
1094     logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1095     video->setTVsize(Video::ASPECT4X3);
1096   }
1097
1098   config = vdr->configLoad("TV", "Widemode");
1099   if (config)
1100   {
1101     if (!STRCASECMP(config, "Letterbox"))
1102     {
1103       logger->info(TAG, "Setting letterbox mode");
1104       video->setMode(Video::LETTERBOX);
1105     }
1106     else
1107     {
1108       logger->info(TAG, "Setting chop-sides mode");
1109       video->setMode(Video::NORMAL);
1110     }
1111     delete[] config;
1112   }
1113   else
1114   {
1115 #ifdef __ANDROID__
1116          logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1117          video->setMode(Video::LETTERBOX);
1118 #else
1119     logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1120     video->setMode(Video::NORMAL);
1121 #endif
1122   }
1123
1124   config = vdr->configLoad("Advanced", "TCP receive window");
1125   if (config)
1126   {
1127     size_t newTCPsize = atoi(config);
1128     delete[] config;
1129
1130     logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1131     vdr->setReceiveWindow(newTCPsize);
1132   }
1133   else
1134   {
1135     logger->info(TAG, "TCP window size not found, setting 2048");
1136     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1137   }
1138
1139   config = vdr->configLoad("Advanced", "Font Name");
1140   if (config)
1141   {
1142         Osd::getInstance()->setFont(config);
1143     logger->info(TAG, "Setting Font to %s", config);
1144     delete[] config;
1145
1146   }
1147
1148
1149   // Set recording list type
1150
1151 #ifdef ADVANCED_MENUES
1152   config = vdr->configLoad("Advanced", "Menu type");
1153
1154   if (config)
1155   {
1156     if (!STRCASECMP(config, "Advanced"))
1157     {
1158       logger->info(TAG, "Switching to Advanced menu");
1159       advMenus = true;
1160     }
1161     else
1162     {
1163       logger->info(TAG, "Switching to Classic menu");
1164       advMenus = false;
1165     }
1166     delete[] config;
1167   }
1168   else
1169   {
1170     logger->info(TAG, "Config General/menu type not found");
1171     advMenus = true;
1172   }
1173 #endif
1174
1175   config = vdr->configLoad("Advanced", "Disable WOL");
1176   if (config)
1177   {
1178     if (!STRCASECMP(config, "Yes"))
1179     {
1180       logger->info(TAG, "Config says disable WOL");
1181       Wol::getInstance()->setEnabled(false);
1182     }
1183     else
1184     {
1185       logger->info(TAG, "Config says enable WOL");
1186       Wol::getInstance()->setEnabled(true);
1187     }
1188
1189     delete[] config;
1190   }
1191   else
1192   {
1193     logger->info(TAG, "By default, enable WOL");
1194     Wol::getInstance()->setEnabled(true);
1195   }
1196   /* device dependend config */
1197   audio->loadOptionsFromServer(vdr);
1198   video->loadOptionsFromServer(vdr);
1199   inputMan->loadOptionsFromServer(vdr);
1200
1201   video->executePendingModeChanges();
1202   // config done
1203
1204   // Save power state = on
1205
1206   vdr->configSave("General", "Last Power State", "On");
1207
1208   // Make sure connection didn't die
1209   if (!vdr->isConnected())
1210   {
1211     Control::getInstance()->connectionLost();
1212   }
1213   else
1214   {
1215     boxstack->remove(vi);
1216
1217     VWelcome* vw = new VWelcome();
1218     vw->draw();
1219     boxstack->add(vw);
1220     // No boxstack->update yet
1221
1222     Config* localConfig = Config::getInstance();
1223     int startToLiveTV{};
1224     localConfig->getInt("main", "start_to_live_tv", startToLiveTV);
1225     if (startToLiveTV)
1226     {
1227       std::shared_ptr<ChannelList> chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);
1228       if (chanList && chanList->size())
1229       {
1230         Channel* chan = NULL;
1231         for (UINT i = 0; i < chanList->size(); i++)
1232         {
1233           if ((*chanList)[i]->number == static_cast<ULONG>(startToLiveTV))
1234           {
1235             chan = (*chanList)[i];
1236             break;
1237           }
1238         }
1239         if (chan)
1240         {
1241           VVideoLiveTV* v = new VVideoLiveTV(chanList, chan->number, NULL);
1242           boxstack->add(v);
1243           v->go();
1244         }
1245         else
1246         {
1247           // Could not find channel, no VVideoLiveTV was made, update vw instead
1248           boxstack->update(vw);
1249         }
1250       }
1251       else
1252       {
1253         Control::getInstance()->connectionLost();
1254       }
1255     }
1256     else // Not starting to live TV
1257     {
1258       boxstack->update(vw);
1259     }
1260
1261     // Enter pre-keys here
1262 //    handleCommand(Input::OK);
1263 //    handleCommand(Input::THREE);
1264 //    handleCommand(Input::SIX);
1265 //    handleCommand(Input::UP);
1266 //    handleCommand(Input::OK);
1267 //    handleCommand(Input::OK);
1268 //    handleCommand(Input::PLAY);
1269 //    handleCommand(Input::DOWN);
1270 //    handleCommand(Input::DOWN);
1271 //    handleCommand(Input::DOWN);
1272 //    handleCommand(Input::RIGHT);
1273 //    handleCommand(Input::RED);
1274   }
1275 }