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