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