/*
 * conference.h
 *
 * Conferencing functions for a simple MCU
 *
 * Copyright (c) 2000 Equivalence Pty. Ltd.
 * Copyright (c) 2004 Post Increment
 *
 * 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 Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
 *
 * Portions of this code were written by Post Increment (http://www.postincrement.com) 
 * with the assistance of funding from Citron Networks (http://www.citron.com.tw)
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): Derek J Smithies (derek@indranet.co.nz)
 *                 ------------------------------
 *
 * $Log: conference.h,v $
 * Revision 2.5  2005/06/21 12:45:21  rjongbloed
 * Disabled video so will compile - for now.
 *
 * Revision 2.4  2005/03/11 00:25:24  csoutheren
 * Fixed problems with flags
 *
 * Revision 2.3  2004/05/26 06:54:31  csoutheren
 * Changed to be a PHTTPServiceProcess
 * Added ability to play WAV files on member entry and exit
 * Added additional documentation on all classes
 * Preparation for re-introducing video
 *
 * Revision 2.2  2004/03/31 03:36:38  csoutheren
 * Fixed problem with user indication messages
 * Fixed problems with room listener and unlisten
 *
 * Revision 2.1  2004/03/11 20:49:44  csoutheren
 * Removed warnings
 *
 * Revision 2.0  2004/03/08 02:06:24  csoutheren
 * Totally rewritten to use new connection locking mecahnism
 * Added ability to monitor conferences
 * Added initial support for H.323 MCU messages
 * Thanks to Citron Networks for supporting this work
 *
 */

#ifndef _OpenMCU_CONFERENCE_H
#define _OpenMCU_CONFERENCE_H

#ifdef _WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4100)
#endif

#include <set>
#include <map>

#include <h323.h>
#include <h323pdu.h>

class OpenMCUH323Connection;

#define NO_MCU_VIDEO


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

#ifndef NO_MCU_VIDEO

class VideoBuffer : public PObject
{
  PCLASSINFO(VideoBuffer, PObject);

  public:
    VideoBuffer();
    ~VideoBuffer();
 
    void WriteAll( BYTE * ptr, PINDEX amount);  //For single stream option
    void Write( BYTE * ptr, PINDEX amount, PINDEX posn);
    void Read(BYTE * ptr, PINDEX amount);
    void Clear(PINDEX posn); //Reset the buffer at the specified position 
    void SetSize(int x, int y); // Set the vidbuffer size

  protected:
    BYTE * buffer;
    PINDEX videoBufferSize;    ///Total number of bytes in buffer. Never gets changed.
    PMutex videoBufferMutex;
    int    bufferFrameSize;
    int    xSize, ySize;
};

typedef map<PString, VideoBuffer *> VideoBufferDict;

#endif

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

class AudioDelay : public PObject
{
  PCLASSINFO(AudioDelay, PObject);

  public:
    AudioDelay();
    virtual BOOL Delay(int time);
    virtual void Restart();

  protected:
    PTime  previousTime;
    BOOL   firstTime;
    int    error;
};

class VideoDelay : public AudioDelay
{
  PCLASSINFO(VideoDelay, AudioDelay);

  public:
    BOOL Delay(int time);
};

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

class MCULock : public PObject
{
  PCLASSINFO(MCULock, PObject);
  public:
    MCULock();
    BOOL Wait(BOOL hard = FALSE);
    void Signal(BOOL hard = FALSE);
    void WaitForClose();
  protected:
    PMutex mutex;
    BOOL closing;
    int count;
    PSyncPoint closeSync;
};

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

class Conference;

/**
  * this class describes a connection between a conference member and a conference
  * each conference member has one instance of class for every other member of the conference
  */

class ConferenceConnection : public PObject {
  PCLASSINFO(ConferenceConnection, PObject);
  public:
    ConferenceConnection(void * _id);
    ~ConferenceConnection();

    void * GetID() const
    { return id; }

#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable:4311)
#endif
    virtual PString GetName() const
    { return PString(PString::Unsigned, (unsigned)id); }
#ifdef _WIN32
#pragma warning(pop)
#endif

    virtual void OnUserInputIndication(const PString &)
    { }

    void WriteAudio(void * source, const void * buffer, PINDEX amount);
    void Write(const BYTE * ptr, PINDEX amount);
    void ReadAudio(BYTE * ptr, PINDEX amount);
    void ReadAndMixAudio(BYTE * ptr, PINDEX amount, PINDEX channels);

  protected:
    Conference * conference;
    void * id;

    void Mix(BYTE * dst, const BYTE * src, PINDEX count, PINDEX channels);

