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