]> git.vomp.tv Git - vompclient.git/blob - playerlivetv.cc
Compile fixes for stretch
[vompclient.git] / playerlivetv.cc
1 /*
2     Copyright 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "playerlivetv.h"
22
23 #include "defines.h"
24 #include "log.h"
25 #include "audio.h"
26 #include "video.h"
27 #include "demuxerts.h"
28 #include "vdr.h"
29 #include "messagequeue.h"
30 #include "remote.h"
31 #include "message.h"
32 #include "channel.h"
33 #include "dvbsubtitles.h"
34 #include "osdreceiver.h"
35
36 // ----------------------------------- Called from outside, one offs or info funcs
37
38 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* tosdReceiver, ChannelList* tchanList)
39 : vfeed(this), afeed(this), tfeed(this)
40 {
41   messageQueue = tmessageQueue;
42   messageReceiver = tmessageReceiver;
43   osdReceiver = tosdReceiver;
44   chanList = tchanList;
45   
46   audio = Audio::getInstance();
47   video = Video::getInstance();
48   logger = Log::getInstance();
49   vdr = VDR::getInstance();
50   initted = false;
51
52   subtitlesShowing = false;
53   videoStartup = false;
54   pendingAudioPlay = false;
55
56   stopNow = false;
57   state = S_STOP;
58
59   video->turnVideoOn();
60 }
61
62 PlayerLiveTV::~PlayerLiveTV()
63 {
64   if (initted) shutdown();
65 }
66
67 int PlayerLiveTV::init()
68 {
69   if (initted) return 0;
70
71   demuxer = new DemuxerTS();
72   if (!demuxer) return 0;
73   subtitles = new DVBSubtitles(osdReceiver);
74   if (!subtitles) return 0;
75
76   teletext = new TeletextDecoderVBIEBU();
77   
78   unsigned int demux_video_size = 2097152;
79   unsigned int demux_audio_size = 524288;
80
81   if (video->supportsh264())
82   {
83     demux_video_size *= 5 * 1;//5;
84   }
85
86   if (audio->maysupportAc3())
87   {
88     //demux_audio_size*=2;
89   }
90
91   int text_fak = video->getTeletextBufferFaktor();
92
93   if (!demuxer->init(this, audio, video, teletext, demux_video_size, demux_audio_size, 65536 * text_fak, 25./*unimportant*/, subtitles))
94   {
95     logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
96     shutdown();
97     return 0;
98   }
99
100   vfeed.init();
101   afeed.init();
102   tfeed.init();
103
104   video->stop();
105   video->blank();
106   audio->stop();
107
108   initted = true;
109   return 1;
110 }
111
112 int PlayerLiveTV::shutdown()
113 {
114   if (!initted) return 0;
115   logger->log("PlayerLiveTV", Log::DEBUG, "Shutdown");
116   stop();
117   initted = false;
118
119   delete demuxer;
120   delete subtitles;
121   delete teletext;
122   teletext = NULL;
123   return 1;
124 }
125
126 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
127 {
128   return demuxer->getmpAudioChannels();
129 }
130
131 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
132 {
133   return demuxer->getac3AudioChannels();
134 }
135
136 int PlayerLiveTV::getCurrentAudioChannel()
137 {
138   return demuxer->getAID();
139 }
140
141 void PlayerLiveTV::setAudioChannel(int newChannel, int type,int streamtype)
142 {
143   demuxer->setAID(newChannel, type, streamtype, true);
144 }
145
146 void PlayerLiveTV::setSubtitleChannel(int newChannel)
147 {
148   demuxer->setSubID(newChannel);
149 }
150
151 int* PlayerLiveTV::getTeletxtSubtitlePages()
152 {
153   return teletext->getSubtitlePages();
154 }
155
156 int PlayerLiveTV::getCurrentSubtitleChannel()
157 {
158   return demuxer->getSubID();
159 }
160
161 bool PlayerLiveTV::toggleSubtitles()
162 {
163   if (!subtitlesShowing)
164   {
165     subtitlesShowing = true;
166     subtitles->show();
167   }
168   else
169   {
170     subtitlesShowing = false;
171     subtitles->hide();
172   }
173   return subtitlesShowing;
174 }
175
176 void PlayerLiveTV::turnSubtitlesOn(bool ison)
177 {
178   if (ison)
179   {
180     subtitlesShowing = true;
181     subtitles->show();
182   }
183   else
184   {
185     subtitlesShowing = false;
186     subtitles->hide();
187   }
188 }
189
190 void PlayerLiveTV::tellSubtitlesOSDVisible(bool visible)
191 {
192   subtitles->setOSDMenuVisibility(visible);
193 }
194
195 // ----------------------------------- Externally called events
196
197 void PlayerLiveTV::go(ULONG index)
198 {
199   struct PLInstruction i;
200   i.instruction = I_SETCHANNEL;
201   i.channelIndex = index;
202   instructions.push(i);
203   threadStart();
204 }
205
206 void PlayerLiveTV::setChannel(ULONG index)
207 {
208   logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
209   struct PLInstruction i;
210   i.instruction = I_SETCHANNEL;
211   i.channelIndex = index;
212   instructions.push(i);  
213   threadSignalNoLock();
214 }
215
216 void PlayerLiveTV::stop()
217 {
218   logger->log("PlayerLiveTV", Log::DEBUG, "stop");
219   struct PLInstruction i;
220   i.instruction = I_STOP;
221   instructions.push(i);
222   threadSignal();
223   threadStop();
224   logger->log("PlayerLiveTV", Log::DEBUG, "stop succesfull");
225 }
226
227 // ----------------------------------- Callback
228
229 void PlayerLiveTV::call(void* caller)
230 {
231   if (caller == demuxer)
232   {
233     logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
234
235     int parx,pary;
236     int dxCurrentAspect = demuxer->getAspectRatio(&parx, &pary);
237     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
238     {
239       if (video->getTVsize() == Video::ASPECT16X9)
240       {
241         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
242         video->setAspectRatio(Video::ASPECT4X3, parx, pary);
243       }
244       else
245       {
246         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
247       }
248
249       Message* m = new Message();
250       m->from = this;
251       m->to = messageReceiver;
252       m->message = Message::PLAYER_EVENT;
253       m->parameter.num = PlayerLiveTV::ASPECT43;
254       messageQueue->postMessageFromOuterSpace(m);
255     }
256     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
257     {
258       if (video->getTVsize() == Video::ASPECT16X9)
259       {
260         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
261         video->setAspectRatio(Video::ASPECT16X9, parx, pary);
262       }
263       else
264       {
265         logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
266       }    
267
268       Message* m = new Message();
269       m->from = this;
270       m->to = messageReceiver;
271       m->message = Message::PLAYER_EVENT;
272       m->parameter.num = PlayerLiveTV::ASPECT169;
273       messageQueue->postMessageFromOuterSpace(m);
274     }
275     else
276     {
277       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... switch anyway");
278       video->setAspectRatio(dxCurrentAspect, parx, pary);
279     }
280   }
281   else if (caller == &afeed)
282   {
283     if (state == S_VIDEOSTARTUP)
284     {
285       logger->log("PlayerLiveTV", Log::DEBUG, "afeed video startup");
286       videoStartup = true;
287       threadSignalNoLock();
288     }
289   }
290 }
291
292 // -----------------------------------
293
294 void PlayerLiveTV::streamReceive(ULONG flag, void* data, ULONG len)
295 {
296   // Flag:
297   // 0 = normal stream packet
298   // 1 = stream end
299   // 2 = connection lost
300
301   //logger->log("PlayerLiveTV", Log::DEBUG, "Received a streamchunk from VDR, flag = %lu", flag);
302
303   if (flag == 1)
304   {
305     if (data) abort();
306     
307     Message* m = new Message();
308     m->from = this;
309     m->to = messageReceiver;
310     m->message = Message::PLAYER_EVENT;
311     m->parameter.num = PlayerLiveTV::STREAM_END;
312     messageQueue->postMessageFromOuterSpace(m);
313   }
314         
315   if (streamChunks.size() < PLAYER_MAX_STREAMING_BUFFERS)
316   {
317     StreamChunk s;
318     s.data = data;
319     s.len = len;
320     streamChunks.push(s);
321     threadSignalNoLock();
322   }
323   else
324   {
325     // Too many chunks in streamChunks, drop this chunk
326     free(data);
327     logger->log("PlayerLiveTV", Log::WARN, "Dropped chunk");
328   }
329 }
330
331 void PlayerLiveTV::clearStreamChunks()
332 {
333   while(streamChunks.size())
334   {
335     logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
336     struct StreamChunk s = streamChunks.front();
337     streamChunks.pop();
338     free(s.data);
339   }
340 }
341
342 void PlayerLiveTV::chunkToDemuxer()
343 {
344   StreamChunk s = streamChunks.front();
345   streamChunks.pop();
346 //  logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
347  /* int a =*/ demuxer->put((UCHAR*)s.data, s.len);
348 //  logger->log("PlayerLiveTV", Log::DEBUG, "put %i to demuxer", a);
349   free(s.data);  
350   if (pendingAudioPlay && (demuxer->getHorizontalSize() || !video->independentAVStartUp())) //Horizontal Size is zero, if not parsed
351   {
352     video->sync();
353     video->play();
354     video->pause();
355     //audio->setStreamType(Audio::MPEG2_PES);
356     audio->sync();
357     audio->play();
358     audio->pause();
359     pendingAudioPlay = false;
360   }
361 }
362
363 void PlayerLiveTV::switchState(UCHAR newState)
364 {
365   logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
366
367   switch(state)
368   {
369     case S_STOP:   // FROM S_STOP
370     {
371       switch(newState)
372       {
373         case S_VIDEOSTARTUP:
374         {
375           video->blank();
376           video->reset();
377           //video->sync();
378           //video->play();
379           //video->pause();
380
381           audio->stop();
382           audio->unPause();
383           audio->reset();
384           //audio->setStreamType(Audio::MPEG2_PES);
385           //audio->sync();
386           // I make this modification, since the video/audio devices needs to know at least
387           // which kind of video is embedded inside the stream
388           // therefore the demuxer needs to feeded at least with enough data
389           // to have one video header
390           // This is crucial, if we have mixed h264/mpeg2 channels
391           // the information from channels is not enough since some directshow decoders need
392           // width and height information before startup
393           pendingAudioPlay = true;
394
395           //audio->play();
396           //audio->pause();
397
398           demuxer->reset();
399           demuxer->seek();
400
401           afeed.start();
402           vfeed.start();
403           subtitles->start();
404           tfeed.start();
405           
406           state = newState;
407           if (!video->independentAVStartUp())
408           {
409             videoStartup = true;
410             threadSignalNoLock();
411           }
412           return;
413         }
414         default:
415         {
416           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
417           abort();
418           break;
419         }
420       }
421     }
422
423     case S_VIDEOSTARTUP:     // FROM S_VIDEOSTARTUP
424     {
425       switch(newState)
426       {
427         case S_PREBUFFERING:
428         {
429           pendingAudioPlay=false;
430           vfeed.release();
431           state = newState;
432           return;
433         }
434         
435         case S_VIDEOSTARTUP:
436         {
437           vdr->stopStreaming();
438           clearStreamChunks(); 
439           vfeed.stop();
440           afeed.stop();
441           subtitles->stop();
442           tfeed.stop();
443                            
444           video->blank();
445           video->reset();
446           //video->sync();
447           //video->play();
448           //video->pause();
449           audio->stop();
450           audio->unPause();
451           audio->reset();
452           //audio->setStreamType(Audio::MPEG2_PES);
453           //audio->sync();
454           pendingAudioPlay = true;
455           //audio->play();
456           //audio->pause();
457
458           demuxer->reset();
459           demuxer->seek();
460
461           afeed.start();
462           vfeed.start();
463           subtitles->start();     
464           tfeed.start();
465           state = newState;
466           if (!video->independentAVStartUp())
467           {
468             videoStartup = true;
469             threadSignalNoLock();
470           }
471           return;
472         }        
473         case S_STOP:
474         { 
475           vdr->stopStreaming();
476           pendingAudioPlay=false;
477           clearStreamChunks();
478           vfeed.stop();
479           afeed.stop();
480           subtitles->stop();
481           tfeed.stop();
482           video->stop();
483           video->blank();
484           audio->stop();
485           audio->reset();
486           video->reset();
487           state = newState;
488           return;
489         }
490         default:
491         {
492           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
493           abort();
494           break;
495         }        
496       }
497     }
498     
499     case S_PREBUFFERING:    // FROM S_PREBUFFERING
500     {
501       switch(newState)
502       {
503         case S_PLAY:
504         {
505           pendingAudioPlay=false;
506           audio->unPause();
507           video->unPause();
508           state = newState;
509           return;
510         }
511         case S_VIDEOSTARTUP:
512         {
513           vdr->stopStreaming();
514           clearStreamChunks();
515           vfeed.stop();
516           afeed.stop();
517           subtitles->stop();
518           tfeed.stop();
519           video->stop();
520           video->blank();
521           audio->stop();
522           audio->unPause();
523           audio->reset();
524
525           video->reset();
526           //video->sync();
527           //video->play();
528           //video->pause();
529
530           //audio->setStreamType(Audio::MPEG2_PES);
531           //audio->sync();
532           pendingAudioPlay = true;
533           //audio->play();
534           //audio->pause();
535
536           demuxer->reset();
537           demuxer->seek();
538
539           afeed.start();
540           vfeed.start();
541           subtitles->start();
542           tfeed.start();
543
544           state = newState;
545           return;
546         }
547         case S_STOP:
548         {
549           pendingAudioPlay=false;
550           vdr->stopStreaming();
551           clearStreamChunks();
552           vfeed.stop();
553           afeed.stop();
554           subtitles->stop();
555           tfeed.stop();
556           video->stop();
557           video->blank();
558           audio->stop();
559           audio->reset();
560           video->reset();
561           state = newState;
562           return;        
563         }
564         default:
565         {
566           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
567           abort();
568           break;
569         }        
570       }
571     }
572     
573     case S_PLAY:     // FROM S_PLAY
574     {
575       switch(newState)
576       {
577         case S_STOP:
578         { 
579           pendingAudioPlay=false;
580           vdr->stopStreaming();
581           clearStreamChunks();
582           vfeed.stop();
583           afeed.stop();
584           subtitles->stop();
585           tfeed.stop();
586           video->stop();
587           video->blank();
588           audio->stop();
589           audio->reset();
590           video->reset();
591           state = newState;
592           return;
593         }
594         case S_VIDEOSTARTUP:
595         {
596           vdr->stopStreaming();
597           clearStreamChunks();
598           vfeed.stop();
599           afeed.stop();
600           subtitles->stop();
601           tfeed.stop();
602           video->stop();
603           video->blank();
604           audio->stop();
605           audio->unPause();
606           audio->reset();
607
608           video->reset();
609           
610           //video->sync();
611          // video->play();
612           //video->pause();
613
614           //audio->setStreamType(Audio::MPEG2_PES);
615           //audio->sync();
616           //audio->play();
617           //audio->pause();
618           pendingAudioPlay = true;
619           demuxer->reset();
620           demuxer->seek();
621
622           afeed.start();
623           vfeed.start();
624           subtitles->start();
625           tfeed.start();
626           state = newState;
627           if (!video->independentAVStartUp())
628           {
629             videoStartup = true;
630             threadSignalNoLock();
631           }
632           return;
633         }
634         default:
635         {
636           logger->log("PlayerLiveTV", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
637           abort();
638           break;
639         }
640       }
641     }    
642   }  
643 }
644
645 bool PlayerLiveTV::checkError()
646 {
647   if (!vdr->isConnected())
648   {
649     if (state != S_STOP) switchState(S_STOP);
650     
651     Message* m = new Message();
652     m->from = this;
653     m->to = messageReceiver;
654     m->message = Message::PLAYER_EVENT;
655     m->parameter.num = PlayerLiveTV::CONNECTION_LOST;
656     messageQueue->postMessageFromOuterSpace(m);
657     
658     return true;
659   }   
660   return false;
661 }
662
663 void PlayerLiveTV::optimizeInstructionQueue()
664 {
665   // Walk the list
666   
667   // Currently there are only 2 instruction types, so this is a bit overkill...
668
669   struct PLInstruction i;
670   while(instructions.size() > 1)
671   {
672     i = instructions.front();
673     if (i.instruction == I_SETCHANNEL)
674     {
675       instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
676     }
677     else if (i.instruction == I_STOP)
678     {
679       return; // return here and ensure the next instruction will be stop
680     }
681   }
682 }
683
684 void PlayerLiveTV::threadMethod()
685 {
686   while(1)
687   {
688     //logger->log("PlayerLiveTV", Log::DEBUG, "VS: %d pA %d",videoStartup,pendingAudioPlay);
689     if (videoStartup && !pendingAudioPlay) // we are in S_VIDEOSTARTUP, afeed has signalled that it has written some data
690     {
691       logger->log("PlayerLiveTV", Log::DEBUG, "Enter prebuffering");
692       switchState(S_PREBUFFERING);
693       videoStartup = false;
694       preBufferCount = 0;
695       checkError();
696     }  
697   
698     while(!instructions.empty())
699     {
700       if (instructions.size() > 1) optimizeInstructionQueue();
701
702       struct PLInstruction i = instructions.front();
703       instructions.pop();
704     
705       if (i.instruction == I_SETCHANNEL)
706       {
707         logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
708         
709         switchState(S_VIDEOSTARTUP);
710         
711         if (!checkError())
712         {
713                 Channel* chan = (*chanList)[i.channelIndex];
714                 chan->loadPids();
715                 h264=chan->vstreamtype==0x1b;
716                 demuxer->seth264(h264);
717                 video->seth264mode(chan->vstreamtype==0x1b);
718                 demuxer->setVID(chan->vpid);
719                 video->seth264mode(chan->vstreamtype==0x1b);
720
721                 bool dolby=false;
722                 int selected=-1;
723                 int prefered=-1;
724                 Command* command = Command::getInstance();
725
726                 if (chan->numDPids > 0 && audio->maysupportAc3())
727                 {
728                         ULONG j = 0;
729                         while (j < chan->numDPids)
730                         {
731                                 int newpref = command->getLangPref(false, chan->dpids[j].desc);
732                                 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type)
733                                                 && (prefered < 0 || newpref < prefered))
734                                 {
735                                         selected = j;
736                                         dolby=true;
737                                         prefered = newpref;
738                                 }
739                                 j++;
740                         }
741                 }
742
743
744
745                 if (chan->numAPids > 0)
746                 {
747                         ULONG j = 0;
748                         while (j < chan->numAPids)
749                         {
750                                 int newpref = command->getLangPref(false, chan->apids[j].desc);
751                                 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type)
752                                                 && (prefered < 0 || newpref < prefered))
753                                 {
754                                         selected = j;
755                                         dolby=false;
756                                         prefered = newpref;
757                                 }
758                                 j++;
759                         }
760                 }
761
762
763                 if (selected >= 0) {
764                         if (dolby) {
765                                 demuxer->setAID(chan->dpids[selected].pid, 1, chan->dpids[selected].type, true);
766                                 audio->setStreamType(Audio::MPEG2_PES);
767                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u",
768                                                 chan->vpid, chan->dpids[selected].pid, chan->dpids[selected].type);
769                         } else {
770                                 demuxer->setAID(chan->apids[selected].pid, 0, chan->apids[selected].type, true);
771                                 audio->setStreamType(Audio::MPEG2_PES);
772                                 logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[selected].pid,
773                                                 chan->apids[selected].type);
774                         }
775
776                 } else {
777                         logger->log("PlayerLiveTV", Log::WARN, "Demuxer video pid only: %u", chan->vpid);
778                 }
779
780
781                 selected = -1;
782                 prefered=-1;
783                 if (chan->numSPids) {
784                         ULONG j = 0;
785                         while (j < chan->numSPids)
786                         {
787                                 int newpref = command->getLangPref(true, chan->spids[j].desc);
788                                 if ( (prefered < 0 || newpref < prefered))
789                                 {
790                                         selected = j;
791                                         prefered = newpref;
792                                 }
793                                 j++;
794                         }
795                 }
796
797                 if (selected >= 0) {
798                         demuxer->setSubID(chan->spids[selected].pid);
799                         if (command->getSubDefault()) {
800                                 turnSubtitlesOn(true);
801                         } else {
802                                 turnSubtitlesOn(false);
803                         }
804                 }
805
806                 demuxer->setTID(chan->tpid);
807                 teletext->ResetDecoder();
808                 int streamSuccess = vdr->streamChannel(chan->number, this);
809                 if (!checkError() && !streamSuccess)
810                 {
811                         Message* m = new Message();
812                         m->from = this;
813                         m->to = messageReceiver;
814                         m->message = Message::PLAYER_EVENT;
815                         m->parameter.num = PlayerLiveTV::STREAM_END;
816                         messageQueue->postMessageFromOuterSpace(m);
817                 }
818         }
819       }
820       else if (i.instruction == I_STOP)
821       {
822           logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
823           switchState(S_STOP);
824           checkError();
825
826           stopNow = true;
827           break;
828       }
829     }
830
831     threadCheckExit();
832
833     if (stopNow) break;
834
835     while(streamChunks.size())
836     {
837       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark1 %d", streamChunks.size());
838       chunkToDemuxer();
839       //logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark2 %d", streamChunks.size());
840
841       if (state == S_PREBUFFERING)
842       {
843         // logger->log("PlayerLiveTV", Log::DEBUG, "chunk mark3");
844         ++preBufferCount;
845         ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
846         logger->log("PlayerLiveTV", Log::DEBUG, "Prebuffering %lu%%", percentDone);
847         
848         Message* m = new Message();
849         m->from = this;
850         m->to = messageReceiver;
851         m->message = Message::PLAYER_EVENT;
852         m->parameter.num = PlayerLiveTV::PREBUFFERING;
853         m->tag = percentDone;
854         messageQueue->postMessageFromOuterSpace(m);
855
856         if (preBufferCount == preBufferAmount)
857         {
858           switchState(S_PLAY);
859           checkError();
860         }
861       }
862     }
863     //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal %d", streamChunks.size());
864     threadLock();
865     threadWaitForSignal(); // unlocks and waits for signal
866     threadUnlock();
867     //logger->log("PlayerLiveTV", Log::DEBUG, "wait for signal2 %d",streamChunks.size());
868   }
869
870   logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
871 }