/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    MSPStrm.h

Abstract:

    Definitions for CMSPStream class.

--*/
#ifndef _MSPSTRM_H_
#define _MSPSTRM_H_


/*++

Class Description:

    Represents a stream in a call.

--*/

#define STRM_INITIAL            0x00000000
#define STRM_TERMINALSELECTED   0x00000001
#define STRM_CONFIGURED         0x00000002
#define STRM_RUNNING            0x00000004
#define STRM_PAUSED             0x00000008
#define STRM_STOPPED            0x00000010

class CMSPStream;

class ATL_NO_VTABLE CPTEventSink :
    public CComObjectRootEx<CComMultiThreadModel>,
    public ITPluggableTerminalEventSink
{

public:
    CPTEventSink();
    ~CPTEventSink();

BEGIN_COM_MAP( CPTEventSink )
    COM_INTERFACE_ENTRY( ITPluggableTerminalEventSink )
END_COM_MAP()

public:
    // --- ITDTEventSink ---
	STDMETHOD(FireEvent)(
        /* in */ const MSP_EVENT_INFO *pMspEventInfo
        );

    
public:

    //
    // set the stream which will be processing our events
    //
    // this method is called by the stream when it creates and initializes
    // the sink object, and also when the stream is going away and want to 
    // tell us that it is no longer available to process our events.
    //

    HRESULT SetSinkStream( CMSPStream *pStream );

private:


    //
    // a nested structure that is used to pass event and stream to the
    // asynchronous event processing routine.
    //

    struct AsyncEventStruct
    {

        //
        // pointer to the stream on which to fire event
        //

        CMSPStream *pMSPStream;

        
        //
        // pointer to the event item to be processed
        //

        MSPEVENTITEM *pEventItem;


        //
        // as a public service, initialize structure's data members 
        //

        AsyncEventStruct()
            :pMSPStream(NULL),
            pEventItem(NULL)
        {
            LOG((MSP_TRACE, "AsyncEventStruct::AsyncEventStruct[%p]", this));
        }


        //
        // as a safety measure, set data members to NULL's in destructor 
        // to make sure no one attemopts to use them after the strcuture is 
        // gone. 
        //
        // note: we don't free any data members here -- that's responsibility 
        // of the structure's client
        //

        ~AsyncEventStruct()
        {
            pMSPStream = NULL;
            pEventItem = NULL;
            
            LOG((MSP_TRACE, "AsyncEventStruct::~AsyncEventStruct[%p]", this));
        }

    }; // AsyncEventStruct


    //
    // the callback function that is submitted to thread pool api for async 
    // event processing. The argument is the event structure containing stream
    // and the actual event
    //
    
    static DWORD WINAPI FireEventCallBack(LPVOID pEventStructure);


private:

     CMSPStream*    m_pMSPStream;
};

class ATL_NO_VTABLE CMSPStream : 
    public CComObjectRootEx<CComMultiThreadModelNoCS>,
    public IDispatchImpl<ITStream, &IID_ITStream, &LIBID_TAPI3Lib>
{
public:

BEGIN_COM_MAP(CMSPStream)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(ITStream)
    COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
END_COM_MAP()

DECLARE_GET_CONTROLLING_UNKNOWN()

    CMSPStream(); 
    ~CMSPStream();

// methods of the CComObject
    virtual void FinalRelease();

// ITStream methods, called by the app.
    STDMETHOD (get_MediaType) (
        OUT     long *                  plMediaType
        );

    STDMETHOD (get_Direction) (
        OUT     TERMINAL_DIRECTION *    pTerminalDirection
        );

    STDMETHOD (get_Name) (
        OUT     BSTR *                  ppName
        ) = 0;

    STDMETHOD (SelectTerminal) (
        IN      ITTerminal *            pTerminal
        );

    STDMETHOD (UnselectTerminal) (
        IN     ITTerminal *             pTerminal
        );

    STDMETHOD (EnumerateTerminals) (
        OUT     IEnumTerminal **        ppEnumTerminal
        );

    STDMETHOD (get_Terminals) (
        OUT     VARIANT *               pTerminals
        );

    STDMETHOD (StartStream) ();

    STDMETHOD (PauseStream) ();

    STDMETHOD (StopStream) ();

// methods called by the MSPCall object.
    virtual HRESULT Init(
        IN     HANDLE                   hAddress,
        IN     CMSPCallBase *           pMSPCall,
        IN     IMediaEvent *            pGraph,
        IN     DWORD                    dwMediaType,
        IN     TERMINAL_DIRECTION       Direction
        );

    virtual HRESULT ShutDown();

    virtual HRESULT GetState(
        OUT     DWORD *                  pdwStatus
        ) { return E_NOTIMPL; }

    virtual HRESULT HandleTSPData(
        IN     BYTE *                   pData,
        IN     DWORD                    dwSize
        );

    virtual HRESULT ProcessGraphEvent(
        IN  long lEventCode,
        IN  LONG_PTR lParam1,
        IN  LONG_PTR lParam2
        );

protected:
    // --- Helper functions ---
    HRESULT RegisterPluggableTerminalEventSink(
        /*[in]*/ ITTerminal*     pTerminal
        );

    HRESULT UnregisterPluggableTerminalEventSink(
        /*[in]*/ ITTerminal*     pTerminal
        );

    
    HRESULT ReleaseSink();


    //
    // we want to have control over our addref and release logic: we need to do
    // special tricks to avoid stream being accessed by the event sink while
    // the stream is being deleted.
    //

    ULONG InternalAddRef();

    ULONG InternalRelease();


public:

    
    //
    // this method is called by CPTEventSink when it has an event for us to 
    // process
    //

    HRESULT HandleSinkEvent(MSPEVENTITEM *pEventItem);


protected:
    // Pointer to the free threaded marshaler.
    IUnknown *                  m_pFTM;

    // The current state of the stream.
    DWORD                       m_dwState;

    // The media type of this stream. Audio, video, or others.
    DWORD                       m_dwMediaType;

    // The direction of this stream. Incoming or outgoing.
    TERMINAL_DIRECTION          m_Direction;

    // The address on which this stream is being used.
    HANDLE                      m_hAddress;

    // The reference to the call object.
    CMSPCallBase *              m_pMSPCall;

    // The pointers to the graph object interfaces.
    IGraphBuilder *             m_pIGraphBuilder;
    IMediaControl *             m_pIMediaControl;

    // The list of stream objects in the call.
    CMSPArray <ITTerminal *>    m_Terminals;

    // The lock that protects the stream object. The stream object 
    // should never acquire the lock and then call a MSPCall method 
    // that might lock.
    CMSPCritSection             m_lock;

    // The lock that protects refcounting on the stream object. this is a 
    // workaround needed to sync against event sink attempting to access the 
    // stream object while it is being deleted.

    CMSPCritSection             m_lockRefCount;

    // The Event Sink for pluggable terminals
    ITPluggableTerminalEventSink* m_pPTEventSink;


    //
    // we have to implement our own reference counting to work around the 
    // problem of event sink addreffing us after we saw our last release
    //

    long                        m_lMyPersonalRefcount;

    
    //
    // this is a flag that we use to distingush between first addref and the 
    // addref on the object whose refcount has gone down to 0.
    //

    BOOL                        m_bFirstAddRef;

};

#endif // __MSPSTRM_H_
