Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
12 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: inqueue2.h
  6. * Content: Definition of the CInputQueue2 class
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 07/16/99 pnewson Created
  12. * 07/27/99 pnewson Overhauled to support new message numbering method
  13. * 08/03/99 pnewson General clean up
  14. * 08/24/99 rodtoll Fixed for release builds -- removed m_wQueueId from debug block
  15. * 01/31/2000 pnewson replace SAssert with DNASSERT
  16. * 03/26/2000 rodtoll Modified queue to be more FPM friendly
  17. * 03/29/2000 rodtoll Bug #30753 - Added volatile to the class definition
  18. * 07/09/2000 rodtoll Added signature bytes
  19. *
  20. ***************************************************************************/
  21. #ifndef _INPUTQUEUE2_H_
  22. #define _INPUTQUEUE2_H_
  23. class CFrame;
  24. class CFramePool;
  25. class CInnerQueue;
  26. class CInnerQueuePool;
  27. typedef struct _QUEUE_PARAMS
  28. {
  29. WORD wFrameSize;
  30. BYTE bInnerQueueSize;
  31. BYTE bMaxHighWaterMark;
  32. int iQuality;
  33. int iHops;
  34. int iAggr;
  35. BYTE bInitHighWaterMark;
  36. WORD wQueueId;
  37. WORD wMSPerFrame;
  38. CFramePool* pFramePool;
  39. } QUEUE_PARAMS, *PQUEUE_PARAMS;
  40. typedef struct _QUEUE_STATISTICS
  41. {
  42. DWORD dwTotalFrames;
  43. DWORD dwTotalMessages;
  44. DWORD dwTotalBadMessages;
  45. DWORD dwDiscardedFrames;
  46. DWORD dwDuplicateFrames;
  47. DWORD dwLostFrames;
  48. DWORD dwLateFrames;
  49. DWORD dwOverflowFrames;
  50. } QUEUE_STATISTICS, *PQUEUE_STATISTICS;
  51. // This class manages a queue of frames. It is designed
  52. // to allow a client class to remove frames from the queue
  53. // at regular intervals, and to hide any out of order
  54. // frame reception, or dropped frames from the caller.
  55. // If for whatever reason there is no frame available
  56. // to give a client, this class will still provide a
  57. // frame marked as silent. This allows the client to
  58. // simply call the dequeue function once per period, and
  59. // consume the data at the agreed rate. So for example,
  60. // the client to this class could be a thread which
  61. // is consuming input data and passing it to DirectSound
  62. // for playback. It can simply get a frame every 1/10 of
  63. // a second (or however long a frame is), and play it.
  64. //
  65. // This is the second generation of input queue. It
  66. // manages a set of inner queues, each of which is used
  67. // for a "message". The stream of speech is divided into
  68. // a series of messages, using silence as the divider.
  69. // This class will not function well if the audio stream
  70. // is not divided into separate messages.
  71. //
  72. #define VSIG_INPUTQUEUE2 'QNIV'
  73. #define VSIG_INPUTQUEUE2_FREE 'QNI_'
  74. //
  75. volatile class CInputQueue2
  76. {
  77. private:
  78. DWORD m_dwSignature; // Debug signature
  79. // A list of pointers to InnerQueue objects. This is where
  80. // the frames get stored. InnerQueues are retrieved from
  81. // a pool of InnerQueues and added to this list as new
  82. // messages arrive. When a message is finished, the InnerQueue
  83. // is removed from this list and returned to the pool.
  84. std::list<CInnerQueue*> m_lpiqInnerQueues;
  85. // The queue will not enqueue any input frames until at least
  86. // one dequeue has been requested. This will function as an interlock
  87. // to ensure that the queue does not fill with data until the
  88. // consumer thread is ready to take it.
  89. BOOL m_fFirstDequeue;
  90. // This flag remembers if it's the first time a frame
  91. // has been accepted for enqueue. We need this so we
  92. // know what the first message number is.
  93. BOOL m_fFirstEnqueue;
  94. // The message number currently at the head of the queue
  95. BYTE m_bCurMsgNum;
  96. // A critical section used to exclude the enqueue, dequeue and reset
  97. // functions from one another. Also passed to the frame class so
  98. // Return calls can be synchronized. These two classes need to share
  99. // a critical section because the CFramePool class updates the
  100. // CFrame pointers in the inner queues when a frame is returned to
  101. // the frame pool.
  102. DNCRITICAL_SECTION m_csQueue;
  103. // a vector of the quality ratings of each high water mark
  104. std::vector<double> m_vdQualityRatings;
  105. // A vector that contains the factored optimum quality for
  106. // each high water mark. As the high water mark gets larger
  107. // we become more tolerant of lost packets. While you may
  108. // want to have a 0.5% late packet rate at 0.1 or 0.2 second
  109. // long queues, you probably don't want to strive for that
  110. // when the queue size reaches 2 seconds!
  111. std::vector<double> m_vdFactoredOptQuals;
  112. // the quality parameters
  113. // Quality is measured by a floating point number.
  114. // This number represents the ratio of "bad stuff" that occurs
  115. // relative to the amount of "stuff" going on.
  116. //
  117. // In intuitive terms, if one of the last 100 frames was bad
  118. // (bad meaning late) the quality rating would be 0.01. (Note
  119. // that we don't count lost frames against the queue, since
  120. // increasing the queue size won't do anything to help lost
  121. // frames.)
  122. //
  123. // However, the measurement isn't quite that simple, because we
  124. // bias it towards the more recent frames. That's what the frame
  125. // strength parameter is for. It represents the "weight" given to
  126. // the most recent frames. A frame strength of 0.01 would mean that
  127. // the most recent frame counts for 1% of the quality of the queue,
  128. // either good or bad.
  129. //
  130. // Note that when we want to compare the "distance" between two
  131. // quality ratings, we'll use the inverse of the value, not the value
  132. // itself. That should match our perception of quality a bit
  133. // more (kind of like our hearing).
  134. //
  135. // For example, the perceived difference in quality between 0.01
  136. // and 0.02 is about 2 - twice as many errors occur on 0.02 than
  137. // 0.01 so the "distance" between 0.01 and 0.02 should be calculated
  138. // like 0.02/0.01 = 2. And the distance between 0.02 and 0.04 should
  139. // be calculated like 0.04/0.02 = 2. So the 'point' 0.04 is the same
  140. // 'distance' from 0.02 as the 'point' 0.01.
  141. //
  142. // Note the wording is weird - bad (low) quality has a higher numerical
  143. // value, oh well
  144. //
  145. // The threshold value is the distance the quality value must wander
  146. // from the optimum in order to warrant considering a change of
  147. // high water mark. For example, a value of 2 would mean that
  148. // for an optimum value of 0.02, the value would have to wander to
  149. // 0.01 or 0.04 before we'd consider a change. This is currently set
  150. // very low so the algorithm will quickly hunt out the best watermarks.
  151. double m_dOptimumQuality;
  152. double m_dQualityThreshold;
  153. double m_dFrameStrength;
  154. // the number of milliseconds in a frame. This is used to normalize
  155. // the frame strength to time, so a particular input aggressiveness
  156. // will provide the same results regardless of the current frame size.
  157. WORD m_wMSPerFrame;
  158. // We are interfacing to the outside world via
  159. // two parameters, Quality and Aggressiveness.
  160. // these members are integers in the range
  161. // defined by the constants above, and are used
  162. // to set the double values above appropriately.
  163. // We need to provide the hop count for reasons
  164. // discussed in the SetQuality() function.
  165. int m_iQuality;
  166. int m_iHops;
  167. int m_iAggr;
  168. // the current high water mark
  169. BYTE m_bCurHighWaterMark;
  170. // the cap on the high water mark
  171. BYTE m_bMaxHighWaterMark;
  172. // the initial high water mark on a new or reset queue
  173. BYTE m_bInitHighWaterMark;
  174. // Some statistics to track.
  175. DWORD m_dwTotalFrames;
  176. DWORD m_dwTotalMessages;
  177. DWORD m_dwTotalBadMessages;
  178. DWORD m_dwDiscardedFrames;
  179. DWORD m_dwDuplicateFrames;
  180. DWORD m_dwLostFrames;
  181. DWORD m_dwLateFrames;
  182. DWORD m_dwOverflowFrames;
  183. DWORD m_dwQueueErrors;
  184. // An abritrary queue ID, provided to the constructor,
  185. // used to identify which queue an instrumentation message
  186. // is coming from. It serves no other purpose, and can be
  187. // ignored except for debug purposes.
  188. WORD m_wQueueId;
  189. // the frame pool to manage the frames so we don't have to
  190. // allocate a huge number of them when only a few are
  191. // actually in use.
  192. CFramePool* m_pFramePool;
  193. // the inner queue pool to manage innner queues. Same idea
  194. // as the frame pool
  195. CInnerQueuePool* m_pInnerQueuePool;
  196. public:
  197. // The constructor.
  198. CInputQueue2();
  199. HRESULT Initialize( PQUEUE_PARAMS pQueueParams );
  200. void DeInitialize();
  201. void GetStatistics( PQUEUE_STATISTICS pStats ) const;
  202. // The destructor. Release all the resources we acquired in the
  203. // constructor
  204. ~CInputQueue2();
  205. // This function clears all buffers and resets the other class
  206. // information to an initial state. DO NOT CALL THIS FUNCTION
  207. // IF THE QUEUE IS IN USE! i.e. do not call it if you have
  208. // not called Return() on every frame that you have
  209. // taken from this queue.
  210. void Reset();
  211. // Call this function to add a frame to the queue. I
  212. // considered returning a reference to a frame which
  213. // the caller could then stuff, but because the frames
  214. // will not always arrive in order, that would mean I would have
  215. // to copy the frame sometimes anyway. So, for simplicity, the
  216. // caller has allocated a frame, which it passes a reference
  217. // to, and this function will copy that frame into the
  218. // appropriate place in the queue, according to its
  219. // message number and sequence number.
  220. void Enqueue(const CFrame& fr);
  221. // This function retrieves the next frame from the head of
  222. // the queue. For speed, it does not copy the data out of the
  223. // buffer, but instead returns a pointer to the actual
  224. // frame from the queue. Of course, there is the danger
  225. // that the CInputQueue2 object which returns a reference to the
  226. // frame may try to reuse that frame before the caller is
  227. // finished with it. The CFrame's lock and unlock member functions
  228. // are used to ensure this does not happen. When the caller
  229. // is finished with the CFrame object, it should call vUnlock()
  230. // on it. If the caller doesn't unlock the frame, bad things
  231. // will happen when the input queue tries lock it again when
  232. // it wants to reuse that frame. In any case, the caller
  233. // should always unlock the returned frame before it attempts
  234. // to dequeue another frame.
  235. CFrame* Dequeue();
  236. // get and set the quality parameters
  237. int GetQuality() const { return m_iQuality; }
  238. void SetQuality(int iQuality, int iHops = 1);
  239. int GetAggr() const { return m_iAggr; }
  240. void SetAggr(int iAggr);
  241. // get and set the default high watermark
  242. BYTE GetInitHighWaterMark() const { return m_bInitHighWaterMark; }
  243. void SetInitHighWaterMark(BYTE bInitHighWaterMark) { m_bInitHighWaterMark = bInitHighWaterMark; }
  244. // get stats
  245. DWORD GetDiscardedFrames() const { return m_dwDiscardedFrames; }
  246. DWORD GetDuplicateFrames() const { return m_dwDuplicateFrames; }
  247. DWORD GetLateFrames() const { return m_dwLateFrames; }
  248. DWORD GetLostFrames() const { return m_dwLostFrames; }
  249. DWORD GetOverflowFrames() const { return m_dwOverflowFrames; }
  250. DWORD GetQueueErrors() const { return m_dwQueueErrors; }
  251. DWORD GetTotalBadMessages() const { return m_dwTotalBadMessages; }
  252. DWORD GetTotalFrames() const { return m_dwTotalFrames; }
  253. DWORD GetTotalMessages() const { return m_dwTotalMessages; }
  254. BYTE GetHighWaterMark() const { return m_bCurHighWaterMark; }
  255. private:
  256. // a function to collect the stats from an input queue after a
  257. // message is complete, and perform the queue adaptation
  258. void HarvestStats(CInnerQueue* piq);
  259. // a function which looks at a finished inner queue and decides
  260. // if the message was 'good' or 'bad'.
  261. double AdjustQuality(const CInnerQueue* piq, double dCurQuality) const;
  262. // set a new high water mark
  263. void SetNewHighWaterMark(BYTE bNewHighWaterMark);
  264. };
  265. #endif