//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
//
// File:FDAUDIO.CPP
// Contents:Audio related routines for full-duplex device usage
//
// Description:This file includes functionality for enumerating devices &
//formats, initializing devices and buffers, and the CALLBACK
//procedures for dealing with full duplex.
//
// So we can get the IID_IDirectSoundNotify and GUID_NULL GUID declared
#defineINITGUID
#include <objbase.h>
#include <cguid.h>
#include "fdfilter.h"
#include "fdaudio.h"
#include "filter.h"
static BOOL IsDSDeviceInList(LPGUID, PDSDEVICEDESC );
static BOOL EnumDSDevices( void );
static BOOL EnumDSCDevices( void );
static BOOL CALLBACK DSEnumProc( LPGUID, LPCSTR, LPCSTR, LPVOID );
static BOOL InitInputDevice(void);
static BOOL InitPrimarySoundBuffer( void );
static void ProcessInput( DWORD );
extern HINSTANCE g_hDSoundLib;
typedef HRESULT (WINAPI * PFN_DSCREATE)(LPGUID lpguid, LPDIRECTSOUND * ppDS, IUnknown FAR * pUnkOuter);
typedef BOOL (WINAPI * PFN_DSENUMERATE)(LPDSENUMCALLBACK lpDSEnumCallback, LPVOID lpContext);
typedef HRESULT (WINAPI * PFN_DSCCREATE)(LPGUID lpGUID,LPDIRECTSOUNDCAPTURE *lplpDSC,LPUNKNOWN pUnkOuter);
typedef BOOL (WINAPI * PFN_DSCENUMERATE)(LPDSENUMCALLBACK lpDSEnumCallback,LPVOID lpContext);
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
static BOOL InitSoundData( BOOL fAllowFormatCancel, BOOL fReset )
{
if( NULL == gpwfxOutput )
{
gpwfxOutput = new WAVEFORMATEX;
if( NULL == gpwfxOutput )
goto ISD_Fail;
ZeroMemory( gpwfxOutput, sizeof(WAVEFORMATEX));
gpwfxOutput->wFormatTag = WAVE_FORMAT_PCM;
DPF( 3, "Created gpwfxOutput" );
DPWFX( 3, gpwfxOutput );
}
if( NULL == gpwfxInput )
{
gpwfxInput = new WAVEFORMATEX;
if( NULL == gpwfxInput )
goto ISD_Fail;
ZeroMemory( gpwfxInput, sizeof(WAVEFORMATEX));
gpwfxInput->wFormatTag = WAVE_FORMAT_PCM;
DPF( 3, "Created gpwfxInput" );
DPWFX( 3, gpwfxInput );
}
EnumDSDevices();
if( NULL == gpdsddOutputDevices )
{
MessageBox( ghMainWnd, "No DirectSound devices are available!", gszAppName, MB_OK );
goto ISD_Fail;
}
EnumDSCDevices();
if( NULL == gpdsddInputDevices )
{
MessageBox( ghMainWnd, "No DirectSoundCapture devices are available!", gszAppName, MB_OK );
goto ISD_Fail;
}
if( !DialogBox( ghInst, MAKEINTRESOURCE(IDD_DEVICES),
ghMainWnd, (DLGPROC)SelectDevicesDlgProc ))
goto ISD_Fail;
if( fReset )
{
StopBuffers();
DestroyBuffers();
CloseDSCDevice(FALSE);
CloseDSDevice();
}
if( !InitPrimarySoundBuffer())
goto ISD_Fail;
if( !InitInputDevice() )
goto ISD_Fail;
if( !DialogBoxParam( ghInst, MAKEINTRESOURCE(IDD_FORMATS),
ghMainWnd, (DLGPROC)SelectFormatsDlgProc,
(LPARAM)fAllowFormatCancel ))
goto ISD_Fail;
return TRUE;
ISD_Fail:
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL InitSoundDevices( BOOL fAllowFormatCancel )
{
inti;
DWORDdwThreadID;
ZeroMemory(grgEventNotify, sizeof(grgEventNotify));
for( i = 0; i < NUM_EVENTS; i++ )
{
grgEventNotify[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
if( NULL == grgEventNotify[i] )
goto ISD_Fail;
}
ghThread = CreateThread( NULL, 0, ThreadProcessInput,
NULL, 0, &dwThreadID );
if( NULL == ghThread )
goto ISD_Fail;
return InitSoundData( fAllowFormatCancel, FALSE );
ISD_Fail:
return FALSE;
}
BOOL ReOpenSoundDevices( BOOL fAllowFormatCancel )
{
return InitSoundData( fAllowFormatCancel, TRUE );
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
static BOOL IsDSDeviceInList( LPGUID lpguidDevice, PDSDEVICEDESC pdsddList )
{
PDSDEVICEDESC pdsdd = pdsddList;
while( pdsdd )
{
// This works because operator== is overloaded for GUIDS
if( NULL == lpguidDevice )
{
if( pdsdd->guDevice == GUID_NULL )
return TRUE;
}
else if( pdsdd->guDevice == *lpguidDevice )
return TRUE;
pdsdd = pdsdd->pNext;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// EnumDSDevices()
//
// Enumerates the DirectSound devices with the help of DirectSoundEnumerate
// and DSEnumProc. Adds entries to a global list about each device.
//
static BOOL EnumDSDevices( void )
{
PFN_DSENUMERATE pfn_DSEnumerate;
// Get a pointer to DirectSoundEnumerate()
pfn_DSEnumerate = (PFN_DSENUMERATE)GetProcAddress(g_hDSoundLib, "DirectSoundEnumerateA");
if (pfn_DSEnumerate == NULL)
{
MessageBox(ghMainWnd, "DSOUND.DLL does not implement DirectSoundEnumerate()", gszAppName, MB_OK);
}
else
{
(*pfn_DSEnumerate)(DSEnumProc, &gpdsddOutputDevices);
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// EnumDSCDevices()
//
// Enumerates the DirectSoundCapture devices with the help of
// DirectSoundCaptureEnumerate and DSEnumProc.
// Adds entries to a global list about each device.
//
static BOOL EnumDSCDevices( void )
{
PFN_DSCENUMERATE pfn_DSCEnumerate;
// Get a pointer to DirectSoundEnumerate()
pfn_DSCEnumerate = (PFN_DSCENUMERATE)GetProcAddress(g_hDSoundLib, "DirectSoundCaptureEnumerateA");
if (pfn_DSCEnumerate == NULL)
{
MessageBox(ghMainWnd, "DSOUND.DLL does not implement DirectSoundCaptureEnumerate(). The system may not have DirectX 5.0 installed.", gszAppName, MB_OK);
}
else
{
(*pfn_DSCEnumerate)(DSEnumProc, &gpdsddInputDevices);
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// InitInputDevice()
//
// Creates and initializes the input device for the application.
//
static BOOL InitInputDevice( void )
{
HRESULTdsrval;
PFN_DSCCREATEpfn_DSCCreate;
// create a DirectSoundCapture object.
pfn_DSCCreate = (PFN_DSCCREATE)GetProcAddress(g_hDSoundLib, "DirectSoundCaptureCreate");
if (pfn_DSCCreate == NULL)
{
MessageBox(ghMainWnd, "DSOUND.DLL does not implement DirectSoundCaptureCreate(). The system may not have DirectX 5.0 installed.", gszAppName, MB_OK);
goto IID_ExitError;
}
else
{
if (FAILED(dsrval = (*pfn_DSCCreate)(&gpdsddIn->guDevice, &gpdsc, NULL)))
{
DPF( 0, "Couldn't open DirectSoundCapture device (%s)", TranslateDSError(dsrval));
goto IID_ExitError;
}
}
return TRUE;
IID_ExitError:
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// InitPrimarySoundBuffer()
//
// Creates and initializes the primary sound buffer for the application.
// We need the primary buffer in order to get the 3D listener interface and
// also to select output format type.
//
static BOOL InitPrimarySoundBuffer( void )
{
HRESULT dsrval;
DSBUFFERDESC dsbd;
PFN_DSCREATEpfn_DSCreate;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
// Create a directsound object.
pfn_DSCreate = (PFN_DSCREATE)GetProcAddress(g_hDSoundLib, "DirectSoundCreate");
if (pfn_DSCreate == NULL)
{
MessageBox(ghMainWnd, "DSOUND.DLL does not implement DirectSoundCreate()", gszAppName, MB_OK);
goto IPSB_ExitError;
}
else
{
if (FAILED(dsrval = (*pfn_DSCreate)(&gpdsddOut->guDevice, &gpds, NULL)))
{
DPF( 0, "Couldn't open DirectSound device (%s)", TranslateDSError(dsrval));
goto IPSB_ExitError;
}
}
if( FAILED( dsrval = gpds->SetCooperativeLevel( ghMainWnd, DSSCL_PRIORITY )))
{
DPF( 0, "Couldn't get PRIORITY cooperative level (%s)", TranslateDSError(dsrval));
goto IPSB_ExitError;
}
if( FAILED( dsrval = gpds->CreateSoundBuffer( &dsbd, &gpdsbPrimary, NULL )))
{
DPF( 0, "Couldn't create primary buffer (%s)", TranslateDSError(dsrval));
goto IPSB_ExitError;
}
return TRUE;
IPSB_ExitError:
if( NULL != gpdsbPrimary )
{
DPF( 1, "Releasing Primary in InitPrimarySoundBuffer() error cleanup" );
gpdsbPrimary->Release();
gpdsbPrimary = NULL;
}
if( NULL != gpds )
{
DPF( 1, "Releasing DSound object in InitPrimarySoundBuffer() error cleanup" );
gpds->Release();
gpds= NULL;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// DSEnumProc()
//
// DirectSoundXXXEnumerate() callback procedure which fills the DSDEVICEDESC list
// with data about available devices.
//
static BOOL CALLBACK DSEnumProc( LPGUID lpguidDevice, LPCSTR lpszDesc,
LPCSTR lpszDrvName, LPVOID lpContext )
{
PDSDEVICEDESC pdsddNew;
PDSDEVICEDESC *ppdsddList = (PDSDEVICEDESC *)lpContext;
if( !IsDSDeviceInList( lpguidDevice, *ppdsddList ))
{
if(( pdsddNew = new DSDEVICEDESC ) == NULL )
{
return TRUE;
}
ZeroMemory( pdsddNew, sizeof(DSDEVICEDESC));
if( NULL != lpguidDevice )
pdsddNew->guDevice = *lpguidDevice;
else
pdsddNew->guDevice = GUID_NULL;
if(( pdsddNew->pszDeviceDesc = new char[lstrlen(lpszDesc)+1]) == NULL )
{
delete pdsddNew;
return TRUE;
}
lstrcpy( pdsddNew->pszDeviceDesc, lpszDesc );
pdsddNew->pNext = *ppdsddList;
*ppdsddList = pdsddNew;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void ClearDSDeviceList( PDSDEVICEDESC *ppdsdd )
{
PDSDEVICEDESC pdsddCur, pdsddTemp;
pdsddCur = *ppdsdd;
while( pdsddCur )
{
if( NULL != pdsddCur->pszDeviceDesc )
delete[] pdsddCur->pszDeviceDesc;
pdsddTemp = pdsddCur->pNext;
delete pdsddCur;
pdsddCur = pdsddTemp;
}
*ppdsdd = NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void FillDeviceCombo( HWND hCombo, PDSDEVICEDESC pdsddDevices )
{
PDSDEVICEDESC pdsdd = pdsddDevices;
int idx;
if( NULL == hCombo )
return;
while( pdsdd )
{
idx = ComboBox_InsertString( hCombo, -1, pdsdd->pszDeviceDesc );
ComboBox_SetItemData( hCombo, idx, pdsdd );
pdsdd = pdsdd->pNext;
}
if( NULL != pdsddDevices )
ComboBox_SetCurSel( hCombo, 0 );
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void ScanAvailableDSFormats( void )
{
WAVEFORMATEX wfx;
HRESULT dsrval;
HCURSOR hCursor;
int i;
DPF( 3, "Scanning %u DirectSound formats for availability", NUM_FORMATCODES );
if( NULL == gpds || NULL == gpdsbPrimary )
{
for( i = 0; i < NUM_FORMATCODES; i++ )
aOutputFormats[i].fEnabled = FALSE;
return;
}
// This might take a second or two, so throw up the hourglass
hCursor = GetCursor();
SetCursor( LoadCursor( NULL, IDC_WAIT ));
ZeroMemory( &wfx, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
for( i = 0; i < NUM_FORMATCODES; i++ )
{
FormatCodeToWFX( aOutputFormats[i].dwCode, &wfx );
if( FAILED( dsrval = gpdsbPrimary->SetFormat( &wfx )))
{
DPF( 5, "Failed with SetFormat() for %u format", aOutputFormats[i].dwCode );
aOutputFormats[i].fEnabled = FALSE;
}
else
{
DPF( 5, "Succeeded with SetFormat() for %u format", aOutputFormats[i].dwCode );
aOutputFormats[i].fEnabled = TRUE;
}
}
SetCursor( hCursor );
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void ScanAvailableDSCFormats( void )
{
WAVEFORMATEX wfx;
HRESULT dsrval;
HCURSOR hCursor;
int i;
DSCBUFFERDESCdscbd;
LPDIRECTSOUNDCAPTUREBUFFERpdscb;
DPF( 3, "Scanning %u DirectSoundCapture formats for availability", NUM_FORMATCODES );
if( NULL == gpdsc )
{
for( i = 0; i < NUM_FORMATCODES; i++ )
aInputFormats[i].fEnabled = FALSE;
return;
}
// This might take a second or two, so throw up the hourglass
hCursor = GetCursor();
SetCursor( LoadCursor( NULL, IDC_WAIT ));
for( i = 0; i < NUM_FORMATCODES; i++ )
aOutputFormats[i].fEnabled = FALSE;
ZeroMemory( &wfx, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
for( i = 0; i < NUM_FORMATCODES; i++ )
{
FormatCodeToWFX( aInputFormats[i].dwCode, &wfx );
ZeroMemory(&dscbd, sizeof(dscbd));
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.lpwfxFormat = &wfx;
pdscb = NULL;
if ((dsrval = gpdsc->CreateCaptureBuffer(&dscbd, &pdscb, NULL)))
{
DPF( 5, "Failed with DirectSoundCapture::CreateCaptureBuffer() for %u format", aInputFormats[i].dwCode );
aInputFormats[i].fEnabled = FALSE;
}
else
{
DPF( 5, "Succeeded with DirectSoundCapture::CreateCaptureBuffer() for %u format", aInputFormats[i].dwCode );
pdscb->Release();
aInputFormats[i].fEnabled = TRUE;
}
}
SetCursor( hCursor );
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void CloseDSDevice( void )
{
if( NULL != gpdsbOutput )
{
gpdsbOutput->Release();
gpdsbOutput = NULL;
}
if( NULL != gpdsbPrimary )
{
gpdsbPrimary->Release();
gpdsbPrimary = NULL;
}
if( NULL != gpds )
{
gpds->Release();
gpds = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
void CloseDSCDevice( BOOL fBufferOnly )
{
if( NULL != gpdscbInput )
{
gpdscbInput->Release();
gpdscbInput = NULL;
}
if( (NULL != gpdsc) && !fBufferOnly )
{
gpdsc->Release();
gpdsc = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL InitBuffers( void )
{
HRESULT dsrval;
inti;
LPDIRECTSOUNDNOTIFYpdsn;
if( gfBuffersInitialized )
return TRUE;
if (NULL == gpdscbInput)
return FALSE;
EnterCriticalSection( &gcsBufferData );
ZeroMemory(grgdsbpn, sizeof(grgdsbpn));
for( i = 0; i < NUM_BUFFERS; i++ )
{
grgdsbpn[i].dwOffset = (gcbBufferSize * i) + gcbBufferSize - 1;
grgdsbpn[i].hEventNotify = grgEventNotify[i];
}
grgdsbpn[i].dwOffset = DSBPN_OFFSETSTOP;
grgdsbpn[i].hEventNotify = grgEventNotify[i];
if( FAILED( dsrval = gpdscbInput->QueryInterface(IID_IDirectSoundNotify, (LPVOID *)&pdsn ) ) )
{
DPF( 0, "Unable to QI for IDirectSoundNotify on input (%s)", TranslateDSError(dsrval));
goto Abort_InitBuffers;
}
dsrval = pdsn->SetNotificationPositions(NUM_POSNOTIFS, grgdsbpn);
pdsn->Release();
if( FAILED( dsrval ) )
{
DPF( 0, "Unable to SetNotificationPositions on input (%s)", TranslateDSError(dsrval));
goto Abort_InitBuffers;
}
ZeroMemory( &gdsbdOutput, sizeof(gdsbdOutput));
gdsbdOutput.dwSize = sizeof(gdsbdOutput);
gdsbdOutput.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
gdsbdOutput.dwBufferBytes = NUM_BUFFERS * gcbBufferSize / 2;
// We want the format of this secondary to match the format of the input
// data. This lets us blindly copy the data out and DSound worries about
// matching the bits and channels to our desired primary buffer format.
gdsbdOutput.lpwfxFormat = gpwfxInput;
if( FAILED( dsrval = gpds->CreateSoundBuffer( &gdsbdOutput, &gpdsbOutput, NULL )))
{
DPF( 0, "Unable to create sound buffer for output (%s)", TranslateDSError(dsrval));
goto Abort_InitBuffers;
}
InterlockedExchange( &gfBuffersInitialized, TRUE );
LeaveCriticalSection( &gcsBufferData );
return TRUE;
Abort_InitBuffers:
// TODO: If there were any buffers put out, we must Reset to get them back
ASSERT( DestroyBuffers());
LeaveCriticalSection( &gcsBufferData );
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL StartBuffers( void )
{
if( NULL == gpdscbInput || NULL == gpdsbOutput )
return FALSE;
gpdscbInput->Start( DSCBSTART_LOOPING );
// Rewind the output buffer, fill it with silence, and play it
gpdsbOutput->SetCurrentPosition( 0 );
WriteSilenceToOutput( 0, gdsbdOutput.dwBufferBytes );
gpdsbOutput->Play( 0, 0, DSBPLAY_LOOPING );
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL StopBuffers( void )
{
if( NULL == gpdscbInput || NULL == gpdsbOutput )
return FALSE;
gpdscbInput->Stop();
gpdsbOutput->Stop();
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL DestroyBuffers( void )
{
ZeroMemory( grgdsbpn, sizeof(grgdsbpn) );
if( NULL != gpdsbOutput )
{
gpdsbOutput->Release();
gpdsbOutput = NULL;
}
InterlockedExchange( &gfBuffersInitialized, FALSE );
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//
BOOL WriteSilenceToOutput( DWORD dwStart, DWORD cbLength )
{
PBYTE pb1, pb2;
DWORD cb1, cb2;
if(( !dwStart && !cbLength ) || NULL == gpdsbOutput
|| NULL == gdsbdOutput.lpwfxFormat )
return FALSE;
if( SUCCEEDED( gpdsbOutput->Lock( dwStart, cbLength, (LPVOID*)&pb1, &cb1, (LPVOID*)&pb2, &cb2, 0 )))
{
FillMemory( pb1, cb1, (gdsbdOutput.lpwfxFormat->wBitsPerSample == 8) ? 128 : 0 );
if( NULL != pb2 && cb2 )
FillMemory( pb2, cb2, (gdsbdOutput.lpwfxFormat->wBitsPerSample == 8) ? 128 : 0 );
gpdsbOutput->Unlock( pb1, cb1, pb2, cb2 );
return TRUE;
}
return FALSE;
}
static void ProcessInput( DWORD iEvent )
{
staticDWORD dwWritePosition = 0xFFFFFFFF;
HRESULTdsrval;
PBYTEpb1, pb2;
DWORDcb1, cb2;
BOOLfRestoredBuffer = FALSE;
LPBYTEpbInput1 = NULL;
DWORDcbInput1;
LPBYTEpbInput2;
DWORDcbInput2;
DWORDibInputStart;
DWORDcbInputEnd;
if( NULL == gpdscbInput )
{
return;
}
EnterCriticalSection( &gcsBufferData );
if( NUM_BUFFERS == iEvent )
{
dwWritePosition = 0xFFFFFFFF;
goto WIC_SkipDataProcessing;
}
else if( iEvent > 0 )
{
ibInputStart = grgdsbpn[iEvent-1].dwOffset+1;
}
else
{
ibInputStart = 0;
}
cbInputEnd = grgdsbpn[iEvent].dwOffset + 1 - ibInputStart;
dsrval = gpdscbInput->Lock(ibInputStart, cbInputEnd,
(LPVOID *)&pbInput1, &cbInput1, (LPVOID *)&pbInput2, &cbInput2, 0);
if( FAILED(dsrval) )
{
DPF( 0, "Couldn't Lock input buffer. (%s)", TranslateDSError(dsrval));
goto WIC_SkipDataProcessing;
}
if( (NULL != pbInput2) || (0 != cbInput2) )
{
DPF( 0, "Second input buffer pointer is non-NULL");
}
if( NULL != gpdsbOutput )
{
DWORD dwStatus;
if( FAILED( dsrval = gpdsbOutput->GetStatus( &dwStatus )))
{
DPF( 0, "Unable to get buffer status. (%s)", TranslateDSError(dsrval));
goto WIC_SkipDataProcessing;
}
if( dwStatus & DSBSTATUS_BUFFERLOST )
{
if( FAILED( dsrval = gpdsbOutput->Restore()))
{
DPF( 0, "Couldn't Restore output buffer. (%s)", TranslateDSError(dsrval));
goto WIC_SkipDataProcessing;
}
dwWritePosition = 0;
fRestoredBuffer = TRUE;
}
else
{
if( dwWritePosition == 0xFFFFFFFF )
{
DWORDdwPlay, dwWrite;
gpdsbOutput->GetCurrentPosition( &dwPlay, &dwWrite );
// Need to add some extra to make sure we're ahead
// of the write cursor
dwWritePosition = dwWrite + (2*gcbBufferSize);
while( dwWritePosition >= gdsbdOutput.dwBufferBytes )
dwWritePosition -= gdsbdOutput.dwBufferBytes;
}
}
if( SUCCEEDED( gpdsbOutput->Lock( dwWritePosition,
cbInput1,
(LPVOID *)&pb1, &cb1, (LPVOID *)&pb2, &cb2, 0 )))
{
if( NULL != pb1 && NULL != gpFilter )
{
gpFilter->Transform( pbInput1, cb1, pb1 );
}
if( cb2 && NULL != pb2 && NULL != gpFilter )
{
gpFilter->Transform( pbInput1 + cb1,
cbInput1 - cb1, pb2 );
}
gpdsbOutput->Unlock( pb1, cb1, pb2,
cbInput1 - cb1 );
dwWritePosition += cbInput1;
while( dwWritePosition >= gdsbdOutput.dwBufferBytes )
dwWritePosition -= gdsbdOutput.dwBufferBytes;
}
if( fRestoredBuffer )
{
gpdsbOutput->SetCurrentPosition( 0 );
if( FAILED( dsrval = gpdsbOutput->Play( 0, 0, DSBPLAY_LOOPING )))
DPF( 0, "Unable to restart restored buffer. (%s)", TranslateDSError(dsrval));
dwWritePosition = 0xFFFFFFFF;
}
}
WIC_SkipDataProcessing:
if( NULL != pbInput1 )
gpdscbInput->Unlock(pbInput1, cbInput1, pbInput2, cbInput2);
LeaveCriticalSection( &gcsBufferData );
}
DWORD WINAPI ThreadProcessInput( LPVOID )
{
DWORDdwResult;
while( TRUE )
{
dwResult = WaitForMultipleObjects( NUM_EVENTS, grgEventNotify,
FALSE, INFINITE );
// Terminate processing?
if( (WAIT_OBJECT_0 + iEventTerminate) == dwResult )
{
break;
}
if( (WAIT_OBJECT_0 <= dwResult) && (dwResult <= (WAIT_OBJECT_0 + iEventReset)) )
{
ProcessInput( dwResult - WAIT_OBJECT_0 );
}
}
return 0;
}