]> git.vomp.tv Git - vompclient.git/blob - vvideolivetv.cc
Start of new live tv
[vompclient.git] / vvideolivetv.cc
1 /*
2     Copyright 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "vvideolivetv.h"
22
23 #include "vchannellist.h"
24 #include "video.h"
25 //#include "playerlivetv.h"
26 #include "channel.h"
27 #include "boxstack.h"
28 #include "colour.h"
29 #include "osd.h"
30 #include "command.h"
31 #include "i18n.h"
32 #include "wtextbox.h"
33 #include "remote.h"
34 #include "vaudioselector.h"
35 #include "colour.h"
36 #include "event.h"
37
38 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
39 {
40   vdr = VDR::getInstance();
41   boxstack = BoxStack::getInstance();
42   video = Video::getInstance();
43
44   chanList = tchanList;
45   vchannelList = tvchannelList;
46   numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
47
48   currentChannelIndex = 0;
49   previousChannelIndex = 0;
50   osdChannelIndex = 0;
51   keying = 0;
52
53   // Convert channel number to index
54   UINT i;
55   for(i = 0; i < chanList->size(); i++)
56   {
57     if ((*chanList)[i]->number == (UINT)initialChannelNumber)
58     {
59       currentChannelIndex = i;
60       osdChannelIndex = i;
61       break;
62     }
63   }
64
65   eventList = NULL;
66
67   videoMode = video->getMode();
68 //  player = new PlayerLiveTV(Command::getInstance(), this);
69 //  player->init(chanList);
70
71   setSize(video->getScreenWidth(), video->getScreenHeight());
72   createBuffer();
73   Colour transparent(0, 0, 0, 0);
74   setBackgroundColour(transparent);
75
76   dowss = false;
77   char* optionWSS = vdr->configLoad("General", "WSS");
78   if (optionWSS)
79   {
80     if (strstr(optionWSS, "Yes")) dowss = true;
81     delete[] optionWSS;
82   }
83   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
84
85   if (dowss)
86   {
87     wss.setFormat(video->getFormat());
88     wss.setWide(true);
89     add(&wss);
90     
91     wssRegion.x = 0;
92     wssRegion.y = 6;
93     wssRegion.w = video->getScreenWidth();
94     wssRegion.h = 2;
95   }
96   
97   Colour osdBack = Colour(50, 50, 50);
98   
99   osd.setBackgroundColour(osdBack);
100   osd.setPosition(0, video->getScreenHeight() - 150);
101   osd.setSize(video->getScreenWidth(), 150);
102   osd.setVisible(false);
103   add(&osd);
104   
105   clock.setBackgroundColour(Colour::BLACK);
106   clock.setPosition(osd.getWidth() - 100, 4);
107   clock.setSize(90, 30);
108   clock.setText("00:00");
109   osd.add(&clock);
110
111   osdChanNum.setBackgroundColour(Colour::BLACK);
112   osdChanNum.setPosition(40, 4);
113   osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
114   osd.add(&osdChanNum);  
115
116   osdChanName.setBackgroundColour(Colour::BLACK);
117   osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
118   osdChanName.setSize(300, 30);
119   osd.add(&osdChanName);
120   
121   boxRed.setBackgroundColour(Colour::RED);
122   boxRed.setPosition(50, 104);
123   boxRed.setSize(18, 16);
124   osd.add(&boxRed);
125
126   boxGreen.setBackgroundColour(Colour::GREEN);
127   boxGreen.setPosition(220, 104);
128   boxGreen.setSize(18, 16);
129   osd.add(&boxGreen);
130
131   boxYellow.setBackgroundColour(Colour::YELLOW);
132   boxYellow.setPosition(390, 104);
133   boxYellow.setSize(18, 16);
134   osd.add(&boxYellow);
135
136   boxBlue.setBackgroundColour(Colour::BLUE);
137   boxBlue.setPosition(560, 104);
138   boxBlue.setSize(18, 16);
139   osd.add(&boxBlue);  
140   
141   textRed.setBackgroundColour(Colour::BLACK);
142   textRed.setPosition(boxRed.getX()+18, 98);
143   textRed.setSize(120, 30);
144   textRed.setText("Summary");
145   osd.add(&textRed);  
146     
147   textGreen.setBackgroundColour(Colour::BLACK);
148   textGreen.setPosition(boxGreen.getX()+18, 98);
149   textGreen.setSize(120, 30);
150   textGreen.setText("Audio");
151   osd.add(&textGreen);  
152     
153   textYellow.setBackgroundColour(Colour::BLACK);
154   textYellow.setPosition(boxYellow.getX()+18, 98);
155   textYellow.setSize(120, 30);
156   textYellow.setText("");
157   osd.add(&textYellow);  
158     
159   textBlue.setBackgroundColour(Colour::BLACK);
160   textBlue.setPosition(boxBlue.getX()+18, 98);
161   textBlue.setSize(90, 30);
162   textBlue.setText("EPG");
163   osd.add(&textBlue);  
164     
165   sl.setPosition(70, 36);
166   sl.setSize(500, 58);
167   sl.setNoLoop();
168   osd.add(&sl);
169 }
170
171 VVideoLiveTV::~VVideoLiveTV()
172 {
173 //  delete player;
174   video->setDefaultAspect();
175 }
176
177 int VVideoLiveTV::handleCommand(int command)
178 {
179   switch(command)
180   {
181     case Remote::STOP:
182     case Remote::BACK:
183     case Remote::MENU:
184     {
185       stop();
186       vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
187       return 4;
188     }
189     case Remote::UP:
190     {
191       // New remote only
192       // epg data up
193       sl.up();
194       sl.draw();
195       boxstack->update(this, osd.getRegion());
196       return 2;
197     }
198     case Remote::DOWN:
199     {
200       // New remote only
201       // epg data down
202       sl.down();
203       sl.draw();
204       boxstack->update(this, osd.getRegion());
205       return 2;
206     }
207     case Remote::LEFT:
208     {
209       // New remote only
210       // epg data ch down
211       doLeft();
212       return 2;
213     }
214     case Remote::RIGHT:
215     {
216       // New remote only
217       // epg data ch up
218       doRight();
219       return 2;
220     }
221     case Remote::DF_UP:
222     case Remote::CHANNELUP:
223     {
224       doChanUp();
225       return 2;
226     }
227     case Remote::DF_DOWN:
228     case Remote::CHANNELDOWN:
229     {
230       doChanDown();
231       return 2;
232     }
233     case Remote::PREVCHANNEL:
234     {
235       channelChange(PREVIOUS, 0);
236       return 2;
237     }
238     case Remote::OK:
239     {
240       doOK();
241       return 2;
242     }
243     case Remote::GUIDE:
244     case Remote::RED:
245     {
246       return 2;
247     }
248     case Remote::FULL:
249     case Remote::TV:
250     {
251       toggleChopSides();
252       return 2;
253     }
254
255     case Remote::ZERO:
256     case Remote::ONE:
257     case Remote::TWO:
258     case Remote::THREE:
259     case Remote::FOUR:
260     case Remote::FIVE:
261     case Remote::SIX:
262     case Remote::SEVEN:
263     case Remote::EIGHT:
264     case Remote::NINE:
265     {
266       // key in channel number
267       doKey(command);
268       return 2;
269     }
270
271     case Remote::GREEN:
272     {
273       /*
274       VAudioSelector* vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((Player*)player)->getCurrentAudioChannel());
275       vas->setBackgroundColour(Colour::VIEWBACKGROUND);
276       vas->setPosition(0, getHeight()-200);
277       vas->draw();
278       BoxStack::getInstance()->add(vas);
279       BoxStack::getInstance()->update(vas);        
280       */
281     }
282 #ifdef DEV
283     case Remote::YELLOW:
284     {
285     }
286     case Remote::BLUE:
287     {
288     }
289 #endif
290   }
291
292   return 1;
293 }
294
295 void VVideoLiveTV::go()
296 {
297   doNowNext();
298   osd.setVisible(true);
299   draw();
300   boxstack->update(this);
301   // set a timer for osd deletion
302
303   // start player  
304 }
305
306 void VVideoLiveTV::stop()
307 {  
308 }
309
310 void VVideoLiveTV::doNowNext()
311 {
312   delData();
313   keying = 0;
314   
315   Channel* currentChannel = (*chanList)[osdChannelIndex];
316
317   char formatChanNum[20];
318   SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
319   osdChanNum.setText(formatChanNum);
320   osdChanName.setText(currentChannel->name);
321
322   eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
323
324   if (!eventList)
325   {
326     sl.addOption(tr("No channel data available"), 0, 1);
327   }
328   else
329   {
330     sort(eventList->begin(), eventList->end(), EventSorter());
331
332     char tempString[300];
333     char tempString2[300];
334     struct tm* btime;
335     Event* event;
336     int eventListSize = eventList->size();
337     for(int i = 0; i < eventListSize; i++)
338     {
339       event = (*eventList)[i];
340
341       //btime = localtime((time_t*)&event->time);
342       time_t etime = event->time;
343       btime = localtime(&etime);
344 #ifndef _MSC_VER
345       strftime(tempString2, 299, "%0H:%0M ", btime);
346 #else
347       strftime(tempString2, 299, "%H:%M ", btime);
348 #endif
349       SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
350       sl.addOption(tempString, (ULONG)event, (i==0));
351     }
352   }
353 }
354
355 void VVideoLiveTV::delData()
356 {
357   if (eventList)
358   {
359     int eventListSize = eventList->size();
360     for(int i = 0; i < eventListSize; i++)
361     {
362       delete (*eventList)[i];
363     }
364     eventList->clear();
365     delete eventList;
366
367   }
368   sl.clear();
369 }
370
371 void VVideoLiveTV::doOK()
372 {
373   if (osd.getVisible())
374   {
375     if (osdChannelIndex == currentChannelIndex)
376     {
377       osd.setVisible(false);
378       draw();
379       boxstack->update(this, osd.getRegion());
380     }
381     else
382     {
383       channelChange(INDEX, osdChannelIndex);
384       doNowNext();
385       draw();
386       boxstack->update(this, osd.getRegion());
387     }
388   }
389   else
390   {
391     osdChannelIndex = currentChannelIndex;
392     doNowNext();
393     osd.setVisible(true);
394     draw();
395     boxstack->update(this, osd.getRegion());
396     // set a timer for deletion of osd
397   }
398 }
399
400 void VVideoLiveTV::doLeft()
401 {
402   if (osd.getVisible())
403   {
404     osdChannelIndex = downChannel(osdChannelIndex);
405   }
406   else
407   {
408     osdChannelIndex = currentChannelIndex;
409     osd.setVisible(true);
410   }    
411
412   doNowNext();
413   draw();
414   boxstack->update(this, osd.getRegion());     
415 }
416
417 void VVideoLiveTV::doRight()
418 {
419   if (osd.getVisible())
420   {
421     osdChannelIndex = upChannel(osdChannelIndex);
422   }
423   else
424   {
425     osdChannelIndex = currentChannelIndex;
426     osd.setVisible(true);
427   }    
428
429   doNowNext();
430   draw();
431   boxstack->update(this, osd.getRegion());  
432 }
433
434 void VVideoLiveTV::doChanUp()
435 {
436   channelChange(OFFSET, UP);
437   osdChannelIndex = currentChannelIndex;
438   doNowNext();
439   draw();
440   boxstack->update(this, osd.getRegion());     
441 }
442
443 void VVideoLiveTV::doChanDown()
444 {
445   channelChange(OFFSET, DOWN);
446   osdChannelIndex = currentChannelIndex;
447   doNowNext();
448   draw();
449   boxstack->update(this, osd.getRegion());   
450 }
451
452 void VVideoLiveTV::doKey(int command)
453 {
454   int i;
455   
456   for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
457   keyingInput[0] = command;
458   keying++;
459
460   char keyingString[numberWidth+1];
461   for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
462   keyingString[numberWidth] = '\0';
463
464   for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
465   
466   if (keying == numberWidth)
467   {
468     UINT newChannel = 0;
469     for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
470     
471     channelChange(NUMBER, newChannel);
472     osdChannelIndex = currentChannelIndex;
473     doNowNext();
474     draw();
475     boxstack->update(this, osd.getRegion());
476   }
477   else
478   {
479     osdChanNum.setText(keyingString);
480     osdChanNum.draw();  
481     boxstack->update(this, osd.getRegion());
482   }
483 }
484
485 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
486 {
487   UINT newChannel = 0;
488
489   if (changeType == INDEX)
490   {
491     newChannel = newData;
492   }
493   else if (changeType == NUMBER)
494   {
495     UINT i;
496     for(i = 0; i < chanList->size(); i++)
497     {
498       if ((*chanList)[i]->number == (UINT)newData)
499       {
500         newChannel = i;
501         break;
502       }
503     }
504
505     if (i == chanList->size())
506     {
507       // no such channel
508       return false;
509     }
510   }
511   else if (changeType == OFFSET)
512   {
513     if (newData == UP) newChannel = upChannel(currentChannelIndex);
514     else newChannel = downChannel(currentChannelIndex);
515   }
516   else if (changeType == PREVIOUS)
517   {
518     newChannel = previousChannelIndex;
519   }
520   else
521   {
522     return false; // bad input
523   }
524
525   if (newChannel == currentChannelIndex) return true;
526
527   previousChannelIndex = currentChannelIndex;
528   currentChannelIndex = newChannel;
529   
530   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
531
532   return true;
533 //  player->setChannel(currentChannelIndex);
534 }
535
536 void VVideoLiveTV::processMessage(Message* m)
537 {
538   if (m->message == Message::MOUSE_LBDOWN)
539   {
540     BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
541   }
542   else if (m->message == Message::CHANNEL_CHANGE)
543   {
544     channelChange(NUMBER, m->parameter);
545   }
546   else if (m->message == Message::EPG_CLOSE)
547   {
548     video->setMode(videoMode);
549   }
550   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
551   {
552     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
553 //    ((Player*)player)->setAudioChannel(m->parameter);
554   }
555   else if (m->message == Message::PLAYER_EVENT)
556   {
557 /*
558     switch(m->parameter)
559     {
560       case Player::CONNECTION_LOST: // connection lost detected
561       {
562         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
563         // I can't handle this, send it to command
564         Message* m2 = new Message();
565         m2->to = Command::getInstance();
566         m2->message = Message::CONNECTION_LOST;
567         Command::getInstance()->postMessageNoLock(m2);
568         break;
569       }
570       case Player::STREAM_END:
571       {
572         // I can't handle this, send it to command - improve this
573         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
574         m2->to = Command::getInstance();
575         m2->message = Message::STREAM_END;
576         Command::getInstance()->postMessageNoLock(m2);
577         break;
578       }
579       case Player::ASPECT43:
580       {
581         if (dowss)
582         {
583           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
584           wss.setWide(false);
585           wss.draw();
586           BoxStack::getInstance()->update(this, &wssRegion);
587         }
588         break;
589       }
590       case Player::ASPECT169:
591       {
592         if (dowss)
593         {
594           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
595           wss.setWide(true);
596           wss.draw();
597           BoxStack::getInstance()->update(this, &wssRegion);
598         }
599         break;
600       }
601     }
602     */
603   }
604 }
605
606 UINT VVideoLiveTV::upChannel(UINT index)
607 {
608   if (index == (chanList->size() - 1)) // at the end
609     return 0; // so go to start
610   else
611     return index + 1;
612 }
613
614 UINT VVideoLiveTV::downChannel(UINT index)
615 {
616   if (index == 0) // at the start
617     return chanList->size() - 1; // so go to end
618   else
619     return index - 1;
620 }
621
622 void VVideoLiveTV::toggleChopSides()
623 {
624   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
625
626   if (videoMode == Video::NORMAL)
627   {
628     videoMode = Video::LETTERBOX;
629     video->setMode(Video::LETTERBOX);
630   }
631   else
632   {
633     videoMode = Video::NORMAL;
634     video->setMode(Video::NORMAL);
635   }
636 }
637