/*
#  $Id$
# -----------------------------------------------------------------------------
#  The part of 'VideoNEXT MediaClient SDK'
# -----------------------------------------------------------------------------
#  Author: Petrov Maxim, 03/01/2010
#  Edited by:
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
*/

#ifndef AUDIOVIDEOPLAYOUTCONTROLLER_H
#define AUDIOVIDEOPLAYOUTCONTROLLER_H

#include "PlayoutBuffer.h"
#include "FrameConsumer.h"
#include "Cache.h"

namespace videonext { namespace media {

class MediaStreamProducerImpl;
struct MediaStreamHandler;
class FileRecorder;

class AudioVideoPlaybackController: public Medium 
{
public:
   enum SINK_TYPE {AUDIO, VIDEO};

   AudioVideoPlaybackController(AdaptiveUsageEnvironment& env,  
                                MediaStreamProducerImpl *p,
                                MediaStreamHandler *mediaStreamHandler,
                                unsigned cacheSize,
                                unsigned bufferLen);
    
   virtual ~AudioVideoPlaybackController();

    /**
     * Add sink to controller. 
     * @note only 2 sinks allowed
     */
   void addSink(FrameConsumer *, SINK_TYPE);

   void removeSink(FrameConsumer *);

   bool hasSinks() {return fSinks[AUDIO] || fSinks[VIDEO];}

   bool hasAudioSink() {return fSinks[AUDIO] != 0;}

   bool hasVideoSink() {return fSinks[VIDEO] != 0;}

   FrameConsumer *audioSink() { return fSinks[AUDIO]; }

   FrameConsumer *videoSink() { return fSinks[VIDEO]; }
        
   /**
    * Playing from cache
    * @param direction Play direction (-1: backward, 1: forward) 
    * @return false if pause was occured. Else returns true.
    * @note this method always invokes from different thread 
    */
   bool playFromCache(int direction = 1);

   void setDirection(int direction) {fDirection = direction;}
   int getDirection() {return fDirection;}
    
   void markJump();
    
   bool jumpToTimestamp(time_t ts, bool playingArchive);
   
   /**
    * Clear current state. 
    */
   void clear();

   bool isStepMode();

   void setPaused(bool val);
   bool isPaused() {return fPaused;}

   void setPlayFramesFromServer(bool val) {fPlayFramesFromServer = val;}
   bool isPlayFramesFromServer() {return fPlayFramesFromServer;}  
    
   void  setSpeed(float val) {fStreamSpeed = val;}
   float getSpeed()          {return fStreamSpeed;}

   void setJitterBufferLen(unsigned value);
   void flushJitterBuffer();
   void enableJitterBuffer(bool value);

   bool startRecording(const char* file_name, const std::map<std::string, std::string>& metadata);
   bool endRecording(bool stop = false);
    
   virtual void setState(STREAM_STATE val, int errorCode = 0);
   virtual void setState2(STREAM_STATE state, int errorCode = 0);

   STREAM_STATE getState() {return fState;}
   int getErrorCode() { return fErrorCode; }

   void setServerPaused(bool val) {fServerPaused = val;}
   bool isServerPaused()          {return fServerPaused;}
   
   MemCounter *memCounter() { return fMemCounter; }
   Cache *cache() { return fCache; }
   Mutex &playMutex() {return fPlayMutex;}
   Mutex &recordingMutex() {return fRecordingMutex;}
   MediaStreamHandler *mediaStreamHandler() {return fMediaStreamHandler;}
   MediaStreamProducerImpl *mediaProducer() {return fMediaProducer;}
   FileRecorder *fileRecorder();

public:

   void addFrame(CPMediaFrame &cpMediaFrame);

   void playFrame(CPMediaFrame &cpMediaFrame, bool show = true);

    
private:
 
    /**
    * Storing frame in video cache
    * @param cpVideoFrame 
    */
    void storeFrame(CPMediaFrame &cpMediaFrame);
 
     /**
     * Playing forward in cache
     * @return false if pause was occured 
     */
    virtual bool playForward();
    
    /**
     * Playing back in cache
     * @return false if pause was occured 
     */
    virtual bool playBackward();       
    
    void delay(const videonext::media::DelayInterval &delayInterval);

protected:
   AdaptiveUsageEnvironment &fEnv;
   MediaStreamProducerImpl *fMediaProducer;
   MediaStreamHandler *fMediaStreamHandler;
   FileRecorder* fFileRecorder;
   bool fPaused;
   bool fServerPaused;
   bool fPlayFramesFromServer;
    
   MemCounter *fMemCounter;
   Cache *fCache;    
   
   float fStreamSpeed; /*!< Stream speed */
    
   int fDirection;        
    
   unsigned char* fBuffer;
   unsigned fBufferSize;

protected:
   STREAM_STATE fState;
   int fErrorCode;

   bool fWaitForKeyFrame;
   FrameConsumer* fSinks[2];
   Mutex fPlayMutex;
   Mutex fSinkMutex;
   Mutex fPlayoutBufferMutex;
   Mutex fRecordingMutex;
   unsigned fBufferLen;
   PlayoutBuffer *fPlayoutBuffer; 

   fd_set fDummySet;
   int fdummySocketNum;
};

}}
#endif

