/*========================================================================== * * 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 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_ */