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