]> git.vomp.tv Git - vompclient.git/commitdiff
Rename class: PlayerRadio to PlayerRadioRec
authorChris Tallon <chris@vomp.tv>
Tue, 3 Mar 2020 22:02:20 +0000 (22:02 +0000)
committerChris Tallon <chris@vomp.tv>
Tue, 3 Mar 2020 22:02:20 +0000 (22:02 +0000)
objects.mk
playerradio.cc [deleted file]
playerradio.h [deleted file]
playerradiorec.cc [new file with mode: 0644]
playerradiorec.h [new file with mode: 0644]
vradiorec.cc
vradiorec.h

index 5fa280591c306b47c26b5a72b42aaaf0f5d516a6..8be322774422cdae21563d383b0789388e02b862 100644 (file)
@@ -1,7 +1,7 @@
 OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.o               \
              message.o messagequeue.o wol.o audio.o video.o log.o                  \
              vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o     \
-             directory.o mark.o option.o playerradio.o vfeed.o afeed.o             \
+             directory.o mark.o option.o vfeed.o afeed.o                           \
              demuxer.o demuxervdr.o demuxerts.o stream.o osd.o surface.o           \
              region.o colour.o boxstack.o boxx.o tbboxx.o vrecording.o             \
              vinfo.o vquestion.o vrecordinglist.o vrecordinglistclassic.o          \
@@ -19,7 +19,7 @@ OBJ_COMMON = command.o tcp.o dsock.o thread.o timers.o i18n.o vdp6.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 playerradiolive.o
+             playervideorec.o playervideolive.o playerradiolive.o playerradiorec.o
 
 OBJ_RASPBERRY = main.o threadp.o osdopenvg.o                                       \
                 ledraspberry.o videoomx.o audioomx.o imageomx.o                    \
