woptionpane.o woptionbox.o wremoteconfig.o wtabbar.o led.o \
inputman.o input.o inputudp.o vpicturebanner.o abstractoption.o \
eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o \
- vvideolivetv.o vsleeptimer.o playerliveradio.o \
+ vvideolivetv.o vsleeptimer.o \
wprogressbar.o bitmap.o dvbsubtitles.o tfeed.o vteletextview.o \
teletextdecodervbiebu.o teletxt/txtfont.o movieinfo.o seriesinfo.o \
wmovieview.o wseriesview.o tvmedia.o wtvmedia.o wpictureview.o \
osdvector.o surfacevector.o buffer.o \
- playervideorec.o playervideolive.o
+ playervideorec.o playervideolive.o playerradiolive.o
OBJ_RASPBERRY = main.o threadp.o osdopenvg.o \
ledraspberry.o videoomx.o audioomx.o imageomx.o \
+++ /dev/null
-/*
- Copyright 2008 Chris Tallon
-
- This file is part of VOMP.
-
- VOMP is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- VOMP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with VOMP. If not, see <https://www.gnu.org/licenses/>.
-*/
-
-#include "playerliveradio.h"
-
-#include "defines.h"
-#include "log.h"
-#include "audio.h"
-#include "demuxerts.h"
-#include "vdr.h"
-#include "messagequeue.h"
-#include "input.h"
-#include "message.h"
-#include "channel.h"
-#include "video.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerLiveRadio::PlayerLiveRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
-: afeed(this)
-{
- messageQueue = tmessageQueue;
- messageReceiver = tmessageReceiver;
- chanList = tchanList;
-
- audio = Audio::getInstance();
- logger = Log::getInstance();
- vdr = VDR::getInstance();
- initted = false;
-
- stopNow = false;
- state = S_STOP;
- Video::getInstance()->turnVideoOff();
-}
-
-PlayerLiveRadio::~PlayerLiveRadio()
-{
- if (initted) shutdown();
-}
-
-int PlayerLiveRadio::init()
-{
- if (initted) return 0;
-
- demuxer = new DemuxerTS();
- if (!demuxer) return 0;
-
- if (!demuxer->init(this, audio, NULL, NULL, 0, 200000, 0))
- {
- logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
- shutdown();
- return 0;
- }
-
- audio->stop();
-
- initted = true;
- return 1;
-}
-
-int PlayerLiveRadio::shutdown()
-{
- if (!initted) return 0;
- stop();
- initted = false;
- delete demuxer;
- return 1;
-}
-
-bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
-{
- return demuxer->getmpAudioChannels();
-}
-
-bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
-{
- return demuxer->getac3AudioChannels();
-}
-
-int PlayerLiveRadio::getCurrentAudioChannel()
-{
- return demuxer->getAID();
-}
-
-int* PlayerLiveRadio::getTeletxtSubtitlePages()
-{
- return NULL;
-}
-
-int PlayerLiveRadio::getCurrentSubtitleChannel()
-{
- return demuxer->getSubID();
-}
-
-void PlayerLiveRadio::setAudioChannel(int newChannel, int type, int streamtype)
-{
- demuxer->setAID(newChannel, type, streamtype, true);
-}
-
-void PlayerLiveRadio::setSubtitleChannel(int newChannel)
-{
- demuxer->setSubID(newChannel);
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerLiveRadio::go(ULONG index)
-{
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- threadStart();
-}
-
-void PlayerLiveRadio::setChannel(ULONG index)
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "setChannel");
- struct PLInstruction i;
- i.instruction = I_SETCHANNEL;
- i.channelIndex = index;
- instructions.push(i);
- logger->log("PlayerLiveRadio", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
- threadSignalNoLock();
-}
-
-void PlayerLiveRadio::stop()
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "stop");
- struct PLInstruction i;
- i.instruction = I_STOP;
- instructions.push(i);
- threadSignal();
- threadStop();
-}
-
-// ----------------------------------- Callback
-
-void PlayerLiveRadio::call(void* /*caller*/)
-{
-}
-
-// -----------------------------------
-
-void PlayerLiveRadio::streamReceive(ULONG flag, void* data, ULONG len)
-{
- // Flag:
- // 0 = normal stream packet
- // 1 = stream end
- // 2 = connection lost
-
- if (flag == 1)
- {
- if (data) abort();
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::STREAM_END;
- messageQueue->postMessage(m);
- }
-
- if (streamChunks.size() < 11)
- {
- StreamChunk s;
- s.data = data;
- s.len = len;
- streamChunks.push(s);
- threadSignalNoLock();
- }
- else
- {
- // Too many chunks in streamChunks, drop this chunk
- free(data);
- logger->log("PlayerLiveRadio", Log::WARN, "Dropped chunk");
- }
-}
-
-void PlayerLiveRadio::clearStreamChunks()
-{
- while(streamChunks.size())
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Dropping chunk from old stream");
- struct StreamChunk s = streamChunks.front();
- streamChunks.pop();
- free(s.data);
- }
-}
-
-void PlayerLiveRadio::chunkToDemuxer()
-{
- StreamChunk s = streamChunks.front();
- streamChunks.pop();
- //logger->log("PlayerLiveRadio", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
- /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);
- //logger->log("PlayerLiveRadio", Log::DEBUG, "put %i to demuxer", a);
- free(s.data);
-}
-
-void PlayerLiveRadio::switchState(UCHAR newState)
-{
- logger->log("PlayerLiveRadio", Log::DEBUG, "Switch from state %u to state %u", state, newState);
-
- switch(state)
- {
- case S_STOP: // FROM S_STOP
- {
- switch(newState)
- {
- case S_PREBUFFERING:
- {
- audio->stop();
- audio->unPause();
- audio->reset();
- audio->setStreamType(Audio::MPEG2_PES);
- audio->systemMuteOff();
- audio->doMuting();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PREBUFFERING: // FROM S_PREBUFFERING
- {
- switch(newState)
- {
- case S_PLAY:
- {
- audio->unPause();
- state = newState;
- return;
- }
- case S_STOP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- state = newState;
- return;
- }
- case S_PREBUFFERING:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
-
- case S_PLAY: // FROM S_PLAY
- {
- switch(newState)
- {
- case S_STOP:
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- state = newState;
- return;
- }
- case S_PREBUFFERING: // IS THIS HOW IT WORKS?
- {
- vdr->stopStreaming();
- clearStreamChunks();
- afeed.stop();
- audio->stop();
- audio->reset();
- audio->play();
- audio->pause();
- demuxer->reset();
- afeed.start();
-
- state = newState;
- preBufferCount = 0;
- return;
- }
- default:
- {
- logger->log("PlayerLiveRadio", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
- abort();
- break;
- }
- }
- }
- }
-}
-
-bool PlayerLiveRadio::checkError()
-{
- if (!vdr->isConnected())
- {
- switchState(S_STOP);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::CONNECTION_LOST;
- messageQueue->postMessage(m);
-
- return true;
- }
- return false;
-}
-
-void PlayerLiveRadio::optimizeInstructionQueue()
-{
- // Walk the list
-
- // Currently there are only 2 instruction types, so this is a bit overkill...
-
- struct PLInstruction i;
- while(instructions.size() > 1)
- {
- i = instructions.front();
- if (i.instruction == I_SETCHANNEL)
- {
- instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
- }
- else if (i.instruction == I_STOP)
- {
- return; // return here and ensure the next instruction will be stop
- }
- }
-}
-
-void PlayerLiveRadio::threadMethod()
-{
- while(1)
- {
- while(!instructions.empty())
- {
- if (instructions.size() > 1)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Should optimise");
- optimizeInstructionQueue();
- }
-
- struct PLInstruction i = instructions.front();
- instructions.pop();
-
- if (i.instruction == I_SETCHANNEL)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
-
- switchState(S_PREBUFFERING);
-
- if (!checkError())
- {
- Channel* chan = (*chanList)[i.channelIndex];
- chan->loadPids();
-
- bool found=false;
-
- if (chan->numAPids > 0)
- {
- ULONG j = 0;
- while (j < chan->numAPids && !found)
- {
- if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type))
- {
- demuxer->setAID(chan->apids[j].pid, 0, chan->apids[j].type, true);
- audio->setStreamType(Audio::MPEG2_PES);
- logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid, chan->apids[j].type);
- found = true;
- }
- j++;
- }
- }
-
- if (!found)
- {
- if (chan->numDPids > 0 && audio->maysupportAc3())
- {
- ULONG j = 0;
- while (j < chan->numDPids && !found)
- {
- if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type))
- {
- demuxer->setAID(chan->dpids[j].pid, 1, chan->dpids[j].type, true);
- audio->setStreamType(Audio::MPEG2_PES);
- logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid, chan->dpids[j].type);
- found=true;
- }
- j++;
- }
- }
- else
- {
- logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
- }
- }
-
- int streamSuccess = vdr->streamChannel(chan->number, this);
- if (!checkError() && !streamSuccess)
- {
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::STREAM_END;
- messageQueue->postMessage(m);
- }
- }
- }
- else if (i.instruction == I_STOP)
- {
- logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
- switchState(S_STOP);
- checkError();
-
- stopNow = true;
- break;
- }
- }
-
- if (stopNow) break;
-
- while(streamChunks.size())
- {
- chunkToDemuxer();
-
- if (state == S_PREBUFFERING)
- {
- ++preBufferCount;
- ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
- logger->log("PlayerLiveRadio", Log::DEBUG, "Prebuffering %lu%%", percentDone);
-
- Message* m = new Message();
- m->from = this;
- m->to = messageReceiver;
- m->message = Message::PLAYER_EVENT;
- m->parameter = PlayerLiveRadio::PREBUFFERING;
- m->tag = percentDone;
- messageQueue->postMessage(m);
-
- if (preBufferCount == preBufferAmount)
- {
- switchState(S_PLAY);
- checkError();
- }
- }
- }
-
- threadLock();
- threadWaitForSignal(); // unlocks and waits for signal
- threadUnlock();
- }
-
- logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");
-}
+++ /dev/null
-/*
- Copyright 2008 Chris Tallon
-
- This file is part of VOMP.
-
- VOMP is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- VOMP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with VOMP. If not, see <https://www.gnu.org/licenses/>.
-*/
-
-#ifndef PLAYERLIVERADIO_H
-#define PLAYERLIVERADIO_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#include <queue>
-
-#include "playerlive.h"
-
-#ifdef WIN32
-#include "threadwin.h"
-#else
-#include "threadp.h"
-#endif
-
-#include "callback.h"
-#include "defines.h"
-#include "afeed.h"
-#include "vdr.h"
-
-class MessageQueue;
-class Audio;
-class Log;
-class DemuxerTS;
-
-class PlayerLiveRadio : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
-{
- public:
- PlayerLiveRadio(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
- virtual ~PlayerLiveRadio();
-
- virtual int init();
- virtual int shutdown();
-
- virtual void go(ULONG index);
- virtual void setChannel(ULONG index);
- virtual void stop();
- virtual void setAudioChannel(int newChannel, int type,int streamtype);
- virtual void setSubtitleChannel(int newChannel);
-
- virtual bool* getDemuxerMpegAudioChannels();
- virtual bool* getDemuxerAc3AudioChannels();
- virtual int getCurrentAudioChannel();
- virtual int *getTeletxtSubtitlePages();
- virtual int getCurrentSubtitleChannel();
-
- void call(void*); // for callback interface
-
- virtual void streamReceive(ULONG, void*, ULONG); // stream receiver interface
-
- // Player events
-
- // FIXME so far this just duplicates the old system + the wss
-
- const static UCHAR CONNECTION_LOST = 1;
- const static UCHAR STOP_PLAYBACK = 2;
- const static UCHAR STREAM_END = 3;
- const static UCHAR ASPECT43 = 4;
- const static UCHAR ASPECT169 = 5;
- const static UCHAR PREBUFFERING = 6;
-
- protected:
- void threadMethod();
-
- private:
- MessageQueue* messageQueue;
- void* messageReceiver;
- Log* logger;
- Audio* audio;
- DemuxerTS* demuxer;
- VDR* vdr;
- AFeed afeed;
- ChannelList* chanList;
-
- std::queue<PLInstruction> instructions;
- const static UCHAR I_SETCHANNEL = 1;
- const static UCHAR I_STOP = 2;
-
- std::queue<StreamChunk> streamChunks;
-
- bool initted;
-
- UCHAR state;
- const static UCHAR S_STOP = 1;
- const static UCHAR S_PREBUFFERING = 2;
- const static UCHAR S_PLAY = 3;
- void switchState(UCHAR newState);
- bool checkError();
-
- bool stopNow;
- int preBufferCount;
- const static int preBufferAmount = 3;
-
- void clearStreamChunks();
- void chunkToDemuxer();
- void optimizeInstructionQueue();
-};
-
-#endif
-
--- /dev/null
+/*
+ Copyright 2008 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include "playerradiolive.h"
+
+#include "defines.h"
+#include "log.h"
+#include "audio.h"
+#include "demuxerts.h"
+#include "vdr.h"
+#include "messagequeue.h"
+#include "input.h"
+#include "message.h"
+#include "channel.h"
+#include "video.h"
+
+// ----------------------------------- Called from outside, one offs or info funcs
+
+PlayerRadioLive::PlayerRadioLive(MessageQueue* tmessageQueue, void* tmessageReceiver, ChannelList* tchanList)
+: afeed(this)
+{
+ messageQueue = tmessageQueue;
+ messageReceiver = tmessageReceiver;
+ chanList = tchanList;
+
+ audio = Audio::getInstance();
+ logger = Log::getInstance();
+ vdr = VDR::getInstance();
+ initted = false;
+
+ stopNow = false;
+ state = S_STOP;
+ Video::getInstance()->turnVideoOff();
+}
+
+PlayerRadioLive::~PlayerRadioLive()
+{
+ if (initted) shutdown();
+}
+
+int PlayerRadioLive::init()
+{
+ if (initted) return 0;
+
+ demuxer = new DemuxerTS();
+ if (!demuxer) return 0;
+
+ if (!demuxer->init(this, audio, NULL, NULL, 0, 200000, 0))
+ {
+ logger->log("PlayerRadioLive", Log::ERR, "Demuxer failed to init");
+ shutdown();
+ return 0;
+ }
+
+ audio->stop();
+
+ initted = true;
+ return 1;
+}
+
+int PlayerRadioLive::shutdown()
+{
+ if (!initted) return 0;
+ stop();
+ initted = false;
+ delete demuxer;
+ return 1;
+}
+
+bool* PlayerRadioLive::getDemuxerMpegAudioChannels()
+{
+ return demuxer->getmpAudioChannels();
+}
+
+bool* PlayerRadioLive::getDemuxerAc3AudioChannels()
+{
+ return demuxer->getac3AudioChannels();
+}
+
+int PlayerRadioLive::getCurrentAudioChannel()
+{
+ return demuxer->getAID();
+}
+
+int* PlayerRadioLive::getTeletxtSubtitlePages()
+{
+ return NULL;
+}
+
+int PlayerRadioLive::getCurrentSubtitleChannel()
+{
+ return demuxer->getSubID();
+}
+
+void PlayerRadioLive::setAudioChannel(int newChannel, int type, int streamtype)
+{
+ demuxer->setAID(newChannel, type, streamtype, true);
+}
+
+void PlayerRadioLive::setSubtitleChannel(int newChannel)
+{
+ demuxer->setSubID(newChannel);
+}
+
+// ----------------------------------- Externally called events
+
+void PlayerRadioLive::go(ULONG index)
+{
+ struct PLInstruction i;
+ i.instruction = I_SETCHANNEL;
+ i.channelIndex = index;
+ instructions.push(i);
+ threadStart();
+}
+
+void PlayerRadioLive::setChannel(ULONG index)
+{
+ logger->log("PlayerRadioLive", Log::DEBUG, "setChannel");
+ struct PLInstruction i;
+ i.instruction = I_SETCHANNEL;
+ i.channelIndex = index;
+ instructions.push(i);
+ logger->log("PlayerRadioLive", Log::DEBUG, "posted setChannel instruction, now %i in queue", instructions.size());
+ threadSignalNoLock();
+}
+
+void PlayerRadioLive::stop()
+{
+ logger->log("PlayerRadioLive", Log::DEBUG, "stop");
+ struct PLInstruction i;
+ i.instruction = I_STOP;
+ instructions.push(i);
+ threadSignal();
+ threadStop();
+}
+
+// ----------------------------------- Callback
+
+void PlayerRadioLive::call(void* /*caller*/)
+{
+}
+
+// -----------------------------------
+
+void PlayerRadioLive::streamReceive(ULONG flag, void* data, ULONG len)
+{
+ // Flag:
+ // 0 = normal stream packet
+ // 1 = stream end
+ // 2 = connection lost
+
+ if (flag == 1)
+ {
+ if (data) abort();
+
+ Message* m = new Message();
+ m->from = this;
+ m->to = messageReceiver;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadioLive::STREAM_END;
+ messageQueue->postMessage(m);
+ }
+
+ if (streamChunks.size() < 11)
+ {
+ StreamChunk s;
+ s.data = data;
+ s.len = len;
+ streamChunks.push(s);
+ threadSignalNoLock();
+ }
+ else
+ {
+ // Too many chunks in streamChunks, drop this chunk
+ free(data);
+ logger->log("PlayerRadioLive", Log::WARN, "Dropped chunk");
+ }
+}
+
+void PlayerRadioLive::clearStreamChunks()
+{
+ while(streamChunks.size())
+ {
+ logger->log("PlayerRadioLive", Log::DEBUG, "Dropping chunk from old stream");
+ struct StreamChunk s = streamChunks.front();
+ streamChunks.pop();
+ free(s.data);
+ }
+}
+
+void PlayerRadioLive::chunkToDemuxer()
+{
+ StreamChunk s = streamChunks.front();
+ streamChunks.pop();
+ //logger->log("PlayerRadioLive", Log::DEBUG, "About to call demuxer with %p %lu", s.data, s.len);
+ /*int a =*/ demuxer->put((UCHAR*)s.data, s.len);
+ //logger->log("PlayerRadioLive", Log::DEBUG, "put %i to demuxer", a);
+ free(s.data);
+}
+
+void PlayerRadioLive::switchState(UCHAR newState)
+{
+ logger->log("PlayerRadioLive", Log::DEBUG, "Switch from state %u to state %u", state, newState);
+
+ switch(state)
+ {
+ case S_STOP: // FROM S_STOP
+ {
+ switch(newState)
+ {
+ case S_PREBUFFERING:
+ {
+ audio->stop();
+ audio->unPause();
+ audio->reset();
+ audio->setStreamType(Audio::MPEG2_PES);
+ audio->systemMuteOff();
+ audio->doMuting();
+ audio->play();
+ audio->pause();
+ demuxer->reset();
+ afeed.start();
+
+ state = newState;
+ preBufferCount = 0;
+ return;
+ }
+ default:
+ {
+ logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
+ abort();
+ break;
+ }
+ }
+ }
+
+ case S_PREBUFFERING: // FROM S_PREBUFFERING
+ {
+ switch(newState)
+ {
+ case S_PLAY:
+ {
+ audio->unPause();
+ state = newState;
+ return;
+ }
+ case S_STOP:
+ {
+ vdr->stopStreaming();
+ clearStreamChunks();
+ afeed.stop();
+ audio->stop();
+ audio->reset();
+ state = newState;
+ return;
+ }
+ case S_PREBUFFERING:
+ {
+ vdr->stopStreaming();
+ clearStreamChunks();
+ afeed.stop();
+ audio->stop();
+ audio->reset();
+ audio->play();
+ audio->pause();
+ demuxer->reset();
+ afeed.start();
+
+ state = newState;
+ preBufferCount = 0;
+ return;
+ }
+ default:
+ {
+ logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
+ abort();
+ break;
+ }
+ }
+ }
+
+ case S_PLAY: // FROM S_PLAY
+ {
+ switch(newState)
+ {
+ case S_STOP:
+ {
+ vdr->stopStreaming();
+ clearStreamChunks();
+ afeed.stop();
+ audio->stop();
+ audio->reset();
+ state = newState;
+ return;
+ }
+ case S_PREBUFFERING: // IS THIS HOW IT WORKS?
+ {
+ vdr->stopStreaming();
+ clearStreamChunks();
+ afeed.stop();
+ audio->stop();
+ audio->reset();
+ audio->play();
+ audio->pause();
+ demuxer->reset();
+ afeed.start();
+
+ state = newState;
+ preBufferCount = 0;
+ return;
+ }
+ default:
+ {
+ logger->log("PlayerRadioLive", Log::EMERG, "Thread called state %u to state %u which is not supported", state, newState);
+ abort();
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool PlayerRadioLive::checkError()
+{
+ if (!vdr->isConnected())
+ {
+ switchState(S_STOP);
+
+ Message* m = new Message();
+ m->from = this;
+ m->to = messageReceiver;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadioLive::CONNECTION_LOST;
+ messageQueue->postMessage(m);
+
+ return true;
+ }
+ return false;
+}
+
+void PlayerRadioLive::optimizeInstructionQueue()
+{
+ // Walk the list
+
+ // Currently there are only 2 instruction types, so this is a bit overkill...
+
+ struct PLInstruction i;
+ while(instructions.size() > 1)
+ {
+ i = instructions.front();
+ if (i.instruction == I_SETCHANNEL)
+ {
+ instructions.pop(); // if this is the first of more than 1 command, currently it cannot possibly be relevant
+ }
+ else if (i.instruction == I_STOP)
+ {
+ return; // return here and ensure the next instruction will be stop
+ }
+ }
+}
+
+void PlayerRadioLive::threadMethod()
+{
+ while(1)
+ {
+ while(!instructions.empty())
+ {
+ if (instructions.size() > 1)
+ {
+ logger->log("PlayerRadioLive", Log::DEBUG, "Should optimise");
+ optimizeInstructionQueue();
+ }
+
+ struct PLInstruction i = instructions.front();
+ instructions.pop();
+
+ if (i.instruction == I_SETCHANNEL)
+ {
+ logger->log("PlayerRadioLive", Log::DEBUG, "start new stream");
+
+ switchState(S_PREBUFFERING);
+
+ if (!checkError())
+ {
+ Channel* chan = (*chanList)[i.channelIndex];
+ chan->loadPids();
+
+ bool found=false;
+
+ if (chan->numAPids > 0)
+ {
+ ULONG j = 0;
+ while (j < chan->numAPids && !found)
+ {
+ if (Audio::getInstance()->streamTypeSupported(chan->apids[j].type))
+ {
+ demuxer->setAID(chan->apids[j].pid, 0, chan->apids[j].type, true);
+ audio->setStreamType(Audio::MPEG2_PES);
+ logger->log("PlayerRadioLive", Log::DEBUG, "Demuxer pids: %u %u %u", chan->vpid, chan->apids[j].pid, chan->apids[j].type);
+ found = true;
+ }
+ j++;
+ }
+ }
+
+ if (!found)
+ {
+ if (chan->numDPids > 0 && audio->maysupportAc3())
+ {
+ ULONG j = 0;
+ while (j < chan->numDPids && !found)
+ {
+ if (Audio::getInstance()->streamTypeSupported(chan->dpids[j].type))
+ {
+ demuxer->setAID(chan->dpids[j].pid, 1, chan->dpids[j].type, true);
+ audio->setStreamType(Audio::MPEG2_PES);
+ logger->log("PlayerRadioLive", Log::DEBUG, "Demuxer pids: %u %u (ac3) %u", chan->vpid, chan->dpids[j].pid, chan->dpids[j].type);
+ found=true;
+ }
+ j++;
+ }
+ }
+ else
+ {
+ logger->log("PlayerRadioLive", Log::WARN, "Demuxer no pids!");
+ }
+ }
+
+ int streamSuccess = vdr->streamChannel(chan->number, this);
+ if (!checkError() && !streamSuccess)
+ {
+ Message* m = new Message();
+ m->from = this;
+ m->to = messageReceiver;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadioLive::STREAM_END;
+ messageQueue->postMessage(m);
+ }
+ }
+ }
+ else if (i.instruction == I_STOP)
+ {
+ logger->log("PlayerRadioLive", Log::DEBUG, "Stopping");
+ switchState(S_STOP);
+ checkError();
+
+ stopNow = true;
+ break;
+ }
+ }
+
+ if (stopNow) break;
+
+ while(streamChunks.size())
+ {
+ chunkToDemuxer();
+
+ if (state == S_PREBUFFERING)
+ {
+ ++preBufferCount;
+ ULONG percentDone = (ULONG)(preBufferCount / (float)preBufferAmount * 100);
+ logger->log("PlayerRadioLive", Log::DEBUG, "Prebuffering %lu%%", percentDone);
+
+ Message* m = new Message();
+ m->from = this;
+ m->to = messageReceiver;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadioLive::PREBUFFERING;
+ m->tag = percentDone;
+ messageQueue->postMessage(m);
+
+ if (preBufferCount == preBufferAmount)
+ {
+ switchState(S_PLAY);
+ checkError();
+ }
+ }
+ }
+
+ threadLock();
+ threadWaitForSignal(); // unlocks and waits for signal
+ threadUnlock();
+ }
+
+ logger->log("PlayerRadioLive", Log::DEBUG, "End of thread");
+}
--- /dev/null
+/*
+ Copyright 2008 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef PLAYERRADIOLIVE_H
+#define PLAYERRADIOLIVE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include <queue>
+
+#include "playerlive.h"
+
+#ifdef WIN32
+#include "threadwin.h"
+#else
+#include "threadp.h"
+#endif
+
+#include "callback.h"
+#include "defines.h"
+#include "afeed.h"
+#include "vdr.h"
+
+class MessageQueue;
+class Audio;
+class Log;
+class DemuxerTS;
+
+class PlayerRadioLive : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
+{
+ public:
+ PlayerRadioLive(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
+ virtual ~PlayerRadioLive();
+
+ virtual int init();
+ virtual int shutdown();
+
+ virtual void go(ULONG index);
+ virtual void setChannel(ULONG index);
+ virtual void stop();
+ virtual void setAudioChannel(int newChannel, int type,int streamtype);
+ virtual void setSubtitleChannel(int newChannel);
+
+ virtual bool* getDemuxerMpegAudioChannels();
+ virtual bool* getDemuxerAc3AudioChannels();
+ virtual int getCurrentAudioChannel();
+ virtual int *getTeletxtSubtitlePages();
+ virtual int getCurrentSubtitleChannel();
+
+ void call(void*); // for callback interface
+
+ virtual void streamReceive(ULONG, void*, ULONG); // stream receiver interface
+
+ // Player events
+
+ // FIXME so far this just duplicates the old system + the wss
+
+ const static UCHAR CONNECTION_LOST = 1;
+ const static UCHAR STOP_PLAYBACK = 2;
+ const static UCHAR STREAM_END = 3;
+ const static UCHAR ASPECT43 = 4;
+ const static UCHAR ASPECT169 = 5;
+ const static UCHAR PREBUFFERING = 6;
+
+ protected:
+ void threadMethod();
+
+ private:
+ MessageQueue* messageQueue;
+ void* messageReceiver;
+ Log* logger;
+ Audio* audio;
+ DemuxerTS* demuxer;
+ VDR* vdr;
+ AFeed afeed;
+ ChannelList* chanList;
+
+ std::queue<PLInstruction> instructions;
+ const static UCHAR I_SETCHANNEL = 1;
+ const static UCHAR I_STOP = 2;
+
+ std::queue<StreamChunk> streamChunks;
+
+ bool initted;
+
+ UCHAR state;
+ const static UCHAR S_STOP = 1;
+ const static UCHAR S_PREBUFFERING = 2;
+ const static UCHAR S_PLAY = 3;
+ void switchState(UCHAR newState);
+ bool checkError();
+
+ bool stopNow;
+ int preBufferCount;
+ const static int preBufferAmount = 3;
+
+ void clearStreamChunks();
+ void chunkToDemuxer();
+ void optimizeInstructionQueue();
+};
+
+#endif
+
#include "audio.h"
#include "playerlive.h"
#include "playervideolive.h"
-#include "playerliveradio.h"
+#include "playerradiolive.h"
#include "channel.h"
#include "boxstack.h"
#include "colour.h"
else
{
streamType = VDR::RADIO;
- player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
+ player = new PlayerRadioLive(Command::getInstance(), this, chanList);
}
player->init();