2 Copyright 2007 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "vvideolivetv.h"
23 #include "vchannellist.h"
25 #include "playerlivetv.h"
34 #include "vaudioselector.h"
40 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
42 vdr = VDR::getInstance();
43 boxstack = BoxStack::getInstance();
44 video = Video::getInstance();
47 vchannelList = tvchannelList;
48 numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
50 currentChannelIndex = 0;
51 previousChannelIndex = 0;
57 // Convert channel number to index
59 for(i = 0; i < chanList->size(); i++)
61 if ((*chanList)[i]->number == (UINT)initialChannelNumber)
63 currentChannelIndex = i;
71 videoMode = video->getMode();
72 player = new PlayerLiveTV(Command::getInstance(), this, chanList);
75 setSize(video->getScreenWidth(), video->getScreenHeight());
77 Colour transparent(0, 0, 0, 0);
78 setBackgroundColour(transparent);
81 char* optionWSS = vdr->configLoad("General", "WSS");
84 if (strstr(optionWSS, "Yes")) dowss = true;
87 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
91 wss.setFormat(video->getFormat());
97 wssRegion.w = video->getScreenWidth();
101 Colour osdBack = Colour(0, 0, 0, 128);
103 osd.setBackgroundColour(osdBack);
104 osd.setPosition(0, video->getScreenHeight() - 150);
105 osd.setSize(video->getScreenWidth(), 150);
106 osd.setVisible(false);
109 clock.setBackgroundColour(osdBack);
110 clock.setPosition(osd.getWidth() - 100, 4);
111 clock.setSize(90, 30);
114 osdChanNum.setBackgroundColour(osdBack);
115 osdChanNum.setPosition(40, 4);
116 osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
117 osd.add(&osdChanNum);
119 osdChanName.setBackgroundColour(osdBack);
120 osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
121 osdChanName.setSize(300, 30);
122 osd.add(&osdChanName);
124 boxRed.setBackgroundColour(Colour::RED);
125 boxRed.setPosition(50, 104);
126 boxRed.setSize(18, 16);
129 boxGreen.setBackgroundColour(Colour::GREEN);
130 boxGreen.setPosition(220, 104);
131 boxGreen.setSize(18, 16);
134 boxYellow.setBackgroundColour(Colour::YELLOW);
135 boxYellow.setPosition(390, 104);
136 boxYellow.setSize(18, 16);
139 boxBlue.setBackgroundColour(Colour::BLUE);
140 boxBlue.setPosition(560, 104);
141 boxBlue.setSize(18, 16);
144 textRed.setBackgroundColour(osdBack);
145 textRed.setPosition(boxRed.getX()+18, 98);
146 textRed.setSize(120, 30);
147 textRed.setText("Summary");
150 textGreen.setBackgroundColour(osdBack);
151 textGreen.setPosition(boxGreen.getX()+18, 98);
152 textGreen.setSize(120, 30);
153 textGreen.setText("Audio");
156 textYellow.setBackgroundColour(osdBack);
157 textYellow.setPosition(boxYellow.getX()+18, 98);
158 textYellow.setSize(120, 30);
159 textYellow.setText("");
160 osd.add(&textYellow);
162 textBlue.setBackgroundColour(osdBack);
163 textBlue.setPosition(boxBlue.getX()+18, 98);
164 textBlue.setSize(90, 30);
165 textBlue.setText("EPG");
168 sl.setBackgroundColour(osdBack);
169 sl.setPosition(70, 36);
175 VVideoLiveTV::~VVideoLiveTV()
180 video->setDefaultAspect();
183 int VVideoLiveTV::handleCommand(int command)
189 if (osd.getVisible())
194 // else drop through to stop
200 vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
232 case Remote::CHANNELUP:
237 case Remote::DF_DOWN:
238 case Remote::CHANNELDOWN:
243 case Remote::PREVCHANNEL:
245 channelChange(PREVIOUS, 0);
275 // key in channel number
283 VAudioSelector* vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((Player*)player)->getCurrentAudioChannel());
284 vas->setBackgroundColour(Colour::VIEWBACKGROUND);
285 vas->setPosition(0, getHeight()-200);
287 BoxStack::getInstance()->add(vas);
288 BoxStack::getInstance()->update(vas);
306 void VVideoLiveTV::go()
310 boxstack->update(this);
315 player->go(currentChannelIndex);
318 void VVideoLiveTV::stop()
320 Timers::getInstance()->cancelTimer(this, 1);
321 Timers::getInstance()->cancelTimer(this, 2);
326 void VVideoLiveTV::doNowNext()
331 Channel* currentChannel = (*chanList)[osdChannelIndex];
333 char formatChanNum[20];
334 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
335 osdChanNum.setText(formatChanNum);
336 osdChanName.setText(currentChannel->name);
338 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
342 sl.addOption(tr("No channel data available"), 0, 1);
346 sort(eventList->begin(), eventList->end(), EventSorter());
348 char tempString[300];
349 char tempString2[300];
352 int eventListSize = eventList->size();
353 for(int i = 0; i < eventListSize; i++)
355 event = (*eventList)[i];
357 //btime = localtime((time_t*)&event->time);
358 time_t etime = event->time;
359 btime = localtime(&etime);
361 strftime(tempString2, 299, "%0H:%0M ", btime);
363 strftime(tempString2, 299, "%H:%M ", btime);
365 SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
366 sl.addOption(tempString, (ULONG)event, (i==0));
371 void VVideoLiveTV::delData()
375 int eventListSize = eventList->size();
376 for(int i = 0; i < eventListSize; i++)
378 delete (*eventList)[i];
387 void VVideoLiveTV::doOK()
389 if (osd.getVisible())
394 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
396 channelChange(NUMBER, newChannel);
397 osdChannelIndex = currentChannelIndex;
400 else if (osdChannelIndex == currentChannelIndex)
406 channelChange(INDEX, osdChannelIndex);
412 osdChannelIndex = currentChannelIndex;
417 void VVideoLiveTV::doLeft()
419 if (osd.getVisible())
420 osdChannelIndex = downChannel(osdChannelIndex);
422 osdChannelIndex = currentChannelIndex;
427 void VVideoLiveTV::doRight()
429 if (osd.getVisible())
430 osdChannelIndex = upChannel(osdChannelIndex);
432 osdChannelIndex = currentChannelIndex;
437 void VVideoLiveTV::doUp()
439 if (osd.getVisible())
443 boxstack->update(this, osd.getRegion());
444 Timers::getInstance()->setTimerD(this, 1, 8); // arrows pressed, go to 8s timer
452 void VVideoLiveTV::doDown()
454 if (osd.getVisible())
458 boxstack->update(this, osd.getRegion());
459 Timers::getInstance()->setTimerD(this, 1, 8); // arrows pressed, go to 8s timer
467 void VVideoLiveTV::doChanUp()
469 channelChange(OFFSET, UP);
470 osdChannelIndex = currentChannelIndex;
475 void VVideoLiveTV::doChanDown()
477 channelChange(OFFSET, DOWN);
478 osdChannelIndex = currentChannelIndex;
483 void VVideoLiveTV::doKey(int command)
485 if (!osd.getVisible()) // First key. prep the data
491 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
492 keyingInput[0] = command;
495 char keyingString[numberWidth+1];
496 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
497 keyingString[numberWidth] = '\0';
499 for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
501 if (keying == numberWidth)
504 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
506 channelChange(NUMBER, newChannel);
507 osdChannelIndex = currentChannelIndex;
512 // Special, modified displayOSD
513 if (!osd.getVisible())
515 osd.setVisible(true);
516 osdChanNum.setText(keyingString);
521 osdChanNum.setText(keyingString);
524 boxstack->update(this, osd.getRegion());
525 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
529 void VVideoLiveTV::displayOSD()
531 osd.setVisible(true);
534 boxstack->update(this, osd.getRegion());
535 Timers::getInstance()->setTimerD(this, 1, 4);
538 void VVideoLiveTV::removeOSD()
540 Timers::getInstance()->cancelTimer(this, 1);
541 osd.setVisible(false);
543 boxstack->update(this, osd.getRegion());
546 void VVideoLiveTV::setClock()
551 struct tm* tms = localtime(&t);
552 strftime(timeString, 19, "%H:%M", tms);
553 clock.setText(timeString);
555 time_t dt = 60 - (t % 60); // seconds to the next minute
556 if (dt == 0) dt = 60; // advance a whole minute if necessary
557 dt += t; // get a time_t value for it rather than using duration
558 // (so it will occur at the actual second and not second and a half)
560 Timers::getInstance()->setTimerT(this, 2, dt);
563 void VVideoLiveTV::doEPG()
565 if (osd.getVisible()) removeOSD();
567 video->setMode(Video::QUARTER);
568 video->setPosition(170, 5); //TODO need to deal with 4:3 switching
570 VEpg* vepg = new VEpg(this, currentChannelIndex, VDR::VIDEO);
573 boxstack->update(vepg);
576 void VVideoLiveTV::timercall(int ref)
582 // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
585 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
587 Message* m = new Message();
588 m->message = Message::CHANNEL_CHANGE;
590 m->parameter = newChannel;
591 m->tag = 1; // signal to call displayOSD();
592 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
596 osd.setVisible(false);
598 Message* m = new Message();
599 m->message = Message::REDRAW;
600 m->to = BoxStack::getInstance();
602 m->parameter = (ULONG)osd.getRegion();
603 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
609 if (osd.getVisible())
612 Message* m = new Message();
613 m->message = Message::REDRAW;
614 m->to = BoxStack::getInstance();
616 m->parameter = (ULONG)osd.getRegion();
617 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
622 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
626 if (changeType == INDEX)
628 newChannel = newData;
630 else if (changeType == NUMBER)
633 for(i = 0; i < chanList->size(); i++)
635 if ((*chanList)[i]->number == (UINT)newData)
642 if (i == chanList->size())
648 else if (changeType == OFFSET)
650 if (newData == UP) newChannel = upChannel(currentChannelIndex);
651 else newChannel = downChannel(currentChannelIndex);
653 else if (changeType == PREVIOUS)
655 newChannel = previousChannelIndex;
659 return false; // bad input
662 if (newChannel == currentChannelIndex) return true;
664 previousChannelIndex = currentChannelIndex;
665 currentChannelIndex = newChannel;
667 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
668 player->setChannel(currentChannelIndex);
669 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
674 void VVideoLiveTV::processMessage(Message* m)
676 if (m->message == Message::MOUSE_LBDOWN)
678 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
680 else if (m->message == Message::CHANNEL_CHANGE)
682 channelChange(NUMBER, m->parameter);
683 osdChannelIndex = currentChannelIndex;
684 if (m->tag == 1) displayOSD();
686 else if (m->message == Message::EPG_CLOSE)
688 video->setMode(videoMode);
690 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
692 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
693 player->setAudioChannel(m->parameter);
695 else if (m->message == Message::PLAYER_EVENT)
699 case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
701 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
702 // I can't handle this, send it to command
703 Message* m2 = new Message();
704 m2->to = Command::getInstance();
705 m2->message = Message::CONNECTION_LOST;
706 Command::getInstance()->postMessageNoLock(m2);
711 case PlayerLiveTV::STREAM_END:
713 // I can't handle this, send it to command - improve this
714 Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
715 m2->to = Command::getInstance();
716 m2->message = Message::STREAM_END;
717 Command::getInstance()->postMessageNoLock(m2);
722 case PlayerLiveTV::ASPECT43:
726 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
729 BoxStack::getInstance()->update(this, &wssRegion);
733 case PlayerLiveTV::ASPECT169:
737 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
740 BoxStack::getInstance()->update(this, &wssRegion);
748 UINT VVideoLiveTV::upChannel(UINT index)
750 if (index == (chanList->size() - 1)) // at the end
751 return 0; // so go to start
756 UINT VVideoLiveTV::downChannel(UINT index)
758 if (index == 0) // at the start
759 return chanList->size() - 1; // so go to end
764 void VVideoLiveTV::toggleChopSides()
766 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
768 if (videoMode == Video::NORMAL)
770 videoMode = Video::LETTERBOX;
771 video->setMode(Video::LETTERBOX);
775 videoMode = Video::NORMAL;
776 video->setMode(Video::NORMAL);