/*
   File: bitstr.hh

   By: Alex Theo de Jong
   Created: February 1996
*/

#ifndef __astream_hh
#define __astream_hh

#ifdef __GNUG__
#pragma interface
#endif

class AudioStream {
  Mpeg2Buffer* inputstream;
  Synchronization* sync;
  unsigned int    word;           // current bits
  unsigned int    value;          // return value for get_bits
  int       frames;        // counters: bytes left, sum of bits, number of frames read
  int    	bitindex;		      // number (0-31, from MSB to LSB) of next bit for get_bits()
  bool      file;                 // read from file or buffer
 public:
  int  bytes;
  AudioStream(const char *filename);
  AudioStream(Mpeg2Buffer* input, Synchronization* s);
  ~AudioStream(void);
#ifndef DEBUG
  inline
#endif
  bool get_header(unsigned int&);
  void get_header_ac3(void);
  // get next 32 bits from bitstream in an unsigned int,
  // returned value False => end of stream
#ifndef DEBUG
  inline
#endif
  bool read_frame(int bytesize);
  // fill buffer with data from bitstream, returned value False => end of stream
#ifndef DEBUG
  inline
#endif
  unsigned int get_bits(int number_of_bits);
  // read bits (1 <= number_of_bits <= 16) from buffer into the lower bits
  // of an unsigned int. The LSB contains the latest read bit of the stream.
};

#ifndef DEBUG
// #ifdef NOT

inline unsigned int AudioStream::get_bits(int n){ 

  for (; bytes && bitindex <= 24; bitindex += 8, bytes--)
    word|=(inputstream->getbyte() << (24 - bitindex));
  value=0;
  value=(word >> (32-n));
  bitindex-=n;
  word<<=n;
  return value;
}

inline bool AudioStream::get_header(unsigned int& headerstring){
  if (bytes) inputstream->skipbytes(bytes);
  if (sync) sync->usedbytes(2, 4);  // 2 is audio ID, 4 is number of bytes
  if (inputstream->waitforbytes(4)!=4){
    TRACER("audio stream failed - exit");
    athr_exit(0);
    return False;
  }
  headerstring=inputstream->getbits32();
  inputstream->signal_buffer();
  while (((headerstring & 0xfff00000)!=0xfff00000) ){
    if (inputstream->waitforbytes(1)!=1){
      TRACER("audio stream failed - exit");
      athr_exit(0);
      return False;
    }
    headerstring<<=8;
    headerstring|=(inputstream->getbyte() & 0x000000ff);
    inputstream->signal_buffer();  
  }
  return (headerstring) ? True : False;
}

inline void AudioStream::get_header_ac3(){
  unsigned int headerstring;
//  if (bytes) inputstream->skipbytes(bytes);
  if (sync) sync->usedbytes(2, 2);  // 2 is audio ID, 4 is number of bytes
  if (inputstream->waitforbytes(2)!=2){
    TRACER("audio stream failed - exit");
    athr_exit(0);
    return ;
  }
  headerstring=inputstream->getbyte();
  headerstring<<=8;
  headerstring|=(inputstream->getbyte() & 0x000000ff);
  inputstream->signal_buffer();
  while (headerstring != 0x0b77 ){
    if (inputstream->waitforbytes(1)!=1){
      TRACER("audio stream failed - exit");
      athr_exit(0);
      return ;
    }
    headerstring<<=8;
    headerstring|=(inputstream->getbyte() & 0x000000ff);
    inputstream->signal_buffer();
  }
  return ;
}


bool AudioStream::read_frame(int bytesize){
int i;
  if ((bytes=inputstream->waitforbytes(bytesize))!=bytesize){
    TRACER("audio stream failed - exit");
    message("audio stream failed - exit");
    athr_exit(0);
    return False;
  }
  if (sync) {
     i = sync->usedbytes(2, bytesize);  // 2 is audio ID, bytesize is number of bytes
  }
  frames++;
  bitindex=0;
  return True;
}

// #endif NOT
#endif DEBUG

#endif  // __astream_hh
