/*
 * Copyright (C) 2002-2003 Fhg Fokus
 *
 * This file is part of SEMS, a free SIP media server.
 *
 * SEMS 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. This program is released under
 * the GPL with the additional exemption that compiling, linking,
 * and/or using OpenSSL is allowed.
 *
 * For a license to use the SEMS software under conditions
 * other than those described here, or to purchase support for this
 * software, please contact iptel.org by e-mail at the following addresses:
 *    info@iptel.org
 *
 * SEMS 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 this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/** @file AmAdvancedAudio.h */

#ifndef _AmAdvancedAudio_h_
#define _AmAdvancedAudio_h_

#include "AmAudio.h"
#include "AmPlaylist.h"

#include "AmThread.h"
#include "amci/codecs.h"

#include <list>
#include "SampleArray.h"

/**
 * \brief Entry in an AudioQueue
 */
struct AudioQueueEntry {
  AmAudio* audio;
  bool put;
  bool get;
  AudioQueueEntry(AmAudio* _audio, bool _put, bool _get) 
    : audio(_audio), put(_put), get(_get) { }
};

/**
 * \brief Holds AmAudios and reads/writes through all
 * 
 * AmAudioQueue can hold AmAudios in input and output queue.
 * Audio will be read through the whole output queue,
 * and written through the whole input queue.
 */

class AmAudioQueue : public AmAudio {

  AmMutex inputQueue_mut;
  std::list<AudioQueueEntry> inputQueue;
  AmMutex outputQueue_mut;
  std::list<AudioQueueEntry> outputQueue;

  bool owning;
 public:
  AmAudioQueue();
  ~AmAudioQueue();

  enum QueueType { OutputQueue, InputQueue };
  enum Pos { Front, Back };

  /** add an audio to a queue */
  void pushAudio(AmAudio* audio, QueueType type, Pos pos, bool write, bool read); 
  /** pop an audio from queue and delete it @return 0 on success, -1 on failure */
  int popAudio(QueueType type, Pos pos); 
  /** pop an audio from queue @return pointer to the audio */
  AmAudio* popAndGetAudio(QueueType type, Pos pos); 
  /** this removes the audio if it is in on of the queues and does not
      delete them */
  int removeAudio(AmAudio* audio);
  void setOwning(bool _owning);

 protected:
  int write(unsigned int user_ts, unsigned int size);
  int read(unsigned int user_ts, unsigned int size);
};

/**
 * \brief AmAudio device with a playlist and a background AmAudio
 *
 * AmAudioFrontlist is an AmAudio device, that has a playlist
 * in front of a AmAudio entry, the 'back' device. The back device
 * is only used if the playlist is empty. - This can be useful when 
 * for example announcements should be played to the participant 
 * while in a conference.
 *
 */
class AmAudioFrontlist : public AmPlaylist {
  AmMutex ba_mut;
  AmAudio* back_audio;
 public:

  AmAudioFrontlist(AmEventQueue* q);
  AmAudioFrontlist(AmEventQueue* q, AmAudio* back_audio);
  ~AmAudioFrontlist();

  void setBackAudio(AmAudio* new_ba);

 protected:
  int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
  int get(unsigned int user_ts, unsigned char* buffer, unsigned int size);
};


/**
 * \brief \ref AmAudio that directly connects input and output
 *
 *  AmAudioBridge simply connects input and output
 *  This is useful e.g. at the end of a AudioQueue
 */
class AmAudioBridge : public AmAudio {
  SampleArrayShort sarr;
 public:
  AmAudioBridge();
  ~AmAudioBridge();
 protected:
  int write(unsigned int user_ts, unsigned int size);
  int read(unsigned int user_ts, unsigned int size);
};

/**
 * \brief \ref AmAudio that delays output from input
 * delays delay_sec seconds (up to ~2)
 */
class AmAudioDelay : public AmAudio {
  SampleArrayShort sarr;
  float delay;
 public:
  AmAudioDelay(float delay_sec);
  ~AmAudioDelay();
 protected:
  int write(unsigned int user_ts, unsigned int size);
  int read(unsigned int user_ts, unsigned int size);
};

/** 
 * AmNullAudio plays silence, and recording goes to void. 
 * it can be parametrized with a maximum length (in milliseconds), 
 * after which it is ended.
 * Read and write length can also be set after creation (and possibly even
 * when in use).
 */
class AmNullAudio 
: public AmAudio {
  int read_msec;
  int write_msec;

  bool read_end_ts_i;
  unsigned int read_end_ts;

  bool write_end_ts_i;
  unsigned int write_end_ts;

 public:
  AmNullAudio(int read_msec = -1, int write_msec = -1)
    : read_msec(read_msec), write_msec(write_msec),
    read_end_ts_i(false), write_end_ts_i(false) { }
  ~AmNullAudio() { }

  /** (re) set maximum read length*/
  void setReadLength(int n_msec);
  /** (re) set maximum write length*/
  void setWriteLength(int n_msec);

 protected:
  int write(unsigned int user_ts, unsigned int size);
  int read(unsigned int user_ts, unsigned int size);
};

#endif // _AmAdvancedAudio_h_