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(50, 50, 50);
103 osd.setBackgroundColour(osdBack);
104 osd.setPosition(0, video->getScreenHeight() - 150);
105 osd.setSize(video->getScreenWidth(), 150);
106 osd.setVisible(false);
109 clock.setBackgroundColour(Colour::BLACK);
110 clock.setPosition(osd.getWidth() - 100, 4);
111 clock.setSize(90, 30);
114 osdChanNum.setBackgroundColour(Colour::BLACK);
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(Colour::BLACK);
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(Colour::BLACK);
145 textRed.setPosition(boxRed.getX()+18, 98);
146 textRed.setSize(120, 30);
147 textRed.setText("Summary");
150 textGreen.setBackgroundColour(Colour::BLACK);
151 textGreen.setPosition(boxGreen.getX()+18, 98);
152 textGreen.setSize(120, 30);
153 textGreen.setText("Audio");
156 textYellow.setBackgroundColour(Colour::BLACK);
157 textYellow.setPosition(boxYellow.getX()+18, 98);
158 textYellow.setSize(120, 30);
159 textYellow.setText("");
160 osd.add(&textYellow);
162 textBlue.setBackgroundColour(Colour::BLACK);
163 textBlue.setPosition(boxBlue.getX()+18, 98);
164 textBlue.setSize(90, 30);
165 textBlue.setText("EPG");
168 sl.setPosition(70, 36);
174 VVideoLiveTV::~VVideoLiveTV()
179 video->setDefaultAspect();
182 int VVideoLiveTV::handleCommand(int command)
188 if (osd.getVisible())
193 // else drop through to stop
199 vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
231 case Remote::CHANNELUP:
236 case Remote::DF_DOWN:
237 case Remote::CHANNELDOWN:
242 case Remote::PREVCHANNEL:
244 channelChange(PREVIOUS, 0);
274 // key in channel number
282 VAudioSelector* vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((Player*)player)->getCurrentAudioChannel());
283 vas->setBackgroundColour(Colour::VIEWBACKGROUND);
284 vas->setPosition(0, getHeight()-200);
286 BoxStack::getInstance()->add(vas);
287 BoxStack::getInstance()->update(vas);
305 void VVideoLiveTV::go()
309 boxstack->update(this);
317 void VVideoLiveTV::stop()
319 Timers::getInstance()->cancelTimer(this, 1);
320 Timers::getInstance()->cancelTimer(this, 2);
325 void VVideoLiveTV::doNowNext()
330 Channel* currentChannel = (*chanList)[osdChannelIndex];
332 char formatChanNum[20];
333 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
334 osdChanNum.setText(formatChanNum);
335 osdChanName.setText(currentChannel->name);
337 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
341 sl.addOption(tr("No channel data available"), 0, 1);
345 sort(eventList->begin(), eventList->end(), EventSorter());
347 char tempString[300];
348 char tempString2[300];
351 int eventListSize = eventList->size();
352 for(int i = 0; i < eventListSize; i++)
354 event = (*eventList)[i];
356 //btime = localtime((time_t*)&event->time);
357 time_t etime = event->time;
358 btime = localtime(&etime);
360 strftime(tempString2, 299, "%0H:%0M ", btime);
362 strftime(tempString2, 299, "%H:%M ", btime);
364 SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
365 sl.addOption(tempString, (ULONG)event, (i==0));
370 void VVideoLiveTV::delData()
374 int eventListSize = eventList->size();
375 for(int i = 0; i < eventListSize; i++)
377 delete (*eventList)[i];
386 void VVideoLiveTV::doOK()
388 if (osd.getVisible())
393 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
395 channelChange(NUMBER, newChannel);
396 osdChannelIndex = currentChannelIndex;
399 else if (osdChannelIndex == currentChannelIndex)
405 channelChange(INDEX, osdChannelIndex);
411 osdChannelIndex = currentChannelIndex;
416 void VVideoLiveTV::doLeft()
418 if (osd.getVisible())
419 osdChannelIndex = downChannel(osdChannelIndex);
421 osdChannelIndex = currentChannelIndex;
426 void VVideoLiveTV::doRight()
428 if (osd.getVisible())
429 osdChannelIndex = upChannel(osdChannelIndex);
431 osdChannelIndex = currentChannelIndex;
436 void VVideoLiveTV::doUp()
438 if (osd.getVisible())
442 boxstack->update(this, osd.getRegion());
443 Timers::getInstance()->setTimerD(this, 1, 8); // arrows pressed, go to 8s timer
451 void VVideoLiveTV::doDown()
453 if (osd.getVisible())
457 boxstack->update(this, osd.getRegion());
458 Timers::getInstance()->setTimerD(this, 1, 8); // arrows pressed, go to 8s timer
466 void VVideoLiveTV::doChanUp()
468 channelChange(OFFSET, UP);
469 osdChannelIndex = currentChannelIndex;
474 void VVideoLiveTV::doChanDown()
476 channelChange(OFFSET, DOWN);
477 osdChannelIndex = currentChannelIndex;
482 void VVideoLiveTV::doKey(int command)
484 if (!osd.getVisible()) // First key. prep the data
490 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
491 keyingInput[0] = command;
494 char keyingString[numberWidth+1];
495 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
496 keyingString[numberWidth] = '\0';
498 for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
500 if (keying == numberWidth)
503 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
505 channelChange(NUMBER, newChannel);
506 osdChannelIndex = currentChannelIndex;
511 // Special, modified displayOSD
512 if (!osd.getVisible())
514 osd.setVisible(true);
515 osdChanNum.setText(keyingString);
520 osdChanNum.setText(keyingString);
523 boxstack->update(this, osd.getRegion());
524 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
528 void VVideoLiveTV::displayOSD()
530 osd.setVisible(true);
533 boxstack->update(this, osd.getRegion());
534 Timers::getInstance()->setTimerD(this, 1, 4);
537 void VVideoLiveTV::removeOSD()
539 Timers::getInstance()->cancelTimer(this, 1);
540 osd.setVisible(false);
542 boxstack->update(this, osd.getRegion());
545 void VVideoLiveTV::setClock()
550 struct tm* tms = localtime(&t);
551 strftime(timeString, 19, "%H:%M", tms);
552 clock.setText(timeString);
554 time_t dt = 60 - (t % 60); // seconds to the next minute
555 if (dt == 0) dt = 60; // advance a whole minute if necessary
556 dt += t; // get a time_t value for it rather than using duration
557 // (so it will occur at the actual second and not second and a half)
559 Timers::getInstance()->setTimerT(this, 2, dt);
562 void VVideoLiveTV::doEPG()
564 if (osd.getVisible()) removeOSD();
566 video->setMode(Video::QUARTER);
567 video->setPosition(170, 5); //TODO need to deal with 4:3 switching
569 VEpg* vepg = new VEpg(NULL, currentChannelIndex, VDR::VIDEO);
572 boxstack->update(vepg);
575 void VVideoLiveTV::timercall(int ref)
581 // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
584 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
586 Message* m = new Message();
587 m->message = Message::CHANNEL_CHANGE;
589 m->parameter = newChannel;
590 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
594 osd.setVisible(false);
596 Message* m = new Message();
597 m->message = Message::REDRAW;
598 m->to = BoxStack::getInstance();
600 m->parameter = (ULONG)osd.getRegion();
601 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
607 if (osd.getVisible())
610 Message* m = new Message();
611 m->message = Message::REDRAW;
612 m->to = BoxStack::getInstance();
614 m->parameter = (ULONG)osd.getRegion();
615 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
620 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
624 if (changeType == INDEX)
626 newChannel = newData;
628 else if (changeType == NUMBER)
631 for(i = 0; i < chanList->size(); i++)
633 if ((*chanList)[i]->number == (UINT)newData)
640 if (i == chanList->size())
646 else if (changeType == OFFSET)
648 if (newData == UP) newChannel = upChannel(currentChannelIndex);
649 else newChannel = downChannel(currentChannelIndex);
651 else if (changeType == PREVIOUS)
653 newChannel = previousChannelIndex;
657 return false; // bad input
660 if (newChannel == currentChannelIndex) return true;
662 previousChannelIndex = currentChannelIndex;
663 currentChannelIndex = newChannel;
665 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
667 player->setChannel(currentChannelIndex);
671 void VVideoLiveTV::processMessage(Message* m)
673 if (m->message == Message::MOUSE_LBDOWN)
675 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
677 else if (m->message == Message::CHANNEL_CHANGE)
679 channelChange(NUMBER, m->parameter);
680 osdChannelIndex = currentChannelIndex;
683 else if (m->message == Message::EPG_CLOSE)
685 video->setMode(videoMode);
687 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
689 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
690 player->setAudioChannel(m->parameter);
692 else if (m->message == Message::PLAYER_EVENT)
696 case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
698 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
699 // I can't handle this, send it to command
700 Message* m2 = new Message();
701 m2->to = Command::getInstance();
702 m2->message = Message::CONNECTION_LOST;
703 Command::getInstance()->postMessageNoLock(m2);
708 case PlayerLiveTV::STREAM_END:
710 // I can't handle this, send it to command - improve this
711 Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
712 m2->to = Command::getInstance();
713 m2->message = Message::STREAM_END;
714 Command::getInstance()->postMessageNoLock(m2);
719 case PlayerLiveTV::ASPECT43:
723 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
726 BoxStack::getInstance()->update(this, &wssRegion);
730 case PlayerLiveTV::ASPECT169:
734 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
737 BoxStack::getInstance()->update(this, &wssRegion);
745 UINT VVideoLiveTV::upChannel(UINT index)
747 if (index == (chanList->size() - 1)) // at the end
748 return 0; // so go to start
753 UINT VVideoLiveTV::downChannel(UINT index)
755 if (index == 0) // at the start
756 return chanList->size() - 1; // so go to end
761 void VVideoLiveTV::toggleChopSides()
763 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
765 if (videoMode == Video::NORMAL)
767 videoMode = Video::LETTERBOX;
768 video->setMode(Video::LETTERBOX);
772 videoMode = Video::NORMAL;
773 video->setMode(Video::NORMAL);