#include "stdafx.h"
#include "kinectaudiostream.h"
#include <stdio.h>
KinectAudioStream::KinectAudioStream(IMediaObject *pKinectDmo) :
m_cRef(1),
m_CurrentWriteBuffer(
NULL),
m_CurrentReadBuffer(
NULL),
m_CurrentReadBufferIndex(0),
m_BytesRead(0),
{
pKinectDmo->AddRef();
m_pKinectDmo = pKinectDmo;
InitializeCriticalSection(&m_Lock);
}
KinectAudioStream::~KinectAudioStream()
{
SafeRelease(m_pKinectDmo);
DeleteCriticalSection(&m_Lock);
}
HRESULT KinectAudioStream::StartCapture()
{
HRESULT hr = S_OK;
m_hStopEvent = CreateEvent(
NULL, TRUE, FALSE,
NULL );
m_hDataReady = CreateEvent(
NULL, FALSE, FALSE,
NULL );
m_BytesRead = 0;
for (UINT
i = 0;
i < NumBuffers;
i++)
{
CStaticMediaBuffer *pBuf = new CStaticMediaBuffer();
m_BufferPool.push(pBuf);
}
m_CurrentWriteBuffer =
NULL;
m_hCaptureThread = CreateThread(
NULL, 0, CaptureThread,
this, 0,
NULL);
return hr;
}
HRESULT KinectAudioStream::StopCapture()
{
HRESULT hr = S_OK;
if (
NULL != m_hStopEvent )
{
SetEvent(m_hStopEvent);
if (
NULL != m_hCaptureThread )
{
WaitForSingleObject( m_hCaptureThread, INFINITE );
CloseHandle( m_hCaptureThread );
}
CloseHandle( m_hStopEvent );
}
if (
NULL != m_hDataReady)
{
SetEvent(m_hDataReady);
CloseHandle(m_hDataReady);
}
ReleaseAllBuffers();
while (!m_BufferPool.empty())
{
CStaticMediaBuffer* mediaBuffer = m_BufferPool.top();
delete mediaBuffer;
m_BufferPool.pop();
}
return hr;
}
STDMETHODIMP KinectAudioStream::Read(void *pBuffer, ULONG cbBuffer, ULONG *pcbRead)
{
HRESULT hr = S_OK;
{
return E_INVALIDARG;
}
ULONG bytesPendingToRead = cbBuffer;
while (bytesPendingToRead > 0 && IsCapturing())
{
ReadOneBuffer((
BYTE**)&pBuffer, &bytesPendingToRead);
if (
NULL == m_CurrentReadBuffer)
{
WaitForSingleObject(m_hDataReady, INFINITE);
}
}
ULONG bytesRead = cbBuffer - bytesPendingToRead;
m_BytesRead += bytesRead;
*pcbRead = bytesRead;
return hr;
}
STDMETHODIMP KinectAudioStream::Write(const void *,ULONG,ULONG *)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition )
{
dwOrigin = dwOrigin;
if (plibNewPosition !=
NULL)
{
plibNewPosition->QuadPart = m_BytesRead + dlibMove.QuadPart;
}
return S_OK;
}
STDMETHODIMP KinectAudioStream::SetSize(ULARGE_INTEGER)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::CopyTo(IStream *,ULARGE_INTEGER,ULARGE_INTEGER *,ULARGE_INTEGER *)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::Commit(DWORD)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::Revert()
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::LockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::UnlockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::Stat(STATSTG *,DWORD)
{
return E_NOTIMPL;
}
STDMETHODIMP KinectAudioStream::Clone(IStream **)
{
return E_NOTIMPL;
}
CStaticMediaBuffer *KinectAudioStream::GetWriteBuffer()
{
CStaticMediaBuffer *pBuf =
NULL;
EnterCriticalSection(&m_Lock);
if (m_BufferPool.size() > 0)
{
pBuf = m_BufferPool.top();
m_BufferPool.pop();
pBuf->SetLength(0);
}
else if (m_ReadBufferQueue.size() > 0)
{
pBuf = m_ReadBufferQueue.front();
m_ReadBufferQueue.pop();
pBuf->SetLength(0);
}
LeaveCriticalSection(&m_Lock);
return pBuf;
}
void KinectAudioStream::ReleaseBuffer(CStaticMediaBuffer* pBuffer)
{
{
EnterCriticalSection(&m_Lock);
pBuffer->SetLength(0);
m_BufferPool.push(pBuffer);
LeaveCriticalSection(&m_Lock);
}
}
void KinectAudioStream::ReleaseAllBuffers()
{
EnterCriticalSection(&m_Lock);
while (m_ReadBufferQueue.size() > 0)
{
CStaticMediaBuffer *pBuf = m_ReadBufferQueue.front();
m_ReadBufferQueue.pop();
ReleaseBuffer(pBuf);
}
if (m_CurrentReadBuffer !=
NULL)
{
ReleaseBuffer(m_CurrentReadBuffer);
}
m_CurrentReadBufferIndex = 0;
m_CurrentReadBuffer =
NULL;
LeaveCriticalSection(&m_Lock);
}
void KinectAudioStream::QueueCapturedData(
BYTE *pData, UINT cbData)
{
DWORD cbWriteData = 0;
DWORD cbMaxLength = 0;
if (cbData <= 0)
{
return;
}
if (
NULL == m_CurrentWriteBuffer)
{
m_CurrentWriteBuffer = GetWriteBuffer();
}
m_CurrentWriteBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
m_CurrentWriteBuffer->GetMaxLength(&cbMaxLength);
if (cbWriteData + cbData < cbMaxLength)
{
memcpy(pWriteData + cbWriteData, pData, cbData);
m_CurrentWriteBuffer->SetLength(cbWriteData + cbData);
}
else
{
QueueCapturedBuffer(m_CurrentWriteBuffer);
m_CurrentWriteBuffer = GetWriteBuffer();
m_CurrentWriteBuffer->GetBufferAndLength(&pWriteData, &cbWriteData);
memcpy(pWriteData, pData, cbData);
m_CurrentWriteBuffer->SetLength(cbData);
}
}
void KinectAudioStream::QueueCapturedBuffer(CStaticMediaBuffer *pBuffer)
{
EnterCriticalSection(&m_Lock);
m_ReadBufferQueue.push(pBuffer);
SetEvent(m_hDataReady);
LeaveCriticalSection(&m_Lock);
}
void KinectAudioStream::ReadOneBuffer(
BYTE **ppbData, ULONG* pcbData)
{
EnterCriticalSection(&m_Lock);
if (m_CurrentReadBuffer ==
NULL)
{
if(m_ReadBufferQueue.size() != 0)
{
m_CurrentReadBuffer = m_ReadBufferQueue.front();
m_ReadBufferQueue.pop();
}
}
if (m_CurrentReadBuffer !=
NULL)
{
DWORD dwDataLength = 0;
m_CurrentReadBuffer->GetBufferAndLength(&pData, &dwDataLength);
ULONG cbToCopy = min(dwDataLength - m_CurrentReadBufferIndex, *pcbData);
memcpy(*ppbData, pData + m_CurrentReadBufferIndex, cbToCopy);
*ppbData = (*ppbData)+cbToCopy;
*pcbData = (*pcbData)-cbToCopy;
m_CurrentReadBufferIndex += cbToCopy;
if (m_CurrentReadBufferIndex >= dwDataLength)
{
ReleaseBuffer(m_CurrentReadBuffer);
m_CurrentReadBuffer =
NULL;
m_CurrentReadBufferIndex = 0;
if(m_ReadBufferQueue.size() != 0)
{
m_CurrentReadBuffer = m_ReadBufferQueue.front();
m_ReadBufferQueue.pop();
}
}
}
LeaveCriticalSection(&m_Lock);
}
DWORD WINAPI KinectAudioStream::CaptureThread(LPVOID pParam)
{
KinectAudioStream *pthis = (KinectAudioStream *) pParam;
return pthis->CaptureThread();
}
DWORD WINAPI KinectAudioStream::CaptureThread()
{
DWORD mmTaskIndex = 0;
HRESULT hr = S_OK;
bool bContinue = true;
CStaticMediaBuffer outputBuffer;
DMO_OUTPUT_DATA_BUFFER OutputBufferStruct = {0};
OutputBufferStruct.pBuffer = &outputBuffer;
DWORD dwStatus = 0;
ULONG cbProduced = 0;
mmHandle = AvSetMmThreadCharacteristics(L"Audio", &mmTaskIndex);
while (bContinue)
{
if (WaitForSingleObject(m_hStopEvent, 0) == WAIT_OBJECT_0)
{
bContinue = false;
continue;
}
do
{
outputBuffer.Init(0);
OutputBufferStruct.dwStatus = 0;
hr = m_pKinectDmo->ProcessOutput(0, 1, &OutputBufferStruct, &dwStatus);
if (FAILED(hr))
{
bContinue = false;
break;
}
if (hr == S_FALSE)
{
cbProduced = 0;
}
else
{
outputBuffer.GetBufferAndLength(&pbOutputBuffer, &cbProduced);
}
if (cbProduced > 0)
{
QueueCapturedData(pbOutputBuffer, cbProduced);
}
} while (OutputBufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE);
Sleep(10);
}
SetEvent(m_hDataReady);
AvRevertMmThreadCharacteristics(mmHandle);
if (FAILED(hr))
{
return 0;
}
return 1;
}