]> git.vomp.tv Git - vompclient-marten.git/blob - playerliveradio.cc
Remove a couple of log lines
[vompclient-marten.git] / playerliveradio.cc
1 /*
2     Copyright 2008 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 "playerliveradio.h"
22
23 #include "log.h"
24 #include "audio.h"
25 #include "demuxerts.h"
26 #include "vdr.h"
27 #include "messagequeue.h"
28 #include "remote.h"
29 #include "message.h"
30 #include "channel.h"
31 #include "video.h"
32
33 // ----------------------------------- Called from outside, one offs or info funcs
34
35 PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
36 : afeed(this)
37 {
38   messageQueue = tmessageQueue;
39   messageReceiver = tmessageReceiver;
40   chanList = tchanList;
41   
42   audio = Audio::getInstance();
43   logger = Log::getInstance();
44   vdr = VDR::getInstance();
45   initted = false;
46
47   stopNow = false;
48   state = S_STOP;
49   Video::getInstance()->turnVideoOff();
50 }
51
52 PlayerLiveRadio::~PlayerLiveRadio()
53 {
54   if (initted) shutdown();
55 }
56
57 int PlayerLiveRadio::init()
58 {
59   if (initted) return 0;
60
61   demuxer = new DemuxerTS();
62   if (!demuxer) return 0;
63  
64   if (!demuxer->init(this, audio, NULL, 0, 200000))
65   {
66     logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
67     shutdown();
68     return 0;
69   }
70
71   afeed.init();
72   audio->stop();
73
74   initted = true;
75   return 1;
76 }
77
78 int PlayerLiveRadio::shutdown()
79 {
80   if (!initted) return 0;
81   stop();
82   initted = false;
83
84   delete demuxer;
85
86
87
88   return 1;
89 }
90
91 bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
92 {
93   return demuxer->getmpAudioChannels();
94 }
95
96 bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
97 {
98   return demuxer->getac3AudioChannels();
99 }
100
101 int PlayerLiveRadio::getCurrentAudioChannel()
102 {
103   return demuxer->getAID();
104 }
105
106 void PlayerLiveRadio::setAudioChannel(int newChannel, int type)
107 {
108   return demuxer->setAID(newChannel, type);
109 }
110
111 // ----------------------------------- Externally called events
112
113 void PlayerLiveRadio::go(ULONG index)
114 {
115   struct PLInstruction i;
116   i.instruction = I_SETCHANNEL;
117   i.channelIndex = index;
118   instructions.push(i);
119   threadStart();
120 }
121
122 void PlayerLiveRadio::setChannel(ULONG index)
123 {
124   logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");
125   struct PLInstruction i;
126   i.instruction = I_SETCHANNEL;
127   i.channelIndex = index;
128   instructions.push(i);  
129   logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
130   threadSignalNoLock();
131 }
132
133 void PlayerLiveRadio::stop()
134 {
135   logger->log("PlayerLiveRadio", Log::DEBUG, "stop");
136   struct PLInstruction i;
137   i.instruction = I_STOP;
138   instructions.push(i);
139   threadSignal();
140   threadStop();
141 }
142
143 // ----------------------------------- Callback
144
145 void PlayerLiveRadio::call(void* caller)
146 {
147 }
148
149 // -----------------------------------
150
151 void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)
152 {
153   if (streamChunks.size() < 11)
154   {
155     StreamChunk s;
156     s.data = data;
157     s.len = len;
158     streamChunks.push(s);
159     threadSignalNoLock();
160   }
161   else
162   {
163     // Too many chunks in streamChunks, drop this chunk
164     free(data);
165     logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");
166   }
167 }
168
169 void PlayerLiveRadio::clearStreamChunks()
170 {
171   while(streamChunks.size())
172   {
173     logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");
174     struct StreamChunk s = streamChunks.front();
175     streamChunks.pop();
176     free(s.data);
177   }
178 }
179
180 void PlayerLiveRadio::chunkToDemuxer()
181 {
182   StreamChunk s = streamChunks.front();
183   streamChunks.pop();
184   logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
185   int a = demuxer->put((UCHAR*)s.data, s.len);
186   logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);
187   free(s.data);  
188 }
189
190 void PlayerLiveRadio::switchState(UCHAR newState)
191 {
192   logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);
193
194   switch(state)
195   {
196     case S_STOP:   // FROM S_STOP
197     {
198       switch(newState)
199       {
200         case S_PREBUFFERING:
201         {
202           audio->stop();
203           audio->unPause();
204           audio->reset();
205           audio->setStreamType(Audio::MPEG2_PES);
206           audio->systemMuteOff();      
207           audio->doMuting();              
208           audio->play();
209           audio->pause();
210           demuxer->reset();
211           afeed.start();
212           
213           state = newState;
214           preBufferCount = 0;
215           return;
216         }
217         default:
218         {
219           logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
220           abort();
221           break;
222         }
223       }
224     }
225
226     case S_PREBUFFERING:    // FROM S_PREBUFFERING
227     {
228       switch(newState)
229       {
230         case S_PLAY:
231         {
232           audio->unPause();
233           state = newState;
234           return;
235         }
236         case S_STOP:
237         {
238           vdr->stopStreaming();
239           clearStreamChunks();
240           afeed.stop();
241           audio->stop();
242           audio->reset();
243           state = newState;
244           return;        
245         }
246         case S_PREBUFFERING:
247         {
248           vdr->stopStreaming();
249           clearStreamChunks();
250           afeed.stop();
251           audio->stop();
252           audio->reset();
253           audio->play();
254           audio->pause();
255           demuxer->reset();
256           afeed.start();
257
258           state = newState;
259           preBufferCount = 0;
260           return;        
261         }
262         default:
263         {
264           logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
265           abort();
266           break;
267         }        
268       }
269     }
270     
271     case S_PLAY:     // FROM S_PLAY
272     {
273       switch(newState)
274       {
275         case S_STOP:
276         { 
277           vdr->stopStreaming();
278           clearStreamChunks();
279           afeed.stop();
280           audio->stop();
281           audio->reset();
282           state = newState;
283           return;
284         }
285         case S_PREBUFFERING: // IS THIS HOW IT WORKS?
286         {
287           vdr->stopStreaming();
288           clearStreamChunks();
289           afeed.stop();
290           audio->stop();
291           audio->reset();
292           audio->play();
293           audio->pause();
294           demuxer->reset();
295           afeed.start();
296
297           state = newState;
298           preBufferCount = 0;
299           return;
300         }
301         default:
302         {
303           logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
304           abort();
305           break;
306         }        
307       }
308     }    
309   }  
310 }
311
312 void PlayerLiveRadio::optimizeInstructionQueue()
313 {
314   // Walk the list
315   
316   // Currently there are only 2 instruction types, so this is a bit overkill...
317
318   struct PLInstruction i;
319   while(instructions.size() > 1)
320   {
321     i = instructions.front();
322     if (i.instruction == I_SETCHANNEL)
323     {
324       logger->log("PlayerLiveRadio", Log::DEBUG, "Optimised out setch to %i", i.channelIndex);
325       instructions.pop();  // if this is the first of more than 1 command, currently it cannot possibly be relevant
326     }
327     else if (i.instruction == I_STOP)
328     {
329       return; // return here and ensure the next instruction will be stop
330     }
331   }
332 }
333
334 void PlayerLiveRadio::threadMethod()
335 {
336   while(1)
337   {
338     while(!instructions.empty())
339     {
340       if (instructions.size() > 1)
341       {
342         logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");
343         optimizeInstructionQueue();
344       }
345
346       struct PLInstruction i = instructions.front();
347       instructions.pop();
348     
349       if (i.instruction == I_SETCHANNEL)
350       {
351         logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
352
353         switchState(S_PREBUFFERING);
354
355         Channel* chan = (*chanList)[i.channelIndex];
356         chan->loadPids();
357
358         if (chan->numAPids > 0) 
359         {
360           demuxer->setAID(chan->apids[0].pid,0);
361           logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
362         }
363         else 
364         {
365           logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
366         }
367
368         vdr->streamChannel(chan->number, this);
369       }
370       else if (i.instruction == I_STOP)
371       {
372         logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
373         switchState(S_STOP);
374
375         stopNow = true;
376         break;
377       }
378     }
379
380     if (stopNow) break;
381
382     while(streamChunks.size())
383     {
384       chunkToDemuxer();
385
386       if (state == S_PREBUFFERING)
387       {        
388         if (++preBufferCount == preBufferAmount)
389         {
390           switchState(S_PLAY);
391         }
392       }
393     }
394     
395     threadLock();
396     threadWaitForSignal(); // unlocks and waits for signal
397     threadUnlock();
398   }
399
400   logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");
401 }
402