|
|
/*==========================================================================
* * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: innerque.h * Content: declaration of the CInnerQueue class * * History: * Date By Reason * ==== == ====== * 07/16/99 pnewson Created * 07/27/99 pnewson Overhauled to support new message numbering method * 08/03/99 pnewson General clean up * 08/24/99 rodtoll Fixed for release builds -- removed m_wQueueId from debug block * 10/28/99 pnewson Bug #113933 debug spew too verbose * implement inner queue pool code * ***************************************************************************/
#ifndef _INNERQUEUE_H_
#define _INNERQUEUE_H_
// The inner queue class is used to queue up a single voice message.
// A 'message' in this context means a series of frames that have the
// same message number and are part of the same stream of speech.
// an enum to specify the allowed states of the frame slots
// I appear to have to declare this out here, instead of inside
// the class, otherwise the vector declaration gets confused.
enum ESlotState { essEmpty = 1, essFull, };
volatile class CInnerQueue { public: // The constructor. bNumSlots must be at least 8, and must be
// a power of 2.
CInnerQueue(BYTE bNumSlots, WORD wFrameSize, CFramePool* pfpFramePool, DNCRITICAL_SECTION* pcsQueue, BYTE bMsgNum, BYTE bHighWaterMark = 0, WORD wQueueId = 0); HRESULT Init();
// The destructor
~CInnerQueue(); // An enum used to describe the possible queue states.
enum EState { empty = 1, // The queue is currently empty, awaiting the first frame
// Enqueue allowed, Dequeue not allowed.
filling, // The queue is currently filling to the high water mark
// Enqueue allowed. Dequeue not allowed.
ready, // The queue has filled to the high water mark
// Enqueue allowed, Dequeue allowed
finished // The queue has emptied. No new frames accepted
// Enqueue not allowed, Dequeue not allowed.
};
// Get the current state of the queue.
EState GetState() const { return m_eState; }
// Set the current state of the queue.
void SetState(EState eState) { m_eState = eState; }
// Get the current size of the queue
BYTE GetSize() const { return m_bQueueSize; }
// Get the current high water mark
BYTE GetHighWaterMark() const { return m_bHighWaterMark; }
// Set the current high water mark
void SetHighWaterMark(BYTE bHighWaterMark);
// Get, set, and increment the filling dequeue count
BYTE GetFillingDequeueReqs() const { return m_bFillingDequeueReqs; } void SetFillingDequeueReqs(BYTE bFillingDequeueReqs) { m_bFillingDequeueReqs = bFillingDequeueReqs; } void IncFillingDequeueReqs() { m_bFillingDequeueReqs++; }
// Get the stats for the current message
WORD GetMissingFrames() const { return m_wMissingFrames; } WORD GetDuplicateFrames() const { return m_wDuplicateFrames; } WORD GetOverflowFrames() const { return m_wOverflowFrames; } WORD GetLateFrames() const { return m_wLateFrames; } DWORD GetMsgLen() const { return m_dwMsgLen; }
// More stats stuff
void AddToKnownZeroLengthDequeues(WORD w) { m_wKnownZeroLengthDequeues += w; } WORD GetKnownZeroLengthDequeues() const { return m_wKnownZeroLengthDequeues; } void IncPossibleZeroLengthDequeues() { m_wPossibleZeroLengthDequeues++; } void SetPossibleZeroLengthDequeues(WORD w) { m_wPossibleZeroLengthDequeues = w; } WORD GetPossibleZeroLengthDequeues() const { return m_wPossibleZeroLengthDequeues; } // Add a frame to the Queue
void Enqueue(const CFrame& frFrame);
// Get a frame from the Queue
CFrame* Dequeue();
// reset the queue to its initial empty state
void Reset();
// reset all the class' stats
void ResetStats();
// get the message number this queue holds
BYTE GetMsgNum() const { return m_bMsgNum; } void SetMsgNum(BYTE bMsgNum) { m_bMsgNum = bMsgNum; } void SetQueueId(WORD wQueueId) { m_wQueueId = wQueueId; }
private: // Has the init function completed successfully?
BOOL m_fInited;
// The current state of the inner queue.
EState m_eState;
// The number of frame slots in the queue. must be a power
// of two, or else things will get bad if the sequence number
// rolls over.
BYTE m_bNumSlots;
// The number of frames required before the queue moves from
// 'filling' to 'ready' state.
BYTE m_bHighWaterMark;
// The current 'size' of the queue. The size of the queue is
// considered to be the number of filled slots, which may not
// be the same as the distance between the first filled slot
// and the last filled slot.
BYTE m_bQueueSize;
// The sequence number of the frame at the head of the queue.
BYTE m_bHeadSeqNum;
// A flag to track the first dequeue action.
bool m_fFirstDequeue;
// an array of slot states
//ESlotState* m_rgeSlotStates;
// An array of pointers to frames. This has to be pointers
// to frames, because CFrame has no default constructor.
CFrame** m_rgpfrSlots;
// This is a little stat that will help us to detect
// when a short message is getting hung up in a queue
// because it's not long enough to trigger the high
// water mark. It counts the number of times an outer dequeue
// operation has been declined because this inner queue
// is in the filling state. This gets reset to 0 when the
// high water mark is hit
BYTE m_bFillingDequeueReqs;
// These vars keep stats on the current message, presumably so
// we can intelligently adjust the high water mark
// A frame is considered missing if it has not arrived by the time
// it is required, but some frames following it have arrived.
WORD m_wMissingFrames;
// This one is pretty obvious. If we get the same frame twice, it's a duplicate
// aarono will bet his car that this can never happen, so if you every see this
// variable above one, call him up and make that bet!
WORD m_wDuplicateFrames;
// Overflow and late frames. If you look at where these are incremented
// you'll see that it is pretty much a judgement call if we're throwing
// away a frame due to an overflow or it being late, so take them with
// a grain of salt. The sum of the two stats is however an accurate count
// of how many frames arrived that we chucked.
WORD m_wOverflowFrames; WORD m_wLateFrames;
// These are used by the outer queue to remember if it
// needed a frame from this queue when it's size was zero.
WORD m_wPossibleZeroLengthDequeues; WORD m_wKnownZeroLengthDequeues;
// This is the number of frames that make up the current message
DWORD m_dwMsgLen; // make a dword in case of no voice detection
// The Queue ID is just used for debug messages
WORD m_wQueueId;
// The message number this queue is for
BYTE m_bMsgNum;
// frame pool stuff
CFramePool* m_pfpFramePool; DNCRITICAL_SECTION* m_pcsQueue; };
// Inner queues are requested as needed by the CInputQueue2 class.
// This class manages a pool of inner queues so that actual memory
// allocations are few and far between.
class CInnerQueuePool { private: BYTE m_bNumSlots; WORD m_wFrameSize; CFramePool* m_pfpFramePool; DNCRITICAL_SECTION* m_pcsQueue; std::vector<CInnerQueue *> m_vpiqPool; DNCRITICAL_SECTION m_lock; // to exclude Get and Return from each other
BOOL m_fCritSecInited;
public: CInnerQueuePool( BYTE bNumSlots, WORD wFrameSize, CFramePool* pfpFramePool, DNCRITICAL_SECTION* pcsQueue);
~CInnerQueuePool();
BOOL Init() { if (DNInitializeCriticalSection(&m_lock) ) { m_fCritSecInited = TRUE; return TRUE; } else { return FALSE; } }
CInnerQueue* Get( BYTE bHighWaterMark = 0, WORD wQueueId = 0, BYTE bMsgNum = 0);
void Return(CInnerQueue* piq); };
#endif // _INNERQUEUE_H_
|