windows-nt/Source/XPSP1/NT/net/tapi/skywalker/hidtsp/phonemgr/tones.cpp
2020-09-26 16:20:57 +08:00

436 lines
9.1 KiB
C++

#include "tones.h"
//////////////////////////////////////////////////////////////////////////////
//
// Helper function used to read a wave file's data into an in-memory buffer.
//
HRESULT ReadWaveFile(char * szFileName, DWORD dwFileSize, BYTE * pbData)
{
const int WAVE_HEADER_SIZE = 44;
FILE * fp;
size_t result;
//
// Check arguments.
//
// Assumption: we are reading at least WAVE_HEADER_SIZE bytes from the file.
// Note: this is data in addition to the header.
//
// _ASSERTE( ! IsBadWritePtr( pbData, dwFileSize ) );
// _ASSERTE( ! IsBadStringPtr( szFileName, (UINT) -1 ) );
if ( dwFileSize < WAVE_HEADER_SIZE )
{
return E_INVALIDARG;
}
//
// Open the file for reading.
//
fp = fopen(szFileName, "rb");
if ( fp == NULL )
{
return E_FAIL;
}
//
// Skip the wave header.
//
result = fread(pbData, sizeof(BYTE), WAVE_HEADER_SIZE, fp);
if ( result != WAVE_HEADER_SIZE )
{
fclose(fp);
return E_FAIL;
}
//
// Read the waveform from the file and close the file.
//
result = fread(pbData, sizeof(BYTE), dwFileSize, fp);
fclose(fp);
if ( result != dwFileSize )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
CTonePlayer::CTonePlayer()
{
m_hWaveOut = NULL;
m_fInitialized = FALSE;
m_fDialtonePlaying = FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
CTonePlayer::~CTonePlayer()
{
//
// We should have closed the wave device by now.
//
if ( m_fInitialized == TRUE )
{
ASSERT( m_hWaveOut == NULL );
}
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::Initialize(void)
{
int i;
//
// It's wasteful to initialize twice, but it won't break anything.
//
ASSERT( m_fInitialized == FALSE );
//
// Read all the files.
//
HRESULT hr = ReadWaveFile(
"dialtone.wav",
WAVE_FILE_SIZE,
(BYTE * ) & m_abDialtoneWaveform
);
if ( FAILED(hr) )
{
return hr;
}
//
// For each digit
//
for ( i = 0; i < NUM_DIGITS; i ++ )
{
//
// Construct the filename for this digit.
//
char szFilename[20];
if ( i < 10 )
{
sprintf(szFilename,"dtmf%d.wav", i);
}
else if ( i == 10 )
{
sprintf(szFilename,"dtmfstar.wav", i);
}
else if ( i == 11 )
{
sprintf(szFilename,"dtmfpound.wav", i);
}
else
{
ASSERT( FALSE );
}
//
// Read the wave file for this digit.
//
HRESULT hr = ReadWaveFile(
szFilename,
WAVE_FILE_SIZE,
(BYTE * ) ( & m_abDigitWaveforms ) + ( i * WAVE_FILE_SIZE )
);
if ( FAILED(hr) )
{
return hr;
}
}
//
// We can now go ahead with the other methods.
//
m_fInitialized = TRUE;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::StartDialtone(
void
)
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOut == NULL )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
//
// Reset the wave device to flush out any pending buffers.
//
waveOutReset( m_hWaveOut );
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite, and read in the data from the file. This can also
// be done ahead of time.
//
ZeroMemory( & m_WaveHeader, sizeof( m_WaveHeader ) );
m_WaveHeader.lpData = (LPSTR) & m_abDialtoneWaveform;
m_WaveHeader.dwBufferLength = WAVE_FILE_SIZE;
m_WaveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
m_WaveHeader.dwLoops = (DWORD) -1;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOut,
& m_WaveHeader,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
mmresult = waveOutWrite(m_hWaveOut,
& m_WaveHeader,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
m_fDialtonePlaying = TRUE;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
// Reset the device to stop playing.
//
HRESULT CTonePlayer::StopDialtone( void )
{
if ( m_fInitialized == FALSE )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOut == NULL )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
waveOutReset( m_hWaveOut );
m_fDialtonePlaying = FALSE;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::GenerateDTMF(
long lDigit
)
{
MMRESULT mmresult;
if ( lDigit < 0 )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
if ( lDigit > NUM_DIGITS )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
if ( m_fInitialized == FALSE )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
if ( m_hWaveOut == NULL )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
//
// Reset the wave device to flush out any pending buffers.
//
waveOutReset( m_hWaveOut );
m_fDialtonePlaying = FALSE;
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite, and read in the data from the file. This can also
// be done ahead of time.
//
ZeroMemory( & m_WaveHeader, sizeof( m_WaveHeader ) );
m_WaveHeader.lpData = (LPSTR) & m_abDigitWaveforms + lDigit * WAVE_FILE_SIZE;
m_WaveHeader.dwBufferLength = WAVE_FILE_SIZE;
m_WaveHeader.dwFlags = 0;
m_WaveHeader.dwLoops = (DWORD) 0;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOut,
& m_WaveHeader,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
mmresult = waveOutWrite(m_hWaveOut,
& m_WaveHeader,
sizeof(WAVEHDR)
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::OpenWaveDevice(
long lWaveID
)
{
MMRESULT mmresult;
if ( m_fInitialized == FALSE )
{
ASSERT( FALSE );
return E_UNEXPECTED;
}
//
// We expect that the wave device will not be opened twice. This is
// dependent on the calling code.
//
ASSERT( m_hWaveOut == NULL );
//
// Open the wave device. Here we specify a hard-coded audio format.
//
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM; // linear PCM
waveFormat.nChannels = 1; // mono
waveFormat.nSamplesPerSec = 8000; // 8 KHz
waveFormat.wBitsPerSample = 16; // 16-bit samples
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0; // no extra format info
mmresult = waveOutOpen(& m_hWaveOut, // returned handle
lWaveID, // which device to use
&waveFormat, // wave format to use
0, // callback function pointer
0, // callback instance data
WAVE_FORMAT_DIRECT // we don't want ACM
);
if ( mmresult != MMSYSERR_NOERROR )
{
return E_FAIL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
void CTonePlayer::CloseWaveDevice(void)
{
if ( m_fInitialized == FALSE )
{
ASSERT( FALSE );
}
ASSERT( m_hWaveOut != NULL );
if ( m_hWaveOut != NULL )
{
waveOutClose( m_hWaveOut );
m_hWaveOut = NULL;
}
}