📄 audiomanager.cpp
字号:
//Loop playing!
bool Done = false;
while (MMResult == MMSYSERR_NOERROR && !Done)
{
//Play the wave
MMResult = waveOutWrite(
WaveOutHandle,
&WaveBufferHeader,
sizeof(WaveBufferHeader)
);
//Make sure it succeeded
if (MMResult != MMSYSERR_NOERROR)
{
break;
}
//Wait for either :
// the sound to finish - signaled by waveOutWrite
// or a user calling StopTone - which signals m_StopToneEvent
const HANDLE c_WaitEvents[] = { SoundDoneEvent, m_StopToneEvent };
DWORD Result = WaitForMultipleObjects(
ARRAYSIZE(c_WaitEvents),
c_WaitEvents,
FALSE,
INFINITE
);
ASSERT(Result != WAIT_FAILED);
if (Result == WAIT_FAILED)
{
MMResult = MMSYSERR_ERROR;
break;
}
//Figure out which handle was signaled (which event)
HANDLE SignaledEvent = c_WaitEvents[ Result - WAIT_OBJECT_0 ];
//If the sound finished playing - restart the loop
if (SignaledEvent == SoundDoneEvent)
{
ResetEvent(SoundDoneEvent);
continue;
}
//If StopProgressTone was called - signal the end of the loop
else if (SignaledEvent == m_StopToneEvent)
{
Done = true;
break;
}
//Otherwise we don't know what happened
else
{
MMResult = MMSYSERR_ERROR;
}
}
cleanup:
//Clean up the waveOut device and waveHeader
waveOutReset(WaveOutHandle);
//Cleans up the WaveBufferHeader struct
waveOutUnprepareHeader(
WaveOutHandle,
&WaveBufferHeader,
sizeof(WaveBufferHeader)
);
//Closes the WaveOutHandle handle
waveOutClose(WaveOutHandle);
if (WaveBufferHeader.lpData)
{
delete[] (BYTE*)(WaveBufferHeader.lpData);
WaveBufferHeader.lpData = NULL;
}
if (pWaveFormat)
{
delete pWaveFormat;
}
//close the event handle
CloseHandle(SoundDoneEvent);
m_ProgressToneThreadId = NULL;
return (MMResult == MMSYSERR_NOERROR) ? S_OK : E_FAIL;
}
HRESULT
AudioManager_t::StopProgressTone(
void
)
{
HRESULT hr = S_OK;
//Restrict access to the player - this Lock is ref-counted
EnterCriticalSection(&m_Lock);
if (m_ProgressToneThreadId == NULL)
{
//There is no tone playing
hr = S_FALSE;
goto leave;
}
//Signal the playing thread to stop playing the tone
SetEvent(m_StopToneEvent);
//Wait for the thread to exit
WaitForSingleObject(
m_ProgressToneThreadId,
INFINITE
);
//Reset the event so it can be reused
ResetEvent(m_StopToneEvent);
m_ProgressToneThreadId = NULL;
leave:
ASSERT(m_ProgressToneThreadId == NULL);
LeaveCriticalSection(&m_Lock);
return hr;
}
HRESULT
AudioManager_t::PlaySound(
BSTR bstrFilePath,
DWORD CallbackHandle
)
{
if (bstrFilePath == NULL ||
bstrFilePath[0] == L'\0')
{
return E_INVALIDARG;
}
MMRESULT MMResult = MMSYSERR_NOERROR;
DWORD BufferSize = 0;
BYTE* pBufferBytes = NULL;
WAVEFORMATEX* pWaveFormat = NULL;
DWORD Wait = 0;
DWORD Duration = 0;
HRESULT hr = S_OK;
if (m_RingWaveOutHandle != NULL)
{
StopSound();
}
//Read Wave File figures out how long the wave is and prepares the
//WaveFormat Structure for playing by waveOutWrite
MMResult = ReadWaveFile(
bstrFilePath,
&pWaveFormat,
&BufferSize,
&pBufferBytes
);
if (MMResult != MMSYSERR_NOERROR)
{
goto leave;
}
//The time that it takes to play the wave
Duration = BufferSize * 1000 / pWaveFormat->nSamplesPerSec;
//Open the wave file
MMResult = waveOutOpen(
&m_RingWaveOutHandle, //handle to the out wave
0, //unused
pWaveFormat, //the waveformatex struct that contains the wav info
CallbackHandle, //The event to signal when the sound is done
NULL, //No additional params
CALLBACK_EVENT //flag indicating that hDoneSound is an event
);
if (MMResult != MMSYSERR_NOERROR)
{
goto leave;
}
//Prepare the header
m_RingWaveDataBlockHeader.dwBufferLength = BufferSize;
//Yes it should be a 'char' even though we are using unicode!
m_RingWaveDataBlockHeader.lpData = (char *)pBufferBytes;
//Inform the wave handle about the header
MMResult = waveOutPrepareHeader(
m_RingWaveOutHandle,
&m_RingWaveDataBlockHeader,
sizeof(m_RingWaveDataBlockHeader)
);
if (MMResult != MMSYSERR_NOERROR)
{
goto leave;
}
MMResult = waveOutWrite(
m_RingWaveOutHandle,
&m_RingWaveDataBlockHeader,
sizeof(m_RingWaveDataBlockHeader)
);
if (MMResult == MMSYSERR_NOERROR)
{
hr = S_OK;
}
leave:
if (MMResult != MMSYSERR_NOERROR)
{
StopSound();
hr = E_FAIL;
}
if (pWaveFormat)
{
delete pWaveFormat;
}
return hr;
}
HRESULT
AudioManager_t::StopSound(
void
)
{
if (m_RingWaveOutHandle != NULL)
{
waveOutReset(m_RingWaveOutHandle);
//Cleans up the hdr struct
waveOutUnprepareHeader(
m_RingWaveOutHandle,
&m_RingWaveDataBlockHeader,
sizeof(m_RingWaveDataBlockHeader)
);
//Closes the hwo handle
waveOutClose(m_RingWaveOutHandle);
//cleanup the allocated wave buffer
if (m_RingWaveDataBlockHeader.lpData)
{
delete[] (BYTE*)(m_RingWaveDataBlockHeader.lpData);
m_RingWaveDataBlockHeader.lpData = NULL;
}
//Null it out for my own sanity
m_RingWaveOutHandle = NULL;
}
return S_OK;
}
HRESULT
AudioManager_t::Ring(
const WCHAR* RingTonePath
)
{
if (RingTonePath == NULL)
{
return E_INVALIDARG;
}
if (IsRinging())
{
return E_FAIL;
}
ResetEvent(m_StopRingEvent);
if (!m_RingTonePath.assign(RingTonePath))
{
ASSERT(FALSE);
return E_OUTOFMEMORY;
}
m_RingThreadId = CreateThread(
NULL,
0,
s_RingerProc,
reinterpret_cast<VOID*>(this),
0,
NULL
);
if (m_RingThreadId == NULL)
{
return CommonUtilities_t::GetErrorFromWin32();
}
return S_OK;
}
HRESULT
AudioManager_t::CancelRing(
void
)
{
if (m_RingThreadId == NULL)
{
//There is no tone playing
return S_FALSE;
}
//Signal the playing thread to stop playing the tone
SetEvent(m_StopRingEvent);
//Wait for the thread to exit
WaitForSingleObject(
m_RingThreadId,
INFINITE
);
//Reset the event so it can be reused
ResetEvent(m_StopRingEvent);
m_RingThreadId = NULL;
return S_OK;
}
DWORD WINAPI
AudioManager_t::s_RingerProc(
LPVOID Parameter
)
{
AudioManager_t* pAudioManager = reinterpret_cast<AudioManager_t*>(Parameter);
if (pAudioManager == NULL)
{
return E_UNEXPECTED;
}
return pAudioManager->RingerProc();
}
DWORD
AudioManager_t::RingerProc(
void
)
{
HRESULT hr = S_OK;
HANDLE SoundDoneEvent = NULL;
bool Stopped = false;
DWORD Wait = 0;
//Create an event for the sound begin done playing
SoundDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!SoundDoneEvent)
{
goto exit;
}
/*
wait for 2 possible events:
1) The sound is done playing and needs to be relooped
2) The stop ring event
*/
HANDLE Events[] = {SoundDoneEvent, m_StopRingEvent};
unsigned int EventCount = ARRAYSIZE(Events);
//While it is not stopped
while (!Stopped)
{
//The handles to wait for.
StartRing(SoundDoneEvent);
//Wait for: the sound being done playing
// kill the sound
Wait = WaitForMultipleObjects(
EventCount,
Events,
FALSE,
INFINITE
);
if (Wait == WAIT_FAILED)
{
ASSERT(FALSE);
//Simulate an external answered event to kill the ringer
//Note: The index of the StopRing event is 1
Wait = 1;
}
else
{
Wait -= WAIT_OBJECT_0;
}
//Get the handle returned
HANDLE ReturnedEvent = Events[Wait];
//If the ring needs to be killed, then kill the ring and re-loop
if (ReturnedEvent == SoundDoneEvent)
{
//Reset the SoundDone event so we can play the sound again
ResetEvent(SoundDoneEvent);
//Wait for a second for the answering or timeout event
Wait = WaitForSingleObject(
m_StopRingEvent,
1000
);
if (Wait != WAIT_TIMEOUT)
{
ReturnedEvent = m_StopRingEvent;
}
}
//If we got the "call answered" event then break the loop
if (ReturnedEvent == m_StopRingEvent)
{
Stopped = true;
}
}
//Immediately terminate the sound
StopRing();
exit:
//Cleanup
//
//Cleanup the handles for the events that were created
CloseHandle(SoundDoneEvent);
//clean up the handle to this thread
CloseHandle(m_RingThreadId);
m_RingThreadId = NULL;
return 0;
}
HRESULT
AudioManager_t::StartRing(
HANDLE CallbackEvent
)
{
//a tone is a call waiting tone IFF the ringtone path is empty
bool CallWaiting = (m_RingTonePath[0] == 0);
ce::auto_bstr bstrRingtone;
if (CallWaiting)
{
PlayProgressTone(ProgressToneCallWaiting);
}
else
{
bstrRingtone = SysAllocString(m_RingTonePath);
if (bstrRingtone != NULL)
{
PlaySound(bstrRingtone, reinterpret_cast<DWORD>(CallbackEvent));
}
}
return S_OK;
}
HRESULT
AudioManager_t::StopRing(
void
)
{
//the tone is a call waiting tone IFF the ringtone path is empty
bool CallWaiting = (m_RingTonePath[0] == 0);
if (CallWaiting)
{
StopProgressTone();
}
else
{
StopSound();
}
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -