From: Chris Tallon Date: Tue, 3 Mar 2020 21:50:23 +0000 (+0000) Subject: Rename class: PlayerLiveRadio to PlayerRadioLive X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=e3df63655e0e1f578f3e7e85e51bfff2c0300334;p=vompclient.git Rename class: PlayerLiveRadio to PlayerRadioLive --- diff --git a/objects.mk b/objects.mk index dd220df..5fa2805 100644 --- a/objects.mk +++ b/objects.mk @@ -14,12 +14,12 @@ OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o 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 \ diff --git a/playerliveradio.cc b/playerliveradio.cc deleted file mode 100644 index 648dab8..0000000 --- a/playerliveradio.cc +++ /dev/null @@ -1,502 +0,0 @@ -/* - 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 . -*/ - -#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"); -} diff --git a/playerliveradio.h b/playerliveradio.h deleted file mode 100644 index 2b7f67c..0000000 --- a/playerliveradio.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - 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 . -*/ - -#ifndef PLAYERLIVERADIO_H -#define PLAYERLIVERADIO_H - -#include -#include -#ifndef WIN32 -#include -#endif -#include - -#include - -#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 instructions; - const static UCHAR I_SETCHANNEL = 1; - const static UCHAR I_STOP = 2; - - std::queue 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 - diff --git a/playerradiolive.cc b/playerradiolive.cc new file mode 100644 index 0000000..8caaa2e --- /dev/null +++ b/playerradiolive.cc @@ -0,0 +1,502 @@ +/* + 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 . +*/ + +#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"); +} diff --git a/playerradiolive.h b/playerradiolive.h new file mode 100644 index 0000000..6ee6e02 --- /dev/null +++ b/playerradiolive.h @@ -0,0 +1,124 @@ +/* + 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 . +*/ + +#ifndef PLAYERRADIOLIVE_H +#define PLAYERRADIOLIVE_H + +#include +#include +#ifndef WIN32 +#include +#endif +#include + +#include + +#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 instructions; + const static UCHAR I_SETCHANNEL = 1; + const static UCHAR I_STOP = 2; + + std::queue 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 + diff --git a/vvideolivetv.cc b/vvideolivetv.cc index 2c9178e..a332417 100644 --- a/vvideolivetv.cc +++ b/vvideolivetv.cc @@ -24,7 +24,7 @@ #include "audio.h" #include "playerlive.h" #include "playervideolive.h" -#include "playerliveradio.h" +#include "playerradiolive.h" #include "channel.h" #include "boxstack.h" #include "colour.h" @@ -94,7 +94,7 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V else { streamType = VDR::RADIO; - player = new PlayerLiveRadio(Command::getInstance(), this, chanList); + player = new PlayerRadioLive(Command::getInstance(), this, chanList); } player->init();