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