📄 audiorender.cpp
字号:
#include <windows.h>
#include "AudioRender.h"
#include "Log.h"
#define AAC_CHUNK_SIZE 1024
//##ModelId=4753B7E9011A
CAudioRender::CAudioRender()
{
m_pDs = NULL;
m_pSoundBuff = NULL;
lInService = FALSE;
m_dwCurPlayCursor = 0;
m_dwBufOffset = 0;
m_pTimer = NULL;
m_nBufService = 500;
m_nLastChunkTime = 0;
m_bEmpty = TRUE;
}
//##ModelId=4753B7E9011B
CAudioRender::~CAudioRender()
{
}
//##ModelId=4753B7E9011C
BOOL CAudioRender::CreateAudioRender(HWND hWnd, int nSamplesPerSec, int nChannels, int nBitsPerSample)
{
m_bEmpty = TRUE;
if( nChannels <= 0 || nBitsPerSample <= 0 )
{
LogMsg(LOG_CRIT, HCLN, "Invalid Wave parameter Channel = %d BitsPerSample = %d", nChannels, nBitsPerSample);
return FALSE;
}
//Initialize Wave header
::memset(&m_WaveFormatEx, 0x00, sizeof(m_WaveFormatEx));
m_WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
m_WaveFormatEx.nChannels = nChannels;
m_WaveFormatEx.wBitsPerSample = nBitsPerSample;
m_WaveFormatEx.cbSize = 0;
m_WaveFormatEx.nSamplesPerSec = nSamplesPerSec;
m_WaveFormatEx.nBlockAlign = (nBitsPerSample / 8) * nChannels;
m_WaveFormatEx.nAvgBytesPerSec = m_WaveFormatEx.nSamplesPerSec * m_WaveFormatEx.nBlockAlign;
if (DirectSoundCreate(NULL, &m_pDs, NULL) == DS_OK)
{
if (m_pDs->SetCooperativeLevel(hWnd, DSSCL_NORMAL) != DS_OK)
{
LogMsg(LOG_CRIT, HCLN, "Can not Set CooperativeLevel!");
return FALSE;
}
}
else
{
LogMsg(LOG_CRIT, HCLN, "Can not create DirectSound!");
return FALSE;
}
m_dwSampleSize = AAC_CHUNK_SIZE * m_WaveFormatEx.nChannels * nBitsPerSample / 8;
// Calculate sound buffer size in bytes
m_dwDSBufferSize = (m_WaveFormatEx.nAvgBytesPerSec * 2 / m_dwSampleSize) * m_dwSampleSize;
ZeroMemory( &m_sDsbd, sizeof(DSBUFFERDESC) );
m_sDsbd.dwSize = sizeof(DSBUFFERDESC);
// Volume苞 Frequency甫 炼辆且荐 乐档废 汲沥茄促.
m_sDsbd.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLVOLUME;
m_sDsbd.dwBufferBytes = m_dwDSBufferSize;
m_sDsbd.lpwfxFormat = (LPWAVEFORMATEX)&m_WaveFormatEx;
if (m_pDs->CreateSoundBuffer(&m_sDsbd, &m_pDSBuff, NULL) != DS_OK)
{
LogMsg(LOG_ERR, HCLN, "Can not create SoundBuffer!");
return FALSE;
}
m_pDSBuff->SetVolume(-50);
m_pSoundBuff = (BYTE *)malloc(m_dwDSBufferSize);
memset(m_pSoundBuff, 0x00, m_dwDSBufferSize);
m_dwBufOffset = 0;
m_nLastChunkTime = 0;
m_dwCurPlayCursor = 0;
LogMsg(LOG_INFO, HCLN, "Create WaveOut!");
return TRUE;
}
//##ModelId=4753B7E9012C
BOOL CAudioRender::DestroyAudioRender()
{
if (m_pDs != NULL)
{
m_pDSBuff->Stop();
m_pDSBuff->Release();
m_pDs->Release();
// m_pDSBuff = NULL;
}
if( m_pTimer )
{
m_pTimer->TimerStop();
delete m_pTimer;
m_pTimer = NULL;
}
if(m_pSoundBuff)
{
free(m_pSoundBuff);
m_pSoundBuff = NULL;
}
LogMsg(LOG_INFO, HCLN, "Destroy WaveOut!");
return TRUE;
}
//##ModelId=4753B7E9012D
BOOL CAudioRender::Play()
{
//
if( m_bEmpty )
{
m_pDSBuff->SetCurrentPosition(0);
ServiceBuffer();
m_bEmpty = FALSE;
}
else
m_pDSBuff->SetCurrentPosition(m_dwCurPlayCursor);
if( m_pDSBuff->Play(0, 0, DSBPLAY_LOOPING) != DS_OK )
{
LogMsg(LOG_ERR, HCLN, "Play Error!");
return FALSE;
}
else
{
// Kick off timer to service buffer
if( m_pTimer )
{
m_pTimer->TimerStop();
delete m_pTimer;
m_pTimer = NULL;
}
m_pTimer = new Timer();
if (m_pTimer)
{
m_pTimer->Create(m_nBufService, m_nBufService, DWORD(this), TimerCallback);
}
}
return TRUE;
}
//##ModelId=4753B7E9012E
BOOL CAudioRender::Stop()
{
if (m_pTimer)
{
m_pTimer->TimerStop();
delete m_pTimer;
m_pTimer = NULL;
}
if (m_pDs)
{
m_pDSBuff->GetCurrentPosition(&m_dwCurPlayCursor, NULL);
m_pDSBuff->Stop();
m_pDSBuff->Restore();
}
return TRUE;
}
//##ModelId=4753B7E90138
void CAudioRender::EmptyWaveBuffer()
{
LogMsg(LOG_INFO, HCLN, "Empty WaveOut! buffer offset = %d", m_dwBufOffset);
m_bEmpty = TRUE;
m_dwCurPlayCursor = 0;
m_dwBufOffset = 0;
m_nLastChunkTime = 0;
}
//##ModelId=4753B7E90139
DWORD CAudioRender::GetCurPlayTime()
{
DWORD dwPlayBufferSize;
if (!m_pDs)
{
LogMsg(LOG_ERR, HCLN, "can't get current play time for directsound!");
return 0; // DSound is Not Initialized.
}
dwPlayBufferSize = m_dwDSBufferSize - GetMaxWriteSize();
DWORD dwBufferTimes = (DWORD)((dwPlayBufferSize * 1024000.0 / m_dwSampleSize)/ m_WaveFormatEx.nSamplesPerSec);
// LogMsg(LOG_INFO, HCLN, "CurChunkTime = %d BufferTime = %d buffersize = %d",
// m_nLastChunkTime, dwBufferTimes, dwPlayBufferSize);
if( m_nLastChunkTime > dwBufferTimes)
return m_nLastChunkTime - dwBufferTimes;
else
return 0;
}
//##ModelId=4753B7E90158
PVOID CAudioRender::GetWaveData(UINT nSize, BOOL bSilence)
{
UINT nNumOfSample = nSize / m_dwSampleSize;
PVOID pWaveData = NULL;
UINT readsize;
int iLimitCounter = (int)nNumOfSample * 2;
UINT nCounter = 0;
memset(m_pSoundBuff, 0x00, nSize);
do
{
iLimitCounter --;
if(iLimitCounter <= 0)
{
LogMsg(LOG_INFO, HCLN, "Empty audio stream buffer!");
break;
}
pWaveData = (BYTE*)m_pAudioStream->Pop(&readsize, &m_nLastChunkTime);
if(pWaveData != NULL)
{
memcpy(m_pSoundBuff + nCounter * m_dwSampleSize, pWaveData, readsize);
nCounter ++;
}
else
{
//LogMsg(LOG_DEBUG, HCLN, "Wait untile push to buffer! %d", nCounter);
if(bSilence)
break;
else
continue;
}
}while(nCounter < nNumOfSample);
return m_pSoundBuff;
}
/* write sound buffer.
*/
//##ModelId=4753B7E9013C
BOOL CAudioRender::WriteWaveData(UINT cbSize)
{
HRESULT hr;
VOID* pDSLockedBuffer = NULL; // Pointer to locked first buffer memory
DWORD dwDSLockedBufferSize = 0; // Size of the locked first DirectSound buffer
VOID* pDSLockedBuffer2 = NULL; // Pointer to locked second buffer memory
DWORD dwDSLockedBufferSize2 = 0; // Size of the locked second DirectSound buffer
PVOID pWaveData = NULL;
// Lock the buffer down
if( FAILED( hr = m_pDSBuff->Lock( m_dwBufOffset, cbSize,
&pDSLockedBuffer, &dwDSLockedBufferSize,
&pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
{
LogMsg(LOG_ERR, HCLN, "Faild Waveout Buffer Lock");
return FALSE;
}
pWaveData = GetWaveData(cbSize, FALSE);
if(pDSLockedBuffer)
{
memcpy(pDSLockedBuffer, pWaveData, dwDSLockedBufferSize);
if(pDSLockedBuffer2)
{
memcpy(pDSLockedBuffer2, (BYTE*)pWaveData + dwDSLockedBufferSize, dwDSLockedBufferSize2);
}
}
// Unlock the buffer, we don't need it anymore.
m_pDSBuff->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, pDSLockedBuffer2, dwDSLockedBufferSize2 );
m_dwBufOffset += (dwDSLockedBufferSize + dwDSLockedBufferSize2);
m_dwBufOffset %= m_dwDSBufferSize; // Circular buffer
return TRUE;
}
//##ModelId=4753B7E9014B
DWORD CAudioRender::GetMaxWriteSize()
{
DWORD dwWriteCursor, dwPlayCursor, dwMaxSize;
if (!m_pDs)
return 0; // DSound is Not Initialized.
// Get current play position
if (m_pDSBuff->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor) == DS_OK)
{
if (m_dwBufOffset < dwPlayCursor)
{
// Our write position trails play cursor
dwMaxSize = dwPlayCursor - m_dwBufOffset;
}
else // (m_cbBufOffset > dwPlayCursor)
{
// Play cursor has wrapped
dwMaxSize = m_dwDSBufferSize - m_dwBufOffset + dwPlayCursor;
}
}
else
{
// GetCurrentPosition call failed
//_ASSERT (0);
dwMaxSize = 0;
}
return (dwMaxSize);
}
//##ModelId=4753B7E9014D
BOOL CAudioRender::ServiceBuffer (void)
{
BOOL fRtn = TRUE;
// Check for reentrance
if (InterlockedExchange (&lInService, TRUE) == FALSE)
{ // Not reentered, proceed normally
// All of sound not played yet, send more data to buffer
DWORD dwFreeSpace = GetMaxWriteSize ();
// Determine free space in sound buffer
if (dwFreeSpace)
{
// Fill free space in buffer with wave data
if (!WriteWaveData ((dwFreeSpace / m_dwSampleSize) * m_dwSampleSize))
{
// Error writing wave data
fRtn = FALSE;
}
}
else
{ // No free space in buffer for some reason
fRtn = FALSE;
}
// Reset reentrancy semaphore
InterlockedExchange (&lInService, FALSE);
}
else
{ // Service routine reentered. Do nothing, just return
fRtn = FALSE;
}
return (fRtn);
}
//##ModelId=4753B7E9013A
BOOL CAudioRender::SetVolume(int nVol)
{
if(m_pDSBuff)
{
if(DS_OK == m_pDSBuff->SetVolume(nVol))
return TRUE;
}
return FALSE;
}
//##ModelId=4753B7E9015B
BOOL CAudioRender::TimerCallback (DWORD dwUser)
{
BOOL nRet;
// dwUser contains ptr to AudioStream object
CAudioRender* pWaveOut = (CAudioRender*) dwUser;
nRet = pWaveOut->ServiceBuffer();
return nRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -