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

#include "cbuffer.h"
#include "debug.h"
#include

#define DEFAULT_FRAME_COUNT 2
#define DEFAULT_FRAME_SIZE PAGE_SIZE * 4
#define DEFAULT_BUFFER_SIZE DEFAULT_FRAME_SIZE * DEFAULT_FRAME_COUNT

CircularBuffer::CircularBuffer(void) :
m_ulFrameCount(DEFAULT_FRAME_COUNT),
m_ulBufferSize(DEFAULT_BUFFER_SIZE),
m_ulFrameSize(DEFAULT_FRAME_SIZE),
m_pDataBuffer(NULL),
m_ulReadingFrame(0),
m_ulFramePtr(0),
m_ulBufferPtr(0),
m_fFrameUsed(NULL),
m_ulBufferPtr2(0)

{
TRACE_ENTER();
TRACE_EXIT();
}

NTSTATUS CircularBuffer::Initialize(void)
{

TRACE_ENTER();

NTSTATUS ntStatus = STATUS_SUCCESS;

KeInitializeSpinLock ( &m_FrameInUseSpinLock ) ;

m_pDataBuffer = (PBYTE)
ExAllocatePoolWithTag
(
NonPagedPool,
m_ulBufferSize,
MSVAD_POOLTAG
);

if (!m_pDataBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
return ntStatus;
}

RtlZeroMemory(m_pDataBuffer, m_ulBufferSize);

m_fFrameUsed = (PBOOL)
ExAllocatePoolWithTag
(
NonPagedPool,
m_ulFrameCount * sizeof(BOOL),
MSVAD_POOLTAG
);

if (!m_fFrameUsed)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;

if (m_pDataBuffer)
ExFreePoolWithTag(m_pDataBuffer, MSVAD_POOLTAG);

return ntStatus;
}

RtlZeroMemory(m_fFrameUsed, m_ulFrameCount * sizeof(BOOL));

TRACE_EXIT();
return ntStatus;
}
CircularBuffer::~CircularBuffer(void)
{
TRACE_ENTER();

if (m_pDataBuffer)
{
ExFreePoolWithTag(m_pDataBuffer, MSVAD_POOLTAG);
}

if (m_fFrameUsed)
{
ExFreePoolWithTag(m_fFrameUsed, MSVAD_POOLTAG);
// NOTE : Do not release m_pFilePtr.
}

TRACE_EXIT();
}

void CircularBuffer::CopyDataTo(IN PBYTE pBuffer, IN ULONG ulByteCount)
{
KIRQL kirl;

BOOL fSaveFrame = FALSE;

if (m_fWriteDisabled)
{
return;
}

if( 0 == ulByteCount )
{
return;
}

KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
if (!m_fFrameUsed[m_ulFramePtr])
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);

ULONG ulWriteBytes = ulByteCount;

if( (m_ulBufferSize - m_ulBufferPtr) < ulWriteBytes )
{
ulWriteBytes = m_ulBufferSize - m_ulBufferPtr;
}

RtlCopyMemory(m_pDataBuffer + m_ulBufferPtr, pBuffer, ulWriteBytes);

m_ulBufferPtr += ulWriteBytes;

if (m_ulBufferPtr >= ((m_ulFramePtr + 1) * m_ulFrameSize))
{
fSaveFrame = TRUE;
}

// Loop the buffer, if we reached the end.
if (m_ulBufferPtr == m_ulBufferSize)
{
fSaveFrame = TRUE;
m_ulBufferPtr = 0;
}

if (fSaveFrame)
{
InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulFramePtr]), TRUE );
m_ulFramePtr = (m_ulFramePtr + 1) % m_ulFrameCount;
}

// Write the left over if the next frame is available.
if (ulWriteBytes != ulByteCount)
{
KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
if (!m_fFrameUsed[m_ulFramePtr])
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
RtlCopyMemory
(
m_pDataBuffer + m_ulBufferPtr,
pBuffer + ulWriteBytes,
ulByteCount - ulWriteBytes
);
m_ulBufferPtr += ulByteCount - ulWriteBytes;
}
else
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
DBG_TRACE("[Frame overflow, next frame is in use]\n\r");

}
}

}
else
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
}

//TRACE_EXIT();
}

void CircularBuffer::CopyDataFrom(IN PBYTE pBuffer, IN ULONG ulByteCount)
{
KIRQL kirl;
BOOL fSaveFrame = FALSE;

if( 0 == ulByteCount )
{
return;
}

KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);

if (m_fFrameUsed[m_ulReadingFrame])
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);

ULONG ulWriteBytes = ulByteCount;

if( (m_ulBufferSize - m_ulBufferPtr2) < ulWriteBytes )
{
ulWriteBytes = m_ulBufferSize - m_ulBufferPtr2;
}

RtlCopyMemory(pBuffer, m_pDataBuffer + m_ulBufferPtr2, ulWriteBytes);

m_ulBufferPtr2 += ulWriteBytes;

if (m_ulBufferPtr2 >= ((m_ulReadingFrame + 1) * m_ulFrameSize))
{
fSaveFrame = TRUE;
}

if (m_ulBufferPtr2 == m_ulBufferSize)
{
fSaveFrame = TRUE;
m_ulBufferPtr2 = 0;
}

if (fSaveFrame)
{
InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulReadingFrame]), FALSE);
m_ulReadingFrame = (m_ulReadingFrame + 1) % m_ulFrameCount;
}

if (ulWriteBytes != ulByteCount)
{
KeAcquireSpinLock(&m_FrameInUseSpinLock, &kirl);
if (m_fFrameUsed[m_ulReadingFrame])
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
RtlCopyMemory
(
pBuffer,
m_pDataBuffer + m_ulBufferPtr2,
ulByteCount - ulWriteBytes
);
m_ulBufferPtr2 += ulByteCount - ulWriteBytes;
}
else
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
DBG_TRACE("[Frame overflow, next frame is in use]\n\r");
}
}

}
else
{
KeReleaseSpinLock( &m_FrameInUseSpinLock, kirl);
RtlFillMemory(pBuffer, ulByteCount, 0);
}

}