/*
 * main.h
 *
 * OpenH323 call generator
 *
 * Copyright (c) 2001 Benny L. Prijono <seventhson@theseventhson.freeserve.co.uk>
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is CallGen323.
 *
 * The Initial Developer of the Original Code is Benny L. Prijono
 *
 * Contributor(s): Equivalence Pty. Ltd.
 *
 * $Log: main.h,v $
 * Revision 1.13  2005/05/04 05:49:32  csoutheren
 * Seperated open transmit and open receive media times
 *
 * Revision 1.12  2004/08/14 07:57:35  rjongbloed
 * Major revision to utilise the PSafeCollection classes for the connections and calls.
 *
 * Revision 1.11  2004/04/26 05:41:10  rjongbloed
 * MOre opalisation to be able to make SIP calls
 *
 * Revision 1.10  2004/04/18 13:57:03  rjongbloed
 * Opalisation of call generator
 *
 * Revision 1.9  2003/05/02 01:21:12  robertj
 * Added ability to call a sequence of destinations rather than only in parallel.
 *
 * Revision 1.8  2002/11/16 00:31:28  robertj
 * Added wait for establishment timeout.
 *
 * Revision 1.7  2002/08/27 03:49:47  robertj
 * Added no media transmission if no WAV file supplied, still opens the
 *   logical channels though. Uses silence suppression.
 * Added detection of completion of run and exit of program.
 *
 * Revision 1.6  2002/07/26 02:14:12  robertj
 * Added ability to prefer and delete codecs.
 * Added fake G.723.1 codec.
 *
 * Revision 1.5  2002/07/23 06:30:39  robertj
 * Another set of enhancements, highlights are continually sending ogm WAV
 *   file and putting received audio into WAV files. As well as more
 *   statistics including a CDR file drop for every call.
 *
 *
 * 25 Jan 2002 Substantial improvement [Equivalence Pty. Ltd.]
 * 25 Jan 2000 Update to incorporate openh323 v.01 alpha2 and fix gatekeeper
 *              related codes [bennylp]
 */


#include <ptclib/delaychan.h>
#include <ptclib/pwavfile.h>


///////////////////////////////////////////////////////////////////////////////

#ifndef USE_OPAL

class PlayMessage : public PDelayChannel
{
    PCLASSINFO(PlayMessage, PDelayChannel);
  public:
    PlayMessage(const PString & filename, unsigned frameDelay, unsigned frameSize);
    virtual BOOL Read(void *, PINDEX);
    virtual BOOL Close();
  protected:
    PWAVFile wavFile;
    BOOL     reallyClose;
};


///////////////////////////////////////////////////////////////////////////////

class RecordMessage : public PDelayChannel
{
    PCLASSINFO(RecordMessage, PDelayChannel);
  public:
    RecordMessage(const PString & filename, unsigned frameDelay, unsigned frameSize);
    virtual BOOL Write(const void *, PINDEX);
    virtual BOOL Close();
  protected:
    BOOL reallyClose;
};

#endif

///////////////////////////////////////////////////////////////////////////////

struct CallDetail
{
  CallDetail()
    : openedTransmitMedia(0),
      openedReceiveMedia(0),
      receivedMedia(0)
    { }

  PTime                openedTransmitMedia;
  PTime                openedReceiveMedia;
  PTime                receivedMedia;
  H323TransportAddress mediaGateway;

  void Drop(
#ifdef USE_OPAL
    OpalConnection & connection
#else
    H323Connection & connection
#endif
  );

  void OnRTPStatistics(const RTP_Session & session, const PString & token);
};


///////////////////////////////////////////////////////////////////////////////

class MyH323EndPoint;

class MyH323Connection : public H323Connection
{
    PCLASSINFO(MyH323Connection, H323Connection);
  public:
    MyH323Connection(
#ifdef USE_OPAL
      OpalCall & call,            /// Call object connection belongs to
      MyH323EndPoint & endpoint,    /// H323 End Point object
      const PString & token,      /// Token for new connection
      const PString & alias,     /// Alias for outgoing call
      const H323TransportAddress & address,   /// Address for outgoing call
      unsigned options = 0        /// Connection option bits
#else
      MyH323EndPoint & ep,
      unsigned callRef
#endif
    );

#ifndef USE_OPAL
    virtual BOOL OpenAudioChannel(
      BOOL isEncoding,              /// Direction of data flow
      unsigned bufferSize,          /// Size of each sound buffer
      H323AudioCodec & codec        /// codec that is doing the opening
    );
#endif

    virtual void OnRTPStatistics(
      const RTP_Session & session   /// Session with statistics
    ) const;

    CallDetail details;

  protected:
    MyH323EndPoint & endpoint;
};


///////////////////////////////////////////////////////////////////////////////

class MyH323EndPoint : public H323EndPoint 
{
    PCLASSINFO(MyH323EndPoint, H323EndPoint);
  public:
    MyH323EndPoint(
#ifdef USE_OPAL
      OpalManager & mgr
#endif
    );

