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