]> git.vomp.tv Git - vompclient-marten.git/blob - player.cc
Fix for cant power down if server unavailable
[vompclient-marten.git] / player.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 "player.h"
22
23 Player::Player(MessageQueue* messageQueue)
24 : vfeed(this), afeed(this)
25 {
26   initted = 0;
27   commandMessageQueue = messageQueue;
28
29   paused = 0;
30   playing = 0;
31   ffwd = 0;
32   fbwd = 0;
33   feedPosition = 0;
34   feedMode = MODE_NORMAL;
35
36   streamLength = 0;
37   // FIXME - this might need settings back to zero for new live play depending on what is done with it
38 }
39
40 Player::~Player()
41 {
42   if (initted) shutdown();
43 }
44
45 int Player::init()
46 {
47   if (initted) return 0;
48
49   video = Video::getInstance();
50   audio = Audio::getInstance();
51
52   if (demuxer.init()) // inverted
53   {
54     Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init");
55     shutdown();
56     return 0;
57   }
58
59   vfeed.init(video->getFD());
60   afeed.init(audio->getFD());
61
62   video->stop();
63   video->blank();
64   audio->stop();
65
66   startup = 0;
67   initted = 1;
68   return 1;
69 }
70
71 int Player::shutdown()
72 {
73   if (!initted) return 0;
74   initted = 0;
75
76   Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown...");
77
78   // copy of stop
79   if (playing)
80   {
81     playing = 0;
82     threadStop();
83     video->stop();
84     video->blank();
85     audio->stop();
86     vfeed.stop();
87     afeed.stop();
88     video->reset();
89     demuxer.reset();
90     feedPosition = 0;
91   }
92
93   return 1;
94 }
95
96 int Player::play()
97 {
98   if (!initted) return 0;
99
100   // If we are just paused, unpause!
101   if (paused)
102   {
103     togglePause();
104     return 1;
105   }
106
107   // If we are fast forwarding, set to normal
108   if (ffwd)
109   {
110     toggleFastForward();
111     return 1;
112   }
113
114   // If we are fast backwarding, set to normal
115   if (fbwd)
116   {
117     toggleFastBackward();
118     return 1;
119   }
120
121   // If we are already playing, bail // FIXME - resync?
122   if (playing)
123   {
124     Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC");
125
126 /*
127     vfeed.stop();
128     afeed.stop();
129     video->reset();
130     audio->reset();
131     demuxer.flush();
132     demuxer.seek();
133     vfeed.start();
134     afeed.start();
135
136
137     video->play();
138     audio->play();
139     video->sync();
140     audio->sync();
141     call();
142 */
143
144     // resync method 2..
145
146     video->pause();
147     usleep(500000);
148     video->play();
149     video->sync();
150
151
152     return 1;
153   }
154
155   // Standard play start
156
157   audio->reset();
158   video->reset();
159   demuxer.reset();
160   startup = 1;
161
162 // ------------------------ This one works, but doesn't allow any pre-buffering.
163   threadStart();
164   vfeed.start();
165   afeed.start();
166   audio->play();
167   video->play();
168   video->sync();
169   audio->sync();
170
171   video->pause();
172       usleep(500000); // SYNC
173   video->sync();
174   video->unPause();
175   video->sync();
176
177 // ------------------------ This one doesn't work, but it should, and would allow for prebuffering.
178
179 /*
180
181   threadStart();
182   sleep(2);
183
184 //  struct timespec delay;
185 //  delay.tv_sec = 1;
186 //  delay.tv_nsec = 500000000;
187 //  nanosleep(&delay, NULL);
188
189   vfeed.start();
190   afeed.start();
191   video->play();
192   audio->play();
193   video->sync();
194   audio->sync();
195 */
196 // ------------------------------------------------------------------------------------------------
197
198   playing = 1;
199   return 1;
200 }
201
202 void Player::stop()
203 {
204   if (!initted) return;
205   if (!playing) return;
206
207   if (ffwd || fbwd)
208   {
209     ffwd = 0;
210     fbwd = 0;
211     afeed.enable();
212     video->unFastForward();
213     audio->systemMuteOff();
214     feedMode = MODE_NORMAL;
215   }
216
217   playing = 0;
218
219   threadStop();
220   video->stop();
221   video->blank();
222   audio->stop();
223   vfeed.stop();
224   afeed.stop();
225   video->reset();
226   demuxer.reset();
227
228   feedPosition = 0;
229 }
230
231 void Player::togglePause()
232 {
233   if (!initted) return;
234   if (!playing) return;
235
236   if (ffwd) toggleFastForward();
237   if (fbwd) toggleFastBackward();
238
239   if (paused)
240   {
241     video->unPause();
242     audio->unPause();
243     paused = 0;
244   }
245   else
246   {
247     video->pause();
248     audio->pause();
249     paused = 1;
250   }
251 }
252
253 void Player::test()
254 {
255   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
256
257 /*
258
259 //  video->test();
260
261   static int flipflop = 0;
262
263   int a;
264   if (flipflop) a = video->setAspectRatio(Video::ASPECT16X9);
265   else a = video->setAspectRatio(Video::ASPECT4X3);
266
267   flipflop = !flipflop;
268
269   printf("A = %i\n", a);
270 */
271 }
272
273 void Player::test2()
274 {
275   Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST");
276
277   video->test2();
278 }
279
280 void Player::setPosition(ULLONG position)
281 {
282   feedPosition = position;
283 }
284
285 void Player::setLength(ULLONG length)
286 {
287   streamLength = length;
288   Log::getInstance()->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength);
289 }
290
291 void Player::skipForward(int seconds)
292 {
293   // skip forward 1 minute
294   Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
295
296   if (paused) togglePause();
297
298   ULLONG moveBy = seconds * 500000;
299
300   threadStop();
301   vfeed.stop();
302   afeed.stop();
303   video->stop();
304   video->reset();
305   audio->reset();
306   audio->doMuting();  // ???
307   demuxer.flush();
308   feedPosition += moveBy;
309
310   printf("Audio test %i\n", audio->test());
311
312   vfeed.start();
313   afeed.start();
314   threadStart();
315   audio->play();
316   video->play();
317   video->sync();
318   audio->sync();
319
320   video->pause();
321       usleep(500000); // SYNC
322   video->sync();
323   video->unPause();
324   video->sync();
325
326 }
327
328 void Player::skipBackward(int seconds)
329 {
330   // skip forward 1 minute
331   Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
332
333   if (paused) togglePause();
334
335   ULLONG moveBy = seconds * 500000;
336
337   threadStop();
338   vfeed.stop();
339   afeed.stop();
340   video->stop();
341   audio->stop();
342   video->reset();
343   audio->reset();
344   audio->doMuting(); // ???
345   demuxer.flush();
346   if (feedPosition > moveBy) feedPosition -= moveBy;
347   vfeed.start();
348   afeed.start();
349   threadStart();
350   audio->play();
351   video->play();
352   video->sync();
353   audio->sync();
354
355   video->pause();
356       usleep(500000); // SYNC
357   video->sync();
358   video->unPause();
359   video->sync();
360
361 }
362
363 void Player::toggleFastForward()
364 {
365   if (!initted) return;
366   if (!playing) return;
367
368   if (paused) togglePause();
369   if (fbwd) toggleFastBackward();
370
371   if (ffwd)
372   {
373     ffwd = 0;
374 //    video->unFastForward();
375
376
377     threadStop();
378     vfeed.stop();
379     afeed.stop();
380     video->stop();
381     audio->stop();
382     video->reset();
383     audio->reset();
384     demuxer.flush();
385 //    demuxer.seek();
386     vfeed.start();
387     afeed.enable();
388     afeed.start();
389     threadStart();
390     video->play();
391     audio->play();
392     video->sync();
393     audio->sync();
394
395     audio->systemMuteOff();
396
397     video->pause();
398         usleep(500000); // SYNC
399     video->sync();
400     video->unPause();
401     video->sync();
402
403 /*
404     demuxer.flushAudio();
405     audio->reset();
406     afeed.enable();
407     //video->reset();
408     audio->play();
409     video->play();
410     video->sync();
411     audio->sync();
412     audio->systemMuteOff();
413 */
414   }
415   else
416   {
417     ffwd = 1;
418     afeed.disable();
419     audio->systemMuteOn();
420     video->fastForward();
421   }
422 }
423
424 void Player::toggleFastBackward()
425 {
426   if (!initted) return;
427   if (!playing) return;
428
429   if (paused) togglePause();
430   if (ffwd) toggleFastForward();
431
432   if (fbwd)
433   {
434     fbwd = 0;
435     afeed.enable();
436     audio->systemMuteOff();
437
438 //    threadStop();
439     feedMode = MODE_NORMAL;
440 //    threadStart();
441   }
442   else
443   {
444     fbwd = 1;
445     afeed.disable();
446     audio->systemMuteOn();
447
448     threadStop();
449     feedMode = MODE_BACKWARDS;
450     video->reset();
451     video->play();
452     demuxer.flush();
453     threadStart();
454   }
455 }
456
457 void Player::jumpToPercent(int percent)
458 {
459   threadStop();
460   vfeed.stop();
461   afeed.stop();
462   video->stop();
463   audio->stop();
464   video->reset();
465   audio->reset();
466   demuxer.flush();
467   demuxer.seek();
468   feedPosition = streamLength * percent / 100;
469   vfeed.start();
470   afeed.start();
471   threadStart();
472   audio->play();
473   video->play();
474   video->sync();
475   audio->sync();
476
477   video->pause();
478       usleep(500000); // SYNC
479   video->sync();
480   video->unPause();
481   video->sync();
482 }
483
484
485 void Player::call()
486 {
487   threadSignalNoLock();
488 }
489
490 // Feed thread
491
492 void Player::threadMethod()
493 {
494   UCHAR buf[blockSize];
495   int thisRead;
496   int writeLength;
497   int thisWrite;
498
499   VDR* vdr = VDR::getInstance();
500
501   int askFor;
502   while(1)
503   {
504     thisRead = 0;
505     writeLength = 0;
506     thisWrite = 0;
507
508     threadCheckExit();
509
510     // a bit hackey. this needs to be split to live and rec players
511     if (streamLength && (feedPosition >= streamLength)) break;
512     askFor = blockSize;
513     if (streamLength && ((feedPosition + blockSize) > streamLength))
514     {
515       askFor = streamLength - feedPosition;
516     }
517     thisRead = vdr->getBlock(buf, feedPosition, askFor);
518     if (startup)
519     {
520       int a_stream = demuxer.scan(buf, thisRead);
521       demuxer.setAudioStream(a_stream);
522       Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
523       startup = 0;
524     }
525
526     if (feedMode == MODE_NORMAL)
527     {
528       feedPosition += thisRead;
529     }
530     else if (feedMode == MODE_BACKWARDS)
531     {
532       if (feedPosition >= 100000)
533       {
534         feedPosition -= 100000;
535         demuxer.seek();
536       }
537       else
538       {
539         // got to the start of the recording.. revert to play mode? how?
540         feedPosition += thisRead;
541       }
542     }
543
544     threadCheckExit();
545
546     while(writeLength < thisRead)
547     {
548       thisWrite = demuxer.put(buf + writeLength, thisRead - writeLength);
549       writeLength += thisWrite;
550
551       if (!thisWrite)
552       {
553         Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
554         // demuxer is full and cant take anymore
555         threadWaitForSignal();
556         Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
557       }
558
559       threadCheckExit();
560     }
561   }
562
563   // end of recording
564   Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends");
565   Message* m = new Message();
566   m->message = Message::STOP_PLAYBACK;
567   Log::getInstance()->log("Player", Log::DEBUG, "Posting message...");
568   commandMessageQueue->postMessage(m);
569   Log::getInstance()->log("Player", Log::DEBUG, "Message posted...");
570
571
572 }