/*==========================================================================
 * Copyright (C) 1999 Microsoft Corporation.  All Rights Reserved.
 *
 * File:       dvserverengine.h
 * Content:    Definition of class for DirectXVoice Server
 * History:
 *   Date		By		Reason
 *   ====		==		======
 *	07/06/99	rodtoll	Created It
 *  07/21/99	rodtoll Added settings confirm message to protocol.
 *  07/22/99	rodtoll	Added multiple reader/single writer guard to class
 *  07/23/99	rodtoll	Additional members for client/server and multicast
 *	07/26/99	rodtoll	Added support for new interfaces and access for DIRECTVOICESERVEROBJECT
 *  08/25/99	rodtoll	General Cleanup/Modifications to support new 
 *						compression sub-system.  
 *						Added parameter to the GetCompression Func
 * 09/14/99		rodtoll	Added new SetNotifyMask function
 *				rodtoll	Updated Iniitalize parameters to take notification masks.
 * 				rodtoll	Implemented notification masks.  (Allows user to choose which notifications to receive) 
 * 10/29/99		rodtoll	Bug #113726 - Integrate Voxware Codecs, updating to use new
 *						pluggable codec architecture.     
 * 11/23/99		rodtoll	Updated Initialize/SetNotifyMask so error checking behaviour is consistant 
 * 12/16/99		rodtoll Fix: Bug #122629 - Host migration broken in unusual configurations.
 *						Updated to use new algorithm described in dvprot.h
 *						- Generate and added host order IDs to player table messages
 *						- Added send of new hostmigrateleave message when shutting down and
 *					      host should migrate
 *						- Sends session lost when shutting down if no one available to take over hosting
 *						- Added new player list message
 *						- Fixed handling of refusing player connections 
 * 01/14/2000	rodtoll	Updated to allow multiple targets for a single player
 *				rodtoll	Updated to use FPM for managing memory for Multicast mode
 *				rodtoll	Updated to use new callback semantics
 * 03/29/2000	rodtoll Bug #30753 - Added volatile to the class definition
 * 04/07/2000   rodtoll Bug #32179 - Prevent registration of > 1 interface
 *              rodtoll Updated to use no copy sends, so handles pooling frames to be sent, proper
 *                      pulling of frames from pools and returns.   
 * 07/09/2000	rodtoll	Added signature bytes
 * 11/16/2000	rodtoll	Bug #40587 - DPVOICE: Mixing server needs to use multi-processors  
 * 11/28/2000	rodtoll	Bug #47333 - DPVOICE: Server controlled targetting - invalid targets are not removed automatically 
 * 04/06/2001	kareemc	Added Voice Defense
 *
 ***************************************************************************/
#ifndef __DVSERVERENGINE_H
#define __DVSERVERENGINE_H


struct DIRECTVOICESERVEROBJECT;
typedef struct _MIXERTHREAD_CONTROL *PMIXERTHREAD_CONTROL;

#define DVSSTATE_NOTINITIALIZED		0x00000000
#define DVSSTATE_IDLE				0x00000001
#define DVSSTATE_STARTUP			0x00000002
#define DVSSTATE_RUNNING			0x00000003
#define DVSSTATE_SHUTDOWN			0x00000004

