/*
 * audio_decoder.h: The audio decoder wrapper (to the libmad library)
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: audio_decoder.h,v 1.18 2005/10/31 14:29:13 cm Exp $
 */

#ifndef __AUDIODECORER_H
#define __AUDIODECODER_H

#include <stdint.h>
#include <vdr/thread.h>
#include <mad.h>
#include "audio_buffer.h"
#include "daap_client.h"
#include "daap_database.h"

#ifdef DECODER_FAAD
#  include <mp4ff.h>
#  include <neaacdec.h>
#endif

#define PCM_BUFFER_SIZE        (512 * 1024)

// is this correct ? (channels * 1152 * sample size)
#define OUTPUT_BUFFER_SIZE     (2 * 1152 * 2)
#define INPUT_BUFFER_SIZE      (5 * 8192)

typedef enum eDecoderSeek {
  dsCurrent,
  dsSet
};

class cAudioDecoder : public cThread {
  protected:
    const cMediaDatabaseBlob *mpo_blob;
    cSimpleRingBuffer mo_PCMBuffer;
  public:
    cAudioDecoder(const cMediaDatabaseBlob *blob);
    virtual ~cAudioDecoder();
    virtual unsigned long Read(uint8_t *data, unsigned long count) = 0;
    virtual unsigned long Available(void) const = 0;
    virtual void Seek(long offset, eDecoderSeek whence) = 0;
    // returns time in milliseconds
    virtual signed long GetCurrentTime(void) = 0;
    // returns bits per second
    virtual unsigned long GetAvgBitRate(void) = 0;
};

class cMp3Decoder : public cAudioDecoder {
  private:
    enum eDecoderState { dsNormal, dsReSync };

    eDecoderState m_state;
    unsigned long m_dataReadPos;
    unsigned long m_numFrames;
    unsigned long m_sumBitRate;
    mad_timer_t m_timer;
    signed short MADFixedToSshort(mad_fixed_t sample) const;
    void Action();
  public:
    cMp3Decoder(const cMediaDatabaseBlob *blob);
    ~cMp3Decoder();
    unsigned long Read(uint8_t *data, unsigned long count) { return mo_PCMBuffer.Get(data, count); } ;
    unsigned long Available(void) const { return mo_PCMBuffer.Available(); };
    void Seek(long offset, eDecoderSeek whence);
    signed long GetCurrentTime(void) { return mad_timer_count(m_timer, MAD_UNITS_MILLISECONDS); };
    unsigned long GetAvgBitRate(void) { return m_sumBitRate / m_numFrames; };
};

#ifdef DECODER_FAAD

class cMp4AACDecoder : public cAudioDecoder {
  friend uint32_t fMp4ffRead(void *user_data, void *buffer, uint32_t length);
  friend uint32_t fMp4ffSeek(void *user_data, uint64_t position);
  private:
    float m_curTime;
    int m_curSample;
    int m_maxSamples;
    int32_t m_selTrack;
    unsigned long m_dataReadPos;
    unsigned long m_avgBitRate;
    mp4ff_t *mp_mp4;
    mp4ff_callback_t *mp_mp4cb;
    void Action();
  public:
    cMp4AACDecoder(const cMediaDatabaseBlob *blob);
    ~cMp4AACDecoder();
    unsigned long Read(uint8_t *data, unsigned long count) { return mo_PCMBuffer.Get(data, count); };
    unsigned long Available(void) const { return mo_PCMBuffer.Available(); };
    void Seek(long offset, eDecoderSeek whence);
    signed long GetCurrentTime(void) { return long(m_curTime); };
    unsigned long GetAvgBitRate(void) { return m_avgBitRate; };
};

#endif

class cAudioDecoders {
  public:
    cAudioDecoders();
    ~cAudioDecoders();
    cAudioDecoder *Get(const char *format, const cMediaDatabaseBlob *) const;
};

#endif
