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