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