diff --git a/playerradio.cc b/playerradio.cc
deleted file mode 100644 (file)
index a1f9c1f..0000000
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
-    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, see <https://www.gnu.org/licenses/>.
-*/
-
-#include "log.h"
-#include "audio.h"
-#include "video.h"
-#include "demuxervdr.h"
-#include "demuxerts.h"
-#include "input.h"
-#include "vdr.h"
-#include "message.h"
-#include "messagequeue.h"
-
-#include "playerradio.h"
-
-// ----------------------------------- Called from outside, one offs or info funcs
-
-PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver)
-: messageQueue(tmessageQueue), messageReceiver(tmessageReceiver), afeed(this)
-{
-  audio = Audio::getInstance();
-  logger = Log::getInstance();
-  vdr = VDR::getInstance();
-  Video::getInstance()->turnVideoOff();
-}
-
-PlayerRadio::~PlayerRadio()
-{
-  if (initted) shutdown();
-}
-
-bool PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthFrames, bool isPesRecording)
-{
-  if (initted) return false;
-
-  if (isPesRecording)
-    demuxer = new DemuxerVDR();
-  else
-    demuxer = new DemuxerTS();
-  if (!demuxer) return false;
-
-  if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))
-  {
-    logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
-    shutdown();
-    return false;
-  }
-
-  audio->stop();
-
-  lengthBytes = tlengthBytes;
-  lengthFrames = tlengthFrames;
-
-  logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
-
-  UINT thisRead = 0;
-  int success;
-
-  UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
-  if (!buffer)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
-    shutdown();
-    if (!vdr->isConnected()) doConnectionLost();
-    return false;
-  }
-
-  success = demuxer->findPTS(buffer, thisRead, &startPTS);
-  if (!success)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
-    free(buffer);
-    shutdown();
-    return false;
-  }
-
-  free(buffer);
-
-  if (!setLengthSeconds())
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");
-    shutdown();
-    return false;
-  }
-
-  initted = true;
-  return true;
-}
-
-bool PlayerRadio::setLengthSeconds()
-{
-  int success;
-  ULLONG endPTS = 0;
-  UINT thisRead = 0;
-  UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
-  if (!buffer)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
-    if (!vdr->isConnected()) doConnectionLost();    
-    return false;
-  }
-
-  success = demuxer->findPTS(buffer, thisRead, &endPTS);
-  free(buffer);
-  if (!success)
-  {
-    logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
-    return false;
-  }
-
-  if (startPTS < endPTS)
-  {
-    lengthSeconds = static_cast<ULONG>((endPTS - startPTS) / 90000);
-  }
-  else
-  {
-    lengthSeconds = static_cast<ULONG>((startPTS - endPTS) / 90000);
-  }
-
-  return true;
-}
-
-int PlayerRadio::shutdown()
-{
-  if (!initted) return 0;
-  switchState(S_STOP);
-  initted = false;
-
-  delete demuxer;
-  demuxer = NULL;
-
-  return 1;
-}
-
-
-void PlayerRadio::setCurrentFrameNumber(ULONG num)
-{
-  currentFrameNumber = num;
-}
-
-ULONG PlayerRadio::getLengthSeconds()
-{
-  return lengthSeconds;
-}
-
-ULONG PlayerRadio::getCurrentSeconds()
-{
-  if (startup) return 0;
-
-  long long currentPTS = demuxer->getAudioPTS();
-  currentPTS -= startPTS;
-  if (currentPTS < 0) currentPTS += 8589934592ULL;
-  ULONG ret = static_cast<ULONG>(currentPTS / 90000);
-  return ret;
-}
-
-// ----------------------------------- Externally called events
-
-void PlayerRadio::play()
-{
-  if (!initted) return;
-  if (state == S_PLAY) return;
-  stateLock.lock();
-  switchState(S_PLAY);
-  stateLock.unlock();
-}
-
-
-void PlayerRadio::playpause()
-{
-  if (!initted) return;
-  stateLock.lock();
-  if (state==S_PLAY) {
-         switchState(S_PAUSE_P);
-  } else {
-         switchState(S_PLAY);
-  }
-  stateLock.unlock();
-}
-
-void PlayerRadio::stop()
-{
-  if (!initted) return;
-  if (state == S_STOP) return;
-  stateLock.lock();
-  logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
-  switchState(S_STOP);
-  stateLock.unlock();
-}
-
-void PlayerRadio::pause()
-{
-  if (!initted) return;
-  stateLock.lock();
-
-  if (state == S_PAUSE_P)
-  {
-    switchState(S_PLAY);
-  }
-  else
-  {
-    switchState(S_PAUSE_P);
-  }
-
-  stateLock.unlock();
-}
-
-void PlayerRadio::jumpToPercent(double percent)
-{
-  stateLock.lock();
-  logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
-  ULONG newFrame = static_cast<ULONG>(percent * lengthFrames / 100);
-  switchState(S_JUMP, newFrame);
-  stateLock.unlock();
-}
-
-void PlayerRadio::skipForward(UINT seconds)
-{
-  stateLock.lock();
-  logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
-  ULONG currentSeconds = getCurrentSeconds();
-  ULONG currentFrame = demuxer->getPacketNum();
-
-  if (currentSeconds == 0) { stateLock.unlock(); return; } // div by zero
-  if (currentFrame == 0) { stateLock.unlock(); return; } // Current pos from demuxer is not valid
-
-  ULONG newFrame = currentFrame + (currentFrame * seconds / currentSeconds);
-  if (newFrame > lengthFrames) { switchState(S_PLAY); stateLock.unlock(); }
-  else switchState(S_JUMP, newFrame);
-  stateLock.unlock();
-}
-
-void PlayerRadio::skipBackward(UINT seconds)
-{
-  stateLock.lock();
-  logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
-
-  ULONG currentSeconds = getCurrentSeconds();
-  ULONG currentFrame = demuxer->getPacketNum();
-
-  if (currentSeconds == 0) { stateLock.unlock(); return; } // div by zero
-  if (currentFrame == 0) { stateLock.unlock(); return; } // Current pos from demuxer is not valid
-
-  ULONG newFrame;
-  if (seconds > currentSeconds)
-    newFrame = 0;
-  else
-    newFrame = currentFrame - (currentFrame * seconds / currentSeconds);
-
-  switchState(S_JUMP, newFrame);
-  stateLock.unlock();
-}
-
-// ----------------------------------- Implementations called events
-
-void PlayerRadio::switchState(UCHAR toState, ULONG jumpToFrame)
-{
-  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(jumpToFrame);
-          return;
-        }
-      }
-    }
-    FALLTHROUGH // keep compiler happy (all posibilities 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(jumpToFrame);
-          return;
-        }
-      }
-    }
-    FALLTHROUGH // keep compiler happy (all posibilities return)
-    case S_STOP: // from S_STOP -----------------------------------
-    {
-      switch(toState)
-      {
-        case S_PLAY: // to S_PLAY
-        {
-          startup = true;
-
-          audio->reset();
-          audio->setStreamType(Audio::MPEG2_PES);
-          audio->systemMuteOff();
-          demuxer->reset();
-
-          // FIXME use restartAtFrame here?
-          if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
-          demuxer->setPacketNum(currentFrameNumber);
-          state = S_PLAY;
-          threadStart();
-          logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
-          afeed.start();
-          audio->play();
-
-          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::restartAtFrame(ULONG newFrame)
-{
-  afeed.stop();
-  threadStop();
-  audio->reset();
-  audio->setStreamType(Audio::MPEG2_PES);
-  demuxer->flush();
-  currentFrameNumber = newFrame;
-  demuxer->setPacketNum(newFrame);
-  afeed.start();
-  threadStart();
-  audio->play();
-  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 (state == S_PLAY) threadFeedPlay();
-}
-
-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 (!setLengthSeconds())
-      {
-        logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");
-        return;
-      }
-    }
-
-    if (feedPosition >= lengthBytes) break;  // finished playback
-
-    if (startup)
-    {
-      if (startupBlockSize > lengthBytes)
-        askFor = static_cast<UINT>(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 = static_cast<UINT>(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;
-  }
-}
-
diff --git a/playerradio.h b/playerradio.h
deleted file mode 100644 (file)
index 57e6625..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*/
-
-#ifndef PLAYERRADIO_H
-#define PLAYERRADIO_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef WIN32
-#include <sys/time.h>
-#endif
-#include <time.h>
-
-#include <mutex>
-
-#include "threadsystem.h"
-
-#include "callback.h"
-#include "defines.h"
-#include "afeed.h"
-
-class Log;
-class Audio;
-class Video;
-class Demuxer;
-class VDR;
-class MessageQueue;
-
-/*
- * Frames...
- *
- * VDR tells me there are around 8.3 "frames" per second in radio recordings.
- * I don't know where this comes from but things seem to work.
- */
-
-class PlayerRadio : public Thread_TYPE, public Callback
-{
-  public:
-    PlayerRadio(MessageQueue* messageQueue, void* messageReceiver);
-    virtual ~PlayerRadio();
-
-    bool init(ULLONG lengthBytes, ULONG lengthFrames, bool IsPesRecording);
-    int shutdown();
-    void setCurrentFrameNumber(ULONG num);
-
-    void play();
-    void stop();
-    void pause();
-    void playpause();
-    void jumpToPercent(double percent);
-    void skipForward(UINT seconds);
-    void skipBackward(UINT 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_PAUSE_I = 3;
-    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 jumpToFrame=0);
-
-    void threadFeedPlay();
-    void threadFeedScan();
-
-    void doConnectionLost();
-    void restartAtFrame(ULONG newFrame);
-    bool setLengthSeconds();
-
-    MessageQueue* messageQueue;
-    void* messageReceiver;
-    Log* logger;
-    Audio* audio;
-    Demuxer* demuxer;
-    VDR* vdr;
-    AFeed afeed;
-
-    bool initted{};
-    bool startup;
-
-    ULLONG startPTS{};
-    ULONG lengthSeconds{};
-
-    std::mutex stateLock;
-
-    ULLONG lengthBytes{};
-    ULONG lengthFrames{};
-    ULONG currentFrameNumber{};
-    static const UINT blockSize{10000};
-    static const UINT startupBlockSize{20000};
-    UCHAR* threadBuffer{};
-    UCHAR state{S_STOP};
-};
-
-#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
-
-*/
diff --git a/playerradiorec.cc b/playerradiorec.cc
new file mode 100644 (file)
index 0000000..0fdf0ad
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+    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, see <https://www.gnu.org/licenses/>.
+*/
+
+#include "log.h"
+#include "audio.h"
+#include "video.h"
+#include "demuxervdr.h"
+#include "demuxerts.h"
+#include "input.h"
+#include "vdr.h"
+#include "message.h"
+#include "messagequeue.h"
+
+#include "playerradiorec.h"
+
+// ----------------------------------- Called from outside, one offs or info funcs
+
+PlayerRadioRec::PlayerRadioRec(MessageQueue* tmessageQueue, void* tmessageReceiver)
+: messageQueue(tmessageQueue), messageReceiver(tmessageReceiver), afeed(this)
+{
+  audio = Audio::getInstance();
+  logger = Log::getInstance();
+  vdr = VDR::getInstance();
+  Video::getInstance()->turnVideoOff();
+}
+
+PlayerRadioRec::~PlayerRadioRec()
+{
+  if (initted) shutdown();
+}
+
+bool PlayerRadioRec::init(ULLONG tlengthBytes, ULONG tlengthFrames, bool isPesRecording)
+{
+  if (initted) return false;
+
+  if (isPesRecording)
+    demuxer = new DemuxerVDR();
+  else
+    demuxer = new DemuxerTS();
+  if (!demuxer) return false;
+
+  if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0))
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Demuxer failed to init");
+    shutdown();
+    return false;
+  }
+
+  audio->stop();
+
+  lengthBytes = tlengthBytes;
+  lengthFrames = tlengthFrames;
+
+  logger->log("PlayerRadioRec", Log::DEBUG, "PlayerRadioRec has received length bytes of %llu", lengthBytes);
+
+  UINT thisRead = 0;
+  int success;
+
+  UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
+  if (!buffer)
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Failed to get start block");
+    shutdown();
+    if (!vdr->isConnected()) doConnectionLost();
+    return false;
+  }
+
+  success = demuxer->findPTS(buffer, thisRead, &startPTS);
+  if (!success)
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Failed to get start PTS");
+    free(buffer);
+    shutdown();
+    return false;
+  }
+
+  free(buffer);
+
+  if (!setLengthSeconds())
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Failed to setLengthSeconds");
+    shutdown();
+    return false;
+  }
+
+  initted = true;
+  return true;
+}
+
+bool PlayerRadioRec::setLengthSeconds()
+{
+  int success;
+  ULLONG endPTS = 0;
+  UINT thisRead = 0;
+  UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
+  if (!buffer)
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Failed to get end block");
+    if (!vdr->isConnected()) doConnectionLost();    
+    return false;
+  }
+
+  success = demuxer->findPTS(buffer, thisRead, &endPTS);
+  free(buffer);
+  if (!success)
+  {
+    logger->log("PlayerRadioRec", Log::ERR, "Failed to get end PTS");
+    return false;
+  }
+
+  if (startPTS < endPTS)
+  {
+    lengthSeconds = static_cast<ULONG>((endPTS - startPTS) / 90000);
+  }
+  else
+  {
+    lengthSeconds = static_cast<ULONG>((startPTS - endPTS) / 90000);
+  }
+
+  return true;
+}
+
+int PlayerRadioRec::shutdown()
+{
+  if (!initted) return 0;
+  switchState(S_STOP);
+  initted = false;
+
+  delete demuxer;
+  demuxer = NULL;
+
+  return 1;
+}
+
+
+void PlayerRadioRec::setCurrentFrameNumber(ULONG num)
+{
+  currentFrameNumber = num;
+}
+
+ULONG PlayerRadioRec::getLengthSeconds()
+{
+  return lengthSeconds;
+}
+
+ULONG PlayerRadioRec::getCurrentSeconds()
+{
+  if (startup) return 0;
+
+  long long currentPTS = demuxer->getAudioPTS();
+  currentPTS -= startPTS;
+  if (currentPTS < 0) currentPTS += 8589934592ULL;
+  ULONG ret = static_cast<ULONG>(currentPTS / 90000);
+  return ret;
+}
+
+// ----------------------------------- Externally called events
+
+void PlayerRadioRec::play()
+{
+  if (!initted) return;
+  if (state == S_PLAY) return;
+  stateLock.lock();
+  switchState(S_PLAY);
+  stateLock.unlock();
+}
+
+
+void PlayerRadioRec::playpause()
+{
+  if (!initted) return;
+  stateLock.lock();
+  if (state==S_PLAY) {
+         switchState(S_PAUSE_P);
+  } else {
+         switchState(S_PLAY);
+  }
+  stateLock.unlock();
+}
+
+void PlayerRadioRec::stop()
+{
+  if (!initted) return;
+  if (state == S_STOP) return;
+  stateLock.lock();
+  logger->log("PlayerRadioRec", Log::DEBUG, "Stop called lock");
+  switchState(S_STOP);
+  stateLock.unlock();
+}
+
+void PlayerRadioRec::pause()
+{
+  if (!initted) return;
+  stateLock.lock();
+
+  if (state == S_PAUSE_P)
+  {
+    switchState(S_PLAY);
+  }
+  else
+  {
+    switchState(S_PAUSE_P);
+  }
+
+  stateLock.unlock();
+}
+
+void PlayerRadioRec::jumpToPercent(double percent)
+{
+  stateLock.lock();
+  logger->log("PlayerRadioRec", Log::DEBUG, "JUMP TO %i%%", percent);
+  ULONG newFrame = static_cast<ULONG>(percent * lengthFrames / 100);
+  switchState(S_JUMP, newFrame);
+  stateLock.unlock();
+}
+
+void PlayerRadioRec::skipForward(UINT seconds)
+{
+  stateLock.lock();
+  logger->log("PlayerRadioRec", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
+  ULONG currentSeconds = getCurrentSeconds();
+  ULONG currentFrame = demuxer->getPacketNum();
+
+  if (currentSeconds == 0) { stateLock.unlock(); return; } // div by zero
+  if (currentFrame == 0) { stateLock.unlock(); return; } // Current pos from demuxer is not valid
+
+  ULONG newFrame = currentFrame + (currentFrame * seconds / currentSeconds);
+  if (newFrame > lengthFrames) { switchState(S_PLAY); stateLock.unlock(); }
+  else switchState(S_JUMP, newFrame);
+  stateLock.unlock();
+}
+
+void PlayerRadioRec::skipBackward(UINT seconds)
+{
+  stateLock.lock();
+  logger->log("PlayerRadioRec", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
+
+  ULONG currentSeconds = getCurrentSeconds();
+  ULONG currentFrame = demuxer->getPacketNum();
+
+  if (currentSeconds == 0) { stateLock.unlock(); return; } // div by zero
+  if (currentFrame == 0) { stateLock.unlock(); return; } // Current pos from demuxer is not valid
+
+  ULONG newFrame;
+  if (seconds > currentSeconds)
+    newFrame = 0;
+  else
+    newFrame = currentFrame - (currentFrame * seconds / currentSeconds);
+
+  switchState(S_JUMP, newFrame);
+  stateLock.unlock();
+}
+
+// ----------------------------------- Implementations called events
+
+void PlayerRadioRec::switchState(UCHAR toState, ULONG jumpToFrame)
+{
+  if (!initted) return;
+
+  logger->log("PlayerRadioRec", 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(jumpToFrame);
+          return;
+        }
+      }
+    }
+    FALLTHROUGH // keep compiler happy (all posibilities 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(jumpToFrame);
+          return;
+        }
+      }
+    }
+    FALLTHROUGH // keep compiler happy (all posibilities return)
+    case S_STOP: // from S_STOP -----------------------------------
+    {
+      switch(toState)
+      {
+        case S_PLAY: // to S_PLAY
+        {
+          startup = true;
+
+          audio->reset();
+          audio->setStreamType(Audio::MPEG2_PES);
+          audio->systemMuteOff();
+          demuxer->reset();
+
+          // FIXME use restartAtFrame here?
+          if (currentFrameNumber > lengthFrames) currentFrameNumber = 0;
+          demuxer->setPacketNum(currentFrameNumber);
+          state = S_PLAY;
+          threadStart();
+          logger->log("PlayerRadioRec", Log::DEBUG, "Immediate play");
+          afeed.start();
+          audio->play();
+
+          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 PlayerRadioRec::restartAtFrame(ULONG newFrame)
+{
+  afeed.stop();
+  threadStop();
+  audio->reset();
+  audio->setStreamType(Audio::MPEG2_PES);
+  demuxer->flush();
+  currentFrameNumber = newFrame;
+  demuxer->setPacketNum(newFrame);
+  afeed.start();
+  threadStart();
+  audio->play();
+  audio->systemMuteOff();
+  audio->doMuting();
+}
+
+void PlayerRadioRec::doConnectionLost()
+{
+  logger->log("PlayerRadioRec", Log::DEBUG, "Connection lost, sending message");
+  Message* m = new Message();
+  m->to = messageReceiver;
+  m->from = this;
+  m->message = Message::PLAYER_EVENT;
+  m->parameter = PlayerRadioRec::CONNECTION_LOST;
+  messageQueue->postMessage(m);
+}
+
+// ----------------------------------- Callback
+
+void PlayerRadioRec::call(void* /*caller*/)
+{
+  threadSignalNoLock();
+}
+
+// ----------------------------------- Feed thread
+
+void PlayerRadioRec::threadMethod()
+{
+  if (state == S_PLAY) threadFeedPlay();
+}
+
+void PlayerRadioRec::threadFeedPlay()
+{
+  ULLONG feedPosition;
+  UINT thisRead, writeLength, thisWrite, askFor;
+  time_t lastRescan = time(NULL);
+
+  feedPosition = vdr->positionFromFrameNumber(currentFrameNumber);
+  if (!vdr->isConnected()) { doConnectionLost(); return; }
+  logger->log("PlayerRadioRec", 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("PlayerRadioRec", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
+      lastRescan = time(NULL);
+
+      if (!setLengthSeconds())
+      {
+        logger->log("PlayerRadioRec", Log::ERR, "Failed to setLengthSeconds in thread");
+        return;
+      }
+    }
+
+    if (feedPosition >= lengthBytes) break;  // finished playback
+
+    if (startup)
+    {
+      if (startupBlockSize > lengthBytes)
+        askFor = static_cast<UINT>(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 = static_cast<UINT>(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("PlayerRadioRec", 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("PlayerRadioRec", 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 = PlayerRadioRec::STOP_PLAYBACK;
+  logger->log("PlayerRadioRec", Log::DEBUG, "Posting message to %p...", messageQueue);
+  messageQueue->postMessage(m);
+}
+
+void PlayerRadioRec::threadPostStopCleanup()
+{
+  if (threadBuffer)
+  {
+    free(threadBuffer);
+    threadBuffer = NULL;
+  }
+}
+
diff --git a/playerradiorec.h b/playerradiorec.h
new file mode 100644 (file)
index 0000000..56a9fc9
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef PLAYERRADIOREC_H
+#define PLAYERRADIOREC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include <mutex>
+
+#include "threadsystem.h"
+
+#include "callback.h"
+#include "defines.h"
+#include "afeed.h"
+
+class Log;
+class Audio;
+class Video;
+class Demuxer;
+class VDR;
+class MessageQueue;
+
+/*
+ * Frames...
+ *
+ * VDR tells me there are around 8.3 "frames" per second in radio recordings.
+ * I don't know where this comes from but things seem to work.
+ */
+
+class PlayerRadioRec : public Thread_TYPE, public Callback
+{
+  public:
+    PlayerRadioRec(MessageQueue* messageQueue, void* messageReceiver);
+    virtual ~PlayerRadioRec();
+
+    bool init(ULLONG lengthBytes, ULONG lengthFrames, bool IsPesRecording);
+    int shutdown();
+    void setCurrentFrameNumber(ULONG num);
+
+    void play();
+    void stop();
+    void pause();
+    void playpause();
+    void jumpToPercent(double percent);
+    void skipForward(UINT seconds);
+    void skipBackward(UINT 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_PAUSE_I = 3;
+    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 jumpToFrame=0);
+
+    void threadFeedPlay();
+    void threadFeedScan();
+
+    void doConnectionLost();
+    void restartAtFrame(ULONG newFrame);
+    bool setLengthSeconds();
+
+    MessageQueue* messageQueue;
+    void* messageReceiver;
+    Log* logger;
+    Audio* audio;
+    Demuxer* demuxer;
+    VDR* vdr;
+    AFeed afeed;
+
+    bool initted{};
+    bool startup;
+
+    ULLONG startPTS{};
+    ULONG lengthSeconds{};
+
+    std::mutex stateLock;
+
+    ULLONG lengthBytes{};
+    ULONG lengthFrames{};
+    ULONG currentFrameNumber{};
+    static const UINT blockSize{10000};
+    static const UINT startupBlockSize{20000};
+    UCHAR* threadBuffer{};
+    UCHAR state{S_STOP};
+};
+
+#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
+
+*/
index f574ef3b7afe2ab2988c53e11e79c4ef0813abf2..dec56c2513f2e6e021be80d598ddf54e6a49acb1 100644 (file)
@@ -25,7 +25,7 @@
 #include "message.h"
 #include "vdr.h"
 #include "video.h"
-#include "playerradio.h"
+#include "playerradiorec.h"
 #include "boxstack.h"
 #include "input.h"
 #include "vinfo.h"
@@ -46,7 +46,7 @@ VRadioRec::VRadioRec(Recording* rec)
   startMargin = 0;
   endMargin = 0;
 
-  player = new PlayerRadio(Command::getInstance(), this);
+  player = new PlayerRadioRec(Command::getInstance(), this);
 
   char* cstartMargin = vdr->configLoad("Timers", "Start margin");
   char* cendMargin = vdr->configLoad("Timers", "End margin");
@@ -311,7 +311,7 @@ void VRadioRec::processMessage(Message* m)
 
     switch(m->parameter)
     {
-      case PlayerRadio::CONNECTION_LOST: // connection lost detected
+      case PlayerRadioRec::CONNECTION_LOST: // connection lost detected
       {
         // I can't handle this, send it to command
         Message* m2 = new Message();
@@ -320,7 +320,7 @@ void VRadioRec::processMessage(Message* m)
         MessageQueue::getInstance()->postMessage(m2);
         break;
       }
-      case PlayerRadio::STOP_PLAYBACK:
+      case PlayerRadioRec::STOP_PLAYBACK:
       {
         // FIXME Obselete ish - improve this
         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
@@ -385,8 +385,8 @@ void VRadioRec::doBar(int action)
   else
   {
     playerState = player->getState();
-    if (playerState == PlayerRadio::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
-    else if (playerState == PlayerRadio::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
+    if (playerState == PlayerRadioRec::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
+    else if (playerState == PlayerRadioRec::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
     else                                            w.nextSymbol = WSymbol::PLAY;
   }
 
index dfff16d8eadeebc0a701032db43bbcba83463226..b333628694e7a88eca85546f21d1a358967f5310 100644 (file)
@@ -30,7 +30,7 @@ class Recording;
 class Message;
 class VDR;
 class Video;
-class PlayerRadio;
+class PlayerRadioRec;
 class BoxStack;
 
 class VRadioRec : public Boxx, public TimerReceiver
@@ -50,7 +50,7 @@ class VRadioRec : public Boxx, public TimerReceiver
     VDR* vdr;
     Video* video;
     Timers* timers;
-    PlayerRadio* player;
+    PlayerRadioRec* player;
     Recording* myRec;
     BoxStack* boxstack;