📄 wavethread.cpp
字号:
// CWaveInThread.cpp : implementation file
//
#include "stdafx.h"
#include "WaveThread.h"
/////////////////////////////////////////////////////////////////////////////
// CWaveInThread thread
CWaveInThread::CWaveInThread()
{
m_pcbWaveIn = NULL;
m_bInitialized = FALSE;
m_threadId = 0;
m_thread = NULL;
m_hWaveIn = NULL;
m_pWaveInBuffer = NULL;
m_pWaveCopyBuffer = NULL;
m_pWaveHeaderArray = NULL;
m_dwActiveThreadPriority = THREAD_PRIORITY_NORMAL;
m_wBufferCount = 0;
m_dwSingleBufferSize = 0;
m_dwBufferSize = 0;
m_dwCopyBufferBytes = 0;
m_pCopyBufferPos = NULL;
m_bPause = FALSE;
ZeroMemory(&m_wfx, sizeof(m_wfx));
InitializeCriticalSection(&m_critSecRtp);
m_hEventKill = CreateEvent(NULL, FALSE, FALSE, NULL);
}
CWaveInThread::~CWaveInThread()
{
// Stop the thread processing
StopThread();
// Delete the critical section
DeleteCriticalSection(&m_critSecRtp);
// Destroy events
CloseHandle(m_hEventKill);
}
// Capture initialization
BOOL CWaveInThread::Init(cbWaveIn pcbWaveIn, // Callback function for event notifications, NULL = No callback!
DWORD dwActiveThreadPriority, // Thread Priority for this thread, if capturing is active
WORD wBufferCount, // Count of buffers to use
DWORD dwSingleBufferSize, // Size of a single buffer in bytes (eg. 8000Hz Mono 16bit: 10ms = 160bytes)
WORD wChannels, // Mono = 1; Stereo = 2
DWORD dwSamplesPerSec, // 8000Hz/11025Hz/22050Hz/44100Hz
WORD wBitsPerSample) // 8bit/16bit
{
if (
( m_bInitialized
) ||
( dwActiveThreadPriority > THREAD_PRIORITY_IDLE
) ||
( wBufferCount < INTERNAL_WAVEOUT_BUFFER_COUNT
) ||
( dwSingleBufferSize < 80
) ||
( wChannels < 1
) ||
( wChannels > 2
) ||
(
( wBitsPerSample != 8
) &&
( wBitsPerSample != 16
)
) ||
(
( dwSamplesPerSec != 8000
) &&
( dwSamplesPerSec != 11025
) &&
( dwSamplesPerSec != 22050
) &&
( dwSamplesPerSec != 44100
)
)
)
{
return FALSE;
}
m_pcbWaveIn = pcbWaveIn;
m_dwActiveThreadPriority = dwActiveThreadPriority;
m_wBufferCount = wBufferCount;
m_dwSingleBufferSize = dwSingleBufferSize;
m_wfx.cbSize = 0;
m_wfx.wFormatTag = WAVE_FORMAT_PCM;
m_wfx.nChannels = wChannels;
m_wfx.nSamplesPerSec = dwSamplesPerSec;
m_wfx.nBlockAlign = (wBitsPerSample * wChannels) / 8;
m_wfx.nAvgBytesPerSec = dwSamplesPerSec * m_wfx.nBlockAlign;
m_wfx.wBitsPerSample = wBitsPerSample;
m_dwBufferSize = wBufferCount * dwSingleBufferSize;
m_bInitialized = TRUE;
return TRUE;
}
// Start capturing
BOOL CWaveInThread::StartThread()
{
UINT id;
WORD i;
if ((m_thread) || (!m_bInitialized))
{
return FALSE;
}
// Start the thread
m_thread = CreateThread(NULL,
0,
ThreadProc,
(void*)this,
0,
&m_threadId);
if (m_thread)
{
DWORD dwExitCode;
if (GetExitCodeThread(m_thread, &dwExitCode))
{
if (dwExitCode != STILL_ACTIVE)
{
return FALSE;
}
}
if (m_hWaveIn == NULL)
{
m_pWaveInBuffer = new unsigned char[m_dwBufferSize];
if (m_pWaveInBuffer)
{
ZeroMemory(m_pWaveInBuffer, m_dwBufferSize);
m_pWaveCopyBuffer = new unsigned char[m_dwBufferSize];
if (m_pWaveCopyBuffer)
{
ZeroMemory(m_pWaveCopyBuffer, m_dwBufferSize);
m_pWaveHeaderArray = new WAVEHDR[m_wBufferCount];
if (m_pWaveHeaderArray)
{
ZeroMemory(m_pWaveHeaderArray, m_wBufferCount * sizeof(WAVEHDR));
for (id = 0; id < waveInGetNumDevs(); id++)
{
if (waveInOpen(&m_hWaveIn, id, &m_wfx, m_threadId, (DWORD)this, CALLBACK_THREAD) == MMSYSERR_NOERROR)
{
for (i=0 ; i<m_wBufferCount ; i++)
{
m_pWaveHeaderArray[i].dwBufferLength = m_dwSingleBufferSize;
m_pWaveHeaderArray[i].lpData = (char*)m_pWaveInBuffer + i * m_dwSingleBufferSize;
m_pWaveHeaderArray[i].dwUser = i;
waveInPrepareHeader(m_hWaveIn, &m_pWaveHeaderArray[i], sizeof(WAVEHDR));
waveInAddBuffer(m_hWaveIn, &m_pWaveHeaderArray[i], sizeof(WAVEHDR));
}
ResetBuffer();
SetThreadPriority(m_thread, m_dwActiveThreadPriority);
m_bPause = FALSE;
waveInStart(m_hWaveIn);
return TRUE;
}
}
}
delete m_pWaveCopyBuffer;
m_pWaveCopyBuffer = NULL;
}
delete m_pWaveInBuffer;
m_pWaveInBuffer = NULL;
}
}
}
StopThread();
return FALSE;
}
// Stop capturing
BOOL CWaveInThread::StopThread()
{
WORD i;
if (m_thread == NULL)
{
return FALSE;
}
SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
SetEvent(m_hEventKill);
if (m_hWaveIn)
{
waveInStop(m_hWaveIn);
}
// This is ugly, wait for 10 seconds, then kill the thread
DWORD res = WaitForSingleObject(m_thread, 10000);
if (res == WAIT_TIMEOUT)
{
if (m_thread)
{
// OK, do it the hard way
TerminateThread(m_thread, 0);
CloseHandle(m_thread);
m_thread = NULL;
}
}
if (m_hWaveIn)
{
waveInReset(m_hWaveIn);
if (m_pWaveHeaderArray)
{
for (i=0 ; i<m_wBufferCount ; i++)
{
waveInUnprepareHeader(m_hWaveIn, &m_pWaveHeaderArray[i], sizeof(WAVEHDR));
}
}
waveInClose(m_hWaveIn);
m_hWaveIn = NULL;
}
if (m_pWaveInBuffer)
{
delete m_pWaveInBuffer;
m_pWaveInBuffer = NULL;
}
if (m_pWaveCopyBuffer)
{
delete m_pWaveCopyBuffer;
m_pWaveCopyBuffer = NULL;
}
if (m_pWaveHeaderArray)
{
delete m_pWaveHeaderArray;
m_pWaveHeaderArray = NULL;
}
return TRUE;
}
// Clear the buffer
void CWaveInThread::ResetBuffer()
{
EnterCriticalSection(&m_critSecRtp);
m_pCopyBufferPos = NULL;
if (m_bPause)
{
SetThreadPriority(m_thread, m_dwActiveThreadPriority);
waveInStart(m_hWaveIn);
m_bPause = FALSE;
}
LeaveCriticalSection(&m_critSecRtp);
}
// Get the size of the needed buffer for one second of data
DWORD CWaveInThread::GetBytesPerSecond()
{
if (m_bInitialized)
{
return m_wfx.nAvgBytesPerSec;
}
return 0;
}
// Get the current length of data in the buffer
DWORD CWaveInThread::GetDataLen()
{
DWORD dwBytes;
EnterCriticalSection(&m_critSecRtp);
dwBytes = m_dwCopyBufferBytes;
LeaveCriticalSection(&m_critSecRtp);
return dwBytes;
}
// Get captured data
BOOL CWaveInThread::ReadData(unsigned char* pBuffer, // Data will be copied into the buffer
DWORD dwCount) // Count of bytes to copy
{
EnterCriticalSection(&m_critSecRtp);
if (
( pBuffer == NULL
) ||
( m_pCopyBufferPos == NULL
) ||
( m_dwCopyBufferBytes < dwCount
)
)
{
LeaveCriticalSection(&m_critSecRtp);
return FALSE;
}
if (m_pCopyBufferPos + dwCount > m_pWaveCopyBuffer + m_dwBufferSize)
{
memcpy(pBuffer,
m_pCopyBufferPos,
m_pWaveCopyBuffer + m_dwBufferSize - m_pCopyBufferPos);
pBuffer += m_pWaveCopyBuffer + m_dwBufferSize - m_pCopyBufferPos;
memcpy(pBuffer,
m_pWaveCopyBuffer,
m_pCopyBufferPos + dwCount - (m_pWaveCopyBuffer + m_dwBufferSize));
m_pCopyBufferPos = m_pWaveCopyBuffer + ((m_pCopyBufferPos + dwCount) - (m_pWaveCopyBuffer + m_dwBufferSize));
}
else
{
memcpy(pBuffer, m_pCopyBufferPos, dwCount);
m_pCopyBufferPos += dwCount;
}
m_dwCopyBufferBytes -= dwCount;
if ((m_bPause) && (m_dwCopyBufferBytes + (m_dwBufferSize / m_wBufferCount) <= m_dwBufferSize))
{
SetThreadPriority(m_thread, m_dwActiveThreadPriority);
waveInStart(m_hWaveIn);
m_bPause = FALSE;
}
LeaveCriticalSection(&m_critSecRtp);
return TRUE;
}
// Handles MM-API for capturing
DWORD WINAPI CWaveInThread::ThreadProc(LPVOID lpParameter)
{
CWaveInThread* pWaveIn = (CWaveInThread*)lpParameter;
MSG msg;
DWORD dwWait = 0;
DWORD dwUser = 0;
WAVEHDR *pWaveHdr = NULL;
WAVE_IN_EVENT event;
if (pWaveIn == NULL)
{
return -1;
}
while ((dwWait = WaitForSingleObject(pWaveIn->m_hEventKill, 5)) != 0)
{
// Handle MMAPI wave capturing thread messages
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
switch (msg.message)
{
case MM_WIM_DATA:
EnterCriticalSection(&pWaveIn->m_critSecRtp);
event = WAVE_IN_EVENT_NONE;
pWaveHdr = (WAVEHDR*)msg.lParam;
// Unprepare header, initialize with the next buffer position, prepare the header
// again and add it to the wave capture device.
if (pWaveHdr)
{
waveInUnprepareHeader(pWaveIn->m_hWaveIn, pWaveHdr, sizeof(WAVEHDR));
dwUser = pWaveHdr->dwUser;
if (pWaveIn->m_pCopyBufferPos == 0)
{
pWaveIn->m_pCopyBufferPos = pWaveIn->m_pWaveCopyBuffer + dwUser * pWaveHdr->dwBufferLength;
pWaveIn->m_dwCopyBufferBytes = 0;
}
if (pWaveIn->m_dwCopyBufferBytes + pWaveHdr->dwBufferLength <= pWaveIn->m_dwBufferSize)
{
memcpy((char*)pWaveIn->m_pWaveCopyBuffer + dwUser * pWaveHdr->dwBufferLength, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded);
if (pWaveHdr->dwBytesRecorded != pWaveHdr->dwBufferLength)
{
ZeroMemory(pWaveHdr->lpData + pWaveHdr->dwBytesRecorded, pWaveHdr->dwBufferLength - pWaveHdr->dwBytesRecorded);
}
pWaveIn->m_dwCopyBufferBytes += pWaveHdr->dwBufferLength;
event = WAVE_IN_EVENT_NEW_BUFFER;
}
else
{
SetThreadPriority(pWaveIn->m_thread, THREAD_PRIORITY_NORMAL);
waveInStop(pWaveIn->m_hWaveIn);
pWaveIn->m_bPause = TRUE;
event = WAVE_IN_EVENT_BUFFER_FULL;
}
ZeroMemory(pWaveHdr, sizeof(WAVEHDR));
pWaveHdr->dwBufferLength = pWaveIn->m_dwSingleBufferSize;
pWaveHdr->lpData = (char*)pWaveIn->m_pWaveInBuffer + dwUser * pWaveIn->m_dwSingleBufferSize;
pWaveHdr->dwUser = dwUser;
waveInPrepareHeader(pWaveIn->m_hWaveIn, pWaveHdr, sizeof(WAVEHDR));
waveInAddBuffer(pWaveIn->m_hWaveIn, pWaveHdr, sizeof(WAVEHDR));
}
LeaveCriticalSection(&pWaveIn->m_critSecRtp);
if ((pWaveIn->m_pcbWaveIn != NULL) && (event != WAVE_IN_EVENT_NONE))
{
(pWaveIn->m_pcbWaveIn)(event);
}
break;
default:
break;
}
}
}
CloseHandle(pWaveIn->m_thread);
pWaveIn->m_thread = NULL;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CWaveOutThread thread
CWaveOutThread::CWaveOutThread()
{
m_pcbWaveOut = NULL;
m_bInitialized = FALSE;
m_threadId = 0;
m_thread = NULL;
m_hWaveOut = NULL;
m_pWaveOutBuffer = NULL;
m_pWaveCopyBuffer = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -