/*
 * ISDN sniffer plugin for VDR
 *
 * Copyright (C) 2003 Andreas Kool <akool@gmx.de>
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id$
 */

/*
 * This file is a shameless copy from the mp3-plugin
 * I have no idea what this code actually does ;)
 */

#include <mad.h>
#include <sndfile.h>

#include <vdr/thread.h>
#include <vdr/player.h>
#include <vdr/ringbuffer.h>
#include "debug.h"

#define MP3BUFSIZE KILOBYTE(100)
#define HDR_SIZE        9
#define LPCM_SIZE       7
#define MAX_FRAMESIZE   2048 // max. frame size allowed for DVB driver
#define SF_SAMPLES (sizeof(pcm->samples[0]) / sizeof(mad_fixed_t))



struct LPCMFrame {
  unsigned char PES[HDR_SIZE];
  unsigned char LPCM[LPCM_SIZE];
  unsigned char Data[MAX_FRAMESIZE-HDR_SIZE-LPCM_SIZE];
};
// cResample
#define MAX_NSAMPLES (1152*7)                                // max. buffer for resampled frame

// ----------------------------------------------------------------

class cSndFile {
private:
  SNDFILE *sf;
public:
  SF_INFO sfi;
  cSndFile(const char *Filename);
  ~cSndFile();
  bool Open(char *Filename);
  void Close(void);
  sf_count_t Stream(int *buffer, sf_count_t frames);
};


// ----------------------------------------------------------------

enum eDecodeStatus { dsOK = 0, dsPlay, dsEof, dsError, dsSoftError };

struct Decode {
  eDecodeStatus status;
  int index;
  struct mad_pcm *pcm;
};


// --- cDecoder -------------------------------------------------------------

class cDecoder {
protected:
  char *filename;
  cMutex lock;
  int locked;
  bool playing;
public:
  cDecoder(const char *Filename);
  virtual ~cDecoder();
  virtual bool Valid(void) = 0;
  virtual bool Start(void) = 0;
  virtual bool Stop(void) = 0;
  virtual struct Decode *Decode(void) = 0;
};
  

// ----------------------------------------------------------------

class cSndDecoder : public cDecoder {
private:
  cSndFile file;
  struct Decode ds;
  struct mad_pcm *pcm;
  unsigned long long index;
  void Init(void);
  bool Clean(void);
  bool GetInfo(bool keepOpen);
  struct Decode *Done(eDecodeStatus status);
public:
  cSndDecoder(const char *Filename);
  ~cSndDecoder();
  virtual bool Valid(void);
  virtual bool Start(void);
  virtual bool Stop(void);
  virtual struct Decode *Decode(void);
};


// --- cSndPlayer ----------------------------------------------------------

class cSndPlayer : public cPlayer, cThread {
private:
  bool active, started;
  cRingBufferFrame *ringBuffer;
  cMutex playModeMutex;
  cCondVar playModeCond;
  cDecoder *decoder;
  cFrame *rframe;
  cFrame *pframe;
  char *filename;
  enum ePlayMode { pmPlay, pmStopped, pmPaused, pmStartup };
  ePlayMode playMode;
  enum eState { msStart, msStop, msDecode, msNormalize, msResample, msOutput, msError, msEof, msWait };
  eState state;
  bool levelgood;
  unsigned int dvbSampleRate;
  int index, num, maxnum;
  void Empty(void);
  void StopPlay(void);
  void SetPlayMode(ePlayMode mode);
  void WaitPlayMode(ePlayMode mode, bool inv);
protected:
  virtual void Activate(bool On);
  virtual void Action(void);
public:
  cSndPlayer(const char *fn);
  virtual ~cSndPlayer();
  bool Active(void) { return active; }
  void Play(void);
};

class cSndPlayerControl : public cControl {
private:
  cSndPlayer *sndplayer;
public:
  cSndPlayerControl(const char *fn);
  virtual ~cSndPlayerControl();
  bool Active(void);
  void Stop(void);
  void Play(void);
  virtual void Hide(void){}
  virtual eOSState ProcessKey(eKeys Key);
  };
