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