    BYTE * buffer;
    PINDEX bufferLen;     ///Number of bytes unread in the buffer.
    PINDEX bufferStart;   ///Current position in the buffer.
    PINDEX bufferSize;    ///Total number of bytes in buffer. Never gets changed.
    PMutex audioBufferMutex;

#ifndef NO_MCU_VIDEO
    BOOL hasVideo;
    IncomingVideo * incomingVideo;
    OutgoingVideo * outgoingVideo;
#endif
};

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

/**
  * this class describes a member of a conference
  */

class ConferenceManager;

class ConferenceMember : public PObject
{
  PCLASSINFO(ConferenceMember, PObject);
  public:

    /**
      * create a new conference member. The single parameter is an "id" (usually a pointer) 
      * that can used to identify this member unambiguously
      */
    ConferenceMember(void * id);

    /**
      * used to add a conference member to a conference. This is not done in the constructor
      * as some conference members have non-trivial startup requirements
      */
    virtual BOOL AddToConference(Conference * conference);

    /**
      * used to remove a conference member from a conference. This is not done in the destructor
      * as some conference members have non-trivial shutdown requirements
      */
    virtual void RemoveFromConference();

    /**
      * If this returns TRUE, the conference member will be visible in all publically displayed
      * conference lists. It will always be visible in the console displays
      */
    virtual BOOL Visible() const
    { return TRUE; }

    /**
      * return the conference member ID
      */
    void * GetID() const
    { return id; }

     
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable:4311)
#endif

    /**
      * return the name of the the conference member
      */
    virtual PString GetName() const
    { return PString(PString::Unsigned, (unsigned)id); }

#ifdef _WIN32
#pragma warning(pop)
#endif

    /**
      * return the conference this member belongs to
      */
    Conference * GetConference()
    { return conference; }

    /**
      * add a new connection for the specified member to this member to the internal list of connections
      */
    virtual void AddConnection(ConferenceMember * newMember);

    /**
      * remove any connections belong to the specified ID from the internal list of connections
      */
    virtual void RemoveConnection(void * id);

    /**
     * This is called when the conference member want to send a user input indication to the the conference.
     * By default, this routines calls OnReceivedUserInputIndication for all of the other conference members
     */
    virtual void SendUserInputIndication(const PString & str);

    /**
     * this virtual function is called when the conference sends a user input indication to the endpoint
     * the conference
     */
    virtual void OnReceivedUserInputIndication(const PString & str)
    { }

    /**
      *  Called when the conference member want to send audio data to the cofnerence
      */
    virtual void WriteAudio(const void * buffer, PINDEX amount);

    /**
      *  Called when the conference member wants to read a block of audio from the conference
      */
    virtual void ReadAudio(void * buffer, PINDEX amount);

    /**
      * Called when another conference member wants to send audio to the endpoint
      * By default, the audio is added to the queue for the specified member
      * so it can be retreived by a later call to OnIncomingAudio
      */
    virtual void OnExternalAudio(void * id, const void * buffer, PINDEX amount);

    /*
     *  Used to create a conference connection for this member
     */
    virtual ConferenceConnection * CreateConnection() = 0;

    void WaitForClose()
    { lock.WaitForClose(); }

  protected:
    typedef std::map<void *, ConferenceConnection *> ConnectionList;
    typedef std::map<void *, ConferenceMember *> MemberList;

    Conference * conference;
    void * id;
    MCULock lock;
    ConnectionList connectionList;
    MemberList memberList;
};

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

/**
  * this class describes a conference or "room"
  */

class Conference : public PObject
{
  PCLASSINFO(Conference, PObject);
  public:
    typedef std::map<void *, ConferenceMember *> MemberList;

    Conference(ConferenceManager & manager,     
      const OpalGloballyUniqueID & _guid,
                   const PString & _number,
                   const PString & _name);

    ~Conference();

    PMutex & GetMutex()
    { return memberListMutex; }

    ConferenceManager & GetManager()
    { return manager; }

    /**
      * add the specified member to the conference
      */
    void AddMember(ConferenceMember * member);

    /**
     * remove the specifed member from the conference.
     * Note that this function does not actually delete the conference member
     * as sometimes a conference member needs to remove itself from a conference
     * 
     * @return if TRUE, the conference is now empty
     */
    BOOL RemoveMember(ConferenceMember * member);

    MemberList & GetMemberList() 
    { return memberList; }

    virtual PString GetName() const
    { return name; }

    virtual PString GetNumber() const
    { return number; }

    OpalGloballyUniqueID GetID() const
    { return guid; }

    virtual BOOL IsVisible() const
    { return TRUE; }

    virtual void OnMemberJoining(ConferenceMember *);

    virtual void OnMemberLeaving(ConferenceMember *);

  protected:
    ConferenceManager & manager;
    PMutex memberListMutex;
    MemberList memberList;

    OpalGloballyUniqueID guid;
    PString number;
    PString name;
};

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

typedef std::map<OpalGloballyUniqueID, Conference *> ConferenceList;

class ConferenceManager : public PObject
{
  PCLASSINFO(ConferenceManager, PObject);
  public:
    ConferenceManager();

    /**
     * Make a new conference with the specified conference ID, number and name
     */
    Conference * MakeConference(
      const OpalGloballyUniqueID & conferenceID, 
      const PString & number, 
      const PString & name
    );

    /**
     * Make a new conference with the specified number and name, and use a new conference ID
     */
    Conference * MakeConference(
      const PString & number, 
      const PString & name
    );

    /**
      * return true if a conference with the specified ID exists
      */
    BOOL HasConference(
      const OpalGloballyUniqueID & conferenceID
    );

    /**
      * return true if a conference with the specified number exists
      */
    BOOL HasConference(
      const PString & number
    );

    /**
      * Remove and delete the specified conference
      */
    void RemoveConference(const OpalGloballyUniqueID & confId);

    /**
      * Remove the specified member from the specified conference.
      * The member will will deleted, and if the conference is empty after the removal, 
      * it is deleted too
      */
    void RemoveMember(const OpalGloballyUniqueID & confId, ConferenceMember * toRemove);


    PMutex & GetConferenceListMutex()
    { return conferenceListMutex; }

    ConferenceList & GetConferenceList()
    { return conferenceList; }

    virtual void OnCreateConference(Conference *)
    { }

    virtual void OnDestroyConference(Conference *)
    { }

    virtual void OnMemberJoining(Conference *, ConferenceMember *)
    { }

    virtual void OnMemberLeaving(Conference *, ConferenceMember *)
    { }

  protected:
    virtual Conference * CreateConference(const OpalGloballyUniqueID & _guid,
                                                       const PString & _number,
                                                       const PString & _name);

    PMutex conferenceListMutex;       
    ConferenceList conferenceList;
};


#ifndef NO_MCU_VIDEO

////////////////////////////////////////////////////
/** OutGoingVideo describes the data leaving the computer,
    and then sent by TCP/IP methods to the remote computer.


    OutGoingVideo is the connection/channel which connects the
    codec and the connection class, for the transport of data.
     */
class OutgoingVideo : public PVideoChannel
{
  PCLASSINFO(OutgoingVideo, PVideoChannel);

  public:
    OutgoingVideo(H323EndPoint & ep, OpenMCUH323Connection & conn, int framesPerSec, BOOL videoLarge);

    ~OutgoingVideo();

    BOOL Close();
    
    /** uses over ride of Read function in the PChannel class.
      */
    BOOL Read(void * buffer, PINDEX  amount);
    
    void SetRenderFrameSize(int /*_width*/, int /*_height*/) 
      {PTRACE(3,"OutgoingVideo Set size");}
    
    BOOL Redraw(const BYTE * /*frame*/) 
        { return TRUE; }

    BOOL IsOpen() const   
        { return !closed; }

    BOOL IsGrabberOpen()
        { return TRUE; }


    PINDEX  GetGrabWidth()
        { return (videoLarge ? 352 : 176); }

    /**Return the height of the currently selected grabbing device.
     */
    PINDEX  GetGrabHeight()
      { return (videoLarge ? 288 : 144 ); }

    protected:
      H323EndPoint & ep;
      OpenMCUH323Connection & conn;

      PMutex videoChanMutex;
      BOOL videoLarge;

      VideoDelay delay;
      int        msBetweenFrames;
      BOOL       closed;
};

////////////////////////////////////////////////////
/** IncomingVideo describes the data entering the computer,
    which is placed in the video buffer.

     */
class IncomingVideo : public PVideoChannel
{
  PCLASSINFO(IncomingVideo, PVideoChannel);

  public:
    IncomingVideo(MyH323EndPoint & ep, OpenMCUH323Connection & conn);

    ~IncomingVideo();
    
    BOOL Write(const void * buffer, PINDEX amount);
    BOOL Close();

    void SetRenderFrameSize(int _width, int _height);

    BOOL Redraw(const BYTE * frame) 
        { return Write(frame,0); }

    BOOL IsOpen() const   
        { return !closed; }

    PINDEX  GetGrabWidth()
        { PTRACE(3,"incomingvideo get grab width"); return width; }

    /**Return the height of the currently selected grabbing device.
     */
    PINDEX  GetGrabHeight()
      { return height; }

    protected:

    MyH323EndPoint & ep;
    OpenMCUH323Connection & conn;
    PMutex videoChanMutex;

    PINDEX  width;
    PINDEX  height;
    PINDEX  frameSize;

    VideoDelay delay;
    BOOL       closed;
};

#endif 

#endif



syntax highlighted by Code2HTML, v. 0.9.1