Jack_thomas
03-31-2006, 02:55 PM
Hi I've got this code and I am trying to implement a thread with it.
Could someone tell me what are the sizes of the capture and playback buffers and their durations ? Are these parameters fixed or can be manipulated ?
What other parameters are being used in this code which can be manipulated ?
What is the rate at which samples are being played from output.
code:
HRESULT __fastcall TDSFilter::InitDirectSound()
{
HRESULT hr;
DSBUFFERDESC dsbdesc;
// ZeroMemory( &aPosNotify, sizeof(DSBPOSITIONNOTIFY) * FNumBuffers);
dwOutputBufferSize = 0;
dwCaptureBufferSize = 0;
dwNotifySize = 0;
dwNextOutputOffset = 0;
// Initialize COM
if( FAILED( hr = CoInitialize(NULL) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CoInitialize"), hr );
// Create IDirectSound using the preferred sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCreate"), hr );
// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetCooperativeLevel"), hr );
// Obtain primary buffer
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create IDirectSoundCapture using the preferred capture device
if( FAILED( hr = DirectSoundCaptureCreate8( NULL, &pDSCapture, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCaptureCreate"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::FreeDirectSound()
{
// Release DirectSound interfaces
SAFE_RELEASE( pDSNotify );
SAFE_RELEASE( pDSBPrimary );
SAFE_RELEASE( pDSBOutput );
SAFE_RELEASE( pDSBCapture );
SAFE_RELEASE( pDSCapture );
SAFE_RELEASE( pDS );
// Release COM
CoUninitialize();
return S_OK;
}
HRESULT __fastcall TDSFilter::ScanAvailableOutputFormats()
{
WAVEFORMATEX wfx;
WAVEFORMATEX wfxSet;
HRESULT hr;
ZeroMemory( &wfxSet, sizeof(wfxSet) );
wfxSet.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a playback format is supported, try to set the format
// using a specific format. If it works then the format is
// supported, otherwise not.
if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
{
abOutputFormatSupported[ iIndex ] = FALSE;
}
else
{
// Get the format that was just set, and see if it
// is actually supported since SetFormat() sometimes returns DS_OK
// even if the format was not supported
if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet),
NULL ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("GetFormat"), hr );
if( memcmp( &wfx, &wfxSet, sizeof(wfx) ) == 0 )
abOutputFormatSupported[ iIndex ] = TRUE;
else
abOutputFormatSupported[ iIndex ] = FALSE;
}
}
return S_OK;
}
void __fastcall TDSFilter::GetWaveFormatFromIndex( INT nIndex, WAVEFORMATEX* pwfx )
{
INT iSampleRate = nIndex % 5;
INT iType = nIndex / 5;
switch( iSampleRate )
{
case 0: pwfx->nSamplesPerSec = 48000; break;
case 1: pwfx->nSamplesPerSec = 44100; break;
case 2: pwfx->nSamplesPerSec = 22050; break;
case 3: pwfx->nSamplesPerSec = 11025; break;
case 4: pwfx->nSamplesPerSec = 8000; break;
}
switch( iType )
{
case 0: pwfx->wBitsPerSample = 16; pwfx->nChannels = 2; break;
case 1: pwfx->wBitsPerSample = 16; pwfx->nChannels = 1; break;
case 2: pwfx->wBitsPerSample = 8; pwfx->nChannels = 2; break;
case 3: pwfx->wBitsPerSample = 8; pwfx->nChannels = 1; break;
}
pwfx->nBlockAlign = pwfx->nChannels * ( pwfx->wBitsPerSample / 8 );
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
}
void __fastcall TDSFilter::ConvertWaveFormatToString( WAVEFORMATEX* pwfx, TCHAR* strFormatName)
{
wsprintf( strFormatName,
TEXT("%u Hz, %u-bit %s"),
pwfx->nSamplesPerSec,
pwfx->wBitsPerSample,
( pwfx->nChannels == 1 ) ? TEXT("Mono") : TEXT("Stereo") );
}
HRESULT __fastcall TDSFilter::ScanAvailableInputFormats()
{
WAVEFORMATEX wfx;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer = NULL;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a capture format is supported, try to create a
// new capture buffer using a specific format. If it works
// then the format is supported, otherwise not.
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.lpwfxFormat = &wfx;
if( FAILED( pDSCapture->CreateCaptureBuffer( &dscbd, &pDSCaptureBuffer, NULL ) ) ) abInputFormatSupported[ iIndex ] = FALSE;
else abInputFormatSupported[ iIndex ] = TRUE;
SAFE_RELEASE( pDSCaptureBuffer );
}
return S_OK;
}
HRESULT __fastcall TDSFilter::SetBufferFormats( WAVEFORMATEX* pwfxInput, WAVEFORMATEX* pwfxOutput )
{
HRESULT hr ;
// Set the format of the primary buffer
// to the format of the output buffer
if( FAILED( hr = pDSBPrimary->SetFormat( pwfxOutput ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetFormat"), hr );
// Set the notification size
dwNotifySize = FBufferSize ;
dwNotifySize -= dwNotifySize % pwfxInput->nBlockAlign;
// Set the buffer sizes
dwOutputBufferSize = FNumBuffers * dwNotifySize / 2;
dwCaptureBufferSize = dwNotifySize * FNumBuffers ;
SAFE_RELEASE( pDSBCapture );
// Create the capture buffer
DSCBUFFERDESC dscbd;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation
if( FAILED( hr = pDSCapture->CreateCaptureBuffer( &dscbd, &pDSBCapture, NULL))) return DXTRACE_ERR_MSGBOX( TEXT("CreateCaptureBuffer"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::CreateOutputBuffer()
{
HRESULT hr;
WAVEFORMATEX wfxInput;
// This sample works by creating notification events which
// are signaled when the capture buffer reachs specific offsets
// WinMain() waits for the associated event to be signaled, and
// when it is, it calls HandleNotifications() which copy the
// data from the capture buffer into the output buffer
ZeroMemory( &wfxInput, sizeof(wfxInput) );
pDSBCapture->GetFormat( &wfxInput, sizeof(wfxInput), NULL );
// Create the direct sound buffer using the same format as the
// capture buffer.
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = dwOutputBufferSize;
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfxInput;
// Create the DirectSound buffer
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create a notification event, for when the sound stops playing
if( FAILED( hr = pDSBCapture->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("QueryInterface"), hr );
// Setup the notification positions
for( unsigned int i = 0; i < FNumBuffers ; i++ ) {
aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
aPosNotify[i].hEventNotify = hNotificationEvent;
}
// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = pDSNotify->SetNotificationPositions( FNumBuffers, aPosNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::StartBuffers()
{
WAVEFORMATEX wfxOutput;
VOID* pDSLockedBuffer = NULL;
DWORD dwDSLockedBufferSize;
HRESULT hr;
// Restore lost buffers
if( FAILED( hr = RestoreBuffer( pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("RestoreBuffer"), hr );
// Reset the buffers
dwNextOutputOffset = 0;
pDSBOutput->SetCurrentPosition( 0 );
// Find out where the capture buffer is right now, then write data
// some extra amount forward to make sure we're ahead of the write cursor
pDSBCapture->GetCurrentPosition( &dwNextCaptureOffset, NULL );
dwNextCaptureOffset -= dwNextCaptureOffset % dwNotifySize;
dwNextOutputOffset = dwNextCaptureOffset + ( dwNotifySize << 1);
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
// Tell the capture buffer to start recording
pDSBCapture->Start( DSCBSTART_LOOPING );
// Rewind the output buffer, fill it with silence, and play it
pDSBOutput->SetCurrentPosition( dwNextOutputOffset );
// Save the format of the capture buffer in g_pCaptureWaveFormat
ZeroMemory( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX) );
pDSBCapture->GetFormat( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX), NULL );
// Get the format of the output buffer
ZeroMemory( &wfxOutput, sizeof(wfxOutput) );
pDSBOutput->GetFormat( &wfxOutput, sizeof(wfxOutput), NULL );
// Fill the output buffer with silence at first
// As capture data arrives, HandleNotifications() will fill
// the output buffer with wave data.
if( FAILED( hr = pDSBOutput->Lock( 0, dwOutputBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( wfxOutput.wBitsPerSample == 8 ? 128 : 0 ) );
pDSBOutput->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL );
// Play the output buffer
pDSBOutput->Play( 0, 0, DSBPLAY_LOOPING );
return S_OK;
}
HRESULT __fastcall TDSFilter::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSBuffer, BOOL* pbRestored )
{
HRESULT hr;
if( pbRestored) *pbRestored = FALSE;
if( !pDSBuffer ) return S_FALSE;
DWORD dwStatus;
if( FAILED( hr = pDSBuffer->GetStatus( &dwStatus ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do {
hr = pDSBuffer->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
} while( ( hr = pDSBuffer->Restore() ) == DSERR_BUFFERLOST );
if( pbRestored) *pbRestored = TRUE;
return S_OK;
} else return S_FALSE;
}
HRESULT __fastcall TDSFilter::HandleNotification()
{
HRESULT hr;
VOID* pDSCaptureLockedBuffer = NULL;
VOID* pDSOutputLockedBuffer = NULL;
DWORD dwDSCaptureLockedBufferSize;
DWORD dwDSOutputLockedBufferSize;
DWORD dwStatus;
// Make sure buffers were not lost, if the were we need
// to start the capture again
if( FAILED( hr = pDSBOutput->GetStatus( &dwStatus))) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
if( FAILED( hr = StartBuffers())) return DXTRACE_ERR_MSGBOX( TEXT("StartBuffers"), hr );
return S_OK;
}
// Lock the capture buffer down
if( FAILED( hr = pDSBCapture->Lock( dwNextCaptureOffset, dwNotifySize, &pDSCaptureLockedBuffer,
&dwDSCaptureLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// Lock the output buffer down
if( FAILED( hr = pDSBOutput->Lock( dwNextOutputOffset, dwNotifySize, &pDSOutputLockedBuffer,
&dwDSOutputLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// These should be equal
if( dwDSOutputLockedBufferSize != dwDSCaptureLockedBufferSize ) return E_FAIL; // Sanity check unhandled case
// Just copy the memory from the
// capture buffer to the playback buffer
Process( (short*) pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize) ;
CopyMemory( pDSOutputLockedBuffer, pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize );
// Unlock the play buffer
pDSBOutput->Unlock( pDSOutputLockedBuffer, dwDSOutputLockedBufferSize, NULL, 0 );
// Unlock the capture buffer
pDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize, NULL, 0 );
// Move the capture offset along
dwNextCaptureOffset += dwDSCaptureLockedBufferSize;
dwNextCaptureOffset %= dwCaptureBufferSize; // Circular buffer
// Move the playback offset along
dwNextOutputOffset += dwDSOutputLockedBufferSize;
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
return S_OK;
}
I would really appreciate your help.
Thanks.
Could someone tell me what are the sizes of the capture and playback buffers and their durations ? Are these parameters fixed or can be manipulated ?
What other parameters are being used in this code which can be manipulated ?
What is the rate at which samples are being played from output.
code:
HRESULT __fastcall TDSFilter::InitDirectSound()
{
HRESULT hr;
DSBUFFERDESC dsbdesc;
// ZeroMemory( &aPosNotify, sizeof(DSBPOSITIONNOTIFY) * FNumBuffers);
dwOutputBufferSize = 0;
dwCaptureBufferSize = 0;
dwNotifySize = 0;
dwNextOutputOffset = 0;
// Initialize COM
if( FAILED( hr = CoInitialize(NULL) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CoInitialize"), hr );
// Create IDirectSound using the preferred sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCreate"), hr );
// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetCooperativeLevel"), hr );
// Obtain primary buffer
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create IDirectSoundCapture using the preferred capture device
if( FAILED( hr = DirectSoundCaptureCreate8( NULL, &pDSCapture, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCaptureCreate"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::FreeDirectSound()
{
// Release DirectSound interfaces
SAFE_RELEASE( pDSNotify );
SAFE_RELEASE( pDSBPrimary );
SAFE_RELEASE( pDSBOutput );
SAFE_RELEASE( pDSBCapture );
SAFE_RELEASE( pDSCapture );
SAFE_RELEASE( pDS );
// Release COM
CoUninitialize();
return S_OK;
}
HRESULT __fastcall TDSFilter::ScanAvailableOutputFormats()
{
WAVEFORMATEX wfx;
WAVEFORMATEX wfxSet;
HRESULT hr;
ZeroMemory( &wfxSet, sizeof(wfxSet) );
wfxSet.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a playback format is supported, try to set the format
// using a specific format. If it works then the format is
// supported, otherwise not.
if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
{
abOutputFormatSupported[ iIndex ] = FALSE;
}
else
{
// Get the format that was just set, and see if it
// is actually supported since SetFormat() sometimes returns DS_OK
// even if the format was not supported
if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet),
NULL ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("GetFormat"), hr );
if( memcmp( &wfx, &wfxSet, sizeof(wfx) ) == 0 )
abOutputFormatSupported[ iIndex ] = TRUE;
else
abOutputFormatSupported[ iIndex ] = FALSE;
}
}
return S_OK;
}
void __fastcall TDSFilter::GetWaveFormatFromIndex( INT nIndex, WAVEFORMATEX* pwfx )
{
INT iSampleRate = nIndex % 5;
INT iType = nIndex / 5;
switch( iSampleRate )
{
case 0: pwfx->nSamplesPerSec = 48000; break;
case 1: pwfx->nSamplesPerSec = 44100; break;
case 2: pwfx->nSamplesPerSec = 22050; break;
case 3: pwfx->nSamplesPerSec = 11025; break;
case 4: pwfx->nSamplesPerSec = 8000; break;
}
switch( iType )
{
case 0: pwfx->wBitsPerSample = 16; pwfx->nChannels = 2; break;
case 1: pwfx->wBitsPerSample = 16; pwfx->nChannels = 1; break;
case 2: pwfx->wBitsPerSample = 8; pwfx->nChannels = 2; break;
case 3: pwfx->wBitsPerSample = 8; pwfx->nChannels = 1; break;
}
pwfx->nBlockAlign = pwfx->nChannels * ( pwfx->wBitsPerSample / 8 );
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
}
void __fastcall TDSFilter::ConvertWaveFormatToString( WAVEFORMATEX* pwfx, TCHAR* strFormatName)
{
wsprintf( strFormatName,
TEXT("%u Hz, %u-bit %s"),
pwfx->nSamplesPerSec,
pwfx->wBitsPerSample,
( pwfx->nChannels == 1 ) ? TEXT("Mono") : TEXT("Stereo") );
}
HRESULT __fastcall TDSFilter::ScanAvailableInputFormats()
{
WAVEFORMATEX wfx;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer = NULL;
ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );
// To test if a capture format is supported, try to create a
// new capture buffer using a specific format. If it works
// then the format is supported, otherwise not.
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.lpwfxFormat = &wfx;
if( FAILED( pDSCapture->CreateCaptureBuffer( &dscbd, &pDSCaptureBuffer, NULL ) ) ) abInputFormatSupported[ iIndex ] = FALSE;
else abInputFormatSupported[ iIndex ] = TRUE;
SAFE_RELEASE( pDSCaptureBuffer );
}
return S_OK;
}
HRESULT __fastcall TDSFilter::SetBufferFormats( WAVEFORMATEX* pwfxInput, WAVEFORMATEX* pwfxOutput )
{
HRESULT hr ;
// Set the format of the primary buffer
// to the format of the output buffer
if( FAILED( hr = pDSBPrimary->SetFormat( pwfxOutput ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetFormat"), hr );
// Set the notification size
dwNotifySize = FBufferSize ;
dwNotifySize -= dwNotifySize % pwfxInput->nBlockAlign;
// Set the buffer sizes
dwOutputBufferSize = FNumBuffers * dwNotifySize / 2;
dwCaptureBufferSize = dwNotifySize * FNumBuffers ;
SAFE_RELEASE( pDSBCapture );
// Create the capture buffer
DSCBUFFERDESC dscbd;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation
if( FAILED( hr = pDSCapture->CreateCaptureBuffer( &dscbd, &pDSBCapture, NULL))) return DXTRACE_ERR_MSGBOX( TEXT("CreateCaptureBuffer"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::CreateOutputBuffer()
{
HRESULT hr;
WAVEFORMATEX wfxInput;
// This sample works by creating notification events which
// are signaled when the capture buffer reachs specific offsets
// WinMain() waits for the associated event to be signaled, and
// when it is, it calls HandleNotifications() which copy the
// data from the capture buffer into the output buffer
ZeroMemory( &wfxInput, sizeof(wfxInput) );
pDSBCapture->GetFormat( &wfxInput, sizeof(wfxInput), NULL );
// Create the direct sound buffer using the same format as the
// capture buffer.
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = dwOutputBufferSize;
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfxInput;
// Create the DirectSound buffer
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );
// Create a notification event, for when the sound stops playing
if( FAILED( hr = pDSBCapture->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("QueryInterface"), hr );
// Setup the notification positions
for( unsigned int i = 0; i < FNumBuffers ; i++ ) {
aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
aPosNotify[i].hEventNotify = hNotificationEvent;
}
// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = pDSNotify->SetNotificationPositions( FNumBuffers, aPosNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::StartBuffers()
{
WAVEFORMATEX wfxOutput;
VOID* pDSLockedBuffer = NULL;
DWORD dwDSLockedBufferSize;
HRESULT hr;
// Restore lost buffers
if( FAILED( hr = RestoreBuffer( pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("RestoreBuffer"), hr );
// Reset the buffers
dwNextOutputOffset = 0;
pDSBOutput->SetCurrentPosition( 0 );
// Find out where the capture buffer is right now, then write data
// some extra amount forward to make sure we're ahead of the write cursor
pDSBCapture->GetCurrentPosition( &dwNextCaptureOffset, NULL );
dwNextCaptureOffset -= dwNextCaptureOffset % dwNotifySize;
dwNextOutputOffset = dwNextCaptureOffset + ( dwNotifySize << 1);
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
// Tell the capture buffer to start recording
pDSBCapture->Start( DSCBSTART_LOOPING );
// Rewind the output buffer, fill it with silence, and play it
pDSBOutput->SetCurrentPosition( dwNextOutputOffset );
// Save the format of the capture buffer in g_pCaptureWaveFormat
ZeroMemory( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX) );
pDSBCapture->GetFormat( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX), NULL );
// Get the format of the output buffer
ZeroMemory( &wfxOutput, sizeof(wfxOutput) );
pDSBOutput->GetFormat( &wfxOutput, sizeof(wfxOutput), NULL );
// Fill the output buffer with silence at first
// As capture data arrives, HandleNotifications() will fill
// the output buffer with wave data.
if( FAILED( hr = pDSBOutput->Lock( 0, dwOutputBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( wfxOutput.wBitsPerSample == 8 ? 128 : 0 ) );
pDSBOutput->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL );
// Play the output buffer
pDSBOutput->Play( 0, 0, DSBPLAY_LOOPING );
return S_OK;
}
HRESULT __fastcall TDSFilter::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSBuffer, BOOL* pbRestored )
{
HRESULT hr;
if( pbRestored) *pbRestored = FALSE;
if( !pDSBuffer ) return S_FALSE;
DWORD dwStatus;
if( FAILED( hr = pDSBuffer->GetStatus( &dwStatus ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do {
hr = pDSBuffer->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
} while( ( hr = pDSBuffer->Restore() ) == DSERR_BUFFERLOST );
if( pbRestored) *pbRestored = TRUE;
return S_OK;
} else return S_FALSE;
}
HRESULT __fastcall TDSFilter::HandleNotification()
{
HRESULT hr;
VOID* pDSCaptureLockedBuffer = NULL;
VOID* pDSOutputLockedBuffer = NULL;
DWORD dwDSCaptureLockedBufferSize;
DWORD dwDSOutputLockedBufferSize;
DWORD dwStatus;
// Make sure buffers were not lost, if the were we need
// to start the capture again
if( FAILED( hr = pDSBOutput->GetStatus( &dwStatus))) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );
if( dwStatus & DSBSTATUS_BUFFERLOST ) {
if( FAILED( hr = StartBuffers())) return DXTRACE_ERR_MSGBOX( TEXT("StartBuffers"), hr );
return S_OK;
}
// Lock the capture buffer down
if( FAILED( hr = pDSBCapture->Lock( dwNextCaptureOffset, dwNotifySize, &pDSCaptureLockedBuffer,
&dwDSCaptureLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// Lock the output buffer down
if( FAILED( hr = pDSBOutput->Lock( dwNextOutputOffset, dwNotifySize, &pDSOutputLockedBuffer,
&dwDSOutputLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// These should be equal
if( dwDSOutputLockedBufferSize != dwDSCaptureLockedBufferSize ) return E_FAIL; // Sanity check unhandled case
// Just copy the memory from the
// capture buffer to the playback buffer
Process( (short*) pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize) ;
CopyMemory( pDSOutputLockedBuffer, pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize );
// Unlock the play buffer
pDSBOutput->Unlock( pDSOutputLockedBuffer, dwDSOutputLockedBufferSize, NULL, 0 );
// Unlock the capture buffer
pDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize, NULL, 0 );
// Move the capture offset along
dwNextCaptureOffset += dwDSCaptureLockedBufferSize;
dwNextCaptureOffset %= dwCaptureBufferSize; // Circular buffer
// Move the playback offset along
dwNextOutputOffset += dwDSOutputLockedBufferSize;
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer
return S_OK;
}
I would really appreciate your help.
Thanks.