]> git.vomp.tv Git - vompclient.git/blob - command.cc
Fixes (1) for new frame number navigation
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "command.h"
22 #ifdef WIN32
23 #include "remotewin.h"
24 #endif
25
26 Command* Command::instance = NULL;
27
28 Command::Command()
29 {
30   if (instance) return;
31   instance = this;
32   initted = 0;
33   isStandby = 0;
34   firstBoot = 1;
35   connLost = NULL;
36 }
37
38 Command::~Command()
39 {
40   instance = NULL;
41 }
42
43 Command* Command::getInstance()
44 {
45   return instance;
46 }
47
48 int Command::init()
49 {
50   if (initted) return 0;
51   initted = 1;
52
53   logger = Log::getInstance();
54   viewman = ViewMan::getInstance();
55   remote = Remote::getInstance();
56
57   if (!logger || !viewman || !remote)
58   {
59     initted = 0;
60     return 0;
61   }
62 #ifndef WIN32
63   pthread_mutex_init(&masterLock, NULL);
64 #else
65   masterLock=CreateMutex(NULL,FALSE,NULL);
66 #endif
67
68   return 1;
69 }
70
71 int Command::shutdown()
72 {
73   if (!initted) return 0;
74   initted = 0;
75   return 1;
76 }
77
78 void Command::stop()
79 {
80 //  VDR::getInstance()->cancelFindingServer();
81   irun = 0;
82 }
83
84 void Command::doWallpaper()
85 {
86   Video* video = Video::getInstance();
87
88   // Blue background
89   View* v = new View();
90   v->create(video->getScreenWidth(), video->getScreenHeight());
91   v->setBackgroundColour(Colour::VIDEOBLUE);
92   v->draw();
93   viewman->add(v);
94   viewman->updateView(v);
95   viewman->removeView(v);
96
97   // Wallpaper
98   wallpaper = new VWallpaper();
99   if (video->getFormat() == Video::PAL)
100   {
101     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
102     wallpaper->init("/wallpaperPAL.jpg");
103   }
104   else
105   {
106     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
107     wallpaper->init("/wallpaperNTSC.jpg");
108   }
109   wallpaper->draw();
110   viewman->add(wallpaper);
111   viewman->updateView(wallpaper);
112 }
113
114 void Command::run()
115 {
116   if (!initted) return;
117   irun = 1;
118 #ifndef WIN32
119   mainPid = getpid();
120 #endif
121
122   // just in case
123   Video::getInstance()->signalOn();
124   Led::getInstance()->on();
125
126   doWallpaper();
127
128   // End of startup. Lock the mutex and put the first view up
129 #ifndef WIN32
130   pthread_mutex_lock(&masterLock);
131 #else
132   WaitForSingleObject(masterLock, INFINITE );
133 #endif
134   VConnect* vconnect = new VConnect();
135   viewman->add(vconnect);
136   vconnect->run();
137
138   UCHAR button = 0;
139   while(irun)
140   {
141     // unlock and wait
142 #ifndef WIN32
143     pthread_mutex_unlock(&masterLock);
144 #else
145     ReleaseMutex(masterLock);
146 #endif
147     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
148     // something happened, lock and process
149
150 #ifndef WIN32
151     pthread_mutex_lock(&masterLock);
152 #else
153     WaitForSingleObject(masterLock, INFINITE );
154 #endif
155
156     if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
157
158     if (button != Remote::NA_SIGNAL) handleCommand(button);
159     processMessageQueue();
160   }
161
162 #ifndef WIN32
163   pthread_mutex_unlock(&masterLock);
164 #else
165   ReleaseMutex(masterLock);
166 #endif
167 }
168
169 void Command::postMessage(Message* m)
170 {
171   // This is locked here in case the main loop is not waiting for an event, but is processing one
172   // it could be killed but then not react to it because the signal wouldn't cause
173   // remote->getButtonPress to break
174   // locking the mutex ensures that the master thread is waiting on getButtonPress
175
176
177 #ifndef WIN32
178   pthread_mutex_lock(&masterLock);
179 #else
180   WaitForSingleObject(masterLock, INFINITE );
181 #endif
182   MessageQueue::postMessage(m);
183
184 #ifndef WIN32
185   kill(mainPid, SIGURG);
186   pthread_mutex_unlock(&masterLock);
187 #else
188   ((RemoteWin*)Remote::getInstance())->Signal();
189   ReleaseMutex(masterLock);
190 #endif
191 }
192
193 void Command::postMessageNoLock(Message* m)
194 {
195   // As above but use this one if this message is being posted because of a button press
196   // the mutex is already locked, locking around postMessage is not needed as the
197   // queue is guaranteed to be run when the button has been processed
198   MessageQueue::postMessage(m);
199 }
200
201 bool Command::postMessageIfNotBusy(Message* m)
202 {
203   // This is for the timers module
204   // If the masterlock is locked then the timers module wants to
205   // cancel delivery
206 #ifndef WIN32
207   if (pthread_mutex_trylock(&masterLock) != EBUSY)
208   {
209     MessageQueue::postMessage(m);
210     kill(mainPid, SIGURG);
211     pthread_mutex_unlock(&masterLock);
212     return true;
213   }
214   else
215   {
216     return false;
217   }
218 #else
219   switch (WaitForSingleObject(masterLock, 0 ))
220   { //FIXME this is not "if not busy" check
221     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
222     // case WAIT_ABANDONED:
223     MessageQueue::postMessage(m);
224     ((RemoteWin*)Remote::getInstance())->Signal();
225     ReleaseMutex(masterLock);
226     return true;
227
228     case WAIT_ABANDONED: return false;
229     case WAIT_TIMEOUT: return false;
230   }
231     return false;
232 #endif
233 }
234
235 void Command::processMessage(Message* m)
236 {
237   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
238
239   switch(m->message)
240   {
241     case Message::STANDBY:
242     {
243       doStandby();
244       break;
245     }
246     case Message::STOP_PLAYBACK:
247     {
248       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
249       break;
250     }
251     case Message::STREAM_END:
252     {
253       VVideoLive::getInstance()->streamEnd();
254       break;
255     }
256     case Message::VDR_CONNECTED:
257     {
258       doJustConnected((VConnect*)m->from);
259       break;
260     }
261     case Message::TIMER:
262     {
263       // FIXME - go to one message queue only - then instead of having
264       // objects deriving from messagequeues, make them derive from
265       // messagereceiver - then one messagequeue can deliver any message to anywhere
266
267       // deliver timer
268
269       ((TimerReceiver*)m->to)->timercall(m->parameter);
270       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
271                                       // run viewman message queue here. FIXME improve this!
272       break;
273     }
274     case Message::SCREENSHOT:
275     {
276       Osd::getInstance()->screenShot("/out.jpg");
277       break;
278     }
279     case Message::CONNECTION_LOST:
280     {
281       doFromTheTop(true);
282       break;
283     }
284   }
285 }
286
287 void Command::handleCommand(int button)
288 {
289   if (isStandby && (button != Remote::POWER)) return;
290
291   if (!connLost && viewman->handleCommand(button)) return; // don't send to viewman if connLost
292
293   // command was not handled
294
295   switch(button)
296   {
297     case Remote::DF_LEFT:
298     case Remote::DF_RIGHT:
299     case Remote::VOLUMEUP:
300     case Remote::VOLUMEDOWN:
301     {
302       VVolume* v = new VVolume();
303       viewman->add(v);
304       v->handleCommand(button); // this will draw+show
305       return;
306     }
307     case Remote::MUTE:
308     {
309       VMute* v = new VMute();
310       v->draw();
311       viewman->add(v);
312       viewman->updateView(v);
313       return;
314     }
315     case Remote::POWER:
316     {
317       doStandby();
318       return;
319     }
320     case Remote::OK:
321     {
322       if (!connLost) return; // if connLost, handle Remote::OK
323       doFromTheTop(false);
324       return;
325     }
326   }
327 }
328
329 void Command::sig1()
330 {
331 #ifdef DEV
332   Message* m = new Message(); // break into master mutex
333   m->message = Message::SCREENSHOT;
334   m->to = this;
335   postMessage(m);
336 #endif
337 }
338
339 void Command::doStandby()
340 {
341   if (isStandby)
342   {
343     Video::getInstance()->signalOn();
344     Led::getInstance()->on();
345     isStandby = 0;
346
347
348     VConnect* vconnect = new VConnect();
349     viewman->add(vconnect);
350     vconnect->run();
351   }
352   else
353   {
354     viewman->removeAll();
355     Video::getInstance()->signalOff();
356     viewman->updateView(wallpaper);
357
358     VDR::getInstance()->configSave("General", "Last Power State", "Off");
359     VDR::getInstance()->disconnect();
360     Led::getInstance()->off();
361     isStandby = 1;
362 #ifdef WIN32
363     stop(); //different behavoiur on windows, we exit
364 #endif
365   }
366 }
367
368 void Command::doFromTheTop(bool which)
369 {
370   if (which)
371   {
372     connLost = new VInfo();
373     connLost->create(360, 200);
374     if (Video::getInstance()->getFormat() == Video::PAL)
375       connLost->setScreenPos(190, 170);
376     else
377       connLost->setScreenPos(180, 120);
378     connLost->setOneLiner(tr("Connection lost"));
379     connLost->setDropThrough();
380     connLost->setBorderOn(1);
381     connLost->setTitleBarColour(Colour::DANGER);
382     connLost->okButton();
383     connLost->draw();
384     viewman->add(connLost);
385     viewman->updateView(connLost);
386     remote->clearBuffer();
387   }
388   else
389   {
390     VDR::getInstance()->disconnect();
391     viewman->removeAll();
392     viewman->updateView(wallpaper);
393     connLost = NULL;
394     VConnect* vconnect = new VConnect();
395     viewman->add(vconnect);
396     vconnect->run();
397   }
398 }
399
400 void Command::doReboot()
401 {
402   VDR::getInstance()->disconnect();
403   // just kill it...
404   logger->log("Command", Log::NOTICE, "Reboot");
405 #ifndef WIN32
406   reboot(LINUX_REBOOT_CMD_RESTART);
407 #endif //Would we support this on windows?
408 }
409
410 void Command::connectionLost()
411 {
412   Message* m = new Message(); // break into master mutex
413   m->message = Message::CONNECTION_LOST;
414   m->to = this;
415   postMessageNoLock(m);
416 }
417
418 void Command::doJustConnected(VConnect* vconnect)
419 {
420   I18n::initialize();
421   Video* video = Video::getInstance();
422   viewman->removeView(vconnect);
423
424   VInfo* vi = new VInfo();
425   vi->create(400, 200);
426   if (video->getFormat() == Video::PAL)
427     vi->setScreenPos(170, 200);
428   else
429     vi->setScreenPos(160, 150);
430
431   vi->setOneLiner(tr("Connected, loading config"));
432   vi->draw();
433   viewman->add(vi);
434   viewman->updateView(vi);
435
436   VDR* vdr = VDR::getInstance();
437   char* config;
438
439   // See if config says to override video format (PAL/NTSC)
440   config = vdr->configLoad("General", "Override Video Format");
441   if (config)
442   {
443     logger->log("Command", Log::DEBUG, "Override Video Format is present");
444
445     if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
446         || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
447     {
448       // Oh sheesh, need to switch format. Bye bye TV...
449
450       // Take everything down
451       viewman->removeAll();
452       viewman->removeView(wallpaper);
453       Osd* osd = Osd::getInstance();
454       osd->shutdown();
455       video->shutdown();
456
457       // Get video and osd back up with the new mode
458       if (!strcmp(config, "PAL"))
459       {
460         logger->log("Command", Log::DEBUG, "Switching to PAL");
461         video->init(Video::PAL);
462       }
463       else if (!strcmp(config, "NTSC"))
464       {
465         logger->log("Command", Log::DEBUG, "Switching to NTSC");
466         video->init(Video::NTSC);
467       }
468       osd->init((char*)("/dev/stbgfx"));
469
470       // Put the wallpaper back
471       doWallpaper();
472
473       // Re add the vinfo
474       vi = new VInfo();
475       vi->create(400, 200);
476       if (video->getFormat() == Video::PAL)
477         vi->setScreenPos(170, 200);
478       else
479         vi->setScreenPos(160, 150);
480
481       vi->setOneLiner(tr("Connected, loading config"));
482       vi->draw();
483       viewman->add(vi);
484       viewman->updateView(vi);
485     }
486     else
487     {
488       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
489     }
490   }
491   else
492   {
493     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
494   }
495
496   // Power off if first boot and config says so
497   if (firstBoot)
498   {
499     firstBoot = 0;
500
501     logger->log("Command", Log::DEBUG, "Load power after boot");
502
503     config = vdr->configLoad("General", "Power After Boot");
504
505     if (config)
506     {
507       if (!STRCASECMP(config, "On"))
508       {
509         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
510       }
511       else if (!STRCASECMP(config, "Off"))
512       {
513         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
514         doStandby();
515         delete[] config;
516         return; // quit here
517       }
518       else if (!STRCASECMP(config, "Last state"))
519       {
520         char* lastPowerState = vdr->configLoad("General", "Last Power State");
521         if (lastPowerState)
522         {
523           if (!STRCASECMP(lastPowerState, "On"))
524           {
525             logger->log("Command", Log::INFO, "Config says Last Power State = On");
526           }
527           else if (!STRCASECMP(lastPowerState, "Off"))
528           {
529             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
530             doStandby();
531             delete[] config;
532             return; // quit here
533           }
534           else
535           {
536             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
537           }
538         }
539         else
540         {
541           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
542         }
543       }
544       else
545       {
546         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
547       }
548       delete[] config;
549     }
550     else
551     {
552       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
553     }
554   }
555
556
557   // Go S-Video if config says so
558
559   config = vdr->configLoad("TV", "Connection");
560
561   if (config)
562   {
563     if (!STRCASECMP(config, "S-Video"))
564     {
565       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
566       video->setConnection(Video::SVIDEO);
567     }
568     else
569     {
570       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
571       video->setConnection(Video::COMPOSITERGB);
572     }
573     delete[] config;
574   }
575   else
576   {
577     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
578   }
579
580   // Set remote type
581
582   config = vdr->configLoad("General", "Remote type");
583
584   if (config)
585   {
586     if (!STRCASECMP(config, "New"))
587     {
588       logger->log("Command", Log::INFO, "Switching to New remote type");
589       remote->setRemoteType(Remote::NEWREMOTE);
590     }
591     else
592     {
593       logger->log("Command", Log::INFO, "Switching to Old remote type");
594       remote->setRemoteType(Remote::OLDREMOTE);
595     }
596     delete[] config;
597   }
598   else
599   {
600     logger->log("Command", Log::INFO, "Config General/Remote type not found");
601     remote->setRemoteType(Remote::OLDREMOTE);
602   }
603
604   // Get TV aspect ratio
605
606   config = vdr->configLoad("TV", "Aspect");
607   if (config)
608   {
609     if (!STRCASECMP(config, "16:9"))
610     {
611       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
612       video->setTVsize(Video::ASPECT16X9);
613     }
614     else
615     {
616       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
617       video->setTVsize(Video::ASPECT4X3);
618     }
619     delete[] config;
620   }
621   else
622   {
623     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
624     video->setTVsize(Video::ASPECT4X3);
625   }
626
627   config = vdr->configLoad("TV", "Widemode");
628   if (config)
629   {
630     if (!STRCASECMP(config, "Letterbox"))
631     {
632       logger->log("Command", Log::INFO, "Setting letterbox mode");
633       video->setMode(Video::LETTERBOX);
634     }
635     else
636     {
637       logger->log("Command", Log::INFO, "Setting chop-sides mode");
638       video->setMode(Video::NORMAL);
639     }
640     delete[] config;
641   }
642   else
643   {
644     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
645     video->setMode(Video::NORMAL);
646   }
647
648   config = vdr->configLoad("Advanced", "TCP receive window");
649   if (config)
650   {
651     size_t newTCPsize = atoi(config);
652     delete[] config;
653
654     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
655     vdr->setReceiveWindow(newTCPsize);
656   }
657   else
658   {
659     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
660     vdr->setReceiveWindow(2048); // Default
661   }
662
663
664   // config done
665
666   // Save power state = on
667
668   vdr->configSave("General", "Last Power State", "On");
669
670   // Make sure connection didn't die
671   if (!vdr->isConnected())
672   {
673     Command::getInstance()->connectionLost();
674   }
675   else
676   {
677     viewman->removeView(vi);
678
679     VWelcome* vw = new VWelcome();
680     vw->draw();
681     viewman->add(vw);
682     viewman->updateView(vw);
683
684     // Enter pre-keys here
685 //    handleCommand(Remote::THREE);
686 //    handleCommand(Remote::SKIPFORWARD);
687 //    handleCommand(Remote::OK);
688 //    handleCommand(Remote::PLAY);
689 //    handleCommand(Remote::OK);
690 //    handleCommand(Remote::DOWN);
691 //    handleCommand(Remote::DOWN);
692 //    handleCommand(Remote::DOWN);
693 //    handleCommand(Remote::OK);
694   }
695 }