音频播放和录制检测

#ifndef __WWAVEHELPER_H__
#define __WWAVEHELPER_H__

#if !WINDOWS_SYSTEM
#error only windows system supported
#endif

#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

#include "uiHelper.h"

class UIHELPER_EXPORT wWaveHelper
{
public:
/************************playback about***************/
static int GetPlaybackDevicesCounts();
static int GetPlaybackIDByName(const chConstString& strDevName);
static chStringA GetPalybackNameByID(int nID);

/************************Record About*****************/
static int GetRecordDevicesCounts();
static int GetRecordIDByName(const chConstString& strDevName);
static chStringA GetRecordNameByID(int nID);
public:
wWaveHelper();
~wWaveHelper();
};

class UIHELPER_EXPORT wMixerCtrl
{
public:
BOOL OpenMixer(int iIndex);
BOOL OpenMixer(const chConstString& strAudioName);
void CloseMixer();
//volum just can get special metrics of an audio line
int GetPlaybackVolum();
int GetCaptureVolum();
BOOL SetPlaybackVolum(int nValue);
BOOL SetCaptureVolum(int nValue);
//mute
bool GetMasterVolumeMute();
bool SetMasterVolumeMute(bool bMute);
bool GetWaveVolumeMute();
bool SetWaveVolumeMute(bool bMute);
private:
int GetVolum(int nType);
BOOL SetVolum(int nType, int nValue);

BOOL GetMute(int nType);
BOOL SetMute(int nType, BOOL bMute);
public:
wMixerCtrl();
wMixerCtrl(int iIndex);
wMixerCtrl(const chConstString& strAudioName);
~wMixerCtrl();
public:
HMIXER m_hMixer;
};

class UIHELPER_EXPORT wWavePlayer
{
public:
bool wavePlayStart(UINT idDev, const chConstString& strFilePath);
void wavePlayStop();
int getCurrentSample();
public:
wWavePlayer();
~wWavePlayer();
private:
HWAVEOUT m_hWaveOut;
chByteArray m_dataWaveFile;
WAVEHDR m_hdrWaveData;
public:
UINT64 m_tickStart;
};

class CWaveIn;
class UIHELPER_EXPORT wWaveRecord :public chCriticalSection
{
public:
bool waveRecordStart(UINT idDev);
void waveRecordStop();
int getCurrentSample();
public:
wWaveRecord();
~wWaveRecord();
public:
bool m_bRecording;//停止标志,因为这里在WIM_DATA 是不断AddBuff,要靠其它变量去控制,停止
HWAVEIN m_hWaveIn;
private:
WAVEHDR m_hdrWaveData[2];
chByteArray m_dataWaveIn;
UINT64 m_tickStart;
CWaveIn* m_pWaveInThread;
};


#endif //__WWAVEHELPER_H__

#include "ETLLib/ETLLib.hpp"
#include "wWaveHelper.h"
#define THIS_MODULE "wWaveHelper"

int wWaveHelper::GetPlaybackDevicesCounts()
{
return ::waveOutGetNumDevs();
}

int wWaveHelper::GetPlaybackIDByName(const chConstString& strDevName)
{
chASSERT(!strDevName.empty());
chStringW strDevNameW = chUTF82W(strDevName);
WAVEOUTCAPSW outcaps;
int nCount = ::waveOutGetNumDevs();
for(int uOutId = 0; uOutId < nCount; uOutId++)
{
if (::waveOutGetDevCapsW(uOutId, &outcaps, sizeof(outcaps)) == MMSYSERR_NOERROR)
{
if(strDevNameW == outcaps.szPname)
{
return uOutId;
}
}
}
return WAVE_MAPPER;
}

chStringA wWaveHelper::GetPalybackNameByID(int nID)
{
chASSERT(nID >= -1);
WAVEOUTCAPSW outcaps;
if (::waveOutGetDevCapsW(nID, &outcaps, sizeof(WAVEOUTCAPSW)) != MMSYSERR_NOERROR)
{
return NULL;
}
return chW2UTF8(outcaps.szPname);
}

int wWaveHelper::GetRecordDevicesCounts()
{
return ::waveInGetNumDevs();
}

int wWaveHelper::GetRecordIDByName(const chConstString& strDevName)
{
chASSERT(!strDevName.empty());
chStringW strDevNameW = chUTF82W(strDevName);
WAVEINCAPSW incaps;
int nCount = ::waveInGetNumDevs();
for(int uInId = 0; uInId < nCount; uInId++)
{
if (::waveInGetDevCapsW(uInId, &incaps, sizeof(incaps)) == MMSYSERR_NOERROR )
{
if(strDevNameW == incaps.szPname)
{
return uInId;
}
}
}
return WAVE_MAPPER;
}

chStringA wWaveHelper::GetRecordNameByID(int nID)
{
chASSERT(nID >= -1);
WAVEINCAPSW incaps;
if (::waveInGetDevCapsW(nID, &incaps, sizeof(incaps)) != MMSYSERR_NOERROR)
{
return NULL;
}
return chW2UTF8(incaps.szPname);
}

wWaveHelper::wWaveHelper()
{

}

wWaveHelper::~wWaveHelper()
{

}


static int GetAudioIDByName(const chConstString& strDevName)
{
chASSERT(!strDevName.empty());
chStringW strDevNameW = chUTF82W(strDevName);
MIXERCAPSW mixCaps;
int nNumMixers = ::mixerGetNumDevs();
for(int uMxId = 0; uMxId < nNumMixers; uMxId++)
{
if (::mixerGetDevCapsW(uMxId, &mixCaps, sizeof(mixCaps)) == MMSYSERR_NOERROR)
{
if(strDevNameW == mixCaps.szPname)
{
return uMxId;
}
}
}
return WAVE_MAPPER;
}


BOOL wMixerCtrl::OpenMixer(int iIndex)
{
chASSERT(iIndex >= 0);
chASSERT(m_hMixer == NULL);
if (::mixerGetNumDevs() == 0)
{
return FALSE;
}
mixerOpen(&m_hMixer, iIndex, 0, 0, CALLBACK_NULL);
chASSERT(m_hMixer != NULL);
//SYZ_TRACE("OpenMixer : %d - %X", iIndex, m_hMixer);
return TRUE;
}

BOOL wMixerCtrl::OpenMixer(const chConstString& strAudioName)
{
int iIndex = GetAudioIDByName(strAudioName);
return OpenMixer(iIndex);
}

void wMixerCtrl::CloseMixer()
{
if(m_hMixer != NULL)
{
mixerClose(m_hMixer);
m_hMixer = NULL;
}
}

int wMixerCtrl::GetVolum(int nType)
{
chASSERT(m_hMixer != NULL);
// Get the line info for the wave in destination line
MIXERLINE mxl;
mxl.cbStruct = sizeof(mxl);
mxl.dwComponentType = nType;
mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE);

// Find a volume control, if any, of the microphone line
MIXERCONTROL mxctrl = {0};
MIXERLINECONTROLS mxlctrl =
{
sizeof mxlctrl, mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME,
1, sizeof MIXERCONTROL, &mxctrl
};

int uVal = 0;
if(mixerGetLineControls((HMIXEROBJ) m_hMixer, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
// Found!
int cChannels = mxl.cChannels;
if (MIXERCONTROL_CONTROLF_UNIFORM & mxctrl.fdwControl)
cChannels = 1;
chASSERT(cChannels > 0);
chSimpleArray<MIXERCONTROLDETAILS_UNSIGNED> valArray(cChannels);

MIXERCONTROLDETAILS mxcd = {sizeof(mxcd), mxctrl.dwControlID,
cChannels, (HWND)0,
sizeof MIXERCONTROLDETAILS_UNSIGNED, (MIXERCONTROLDETAILS_UNSIGNED*)valArray};

mixerGetControlDetails((HMIXEROBJ)m_hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
double dVolTotal = 0;
for(int i = 0; i < cChannels; i++)
dVolTotal += valArray[i].dwValue;
uVal = (int)(dVolTotal / cChannels);
}
//SYZ_TRACE("GetVolume : %d-%X", nType, uVal);
return uVal;
}


int wMixerCtrl::GetPlaybackVolum()
{
return GetVolum(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT);
}

int wMixerCtrl::GetCaptureVolum()
{
return GetVolum(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
}

BOOL wMixerCtrl::SetVolum(int nType, int nValue)
{
chASSERT(m_hMixer != NULL);
// Get the line info for the wave in destination line
MIXERLINE mxl;
mxl.cbStruct = sizeof(mxl);
mxl.dwComponentType = nType;
mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE);

// Find a volume control, if any, of the microphone line
MIXERCONTROL mxctrl = {0};
MIXERLINECONTROLS mxlctrl =
{
sizeof mxlctrl, mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME,
1, sizeof MIXERCONTROL, &mxctrl
};

if(mixerGetLineControls((HMIXEROBJ) m_hMixer, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
// Found!
int cChannels = mxl.cChannels;
if (MIXERCONTROL_CONTROLF_UNIFORM & mxctrl.fdwControl)
cChannels = 1;
chASSERT(cChannels > 0);

chSimpleArray<MIXERCONTROLDETAILS_UNSIGNED> valArray(cChannels);
for(int i = 0; i < cChannels; i++)
{
valArray[i].dwValue = nValue;
}

MIXERCONTROLDETAILS mxcd = {sizeof(mxcd), mxctrl.dwControlID,
cChannels, (HWND)0,
sizeof MIXERCONTROLDETAILS_UNSIGNED, (MIXERCONTROLDETAILS_UNSIGNED*)valArray};

mixerSetControlDetails((HMIXEROBJ)m_hMixer, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
}
//SYZ_TRACE("SetVolume : %d-%X", nType, uVal);
return TRUE;
}

BOOL wMixerCtrl::SetPlaybackVolum(int nValue)
{
return GetVolum(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT);
}

BOOL wMixerCtrl::SetCaptureVolum(int nValue)
{
return GetVolum(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
}

BOOL wMixerCtrl::GetMute(int nType)
{
chASSERT(m_hMixer != NULL);
MIXERLINE mxl;
mxl.cbStruct = sizeof(MIXERLINE);
mxl.dwComponentType = nType;
if (mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
{
WARNING_TRACE("GetMute-mixerGetLineInfo Failed!");
return FALSE;
}

// Find a volume control, if any, of the microphone line
MIXERCONTROL mxctrl = {0};
MIXERLINECONTROLS mxlctrl =
{
sizeof mxlctrl, mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE,
1, sizeof MIXERCONTROL, &mxctrl
};

if(mixerGetLineControls((HMIXEROBJ) m_hMixer, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
mxcd.hwndOwner = 0;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxctrl.dwControlID;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = &mxcdMute;
mxcd.cChannels = MIXERCONTROL_CONTROLF_UNIFORM;
mxcd.cMultipleItems = 0;
if (mixerGetControlDetails((HMIXEROBJ)m_hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR)
{
return mxcdMute.fValue;
}
WARNING_TRACE("GetMute-mixerGetControlDetails Failed!");
}
WARNING_TRACE("GetMute-mixerGetLineControls Failed!");
return FALSE;
}

bool wMixerCtrl::GetMasterVolumeMute()
{
return GetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) != FALSE;
}

bool wMixerCtrl::GetWaveVolumeMute()
{
return GetMute(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT) != FALSE;
}

BOOL wMixerCtrl::SetMute(int nType, BOOL bMute)
{
chASSERT(m_hMixer != NULL);
MIXERLINE mxl;
mxl.cbStruct = sizeof(MIXERLINE);
mxl.dwComponentType = nType;
if (mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
{
WARNING_TRACE("SetMute-mixerGetLineInfo Failed!");
return FALSE;
}

MIXERCONTROL mxctrl = {0};
MIXERLINECONTROLS mxlctrl =
{
sizeof mxlctrl, mxl.dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE,
1, sizeof MIXERCONTROL, &mxctrl
};

if(mixerGetLineControls((HMIXEROBJ) m_hMixer, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
mxcdMute.fValue = bMute;
mxcd.hwndOwner = 0;
mxcd.dwControlID = mxctrl.dwControlID;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = &mxcdMute;
mxcd.cChannels = MIXERCONTROL_CONTROLF_UNIFORM ;
mxcd.cMultipleItems = 0;

if (mixerSetControlDetails((HMIXEROBJ)m_hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR)
{
return TRUE;
}
WARNING_TRACE("SetMute-mixerSetControlDetails Failed!");
}
WARNING_TRACE("SetMute-mixerGetLineControls Failed!");
return FALSE;
}

bool wMixerCtrl::SetMasterVolumeMute(bool bMute)
{
return SetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, bMute) != FALSE;
}

bool wMixerCtrl::SetWaveVolumeMute(bool bMute)
{
return SetMute(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, bMute) != FALSE;
}

wMixerCtrl::wMixerCtrl()
{
m_hMixer = NULL;
}
wMixerCtrl::wMixerCtrl(int iIndex)
{
m_hMixer = NULL;
OpenMixer(iIndex);
}
wMixerCtrl::wMixerCtrl(const chConstString& strAudioName)
{
m_hMixer = NULL;
OpenMixer(strAudioName);
}

wMixerCtrl::~wMixerCtrl()
{
if (m_hMixer != NULL)
{
CloseMixer();
}
}

struct WAVEHEAD{
char riffTag[4];
char dataLen[4];
char waveTag[4];
char fmtTag[4];
char resvr[4];
char dataType[2];
char channelTag[2];
char SamplesPerSecTag[4];
char DataTransferRatePerSec[4];
char BitsPerSample[2];
char PCM[2];
char fact[4];
char filesize[4];
public:
bool operator == (const WAVEHEAD& head) const
{
return (memcmp(head.riffTag, riffTag, 4) == 0
&& memcmp(head.waveTag, waveTag, 4) == 0
&& memcmp(head.fmtTag, fmtTag, 4) == 0
&& memcmp(head.channelTag, channelTag, 2) == 0
&& memcmp(head.SamplesPerSecTag, SamplesPerSecTag, 4) == 0
&& memcmp(head.BitsPerSample, BitsPerSample, 2) == 0);
}
};


static bool is8k16bitWaveData(const chByteArray& data)
{
static WAVEHEAD wave8K16bit = {
{'R', 'I', 'F', 'F'},
{},
{'W', 'A', 'V', 'E'},
{'f', 'm', 't', ' '},
{},
{},
{0x1, 0x0},
{0x40, 0x1f, 0x0, 0x0},
{},
{0x2, 0x0}
};
WAVEHEAD* pFileFmt = (WAVEHEAD*)data.data();
return data.size() >= sizeof(WAVEHEAD) && wave8K16bit == *pFileFmt;
}

bool wWavePlayer::wavePlayStart(UINT idDev, const chConstString& strFilePath)
{
m_dataWaveFile = etlDumpBinFile(strFilePath);
if(m_dataWaveFile.empty())
{
INFO_TRACE("Unable to load file");
return false;
}

chASSERT(is8k16bitWaveData(m_dataWaveFile));

WAVEFORMATEX wfx; /* look this up in your documentation */
wfx.nSamplesPerSec = 8000; /* sample rate */
wfx.wBitsPerSample = 16; /* sample size */
wfx.nChannels = 1; /* channels*/
wfx.cbSize = 0; /* size of _extra_ info */
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;

if(waveOutOpen(&m_hWaveOut,
idDev,
&wfx,
0,
0,
CALLBACK_NULL) != MMSYSERR_NOERROR)
{
INFO_TRACE("unable to open WAVE_MAPPER device");
return false;
}

INFO_TRACE("The Wave Mapper device was opened successfully!");

ZeroMemory(&m_hdrWaveData, sizeof(WAVEHDR));
m_hdrWaveData.lpData = (LPSTR)m_dataWaveFile.data() + sizeof(WAVEHEAD);
m_hdrWaveData.dwBufferLength = m_dataWaveFile.size() - sizeof(WAVEHEAD) ;
m_hdrWaveData.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
m_hdrWaveData.dwLoops = -1;

waveOutPrepareHeader(m_hWaveOut, &m_hdrWaveData, sizeof(WAVEHDR));
waveOutWrite(m_hWaveOut, &m_hdrWaveData, sizeof(WAVEHDR));
m_tickStart = etlGetTickCount();
return true;
}

void wWavePlayer::wavePlayStop()
{
if (m_hWaveOut != NULL)
{
waveOutReset(m_hWaveOut);
waveOutUnprepareHeader(m_hWaveOut, &m_hdrWaveData, sizeof(WAVEHDR));
waveOutClose(m_hWaveOut);
m_hWaveOut = NULL;
m_tickStart = 0;
}
}
int wWavePlayer::getCurrentSample()
{
//chASSERT(m_Playblock.size() != 0);
//1毫秒偏移16byte ===> 16*1*8000/1000/8 = 16byte
UINT64 nByteOffset = (etlGetTickCount() - m_tickStart) * 16;
int iByteOffset = (int)(nByteOffset % (m_dataWaveFile.size() - sizeof(WAVEHEAD)));
LPBYTE pWaveData = m_dataWaveFile.data() + sizeof(WAVEHEAD);
return chMAKEWORD(pWaveData[iByteOffset + 1], pWaveData[iByteOffset]);
}

wWavePlayer::wWavePlayer()
{
m_hWaveOut = NULL;
m_tickStart = 0;
}

wWavePlayer::~wWavePlayer()
{
wavePlayStop();
}


#define MAX_BUFF_SOUNDSIZE 3200

//////////////////////////////////////////////////////////////////////////
//use thread process msg
DWORD WINAPI AudioInThreadProc(LPVOID lpParameter)
{
SYZ_TRACE("AudioInThreadProc start. ");
MSG msg;
while(GetMessage(&msg,0,0,0))
{
switch(msg.message )
{
case MM_WIM_OPEN:
SYZ_TRACE("MM_WIM_OPEN ");
break;
case MM_WIM_CLOSE:
SYZ_TRACE("MM_WIM_CLOSE ");
break;
case MM_WIM_DATA:
WAVEHDR* pWaveHdr = (WAVEHDR*)msg.lParam;//dwParam1指向WAVEHDR的地址
//waveInUnprepareHeader((HWAVEIN)msg.wParam, pWaveHdr, sizeof(WAVEHDR));
if(pWaveHdr->dwBytesRecorded != MAX_BUFF_SOUNDSIZE)
{
//clear dirty data
memset(pWaveHdr->lpData, 0, MAX_BUFF_SOUNDSIZE);
break;
}
pWaveHdr->dwBytesRecorded = 0;
pWaveHdr->dwFlags = 0;
waveInPrepareHeader((HWAVEIN)msg.wParam, pWaveHdr, sizeof(WAVEHDR));
waveInAddBuffer((HWAVEIN)msg.wParam, pWaveHdr, sizeof(WAVEHDR));
break;
}
}
SYZ_TRACE("AudioInThreadProc exit. ");
return msg.wParam;
}
class CWaveIn
{
public:
BOOL StartThread()
{
m_hAudioIn = CreateThread(0, 0, AudioInThreadProc, this, 0, &m_dwAudioInId);
if(m_hAudioIn == NULL)
{
SYZ_TRACE("CWaveIn::StartThread: Strat wave in thread fail. ");
return FALSE;
}
return TRUE;
}
CWaveIn()
{
m_dwAudioInId = 0;
if (!StartThread())
{
m_dwAudioInId = 0;
}
}
~CWaveIn()
{
if (m_dwAudioInId != NULL)
{
TerminateThread(m_hAudioIn, 0);
}
}
public:
DWORD m_dwAudioInId;
private:
HANDLE m_hAudioIn;
};
//////////////////////////////////////////////////////////////////////////
DWORD CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
SYZ_TRACE("waveInProc:: hWaveIn: point[%p] uMsg==[%d]", hWaveIn, uMsg);
if (uMsg == WIM_DATA)
{
WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1;//dwParam1指向WAVEHDR的地址
wWaveRecord* pWaveRecord = (wWaveRecord*)dwInstance;
SYZ_TRACE("WAVEHDR stuct data:
lpData[%p], dwBufferLength[%d], dwBytesRecorded[%d], dwUser[%p], dwFlags[%d], dwLoops[%d], lpNext[%p], reserved[%p]",
pWaveHdr->lpData, pWaveHdr->dwBufferLength, pWaveHdr->dwBytesRecorded, pWaveHdr->dwUser, pWaveHdr->dwFlags, pWaveHdr->dwLoops, pWaveHdr->lpNext, pWaveHdr->reserved);
pWaveRecord->Lock();
if (pWaveRecord->m_bRecording && pWaveHdr->dwBytesRecorded == MAX_BUFF_SOUNDSIZE)
{
//waveInUnprepareHeader(hWaveIn, pWaveHdr, sizeof(WAVEHDR));
pWaveHdr->dwBytesRecorded = 0;
pWaveHdr->dwFlags = 0;
SYZ_TRACE("befor call waveInPrepareHeader");
MMRESULT hr = waveInPrepareHeader(hWaveIn, pWaveHdr, sizeof(WAVEHDR));
SYZ_TRACE("waveInPrepareHeader result [%d]", (hr == MMSYSERR_NOERROR));
hr = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR));
SYZ_TRACE("waveInAddBuffer result [%d]", (hr == MMSYSERR_NOERROR));
}
else
{
//clear dirty data
memset(pWaveHdr->lpData, 0, MAX_BUFF_SOUNDSIZE);
}
pWaveRecord->Unlock();
}
else
{
//SYZ_TRACE("waveInProc:: hWaveIn: point[%p] uMsg==[%d]", &hWaveIn, uMsg);
}
return 0;
}

bool wWaveRecord::waveRecordStart(UINT idDev)
{
WAVEFORMATEX wfx;
memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1;
wfx.nSamplesPerSec = 8000 ;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
wfx.cbSize = 0;

if (m_pWaveInThread == NULL)
{
INFO_TRACE("waveIn callBack_Thread creater failed");
}
//CALLBACK_THREAD
/*if(waveInOpen(&m_hWaveIn,
idDev,
&wfx,
(DWORD_PTR)(m_pWaveInThread->m_dwAudioInId),
(DWORD)this,
CALLBACK_THREAD) != MMSYSERR_NOERROR)
{
INFO_TRACE("unable to open waveIn device");
return false;
};*/
//CALLBACK_FUNCTION
if(waveInOpen(&m_hWaveIn,
idDev,
&wfx,
(DWORD_PTR)(waveInProc),
(DWORD)this,
CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
{
INFO_TRACE("unable to open waveIn device");
return false;
};
m_dataWaveIn.resize(MAX_BUFF_SOUNDSIZE * chLENOF(m_hdrWaveData));
for (int i = 0; i < chLENOF(m_hdrWaveData); ++i)
{
m_hdrWaveData[i].lpData = (LPSTR)m_dataWaveIn.data() + MAX_BUFF_SOUNDSIZE * i;
m_hdrWaveData[i].dwBufferLength = MAX_BUFF_SOUNDSIZE;
m_hdrWaveData[i].dwBytesRecorded = 0;
m_hdrWaveData[i].dwFlags = 0;
waveInPrepareHeader(m_hWaveIn, &m_hdrWaveData[i], sizeof(WAVEHDR));
waveInAddBuffer(m_hWaveIn, &m_hdrWaveData[i], sizeof(WAVEHDR));
}
Lock();
m_bRecording = true;
Unlock();
waveInStart(m_hWaveIn);
return true;
}

void wWaveRecord::waveRecordStop()
{
if (m_hWaveIn != NULL)
{
Lock();
m_bRecording = false;
Unlock();
waveInStop(m_hWaveIn);
waveInReset(m_hWaveIn);
for (int i = 0; i < chLENOF(m_hdrWaveData); ++i)
{
waveInUnprepareHeader(m_hWaveIn, &m_hdrWaveData[i], sizeof(WAVEHDR));
}
waveInClose(m_hWaveIn);
m_hWaveIn = NULL;
m_tickStart = 0;
}
}

int wWaveRecord::getCurrentSample()
{
UINT64 nByteOffset = (etlGetTickCount() - m_tickStart) * 16;
int iByteOffset = (int)(nByteOffset % m_dataWaveIn.size());
LPBYTE pWaveData = m_dataWaveIn.data();
return chMAKEWORD(pWaveData[iByteOffset + 1], pWaveData[iByteOffset]);
}

wWaveRecord::wWaveRecord()
{
m_bRecording = false;
m_hWaveIn = NULL;
m_tickStart = 0;
m_pWaveInThread = new CWaveIn();
}

wWaveRecord::~wWaveRecord()
{
waveRecordStop();
if (m_pWaveInThread != NULL)
{
delete m_pWaveInThread;
}
}

原文地址:https://www.cnblogs.com/hqu-ye/p/4315937.html