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