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