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"
26 #include "playerlive.h"
27 #include "playerlivetv.h"
28 #include "playerliveradio.h"
37 #include "vaudioselector.h"
44 #include "vteletextview.h"
46 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
47 : osdBack(0, 0, 0, 128)
49 vdr = VDR::getInstance();
50 boxstack = BoxStack::getInstance();
51 video = Video::getInstance();
56 vchannelList = tvchannelList;
57 numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
59 currentChannelIndex = 0;
60 previousChannelIndex = 0;
67 // Convert channel number to index
69 for(i = 0; i < chanList->size(); i++)
71 if ((*chanList)[i]->number == (UINT)initialChannelNumber)
73 currentChannelIndex = i;
81 videoMode = video->getMode();
83 if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
85 streamType = VDR::VIDEO;
86 player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
90 streamType = VDR::RADIO;
91 player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
95 setSize(video->getScreenWidth(), video->getScreenHeight());
97 DrawStyle transparent(0, 0, 0, 0);
98 setBackgroundColour(transparent);
101 char* optionWSS = vdr->configLoad("General", "WSS");
104 if (strstr(optionWSS, "Yes")) dowss = true;
107 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
111 wss.setFormat(video->getFormat());
117 wssRegion.w = video->getScreenWidth();
121 // This variable is set to true if the user pressed OK to bring the OSD on screen
122 // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
123 okTriggeredOSD = false;
127 osd.setBackgroundColour(osdBack);
128 osd.setPosition(0, video->getScreenHeight() - 150);
129 osd.setSize(video->getScreenWidth(), 150);
130 osd.setVisible(false);
133 clock.setBackgroundColour(osdBack);
134 clock.setPosition(osd.getWidth() - 100, 4);
135 clock.setSize(90, 30);
138 osdChanNum.setBackgroundColour(osdBack);
139 osdChanNum.setPosition(50, 4);
140 osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
141 osd.add(&osdChanNum);
143 osdChanName.setBackgroundColour(osdBack);
144 osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
145 osdChanName.setSize(300, 30);
146 osd.add(&osdChanName);
148 boxRed.setBackgroundColour(DrawStyle::RED);
149 boxRed.setPosition(54, 104);
150 boxRed.setSize(18, 16);
153 boxGreen.setBackgroundColour(DrawStyle::GREEN);
154 boxGreen.setPosition(220, 104);
155 boxGreen.setSize(18, 16);
158 boxYellow.setBackgroundColour(DrawStyle::YELLOW);
159 boxYellow.setPosition(390, 104);
160 boxYellow.setSize(18, 16);
163 boxBlue.setBackgroundColour(DrawStyle::BLUE);
164 boxBlue.setPosition(560, 104);
165 boxBlue.setSize(18, 16);
168 textRed.setBackgroundColour(osdBack);
169 textRed.setPosition(boxRed.getX2(), 98);
170 textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
171 textRed.setText(tr("Summary"));
174 if (streamType == VDR::VIDEO)
176 textGreen.setBackgroundColour(osdBack);
177 textGreen.setPosition(boxGreen.getX2(), 98);
178 textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
179 textGreen.setText(tr("Audio"));
183 textYellow.setBackgroundColour(osdBack);
184 textYellow.setPosition(boxYellow.getX2(), 98);
185 textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
186 textYellow.setText(tr("Teletext"));
187 osd.add(&textYellow);
189 textBlue.setBackgroundColour(osdBack);
190 textBlue.setPosition(boxBlue.getX2(), 98);
191 textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
192 textBlue.setText(tr("EPG"));
195 sl.setBackgroundColour(osdBack);
196 sl.setPosition(70, 36);
202 summary.setBackgroundColour(osdBack);
203 summary.setPosition(0, video->getScreenHeight() - 300);
204 summary.setSize(video->getScreenWidth(), 150);
205 summary.setVisible(false);
208 textSummary.setBackgroundColour(osdBack);
209 textSummary.setPosition(40, 10);
210 textSummary.setSize(video->getScreenWidth() - 80, 130);
211 textSummary.setParaMode(true);
212 summary.add(&textSummary);
214 summaryBlackLine.setBackgroundColour(DrawStyle::BLACK);
215 summaryBlackLine.setPosition(0, summary.getHeight() - 4);
216 summaryBlackLine.setSize(summary.getWidth(), 4);
217 summary.add(&summaryBlackLine);
219 sAspectRatio.setPosition(osd.getWidth() - 90, 40);
220 sAspectRatio.nextColour = DrawStyle::SELECTHIGHLIGHT;
221 sAspectRatio.setVisible(false);
222 osd.add(&sAspectRatio);
224 bufferBar.setPosition(osd.getWidth() - 90, 70);
225 bufferBar.setSize(40, 20);
226 bufferBar.setVisible(true);
229 sAudioChannels.setPosition(osd.getWidth() - 130, 40);
230 sAudioChannels.nextColour = DrawStyle::SELECTHIGHLIGHT;
231 sAudioChannels.setVisible(false);
232 osd.add(&sAudioChannels);
234 textUnavailable.setBackgroundColour(osdBack);
235 textUnavailable.setPosition(60, 30);
236 textUnavailable.setSize(osd.getWidth() - 120, 30);
237 textUnavailable.setText(tr("Channel Unavailable"));
238 textUnavailable.setVisible(false);
239 add(&textUnavailable);
242 Region r1 = summary.getRegionR();
243 Region r2 = osd.getRegionR();
244 osdSummaryRegion = r1 + r2;
247 void VVideoLiveTV::preDelete()
252 VVideoLiveTV::~VVideoLiveTV()
255 video->setDefaultAspect();
259 void VVideoLiveTV::delData()
263 int eventListSize = eventList->size();
264 for(int i = 0; i < eventListSize; i++)
266 delete (*eventList)[i];
275 int VVideoLiveTV::handleCommand(int command)
281 if (osd.getVisible() && !textUnavailable.getVisible())
286 // else drop through to stop
291 vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
295 // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
298 if (Remote::getInstance()->mayHaveFewButtons()) {
299 if (okTriggeredOSD) doUpDown(false);
300 else doChanUpDown(UP);
308 if (Remote::getInstance()->mayHaveFewButtons()) {
309 if (okTriggeredOSD) doUpDown(true);
310 else doChanUpDown(DOWN);
326 // Continue new remote only...
327 case Remote::CHANNELUP:
332 case Remote::CHANNELDOWN:
338 // END NEW REMOTE ONLY, START OLD REMOTE ONLY
340 // DF_LEFT and DF_RIGHT never get here because they are stolen
341 // by command as vol- and vol+
343 // Old remote. Decide what to do based on whether
344 // OK was pressed - osd shown manually, use up/down for epg nav
345 // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
349 // Old remote, decide what to do based on okTriggeredOSD
350 if (okTriggeredOSD) doUpDown(false);
351 else doChanUpDown(UP);
354 case Remote::DF_DOWN:
356 // Old remote, decide what to do based on okTriggeredOSD
357 if (okTriggeredOSD) doUpDown(true);
358 else doChanUpDown(DOWN);
362 // END NEW/OLD REMOTE STUFF
364 case Remote::PREVCHANNEL:
366 channelChange(PREVIOUS, 0);
367 osdChannelIndex = currentChannelIndex;
400 // key in channel number
407 if (streamType == VDR::VIDEO) doAudioSelector();
412 if (streamType ==VDR::VIDEO)
414 doTeletext(); //TODO: Add a selector for subtitles or teletext
425 if (streamType == VDR::VIDEO)
426 (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
433 void VVideoLiveTV::go()
437 boxstack->update(this);
442 player->go(currentChannelIndex);
445 void VVideoLiveTV::stop()
447 Timers::getInstance()->cancelTimer(this, 1);
448 Timers::getInstance()->cancelTimer(this, 2);
453 void VVideoLiveTV::doLeftRight(bool right)
455 if (osd.getVisible())
457 if (right) osdChannelIndex = upChannel(osdChannelIndex);
458 else osdChannelIndex = downChannel(osdChannelIndex);
462 osdChannelIndex = currentChannelIndex;
467 void VVideoLiveTV::doUpDown(bool down)
469 if (osd.getVisible())
483 void VVideoLiveTV::doChanUpDown(int which)
485 channelChange(OFFSET, which);
486 osdChannelIndex = currentChannelIndex;
490 void VVideoLiveTV::doOK()
492 if (osd.getVisible())
497 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
499 channelChange(NUMBER, newChannel);
500 osdChannelIndex = currentChannelIndex;
503 else if (osdChannelIndex == currentChannelIndex)
509 channelChange(INDEX, osdChannelIndex);
515 osdChannelIndex = currentChannelIndex;
517 okTriggeredOSD = true;
521 void VVideoLiveTV::doSummary()
523 if (summary.getVisible())
525 summary.setVisible(false);
527 boxstack->update(this, summary.getRegion());
528 Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
532 summary.setVisible(true);
534 if (osd.getVisible())
536 Timers::getInstance()->cancelTimer(this, 1);
545 void VVideoLiveTV::doKey(int command)
547 if (!osd.getVisible()) // First key. prep the data
554 for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
555 keyingInput[0] = command;
558 char* keyingString = new char[numberWidth + 1];
559 for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
560 keyingString[numberWidth] = '\0';
562 for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
564 if (keying == numberWidth)
567 for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
569 channelChange(NUMBER, newChannel);
570 osdChannelIndex = currentChannelIndex;
571 Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
572 displayOSD(true); // this will put one back if required
576 osdChanNum.setText(keyingString);
578 if (!osd.getVisible())
580 osd.setVisible(true);
587 boxstack->update(this, osd.getRegion());
588 Timers::getInstance()->setTimerD(this, 1, 3); // 3s for keying input
590 delete[] keyingString;
593 void VVideoLiveTV::doTeletext(bool subtitlemode)
595 if (streamType !=VDR::VIDEO) return;
596 (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(true);
603 // and reset the display - this is a copy from setNowNextData
604 char formatChanNum[20];
605 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
606 osdChanNum.setText(formatChanNum);
607 osdChanName.setText((*chanList)[osdChannelIndex]->name);
609 (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(true);
610 if (osd.getVisible()) clearScreen();
612 VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
614 vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this, (PlayerLiveTV*)player);
615 ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
618 vtxv->setSubtitleMode(subtitlemode);
623 BoxStack::getInstance()->add(vtxv);
625 BoxStack::getInstance()->update(this);
626 BoxStack::getInstance()->update(vtxv);
629 void VVideoLiveTV::doAudioSelector()
631 // If the osd is already visisble there might be a timer for it
632 Timers::getInstance()->cancelTimer(this, 1);
633 //This causes a deadlock with the timertrhread itself is locked
640 // and reset the display - this is a copy from setNowNextData
641 char formatChanNum[20];
642 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
643 osdChanNum.setText(formatChanNum);
644 osdChanName.setText((*chanList)[osdChannelIndex]->name);
646 int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
647 int subtitleType=0x10;
648 if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
649 if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
650 ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode()
652 subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
656 subtitleType=0xFF; //turnedOff
662 vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
663 subtitleType,subtitleChannel,NULL);
665 vas->setBackgroundColour(osdBack);
666 vas->setPosition(0, osd.getScreenY() - vas->getHeight());
669 // make vas != null and displayOSD will not set a timer or do any boxstack update
670 summary.setVisible(false);
671 if (osd.getVisible()) displayOSD(false);
672 else displayOSD(true);
675 BoxStack::getInstance()->add(vas);
676 BoxStack::getInstance()->update(this);
677 BoxStack::getInstance()->update(vas);
680 void VVideoLiveTV::doEPG()
682 if (osd.getVisible()) clearScreen();
684 video->setMode(Video::QUARTER);
685 video->setPosition(170, 5); //TODO need to deal with 4:3 switching
687 VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);
690 boxstack->update(vepg);
693 void VVideoLiveTV::setNowNextData()
697 Channel* currentChannel = (*chanList)[osdChannelIndex];
699 char formatChanNum[20];
700 SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
701 osdChanNum.setText(formatChanNum);
702 osdChanName.setText(currentChannel->name);
704 eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
708 sl.addOption(tr("No channel data available"), 0, 1);
712 sort(eventList->begin(), eventList->end(), EventSorter());
714 char tempString[300];
715 char tempString2[300];
718 int eventListSize = eventList->size();
719 for(int i = 0; i < eventListSize; i++)
721 event = (*eventList)[i];
723 //btime = localtime((time_t*)&event->time);
724 time_t etime = event->time;
725 btime = localtime(&etime);
727 strftime(tempString2, 299, "%0H:%0M ", btime);
729 strftime(tempString2, 299, "%H:%M ", btime);
731 SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
733 sl.addOption(tempString, (ULONG)event, (i==0));
738 void VVideoLiveTV::setSummaryData()
740 // If osd is not being displayed, sl will be filled with now, current channel
741 // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
742 Event* selectedEvent = (Event*)sl.getCurrentOptionData();
746 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");
747 textSummary.setText(tr("No summary available"));
751 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);
752 textSummary.setText(selectedEvent->description);
756 void VVideoLiveTV::displayOSD(bool newNowNextData)
758 (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(true);
759 osd.setVisible(true);
767 if (summary.getVisible())
771 boxstack->update(this, &osdSummaryRegion);
775 boxstack->update(this, osd.getRegion());
778 bool setTimer = true;
779 if (vas) setTimer = false;
780 if (summary.getVisible()) setTimer = false;
781 if (textUnavailable.getVisible()) setTimer = false;
783 if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
786 void VVideoLiveTV::clearScreen()
788 if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
790 textUnavailable.setVisible(false);
791 osd.setVisible(false);
792 summary.setVisible(false);
794 okTriggeredOSD = false;
797 boxstack->update(this);
799 (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(false);
802 void VVideoLiveTV::showUnavailable()
804 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");
805 textUnavailable.setVisible(true);
806 textUnavailable.draw();
808 if (!osd.getVisible()) displayOSD(true);
810 boxstack->update(this, textUnavailable.getRegion());
813 void VVideoLiveTV::setClock()
818 struct tm* tms = localtime(&t);
819 strftime(timeString, 19, "%H:%M", tms);
820 clock.setText(timeString);
822 time_t dt = 60 - (t % 60); // seconds to the next minute
823 if (dt == 0) dt = 60; // advance a whole minute if necessary
824 dt += t; // get a time_t value for it rather than using duration
825 // (so it will occur at the actual second and not second and a half)
827 Timers::getInstance()->setTimerT(this, 2, dt);
830 void VVideoLiveTV::timercall(int ref)
836 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start.");
838 for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
840 Message* m = new Message();
841 m->message = Message::CHANNEL_CHANGE;
843 m->parameter = newChannel;
844 m->tag = 1; // signal to call displayOSD();
845 Command::getInstance()->postMessageFromOuterSpace(m);
846 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end.");
850 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start.");
851 // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
852 if (preBuffering < 100)
854 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");
855 Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
858 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1.");
859 osd.setVisible(false);
860 okTriggeredOSD = false;
861 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2.");
863 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4.");
864 boxstack->update(this, osd.getRegion());
866 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3.");
867 (static_cast<PlayerLiveTV*>(player))->tellSubtitlesOSDVisible(false);
868 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end.");
873 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 start.");
875 if (osd.getVisible())
878 boxstack->update(this, osd.getRegion());
880 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end.");
884 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
887 if (streamType ==VDR::VIDEO) {
888 VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
890 BoxStack::getInstance()->remove(vtxt);
894 if (changeType == INDEX)
896 newChannel = newData;
898 else if (changeType == NUMBER)
901 for(i = 0; i < chanList->size(); i++)
903 if ((*chanList)[i]->number == (UINT)newData)
910 if (i == chanList->size())
916 else if (changeType == OFFSET)
918 if (newData == UP) newChannel = upChannel(currentChannelIndex);
919 else newChannel = downChannel(currentChannelIndex);
921 else if (changeType == PREVIOUS)
923 newChannel = previousChannelIndex;
927 return false; // bad input
930 if (newChannel == currentChannelIndex) return true;
932 previousChannelIndex = currentChannelIndex;
933 currentChannelIndex = newChannel;
937 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
938 player->setChannel(currentChannelIndex);
939 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
941 // Blank out the symbols
942 sAspectRatio.setVisible(false);
943 bufferBar.setPercent(0);
944 sAudioChannels.setVisible(false);
946 // Remove other stuff
947 if (textUnavailable.getVisible())
949 textUnavailable.setVisible(false);
954 BoxStack::getInstance()->update(this);
959 void VVideoLiveTV::processMessage(Message* m)
961 if (m->message == Message::MOUSE_LBDOWN)
963 //check if press is outside this view! then simulate cancel
964 int x=(m->parameter>>16)-osd.getScreenX();
965 int y=(m->parameter&0xFFFF)-osd.getScreenY();
966 if (osd.getVisible()) {
968 if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
969 (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
970 BoxStack::getInstance()->handleCommand(Remote::RED);
971 } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
972 (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
973 BoxStack::getInstance()->handleCommand(Remote::GREEN);
974 } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
975 (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
976 BoxStack::getInstance()->handleCommand(Remote::YELLOW);
977 } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
978 (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
979 BoxStack::getInstance()->handleCommand(Remote::BLUE);
981 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
985 BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
988 else if (m->message == Message::CHANNEL_CHANGE)
990 channelChange(NUMBER, m->parameter);
991 osdChannelIndex = currentChannelIndex;
992 if (m->tag == 1) displayOSD(true);
994 else if (m->message == Message::EPG_CLOSE)
996 video->setMode(videoMode);
998 else if (m->message == Message::CHILD_CLOSE)
1006 else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
1008 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
1009 player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16,(m->parameter & 0xFF000000)>>24);
1011 else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
1013 if (streamType !=VDR::VIDEO) return;
1014 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
1015 int type=((m->parameter & 0xFF0000)>>16);
1017 case 0x10: { //dvbsubtitle
1018 if (streamType == VDR::VIDEO){
1019 player->setSubtitleChannel((m->parameter & 0xFFFF));
1020 (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
1021 VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
1022 if (vtxt && vtxt->isInSubtitleMode()) {
1023 BoxStack::getInstance()->remove(vtxt);
1027 case 0xFF: { //nosubtitles
1028 if (streamType == VDR::VIDEO){
1029 (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
1030 VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
1031 if (vtxt && vtxt->isInSubtitleMode()) {
1032 BoxStack::getInstance()->remove(vtxt);
1036 case 0x11: { //videotext
1037 (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
1039 ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
1043 BoxStack::getInstance()->update(vas);
1044 //BoxStack::getInstance()->update(&osd); //eveil error
1046 BoxStack::getInstance()->update(this, osd.getRegion());
1050 else if (m->message == Message::PLAYER_EVENT)
1052 switch(m->parameter)
1054 case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
1056 Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
1057 Command::getInstance()->connectionLost();
1061 case PlayerLiveTV::STREAM_END:
1063 // Message comes from playerlivetv through master mutex, so can do anything here
1068 case PlayerLiveTV::ASPECT43:
1071 if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
1073 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
1076 BoxStack::getInstance()->update(this, &wssRegion);
1080 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
1081 sAspectRatio.setVisible(true);
1083 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1086 BoxStack::getInstance()->update(this, osd.getRegion());
1091 case PlayerLiveTV::ASPECT169:
1094 if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
1096 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
1099 BoxStack::getInstance()->update(this, &wssRegion);
1103 sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
1104 sAspectRatio.setVisible(true);
1106 if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
1109 BoxStack::getInstance()->update(this, osd.getRegion());
1114 case PlayerLiveTV::PREBUFFERING:
1116 preBuffering = m->tag;
1117 Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
1118 bufferBar.setPercent(preBuffering);
1120 if (osd.getVisible())
1122 bufferBar.setVisible(true);
1125 bufferBar.getRootBoxRegion(&r); ///////// FIXME !!!
1126 BoxStack::getInstance()->update(this, &r);
1128 if (preBuffering == 100)
1130 doAudioChannelSymbol();
1138 void VVideoLiveTV::doAudioChannelSymbol()
1141 Channel* currentChannel = (*chanList)[osdChannelIndex];
1143 bool multiAudio = false;
1144 if (Audio::getInstance()->supportsAc3()) {
1145 if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;
1147 if (currentChannel->numAPids > 1) multiAudio = true;
1151 if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
1152 else sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
1153 sAudioChannels.setVisible(true);
1155 if (osd.getVisible())
1157 sAudioChannels.draw();
1159 sAudioChannels.getRootBoxRegion(&r); ///////// FIXME !!!
1163 BoxStack::getInstance()->update(this, &r);
1167 UINT VVideoLiveTV::upChannel(UINT index)
1169 if (index == (chanList->size() - 1)) // at the end
1170 return 0; // so go to start
1175 UINT VVideoLiveTV::downChannel(UINT index)
1177 if (index == 0) // at the start
1178 return chanList->size() - 1; // so go to end
1183 void VVideoLiveTV::toggleChopSides()
1185 if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
1187 if (videoMode == Video::NORMAL)
1189 videoMode = Video::LETTERBOX;
1190 video->setMode(Video::LETTERBOX);
1194 videoMode = Video::NORMAL;
1195 video->setMode(Video::NORMAL);
1199 void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
1201 drawBitmap(posX, posY, bm,region);
1203 r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
1204 boxstack->update(this, &r);
1207 void VVideoLiveTV::clearOSD()
1209 rectangle(area, DrawStyle(0,0,0,0));
1210 boxstack->update(this, &area);
1213 void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
1216 r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;
1217 //now convert to our display
1218 float scalex=720.f/((float) (region.framewidth+1));
1219 float scaley=576.f/((float) (region.frameheight+1));
1220 r.x=floor(scalex*((float)r.x));
1221 r.y=floor(scaley*((float)r.y));
1222 r.w=ceil(scalex*((float)r.w));
1223 r.h=ceil(scaley*((float)r.h));
1224 rectangle(r, DrawStyle(0,0,0,0));
1225 boxstack->update(this, &r);