2 Copyright 2007-2008 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.
21 #include "vvideolivetv.h"
23 #include "vchannellist.h"
25 #include "playerlive.h"
26 #include "playerlivetv.h"
27 #include "playerliveradio.h"
36 #include "vaudioselector.h"
42 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
44 vdr = VDR::getInstance();
45 boxstack = BoxStack::getInstance();
46 video = Video::getInstance();
49 vchannelList = tvchannelList;
50 numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
52 currentChannelIndex = 0;
53 previousChannelIndex = 0;
59 // Convert channel number to index
61 for(i = 0; i < chanList->size(); i++)
63 if ((*chanList)[i]->number == (UINT)initialChannelNumber)
65 currentChannelIndex = i;
73 videoMode = video->getMode();
75 if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
77 player = new PlayerLiveTV(Command::getInstance(), this, chanList);
81 player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
85 setSize(video->getScreenWidth(), video->getScreenHeight());
87 Colour transparent(0, 0, 0, 0);
88 setBackgroundColour(transparent);
91 char* optionWSS = vdr->configLoad("General", "WSS");
94 if (strstr(optionWSS, "Yes")) dowss = true;
97 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
101 wss.setFormat(video->getFormat());
107 wssRegion.w = video->getScreenWidth();
111 Colour osdBack = Colour(0, 0, 0, 128);
113 osd.setBackgroundColour(osdBack);
114 osd.setPosition(0, video->getScreenHeight() - 150);
115 osd.setSize(video->getScreenWidth(), 150);
116 osd.setVisible(false);
119 clock.setBackgroundColour(osdBack);
120 clock.setPosition(osd.getWidth() - 100, 4);
121 clock.setSize(90, 30);
124 osdChanNum.setBackgroundColour(osdBack);
125 osdChanNum.setPosition(40, 4);
126 osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
127 osd.add(&osdChanNum);
129 osdChanName.setBackgroundColour(osdBack);
130 osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
131 osdChanName.setSize(300, 30);
132 osd.add(&osdChanName);
134 boxRed.setBackgroundColour(Colour::RED);
135 boxRed.setPosition(50, 104);
136 boxRed.setSize(18, 16);
139 boxGreen.setBackgroundColour(Colour::GREEN);
140 boxGreen.setPosition(220, 104);
141 boxGreen.setSize(18, 16);
144 boxYellow.setBackgroundColour(Colour::YELLOW);
145 boxYellow.setPosition(390, 104);
146 boxYellow.setSize(18, 16);
149 boxBlue.setBackgroundColour(Colour::BLUE);
150 boxBlue.setPosition(560, 104);
151 boxBlue.setSize(18, 16);
154 textRed.setBackgroundColour(osdBack);
155 textRed.setPosition(boxRed.getX()+18, 98);
156 textRed.setSize(120, 30);
157 textRed.setText("Summary");
160 textGreen.setBackgroundColour(osdBack);
161 textGreen.setPosition(boxGreen.getX()+18, 98);
162 textGreen.setSize(120, 30);
163 textGreen.setText("Audio");
166 textYellow.setBackgroundColour(osdBack);
167 textYellow.setPosition(boxYellow.getX()+18, 98);
168 textYellow.setSize(120, 30);
169 textYellow.setText("");
170 osd.add(&textYellow);
172 textBlue.setBackgroundColour(osdBack);
173 textBlue.setPosition(boxBlue.getX()+18, 98);
174 textBlue.setSize(90, 30);
175 textBlue.setText("EPG");
178 sl.setBackgroundColour(osdBack);
179 sl.setPosition(70, 36);
185 summary.setBackgroundColour(osdBack);
186 summary.setPosition(0, video->getScreenHeight() - 300);
187 summary.setSize(video->getScreenWidth(), 150);
188 summary.setVisible(false);
191 textSummary.setBackgroundColour(osdBack);
192 textSummary.setPosition(30, 10);
193 textSummary.setSize(video->getScreenWidth() - 60, 130);
194 textSummary.setParaMode(true);
195 summary.add(&textSummary);
197 summaryBlackLine.setBackgroundColour(Colour::BLACK);
198 summaryBlackLine.setPosition(0, summary.getHeight() - 4);
199 summaryBlackLine.setSize(summary.getWidth(), 4);
200 summary.add(&summaryBlackLine);
203 Region r1 = summary.getRegionR();
204 Region r2 = osd.getRegionR();
205 osdSummaryRegion = r1 + r2;
208 VVideoLiveTV::~VVideoLiveTV()
213 video->setDefaultAspect();
217 void VVideoLiveTV::delData()
221 int eventListSize = eventList->size();
222 for(int i = 0; i < eventListSize; i++)
224 delete (*eventList)[i];
233 int VVideoLiveTV::handleCommand(int command)
239 if (osd.getVisible())
244 // else drop through to stop
249 vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
281 case Remote::CHANNELUP:
286 case Remote::DF_DOWN:
287 case Remote::CHANNELDOWN:
292 case Remote::PREVCHANNEL:
294 channelChange(PREVIOUS, 0);
326 // key in channel number
334 VAudioSelector* vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((Player*)player)->getCurrentAudioChannel());
335 vas->setBackgroundColour(Colour::VIEWBACKGROUND);
336 vas->setPosition(0, getHeight()-200);
338 BoxStack::getInstance()->add(vas);
339 BoxStack::getInstance()->update(vas);
357 void VVideoLiveTV::go()
361 boxstack->update(this);
366 player->go(currentChannelIndex);
369 void VVideoLiveTV::stop()
371 Timers::getInstance()->cancelTimer(this, 1);
372 Timers::getInstance()->cancelTimer(this, 2);
377 void VVideoLiveTV::doLeftRight(bool right)
379 if (osd.getVisible())
381 if (right) osdChannelIndex = upChannel(osdChannelIndex);
382 else osdChannelIndex = downChannel(osdChannelIndex);
386 osdChannelIndex = currentChannelIndex;
391 void VVideoLiveTV::doUpDown(bool down)
393 if (osd.getVisible())
407 void VVideoLiveTV::doChanUpDown(int which)
409 channelChange(OFFSET, which);
410 osdChannelIndex = currentChannelIndex;
414 void VVideoLiveTV::doOK()
416 if (osd.getVisible())
421 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
423 channelChange(NUMBER, newChannel);
424 osdChannelIndex = currentChannelIndex;
427 else if (osdChannelIndex == currentChannelIndex)
433 channelChange(INDEX, osdChannelIndex);
439 osdChannelIndex = currentChannelIndex;
444 void VVideoLiveTV::doSummary()
446 if (summary.getVisible())
448 summary.setVisible(false);
450 boxstack->update(this, summary.getRegion());
451 Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
455 summary.setVisible(true);
457 if (osd.getVisible())
459 Timers::getInstance()->cancelTimer(this, 1);
468 void VVideoLiveTV::doKey(int command)
470 if (!osd.getVisible()) // First key. prep the data
477 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
478 keyingInput[0] = command;
481 char* keyingString = new char[numberWidth + 1];
482 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
483 keyingString[numberWidth] = '\0';
485 for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
487 if (keying == numberWidth)
490 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
492 channelChange(NUMBER, newChannel);
493 osdChannelIndex = currentChannelIndex;
494 Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
495 displayOSD(true); // this will put one back if required
499 osdChanNum.setText(keyingString);
501 if (!osd.getVisible())
503 osd.setVisible(true);
510 boxstack->update(this, osd.getRegion());
511 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
513 delete[] keyingString;
516 void VVideoLiveTV::doEPG()
518 if (osd.getVisible()) clearScreen();
520 video->setMode(Video::QUARTER);
521 video->setPosition(170, 5); //TODO need to deal with 4:3 switching
523 VEpg* vepg = new VEpg(this, currentChannelIndex, VDR::VIDEO);
526 boxstack->update(vepg);
529 void VVideoLiveTV::setNowNextData()
533 Channel* currentChannel = (*chanList)[osdChannelIndex];
535 char formatChanNum[20];
536 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
537 osdChanNum.setText(formatChanNum);
538 osdChanName.setText(currentChannel->name);
540 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
544 sl.addOption(tr("No channel data available"), 0, 1);
548 sort(eventList->begin(), eventList->end(), EventSorter());
550 char tempString[300];
551 char tempString2[300];
554 int eventListSize = eventList->size();
555 for(int i = 0; i < eventListSize; i++)
557 event = (*eventList)[i];
559 //btime = localtime((time_t*)&event->time);
560 time_t etime = event->time;
561 btime = localtime(&etime);
563 strftime(tempString2, 299, "%0H:%0M ", btime);
565 strftime(tempString2, 299, "%H:%M ", btime);
567 SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
569 sl.addOption(tempString, (ULONG)event, (i==0));
574 void VVideoLiveTV::setSummaryData()
576 // If osd is not being displayed, sl will be filled with now, current channel
577 // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
578 Event* selectedEvent = (Event*)sl.getCurrentOptionData();
582 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");
583 textSummary.setText(tr("No summary available"));
587 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);
588 textSummary.setText(selectedEvent->description);
592 void VVideoLiveTV::displayOSD(bool newNowNextData)
594 osd.setVisible(true);
602 if (summary.getVisible())
606 boxstack->update(this, &osdSummaryRegion);
610 boxstack->update(this, osd.getRegion());
611 Timers::getInstance()->setTimerD(this, 1, 4);
615 void VVideoLiveTV::clearScreen()
617 if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
619 osd.setVisible(false);
621 if (summary.getVisible())
623 summary.setVisible(false);
625 boxstack->update(this, &osdSummaryRegion);
630 boxstack->update(this, osd.getRegion());
634 void VVideoLiveTV::setClock()
639 struct tm* tms = localtime(&t);
640 strftime(timeString, 19, "%H:%M", tms);
641 clock.setText(timeString);
643 time_t dt = 60 - (t % 60); // seconds to the next minute
644 if (dt == 0) dt = 60; // advance a whole minute if necessary
645 dt += t; // get a time_t value for it rather than using duration
646 // (so it will occur at the actual second and not second and a half)
648 Timers::getInstance()->setTimerT(this, 2, dt);
651 void VVideoLiveTV::timercall(int ref)
657 // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
660 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
662 Message* m = new Message();
663 m->message = Message::CHANNEL_CHANGE;
665 m->parameter = newChannel;
666 m->tag = 1; // signal to call displayOSD();
667 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
671 osd.setVisible(false);
673 Message* m = new Message();
674 m->message = Message::REDRAW;
675 m->to = BoxStack::getInstance();
677 m->parameter = (ULONG)osd.getRegion();
678 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
684 if (osd.getVisible())
687 Message* m = new Message();
688 m->message = Message::REDRAW;
689 m->to = BoxStack::getInstance();
691 m->parameter = (ULONG)osd.getRegion();
692 Command::getInstance()->postMessageFromOuterSpace(m); // FIXME cjt yeah you know what.
697 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
701 if (changeType == INDEX)
703 newChannel = newData;
705 else if (changeType == NUMBER)
708 for(i = 0; i < chanList->size(); i++)
710 if ((*chanList)[i]->number == (UINT)newData)
717 if (i == chanList->size())
723 else if (changeType == OFFSET)
725 if (newData == UP) newChannel = upChannel(currentChannelIndex);
726 else newChannel = downChannel(currentChannelIndex);
728 else if (changeType == PREVIOUS)
730 newChannel = previousChannelIndex;
734 return false; // bad input
737 if (newChannel == currentChannelIndex) return true;
739 previousChannelIndex = currentChannelIndex;
740 currentChannelIndex = newChannel;
742 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
743 player->setChannel(currentChannelIndex);
744 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
749 void VVideoLiveTV::processMessage(Message* m)
751 if (m->message == Message::MOUSE_LBDOWN)
753 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
755 else if (m->message == Message::CHANNEL_CHANGE)
757 channelChange(NUMBER, m->parameter);
758 osdChannelIndex = currentChannelIndex;
759 if (m->tag == 1) displayOSD(true);
761 else if (m->message == Message::EPG_CLOSE)
763 video->setMode(videoMode);
765 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
767 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
768 player->setAudioChannel(m->parameter);
770 else if (m->message == Message::PLAYER_EVENT)
774 case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
776 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
777 // I can't handle this, send it to command
778 Message* m2 = new Message();
779 m2->to = Command::getInstance();
780 m2->message = Message::CONNECTION_LOST;
781 Command::getInstance()->postMessageNoLock(m2);
786 case PlayerLiveTV::STREAM_END:
788 // I can't handle this, send it to command - improve this
789 Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
790 m2->to = Command::getInstance();
791 m2->message = Message::STREAM_END;
792 Command::getInstance()->postMessageNoLock(m2);
797 case PlayerLiveTV::ASPECT43:
801 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
804 BoxStack::getInstance()->update(this, &wssRegion);
808 case PlayerLiveTV::ASPECT169:
812 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
815 BoxStack::getInstance()->update(this, &wssRegion);
823 UINT VVideoLiveTV::upChannel(UINT index)
825 if (index == (chanList->size() - 1)) // at the end
826 return 0; // so go to start
831 UINT VVideoLiveTV::downChannel(UINT index)
833 if (index == 0) // at the start
834 return chanList->size() - 1; // so go to end
839 void VVideoLiveTV::toggleChopSides()
841 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
843 if (videoMode == Video::NORMAL)
845 videoMode = Video::LETTERBOX;
846 video->setMode(Video::LETTERBOX);
850 videoMode = Video::NORMAL;
851 video->setMode(Video::NORMAL);