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