]> git.vomp.tv Git - vompclient.git/blob - vvideolivetv.cc
Windows AC3, live tv banner icon w/s
[vompclient.git] / vvideolivetv.cc
1 /*
2     Copyright 2007-2008 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 #include "vvideolivetv.h"
22
23 #include "vchannellist.h"
24 #include "video.h"
25 #include "playerlive.h"
26 #include "playerlivetv.h"
27 #include "playerliveradio.h"
28 #include "channel.h"
29 #include "boxstack.h"
30 #include "colour.h"
31 #include "osd.h"
32 #include "command.h"
33 #include "i18n.h"
34 #include "wtextbox.h"
35 #include "remote.h"
36 #include "vaudioselector.h"
37 #include "colour.h"
38 #include "event.h"
39 #include "timers.h"
40 #include "vepg.h"
41
42 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
43 {
44   vdr = VDR::getInstance();
45   boxstack = BoxStack::getInstance();
46   video = Video::getInstance();
47   
48   vas = NULL;
49
50   chanList = tchanList;
51   vchannelList = tvchannelList;
52   numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
53
54   currentChannelIndex = 0;
55   previousChannelIndex = 0;
56   osdChannelIndex = 0;
57   keying = 0;
58
59   playing = false;
60
61   // Convert channel number to index
62   UINT i;
63   for(i = 0; i < chanList->size(); i++)
64   {
65     if ((*chanList)[i]->number == (UINT)initialChannelNumber)
66     {
67       currentChannelIndex = i;
68       osdChannelIndex = i;
69       break;
70     }
71   }
72
73   eventList = NULL;
74
75   videoMode = video->getMode();
76   
77   if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
78   {
79     streamType = VDR::VIDEO;
80     player = new PlayerLiveTV(Command::getInstance(), this, chanList);
81   }
82   else
83   {
84     streamType = VDR::RADIO;
85     player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
86   }
87   player->init();
88
89   setSize(video->getScreenWidth(), video->getScreenHeight());
90   createBuffer();
91   Colour transparent(0, 0, 0, 0);
92   setBackgroundColour(transparent);
93
94   dowss = false;
95   char* optionWSS = vdr->configLoad("General", "WSS");
96   if (optionWSS)
97   {
98     if (strstr(optionWSS, "Yes")) dowss = true;
99     delete[] optionWSS;
100   }
101   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
102
103   if (dowss)
104   {
105     wss.setFormat(video->getFormat());
106     wss.setWide(true);
107     add(&wss);
108     
109     wssRegion.x = 0;
110     wssRegion.y = 6;
111     wssRegion.w = video->getScreenWidth();
112     wssRegion.h = 2;
113   }
114   
115   Colour osdBack = Colour(0, 0, 0, 128);
116   
117   osd.setBackgroundColour(osdBack);
118   osd.setPosition(0, video->getScreenHeight() - 150);
119   osd.setSize(video->getScreenWidth(), 150);
120   osd.setVisible(false);
121   add(&osd);
122   
123   clock.setBackgroundColour(osdBack);
124   clock.setPosition(osd.getWidth() - 100, 4);
125   clock.setSize(90, 30);
126   osd.add(&clock);
127
128   osdChanNum.setBackgroundColour(osdBack);
129   osdChanNum.setPosition(40, 4);
130   osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
131   osd.add(&osdChanNum);  
132
133   osdChanName.setBackgroundColour(osdBack);
134   osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
135   osdChanName.setSize(300, 30);
136   osd.add(&osdChanName);
137   
138   boxRed.setBackgroundColour(Colour::RED);
139   boxRed.setPosition(50, 104);
140   boxRed.setSize(18, 16);
141   osd.add(&boxRed);
142
143   boxGreen.setBackgroundColour(Colour::GREEN);
144   boxGreen.setPosition(220, 104);
145   boxGreen.setSize(18, 16);
146   osd.add(&boxGreen);
147
148   boxYellow.setBackgroundColour(Colour::YELLOW);
149   boxYellow.setPosition(390, 104);
150   boxYellow.setSize(18, 16);
151   osd.add(&boxYellow);
152
153   boxBlue.setBackgroundColour(Colour::BLUE);
154   boxBlue.setPosition(560, 104);
155   boxBlue.setSize(18, 16);
156   osd.add(&boxBlue);  
157   
158   textRed.setBackgroundColour(osdBack);
159   textRed.setPosition(boxRed.getX()+18, 98);
160   textRed.setSize(120, 30);
161   textRed.setText("Summary");
162   osd.add(&textRed);  
163     
164   if (streamType == VDR::VIDEO)
165   {
166     textGreen.setBackgroundColour(osdBack);
167     textGreen.setPosition(boxGreen.getX()+18, 98);
168     textGreen.setSize(120, 30);
169     textGreen.setText("Audio");
170     osd.add(&textGreen);  
171   }
172     
173   textYellow.setBackgroundColour(osdBack);
174   textYellow.setPosition(boxYellow.getX()+18, 98);
175   textYellow.setSize(120, 30);
176   textYellow.setText("");
177   osd.add(&textYellow);  
178     
179   textBlue.setBackgroundColour(osdBack);
180   textBlue.setPosition(boxBlue.getX()+18, 98);
181   textBlue.setSize(90, 30);
182   textBlue.setText("EPG");
183   osd.add(&textBlue);  
184     
185   sl.setBackgroundColour(osdBack);
186   sl.setPosition(70, 36);
187   sl.setSize(500, 58);
188   sl.setNoLoop();
189   osd.add(&sl);
190   
191   // Summary Box
192   summary.setBackgroundColour(osdBack);
193   summary.setPosition(0, video->getScreenHeight() - 300);
194   summary.setSize(video->getScreenWidth(), 150);
195   summary.setVisible(false);
196   add(&summary);  
197   
198   textSummary.setBackgroundColour(osdBack);
199   textSummary.setPosition(40, 10);
200   textSummary.setSize(video->getScreenWidth() - 80, 130);
201   textSummary.setParaMode(true);
202   summary.add(&textSummary);
203   
204   summaryBlackLine.setBackgroundColour(Colour::BLACK);
205   summaryBlackLine.setPosition(0, summary.getHeight() - 4);
206   summaryBlackLine.setSize(summary.getWidth(), 4);
207   summary.add(&summaryBlackLine);
208   
209   sAspectRatio.setPosition(osd.getWidth() - 90, clock.getY2()+4);
210   sAspectRatio.nextColour = Colour::YELLOW;
211   sAspectRatio.setVisible(false);
212   osd.add(&sAspectRatio);
213   
214   // FIXME painful
215   Region r1 = summary.getRegionR();
216   Region r2 = osd.getRegionR();
217   osdSummaryRegion = r1 + r2;
218 }
219
220 VVideoLiveTV::~VVideoLiveTV()
221 {
222   if (playing) stop();
223
224   delete player;
225   video->setDefaultAspect();
226   delData();
227 }
228
229 void VVideoLiveTV::delData()
230 {
231   if (eventList)
232   {
233     int eventListSize = eventList->size();
234     for(int i = 0; i < eventListSize; i++)
235     {
236       delete (*eventList)[i];
237     }
238     eventList->clear();
239     delete eventList;
240
241   }
242   sl.clear();
243 }
244
245 int VVideoLiveTV::handleCommand(int command)
246 {
247   switch(command)
248   {
249     case Remote::BACK:
250     {
251       if (osd.getVisible())
252       {
253         clearScreen();
254         return 2;
255       }
256       // else drop through to stop
257     }
258     case Remote::STOP:
259     {
260       stop();
261       vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
262       return 4;
263     }
264     case Remote::UP:
265     {
266       // New remote only
267       // epg data up
268       doUpDown(false);
269       return 2;
270     }
271     case Remote::DOWN:
272     {
273       // New remote only
274       // epg data down
275       doUpDown(true);
276       return 2;
277     }
278     case Remote::LEFT:
279     {
280       // New remote only
281       // epg data ch down
282       doLeftRight(false);
283       return 2;
284     }
285     case Remote::RIGHT:
286     {
287       // New remote only
288       // epg data ch up
289       doLeftRight(true);
290       return 2;
291     }
292     case Remote::DF_UP:
293     case Remote::CHANNELUP:
294     {
295       doChanUpDown(UP);
296       return 2;
297     }
298     case Remote::DF_DOWN:
299     case Remote::CHANNELDOWN:
300     {
301       doChanUpDown(DOWN);
302       return 2;
303     }
304     case Remote::PREVCHANNEL:
305     {
306       channelChange(PREVIOUS, 0);
307       return 2;
308     }
309     case Remote::OK:
310     {
311       doOK();
312       return 2;
313     }
314     case Remote::RED:
315     case Remote::MENU:
316     {
317       doSummary();
318       return 2;
319     }
320     case Remote::FULL:
321     case Remote::TV:
322     {
323       toggleChopSides();
324       return 2;
325     }
326
327     case Remote::ZERO:
328     case Remote::ONE:
329     case Remote::TWO:
330     case Remote::THREE:
331     case Remote::FOUR:
332     case Remote::FIVE:
333     case Remote::SIX:
334     case Remote::SEVEN:
335     case Remote::EIGHT:
336     case Remote::NINE:
337     {
338       // key in channel number
339       doKey(command);
340       return 2;
341     }
342
343     case Remote::GREEN:
344     {
345       if (streamType == VDR::VIDEO) doAudioSelector();
346       return 2;   
347     }
348     case Remote::YELLOW:
349     {
350       return 2;
351     }
352     case Remote::GUIDE:
353     case Remote::BLUE:
354     {
355       doEPG();
356       return 2;
357     }
358   }
359
360   return 1;
361 }
362
363 void VVideoLiveTV::go()
364 {
365   playing = true;
366   draw();
367   boxstack->update(this);
368
369   setClock();
370   displayOSD(true);
371   
372   player->go(currentChannelIndex);
373 }
374
375 void VVideoLiveTV::stop()
376 {
377   Timers::getInstance()->cancelTimer(this, 1);
378   Timers::getInstance()->cancelTimer(this, 2);
379   player->stop();
380   playing = false;
381 }
382
383 void VVideoLiveTV::doLeftRight(bool right)
384 {
385   if (osd.getVisible())
386   {
387     if (right) osdChannelIndex = upChannel(osdChannelIndex);
388     else       osdChannelIndex = downChannel(osdChannelIndex);
389   }
390   else
391   {
392     osdChannelIndex = currentChannelIndex;
393   }
394   displayOSD(true);
395 }
396
397 void VVideoLiveTV::doUpDown(bool down)
398 {
399   if (osd.getVisible())
400   {
401     if (down) sl.down();
402     else      sl.up();
403     sl.draw();
404     
405     displayOSD(false);
406   }
407   else
408   {
409     displayOSD(true);
410   }
411 }
412
413 void VVideoLiveTV::doChanUpDown(int which)
414 {
415   channelChange(OFFSET, which);
416   osdChannelIndex = currentChannelIndex;
417   displayOSD(true);
418 }
419
420 void VVideoLiveTV::doOK()
421 {
422   if (osd.getVisible())
423   {
424     if (keying)
425     {
426       UINT newChannel = 0;
427       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
428       
429       channelChange(NUMBER, newChannel);
430       osdChannelIndex = currentChannelIndex;
431       displayOSD(true);
432     }
433     else if (osdChannelIndex == currentChannelIndex)
434     {
435       clearScreen();
436     }
437     else
438     {
439       channelChange(INDEX, osdChannelIndex);
440       displayOSD(true);
441     }
442   }
443   else
444   {
445     osdChannelIndex = currentChannelIndex;
446     displayOSD(true);
447   }
448 }
449
450 void VVideoLiveTV::doSummary()
451 {
452   if (summary.getVisible())
453   {
454     summary.setVisible(false);
455     draw();
456     boxstack->update(this, summary.getRegion());
457     Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
458     return;
459   }
460
461   summary.setVisible(true);
462
463   if (osd.getVisible())
464   {
465     Timers::getInstance()->cancelTimer(this, 1);
466     displayOSD(false);
467   }
468   else
469   {
470     displayOSD(true);
471   }
472 }
473
474 void VVideoLiveTV::doKey(int command)
475 {
476   if (!osd.getVisible()) // First key. prep the data
477   {
478     setNowNextData();
479     keying = 0;    
480   }
481
482   int i;
483   for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
484   keyingInput[0] = command;
485   keying++;
486
487   char* keyingString = new char[numberWidth + 1];
488   for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
489   keyingString[numberWidth] = '\0';
490
491   for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
492   
493   if (keying == numberWidth)
494   {
495     UINT newChannel = 0;
496     for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
497     
498     channelChange(NUMBER, newChannel);
499     osdChannelIndex = currentChannelIndex;
500     Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
501     displayOSD(true); // this will put one back if required
502   }
503   else
504   {
505     osdChanNum.setText(keyingString);
506
507     if (!osd.getVisible())
508     {
509       osd.setVisible(true);
510       draw();
511     }
512     else
513     {
514       osdChanNum.draw();
515     }
516     boxstack->update(this, osd.getRegion());
517     Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
518   }
519   delete[] keyingString;
520 }
521
522 void VVideoLiveTV::doAudioSelector()
523 {
524   // If the osd is already visisble there might be a timer for it
525   Timers::getInstance()->cancelTimer(this, 1);
526
527   // Cancel keying
528   if (keying)
529   {
530     keying = 0;
531     // and reset the display - this is a copy from setNowNextData
532     char formatChanNum[20];
533     SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
534     osdChanNum.setText(formatChanNum);
535     osdChanName.setText((*chanList)[osdChannelIndex]->name);
536   }
537
538   // Draw the selector
539   vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel());
540   Colour osdBack = Colour(0, 0, 0, 128);
541   vas->setBackgroundColour(osdBack);
542   vas->setPosition(0, osd.getScreenY() - vas->getHeight());
543   vas->draw();
544
545   // make vas != null and displayOSD will not set a timer or do any boxstack update
546   summary.setVisible(false);
547   if (osd.getVisible()) displayOSD(false);
548   else displayOSD(true);
549   draw();
550
551   BoxStack::getInstance()->add(vas);
552   BoxStack::getInstance()->update(this);        
553   BoxStack::getInstance()->update(vas);     
554 }      
555       
556 void VVideoLiveTV::doEPG()
557 {
558   if (osd.getVisible()) clearScreen();
559
560   video->setMode(Video::QUARTER);
561   video->setPosition(170, 5); //TODO need to deal with 4:3 switching
562
563   VEpg* vepg = new VEpg(this, currentChannelIndex, VDR::VIDEO);
564   vepg->draw();
565   boxstack->add(vepg);
566   boxstack->update(vepg);
567 }
568
569 void VVideoLiveTV::setNowNextData()
570 {
571   delData();
572   
573   Channel* currentChannel = (*chanList)[osdChannelIndex];
574
575   char formatChanNum[20];
576   SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
577   osdChanNum.setText(formatChanNum);
578   osdChanName.setText(currentChannel->name);
579
580   eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
581
582   if (!eventList)
583   {
584     sl.addOption(tr("No channel data available"), 0, 1);
585   }
586   else
587   {
588     sort(eventList->begin(), eventList->end(), EventSorter());
589
590     char tempString[300];
591     char tempString2[300];
592     struct tm* btime;
593     Event* event;
594     int eventListSize = eventList->size();
595     for(int i = 0; i < eventListSize; i++)
596     {
597       event = (*eventList)[i];
598
599       //btime = localtime((time_t*)&event->time);
600       time_t etime = event->time;
601       btime = localtime(&etime);
602 #ifndef _MSC_VER
603       strftime(tempString2, 299, "%0H:%0M ", btime);
604 #else
605       strftime(tempString2, 299, "%H:%M ", btime);
606 #endif
607       SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
608       
609       sl.addOption(tempString, (ULONG)event, (i==0));
610     }
611   }
612 }
613
614 void VVideoLiveTV::setSummaryData()
615 {
616   // If osd is not being displayed, sl will be filled with now, current channel
617   // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
618   Event* selectedEvent = (Event*)sl.getCurrentOptionData();
619   
620   if (!selectedEvent)
621   {
622     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  
623     textSummary.setText(tr("No summary available"));
624   }
625   else
626   {
627     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  
628     textSummary.setText(selectedEvent->description);
629   }
630 }
631
632 void VVideoLiveTV::displayOSD(bool newNowNextData)
633 {
634   osd.setVisible(true);
635   if (newNowNextData)
636   {
637     setNowNextData();
638     keying = 0;  
639   }
640   osd.draw();
641   
642   if (summary.getVisible())
643   {
644     setSummaryData();
645     summary.draw();
646     boxstack->update(this, &osdSummaryRegion);
647   }
648   else if (!vas)
649   {
650     boxstack->update(this, osd.getRegion());
651     Timers::getInstance()->setTimerD(this, 1, 4);
652   }
653 }
654
655 void VVideoLiveTV::clearScreen()
656 {  
657   if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
658
659   osd.setVisible(false);
660
661   if (summary.getVisible())
662   {
663     summary.setVisible(false);
664     draw();
665     boxstack->update(this, &osdSummaryRegion);
666   }
667   else
668   {
669     draw();
670     boxstack->update(this, osd.getRegion());
671   }
672 }
673
674 void VVideoLiveTV::setClock()
675 {
676   char timeString[20];
677   time_t t;
678   time(&t);
679   struct tm* tms = localtime(&t);
680   strftime(timeString, 19, "%H:%M", tms);
681   clock.setText(timeString);
682
683   time_t dt = 60 - (t % 60);  // seconds to the next minute
684   if (dt == 0) dt = 60; // advance a whole minute if necessary
685   dt += t;  // get a time_t value for it rather than using duration
686   // (so it will occur at the actual second and not second and a half)
687
688   Timers::getInstance()->setTimerT(this, 2, dt);
689 }
690
691 void VVideoLiveTV::timercall(int ref)
692 {
693   if (ref == 1)
694   {
695     if (keying)
696     {
697       // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
698       
699       UINT newChannel = 0;
700       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
701       
702       Message* m = new Message();
703       m->message = Message::CHANNEL_CHANGE;
704       m->to = this;
705       m->parameter = newChannel;
706       m->tag = 1; // signal to call displayOSD();
707       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
708     }
709     else
710     {
711       osd.setVisible(false);
712       draw();
713       Message* m = new Message();
714       m->message = Message::REDRAW;
715       m->to = BoxStack::getInstance();
716       m->from = this;
717       m->parameter = (ULONG)osd.getRegion();
718       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
719     }
720   }
721   else if (ref == 2)
722   {
723     setClock();
724     if (osd.getVisible())
725     {
726       clock.draw();
727       Message* m = new Message();
728       m->message = Message::REDRAW;
729       m->to = BoxStack::getInstance();
730       m->from = this;
731       m->parameter = (ULONG)osd.getRegion();
732       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.    
733     }
734   }
735 }
736
737 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
738 {
739   UINT newChannel = 0;
740
741   if (changeType == INDEX)
742   {
743     newChannel = newData;
744   }
745   else if (changeType == NUMBER)
746   {
747     UINT i;
748     for(i = 0; i < chanList->size(); i++)
749     {
750       if ((*chanList)[i]->number == (UINT)newData)
751       {
752         newChannel = i;
753         break;
754       }
755     }
756
757     if (i == chanList->size())
758     {
759       // no such channel
760       return false;
761     }
762   }
763   else if (changeType == OFFSET)
764   {
765     if (newData == UP) newChannel = upChannel(currentChannelIndex);
766     else newChannel = downChannel(currentChannelIndex);
767   }
768   else if (changeType == PREVIOUS)
769   {
770     newChannel = previousChannelIndex;
771   }
772   else
773   {
774     return false; // bad input
775   }
776
777   if (newChannel == currentChannelIndex) return true;
778
779   previousChannelIndex = currentChannelIndex;
780   currentChannelIndex = newChannel;
781   
782   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
783   player->setChannel(currentChannelIndex);
784   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
785
786   return true;
787 }
788
789 void VVideoLiveTV::processMessage(Message* m)
790 {
791   if (m->message == Message::MOUSE_LBDOWN)
792   {
793     //check if press is outside this view! then simulate cancel
794     int x=(m->parameter>>16)-osd.getScreenX();
795     int y=(m->parameter&0xFFFF)-osd.getScreenY();
796     if (osd.getVisible()) {
797     
798         if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
799             (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
800             BoxStack::getInstance()->handleCommand(Remote::RED);
801         } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
802             (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
803             BoxStack::getInstance()->handleCommand(Remote::GREEN);
804         } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
805             (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
806             BoxStack::getInstance()->handleCommand(Remote::YELLOW);
807         } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
808             (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
809             BoxStack::getInstance()->handleCommand(Remote::BLUE);
810         } else {
811             BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
812         }
813
814     } else {
815         BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
816     }
817   }
818   else if (m->message == Message::CHANNEL_CHANGE)
819   {
820     channelChange(NUMBER, m->parameter);
821     osdChannelIndex = currentChannelIndex;
822     if (m->tag == 1) displayOSD(true);
823   }
824   else if (m->message == Message::EPG_CLOSE)
825   {
826     video->setMode(videoMode);
827   }
828   else if (m->message == Message::CHILD_CLOSE)
829   {
830     if (m->from == vas)
831     {
832       vas = NULL;
833       displayOSD(false);
834     }
835   }
836   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
837   {
838     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
839     player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16);
840   }
841   else if (m->message == Message::PLAYER_EVENT)
842   {
843     switch(m->parameter)
844     {
845       case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
846       {
847         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
848         // I can't handle this, send it to command
849         Message* m2 = new Message();
850         m2->to = Command::getInstance();
851         m2->message = Message::CONNECTION_LOST;
852         Command::getInstance()->postMessageNoLock(m2);
853         break;
854       }
855       
856       /*
857       case PlayerLiveTV::STREAM_END:
858       {
859         // I can't handle this, send it to command - improve this
860         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
861         m2->to = Command::getInstance();
862         m2->message = Message::STREAM_END;
863         Command::getInstance()->postMessageNoLock(m2);
864         break;
865       }
866       */
867       
868       case PlayerLiveTV::ASPECT43:
869       {
870         if (dowss)
871         {
872           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
873           wss.setWide(false);
874           wss.draw();
875           BoxStack::getInstance()->update(this, &wssRegion);
876         }
877         
878         sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
879         sAspectRatio.setVisible(true);
880         osd.draw();
881         BoxStack::getInstance()->update(this, osd.getRegion());
882         
883         break;
884       }
885       case PlayerLiveTV::ASPECT169:
886       {
887         if (dowss)
888         {
889           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
890           wss.setWide(true);
891           wss.draw();
892           BoxStack::getInstance()->update(this, &wssRegion);
893         }
894         
895         sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
896         sAspectRatio.setVisible(true);
897         osd.draw();
898         BoxStack::getInstance()->update(this, osd.getRegion());
899                 
900         break;
901       }
902       case PlayerLiveTV::PREBUFFERING:
903       {
904         Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", m->tag);
905       }
906     }
907   }
908 }
909
910 UINT VVideoLiveTV::upChannel(UINT index)
911 {
912   if (index == (chanList->size() - 1)) // at the end
913     return 0; // so go to start
914   else
915     return index + 1;
916 }
917
918 UINT VVideoLiveTV::downChannel(UINT index)
919 {
920   if (index == 0) // at the start
921     return chanList->size() - 1; // so go to end
922   else
923     return index - 1;
924 }
925
926 void VVideoLiveTV::toggleChopSides()
927 {
928   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
929
930   if (videoMode == Video::NORMAL)
931   {
932     videoMode = Video::LETTERBOX;
933     video->setMode(Video::LETTERBOX);
934   }
935   else
936   {
937     videoMode = Video::NORMAL;
938     video->setMode(Video::NORMAL);
939   }
940 }
941