    // override from H323EndPoint
    virtual H323Connection * CreateConnection(
#ifdef USE_OPAL
      OpalCall & call,           /// Call object to attach the connection to
      const PString & token,     /// Call token for new connection
      void * userData,           /// Arbitrary user data from MakeConnection
      OpalTransport & transport, /// Transport for connection
      const PString & alias,     /// Alias for outgoing call
      const H323TransportAddress & address,   /// Address for outgoing call
      H323SignalPDU * setupPDU   /// Setup PDU for incoming call
#else
      unsigned callReference
#endif
    );
    virtual void OnConnectionEstablished(
      H323Connection & connection,    /// Connection that was established
      const PString & token           /// Token for identifying connection
    );
    virtual void OnConnectionCleared(
      H323Connection & connection,    /// Connection that was established
      const PString & token           /// Token for identifying connection
    );
    BOOL OnStartLogicalChannel(
      H323Connection & connection,
      H323Channel & PTRACE_channel
    );
};


///////////////////////////////////////////////////////////////////////////////

#ifdef USE_OPAL

class MySIPEndPoint;

class MySIPConnection : public SIPConnection
{
    PCLASSINFO(MySIPConnection, SIPConnection);
  public:
    MySIPConnection(
      OpalCall & call,            /// Owner calll for connection
      MySIPEndPoint & endpoint,     /// Owner endpoint for connection
      const PString & token,      /// token to identify the connection
      const SIPURL & address,     /// Destination address for outgoing call
      OpalTransport * transport   /// Transport INVITE came in on
    );

    virtual void OnRTPStatistics(
      const RTP_Session & session   /// Session with statistics
    ) const;

    CallDetail details;

  protected:
    MySIPEndPoint & endpoint;
};


///////////////////////////////////////////////////////////////////////////////

class MySIPEndPoint : public SIPEndPoint 
{
    PCLASSINFO(MySIPEndPoint, SIPEndPoint);
  public:
    MySIPEndPoint(
      OpalManager & mgr
    );

    // override from H323EndPoint
    virtual SIPConnection * CreateConnection(
      OpalCall & call,            /// Owner of connection
      const PString & token,      /// token used to identify connection
      void * userData,            /// User data for connection
      const SIPURL & destination, /// Destination for outgoing call
      OpalTransport * transport,  /// Transport INVITE has been received on
      SIP_PDU * invite            /// Original INVITE pdu
    );

    virtual void OnEstablished(
      OpalConnection & connection   /// Connection that was established
    );
    virtual void OnReleased(
      OpalConnection & connection   /// Connection that was established
    );
    BOOL OnOpenMediaStream(
      OpalConnection & connection,
      OpalMediaStream & stream
    );
};


#endif

///////////////////////////////////////////////////////////////////////////////

class CallGen;

struct CallParams
{
  CallParams(CallGen & app)
    : callgen(app) { }

  CallGen & callgen;

  unsigned repeat;
  PTimeInterval tmax_est;
  PTimeInterval tmin_call;
  PTimeInterval tmax_call;
  PTimeInterval tmin_wait;
  PTimeInterval tmax_wait;
};


///////////////////////////////////////////////////////////////////////////////

class CallThread : public PThread
{
  PCLASSINFO(CallThread, PThread);
  public:
    CallThread(
      unsigned index,
      const PStringArray & destinations,
      const CallParams & params
    );
    void Main();
    void Stop();

  protected:
    PStringArray destinations;
    unsigned     index;
    CallParams   params;
    PSyncPoint   exit;
};

PLIST(CallThreadList, CallThread);


///////////////////////////////////////////////////////////////////////////////

class CallGen : public PProcess 
{
  PCLASSINFO(CallGen, PProcess)

  public:
    CallGen();
    void Main();
    static CallGen & Current() { return (CallGen&)PProcess::Current(); }

    PString    outgoingMessageFile;
    PString    incomingAudioDirectory;
    PTextFile  cdrFile;

    PSyncPoint threadEnded;
    unsigned   totalAttempts;
    unsigned   totalEstablished;
    PMutex     coutMutex;

#ifdef USE_OPAL
  OpalManager manager;

  BOOL Start(const PString & destination, PString & token) {
    return manager.SetUpCall("ivr:*", destination, token);
  }
  BOOL Exists(const PString & token) {
    return manager.HasCall(token);
  }
  BOOL IsEstablished(const PString & token) {
    return manager.IsCallEstablished(token);
  }
  BOOL Clear(PString & token) {
    return manager.ClearCallSynchronous(token);
  }
  void ClearAll() {
    manager.ClearAllCalls();
  }
#else
  MyH323EndPoint * h323;

  BOOL Start(const PString & destination, PString & token) {
    return h323->MakeCall(destination, token) != NULL;
  }
  BOOL Exists(const PString & token) {
    return h323->HasConnection(token);
  }
  BOOL IsEstablished(const PString & token) {
    return h323->IsConnectionEstablished(token);
  }
  BOOL Clear(PString & token) {
    return h323->ClearCallSynchronous(token);
  }
  void ClearAll() {
    h323->ClearAllCalls();
  }
#endif
  protected:
    PDECLARE_NOTIFIER(PThread, CallGen, Cancel);
    PConsoleChannel console;
    CallThreadList threadList;
};


///////////////////////////////////////////////////////////////////////////////


syntax highlighted by Code2HTML, v. 0.9.1