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