Windows Kernel Audio Piping

Well lately I have been busy working on a small driver for the windows kernel. The point of it from the start was to capture the data sent to the wave out and pipe it in as if it came from the microphone. What for? Well I did not have a microphone back then and I wanted to communicate through Skype and I wanted to write to the text to speech engine and send it as my robotic voice of sort. Unfortunately I did not have enough time or patience to achieve it till now. I have just recently finished it and it works just as intended. I haven't had the time to clean the source to upload it but didn't want to miss the opportunity to document the date and what I have been up to.

I realize there is a project called virtual audio cable that does that and other things, however it has a cost and I was thrilled to work with the WinDDK.

Next up: working with mongodb and mongodb

  1. #include "cbuffer.h"
  2. #include "debug.h"
  3. #include <msvad.h>
  4.  
  5. #define DEFAULT_FRAME_COUNT 2
  6. #define DEFAULT_FRAME_SIZE PAGE_SIZE * 4
  7. #define DEFAULT_BUFFER_SIZE DEFAULT_FRAME_SIZE * DEFAULT_FRAME_COUNT
  8.  
  9. CircularBuffer::CircularBuffer(void) :
  10. m_ulFrameCount(DEFAULT_FRAME_COUNT),
  11. m_ulBufferSize(DEFAULT_BUFFER_SIZE),
  12. m_ulFrameSize(DEFAULT_FRAME_SIZE),
  13. m_pDataBuffer(NULL),
  14. m_ulReadingFrame(0),
  15. m_ulFramePtr(0),
  16. m_ulBufferPtr(0),
  17. m_fFrameUsed(NULL),
  18. m_ulBufferPtr2(0)
  19.  
  20. {
  21. TRACE_ENTER();
  22. TRACE_EXIT();
  23. }
  24.  
  25. NTSTATUS CircularBuffer::Initialize(void)
  26. {
  27.  
  28. TRACE_ENTER();
  29.  
  30. NTSTATUS ntStatus = STATUS_SUCCESS;
  31.  
  32. KeInitializeSpinLock ( &m_FrameInUseSpinLock ) ;
  33.  
  34. m_pDataBuffer = (PBYTE)
  35. ExAllocatePoolWithTag
  36. (
  37. NonPagedPool,
  38. m_ulBufferSize,
  39. MSVAD_POOLTAG
  40. );
  41.  
  42. if (!m_pDataBuffer)
  43. {
  44. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  45. return ntStatus;
  46. }
  47.  
  48. RtlZeroMemory(m_pDataBuffer, m_ulBufferSize);
  49.  
  50. m_fFrameUsed = (PBOOL)
  51. ExAllocatePoolWithTag
  52. (
  53. NonPagedPool,
  54. m_ulFrameCount * sizeof(BOOL),
  55. MSVAD_POOLTAG
  56. );
  57.  
  58. if (!m_fFrameUsed)
  59. {
  60. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  61.  
  62. if (m_pDataBuffer)
  63. ExFreePoolWithTag(m_pDataBuffer, MSVAD_POOLTAG);
  64.  
  65. return ntStatus;
  66. }
  67.  
  68. RtlZeroMemory(m_fFrameUsed, m_ulFrameCount * sizeof(BOOL));
  69.  
  70. TRACE_EXIT();
  71. return ntStatus;
  72. }
  73. CircularBuffer::~CircularBuffer(void)
  74. {
  75. TRACE_ENTER();
  76.  
  77. if (m_pDataBuffer)
  78. {
  79. ExFreePoolWithTag(m_pDataBuffer, MSVAD_POOLTAG);
  80. }
  81.  
  82. if (m_fFrameUsed)
  83. {
  84. ExFreePoolWithTag(m_fFrameUsed, MSVAD_POOLTAG);
  85. // NOTE : Do not release m_pFilePtr.
  86. }
  87.  
  88. TRACE_EXIT();
  89. }
  90.  
  91. void CircularBuffer::CopyDataTo(IN PBYTE pBuffer, IN ULONG ulByteCount)
  92. {
  93. KIRQL kirl;
  94.  
  95. BOOL fSaveFrame = FALSE;
  96.  
  97. if (m_fWriteDisabled)
  98. {
  99. return;
  100. }
  101.  
  102. if( 0 == ulByteCount )
  103. {
  104. return;
  105. }
  106.  
  107. KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
  108. if (!m_fFrameUsed[m_ulFramePtr])
  109. {
  110. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  111.  
  112. ULONG ulWriteBytes = ulByteCount;
  113.  
  114. if( (m_ulBufferSize - m_ulBufferPtr) < ulWriteBytes )
  115. {
  116. ulWriteBytes = m_ulBufferSize - m_ulBufferPtr;
  117. }
  118.  
  119. RtlCopyMemory(m_pDataBuffer + m_ulBufferPtr, pBuffer, ulWriteBytes);
  120.  
  121. m_ulBufferPtr += ulWriteBytes;
  122.  
  123. if (m_ulBufferPtr >= ((m_ulFramePtr + 1) * m_ulFrameSize))
  124. {
  125. fSaveFrame = TRUE;
  126. }
  127.  
  128. // Loop the buffer, if we reached the end.
  129. if (m_ulBufferPtr == m_ulBufferSize)
  130. {
  131. fSaveFrame = TRUE;
  132. m_ulBufferPtr = 0;
  133. }
  134.  
  135. if (fSaveFrame)
  136. {
  137. InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulFramePtr]), TRUE );
  138. m_ulFramePtr = (m_ulFramePtr + 1) % m_ulFrameCount;
  139. }
  140.  
  141. // Write the left over if the next frame is available.
  142. if (ulWriteBytes != ulByteCount)
  143. {
  144. KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
  145. if (!m_fFrameUsed[m_ulFramePtr])
  146. {
  147. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  148. RtlCopyMemory
  149. (
  150. m_pDataBuffer + m_ulBufferPtr,
  151. pBuffer + ulWriteBytes,
  152. ulByteCount - ulWriteBytes
  153. );
  154. m_ulBufferPtr += ulByteCount - ulWriteBytes;
  155. }
  156. else
  157. {
  158. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  159. DBG_TRACE("[Frame overflow, next frame is in use]\n\r");
  160.  
  161. }
  162. }
  163.  
  164. }
  165. else
  166. {
  167. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  168. }
  169.  
  170. //TRACE_EXIT();
  171. }
  172.  
  173.  
  174. void CircularBuffer::CopyDataFrom(IN PBYTE pBuffer, IN ULONG ulByteCount)
  175. {
  176. KIRQL kirl;
  177. BOOL fSaveFrame = FALSE;
  178.  
  179. if( 0 == ulByteCount )
  180. {
  181. return;
  182. }
  183.  
  184. KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
  185.  
  186.  
  187. if (m_fFrameUsed[m_ulReadingFrame])
  188. {
  189. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  190.  
  191. ULONG ulWriteBytes = ulByteCount;
  192.  
  193. if( (m_ulBufferSize - m_ulBufferPtr2) < ulWriteBytes )
  194. {
  195. ulWriteBytes = m_ulBufferSize - m_ulBufferPtr2;
  196. }
  197.  
  198. RtlCopyMemory(pBuffer, m_pDataBuffer + m_ulBufferPtr2, ulWriteBytes);
  199.  
  200. m_ulBufferPtr2 += ulWriteBytes;
  201.  
  202. if (m_ulBufferPtr2 >= ((m_ulReadingFrame + 1) * m_ulFrameSize))
  203. {
  204. fSaveFrame = TRUE;
  205. }
  206.  
  207.  
  208. if (m_ulBufferPtr2 == m_ulBufferSize)
  209. {
  210. fSaveFrame = TRUE;
  211. m_ulBufferPtr2 = 0;
  212. }
  213.  
  214. if (fSaveFrame)
  215. {
  216. InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulReadingFrame]), FALSE);
  217. m_ulReadingFrame = (m_ulReadingFrame + 1) % m_ulFrameCount;
  218. }
  219.  
  220. if (ulWriteBytes != ulByteCount)
  221. {
  222. KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
  223. if (m_fFrameUsed[m_ulReadingFrame])
  224. {
  225. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  226. RtlCopyMemory
  227. (
  228. pBuffer,
  229. m_pDataBuffer + m_ulBufferPtr2,
  230. ulByteCount - ulWriteBytes
  231. );
  232. m_ulBufferPtr2 += ulByteCount - ulWriteBytes;
  233. }
  234. else
  235. {
  236. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  237. DBG_TRACE("[Frame overflow, next frame is in use]\n\r");
  238. }
  239. }
  240.  
  241.  
  242. }
  243. else
  244. {
  245. KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
  246. RtlFillMemory(pBuffer, ulByteCount, 0);
  247. }
  248.  
  249.  
  250. }