// CDirectVoiceClientEngine
//
// This class represents the IDirectXVoiceServer interface.
//
#define VSIG_SERVERENGINE		'EVSV'
#define VSIG_SERVERENGINE_FREE	'EVS_'
//
volatile class CDirectVoiceServerEngine: public CDirectVoiceEngine
{

public:
	CDirectVoiceServerEngine( DIRECTVOICESERVEROBJECT *lpObject );
	~CDirectVoiceServerEngine();

public: // IDirectXVoiceServer Interface

	HRESULT HostMigrateStart(LPDVSESSIONDESC lpSessionDesc, DWORD dwHostOrderIDSeed = 0 );
    virtual HRESULT StartSession(LPDVSESSIONDESC lpSessionDesc, DWORD dwFlags, DWORD dwHostOrderIDSeed = 0 );
    virtual HRESULT StopSession(DWORD dwFlags, BOOL fSilent=FALSE, HRESULT hrResult = DV_OK );
    virtual HRESULT GetSessionDesc(LPDVSESSIONDESC lpSessionDescBuffer );
    virtual HRESULT SetSessionDesc(LPDVSESSIONDESC lpSessionDesc );
    HRESULT GetCaps(LPDVCAPS dvCaps);
    HRESULT GetCompressionTypes( LPVOID lpBuffer, LPDWORD lpdwBufferSize, LPDWORD lpdwNumElements, DWORD dwFlags);
    virtual HRESULT SetTransmitTarget(DVID dvidSource, PDVID pdvidTargets, DWORD dwNumTargets, DWORD dwFlags);
    virtual HRESULT GetTransmitTarget(DVID dvidSource, LPDVID lpdvidTargets, PDWORD pdwNumElements, DWORD dwFlags );
	virtual HRESULT MigrateHost( DVID dvidNewHost, LPDIRECTPLAYVOICESERVER lpdvServer );    
	virtual HRESULT SetNotifyMask( LPDWORD lpdwMessages, DWORD dwNumElements );	

public: // CDirectVoiceEngine Members

	HRESULT Initialize( CDirectVoiceTransport *lpTransport, LPDVMESSAGEHANDLER lpdvHandler, LPVOID lpUserContext, LPDWORD lpdwMessages, DWORD dwNumElements );
	virtual BOOL ReceiveSpeechMessage( DVID dvidSource, LPVOID lpMessage, DWORD dwSize );
	HRESULT StartTransportSession();
	HRESULT StopTransportSession();
	HRESULT AddPlayer( DVID dvID );
	HRESULT RemovePlayer( DVID dvID );
	HRESULT CreateGroup( DVID dvID );
	HRESULT DeleteGroup( DVID dvID );
	HRESULT AddPlayerToGroup( DVID dvidGroup, DVID dvidPlayer );
	HRESULT RemovePlayerFromGroup( DVID dvidGroup, DVID dvidPlayer );

	inline DWORD GetCurrentState() { return m_dwCurrentState; };	

	BOOL	InitClass();
	
public: // packet validation
	inline BOOL ValidateSettingsFlags( DWORD dwFlags );
	inline BOOL ValidatePacketType( PDVPROTOCOLMSG_FULLMESSAGE lpdvFullMessage );

	
protected: // Protocol Layer Handling (protserver.cpp)

    HRESULT Send_SessionLost( HRESULT hrReason );
    HRESULT Send_HostMigrateLeave( );
    HRESULT Send_HostMigrated();
    HRESULT Send_DisconnectConfirm( DVID dvid, HRESULT hrReason );
    HRESULT Send_DeletePlayer( DVID dvid );
    HRESULT Send_CreatePlayer( DVID dvidTarget, CVoicePlayer *pPlayer );
    HRESULT Send_ConnectRefuse( DVID dvid, HRESULT hrReason );
    HRESULT Send_ConnectAccept( DVID dvid );
	HRESULT SendPlayerList( DVID dvidSource, DWORD dwHostOrderID );
    
	BOOL CheckProtocolCompatible( BYTE ucMajor, BYTE ucMinor, DWORD dwBuild );    

protected:

	HRESULT InternalSetNotifyMask( LPDWORD lpdwMessages, DWORD dwNumElements );	

	void DoPlayerDisconnect( DVID dvidPlayer, BOOL bInformPlayer );
	void TransmitMessage( DWORD dwMessageType, LPVOID lpdvData, DWORD dwSize );
	void SetCurrentState( DWORD dwState );
	HRESULT CreatePlayerEntry( DVID dvidSource, PDVPROTOCOLMSG_SETTINGSCONFIRM lpdvSettingsConfirm, DWORD dwHostOrderID, CVoicePlayer **ppPlayer );

	BOOL HandleDisconnect( DVID dvidSource, PDVPROTOCOLMSG_GENERIC lpdvDisconnect, DWORD dwSize );
	BOOL HandleConnectRequest( DVID dvidSource, PDVPROTOCOLMSG_CONNECTREQUEST lpdvConnectRequest, DWORD dwSize );
	BOOL HandleSettingsConfirm( DVID dvidSource, PDVPROTOCOLMSG_SETTINGSCONFIRM lpdvSettingsConfirm, DWORD dwSize );
	BOOL HandleSettingsReject( DVID dvidSource, PDVPROTOCOLMSG_GENERIC lpdvGeneric, DWORD dwSize );
	BOOL HandleSpeechWithTarget( DVID dvidSource, PDVPROTOCOLMSG_SPEECHWITHTARGET lpdvSpeech, DWORD dwSize );
	BOOL HandleSpeech( DVID dvidSource, PDVPROTOCOLMSG_SPEECHHEADER lpdvSpeech, DWORD dwSize );	

	PDVTRANSPORT_BUFFERDESC GetTransmitBuffer( DWORD dwSize, LPVOID *ppvContext );
    HRESULT SendComplete( PDVEVENTMSG_SENDCOMPLETE pSendComplete );
    void ReturnTransmitBuffer( PVOID pvContext );

	HRESULT BuildAndSendTargetUpdate( DVID dvidSource, CVoicePlayer *pPlayerInfo );

	BOOL CheckForMigrate( DWORD dwFlags, BOOL fSilent );
	HRESULT InformClientsOfMigrate();
	void WaitForBufferReturns();

protected: // Client Server specific information (mixserver.cpp)

	static DWORD WINAPI MixerWorker( void *lpContext );
	static DWORD WINAPI MixerControl( void *pvContext );
	static BOOL MixingServerWakeupProc( DWORD_PTR param );

	void HandleMixerThreadError( HRESULT hr );
	void Mixer_Buffer_Reset(DWORD dwThreadIndex);
	void Mixer_Buffer_MixBuffer( DWORD dwThreadIndex,unsigned char *source );
	void Mixer_Buffer_Normalize( DWORD dwThreadIndex );

	HRESULT SetupBuffers();
	HRESULT FreeBuffers();

	HRESULT StartupClientServer();
	HRESULT ShutdownClientServer();

	HRESULT ShutdownWorkerThreads();
	HRESULT StartWorkerThreads();

	HRESULT HandleMixingReceive( CDVCSPlayer *pTargetPlayer, PDVPROTOCOLMSG_SPEECHWITHTARGET pdvSpeechWithtarget, DWORD dwSpeechSize, PBYTE pbSpeechData );	

	void AddPlayerToMixingAddList( CVoicePlayer *pVoicePlayer );
	void UpdateActiveMixingPendingList( DWORD dwThreadIndex, DWORD *pdwNumActive );
	void CleanupMixingList();

	void SpinWorkToThread( LONG lThreadIndex );

	void FindAndRemoveDeadTarget( DVID dvidTargetID );

protected: // Forwarding Server specific funcs (fwdserver.cpp)

	HRESULT StartupMulticast();
	HRESULT ShutdownMulticast();

	HRESULT HandleForwardingReceive( CVoicePlayer *pTargetPlayer,PDVPROTOCOLMSG_SPEECHWITHTARGET pdvSpeechWithtarget, DWORD dwSpeechSize, PBYTE pbSpeechData );

	void CleanupActiveList();

protected:

	DWORD					m_dwSignature;			// Signature 

	LPDVMESSAGEHANDLER		m_lpMessageHandler;		// User message handler
	LPVOID					m_lpUserContext;		// User context for message handler
	DVID					m_dvidLocal;			// DVID of the transport player for this host
	DWORD					m_dwCurrentState;		// Current state of the engine
    CDirectVoiceTransport	*m_lpSessionTransport;	// Transport for the session
	DVSESSIONDESC			m_dvSessionDesc;		// Description of session
	DWORD					m_dwTransportFlags;		// Flags for the transport session
	DWORD					m_dwTransportSessionType;
													// Type of transport session (client/server or peer to peer)
	LPDVFULLCOMPRESSIONINFO m_lpdvfCompressionInfo;	// Details of current compression type
	DWORD					m_dwCompressedFrameSize;// Max size of compressed frame
	DWORD					m_dwUnCompressedFrameSize;
													// Size of a single frame uncompressed
	DWORD					m_dwNumPerBuffer;		// Size of playback/record buffers in frames
	CFramePool				*m_pFramePool;			// Pool of frames for the queues
	 												// time of a frame size.
	DIRECTVOICESERVEROBJECT *m_lpObject;			// Pointer to the COM object this is running in 

	LPDWORD					m_lpdwMessageElements;	// Array containing the DVMSGID_XXXX values for all the
													// notifications developer wishes to receive.
													// If this is NULL all notifications are active
	DWORD					m_dwNumMessageElements;	// # of elements in the m_lpdwMessageElements array
	DWORD					m_dwNextHostOrderID;
	HRESULT					m_hrStopSessionResult;	// Reason that the session was stopped

    BOOL					m_mixerEightBit;		// Is the mixer format 8-bit
	BYTE					m_padding[3];    

	ServerStats				*m_pServerStats;

	DVCAPS					m_dvCaps;				// Caps

	DNCRITICAL_SECTION		m_csClassLock;
	DNCRITICAL_SECTION		m_csNotifyLock;			// Lock protection notification mask

	BILINK					m_blPlayerActiveList;
	DNCRITICAL_SECTION		m_csPlayerActiveList;

    CVoiceNameTable         m_voiceNameTable;
    CLockedFixedPool<CDVCSPlayer> m_fpCSPlayers;
    CLockedFixedPool<CVoicePlayer> m_fpPlayers;
	DNCRITICAL_SECTION		m_csHostOrderLock;

    DNCRITICAL_SECTION        m_csBufferLock;
	ServerStats				m_dvsServerStatsFixed;	// If global memory is unavailable    
    PFPOOL                  m_pBufferDescPool;
    PFPOOL                  *m_pBufferPools;
    DWORD                   *m_pdwBufferPoolSizes;
    DWORD                   m_dwNumPools;

protected: // Mixing server information

	DWORD					m_dwNumMixingThreads;
    DWORD					m_dwMixerSize;		// # of samples in the high resolution  mixer buffer	

	DNCRITICAL_SECTION		m_csMixingAddList;

	HANDLE					m_hTickSemaphore;		// Semaphore signalled by the timer
	HANDLE					m_hShutdownMixerEvent;	// Event signalled to shutdown the mixer
	HANDLE					m_hMixerDoneEvent;		// Signalled by the mixer thread when it's shutdown
	Timer					*m_timer;				// Timer that is signalled on a period equal to the

	PMIXERTHREAD_CONTROL	m_prWorkerControl;

	DWORD					m_dwMixerControlThreadID;
	HANDLE					m_hMixerControlThread;

	MixingServerStats		m_statMixingFixed;
	MixingServerStats		*m_pStats;

    PERF_APPLICATION		m_perfInfo;					// Perf info entry for this object	
    PERF_APPLICATION_INFO	m_perfAppInfo;				// APplication specific perrf info
    DNCRITICAL_SECTION		m_csStats;

	BOOL					m_fCritSecInited;
};

#endif