]> git.vomp.tv Git - vompclient.git/blob - vvideolive.cc
Switch trunk code to new boxes
[vompclient.git] / vvideolive.cc
1 /*
2     Copyright 2004-2005 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 "vvideolive.h"
22
23 #include "vchannellist.h"
24 #include "video.h"
25 #include "player.h"
26 #include "playerradio.h"
27 #include "channel.h"
28 #include "vlivebanner.h"
29 #include "boxstack.h"
30 #include "vchannelselect.h"
31 #include "colour.h"
32 #include "osd.h"
33 #include "vinfo.h"
34 #include "command.h"
35 #include "i18n.h"
36 #include "vepg.h"
37 #include "wtextbox.h"
38 #include "remote.h"
39 #include "vaudioselector.h"
40
41 VVideoLive* VVideoLive::instance = NULL;
42
43 VVideoLive::VVideoLive(ChannelList* tchanList, ULONG tstreamType, VChannelList* tvchannelList)
44 {
45   instance = this;
46   vdr = VDR::getInstance();
47   boxstack = BoxStack::getInstance();
48   video = Video::getInstance();
49
50   chanList = tchanList;
51   vchannelList = tvchannelList;
52
53   currentChannel = 0;
54   previousChannel = 0;
55   unavailable = 0;
56   unavailableView = NULL;
57   streamType = tstreamType;
58   videoMode = video->getMode();
59
60   if (streamType == VDR::RADIO)
61   {
62     player = (void*)new PlayerRadio(Command::getInstance(), this, false);
63     ((PlayerRadio*)player)->init(0, 0);
64   }
65   else
66   {
67     player = (void*)new Player(Command::getInstance(), this, false);
68     ((Player*)player)->init();
69   }
70
71   setSize(video->getScreenWidth(), video->getScreenHeight());
72   createBuffer();
73   Colour transparent(0, 0, 0, 0);
74   fillColour(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("VVideoLive", Log::DEBUG, "Do WSS: %u", dowss);
84
85   wss.setFormat(video->getFormat());
86   wss.setWide(true);
87   add(&wss);
88
89   wssRegion.x = 0;
90   wssRegion.y = 6;
91   wssRegion.w = video->getScreenWidth();
92   wssRegion.h = 2;
93 }
94
95 VVideoLive::~VVideoLive()
96 {
97   if (streamType == VDR::RADIO)
98   {
99     delete (PlayerRadio*)player;
100   }
101   else
102   {
103     delete (Player*)player;
104   }
105
106   instance = NULL;
107   video->setDefaultAspect();
108 }
109
110 VVideoLive* VVideoLive::getInstance()
111 {
112   return instance;
113 }
114
115 int VVideoLive::handleCommand(int command)
116 {
117   switch(command)
118   {
119     case Remote::STOP:
120     case Remote::BACK:
121     case Remote::MENU:
122     {
123       if (unavailable) showUnavailable(0);
124       else stop();
125
126       vchannelList->highlightChannel((*chanList)[currentChannel]);
127       return 4;
128     }
129     // Take up and down from new remote and do live banner
130     case Remote::UP:
131     case Remote::DOWN:
132     {
133       doBanner(true);
134       return 2;
135     }
136     case Remote::DF_UP:
137     case Remote::CHANNELUP:
138     {
139       if (unavailable) showUnavailable(0);
140       else stop();
141       channelChange(OFFSET, UP);
142       return 2;
143     }
144     case Remote::DF_DOWN:
145     case Remote::CHANNELDOWN:
146     {
147       if (unavailable) showUnavailable(0);
148       else stop();
149       channelChange(OFFSET, DOWN);
150       return 2;
151     }
152     case Remote::PREVCHANNEL:
153     {
154       if (unavailable) showUnavailable(0);
155       else stop();
156       channelChange(PREVIOUS, 0);
157       return 2;
158     }
159     case Remote::OK:
160     {
161       doBanner(true);
162       return 2;
163     }
164     case Remote::GUIDE:
165     case Remote::RED:
166     {
167       showEPG();
168       return 2;
169     }
170     case Remote::FULL:
171     case Remote::TV:
172     {
173       toggleChopSides();
174       return 2;
175     }
176
177     case Remote::ZERO:
178     case Remote::ONE:
179     case Remote::TWO:
180     case Remote::THREE:
181     case Remote::FOUR:
182     case Remote::FIVE:
183     case Remote::SIX:
184     case Remote::SEVEN:
185     case Remote::EIGHT:
186     case Remote::NINE:
187     {
188       VChannelSelect* v = new VChannelSelect(this);
189       v->draw();
190       boxstack->add(v);
191       boxstack->update(v);
192
193       v->handleCommand(command);
194
195       return 2;
196     }
197     case Remote::GREEN:
198     {
199       if (streamType == VDR::VIDEO)
200       {
201         VAudioSelector* vas = new VAudioSelector(this, (*chanList)[currentChannel], ((Player*)player)->getCurrentAudioChannel());
202         vas->setBackgroundColour(Colour::VIEWBACKGROUND);
203         vas->setPosition(0, getHeight()-200);
204         vas->draw();
205         BoxStack::getInstance()->add(vas);
206         BoxStack::getInstance()->update(vas);        
207       }
208     }
209 #ifdef DEV
210     case Remote::YELLOW:
211     {
212     }
213     case Remote::BLUE:
214     {
215     }
216 #endif
217   }
218
219   return 1;
220 }
221
222 void VVideoLive::channelChange(UCHAR changeType, UINT newData)
223 {
224   UINT newChannel = 0;
225
226   if (changeType == INDEX)
227   {
228     newChannel = newData;
229   }
230   else if (changeType == NUMBER)
231   {
232     UINT i;
233     for(i = 0; i < chanList->size(); i++)
234     {
235       if ((*chanList)[i]->number == (UINT)newData)
236       {
237         newChannel = i;
238         break;
239       }
240     }
241
242     if (i == chanList->size())
243     {
244       doNoSuchChannel();
245       return;
246     }
247   }
248   else if (changeType == OFFSET)
249   {
250     if (newData == UP) newChannel = upChannel();
251     else newChannel = downChannel();
252   }
253   else if (changeType == PREVIOUS)
254   {
255     newChannel = previousChannel;
256   }
257   else
258   {
259     return; // bad input!
260   }
261
262   previousChannel = currentChannel;
263   currentChannel = newChannel;
264
265   if (unavailable) showUnavailable(0);
266   else stop(1);
267
268   VEpg* vepg = VEpg::getInstance();
269   if(vepg) vepg->setCurrentChannel((*chanList)[currentChannel]->name);
270
271   VLiveBanner* vlb = VLiveBanner::getInstance();
272   if (vlb)
273   {
274     vlb->setChannel((*chanList)[currentChannel]);
275     vlb->draw();
276     boxstack->update(vlb);
277   }
278
279   play();
280 }
281
282 void VVideoLive::streamEnd()
283 {
284   Log::getInstance()->log("VVideoLive", Log::DEBUG, "streamEnd");
285   stop(1);
286   showUnavailable(1);
287 }
288
289 void VVideoLive::processMessage(Message* m)
290 {
291   if (m->message == Message::MOUSE_LBDOWN)
292   {
293     BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
294   }
295   else if (m->message == Message::CHANNEL_CHANGE)
296   {
297     channelChange(NUMBER, m->parameter);
298   }
299   else if (m->message == Message::EPG)
300   {
301     Log::getInstance()->log("VVideoLive", Log::DEBUG, "EPG requested from live banner");
302     showEPG();
303   }
304   else if (m->message == Message::EPG_CLOSE)
305   {
306     video->setMode(videoMode);
307     if (saveUnavailable) showUnavailable(1);
308   }
309   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
310   {
311     Log::getInstance()->log("VVideoLive", Log::DEBUG, "Received change audio channel to %i", m->parameter);
312     ((Player*)player)->setAudioChannel(m->parameter);
313   }
314   else if (m->message == Message::PLAYER_EVENT)
315   {
316     switch(m->parameter)
317     {
318       case Player::CONNECTION_LOST: // connection lost detected
319       {
320         Log::getInstance()->log("VVideoLive", Log::DEBUG, "Received connection lost from player");
321         // I can't handle this, send it to command
322         Message* m2 = new Message();
323         m2->to = Command::getInstance();
324         m2->message = Message::CONNECTION_LOST;
325         Command::getInstance()->postMessageNoLock(m2);
326         break;
327       }
328       case Player::STREAM_END:
329       {
330         // I can't handle this, send it to command - improve this
331         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
332         m2->to = Command::getInstance();
333         m2->message = Message::STREAM_END;
334         Command::getInstance()->postMessageNoLock(m2);
335         break;
336       }
337       case Player::ASPECT43:
338       {
339         if (dowss)
340         {
341           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
342           wss.setWide(false);
343           wss.draw();
344           BoxStack::getInstance()->update(this, &wssRegion);
345         }
346         break;
347       }
348       case Player::ASPECT169:
349       {
350         if (dowss)
351         {
352           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
353           wss.setWide(true);
354           wss.draw();
355           BoxStack::getInstance()->update(this, &wssRegion);
356         }
357         break;
358       }
359     }
360   }
361 }
362
363 void VVideoLive::doBanner(bool bannerTakesCommands)
364 {
365   if (VEpg::getInstance()) return;
366
367   if (VLiveBanner::getInstance()) return; // there already is one
368
369   VLiveBanner* vlb = new VLiveBanner(this, (*chanList)[currentChannel], bannerTakesCommands);
370
371   vlb->draw();
372   boxstack->add(vlb);
373   boxstack->update(vlb);
374 }
375
376 void VVideoLive::doNoSuchChannel()
377 {
378   Log::getInstance()->log("VVideoLive", Log::ERR, "No such channel");
379   // FIXME do gui for this
380 }
381
382 void VVideoLive::showUnavailable(int active)
383 {
384   if (active == unavailable) return;
385
386   if (active)
387   {
388     unavailable = 1;
389
390     unavailableView = new VInfo();
391     unavailableView->setSize(400, 200);
392     unavailableView->createBuffer();
393     if (video->getFormat() == Video::PAL)
394     {
395       unavailableView->setPosition(170, 200);
396     }
397     else
398     {
399       unavailableView->setPosition(160, 150);
400     }
401     unavailableView->setTitleText((*chanList)[currentChannel]->name);
402     unavailableView->setOneLiner(tr("Channel unavailable"));
403     unavailableView->setDropThrough();
404     unavailableView->draw();
405     boxstack->add(unavailableView);
406     boxstack->update(unavailableView);
407   }
408   else
409   {
410     unavailable = 0;
411     boxstack->remove(unavailableView);
412     unavailableView = NULL;
413   }
414 }
415
416 void VVideoLive::play(int noShowVLB)
417 {
418   showUnavailable(0);
419
420   int available = vdr->streamChannel((*chanList)[currentChannel]->number);
421
422   if (!available)
423   {
424     if (!noShowVLB) doBanner(false);
425     showUnavailable(1);
426     if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
427   }
428   else
429   {
430     if (!noShowVLB) doBanner(false);
431
432     // FIXME - change this streamType thingy to the new system using getPids
433     // FIXME - upgrade PlayerRadio to new getPids
434
435     Channel* toPlay = (*chanList)[currentChannel];
436     toPlay->loadPids();
437
438     if (streamType == VDR::RADIO)
439     {
440       ((PlayerRadio*)player)->play(toPlay->apids[0].pid);
441     }
442     else
443     {
444       ((Player*)player)->play(toPlay->vpid, toPlay->apids[0].pid);
445     }
446   }
447 }
448
449 void VVideoLive::stop(int noRemoveVLB)
450 {
451   if (unavailable) return;
452   if (!noRemoveVLB && VLiveBanner::getInstance()) boxstack->remove(VLiveBanner::getInstance()); // if live banner is present, remove it. won't cause damage if its not present
453
454   if (streamType == VDR::RADIO)
455   {
456     ((PlayerRadio*)player)->stop();
457   }
458   else
459   {
460     ((Player*)player)->stop();
461   }
462
463   Log::getInstance()->log("VVideoLive", Log::DEBUG, "Delay starts here due to time taken by plugin to stop");
464   vdr->stopStreaming();
465   if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
466   Log::getInstance()->log("VVideoLive", Log::DEBUG, "Delay ends here due to time taken by plugin to stop");
467 }
468
469 UINT VVideoLive::upChannel()
470 {
471   if (currentChannel == (chanList->size() - 1)) // at the end
472     return 0; // so go to start
473   else
474     return currentChannel + 1;
475 }
476
477 UINT VVideoLive::downChannel()
478 {
479   if (currentChannel == 0) // at the start
480     return chanList->size() - 1; // so go to end
481   else
482     return currentChannel - 1;
483 }
484
485 void VVideoLive::showEPG()
486 {
487   saveUnavailable = unavailable;
488   if (unavailable) showUnavailable(0);
489
490   if (VEpg::getInstance()) return; // already showing!
491
492   video->setMode(Video::QUARTER);
493   video->setPosition(170, 5); //TODO need to deal with 4:3 switching
494
495   VEpg* vepg = new VEpg(this, currentChannel, streamType);
496   vepg->draw();
497
498   boxstack->add(vepg);
499   boxstack->update(vepg);
500 }
501
502 void VVideoLive::toggleChopSides()
503 {
504   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
505
506   if (videoMode == Video::NORMAL)
507   {
508     videoMode = Video::LETTERBOX;
509     video->setMode(Video::LETTERBOX);
510   }
511   else
512   {
513     videoMode = Video::NORMAL;
514     video->setMode(Video::NORMAL);
515   }
516 }
517