276 lines
9.2 KiB
C
276 lines
9.2 KiB
C
|
/*==========================================================================
|
||
|
*
|
||
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: frame.h
|
||
|
* Content: declaration of the CFrame and CFramePool classes
|
||
|
*
|
||
|
* History:
|
||
|
* Date By Reason
|
||
|
* ==== == ======
|
||
|
* 07/16/99 pnewson Created
|
||
|
* 07/22/99 rodtoll Updated target to be DWORD
|
||
|
* 08/03/99 pnewson General clean up, updated target to DVID
|
||
|
* 01/14/2000 rodtoll Updated to support multiple targets. Frame will
|
||
|
* automatically allocate memory as needed for targets.
|
||
|
* rodtoll Added SetEqual function to making copying of frame
|
||
|
* in Queue easier.
|
||
|
* rodtoll Added support for "user controlled memory" frames.
|
||
|
* When the default constructor is used with the UserOwn_XXXX
|
||
|
* functions the frames use user specified buffers.
|
||
|
* (Removes a buffer copy when queueing data).
|
||
|
* 01/31/2000 pnewson replace SAssert with DNASSERT
|
||
|
* 03/29/2000 rodtoll Bug #30753 - Added volatile to the class definition
|
||
|
* 07/09/2000 rodtoll Added signature bytes
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#ifndef _FRAME_H_
|
||
|
#define _FRAME_H_
|
||
|
|
||
|
// forward declaration
|
||
|
class CFramePool;
|
||
|
|
||
|
#define VSIG_FRAME 'MRFV'
|
||
|
#define VSIG_FRAME_FREE 'MRF_'
|
||
|
|
||
|
// This class is designed to manage one frame of sound data.
|
||
|
//
|
||
|
// tag: fr
|
||
|
volatile class CFrame
|
||
|
{
|
||
|
private:
|
||
|
|
||
|
DWORD m_dwSignature;
|
||
|
// The critical section object which is used to protect the
|
||
|
// return method. This is passed in by CInputQueue2 and/or CInnerQueue
|
||
|
// class, so that the return method is serialized with calls to
|
||
|
// Reset, Enqueue and Dequeue. If no critical section is passed,
|
||
|
// the Return member should not be used, and this frame should
|
||
|
// not be part of a managed pool.
|
||
|
DNCRITICAL_SECTION *m_pCriticalSection;
|
||
|
|
||
|
// Length of the data within the frame. There may be less then a whole
|
||
|
// frame worth of data in the buffer due to compression/decompression may
|
||
|
// result in a slightly different size buffer.
|
||
|
WORD m_wFrameLength;
|
||
|
|
||
|
// The size of this frame. It would be easier to make
|
||
|
// this a class constant, but we're probably going to want to
|
||
|
// toy with the frame sizes while we're optimizing, and
|
||
|
// we may even get really fancy in the future and have
|
||
|
// the client and server negotiate the frame size at connection
|
||
|
// time, all of which will be easier if we bite the bullet now
|
||
|
// and make this a member variable. Note this is constant,
|
||
|
// so once a frame is instantiated, it's size is permanently set.
|
||
|
WORD m_wFrameSize;
|
||
|
|
||
|
// The client number this frame is coming from or
|
||
|
// going to.
|
||
|
WORD m_wClientId;
|
||
|
|
||
|
// The frame sequence number.
|
||
|
BYTE m_wSeqNum;
|
||
|
|
||
|
// The message number the frame is part of
|
||
|
BYTE m_bMsgNum;
|
||
|
|
||
|
// The target of the frame
|
||
|
PDVID m_pdvidTargets;
|
||
|
DWORD m_dwNumTargets;
|
||
|
DWORD m_dwMaxTargets;
|
||
|
|
||
|
bool m_fOwned;
|
||
|
|
||
|
// A flag to specify that this frame contains nothing but silence.
|
||
|
// When this flag is set, the data in the frame buffer should not
|
||
|
// be used - it's probably not valid.
|
||
|
BYTE m_bIsSilence;
|
||
|
|
||
|
// A pointer to the frame's data
|
||
|
BYTE* m_pbData;
|
||
|
|
||
|
// If this frame is part of a managed frame pool, this
|
||
|
// member will be non-null.
|
||
|
CFramePool* m_pFramePool;
|
||
|
|
||
|
// If this frame is part of a managed frame pool, this
|
||
|
// points to the "primary" pointer to this frame.
|
||
|
// When the frame is unlocked, and therefore returned
|
||
|
// to the pool, the pointer this member points to will
|
||
|
// be set to null. This action is protected by the
|
||
|
// critical section passed to the class.
|
||
|
CFrame** m_ppfrPrimary;
|
||
|
|
||
|
// A flag to indicate if this frame was "lost". This is
|
||
|
// used to distinguish the silent frames pulled from the
|
||
|
// queue between messages from the dead space caused by
|
||
|
// a known lost packet.
|
||
|
bool m_fIsLost;
|
||
|
|
||
|
|
||
|
// don't allow copy construction or assignment of these
|
||
|
// structures, as this would kill our performance, and
|
||
|
// we don't want to do it by accident
|
||
|
CFrame(const CFrame& fr);
|
||
|
CFrame& operator=(const CFrame& fr);
|
||
|
|
||
|
public:
|
||
|
|
||
|
// This constructor sets all the frame's info, and allocates
|
||
|
// the data buffer, but does not set the data inside the buffer
|
||
|
// to anything. Defaults are provided for all the parameters
|
||
|
// except for the frame size. Note: no default constructor,
|
||
|
// since you must specify the frame size.
|
||
|
CFrame(WORD wFrameSize,
|
||
|
WORD wClientNum = 0,
|
||
|
BYTE wSeqNum = 0,
|
||
|
BYTE bMsgNum = 0,
|
||
|
BYTE bIsSilence = 0,
|
||
|
CFramePool *pFramePool = NULL,
|
||
|
DNCRITICAL_SECTION* pCriticalSection = NULL,
|
||
|
CFrame** ppfrPrimary = NULL);
|
||
|
|
||
|
// A frame which manages user ownded memory
|
||
|
CFrame();
|
||
|
|
||
|
// The destructor cleans up the memory allocated by the
|
||
|
// constructor
|
||
|
~CFrame();
|
||
|
|
||
|
inline DWORD GetNumTargets() const { return m_dwNumTargets; };
|
||
|
inline const PDVID const GetTargetList() const { return m_pdvidTargets; };
|
||
|
|
||
|
// Length of the data within the buffer
|
||
|
WORD GetFrameLength() const { return m_wFrameLength; }
|
||
|
|
||
|
// returns the frame size, (the length of the data buffer)
|
||
|
WORD GetFrameSize() const { return m_wFrameSize; }
|
||
|
|
||
|
HRESULT SetEqual( const CFrame &frSourceFrame );
|
||
|
|
||
|
// These are just a bunch of set and get functions for
|
||
|
// the simple parts of the class, the client id, the
|
||
|
// sequence number, the silence flag, etc.
|
||
|
HRESULT GetTargets( PDVID pdvidTargets, PDWORD pdwNumTargets ) const;
|
||
|
HRESULT SetTargets( PDVID pdvidTargets, DWORD dwNumTargets );
|
||
|
|
||
|
BYTE GetMsgNum() const { return m_bMsgNum; }
|
||
|
void SetMsgNum( BYTE msgNum ) { m_bMsgNum = msgNum; }
|
||
|
void SetClientId(WORD wClientId) { m_wClientId = wClientId; }
|
||
|
WORD GetClientId() const { return m_wClientId; }
|
||
|
void SetSeqNum(BYTE wSeqNum) { m_wSeqNum = wSeqNum; }
|
||
|
BYTE GetSeqNum() const { return m_wSeqNum; }
|
||
|
void SetIsSilence(BYTE bIsSilence) { m_bIsSilence = bIsSilence; }
|
||
|
void SetFrameLength(const WORD &length) { m_wFrameLength = length; }
|
||
|
BYTE GetIsSilence() const { return m_bIsSilence; }
|
||
|
bool GetIsLost() const { return m_fIsLost; }
|
||
|
void SetIsLost(bool fIsLost) { m_fIsLost = fIsLost; }
|
||
|
|
||
|
// Now we have the functions which handle the data. This
|
||
|
// class is pretty trusting, because it will give out the
|
||
|
// pointer to it's data. This is to avoid all non-required
|
||
|
// buffer copies. For example, when you hand a buffer to
|
||
|
// a wave in function, you can give it the pointer to this
|
||
|
// buffer, and it will fill in the frame's buffer directly.
|
||
|
// Between this function and the GetFrameSize() and
|
||
|
// GetFrameLength() functions, you can do anything you want
|
||
|
// with the buffer.
|
||
|
BYTE* GetDataPointer() const { return m_pbData; }
|
||
|
|
||
|
// This copies the data from another frame into this frame
|
||
|
void CopyData(const CFrame& fr)
|
||
|
{
|
||
|
memcpy(m_pbData, fr.GetDataPointer(), fr.GetFrameLength() );
|
||
|
m_wFrameLength = fr.GetFrameLength();
|
||
|
}
|
||
|
|
||
|
void UserOwn_SetData( BYTE *pbData, DWORD dwLength )
|
||
|
{
|
||
|
m_pbData = pbData;
|
||
|
m_wFrameLength = dwLength;
|
||
|
m_wFrameSize = dwLength;
|
||
|
}
|
||
|
|
||
|
void UserOwn_SetTargets( PDVID pdvidTargets, DWORD dwNumTargets )
|
||
|
{
|
||
|
m_pdvidTargets = pdvidTargets;
|
||
|
m_dwNumTargets = dwNumTargets;
|
||
|
m_dwMaxTargets = dwNumTargets;
|
||
|
}
|
||
|
|
||
|
// This copies data from a buffer into this frame's
|
||
|
// buffer.
|
||
|
void CopyData(const BYTE* pbData, WORD wFrameLength);
|
||
|
|
||
|
// If this frame is part of a frame pool managed by a
|
||
|
// CFramePool object, then call this function when you
|
||
|
// are done with the frame and want to return it to the
|
||
|
// pool.
|
||
|
void Return();
|
||
|
|
||
|
void SetCriticalSection(DNCRITICAL_SECTION* pCrit) { m_pCriticalSection = pCrit; }
|
||
|
void SetPrimaryPointer(CFrame** ppfrPrimary) { m_ppfrPrimary = ppfrPrimary; }
|
||
|
void SetFramePool(CFramePool* pFramePool) { m_pFramePool = pFramePool; }
|
||
|
};
|
||
|
|
||
|
// This class manages a pool of frames, to reduce memory requirements.
|
||
|
// Only a few buffers are actually in use at any time by the queue
|
||
|
// class, and yet it may have to allocate hundreds of them unless
|
||
|
// a class such as this is used to manage their reuse.
|
||
|
volatile class CFramePool
|
||
|
{
|
||
|
private:
|
||
|
// the pool is simply a vector of frame objects
|
||
|
std::vector<CFrame *> m_vpfrPool;
|
||
|
|
||
|
// All the frames in the pool must be the same size,
|
||
|
// which is stored here.
|
||
|
WORD m_wFrameSize;
|
||
|
|
||
|
// This critical section is used to exclude the Get()
|
||
|
// and return members from each other.
|
||
|
DNCRITICAL_SECTION m_lock;
|
||
|
|
||
|
BOOL m_fCritSecInited;
|
||
|
|
||
|
public:
|
||
|
// Each frame pool manages frames of a certain size,
|
||
|
// so they can be easily reused. If you need multiple
|
||
|
// different frame sizes, you'll need more than one
|
||
|
// frame pool.
|
||
|
CFramePool(WORD wFrameSize);
|
||
|
~CFramePool();
|
||
|
|
||
|
BOOL Init()
|
||
|
{
|
||
|
if (DNInitializeCriticalSection( &m_lock ))
|
||
|
{
|
||
|
m_fCritSecInited = TRUE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Use Get to retrieve a frame from the pool. ppfrPrimary
|
||
|
// is a pointer to a point that you want set to null when
|
||
|
// this frame is returned to the pool. pCriticalSection
|
||
|
// points to a critical section that will be entered before
|
||
|
// setting the pointer to null, and left after setting the
|
||
|
// pointer to null. This is so external classes (such as
|
||
|
// CInnerQueue) can pass in a critical section that they also
|
||
|
// use to before examining the pointer referred to by ppfrPrimary
|
||
|
CFrame* Get(DNCRITICAL_SECTION* pCriticalSection, CFrame** ppfrPrimary);
|
||
|
|
||
|
// Call Return to give a frame back to the frame pool.
|
||
|
// This may set a pointer to null and enter a critical
|
||
|
// section, as described in Get() above.
|
||
|
void Return(CFrame* pFrame);
|
||
|
};
|
||
|
|
||
|
|
||
|
#endif /* _FRAME_H_ */
|