]> git.vomp.tv Git - vompclient.git/blob - playerlivetv.cc
Live TV update
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "playerlivetv.h"
22
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 "remote.h"
30 #include "message.h"
31 #include "channel.h"
32
33 // ----------------------------------- Called from outside, one offs or info funcs
34
35 PlayerLiveTV::PlayerLiveTV(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
36 : vfeed(this), afeed(this)
37 {
38   messageQueue = tmessageQueue;
39   messageReceiver = tmessageReceiver;
40   chanList = tchanList;
41   
42   audio = Audio::getInstance();
43   video = Video::getInstance();
44   logger = Log::getInstance();
45   vdr = VDR::getInstance();
46   initted = false;
47
48 //  videoStartup = false;
49 //  preBuffering = false;
50
51   stopNow = false;
52   state = 1;
53
54   video->turnVideoOn();
55 }
56
57 PlayerLiveTV::~PlayerLiveTV()
58 {
59   if (initted) shutdown();
60 }
61
62 int PlayerLiveTV::init()
63 {
64   if (initted) return 0;
65
66   demuxer = new DemuxerTS();
67   if (!demuxer) return 0;
68  
69   if (!demuxer->init(this, audio, video, 2097152, 524288))
70   {
71     logger->log("PlayerLiveTV", Log::ERR, "Demuxer failed to init");
72     shutdown();
73     return 0;
74   }
75
76   vfeed.init();
77   afeed.init();
78
79   video->stop();
80   video->blank();
81   audio->stop();
82
83   initted = true;
84   return 1;
85 }
86
87 int PlayerLiveTV::shutdown()
88 {
89   if (!initted) return 0;
90   stop();
91   initted = false;
92
93   delete demuxer;
94
95 #ifdef WIN32
96   CloseHandle(mutex);
97 #endif
98
99   return 1;
100 }
101
102 bool* PlayerLiveTV::getDemuxerMpegAudioChannels()
103 {
104   return demuxer->getmpAudioChannels();
105 }
106
107 bool* PlayerLiveTV::getDemuxerAc3AudioChannels()
108 {
109   return demuxer->getac3AudioChannels();
110 }
111
112 int PlayerLiveTV::getCurrentAudioChannel()
113 {
114   return demuxer->getAID();
115 }
116
117 void PlayerLiveTV::setAudioChannel(int newChannel)
118 {
119   return demuxer->setAID(newChannel);
120 }
121
122 // ----------------------------------- Externally called events
123
124 void PlayerLiveTV::go(ULONG index)
125 {
126   struct PLTVInstruction i;
127   i.instruction = 1;
128   i.channelIndex = index;
129   instructions.push(i);
130   
131   threadStart();
132 }
133
134 void PlayerLiveTV::setChannel(ULONG index)
135 {
136 //  demuxer->setVID(Vpid);
137 //  demuxer->setAID(Apid);
138 //  play();
139   logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
140   
141   struct PLTVInstruction i;
142   i.instruction = 1;
143   i.channelIndex = index;
144   instructions.push(i);  
145   
146   threadSignalNoLock();
147 }
148
149 void PlayerLiveTV::stop()
150 {
151   logger->log("PlayerLiveTV", Log::DEBUG, "stop");
152
153   struct PLTVInstruction i;
154   i.instruction = 2;
155   instructions.push(i);
156   
157   logger->log("PlayerLiveTV", Log::DEBUG, "Pushed instruction");
158
159   threadSignal();
160
161   logger->log("PlayerLiveTV", Log::DEBUG, "Signal sent");
162
163   threadStop();
164
165   logger->log("PlayerLiveTV", Log::DEBUG, "Stop returning");
166 }
167
168 // ----------------------------------- Callback
169
170 void PlayerLiveTV::call(void* caller)
171 {
172   if (caller == demuxer)
173   {
174     logger->log("PlayerLiveTV", Log::DEBUG, "Callback from demuxer");
175
176     if (video->getTVsize() == Video::ASPECT4X3)
177     {
178       logger->log("PlayerLiveTV", Log::DEBUG, "TV is 4:3, ignoring aspect switching");
179       return;
180     }
181
182     int dxCurrentAspect = demuxer->getAspectRatio();
183     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
184     {
185       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
186       video->setAspectRatio(Video::ASPECT4X3);
187
188       Message* m = new Message();
189       m->from = this;
190       m->to = messageReceiver;
191       m->message = Message::PLAYER_EVENT;
192       m->parameter = PlayerLiveTV::ASPECT43;
193       messageQueue->postMessageFromOuterSpace(m);
194     }
195     else if (dxCurrentAspect == Demuxer::ASPECT_16_9)
196     {
197       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is 16:9 aspect, switching TV");
198       video->setAspectRatio(Video::ASPECT16X9);
199
200       Message* m = new Message();
201       m->from = this;
202       m->to = messageReceiver;
203       m->message = Message::PLAYER_EVENT;
204       m->parameter = PlayerLiveTV::ASPECT169;
205       messageQueue->postMessageFromOuterSpace(m);
206     }
207     else
208     {
209       logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer said video is something else... ignoring");
210     }
211
212   }
213   else
214   {
215     if (videoStartup)
216     {
217       logger->log("PlayerLiveTV", Log::DEBUG, "Video startup");
218       videoStartup = false;
219       video->reset();
220       video->play();
221       video->sync();
222       vfeed.release();
223     }
224
225     threadSignalNoLock();
226   }
227 }
228
229 // -----------------------------------
230
231 void PlayerLiveTV::streamReceive(void* data, ULONG len)
232 {
233   logger->log("PlayerLiveTV", Log::DEBUG, "Got data, %p, %lu", data, len);
234   
235
236   if (streamChunks.size() < 11)
237   {
238     StreamChunk s;
239     s.data = data;
240     s.len = len;
241     streamChunks.push(s);
242     threadSignalNoLock();
243   }
244   else
245
246   {
247     // Too many chunks in streamChunks, drop this chunk
248     free(data);
249     logger->log("PlayerLiveTV", Log::DEBUG, "Dropped chunk");
250   }
251 }
252
253 void PlayerLiveTV::clearStreamChunks()
254 {
255   while(streamChunks.size())
256   {
257     logger->log("PlayerLiveTV", Log::DEBUG, "Dropping chunk from old stream");
258     struct StreamChunk s = streamChunks.front();
259     streamChunks.pop();
260     free(s.data);
261   }
262 }
263
264 void PlayerLiveTV::chunkToDemuxer()
265 {
266   StreamChunk s = streamChunks.front();
267   streamChunks.pop();
268   logger->log("PlayerLiveTV", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
269   demuxer->put((UCHAR*)s.data, s.len);
270   free(s.data);  
271 }
272
273 void PlayerLiveTV::switchState(UCHAR newState)
274 {
275   logger->log("PlayerLiveTV", Log::DEBUG, "Switch from state %u to state %u", state, newState);
276
277   switch(state)
278   {
279     case S_STOP:   // FROM S_STOP
280     {
281       switch(newState)
282       {
283         case S_STOP:
284         {
285           abort();
286         }
287         case S_PREBUFFERING:
288         {
289           break;
290         }
291         case S_PLAY:
292         {
293           abort();
294         }
295       }
296       break;
297     }
298     
299     case S_PREBUFFERING:    // FROM S_PREBUFFERING
300     {
301       switch(newState)
302       {
303         case S_STOP:
304         {
305           vdr->stopStreaming();
306           clearStreamChunks();
307           break;
308         }      
309         case S_PREBUFFERING:
310         {
311           vdr->stopStreaming();
312           clearStreamChunks();
313           break;
314         }
315         case S_PLAY:
316         {
317           videoStartup = true;
318
319           audio->reset();
320           audio->setStreamType(Audio::MPEG2_PES);
321           audio->systemMuteOff();
322           video->reset();
323           demuxer->reset();
324           demuxer->seek();
325           
326           audio->sync();
327           audio->play();
328           video->sync();
329           video->pause();
330           afeed.start();
331           vfeed.start();
332           break;
333         }
334       }
335       break;
336     }
337     
338     case S_PLAY:     // FROM S_PLAY
339     {
340       switch(newState)
341       {
342         case S_STOP:
343         { 
344           vdr->stopStreaming();
345           clearStreamChunks();
346           vfeed.stop();
347           afeed.stop();
348           video->stop();
349           video->blank();
350           audio->stop();
351           audio->unPause();
352           video->reset();
353           break;
354         }
355         case S_PREBUFFERING:
356         {
357           vdr->stopStreaming();
358           clearStreamChunks();
359           vfeed.stop();
360           afeed.stop();
361           video->stop();
362           video->blank();
363           audio->stop();
364           audio->unPause();
365           video->reset();
366           demuxer->reset();
367           break;
368         }
369         case S_PLAY:
370         {
371           abort();
372         }
373       }
374       break;
375     }    
376   }  
377   
378   state = newState;
379 }
380
381 void PlayerLiveTV::threadMethod()
382 {
383   logger->log("PlayerLiveTV", Log::DEBUG, "Thread started");
384
385   while(1)
386   {
387     while(!instructions.empty())
388     {
389       struct PLTVInstruction i = instructions.front();
390       instructions.pop();
391     
392       logger->log("PlayerLiveTV", Log::DEBUG, "%u %lu", i.instruction, i.channelIndex);
393       
394
395       if (i.instruction == 1)
396       {
397         logger->log("PlayerLiveTV", Log::DEBUG, "start new stream");
398
399         switchState(S_PREBUFFERING);
400
401         Channel* chan = (*chanList)[i.channelIndex];
402         chan->loadPids();
403         demuxer->setVID(chan->vpid);
404         demuxer->setAID(chan->apids[0].pid);
405         logger->log("PlayerLiveTV", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
406         vdr->streamChannel(chan->number, this);
407         
408       }
409       else if (i.instruction == 2)
410       {
411         logger->log("PlayerLiveTV", Log::DEBUG, "Stopping");
412         switchState(S_STOP);
413
414         stopNow = true;
415         break;
416       }
417     }
418
419     if (stopNow) break;
420
421     if (streamChunks.size())
422     {
423       if (state == S_PREBUFFERING)
424       {
425         if (streamChunks.size() > 4)
426         {
427           while(streamChunks.size()) chunkToDemuxer();
428           switchState(S_PLAY);
429         }
430       }
431       else if (state == S_PLAY)
432       {
433         while(streamChunks.size()) chunkToDemuxer();
434       }
435     }
436     
437     threadLock();
438     threadWaitForSignal(); // unlocks and waits for signal
439     
440     threadUnlock();
441     logger->log("PlayerLiveTV", Log::DEBUG, "Woken");
442   }
443
444   logger->log("PlayerLiveTV", Log::DEBUG, "End of thread");
445 }
446
447 void PlayerLiveTV::threadPostStopCleanup()
448 {
449   logger->log("PlayerLiveTV", Log::DEBUG, "Post stop cleanup");
450 }
451
452 // ----------------------------------- Dev
453
454 #ifdef DEV
455 void PlayerLiveTV::test1()
456 {
457   logger->log("PlayerLiveTV", Log::DEBUG, "PLAYER TEST 1");
458 }
459
460 void PlayerLiveTV::test2()
461 {
462   logger->log("PlayerLiveTV", Log::DEBUG, "PLAYER TEST 2");
463 }
464 #endif
465