// Enter pre-keys here
// handleCommand(Remote::THREE);
-// handleCommand(Remote::SKIPFORWARD);
+// handleCommand(Remote::UP);
// handleCommand(Remote::OK);
-// handleCommand(Remote::PLAY);
// handleCommand(Remote::OK);
-// handleCommand(Remote::DOWN);
+// handleCommand(Remote::PLAY);
// handleCommand(Remote::DOWN);
// handleCommand(Remote::DOWN);
// handleCommand(Remote::OK);
{
arcnt = 0;
aspect_ratio = ar;
- callback->call(this);
+ if (callback) callback->call(this);
}
}
else
message.o messagequeue.o udp.o \\r
vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \\r
directory.o \\r
- player.o vfeed.o afeed.o \\r
+ player.o playerradio.o vfeed.o afeed.o \\r
demuxer.o demuxervdr.o stream.o draintarget.o \\r
viewman.o box.o region.o colour.o view.o \\r
vinfo.o vquestion.o vwallpaper.o vrecordinglist.o vlivebanner.o \\r
vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o \\r
vchannellist.o vwelcome.o vvideolive.o vvideorec.o vepgsettimer.o \\r
vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \\r
+ vradiorec.o \\r
widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o \\r
woptionbox.o wtextbox.o wwss.o \\r
fonts/helvB24.o fonts/helvB18.o \\r
void threadFeedPlay();
void threadFeedScan();
- void setEndTS();
void doConnectionLost();
void restartAtFrame(ULONG newFrame);
--- /dev/null
+/*
+ Copyright 2004-2006 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "playerradio.h"
+
+// ----------------------------------- Called from outside, one offs or info funcs
+
+PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, bool tIsRecording)
+: afeed(this)
+{
+ messageQueue = tmessageQueue;
+ messageReceiver = tmessageReceiver;
+ audio = Audio::getInstance();
+ logger = Log::getInstance();
+ vdr = VDR::getInstance();
+ initted = false;
+ lengthBytes = 0;
+ lengthFrames = 0;
+ streamPos = 0;
+ state = S_STOP;
+
+ startPTS = 0;
+ lengthSeconds = 0;
+
+ isRecording = tIsRecording;
+
+ threadBuffer = NULL;
+
+ blockSize = 10000;
+ startupBlockSize = 20000;
+ preBufferSize = 20000;
+}
+
+PlayerRadio::~PlayerRadio()
+{
+ if (initted) shutdown();
+}
+
+int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthFrames)
+{
+ if (initted) return 0;
+#ifndef WIN32
+ pthread_mutex_init(&mutex, NULL);
+#else
+ mutex=CreateMutex(NULL,FALSE,NULL);
+#endif
+
+ demuxer = new DemuxerVDR();
+ if (!demuxer) return 0;
+
+ if (!demuxer->init(this, audio, NULL))
+ {
+ logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
+ shutdown();
+ return 0;
+ }
+
+ afeed.init();
+ audio->stop();
+
+ lengthBytes = tlengthBytes;
+ lengthFrames = tlengthFrames;
+
+ logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
+
+ UINT thisRead = 0;
+ ULLONG endPTS = 0;
+ int success;
+
+ threadBuffer = vdr->getBlock(0, 10000, &thisRead);
+ if (!threadBuffer)
+ {
+ logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
+ shutdown();
+ return 0;
+ }
+
+ success = demuxer->findPTS(threadBuffer, thisRead, &startPTS);
+ if (!success)
+ {
+ logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
+ shutdown();
+ return 0;
+ }
+
+ threadBuffer = vdr->getBlock(tlengthBytes - 10000, 10000, &thisRead);
+ if (!threadBuffer)
+ {
+ logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
+ shutdown();
+ return 0;
+ }
+
+ success = demuxer->findPTS(threadBuffer, thisRead, &endPTS);
+ if (!success)
+ {
+ logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
+ shutdown();
+ return 0;
+ }
+
+ logger->log("PlayerRadio", Log::DEBUG, "Start: %llu, End: %llu", startPTS, endPTS);
+
+ if (startPTS < endPTS)
+ {
+ lengthSeconds = (endPTS - startPTS) / 90000;
+ }
+ else
+ {
+ lengthSeconds = (startPTS - endPTS) / 90000;
+ }
+
+ initted = true;
+ return 1;
+}
+
+int PlayerRadio::shutdown()
+{
+ if (!initted) return 0;
+ switchState(S_STOP);
+ initted = false;
+
+ delete demuxer;
+ demuxer = NULL;
+
+#ifdef WIN32
+ CloseHandle(mutex);
+#endif
+
+ return 1;
+}
+
+
+void PlayerRadio::setStartBytes(ULLONG startBytes)
+{
+ streamPos = startBytes;
+}
+
+ULONG PlayerRadio::getLengthSeconds()
+{
+ return lengthSeconds;
+}
+
+ULONG PlayerRadio::getCurrentSeconds()
+{
+ if (startup) return 0;
+ return 0;
+}
+
+// ----------------------------------- Externally called events
+
+void PlayerRadio::play()
+{
+ if (!initted) return;
+ if (state == S_PLAY) return;
+ lock();
+ switchState(S_PLAY);
+ unLock();
+}
+
+void PlayerRadio::stop()
+{
+ if (!initted) return;
+ if (state == S_STOP) return;
+ lock();
+ logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
+ switchState(S_STOP);
+ unLock();
+}
+
+void PlayerRadio::pause()
+{
+ if (!initted) return;
+ lock();
+
+ if (state == S_PAUSE_P)
+ {
+ switchState(S_PLAY);
+ }
+ else
+ {
+ switchState(S_PAUSE_P);
+ }
+
+ unLock();
+}
+
+void PlayerRadio::jumpToPercent(int percent)
+{
+ lock();
+ logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
+ ULONG newFrame = percent * lengthFrames / 100;
+ switchState(S_JUMP, newFrame);
+ unLock();
+}
+
+void PlayerRadio::skipForward(int seconds)
+{
+ lock();
+ logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
+ ULONG newFrame = getCurrentSeconds();
+ if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
+// newFrame += seconds * video->getFPS();
+ if (newFrame > lengthFrames) { switchState(S_PLAY); unLock(); }
+ else switchState(S_JUMP, newFrame);
+ unLock();
+}
+
+void PlayerRadio::skipBackward(int seconds)
+{
+ lock();
+ logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
+ long newFrame = getCurrentSeconds();
+ if (newFrame == 0) { unLock(); return; } // Current pos from demuxer is not valid
+// newFrame -= seconds * video->getFPS();
+ if (newFrame < 0) newFrame = 0;
+ switchState(S_JUMP, newFrame);
+ unLock();
+}
+
+// ----------------------------------- Implementations called events
+
+void PlayerRadio::switchState(UCHAR toState, ULONG jumpFrame)
+{
+ if (!initted) return;
+
+ logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);
+
+ switch(state) // current state selector
+ {
+ case S_PLAY: // from S_PLAY -----------------------------------
+ {
+ switch(toState)
+ {
+ case S_PLAY: // to S_PLAY
+ {
+ return;
+ }
+ case S_PAUSE_P: // to S_PAUSE_P
+ {
+ audio->pause();
+ state = S_PAUSE_P;
+ return;
+ }
+ case S_STOP: // to S_STOP
+ {
+ afeed.stop();
+ threadStop();
+ audio->stop();
+ audio->unPause();
+ demuxer->reset();
+ state = S_STOP;
+ return;
+ }
+ case S_JUMP: // to S_JUMP
+ {
+ restartAtFrame(jumpFrame);
+ return;
+ }
+ }
+ }
+ case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
+ {
+ switch(toState)
+ {
+ case S_PLAY: // to S_PLAY
+ {
+ audio->unPause();
+ state = S_PLAY;
+ return;
+ }
+ case S_PAUSE_P: // to S_PAUSE_P
+ {
+ return;
+ }
+ case S_STOP: // to S_STOP
+ {
+ afeed.stop();
+ threadStop();
+ audio->stop();
+ audio->unPause();
+ demuxer->reset();
+ audio->systemMuteOff();
+ state = S_STOP;
+ return;
+ }
+ case S_JUMP: // to S_JUMP
+ {
+ state = S_PLAY;
+ audio->unPause();
+ restartAtFrame(jumpFrame);
+ return;
+ }
+ }
+ }
+ case S_STOP: // from S_STOP -----------------------------------
+ {
+ switch(toState)
+ {
+ case S_PLAY: // to S_PLAY
+ {
+ startup = true;
+
+ audio->reset();
+ audio->systemMuteOff();
+ demuxer->reset();
+ if (isRecording)
+ {
+ // FIXME use restartAtFrame here?
+ if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
+ demuxer->setFrameNum(currentFrameNumber);
+ }
+
+ state = S_PLAY;
+ threadStart();
+
+ if (isRecording)
+ {
+ logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
+ afeed.start();
+ audio->sync();
+ audio->play();
+ }
+ else // do prebuffering
+ {
+ logger->log("PlayerRadio", Log::DEBUG, "Prebuffering...");
+ preBuffering = true;
+ }
+ return;
+ }
+ case S_PAUSE_P: // to S_PAUSE_P
+ {
+ return;
+ }
+ case S_STOP: // to S_STOP
+ {
+ return;
+ }
+ case S_JUMP: // to S_JUMP
+ {
+ return;
+ }
+ }
+ }
+ // case S_JUMP cannot be selected as a start state because it auto flips to play
+ }
+}
+
+// ----------------------------------- Internal functions
+
+void PlayerRadio::lock()
+{
+#ifndef WIN32
+ pthread_mutex_lock(&mutex);
+ logger->log("PlayerRadio", Log::DEBUG, "LOCKED");
+
+#else
+ WaitForSingleObject(mutex, INFINITE);
+#endif
+}
+
+void PlayerRadio::unLock()
+{
+#ifndef WIN32
+ logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");
+ pthread_mutex_unlock(&mutex);
+#else
+ ReleaseMutex(mutex);
+#endif
+}
+
+void PlayerRadio::restartAtFrame(ULONG newFrame)
+{
+ afeed.stop();
+ threadStop();
+ audio->reset();
+ demuxer->flush();
+ currentFrameNumber = newFrame;
+ demuxer->setFrameNum(newFrame);
+ afeed.start();
+ threadStart();
+ audio->play();
+ audio->sync();
+ audio->systemMuteOff();
+ audio->doMuting();
+}
+
+void PlayerRadio::doConnectionLost()
+{
+ logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");
+ Message* m = new Message();
+ m->to = messageReceiver;
+ m->from = this;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadio::CONNECTION_LOST;
+ messageQueue->postMessage(m);
+}
+
+// ----------------------------------- Callback
+
+void PlayerRadio::call(void* caller)
+{
+ threadSignalNoLock();
+}
+
+// ----------------------------------- Feed thread
+
+void PlayerRadio::threadMethod()
+{
+ if (isRecording)
+ {
+ if (state == S_PLAY) threadFeedPlay();
+ }
+ else
+ {
+ threadFeedLive();
+ }
+}
+
+void PlayerRadio::threadFeedLive()
+{
+ UINT thisRead;
+ UINT writeLength;
+ UINT thisWrite;
+ UINT preBufferTotal = 0;
+
+ UINT askFor;
+ while(1)
+ {
+ thisRead = 0;
+ writeLength = 0;
+ thisWrite = 0;
+
+ threadCheckExit();
+
+ if (startup)
+ askFor = startupBlockSize; // find audio streams sized block
+ else
+ askFor = blockSize; // normal
+
+ threadBuffer = vdr->getBlock(0, askFor, &thisRead);
+
+ if (!vdr->isConnected())
+ {
+ doConnectionLost();
+ return;
+ }
+
+ if (!threadBuffer) break;
+
+ if (startup)
+ {
+ int a_stream = demuxer->scan(threadBuffer, thisRead);
+ demuxer->setAudioStream(a_stream);
+ logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
+ startup = false;
+ }
+
+ if (preBuffering)
+ {
+ preBufferTotal += thisRead;
+ if (preBufferTotal >= preBufferSize)
+ {
+ logger->log("PlayerRadio", Log::DEBUG, "Got >500K, prebuffering complete");
+
+ preBuffering = false;
+ preBufferTotal = 0;
+
+ audio->sync();
+ audio->play();
+ afeed.start();
+// unLock(); // thread will be locked by play until here
+ // FIXME - see if this can segfault because it is starting threads out of the master mutex
+ }
+ }
+
+ threadCheckExit();
+
+ while(writeLength < thisRead)
+ {
+ thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
+ writeLength += thisWrite;
+
+ if (!thisWrite)
+ {
+ // demuxer is full and can't take anymore
+ threadLock();
+ threadWaitForSignal();
+ threadUnlock();
+ }
+
+ threadCheckExit();
+ }
+
+ free(threadBuffer);
+ threadBuffer = NULL;
+
+ }
+
+ logger->log("PlayerRadio", Log::DEBUG, "Live play failed to start or interrupted");
+
+ threadCheckExit();
+
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
+ m->to = messageReceiver;
+ m->from = this;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadio::STREAM_END;
+ logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
+ messageQueue->postMessage(m);
+ logger->log("PlayerRadio", Log::DEBUG, "Message posted...");
+}
+
+void PlayerRadio::threadFeedPlay()
+{
+ ULLONG feedPosition;
+ UINT thisRead, writeLength, thisWrite, askFor;
+ time_t lastRescan = time(NULL);
+
+ feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
+ if (!vdr->isConnected()) { doConnectionLost(); return; }
+ logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedframe %i goto %llu", currentFrameNumber, feedPosition);
+
+
+ while(1)
+ {
+ thisRead = 0;
+ writeLength = 0;
+ thisWrite = 0;
+
+ threadCheckExit();
+
+ // If we havn't rescanned for a while..
+ if ((lastRescan + 60) < time(NULL))
+ {
+ lengthBytes = vdr->rescanRecording(&lengthFrames);
+ if (!vdr->isConnected()) { doConnectionLost(); return; }
+ logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
+ lastRescan = time(NULL);
+ }
+
+ if (feedPosition >= lengthBytes) break; // finished playback
+
+ if (startup)
+ {
+ if (startupBlockSize > lengthBytes)
+ askFor = lengthBytes; // is a very small recording!
+ else
+ askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
+ }
+ else
+ {
+ if ((feedPosition + blockSize) > lengthBytes) // last block of recording
+ askFor = lengthBytes - feedPosition;
+ else // normal
+ askFor = blockSize;
+ }
+
+ threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
+ feedPosition += thisRead;
+
+ if (!vdr->isConnected())
+ {
+ doConnectionLost();
+ return;
+ }
+
+ if (!threadBuffer) break;
+
+ if (startup)
+ {
+ int a_stream = demuxer->scan(threadBuffer, thisRead);
+ demuxer->setAudioStream(a_stream);
+ logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
+ startup = false;
+ }
+
+ threadCheckExit();
+
+ while(writeLength < thisRead)
+ {
+ thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
+ writeLength += thisWrite;
+
+ if (!thisWrite)
+ {
+ // demuxer is full and can't take anymore
+ threadLock();
+ threadWaitForSignal();
+ threadUnlock();
+ }
+
+ threadCheckExit();
+ }
+
+ free(threadBuffer);
+ threadBuffer = NULL;
+
+ }
+
+ // end of recording
+ logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");
+
+ threadCheckExit();
+
+
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
+ m->to = messageReceiver;
+ m->from = this;
+ m->message = Message::PLAYER_EVENT;
+ m->parameter = PlayerRadio::STOP_PLAYBACK;
+ logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
+ messageQueue->postMessage(m);
+}
+
+void PlayerRadio::threadPostStopCleanup()
+{
+ if (threadBuffer)
+ {
+ free(threadBuffer);
+ threadBuffer = NULL;
+ }
+}
--- /dev/null
+/*
+ Copyright 2004-2006 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef PLAYERRADIO_H
+#define PLAYERRADIO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include "audio.h"
+#include "demuxervdr.h"
+#include "afeed.h"
+#include "remote.h"
+#include "vdr.h"
+#include "callback.h"
+#include "message.h"
+#include "messagequeue.h"
+
+#ifdef WIN32
+#include "threadwin.h"
+#else
+#include "threadp.h"
+#endif
+
+class PlayerRadio : public Thread_TYPE, public Callback
+{
+ public:
+ PlayerRadio(MessageQueue* messageQueue, void* messageReceiver, bool isRecording);
+ virtual ~PlayerRadio();
+
+ int init(ULLONG lengthBytes, ULONG lengthFrames);
+ int shutdown();
+ void setStartBytes(ULLONG startBytes);
+
+ void play();
+ void stop();
+ void pause();
+ void jumpToPercent(int percent);
+ void skipForward(int seconds);
+ void skipBackward(int seconds);
+
+ UCHAR getState() { return state; }
+ ULONG getCurrentSeconds();
+ ULONG getLengthSeconds();
+
+ void call(void*); // for callback interface
+
+ const static UCHAR S_PLAY = 1;
+ const static UCHAR S_PAUSE_P = 2;
+ const static UCHAR S_STOP = 6;
+ const static UCHAR S_JUMP = 7;
+
+ // Player events
+
+ const static UCHAR CONNECTION_LOST = 1;
+ const static UCHAR STOP_PLAYBACK = 2;
+ const static UCHAR STREAM_END = 3;
+
+ protected:
+ void threadMethod();
+ void threadPostStopCleanup();
+
+ private:
+ void switchState(UCHAR newState, ULONG jumpFrame=0);
+
+ void threadFeedLive();
+ void threadFeedPlay();
+ void threadFeedScan();
+
+ void doConnectionLost();
+ void restartAtFrame(ULONG newFrame);
+
+ MessageQueue* messageQueue;
+ void* messageReceiver;
+ Log* logger;
+ Audio* audio;
+ Demuxer* demuxer;
+ VDR* vdr;
+ AFeed afeed;
+
+ bool initted;
+ bool startup;
+ bool isRecording;
+ bool preBuffering;
+
+ ULLONG startPTS;
+ ULONG lengthSeconds;
+
+#ifndef WIN32
+ pthread_mutex_t mutex;
+#else
+ HANDLE mutex;
+#endif
+ void lock();
+ void unLock();
+
+ ULLONG lengthBytes;
+ ULLONG streamPos;
+ ULONG lengthFrames;
+ ULONG currentFrameNumber;
+ UINT blockSize;
+ UINT startupBlockSize;
+ UINT preBufferSize;
+ UCHAR* threadBuffer;
+ UCHAR state;
+};
+
+#endif
+
+
+/*
+
+Possible states:
+
+Play, Pause, FFwd, FBwd, (Stop), [Jump]
+
+ Possible Working
+
+Play -> PauseP * *
+ -> Stop * *
+ -> Jump * *
+
+PauseP -> Play * *
+ -> Stop * *
+ -> Jump * *
+
+PauseI -> Play * *
+ -> PauseP
+ -> Stop * *
+ -> Jump * *
+
+Stop -> Play * *
+ -> PauseP
+ -> Jump
+
+Jump -> Play
+ -> PauseP
+ -> Stop
+
+*/
--- /dev/null
+/*
+ Copyright 2004-2006 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "vradiorec.h"
+
+VRadioRec::VRadioRec(Recording* rec)
+{
+ vdr = VDR::getInstance();
+ video = Video::getInstance();
+ timers = Timers::getInstance();
+ myRec = rec;
+ playing = false;
+ startMargin = 0;
+ endMargin = 0;
+
+ player = new PlayerRadio(Command::getInstance(), this, true);
+
+ char* cstartMargin = vdr->configLoad("Timers", "Start margin");
+ char* cendMargin = vdr->configLoad("Timers", "End margin");
+ if (!cstartMargin)
+ {
+ startMargin = 300; // 5 mins default
+ }
+ else
+ {
+ startMargin = atoi(cstartMargin) * 60;
+ delete[] cstartMargin;
+ }
+
+ if (!cendMargin)
+ {
+ endMargin = 300; // 5 mins default
+ }
+ else
+ {
+ endMargin = atoi(cendMargin) * 60;
+ delete[] cendMargin;
+ }
+
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
+
+ create(video->getScreenWidth(), video->getScreenHeight());
+ setBackgroundColour(Colour::BLACK);
+
+ barRegion.x = 0;
+ barRegion.y = video->getScreenHeight() - 58; // FIXME, need to be - 1? and below?
+ barRegion.w = video->getScreenWidth();
+ barRegion.h = 58;
+
+ clocksRegion.x = barRegion.x + 140;
+ clocksRegion.y = barRegion.y + 12;
+ clocksRegion.w = 170;
+ clocksRegion.h = surface->getFontHeight();
+
+
+ barBlue.set(0, 0, 150, 150);
+
+ barShowing = false;
+}
+
+VRadioRec::~VRadioRec()
+{
+ if (playing) stopPlay();
+
+ timers->cancelTimer(this, 1);
+ timers->cancelTimer(this, 2);
+
+ // kill recInfo in case resumePoint has changed (likely)
+ myRec->dropRecInfo();
+ // FIXME - do this properly - save the resume point back to the server manually and update
+ // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
+}
+
+void VRadioRec::draw()
+{
+ View::draw();
+}
+
+void VRadioRec::go()
+{
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());
+ ULONG lengthFrames = 0;
+ ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames);
+
+ bool cantStart = false;
+
+ if (!lengthBytes) cantStart = true;
+ else if (!player->init(lengthBytes, lengthFrames)) cantStart = true;
+ else
+ {
+ doBar(0);
+ // player->setStartBytes(startBytes);
+ player->play();
+ playing = true;
+ }
+
+ if (cantStart)
+ {
+ stopPlay(); // clean up
+
+ if (!vdr->isConnected())
+ {
+ Command::getInstance()->connectionLost();
+ return;
+ }
+
+ ViewMan* viewman = ViewMan::getInstance();
+
+ Message* m = new Message();
+ m->message = Message::CLOSE_ME;
+ m->from = this;
+ m->to = viewman;
+ Command::getInstance()->postMessageNoLock(m);
+
+ VInfo* vi = new VInfo();
+ vi->create(400, 150);
+ if (video->getFormat() == Video::PAL)
+ vi->setScreenPos(170, 200);
+ else
+ vi->setScreenPos(160, 150);
+ vi->setExitable();
+ vi->setBorderOn(1);
+ vi->setTitleBarOn(0);
+ vi->setOneLiner(tr("Error playing recording"));
+ vi->draw();
+
+ m = new Message();
+ m->message = Message::ADD_VIEW;
+ m->to = viewman;
+ m->parameter = (ULONG)vi;
+ Command::getInstance()->postMessageNoLock(m);
+ }
+}
+
+int VRadioRec::handleCommand(int command)
+{
+ switch(command)
+ {
+ case Remote::PLAY:
+ {
+ player->play();
+ doBar(0);
+ return 2;
+ }
+
+ case Remote::STOP:
+ case Remote::BACK:
+ case Remote::MENU:
+ {
+ if (playing) stopPlay();
+ return 4;
+ }
+ case Remote::PAUSE:
+ {
+ player->pause();
+ doBar(0);
+ return 2;
+ }
+ case Remote::SKIPFORWARD:
+ {
+ doBar(3);
+ player->skipForward(60);
+ return 2;
+ }
+ case Remote::SKIPBACK:
+ {
+ doBar(4);
+ player->skipBackward(60);
+ return 2;
+ }
+ case Remote::YELLOW:
+ {
+ doBar(2);
+ player->skipBackward(10);
+ return 2;
+ }
+ case Remote::BLUE:
+ {
+ doBar(1);
+ player->skipForward(10);
+ return 2;
+ }
+ case Remote::OK:
+ {
+ if (barShowing) removeBar();
+ else doBar(0);
+ return 2;
+ }
+
+ case Remote::ZERO: player->jumpToPercent(0); doBar(0); return 2;
+ case Remote::ONE: player->jumpToPercent(10); doBar(0); return 2;
+ case Remote::TWO: player->jumpToPercent(20); doBar(0); return 2;
+ case Remote::THREE: player->jumpToPercent(30); doBar(0); return 2;
+ case Remote::FOUR: player->jumpToPercent(40); doBar(0); return 2;
+ case Remote::FIVE: player->jumpToPercent(50); doBar(0); return 2;
+ case Remote::SIX: player->jumpToPercent(60); doBar(0); return 2;
+ case Remote::SEVEN: player->jumpToPercent(70); doBar(0); return 2;
+ case Remote::EIGHT: player->jumpToPercent(80); doBar(0); return 2;
+ case Remote::NINE: player->jumpToPercent(90); doBar(0); return 2;
+
+#ifdef DEV
+ case Remote::RED:
+ {
+ //player->test1();
+
+
+ /*
+ // for testing EPG in NTSC with a NTSC test video
+ Video::getInstance()->setMode(Video::QUARTER);
+ Video::getInstance()->setPosition(170, 5);
+ VEpg* vepg = new VEpg(NULL, 0);
+ vepg->draw();
+ ViewMan::getInstance()->add(vepg);
+ ViewMan::getInstance()->updateView(vepg);
+ */
+
+ return 2;
+ }
+ case Remote::GREEN:
+ {
+ //player->test2();
+ return 2;
+ }
+#endif
+
+ }
+
+ return 1;
+}
+
+void VRadioRec::processMessage(Message* m)
+{
+ if (m->from != player) return;
+ if (m->message != Message::PLAYER_EVENT) return;
+
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");
+
+ switch(m->parameter)
+ {
+ case Player::CONNECTION_LOST: // connection lost detected
+ {
+ // I can't handle this, send it to command
+ Message* m = new Message();
+ m->to = Command::getInstance();
+ m->message = Message::CONNECTION_LOST;
+ Command::getInstance()->postMessageNoLock(m);
+ break;
+ }
+ case Player::STOP_PLAYBACK:
+ {
+ // FIXME Obselete ish - improve this
+ Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
+ m->to = Command::getInstance();
+ m->message = Message::STOP_PLAYBACK;
+ Command::getInstance()->postMessageNoLock(m);
+ break;
+ }
+ }
+}
+
+void VRadioRec::stopPlay()
+{
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");
+
+ // FIXME work out a better soln for this
+ // Fix a problem to do with thread sync here
+ // because the bar gets a timer every 0.2s and it seems to take up to 0.1s,
+ // (or maybe just the wrong thread being selected?) for the main loop to lock and process
+ // the video stop message it is possible for a bar message to stack up after a stop message
+ // when the bar message is finally processed the prog crashes because this is deleted by then
+ removeBar();
+ //
+
+ player->stop();
+ vdr->stopStreaming();
+ delete player;
+
+ playing = false;
+
+ if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
+ Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");
+}
+
+void VRadioRec::doBar(int action)
+{
+ barShowing = true;
+
+ rectangle(barRegion, barBlue);
+
+ /* Work out what to display - choices:
+
+ Playing >
+ Paused ||
+
+ Specials, informed by parameter
+
+ Skip forward 10s >|
+ Skip backward 10s |<
+ Skip forward 1m >>|
+ Skip backward 1m |<<
+
+ */
+
+ WSymbol w;
+ w.setSurface(surface);
+ w.nextSymbol = 0;
+ w.setSurfaceOffset(barRegion.x + 66, barRegion.y + 16);
+
+ UCHAR playerState = 0;
+
+ if (action)
+ {
+ if (action == 1) w.nextSymbol = WSymbol::SKIPFORWARD;
+ else if (action == 2) w.nextSymbol = WSymbol::SKIPBACK;
+ else if (action == 3) w.nextSymbol = WSymbol::SKIPFORWARD2;
+ else if (action == 4) w.nextSymbol = WSymbol::SKIPBACK2;
+ }
+ else
+ {
+ playerState = player->getState();
+ if (playerState == Player::S_PAUSE_P) w.nextSymbol = WSymbol::PAUSE;
+ else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
+ else w.nextSymbol = WSymbol::PLAY;
+ }
+
+ w.draw();
+
+ drawBarClocks();
+
+ ViewMan::getInstance()->updateView(this, &barRegion);
+
+ timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd
+ timers->setTimerD(this, 2, 0, 200000000);
+}
+
+void VRadioRec::timercall(int clientReference)
+{
+ switch(clientReference)
+ {
+ case 1:
+ {
+ // Remove bar
+ removeBar();
+ break;
+ }
+ case 2:
+ {
+ // Update clock
+ if (!barShowing) break;
+ drawBarClocks();
+ ViewMan::getInstance()->updateView(this, &barRegion);
+ timers->setTimerD(this, 2, 0, 200000000);
+ break;
+ }
+ }
+}
+
+void VRadioRec::drawBarClocks()
+{
+ Log* logger = Log::getInstance();
+ logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");
+
+ // Draw RTC
+ // Blank the area first
+ rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
+ char timeString[20];
+ time_t t;
+ time(&t);
+ struct tm* tms = localtime(&t);
+ strftime(timeString, 19, "%H:%M", tms);
+ drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT);
+
+ // Draw clocks
+
+ rectangle(clocksRegion, barBlue);
+
+/*
+ ULONG currentFrameNum = player->getCurrentFrameNum();
+ ULONG lengthFrames;
+ if (myRec->recInfo->timerEnd > time(NULL))
+ {
+ // chasing playback
+ // Work out an approximate length in frames (good to 1s...)
+ lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
+ }
+ else
+ {
+// lengthFrames = player->getLengthFrames();
+ lengthFrames = 0;
+ }
+
+ hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
+ hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
+
+ char buffer[100];
+ if (currentFrameNum >= lengthFrames)
+ {
+ strcpy(buffer, "-:--:-- / -:--:--");
+ }
+ else
+ {
+ SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
+ logger->log("VRadioRec", Log::DEBUG, buffer);
+ }
+*/
+
+ ULONG currentSeconds = player->getCurrentSeconds();
+ ULONG lengthSeconds = player->getLengthSeconds();
+ char buffer[100];
+
+ if (lengthSeconds && (currentSeconds < lengthSeconds))
+ {
+ ULONG dcurrentSeconds = currentSeconds;
+ ULONG dlengthSeconds = lengthSeconds;
+
+ ULONG currentHours = dcurrentSeconds / 3600;
+ dcurrentSeconds %= 3600;
+ ULONG currentMinutes = dcurrentSeconds / 60;
+ dcurrentSeconds %= 60;
+
+ ULONG lengthHours = dlengthSeconds / 3600;
+ dlengthSeconds %= 3600;
+ ULONG lengthMinutes = dlengthSeconds / 60;
+ dlengthSeconds %= 60;
+
+ SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);
+ logger->log("VRadioRec", Log::DEBUG, buffer);
+ }
+ else
+ {
+ strcpy(buffer, "-:--:-- / -:--:--");
+ }
+
+ drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
+
+
+
+
+ // Draw progress bar
+ int progBarXbase = barRegion.x + 300;
+
+ rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT);
+ rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
+
+ if (currentSeconds > lengthSeconds) return;
+ if (lengthSeconds == 0) return;
+
+ // Draw yellow portion
+ int progressWidth = 302 * currentSeconds / lengthSeconds;
+ rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT);
+/*
+
+ if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
+ {
+ int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes
+
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
+// Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
+ Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
+ rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, Colour::RED);
+ }
+*/
+
+ logger->log("VRadioRec", Log::DEBUG, "blips");
+
+ // Now calc position for start margin blips
+ int posPix;
+
+ posPix = 302 * startMargin / lengthSeconds;
+ logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);
+
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
+
+ posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;
+
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT);
+ rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT);
+}
+
+void VRadioRec::removeBar()
+{
+ if (!barShowing) return;
+ timers->cancelTimer(this, 2);
+ barShowing = false;
+ rectangle(barRegion, Colour::BLACK);
+ ViewMan::getInstance()->updateView(this, &barRegion);
+}
--- /dev/null
+/*
+ Copyright 2004-2006 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef VRADIOREC_H
+#define VRADIOREC_H
+
+#include <stdio.h>
+
+#include "video.h"
+#include "view.h"
+#include "playerradio.h"
+#include "vdr.h"
+#include "recording.h"
+#include "command.h"
+#include "colour.h"
+#include "osd.h"
+#include "timers.h"
+#include "timerreceiver.h"
+#include "message.h"
+
+class Timers;
+
+class VRadioRec : public View, public TimerReceiver
+{
+ public:
+ VRadioRec(Recording* rec);
+ ~VRadioRec();
+ void draw();
+ int handleCommand(int command);
+ void go();
+
+ void timercall(int clientReference);
+ void processMessage(Message* m);
+
+ private:
+ VDR* vdr;
+ Video* video;
+ Timers* timers;
+ PlayerRadio* player;
+ Recording* myRec;
+
+ Colour barBlue;
+
+ bool playing;
+ bool barShowing;
+ bool stickyBar;
+
+ void doBar(int action);
+ void drawBarClocks();
+ void stopPlay();
+ void removeBar();
+ Region barRegion;
+ Region clocksRegion;
+
+ UINT startMargin;
+ UINT endMargin;
+};
+
+#endif
if (toPlay)
{
toPlay->loadRecInfo();
- VVideoRec* vidrec = new VVideoRec(toPlay);
- vidrec->draw();
- viewman->add(vidrec);
- viewman->updateView(vidrec);
- vidrec->go(resume);
+ if (toPlay->recInfo->hasVideo())
+ {
+ VVideoRec* vidrec = new VVideoRec(toPlay);
+ vidrec->draw();
+ viewman->add(vidrec);
+ viewman->updateView(vidrec);
+ vidrec->go(resume);
+ }
+ else
+ {
+ VRadioRec* radrec = new VRadioRec(toPlay);
+ radrec->draw();
+ viewman->add(radrec);
+ viewman->updateView(radrec);
+ radrec->go();
+ }
return 1;
}
// should not get to here
#include "vrecordingmenu.h"
#include "vdr.h"
#include "vvideorec.h"
+#include "vradiorec.h"
#include "colour.h"
#include "video.h"
#include "i18n.h"
#include <stdio.h>
+#include "video.h"
#include "view.h"
#include "player.h"
#include "vdr.h"