2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
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.
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.
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.
22 #include <linux/errno.h>
28 #include "remotewin.h"
32 #include "remoteandroid.h"
41 #include "vserverselect.h"
47 #include "timerreceiver.h"
57 #include "vsleeptimer.h"
60 Command* Command::instance = NULL;
79 Command* Command::getInstance()
84 int Command::init(bool tcrashed, char* tServer)
86 if (initted) return 0;
91 logger = Log::getInstance();
92 boxstack = BoxStack::getInstance();
93 remote = Remote::getInstance();
95 remote->InitHWCListwithDefaults();
97 if (!logger || !boxstack || !remote)
102 #ifdef GRADIENT_DRAWING
103 SkinFactory::InitEnhancedSkin();
105 SkinFactory::InitDefaultSkin();
109 pthread_mutex_init(&masterLock, NULL);
111 masterLock=CreateMutex(NULL,FALSE,NULL);
117 int Command::shutdown()
119 if (!initted) return 0;
126 // VDR::getInstance()->cancelFindingServer();
127 logger->log("Command", Log::NOTICE, "Command stop1...");
130 logger->log("Command", Log::NOTICE, "Command stop2...");
134 void Command::doWallpaper()
136 Video* video = Video::getInstance();
139 Boxx* bbg = new Boxx();
140 bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
142 bbg->fillColour(DrawStyle::VIDEOBLUE);
144 boxstack->update(bbg);
145 boxstack->remove(bbg);
148 WJpeg* wallpaperj = new WJpegTYPE();
149 wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
150 wallpaperj->createBuffer();
152 if (video->getFormat() == Video::PAL)
154 logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
156 wallpaperj->init("/wallpaperPAL.jpg");
158 wallpaperj->init("wallpaperPAL.jpg");
163 logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
164 wallpaperj->init("/wallpaperNTSC.jpg");
168 boxstack->add(wallpaperj);
169 boxstack->update(wallpaperj);
171 wallpaper = wallpaperj;
176 if (!initted) return;
183 Video::getInstance()->signalOn();
184 Led::getInstance()->on();
188 // End of startup. Lock the mutex and put the first view up
189 // logger->log("Command", Log::DEBUG, "WANT LOCK");
191 pthread_mutex_lock(&masterLock);
193 WaitForSingleObject(masterLock, INFINITE );
195 //logger->log("Command", Log::DEBUG, "LOCKED");
203 VConnect* vconnect = new VConnect(server);
204 boxstack->add(vconnect);
208 // Start method 2 of getting commands in...
215 //logger->log("Command", Log::DEBUG, "UNLOCK");
217 pthread_mutex_unlock(&masterLock);
219 ReleaseMutex(masterLock);
222 button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit
223 // something happened, lock and process
225 // logger->log("Command", Log::DEBUG, "WANT LOCK");
227 pthread_mutex_lock(&masterLock);
229 WaitForSingleObject(masterLock, INFINITE );
231 // logger->log("Command", Log::DEBUG, "LOCK");
233 if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
235 if (button != Remote::NA_SIGNAL) handleCommand(button);
236 processMessageQueue();
240 //logger->log("Command", Log::DEBUG, "UNLOCK");
242 pthread_mutex_unlock(&masterLock);
244 ReleaseMutex(masterLock);
250 void Command::postMessage(Message* m)
252 // This is locked here in case the main loop is not waiting for an event, but is processing one
253 // it could be killed but then not react to it because the signal wouldn't cause
254 // remote->getButtonPress to break
255 // locking the mutex ensures that the master thread is waiting on getButtonPress
258 //logger->log("Command", Log::DEBUG, "WANT LOCK");
260 pthread_mutex_lock(&masterLock);
262 WaitForSingleObject(masterLock, INFINITE );
264 //logger->log("Command", Log::DEBUG, "LOCK");
265 MessageQueue::postMessage(m);
269 kill(mainPid, SIGURG);
271 ((RemoteAndroid*)Remote::getInstance())->Signal();
273 pthread_mutex_unlock(&masterLock);
275 ((RemoteWin*)Remote::getInstance())->Signal();
276 ReleaseMutex(masterLock);
278 //logger->log("Command", Log::DEBUG, "UNLOCK");
281 void Command::postMessageNoLock(Message* m)
283 // As above but use this one if this message is being posted because of a button press
284 // the mutex is already locked, locking around postMessage is not needed as the
285 // queue is guaranteed to be run when the button has been processed
286 MessageQueue::postMessage(m);
289 bool Command::postMessageIfNotBusy(Message* m)
291 // Used for Windows mouse events
293 //logger->log("Command", Log::DEBUG, "TRY LOCK");
295 if (pthread_mutex_trylock(&masterLock) != EBUSY)
297 //logger->log("Command", Log::DEBUG, "LOCK");
298 MessageQueue::postMessage(m);
300 kill(mainPid, SIGURG);
302 ((RemoteAndroid*)Remote::getInstance())->Signal();
304 pthread_mutex_unlock(&masterLock);
305 //logger->log("Command", Log::DEBUG, "UNLOCK");
313 switch (WaitForSingleObject(masterLock, 0 ))
314 { //FIXME this is not "if not busy" check
315 case WAIT_OBJECT_0: //but with proper argument 0 this did not work
316 // case WAIT_ABANDONED:
317 MessageQueue::postMessage(m);
318 ((RemoteWin*)Remote::getInstance())->Signal();
319 ReleaseMutex(masterLock);
322 case WAIT_ABANDONED: return false;
323 case WAIT_TIMEOUT: return false;
329 void Command::postMessageFromOuterSpace(Message* m)
332 Yet another way of getting messages into Command. This one is for events that
333 are not standard button presses (or UDP generated buttons). It is also not for
334 events that are generated as a result of other events (events that can safely
335 call postMessageNoLock and be guaranteed that the message will be processed
336 because it is known that the queue is currently being processed).
337 This is for events that come from outer space and can occur when the master
338 mutex is locked or not, they need to be queued and executed but it doesn't
340 Actually so far it is for events caused by the video stream - aspect ratio
341 changes. These can occur when the master mutex is locked and so postMessage
342 doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
343 locked at the time then the message could be sat around a while before
345 The whole message system was at first supposed to prevent the problem of
346 calling a function on an object that had just been deleted, by ordering
347 messages such that all calls are done before object deletion. However,
348 because of the new centralised messaging system and the fact that BoxStack
349 locates the destination object before calling it, the messaging system now
350 allows the kind of sloppy calls it was supposed to stop. Weird huh. This
351 is mentioned here because the video stream might generate an event just as
352 the user hits stop. The mutex is locked, and by the time the message
353 is examined the vvideorec/live has been deleted. This doesn't matter because
354 boxstack will drop the message if it can't find the matching object to
356 Finally, all this is fine and dandy, except that I'm not 100% sure that
357 this sloppy postMessage and hope a queued signal will force it to be processed
358 thingy will actually work. Hmmm.
359 Lastly <g>, I will consider making the naming system a little more sane
363 logger->log("Command", Log::DEBUG, "PMFOS called");
364 MessageQueue::postMessage(m);
368 kill(mainPid, SIGURG);
370 ((RemoteAndroid*)Remote::getInstance())->Signal();
373 ((RemoteWin*)Remote::getInstance())->Signal();
377 void Command::processMessage(Message* m)
379 // FIXME - a slight modification - how if messagereceivers were to register
380 // themselves as receivers to avoid the calling-a-deleted-object problem
381 // then only deliver/register/unregister would have to be protected
383 logger->log("Command", Log::DEBUG, "processing message %i", m->message);
391 case Message::STOP_PLAYBACK:
393 handleCommand(Remote::STOP); // an odd way of doing it, but so simple
396 // Also connection_lost comes from player - anywhere else?
400 case Message::VDR_CONNECTED:
402 doJustConnected((VConnect*)m->from);
405 case Message::SCREENSHOT:
407 Osd::getInstance()->screenShot("/out.jpg");
410 case Message::CONNECTION_LOST:
415 case Message::UDP_BUTTON:
417 handleCommand(m->parameter);
420 case Message::CHANGE_LANGUAGE:
422 boxstack->removeAll();
423 boxstack->update(wallpaper);
425 if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
426 VWelcome* vw = new VWelcome();
429 boxstack->update(vw);
432 case Message::LAST_VIEW_CLOSE:
434 // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
441 // VWelcome* vw = new VWelcome();
443 // boxstack->add(vw);
444 // boxstack->update(vw);
448 case Message::NEW_PICTURE:
450 Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE");
451 OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
453 osdv->informPicture(m->tag,m->parameter);
457 case Message::NEW_PICTURE_STATIC:
459 OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
461 osdv->informPicture(((long long)m->tag)<<32LL,m->parameter);
471 Instead of sending through the boxstack, implement a more generic MessageReceiver interface
472 and have potential receivers register with something
473 When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
474 This could all be done using the existing big command mutex to keep it simple
477 logger->log("Command", Log::DEBUG, "Sending message to boxstack");
478 boxstack->processMessage(m);
482 void Command::handleCommand(int button)
484 if (isStandby && (button != Remote::POWER)
485 && (button != Remote::POWERON) && (button != Remote::POWEROFF)) return;
486 if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
488 // command was not handled
492 case Remote::DF_LEFT:
493 case Remote::DF_RIGHT:
494 case Remote::VOLUMEUP:
495 case Remote::VOLUMEDOWN:
497 if (remote->handlesVolume()) {
498 if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)
499 remote->volumeDown();
500 else remote->volumeUp();
502 VVolume* v = new VVolume();
504 v->handleCommand(button); // this will draw+show
510 if (remote->handlesVolume()) {
511 remote->volumeMute();
513 VMute* v = new VMute();
525 case Remote::POWERON:
530 case Remote::POWEROFF:
538 if (!connLost) return; // if connLost, handle Remote::OK
544 VSleeptimer* sleep = new VSleeptimer();
545 boxstack->add(sleep);
546 sleep->handleCommand(button); // this will draw+show
555 Message* m = new Message(); // break into master mutex
556 m->message = Message::SCREENSHOT;
562 void Command::doStandby()
575 void Command::doPowerOn()
579 Video::getInstance()->signalOn();
580 Led::getInstance()->on();
581 Remote::getInstance()->changePowerState(true);
585 VConnect* vconnect = new VConnect(server);
586 boxstack->add(vconnect);
591 void Command::doPowerOff()
595 VDR::getInstance()->shutdownVDR();
596 boxstack->removeAll();
597 Video::getInstance()->signalOff();
598 boxstack->update(wallpaper);
600 VDR::getInstance()->configSave("General", "Last Power State", "Off");
601 logger->unsetExternLogger();
602 VDR::getInstance()->disconnect();
603 Led::getInstance()->off();
604 Remote::getInstance()->changePowerState(false);
606 Sleeptimer::getInstance()->shutdown();
608 stop(); //different behavoiur on windows, we exit
613 void Command::doFromTheTop(bool which)
615 if (isStandby) return;
620 logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
624 logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
625 connLost = new VInfo();
626 connLost->setSize(360, 200);
627 connLost->createBuffer();
628 if (Video::getInstance()->getFormat() == Video::PAL)
629 connLost->setPosition(190, 170);
631 connLost->setPosition(180, 120);
632 connLost->setOneLiner(tr("Connection lost"));
633 connLost->setDropThrough();
634 connLost->setBorderOn(1);
635 connLost->setTitleBarColour(DrawStyle::DANGER);
636 connLost->okButton();
638 boxstack->add(connLost);
639 boxstack->update(connLost);
640 remote->clearBuffer();
644 logger->unsetExternLogger();
645 VDR::getInstance()->disconnect();
646 boxstack->removeAll();
647 boxstack->update(wallpaper);
651 remote->clearBuffer();
653 // at this point, everything should be reset to first-go
655 VConnect* vconnect = new VConnect(server);
656 boxstack->add(vconnect);
661 void Command::doReboot()
664 logger->unsetExternLogger();
665 VDR::getInstance()->disconnect();
667 logger->log("Command", Log::NOTICE, "Reboot");
669 #ifndef VOMP_HAS_EXIT
670 // some plattforms, want a proper deinitialisation of their hardware before reboot
671 Osd::getInstance()->shutdown();
672 Audio::getInstance()->shutdown();
673 Video::getInstance()->shutdown();
674 Remote::getInstance()->shutdown();
676 reboot(LINUX_REBOOT_CMD_RESTART);
677 // if reboot is not allowed -> stop
689 #endif //Would we support this on windows?
692 void Command::connectionLost()
694 logger->unsetExternLogger();
695 Message* m = new Message(); // break into master mutex
696 m->message = Message::CONNECTION_LOST;
698 postMessageFromOuterSpace(m);
701 void Command::buildCrashedBox()
703 VInfo* crash = new VInfo();
704 crash->setSize(360, 250);
705 crash->createBuffer();
706 if (Video::getInstance()->getFormat() == Video::PAL)
707 crash->setPosition(190, 146);
709 crash->setPosition(180, 96);
710 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.");
711 crash->setBorderOn(1);
712 crash->setTitleBarColour(DrawStyle::DANGER);
714 crash->setExitable();
716 boxstack->add(crash);
717 boxstack->update(crash);
720 void Command::doJustConnected(VConnect* vconnect)
723 if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
724 logger->log("Command", Log::INFO, "Entering doJustConnected");
726 Video* video = Video::getInstance();
727 Audio* audio = Audio::getInstance();
728 boxstack->remove(vconnect);
730 VInfo* vi = new VInfo();
731 vi->setSize(400, 200);
733 if (video->getFormat() == Video::PAL)
734 vi->setPosition(170, 200);
736 vi->setPosition(160, 150);
737 vi->setOneLiner(tr("Connected, loading config"));
740 boxstack->update(vi);
742 VDR* vdr = VDR::getInstance();
745 // See if we're supposed to do network logging
746 config = vdr->configLoad("Advanced", "Network logging");
747 if (config && !STRCASECMP(config, "On"))
749 logger->log("Command", Log::INFO, "Turning on network logging");
750 logger->setExternLogger(vdr);
754 logger->unsetExternLogger();
755 logger->log("Command", Log::INFO, "Turned off network logging");
757 if (config) delete[] config;
759 // See if config says to override video format (PAL/NTSC)
760 config = vdr->configLoad("General", "Override Video Format");
763 logger->log("Command", Log::DEBUG, "Override Video Format is present");
765 if ( (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
766 || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
767 || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
768 || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
771 // Oh sheesh, need to switch format. Bye bye TV...
773 // Take everything down
774 boxstack->removeAll();
775 boxstack->remove(wallpaper);
776 Osd* osd = Osd::getInstance();
782 remote->shutdown(); // need on raspberry shut not do any harm, hopefully
783 remote->init(RemoteStartDev);
785 // Get video and osd back up with the new mode
786 if (!strcmp(config, "PAL"))
788 logger->log("Command", Log::DEBUG, "Switching to PAL");
789 video->init(Video::PAL);
791 else if (!strcmp(config, "NTSC"))
793 logger->log("Command", Log::DEBUG, "Switching to NTSC");
794 video->init(Video::NTSC);
795 } else if (!strcmp(config, "PAL_M"))
797 logger->log("Command", Log::DEBUG, "Switching to PAL_M");
798 video->init(Video::PAL_M);
799 } else if (!strcmp(config, "NTSC_J"))
801 logger->log("Command", Log::DEBUG, "Switching to NTSC_J");
802 video->init(Video::NTSC_J);
805 //we do not init twice
806 osd->init((char*)("/dev/stbgfx"));
809 // Put the wallpaper back
814 vi->setSize(400, 200);
816 if (video->getFormat() == Video::PAL)
817 vi->setPosition(170, 200);
819 vi->setPosition(160, 150);
821 vi->setOneLiner(tr("Connected, loading config"));
824 boxstack->update(vi);
828 logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
833 logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
836 // Power off if first boot and config says so
841 logger->log("Command", Log::DEBUG, "Load power after boot");
843 config = vdr->configLoad("General", "Power After Boot");
847 if (!STRCASECMP(config, "On"))
849 logger->log("Command", Log::INFO, "Config says Power After Boot = On");
851 else if (!STRCASECMP(config, "Off"))
853 logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
858 else if (!STRCASECMP(config, "Last state"))
860 char* lastPowerState = vdr->configLoad("General", "Last Power State");
863 if (!STRCASECMP(lastPowerState, "On"))
865 logger->log("Command", Log::INFO, "Config says Last Power State = On");
867 else if (!STRCASECMP(lastPowerState, "Off"))
869 logger->log("Command", Log::INFO, "Config says Last Power State = Off");
876 logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
881 logger->log("Command", Log::INFO, "Config General/Last Power State not found");
886 logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
892 logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
897 // Go S-Video if config says so
899 config = vdr->configLoad("TV", "Connection");
903 if (!STRCASECMP(config, "S-Video"))
905 logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
906 video->setConnection(Video::SVIDEO);
907 } else if (!STRCASECMP(config, "HDMI"))
909 logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);
910 video->setConnection(Video::HDMI);
911 } else if (!STRCASECMP(config, "HDMI3D"))
913 logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);
914 video->setConnection(Video::HDMI3D);
918 logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
919 video->setConnection(Video::COMPOSITERGB);
925 logger->log("Command", Log::INFO, "Config TV/S-Video not found");
928 // Set to shutdown VDR if config says
930 config = vdr->configLoad("General", "VDR shutdown");
933 if (!STRCASECMP(config, "On"))
935 logger->log("Command", Log::INFO, "Shutdown VDR when shutting down vomp");
936 vdr->setVDRShutdown(true);
938 else if (!STRCASECMP(config, "Off"))
940 logger->log("Command", Log::INFO, "Shutdown only vomp");
941 vdr->setVDRShutdown(false);
946 logger->log("Command", Log::INFO, "Default shutdown only vomp");
947 vdr->setVDRShutdown(false); // Default
952 config = vdr->configLoad("General", "Remote type");
956 if (!STRCASECMP(config, "New"))
958 logger->log("Command", Log::INFO, "Switching to New remote type");
959 remote->setRemoteType(Remote::NEWREMOTE);
963 logger->log("Command", Log::INFO, "Switching to Old remote type");
964 remote->setRemoteType(Remote::OLDREMOTE);
970 logger->log("Command", Log::INFO, "Config General/Remote type not found");
971 remote->setRemoteType(Remote::OLDREMOTE);
976 // Get TV aspect ratio
978 config = vdr->configLoad("TV", "Aspect");
981 if (!STRCASECMP(config, "16:9"))
983 logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
984 video->setTVsize(Video::ASPECT16X9);
988 logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
989 video->setTVsize(Video::ASPECT4X3);
995 logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
996 video->setTVsize(Video::ASPECT4X3);
999 config = vdr->configLoad("TV", "Widemode");
1002 if (!STRCASECMP(config, "Letterbox"))
1004 logger->log("Command", Log::INFO, "Setting letterbox mode");
1005 video->setMode(Video::LETTERBOX);
1009 logger->log("Command", Log::INFO, "Setting chop-sides mode");
1010 video->setMode(Video::NORMAL);
1017 logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
1018 video->setMode(Video::LETTERBOX);
1020 logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
1021 video->setMode(Video::NORMAL);
1025 config = vdr->configLoad("Advanced", "TCP receive window");
1028 size_t newTCPsize = atoi(config);
1031 logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
1032 vdr->setReceiveWindow(newTCPsize);
1036 logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
1037 if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1040 config = vdr->configLoad("Advanced", "Font Name");
1043 Osd::getInstance()->setFont(config);
1044 logger->log("Command", Log::INFO, "Setting Font to %s", config);
1050 // Set recording list type
1053 #ifdef ADVANCED_MENUES
1054 config = vdr->configLoad("Advanced", "Menu type");
1058 if (!STRCASECMP(config, "Advanced"))
1060 logger->log("Command", Log::INFO, "Switching to Advanced menu");
1066 logger->log("Command", Log::INFO, "Switching to Classic menu");
1073 logger->log("Command", Log::INFO, "Config General/menu type not found");
1078 config = vdr->configLoad("Advanced", "Disable WOL");
1081 if (!STRCASECMP(config, "Yes"))
1083 logger->log("Command", Log::INFO, "Config says disable WOL");
1084 Wol::getInstance()->setEnabled(false);
1088 logger->log("Command", Log::INFO, "Config says enable WOL");
1089 Wol::getInstance()->setEnabled(true);
1096 logger->log("Command", Log::INFO, "By default, enable WOL");
1097 Wol::getInstance()->setEnabled(true);
1099 /* device dependend config */
1100 audio->loadOptionsfromServer(vdr);
1101 video->loadOptionsfromServer(vdr);
1102 remote->loadOptionsfromServer(vdr);
1104 video->executePendingModeChanges();
1107 // Save power state = on
1109 vdr->configSave("General", "Last Power State", "On");
1111 // Make sure connection didn't die
1112 if (!vdr->isConnected())
1114 Command::getInstance()->connectionLost();
1118 boxstack->remove(vi);
1120 VWelcome* vw = new VWelcome();
1123 boxstack->update(vw);
1125 // Enter pre-keys here
1126 // handleCommand(Remote::OK);
1127 // handleCommand(Remote::THREE);
1128 // handleCommand(Remote::SIX);
1129 // handleCommand(Remote::OK);
1130 // handleCommand(Remote::UP);
1131 // handleCommand(Remote::PLAY);
1132 // handleCommand(Remote::DOWN);
1133 // handleCommand(Remote::DOWN);
1134 // handleCommand(Remote::DOWN);
1135 // handleCommand(Remote::OK);
1136 // handleCommand(Remote::RED);