windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/wavedev.cpp
2020-09-26 16:20:57 +08:00

484 lines
8.6 KiB
C++

#include "precomp.h"
#include "WaveDev.h"
#include "WaveIo.h"
// utility function for both waveIndev and waveOutdev
// builds a PCM WaveFormatEx structure for a given sampling rate and size
static MMRESULT MakeWaveFormat(WAVEFORMATEX *pWF, int hertz, int bps)
{
WAVEFORMATEX waveFormat;
if ((bps != 8) && (bps != 16))
{
return WAVERR_BADFORMAT;
}
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 1;
waveFormat.nSamplesPerSec = hertz;
waveFormat.nAvgBytesPerSec = hertz * bps/8;
waveFormat.nBlockAlign = bps/8;
waveFormat.wBitsPerSample = (WORD)bps;
waveFormat.cbSize = 0;
*pWF = waveFormat;
return MMSYSERR_NOERROR;
}
waveInDev::waveInDev(UINT uDevId, HANDLE hEvent) :
m_devID(uDevId), m_hwi(NULL), m_bOpen(FALSE), m_fAllowMapper(TRUE),
m_hEvent(hEvent)
{
ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
return;
}
waveInDev::~waveInDev()
{
Close();
}
MMRESULT waveInDev::Open(int hertz, int bps)
{
MMRESULT mmr;
WAVEFORMATEX waveFormat;
DWORD dwCallbackType = (m_hEvent ? CALLBACK_EVENT : CALLBACK_NULL );
if (m_bOpen == TRUE)
return MMSYSERR_NOERROR;
mmr = MakeWaveFormat(&waveFormat, hertz, bps);
if (mmr != MMSYSERR_NOERROR)
{
return mmr;
}
mmr = waveInOpen(&m_hwi, m_devID, &waveFormat, (DWORD_PTR)m_hEvent, 0, dwCallbackType);
// begin hack, try to open wave_mapper
// this may end up opening a different device!
if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper))
{
mmr = waveInOpen(&m_hwi, WAVE_MAPPER, &waveFormat, (DWORD_PTR)m_hEvent,
0, dwCallbackType);
}
if (mmr == MMSYSERR_NOERROR)
m_bOpen = TRUE;
waveInStart(m_hwi);
m_waveFormat = waveFormat;
return mmr;
}
MMRESULT waveInDev::PrepareHeader(WAVEHDR *pWaveHdr)
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_INVALHANDLE;
mmr = waveInPrepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveInDev::UnPrepareHeader(WAVEHDR *pWaveHdr)
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_INVALHANDLE;
mmr = waveInUnprepareHeader(m_hwi, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveInDev::Reset()
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_NOERROR;
mmr = waveInReset(m_hwi);
return mmr;
}
MMRESULT waveInDev::Close()
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_NOERROR;
waveInReset(m_hwi);
mmr = waveInClose(m_hwi);
if (mmr == MMSYSERR_NOERROR)
m_bOpen = FALSE;
return mmr;
}
MMRESULT waveInDev::Record(WAVEHDR *pHdr)
{
MMRESULT mmr;
if (m_bOpen == FALSE)
{
return MMSYSERR_INVALHANDLE;
}
mmr = waveInAddBuffer(m_hwi, pHdr, sizeof(WAVEHDR));
return mmr;
}
void waveInDev::AllowMapper(BOOL fAllowMapper)
{
m_fAllowMapper = fAllowMapper;
}
waveOutDev::waveOutDev(UINT uDevID, HWND hwnd)
: m_devID(uDevID), m_hwo(NULL), m_bOpen(FALSE), m_hWnd(hwnd),
m_pfBuffer(NULL), m_nBufferSize(0), m_fFileBufferValid(FALSE),
m_fAllowMapper(TRUE)
{
ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
ZeroMemory(m_szPlayFile, sizeof(m_szPlayFile));
ZeroMemory(&m_waveHdr, sizeof(m_waveHdr));
if (hwnd == NULL)
{
m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hEvent == NULL)
{
ERROR_OUT(("waveOutDev::waveOutDev - Unable to create event"));
}
}
else
m_hEvent = NULL;
}
waveOutDev::~waveOutDev()
{
Close();
if (m_hEvent)
CloseHandle(m_hEvent);
if (m_pfBuffer)
LocalFree(m_pfBuffer);
}
MMRESULT waveOutDev::Open(int hertz, int bps)
{
MMRESULT mmr;
WAVEFORMATEX waveFormat;
mmr = MakeWaveFormat(&waveFormat, hertz, bps);
if (mmr != MMSYSERR_NOERROR)
{
return mmr;
}
return Open(&waveFormat);
}
MMRESULT waveOutDev::Open(WAVEFORMATEX *pWaveFormat)
{
MMRESULT mmr;
m_waveFormat = *pWaveFormat;
if (m_bOpen == TRUE)
return MMSYSERR_NOERROR;
if (m_hWnd == NULL)
{
mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hEvent,
0, CALLBACK_EVENT);
}
else
{
mmr = waveOutOpen(&m_hwo, m_devID, &m_waveFormat, (DWORD_PTR)m_hWnd,
0, CALLBACK_WINDOW);
}
// begin hack, try to open wave_mapper
// this may end up opening a different device!
if ((mmr == WAVERR_BADFORMAT) && (m_fAllowMapper))
{
if (m_hWnd == NULL)
{
mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat,
(DWORD_PTR)m_hEvent, 0, CALLBACK_EVENT);
}
else
{
mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, &m_waveFormat,
(DWORD_PTR)m_hWnd, 0, CALLBACK_WINDOW);
}
}
if (mmr == MMSYSERR_NOERROR)
m_bOpen = TRUE;
return mmr;
}
MMRESULT waveOutDev::Close()
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_NOERROR;
waveOutReset(m_hwo);
if (m_waveHdr.dwFlags & WHDR_PREPARED)
{
waveOutUnprepareHeader(m_hwo, &m_waveHdr, sizeof(m_waveHdr));
m_waveHdr.dwFlags = 0;
}
mmr = waveOutClose(m_hwo);
if (mmr == MMSYSERR_NOERROR)
m_bOpen = FALSE;
else
ERROR_OUT(("ATW:Close failed"));
return mmr;
}
MMRESULT waveOutDev::PrepareHeader(WAVEHDR *pWhdr, SHORT *shBuffer, int numSamples)
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_INVALHANDLE;
// if shBuffer is not NULL, we assume the caller wants us to fill in the
// WAVEHDR struct
if (shBuffer)
{
ZeroMemory(pWhdr, sizeof(WAVEHDR));
pWhdr->lpData = (LPSTR)shBuffer;
pWhdr->dwBufferLength = numSamples * m_waveFormat.nBlockAlign;
}
mmr = waveOutPrepareHeader(m_hwo, pWhdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveOutDev::UnprepareHeader(WAVEHDR *pWaveHdr)
{
MMRESULT mmr;
if (m_bOpen == FALSE)
return MMSYSERR_INVALHANDLE;
mmr = waveOutUnprepareHeader(m_hwo, pWaveHdr, sizeof(WAVEHDR));
return mmr;
}
MMRESULT waveOutDev::Play(WAVEHDR *pWaveHdr)
{
MMRESULT mmr;
DWORD dwTimeOut;
DWORD dwRet;
int numSamples;
if (m_bOpen == FALSE)
return MMSYSERR_INVALHANDLE;
if (m_hEvent)
ResetEvent(m_hEvent);
mmr = waveOutWrite(m_hwo, pWaveHdr, sizeof(WAVEHDR));
if (mmr != MMSYSERR_NOERROR)
return mmr;
if (m_hEvent)
{
numSamples = pWaveHdr->dwBufferLength / m_waveFormat.nBlockAlign;
dwTimeOut = 5 * ((1000 * numSamples) / m_waveFormat.nSamplesPerSec);
dwRet = WaitForSingleObject(m_hEvent, dwTimeOut);
if ((dwRet != WAIT_ABANDONED) && (dwRet != WAIT_OBJECT_0))
{
ERROR_OUT(("waveOutDev::Play() - WaitForSingleObject Failed"));
return WAVERR_LASTERROR + 1;
}
}
return MMSYSERR_NOERROR;
}
// File io errors or anything unexpected results in -1 being returned
// Otherwise, returns the MMRESULT of the last waveOut call made
MMRESULT waveOutDev::PlayFile(LPCTSTR szFileName)
{
MMRESULT mmr;
WAVEIOCB waveiocb;
WIOERR werr;
DWORD dwSize;
PCHAR pBuffer;
// quick optimization
// if the same file is being played twice in a row
// the just replay the buffer
if ((m_fFileBufferValid) && (0 == lstrcmp(szFileName, m_szPlayFile)))
{
Close();
mmr = Open(&m_PlayFileWf);
if (mmr == MMSYSERR_NOERROR)
{
mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer, m_nBufferSize / m_PlayFileWf.nBlockAlign);
if (mmr == MMSYSERR_NOERROR)
{
mmr = Play(&m_waveHdr);
}
}
m_fFileBufferValid = (mmr == MMSYSERR_NOERROR);
return mmr;
}
ZeroMemory(&waveiocb, sizeof(waveiocb));
werr = wioFileOpen(&waveiocb, szFileName, 0);
if (werr == WIOERR_NOERROR)
{
// prepare to read the samples!
// quick hack, if the file to play was the same as the last,
// then use the same buffer
m_fFileBufferValid = FALSE;
if (m_pfBuffer == NULL)
{
m_pfBuffer = (char *)LocalAlloc(LPTR, waveiocb.dwDataBytes);
}
else
{
pBuffer = (char*)LocalReAlloc(m_pfBuffer, waveiocb.dwDataBytes, LMEM_MOVEABLE |LMEM_ZEROINIT);
if(NULL != pBuffer)
{
m_pfBuffer = pBuffer;
}
else
{
// Failed to reallocate buffer, make sure to clean up
LocalFree(m_pfBuffer);
m_pfBuffer = NULL;
}
}
if (m_pfBuffer == NULL)
{
wioFileClose(&waveiocb, 0);
return -1;
}
// read
mmioSeek(waveiocb.hmmio, waveiocb.dwDataOffset, SEEK_SET);
dwSize = mmioRead(waveiocb.hmmio, m_pfBuffer, waveiocb.dwDataBytes);
if (dwSize == 0)
return -1;
Close();
mmr = Open(waveiocb.pwfx);
if (mmr != MMSYSERR_NOERROR)
{
wioFileClose(&waveiocb, 0);
return mmr;
}
// mmr = Play((short *)m_pfBuffer, dwSize / (waveiocb.pwfx)->nBlockAlign);
mmr = PrepareHeader(&m_waveHdr, (SHORT*)m_pfBuffer,
dwSize / (waveiocb.pwfx)->nBlockAlign);
if (mmr == MMSYSERR_NOERROR)
{
mmr = Play(&m_waveHdr);
}
m_fFileBufferValid = (mmr == MMSYSERR_NOERROR);
if (m_fFileBufferValid)
{
m_PlayFileWf = *(waveiocb.pwfx);
lstrcpy(m_szPlayFile, szFileName);
m_nBufferSize = dwSize;
}
wioFileClose(&waveiocb, 0);
return mmr;
}
return -1;
}
void waveOutDev::AllowMapper(BOOL fAllowMapper)
{
m_fAllowMapper = fAllowMapper;
}