]> git.vomp.tv Git - vompclient.git/commitdiff
Live radio half way there
authorChris Tallon <chris@vomp.tv>
Wed, 2 Apr 2008 20:23:07 +0000 (20:23 +0000)
committerChris Tallon <chris@vomp.tv>
Wed, 2 Apr 2008 20:23:07 +0000 (20:23 +0000)
GNUmakefile
afeed.cc
objects.mk
playerlive.h [new file with mode: 0644]
playerliveradio.cc [new file with mode: 0644]
playerliveradio.h [new file with mode: 0644]
playerlivetv.cc
playerlivetv.h
vchannellist.cc
vvideolivetv.cc
vvideolivetv.h

index 11c6f9480fe81088d1df405715be5189f546148e..ebef069c44411ecb97692ea3742c5782daa06204 100644 (file)
@@ -38,8 +38,8 @@ strip:
        $(STRIP) vompclient
 
 install:
-       rm -f /diskless/nfs/mvp/vompclient
-       cp vompclient /diskless/nfs/mvp
+       rm -f /mnt/auto/defiant/diskless/nfs/mvp/vompclient
+       cp vompclient /mnt/auto/defiant/diskless/nfs/mvp
 
 install-wmp:
        rm -f /diskless/nfs/wmvp/vompclient
index f6502015f4bd23488985e0df2a92f7fb7ca68d9f..9250c036357a3bf34a686da2a5fe82712b92713b 100644 (file)
--- a/afeed.cc
+++ b/afeed.cc
@@ -77,6 +77,7 @@ void AFeed::threadMethod()
       if (alen)
       {
         cb.call(this);
+        Log::getInstance()->log("Afeed", Log::DEBUG, "written");
       }
       else
       {
index bd8ee208c6040838cd4c222e27173631e8fe874a..04784277aa5987480f7d9e1c3a47d49f5bb5e196 100644 (file)
@@ -18,4 +18,4 @@ OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o     \
            vaudioplayer.o audioplayer.o demuxeraudio.o abstractoption.o       \
            eventdispatcher.o vdrrequestpacket.o vdrresponsepacket.o           \
            vvideolivetv.o                                                     \
-           vvideolive.o vlivebanner.o playerlivetv.o
+           vvideolive.o vlivebanner.o playerlivetv.o playerliveradio.o
diff --git a/playerlive.h b/playerlive.h
new file mode 100644 (file)
index 0000000..4321c77
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+    Copyright 2004-2005 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 PLAYERLIVE_H
+#define PLAYERLIVE_H
+
+#include "defines.h"
+
+struct StreamChunk
+{
+  void* data;
+  ULONG len;
+};
+
+struct PLInstruction
+{
+  UCHAR instruction;
+  ULONG channelIndex;
+};
+
+class PlayerLive
+{
+  public:
+    virtual ~PlayerLive() {}
+
+    virtual int init()=0;
+    virtual int shutdown()=0;
+
+    virtual void go(ULONG index)=0;
+    virtual void setChannel(ULONG index)=0;
+    virtual void stop()=0;
+    virtual void setAudioChannel(int newChannel)=0;
+
+    virtual bool* getDemuxerMpegAudioChannels()=0;
+    virtual bool* getDemuxerAc3AudioChannels()=0;
+    virtual int getCurrentAudioChannel()=0;
+};
+
+#endif
+
diff --git a/playerliveradio.cc b/playerliveradio.cc
new file mode 100644 (file)
index 0000000..6ea19d6
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+    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, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include "playerliveradio.h"
+
+#include "log.h"
+#include "audio.h"
+#include "demuxerts.h"
+#include "vdr.h"
+#include "messagequeue.h"
+#include "remote.h"
+#include "message.h"
+#include "channel.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;
+}
+
+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, 0, 40000))
+  {
+    logger->log("PlayerLiveRadio", Log::ERR, "Demuxer failed to init");
+    shutdown();
+    return 0;
+  }
+
+  afeed.init();
+  audio->stop();
+
+  initted = true;
+  return 1;
+}
+
+int PlayerLiveRadio::shutdown()
+{
+  if (!initted) return 0;
+  stop();
+  initted = false;
+
+  delete demuxer;
+
+#ifdef WIN32
+  CloseHandle(mutex);
+#endif
+
+  return 1;
+}
+
+bool* PlayerLiveRadio::getDemuxerMpegAudioChannels()
+{
+  return demuxer->getmpAudioChannels();
+}
+
+bool* PlayerLiveRadio::getDemuxerAc3AudioChannels()
+{
+  return demuxer->getac3AudioChannels();
+}
+
+int PlayerLiveRadio::getCurrentAudioChannel()
+{
+  return demuxer->getAID();
+}
+
+void PlayerLiveRadio::setAudioChannel(int newChannel)
+{
+  return demuxer->setAID(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);  
+  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(void* data, ULONG len)
+{
+  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->sync();
+          audio->play();
+          audio->pause();
+
+          demuxer->reset();
+//          demuxer->seek();
+
+          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;        
+        }
+        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();
+          vfeed.stop();
+          afeed.stop();
+          video->stop();
+          video->blank();
+          audio->stop();
+          audio->unPause();
+          audio->reset();
+
+          video->reset();
+          video->sync();
+          video->play();
+          video->pause();
+
+          audio->setStreamType(Audio::MPEG2_PES);
+          audio->sync();
+          audio->play();
+          audio->pause();
+
+          demuxer->reset();
+          demuxer->seek();
+
+          afeed.start();
+          vfeed.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;
+        }        
+      }
+    }    
+  }  
+}
+
+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) optimizeInstructionQueue();
+
+      struct PLInstruction i = instructions.front();
+      instructions.pop();
+    
+      if (i.instruction == I_SETCHANNEL)
+      {
+        logger->log("PlayerLiveRadio", Log::DEBUG, "start new stream");
+
+        switchState(S_PREBUFFERING);
+
+        Channel* chan = (*chanList)[i.channelIndex];
+        chan->loadPids();
+
+        if (chan->numAPids > 0) 
+        {
+          demuxer->setAID(chan->apids[0].pid);
+          logger->log("PlayerLiveRadio", Log::DEBUG, "Demuxer pids: %u %u", chan->vpid, chan->apids[0].pid);
+        }
+        else 
+        {
+          logger->log("PlayerLiveRadio", Log::WARN, "Demuxer no pids!");
+        }
+
+        vdr->streamChannel(chan->number, this);
+      }
+      else if (i.instruction == I_STOP)
+      {
+        logger->log("PlayerLiveRadio", Log::DEBUG, "Stopping");
+        switchState(S_STOP);
+
+        stopNow = true;
+        break;
+      }
+    }
+
+    if (stopNow) break;
+
+    while(streamChunks.size())
+    {
+      chunkToDemuxer();
+
+      if (state == S_PREBUFFERING)
+      {        
+        if (++preBufferCount == preBufferAmount)
+        {
+          switchState(S_PLAY);
+        }
+      }
+    }
+    
+    threadLock();
+    threadWaitForSignal(); // unlocks and waits for signal
+    threadUnlock();
+  }
+
+  logger->log("PlayerLiveRadio", Log::DEBUG, "End of thread");
+}
+
diff --git a/playerliveradio.h b/playerliveradio.h
new file mode 100644 (file)
index 0000000..794d502
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+    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, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef PLAYERLIVERADIO_H
+#define PLAYERLIVERADIO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include <queue>
+
+#include "playerlive.h"
+
+#ifdef WIN32
+#include "threadwin.h"
+#else
+#include "threadp.h"
+#endif
+
+#include "callback.h"
+#include "defines.h"
+#include "afeed.h"
+#include "vdr.h"
+
+class MessageQueue;
+class Audio;
+class Log;
+class DemuxerTS;
+
+class PlayerLiveRadio : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
+{
+  public:
+    PlayerLiveRadio(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
+    virtual ~PlayerLiveRadio();
+
+    virtual int init();
+    virtual int shutdown();
+
+    virtual void go(ULONG index);
+    virtual void setChannel(ULONG index);
+    virtual void stop();
+    virtual void setAudioChannel(int newChannel);
+
+    virtual bool* getDemuxerMpegAudioChannels();
+    virtual bool* getDemuxerAc3AudioChannels();
+    virtual int getCurrentAudioChannel();
+
+    void call(void*); // for callback interface
+
+    virtual void streamReceive(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;
+
+  protected:
+    void threadMethod();
+    void threadPostStopCleanup() {};
+
+  private:
+    MessageQueue* messageQueue;
+    void* messageReceiver;
+    Log* logger;
+    Audio* audio;
+    DemuxerTS* demuxer;
+    VDR* vdr;
+    AFeed afeed;
+    ChannelList* chanList;
+
+    queue<PLInstruction> instructions;
+    const static UCHAR I_SETCHANNEL = 1;
+    const static UCHAR I_STOP = 2;
+    
+    queue<StreamChunk> streamChunks;
+    
+    bool initted;
+
+    UCHAR state;
+    const static UCHAR S_STOP = 1;
+    const static UCHAR S_PREBUFFERING = 2;
+    const static UCHAR S_PLAY = 3;
+    void switchState(UCHAR newState);
+
+    bool stopNow;
+    int preBufferCount;
+    const static int preBufferAmount = 3;
+
+    void clearStreamChunks();
+    void chunkToDemuxer();
+    void optimizeInstructionQueue();
+};
+
+#endif
+
index 9584a336d0eb7bb8dae052386104d50074082f3d..f32bf58354f4a7d7d8c42c69cafc75dc91780460 100644 (file)
@@ -122,7 +122,7 @@ void PlayerLiveTV::setAudioChannel(int newChannel)
 
 void PlayerLiveTV::go(ULONG index)
 {
-  struct PLTVInstruction i;
+  struct PLInstruction i;
   i.instruction = I_SETCHANNEL;
   i.channelIndex = index;
   instructions.push(i);
@@ -132,7 +132,7 @@ void PlayerLiveTV::go(ULONG index)
 void PlayerLiveTV::setChannel(ULONG index)
 {
   logger->log("PlayerLiveTV", Log::DEBUG, "setChannel");
-  struct PLTVInstruction i;
+  struct PLInstruction i;
   i.instruction = I_SETCHANNEL;
   i.channelIndex = index;
   instructions.push(i);  
@@ -142,7 +142,7 @@ void PlayerLiveTV::setChannel(ULONG index)
 void PlayerLiveTV::stop()
 {
   logger->log("PlayerLiveTV", Log::DEBUG, "stop");
-  struct PLTVInstruction i;
+  struct PLInstruction i;
   i.instruction = I_STOP;
   instructions.push(i);
   threadSignal();
@@ -484,7 +484,7 @@ void PlayerLiveTV::optimizeInstructionQueue()
   
   // Currently there are only 2 instruction types, so this is a bit overkill...
 
-  struct PLTVInstruction i;
+  struct PLInstruction i;
   while(instructions.size() > 1)
   {
     i = instructions.front();
@@ -514,7 +514,7 @@ void PlayerLiveTV::threadMethod()
     {
       if (instructions.size() > 1) optimizeInstructionQueue();
 
-      struct PLTVInstruction i = instructions.front();
+      struct PLInstruction i = instructions.front();
       instructions.pop();
     
       if (i.instruction == I_SETCHANNEL)
index f4de8872e981fd52b8ef0e4e88e3986f98957a38..a1321a854d729b558a237bb3acd979c41f45a89b 100644 (file)
@@ -30,6 +30,8 @@
 
 #include <queue>
 
+#include "playerlive.h"
+
 #ifdef WIN32
 #include "threadwin.h"
 #else
@@ -48,35 +50,23 @@ class Video;
 class Log;
 class DemuxerTS;
 
-struct PLTVInstruction
-{
-  UCHAR instruction;
-  ULONG channelIndex;
-};
-
-struct StreamChunk
-{
-  void* data;
-  ULONG len;
-};
-
-class PlayerLiveTV : public Thread_TYPE, public Callback, public StreamReceiver
+class PlayerLiveTV : public PlayerLive, public Thread_TYPE, public Callback, public StreamReceiver
 {
   public:
     PlayerLiveTV(MessageQueue* messageQueue, void* messageReceiver, ChannelList* chanList);
     virtual ~PlayerLiveTV();
 
-    int init();
-    int shutdown();
+    virtual int init();
+    virtual int shutdown();
 
-    void go(ULONG index);
-    void setChannel(ULONG index);
-    void stop();
-    void setAudioChannel(int newChannel);
+    virtual void go(ULONG index);
+    virtual void setChannel(ULONG index);
+    virtual void stop();
+    virtual void setAudioChannel(int newChannel);
 
-    bool* getDemuxerMpegAudioChannels();
-    bool* getDemuxerAc3AudioChannels();
-    int getCurrentAudioChannel();
+    virtual bool* getDemuxerMpegAudioChannels();
+    virtual bool* getDemuxerAc3AudioChannels();
+    virtual int getCurrentAudioChannel();
 
     void call(void*); // for callback interface
 
@@ -108,7 +98,7 @@ class PlayerLiveTV : public Thread_TYPE, public Callback, public StreamReceiver
     AFeed afeed;
     ChannelList* chanList;
 
-    queue<PLTVInstruction> instructions;
+    queue<PLInstruction> instructions;
     const static UCHAR I_SETCHANNEL = 1;
     const static UCHAR I_STOP = 2;
     
index d9e2a4966d753e8a63afe579eec317741e40ce0c..d624b623d4f5524b57fc8193b36def253f7aac64 100644 (file)
@@ -220,11 +220,12 @@ int VChannelList::handleCommand(int command)
       if (chanList) chan = (Channel*)sl.getCurrentOptionData();
       if (chan == NULL) return 2;
  
-      if (chan->type == VDR::VIDEO)
-      {
+//      if (chan->type == VDR::VIDEO)
+//      {
         VVideoLiveTV* v = new VVideoLiveTV(chanList, chan->number, this);
         boxstack->add(v);
         v->go();
+/*
       }
       else
       {
@@ -234,7 +235,7 @@ int VChannelList::handleCommand(int command)
         boxstack->update(v);
         v->channelChange(VVideoLive::NUMBER, chan->number);
       }
-
+*/
       return 2;
     }
     case Remote::BACK:
index 8f808cc0969239323263788c7ddd9a09a522ce6b..99ea2e116e3b97e6c784e5e255c1cfcf9704ee47 100644 (file)
@@ -22,7 +22,9 @@
 
 #include "vchannellist.h"
 #include "video.h"
+#include "playerlive.h"
 #include "playerlivetv.h"
+#include "playerliveradio.h"
 #include "channel.h"
 #include "boxstack.h"
 #include "colour.h"
@@ -69,7 +71,15 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
   eventList = NULL;
 
   videoMode = video->getMode();
-  player = new PlayerLiveTV(Command::getInstance(), this, chanList);
+  
+  if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
+  {
+    player = new PlayerLiveTV(Command::getInstance(), this, chanList);
+  }
+  else
+  {
+    player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
+  }
   player->init();
 
   setSize(video->getScreenWidth(), video->getScreenHeight());
index 6acf8e6b838d077d556600712a005c1efbc7e495..bc048d18822dd78cc8a560dc2cd4aa2bf67e8a87 100644 (file)
@@ -38,7 +38,7 @@ class Video;
 class VChannelList;
 class BoxStack;
 class WTextbox;
-class PlayerLiveTV;
+class PlayerLive;
 
 class VVideoLiveTV : public Boxx, public TimerReceiver
 {
@@ -68,7 +68,7 @@ class VVideoLiveTV : public Boxx, public TimerReceiver
     BoxStack* boxstack;
     VDR* vdr;
     Video* video;
-    PlayerLiveTV* player;
+    PlayerLive* player;
     bool playing;
     ChannelList* chanList;
     VChannelList* vchannelList;