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