//CPP文件
#include "WaveRecorder.h"
typedef struct
{
DWORD dwRiff; // Type of file header.
DWORD dwSize; // Size of file header.
DWORD dwWave; // Type of wave.
}RIFF_FILEHEADER,
*PRIFF_FILEHEADER;
//
// 数据块头
//
typedef struct
{
DWORD dwCKID; // Type Identification for current chunk header.
DWORD dwSize; // Size of current chunk header.
}RIFF_CHUNKHEADER,
*PRIFF_CHUNKHEADER;
//
// 块类型
//
#define RIFF_FILE mmioFOURCC('R','I','F','F')
#define RIFF_WAVE mmioFOURCC('W','A','V','E')
#define RIFF_FORMAT mmioFOURCC('f','m','t',' ')
#define RIFF_CHANNEL mmioFOURCC('d','a','t','a')
//
// 定义WAVE录音程序私有数据
//
typedef struct tagRECORDER_HANDLER
{
CWaveRecorder::RECORD_STATE eRecordState; //录音状态
CFile stWaveFile; //录音目标文件句柄
CHAR *pRecordBuffer; //录音目标缓冲地址
DWORD nRecordBufferLength; //录音目标缓冲长度(字节)
DWORD dwRecordedBytesCount; //已录音字节数
DWORD dwMaxRecordTime; //用户限制的最大录音时间
HWAVEIN hWaveIn; //录音设备句柄
WAVEFORMATEX stWaveFormat; //录音格式
WAVEHDR *pWaveInHeaderList; //录音数据采集信息头链
WORD wWaveInBuffersCount; //录音数据采集缓冲个数
WORD wWaveInBufferUsedCount; //已使用的录音数据采集缓冲个数
WaveEndCallback_T *pWaveEndCallback; //录音结束通知回调函数
VOID *pCallbackParam; //录音结束通知回调函数参数(由调用方输入)
}RECORDER_HANDLER,
*PRECORDER_HANDLER;
CWaveRecorder::CWaveRecorder()
{
RECORDER_HANDLER *pRecorder;
m_hPauseProcessThread = NULL;
m_hPostStopThread = NULL;
pRecorder = new RECORDER_HANDLER;
ASSERT(NULL != pRecorder);
memset(&pRecorder->stWaveFormat, 0, sizeof(WAVEFORMATEX));
pRecorder->eRecordState = RS_STOPPED;
pRecorder->pRecordBuffer = NULL;
pRecorder->nRecordBufferLength = 0;
pRecorder->dwRecordedBytesCount = 0;
pRecorder->dwMaxRecordTime = INFINITE; //默认一直录音(仅受磁盘或缓冲容量限制)
pRecorder->hWaveIn = NULL;
pRecorder->pWaveInHeaderList = NULL;
pRecorder->wWaveInBuffersCount = 0;
pRecorder->wWaveInBufferUsedCount = 0;
pRecorder->pWaveEndCallback = NULL;
pRecorder->pCallbackParam = NULL;
m_hRecorder = (HANDLE)pRecorder;
}
CWaveRecorder::~CWaveRecorder()
{
RECORDER_HANDLER *pRecorder;
pRecorder = (RECORDER_HANDLER *)m_hRecorder;
ASSERT(NULL != pRecorder);
//
// 停止录音
//
Stop();
if(NULL != m_hPauseProcessThread)
{
WaitForSingleObject(m_hPauseProcessThread, INFINITE);
CloseHandle(m_hPauseProcessThread);
m_hPauseProcessThread = NULL;
}
//
// 释放WAVE IN缓冲
//
FreeWaveInBuffer();
delete pRecorder;
m_hRecorder = NULL;
}
////////////////////////////////////////////////////////////////////////////////
// 函数名称:Init
// 功能描述:初始化录音环境
//
////////////////////////////////////////////////////////////////////////////////
BOOL CWaveRecorder::Init(
IN WaveEndCallback_T *pWaveEndCallback,
IN VOID *pParam,
IN LPWAVEFORMATEX lpWaveFmt,
OUT INT* pnErrCode
)
{
RECORDER_HANDLER *pRecorder;
MMRESULT hResult;
pRecorder = (RECORDER_HANDLER *)m_hRecorder;
ASSERT(NULL != pRecorder);
//
// 初始化录音环境
//
if(INVALID_HANDLE_VALUE != pRecorder->stWaveFile)
{
pRecorder->stWaveFile.Close();
}
pRecorder->pRecordBuffer = NULL;
pRecorder->nRecordBufferLength = 0;
pRecorder->dwRecordedBytesCount = 0;
pRecorder->pWaveEndCallback = pWaveEndCallback;
pRecorder->pCallbackParam = pParam;
if(NULL != lpWaveFmt)
{
//
// 接受用户WAVE格式参数
//
pRecorder->stWaveFormat = *lpWaveFmt;
}
else
{
//
// 设置默认WAVE格式参数
//
pRecorder->stWaveFormat.cbSize = 0;
pRecorder->stWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
pRecorder->stWaveFormat.wBitsPerSample = 16;
pRecorder->stWaveFormat.nSamplesPerSec = 11025;
pRecorder->stWaveFormat.nChannels = 1;
pRecorder->stWaveFormat.nBlockAlign = pRecorder->stWaveFormat.nChannels
* pRecorder->stWaveFormat.wBitsPerSample
/ 8;
pRecorder->stWaveFormat.nAvgBytesPerSec = pRecorder->stWaveFormat.nBlockAlign
* pRecorder->stWaveFormat.nSamplesPerSec;
}
//
// 分配WAVE IN缓冲
//
FreeWaveInBuffer();
pRecorder->wWaveInBuffersCount = 5;
pRecorder->wWaveInBufferUsedCount = 0;
if(!AllocateWaveInBuffer())
{
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_OUTOFMEMORY;
}
return FALSE;
}
//
// 打开录音设备
//
hResult = ::waveInOpen(
&pRecorder->hWaveIn,
WAVE_MAPPER,
&pRecorder->stWaveFormat,
(DWORD_PTR)OnRecordCallback,
(DWORD_PTR)this,
CALLBACK_FUNCTION
);
if(MMSYSERR_NOERROR != hResult)
{
FreeWaveInBuffer();
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_OPEN_FAILED;
}
return FALSE;
}
pRecorder->eRecordState = RS_STOPPED;
//
// 初始化成功
//
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_SUCCESS;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
// 函数名称:Init
// 功能描述:初始化录音环境(录音保存到指定文件)
//
////////////////////////////////////////////////////////////////////////////////
BOOL CWaveRecorder::Init(
IN const CString &szWaveFile,
IN WaveEndCallback_T *pWaveEndCallback /* = NULL */,
IN VOID *pParam /* = NULL */,
IN LPWAVEFORMATEX lpWaveFmt /* = NULL */,
OUT INT* pnErrCode /* = NULL */
)
{
RECORDER_HANDLER *pRecorder;
pRecorder = (RECORDER_HANDLER *)m_hRecorder;
ASSERT(NULL != pRecorder);
if(!Init(pWaveEndCallback, pParam, lpWaveFmt, pnErrCode))
{
return FALSE;
}
if(0 >= szWaveFile.GetLength())
{
FreeWaveInBuffer();
//
// 无效路径
//
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_BAD_PATHNAME;
}
return FALSE;
}
//
// 创建录音文件
//
if(!pRecorder->stWaveFile.Open(
szWaveFile,
CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite | CFile::typeBinary
))
{
FreeWaveInBuffer();
//
// 创建文件失败
//
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_CREATE_FAILED;
}
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
// 函数名称:Init
// 功能描述:初始化录音环境(录音到内存缓冲)
//
////////////////////////////////////////////////////////////////////////////////
BOOL CWaveRecorder::Init(
IN CHAR *pWaveBuffer,
IN DWORD dwBufferLength,
IN WaveEndCallback_T *pWaveEndCallback /* = NULL */,
IN VOID *pParam /* = NULL */,
IN LPWAVEFORMATEX lpWaveFmt /* = NULL */,
OUT INT* pnErrCode /* = NULL */
)
{
RECORDER_HANDLER *pRecorder;
pRecorder = (RECORDER_HANDLER *)m_hRecorder;
ASSERT(NULL != pRecorder);
if(!Init(pWaveEndCallback, pParam, lpWaveFmt, pnErrCode))
{
return FALSE;
}
if((NULL == pWaveBuffer)
|| (GetBufferSize(10, lpWaveFmt) >= dwBufferLength) //缓冲区不够录10毫秒视为无效
)
{
FreeWaveInBuffer();
//
// 无效缓冲
//
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_INVALID_USER_BUFFER;
}
return FALSE;
}
pRecorder->pRecordBuffer = pWaveBuffer;
pRecorder->nRecordBufferLength = dwBufferLength;
//
// 初始化成功
//
if(NULL != pnErrCode)
{
*pnErrCode = ERROR_SUCCESS;
}
return TRUE;
}