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, see <https://www.gnu.org/licenses/>.
20 #include "playerradiolive.h"
25 #include "demuxerts.h"
27 #include "messagequeue.h"
33 // ----------------------------------- Called from outside, one offs or info funcs
35 PlayerRadioLive::PlayerRadioLive(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
38 messageQueue = tmessageQueue;
39 messageReceiver = tmessageReceiver;
42 audio = Audio::getInstance();
43 logger = Log::getInstance();
44 vdr = VDR::getInstance();
49 Video::getInstance()->turnVideoOff();
52 PlayerRadioLive::~PlayerRadioLive()
54 if (initted) shutdown();
57 int PlayerRadioLive::init()
59 if (initted) return 0;
61 demuxer = new DemuxerTS();
62 if (!demuxer) return 0;
64 if (!demuxer->init(this, audio, NULL, NULL, 0, 200000, 0))
66 logger->log("PlayerRadioLive", Log::ERR, "Demuxer failed to init");
77 int PlayerRadioLive::shutdown()
79 if (!initted) return 0;
86 bool* PlayerRadioLive::getDemuxerMpegAudioChannels()
88 return demuxer->getmpAudioChannels();
91 bool* PlayerRadioLive::getDemuxerAc3AudioChannels()
93 return demuxer->getac3AudioChannels();
96 int PlayerRadioLive::getCurrentAudioChannel()
98 return demuxer->getAID();
101 int* PlayerRadioLive::getTeletxtSubtitlePages()
106 int PlayerRadioLive::getCurrentSubtitleChannel()
108 return demuxer->getSubID();
111 void PlayerRadioLive::setAudioChannel(int newChannel, int type, int streamtype)
113 demuxer->setAID(newChannel, type, streamtype, true);
116 void PlayerRadioLive::setSubtitleChannel(int newChannel)
118 demuxer->setSubID(newChannel);
121 // ----------------------------------- Externally called events
123 void PlayerRadioLive::go(ULONG index)
125 struct PLInstruction i;
126 i.instruction = I_SETCHANNEL;
127 i.channelIndex = index;
128 instructions.push(i);
132 void PlayerRadioLive::setChannel(ULONG index)
134 logger->log("PlayerRadioLive", Log::DEBUG, "setChannel");
135 struct PLInstruction i;
136 i.instruction = I_SETCHANNEL;
137 i.channelIndex = index;
138 instructions.push(i);
139 logger->log("PlayerRadioLive", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
140 threadSignalNoLock();
143 void PlayerRadioLive::stop()
145 logger->log("PlayerRadioLive", Log::DEBUG, "stop");
146 struct PLInstruction i;
147 i.instruction = I_STOP;
148 instructions.push(i);
153 // ----------------------------------- Callback
155 void PlayerRadioLive::call(void* /*caller*/)
159 // -----------------------------------
161 void PlayerRadioLive::streamReceive(ULONG flag, void* data, ULONG len)
164 // 0 = normal stream packet
166 // 2 = connection lost
172 Message* m = new Message();
174 m->to = messageReceiver;
175 m->message = Message::PLAYER_EVENT;
176 m->parameter = PlayerRadioLive::STREAM_END;
177 messageQueue->postMessage(m);
180 if (streamChunks.size() < 11)
185 streamChunks.push(s);
186 threadSignalNoLock();
190 // Too many chunks in streamChunks, drop this chunk
192 logger->log("PlayerRadioLive", Log::WARN, "Dropped chunk");
196 void PlayerRadioLive::clearStreamChunks()
198 while(streamChunks.size())
200 logger->log("PlayerRadioLive", Log::DEBUG, "Dropping chunk from old stream");
201 struct StreamChunk s = streamChunks.front();
207 void PlayerRadioLive::chunkToDemuxer()
209 StreamChunk s = streamChunks.front();
211 //logger->log("PlayerRadioLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
212 /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);
213 //logger->log("PlayerRadioLive", Log::DEBUG, "put %i to demuxer", a);
217 void PlayerRadioLive::switchState(UCHAR newState)
219 logger->log("PlayerRadioLive", Log::DEBUG, "Switch from state %u to state %u", state, newState);
223 case S_STOP: // FROM S_STOP
232 audio->setStreamType(Audio::MPEG2_PES);
233 audio->systemMuteOff();
246 logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
253 case S_PREBUFFERING: // FROM S_PREBUFFERING
265 vdr->stopStreaming();
275 vdr->stopStreaming();
291 logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
298 case S_PLAY: // FROM S_PLAY
304 vdr->stopStreaming();
312 case S_PREBUFFERING: // IS THIS HOW IT WORKS?
314 vdr->stopStreaming();
330 logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
339 bool PlayerRadioLive::checkError()
341 if (!vdr->isConnected())
345 Message* m = new Message();
347 m->to = messageReceiver;
348 m->message = Message::PLAYER_EVENT;
349 m->parameter = PlayerRadioLive::CONNECTION_LOST;
350 messageQueue->postMessage(m);
357 void PlayerRadioLive::optimizeInstructionQueue()
361 // Currently there are only 2 instruction types, so this is a bit overkill...
363 struct PLInstruction i;
364 while(instructions.size() > 1)
366 i = instructions.front();
367 if (i.instruction == I_SETCHANNEL)
369 instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
371 else if (i.instruction == I_STOP)
373 return; // return here and ensure the next instruction will be stop
378 void PlayerRadioLive::threadMethod()
382 while(!instructions.empty())
384 if (instructions.size() > 1)
386 logger->log("PlayerRadioLive", Log::DEBUG, "Should optimise");
387 optimizeInstructionQueue();
390 struct PLInstruction i = instructions.front();
393 if (i.instruction == I_SETCHANNEL)
395 logger->log("PlayerRadioLive", Log::DEBUG, "start new stream");
397 switchState(S_PREBUFFERING);
401 Channel* chan = (*chanList)[i.channelIndex];
406 if (chan->numAPids > 0)
409 while (j < chan->numAPids && !found)
411 if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type))
413 demuxer->setAID(chan->apids[j].pid, 0, chan->apids[j].type, true);
414 audio->setStreamType(Audio::MPEG2_PES);
415 logger->log("PlayerRadioLive", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid, chan->apids[j].type);
424 if (chan->numDPids > 0 && audio->maysupportAc3())
427 while (j < chan->numDPids && !found)
429 if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type))
431 demuxer->setAID(chan->dpids[j].pid, 1, chan->dpids[j].type, true);
432 audio->setStreamType(Audio::MPEG2_PES);
433 logger->log("PlayerRadioLive", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid, chan->dpids[j].type);
441 logger->log("PlayerRadioLive", Log::WARN, "Demuxer no pids!");
445 int streamSuccess = vdr->streamChannel(chan->number, this);
446 if (!checkError() && !streamSuccess)
448 Message* m = new Message();
450 m->to = messageReceiver;
451 m->message = Message::PLAYER_EVENT;
452 m->parameter = PlayerRadioLive::STREAM_END;
453 messageQueue->postMessage(m);
457 else if (i.instruction == I_STOP)
459 logger->log("PlayerRadioLive", Log::DEBUG, "Stopping");
470 while(streamChunks.size())
474 if (state == S_PREBUFFERING)
477 ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
478 logger->log("PlayerRadioLive", Log::DEBUG, "Prebuffering %lu%%", percentDone);
480 Message* m = new Message();
482 m->to = messageReceiver;
483 m->message = Message::PLAYER_EVENT;
484 m->parameter = PlayerRadioLive::PREBUFFERING;
485 m->tag = percentDone;
486 messageQueue->postMessage(m);
488 if (preBufferCount == preBufferAmount)
497 threadWaitForSignal(); // unlocks and waits for signal
501 logger->log("PlayerRadioLive", Log::DEBUG, "End of thread");