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