2 Copyright 2008 Chris Tallon
4 This file is part of VOMP.
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.
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.
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.
21 #include "playerliveradio.h"
25 #include "demuxerts.h"
27 #include "messagequeue.h"
32 // ----------------------------------- Called from outside, one offs or info funcs
34 PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
37 messageQueue = tmessageQueue;
38 messageReceiver = tmessageReceiver;
41 audio = Audio::getInstance();
42 logger = Log::getInstance();
43 vdr = VDR::getInstance();
50 PlayerLiveRadio::~PlayerLiveRadio()
52 if (initted) shutdown();
55 int PlayerLiveRadio::init()
57 if (initted) return 0;
59 demuxer = new DemuxerTS();
60 if (!demuxer) return 0;
62 if (!demuxer->init(this, audio, NULL, 0, 40000))
64 logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
76 int PlayerLiveRadio::shutdown()
78 if (!initted) return 0;
91 bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
93 return demuxer->getmpAudioChannels();
96 bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
98 return demuxer->getac3AudioChannels();
101 int PlayerLiveRadio::getCurrentAudioChannel()
103 return demuxer->getAID();
106 void PlayerLiveRadio::setAudioChannel(int newChannel)
108 return demuxer->setAID(newChannel);
111 // ----------------------------------- Externally called events
113 void PlayerLiveRadio::go(ULONG index)
115 struct PLInstruction i;
116 i.instruction = I_SETCHANNEL;
117 i.channelIndex = index;
118 instructions.push(i);
122 void PlayerLiveRadio::setChannel(ULONG index)
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 threadSignalNoLock();
132 void PlayerLiveRadio::stop()
134 logger->log("PlayerLiveRadio", Log::DEBUG, "stop");
135 struct PLInstruction i;
136 i.instruction = I_STOP;
137 instructions.push(i);
142 // ----------------------------------- Callback
144 void PlayerLiveRadio::call(void* caller)
148 // -----------------------------------
150 void PlayerLiveRadio::streamReceive(void* data, ULONG len)
152 if (streamChunks.size() < 11)
157 streamChunks.push(s);
158 threadSignalNoLock();
162 // Too many chunks in streamChunks, drop this chunk
164 logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");
168 void PlayerLiveRadio::clearStreamChunks()
170 while(streamChunks.size())
172 logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");
173 struct StreamChunk s = streamChunks.front();
179 void PlayerLiveRadio::chunkToDemuxer()
181 StreamChunk s = streamChunks.front();
183 logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
184 int a = demuxer->put((UCHAR*)s.data, s.len);
185 logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);
189 void PlayerLiveRadio::switchState(UCHAR newState)
191 logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);
195 case S_STOP: // FROM S_STOP
204 audio->setStreamType(Audio::MPEG2_PES);
205 audio->systemMuteOff();
222 logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
229 case S_PREBUFFERING: // FROM S_PREBUFFERING
241 vdr->stopStreaming();
251 logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
258 case S_PLAY: // FROM S_PLAY
264 vdr->stopStreaming();
272 case S_PREBUFFERING: // IS THIS HOW IT WORKS?
275 vdr->stopStreaming();
290 audio->setStreamType(Audio::MPEG2_PES);
308 logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
317 void PlayerLiveRadio::optimizeInstructionQueue()
321 // Currently there are only 2 instruction types, so this is a bit overkill...
323 struct PLInstruction i;
324 while(instructions.size() > 1)
326 i = instructions.front();
327 if (i.instruction == I_SETCHANNEL)
329 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
331 else if (i.instruction == I_STOP)
333 return; // return here and ensure the next instruction will be stop
338 void PlayerLiveRadio::threadMethod()
342 while(!instructions.empty())
344 if (instructions.size() > 1) optimizeInstructionQueue();
346 struct PLInstruction i = instructions.front();
349 if (i.instruction == I_SETCHANNEL)
351 logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
353 switchState(S_PREBUFFERING);
355 Channel* chan = (*chanList)[i.channelIndex];
358 if (chan->numAPids > 0)
360 demuxer->setAID(chan->apids[0].pid);
361 logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
365 logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
368 vdr->streamChannel(chan->number, this);
370 else if (i.instruction == I_STOP)
372 logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
382 while(streamChunks.size())
386 if (state == S_PREBUFFERING)
388 if (++preBufferCount == preBufferAmount)
396 threadWaitForSignal(); // unlocks and waits for signal
400 logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");