Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3497 lines
97 KiB

//--------------------------------------------------------------------------;
//
// File: DSoundHW.c
//
// Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
//
// Abstract:
//
//
// Contents:
// IDSHWQueryInterface()
// IDSHWAddRef()
// IDSHWRelease()
// IDSHWCreateSoundBuffer()
// IDSHWEnumSoundBuffers()
// IDSHWGetCaps()
// IDSHWDuplicateSoundBuffer()
// IDSHWSetCooperativeLevel()
// IDSHWCompact();
// IDSHWGetSpeakerConfig()
// IDSHWSetSpeakerConfig()
// IDSHWInitialize()
// DSHWCreateTable()
// GetTopUnownedWindow() added by angusm on 11/27/95
// CreateFocusThread() added by angusm on 12/1/95
// cSoundObjects() added by angusm on 11/30/95
//
// History:
// Date By Reason
// ==== == ======
// 3/5/96 angusm Added use of fInitialized
// 03/20/06 angusm Added support for Sticky Focus
//
//--------------------------------------------------------------------------;
#include "dsoundpr.h"
#ifndef DSBLD_EMULONLY
#include <pbt.h>
#endif
#include "grace.h"
#include "flocks.h"
/* Global Constansts */
#define POLL_INTERVAL 250 /* number of miliseconds between polls
* for active window */
#define WAKEFOCUSTHREAD "DSWakeFocusThread" /* event name for Focus Thread
* event. */
#define FOCUSSTARTUPEVENT "DSFocusStartupEvent" /* event name for handshake
* after Focus Thread
* startup code */
/* Function Prototypes */
HWND GetTopUnownedWindow (HWND hWindow);
BOOL IsValidDSApp (DWORD dwTid);
void EndFocusThread();
DWORD WINAPI FocusTracker (LPVOID lpvPollInterval);
__inline void DseUpdateActivationState (LPDSOUNDEXTERNAL pdse);
__inline void DsbeDeactivateIfNecessary (LPDSBUFFEREXTERNAL);
__inline void ActivateFocusWindow (void);
// From DirectDraw - for subclassing
extern HRESULT _stdcall DSoundHelp( HWND hWnd,WNDPROC lpWndProc,DWORD dwPID );
LRESULT CALLBACK SubclassWndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam );
LPDSOUNDINFO gpdsinfo;
//--------------------------------------------------------------------------;
//
// HRESULT DseVerifyValidFormat
//
// Description:
// This function returns DS_OK if the specified format is valid for
// this sound device.
//
//--------------------------------------------------------------------------;
HRESULT DseVerifyValidFormat
(
LPDSOUNDEXTERNAL pdse,
LPWAVEFORMATEX pwfx
)
{
DSCAPS dsc;
HRESULT hr;
ZeroMemory(&dsc, sizeof(dsc));
dsc.dwSize = sizeof(dsc);
hr = DsGetCaps (pdse->pds, &dsc);
if (DS_OK != hr) {
return hr;
}
if (WAVE_FORMAT_PCM != pwfx->wFormatTag) return DSERR_BADFORMAT;
if( ( (pwfx->nChannels == 1) &&
!(dsc.dwFlags & DSCAPS_PRIMARYMONO) ) ||
( (pwfx->nChannels == 2) &&
!(dsc.dwFlags & DSCAPS_PRIMARYSTEREO) ) ||
( (pwfx->wBitsPerSample == 8) &&
!(dsc.dwFlags & DSCAPS_PRIMARY8BIT) ) ||
( (pwfx->wBitsPerSample == 16) &&
!(dsc.dwFlags & DSCAPS_PRIMARY16BIT) ) ) {
return DSERR_BADFORMAT;
}
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// HRESULT DseSaveAppFormat
//
// Description:
// This function saves the specified format as the app format in the
// specified dse object.
//
//--------------------------------------------------------------------------;
HRESULT DseSaveAppFormat(LPDSOUNDEXTERNAL pdse, LPWAVEFORMATEX pwfxAppCaller)
{
LPWAVEFORMATEX pwfxApp;
int cbFormat;
cbFormat = SIZEOF_WAVEFORMATEX(pwfxAppCaller);
pwfxApp = (LPWAVEFORMATEX)MemAlloc(cbFormat);
if (NULL == pwfxApp) {
DPF(0, "DseSaveAppFormat: error: Out of memory saving app's format");
return DSERR_OUTOFMEMORY;
}
CopyMemory(pwfxApp, pwfxAppCaller, cbFormat);
if (NULL != pdse->pwfxApp) {
DPF(1, "Freeing previous app format");
MemFree(pdse->pwfxApp);
}
pdse->pwfxApp = pwfxApp;
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// HRESULT IDSHWQueryInterface
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWQueryInterface
(
LPDIRECTSOUND pids,
REFIID riid,
LPVOID FAR* ppvObj
)
{
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::QueryInterface - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
if( 0 == pdse->uRefCount ) {
RPF("IDirectSound::QueryInterface - Invalid ref count");
return DSERR_INVALIDPARAM;
}
if (IDSHWINITIALIZEF_INITIALIZED == pdse->fInitialized) {
ASSERT(VALID_DSOUND_PTR(pdse->pds));
}
if( riid == NULL ) {
RPF("IDirectSound::QueryInterface - NULL riid");
return DSERR_INVALIDPARAM;
}
if( ppvObj == NULL ) {
RPF("IDirectSound::QueryInterface - NULL ppvObj");
return DSERR_INVALIDPARAM;
}
ENTER_DLL_CSECT();
if( IsEqualGUID(riid,&IID_IDirectSound) ||
IsEqualGUID(riid,&IID_IUnknown) ) {
*ppvObj = pdse;
pdse->lpVtbl->AddRef((LPDIRECTSOUND)pdse);
LEAVE_DLL_CSECT();
return DS_OK;
}
else
{
LEAVE_DLL_CSECT();
return DSERR_NOINTERFACE;
}
LEAVE_DLL_CSECT();
return DSERR_GENERIC;
} // IDSHWQueryInterface()
//--------------------------------------------------------------------------;
//
// IDSHWAddRef
//
// Description:
// This function implements the standard IUnknown::AddRef()
//
// Arguments:
// pids "this" pointer
//
// Return (ULONG):
// Estimate of the value of the reference count.
//
// History:
// 02/11/96 angusm Removed need to have (uRefCount != 0)
//
//--------------------------------------------------------------------------;
LONG DsAddRef(LPDSOUND pds)
{
pds->uRefCount++;
return (int)pds->uRefCount;
}
ULONG FAR PASCAL IDSHWAddRef
(
LPDIRECTSOUND pids
)
{
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::AddRef - Invalid Object");
return 0;
}
pdse = (LPDSOUNDEXTERNAL)pids;
if( 0 == pdse->uRefCount) {
RPF("IDirectSound::AddRef - Invalid Object or ref count");
return 0;
}
ENTER_DLL_CSECT();
pdse->uRefCount++;
LEAVE_DLL_CSECT();
return pdse->uRefCount;
} // IDSHWAddRef()
LONG DsRelease(LPDSOUND pds)
{
LPDSOUND pdsList;
LPDSOUND pdsPrev;
HANDLE hMixThread;
if (0 != --pds->uRefCount) {
DPF(3,"DsRelease done, ref count now %X", pds->uRefCount );
ASSERT((LONG)pds->uRefCount > 0);
return pds->uRefCount;
}
DPF(2,"Destroying DirectSound object");
// Free the primary we created
if( pds->pdsbePrimary != NULL ) {
IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)(pds->pdsbePrimary));
}
pds->pdsbePrimary = NULL;
//
if (!(DS_INTERNALF_WAVEEMULATED & pds->fdwInternal)) {
hMixThread = mxTerminate(pds);
} else {
hMixThread = NULL;
}
// Remove it from the list
pdsList = gpdsinfo->pDSoundObj;
pdsPrev = NULL;
while( pdsList != NULL ) {
if( pds == pdsList ) {
if( pdsPrev ) {
// Previous element in list remove it
pdsPrev->pNext = pdsList->pNext;
} else {
// Head of list - remove
gpdsinfo->pDSoundObj = pdsList->pNext;
}
pdsList = NULL;
} else {
pdsPrev = pdsList;
pdsList = pdsList->pNext;
}
}
pds->pNext = NULL;
// If we allocated a heap manager for the driver
if (DSDHEAP_CREATEHEAP == pds->dwHeapType) {
VidMemFini(pds->pDriverHeap);
pds->pDriverHeap = NULL;
}
// Free the Wave Blit structure we use on eumlation
MemFree( pds->pdswb );
// FINI layer to VxD
if( pds->hHal) {
DPF(3,"Close HAL layer %X", pds->hHal );
vxdDrvClose( pds->hHal );
DPF(3,"Finished Close HAL layer" );
}
pds->hHal = INVALID_HANDLE_VALUE;
// Close mmsystem wave handle if we opened one for this driver
if (pds->hwo) {
// ASSERT(DSDDESC_DOMMSYSTEMOPEN & pds->dsDrvDesc.dwFlags);
HelperWaveClose( (DWORD)(pds->hwo) );
pds->hwo = NULL;
}
#ifdef DEBUG
// Validity checking
if(!(pds->fdwInternal & DS_INTERNALF_ALLOCATED)) {
DPF(0,"******* Already Freed dsound HW object ********");
}
if( pds->pdsb != NULL ) {
DPF(0,"******* PDSB != NULL ********");
}
if( pds->pdsbPrimary != NULL ) {
DPF(0,"******* PDSBPrimary != NULL ********");
}
if( pds->hPlaybackThread != NULL ) {
DPF(0,"******* Playback thread != NULL ********");
}
if( pds->hwo != NULL ) {
DPF(0,"******* HWO != NULL ********");
}
if( pds->dwBuffersPlaying != 0 ) {
DPF(0,"******* BuffersPlaying != NULL ********");
}
#endif
pds->dwSig = 0xdeaddead;
MemFree( pds );
DPF(3,"Release done %X ref count now 0", pds);
//
// Wait for mixer thread to die
//
if (NULL != hMixThread) {
DWORD dwResult;
HANDLE hHelper;
HANDLE hMixThreadOurs;
DPF(3, "IDSHWRelease: note: waiting for mixer thread to terminate");
hHelper = OpenProcess(PROCESS_DUP_HANDLE, FALSE, gpdsinfo->pidHelper);
if (hHelper)
{
if (DuplicateHandle(hHelper, hMixThread, GetCurrentProcess(),
&hMixThreadOurs, SYNCHRONIZE | THREAD_TERMINATE,
FALSE, DUPLICATE_CLOSE_SOURCE))
{
dwResult = WaitForSingleObjectEx(hMixThreadOurs, INFINITE, FALSE);
ASSERT(WAIT_OBJECT_0 == dwResult);
dwResult = CloseHandle(hMixThreadOurs);
ASSERT(dwResult);
}
dwResult = CloseHandle(hHelper);
ASSERT(dwResult);
}
}
return 0;
} // DsRelease()
void DseTerminate(LPDSOUNDEXTERNAL pdse)
{
LPDSOUNDEXTERNAL pdseList;
LPDSOUNDEXTERNAL pdsePrev;
HANDLE hFocusLock;
// Now release any buffers this process may have accessed.
// Release all buffers for this process for this object
FreeBuffersForProcess( pdse );
// We use DSoundHelp to give us APM window notifications. If we are
// building only for emulation mode then we don't need APM notifications
// since APM will be handled entirely by the WAVE drivers that we are
// using for emulation.
#ifndef DSBLD_EMULONLY
// Remove the window from the subclass list
// Window is stored by PID
DSoundHelp( NULL, SubclassWndProc, HackGetCurrentProcessId() );
#endif
// Remove it from the list
if (FALSE == GetFocusLock(&hFocusLock)) {
DPF (3, "Could not get Focus Lock");
}
pdseList = gpdsinfo->pDSoundExternalObj;
pdsePrev = NULL;
while( pdseList != NULL ) {
if( pdse == pdseList ) {
if( pdsePrev ) {
// Previous element in list remove it
pdsePrev->pNext = pdseList->pNext;
} else {
// Head of list - remove
gpdsinfo->pDSoundExternalObj = pdseList->pNext;
}
pdseList = NULL;
} else {
pdsePrev = pdseList;
pdseList = pdseList->pNext;
}
}
pdse->pNext = NULL;
if (FALSE == ReleaseFocusLock(hFocusLock)) {
DPF (3, "Could not release Focus Lock.");
}
// If an app wave format was allocated for this, then free it.
if (pdse->pwfxApp) MemFree(pdse->pwfxApp);
pdse->pwfxApp = NULL;
//
DsRelease(pdse->pds);
}
ULONG FAR PASCAL IDSHWRelease(LPDIRECTSOUND pIDs)
{
LPDSOUNDEXTERNAL pdse;
ULONG cRef;
pdse = (LPDSOUNDEXTERNAL)pIDs;
ENTER_DLL_CSECT();
cRef = --pdse->uRefCount;
if (0 == cRef) {
// Check to see if the object is initialized
if (IDSHWINITIALIZEF_UNINITIALIZED != pdse->fInitialized) {
DPF(1, "DseRelease: deleting object %08Xh", pdse);
/* End Focus Thread */
if (1 == cSoundObjects()) EndFocusThread();
DseTerminate(pdse);
pdse->fInitialized = IDSHWINITIALIZEF_UNINITIALIZED;
}
DPF(0, "Freeing pdse %08Xh", pdse);
MemFree( pdse );
}
LEAVE_DLL_CSECT();
return cRef;
}
//--------------------------------------------------------------------------;
//
// HRESULT DseCreateDsbe
//
// Description:
// This function operates on a Dse object to create a Dsb object
//
// Arguments:
//
// Return (HRESULT):
//
//--------------------------------------------------------------------------;
HRESULT DseCreateDsbe
(
LPDSOUNDEXTERNAL pdse,
LPDSBUFFERDESC pdsbd,
LPDSBUFFEREXTERNAL *ppdsbe
)
{
LPDSBUFFER pdsb;
LPDSBUFFEREXTERNAL pdsbe;
LPDSBUFFER pdsb1;
LPDSBUFFEREXTERNAL pdsbe1;
UINT uDevID;
LPDSOUND pds;
DWORD cbMixBufferSize;
DWORD cbFormatSize;
DWORD dw;
DWORD dwForce;
LPDSPROCESS pDSPID;
DSCAPS dsc;
BOOL fTryHardware, fTrySoftware;
HRESULT hr;
HRESULT hrReturn;
DSBUFFERDESC dsbdTemp;
HRESULT hrTemp;
DPF(3,"DseCreateDsbe()");
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
hrReturn = DS_OK;
*ppdsbe = NULL;
dwForce = 0;
uDevID = pds->uDeviceID;
_fmemcpy( &dsbdTemp, pdsbd, sizeof(DSBUFFERDESC));
// If the user wants a primary then it must be Hardware
// If they're trying to force a software primary, fail them
// Set the hardware flag otherwise
// Also set that this buffer can be blt to
// If it's not a request for a primary, then set our internal force flag
if( (dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER) ) {
if( (dsbdTemp.dwFlags & DSBCAPS_LOCSOFTWARE) ) {
RPF("IDirectSound::CreateSoundBuffer - Invalid attempt to force a software primary buffer!");
return DSERR_INVALIDPARAM;
}
dsbdTemp.dwFlags |= DSBCAPS_LOCHARDWARE;
dsbdTemp.dwFlags |= DSBCAPS_CTRLWAVEBLTDST;
// Caller mustn't specify primary specify buffer size.
if ( (0 != dsbdTemp.dwBufferBytes) ) {
RPF("IDirectSound::CreateSoundBuffer - Primary buffers must be created with dwBufferBytes = 0");
return DSERR_INVALIDPARAM;
}
else {
dsbdTemp.dwBufferBytes = DEFAULT_PRIMARY_SIZE;
}
// We don't allow any apps to specify a format for primary buffers.
if (NULL != dsbdTemp.lpwfxFormat) {
RPF("IDirectSound::CreateSoundBuffer - error: app must not specify primary buffer format");
return DSERR_INVALIDCALL;
}
} else {
// NOTE: There is a conflict of motives with these flags: the user is
// telling us what they want to do, but we use them internally to tell
// ourselves what to do, so save off the user's intentions into dwForce
// and then tell them what they actually got at the end of the create
if( (dsbdTemp.dwFlags & DSBCAPS_LOCSOFTWARE) ) {
dsbdTemp.dwFlags &= (~DSBCAPS_LOCSOFTWARE);
dwForce = DSBCAPS_LOCSOFTWARE;
}
else if( (dsbdTemp.dwFlags & DSBCAPS_LOCHARDWARE) ) {
dsbdTemp.dwFlags &= (~DSBCAPS_LOCHARDWARE);
dwForce = DSBCAPS_LOCHARDWARE;
}
}
// Check that buffer has a real size...
if( dsbdTemp.dwBufferBytes <= 4 ) {
RPF("IDirectSound::CreateSoundBuffer - Buffer size too small");
return DSERR_INVALIDPARAM;
}
if( dsbdTemp.dwBufferBytes >= 0x10000000 ) {
RPF("IDirectSound::CreateSoundBuffer - Buffer size too large");
return DSERR_INVALIDPARAM;
}
//
// If the app is creating a primary, and a primary already exists for
// the app, then return the app's existing primary buffer object.
//
if (DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags) {
pdsbe = pdse->pdsbe;
while (NULL != pdsbe) {
if (DSB_INTERNALF_PRIMARY & pdsbe->pdsb->fdwDsbI) break;
pdsbe = pdsbe->pNext;
}
if (NULL != pdsbe) {
//
// If they requested vol control, specify that this pdsbe is allowed.
//
if( dsbdTemp.dwFlags & DSBCAPS_CTRLVOLUME ) {
pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLVOLUMEPRIMARY;
}
//
// If they requested pan control, specify that this pdsbe is allowed.
//
if( dsbdTemp.dwFlags & DSBCAPS_CTRLPAN ) {
pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLPANPRIMARY;
}
// Addref and return pointer to existing buffer
pdsbe->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbe);
*ppdsbe = pdsbe;
return DS_OK;
}
}
// Allocate the dsbe object
pdsbe = (LPDSBUFFEREXTERNAL)MemAlloc(sizeof(DSBUFFEREXTERNAL));
if(NULL == pdsbe) {
DPF(0,"CreateSoundBuffer object (External) alloc fail");
goto CREATE_ERROR_LAST;
}
pdsbe->lpVtbl = gpdsinfo->lpVtblDSb;
pdsbe->pdse = pdse;
pdsbe->uRefCount = 1;
pdsbe->dwPID = GetCurrentProcessId();
pdsbe->dwPriority = pdse->dwPriority;
pdsbe->pNext = pdse->pdsbe;
pdse->pdsbe = pdsbe;
// HACK HACK Multiple Primaries
// Check to see if primary buffer is already allocated.
if( (dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER ) && (pds->pdsbPrimary) ) {
// We are asking for another primary buffer...
DPF(3,"Primary Object already allocated" );
ASSERT( VALID_DSBUFFER_PTR(pds->pdsbPrimary) );
ASSERT( DSBUFFSIG == pds->pdsbPrimary->dwSig );
// Point external object to this primary
pdsb = pds->pdsbPrimary;
pdsbe->pdsb = pds->pdsbPrimary;
// If this is not waveemulated, create an alias pointer to the data
// buffer. Note that this only reserves linear address space.
// Physical memory is committed on Lock.
if (!(pdsb->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
pdsbe->pDSBufferAlias = vxdMemReserveAlias(pdsb->pDSBuffer, pdsb->cbBufferSize);
} else {
pdsbe->pDSBufferAlias = NULL;
}
//
// If they requested vol control, specify that this pdsbe is allowed.
//
if( dsbdTemp.dwFlags & DSBCAPS_CTRLVOLUME ) {
pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLVOLUMEPRIMARY;
}
//
// If they requested pan control, specify that this pdsbe is allowed.
//
if( dsbdTemp.dwFlags & DSBCAPS_CTRLPAN ) {
pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLPANPRIMARY;
}
// Addref existing object and return pointer to it
pdsbe->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbe);
// The refcount on this external primary should be 1 for the create
// But it is now 2 since addref needs a + refcount to work
// So reset it to 1
pdsbe->uRefCount = 1;
DPF(2, "Return buffer ext %X, core %X mem ptr %X size %X",
pdsbe, pdsb, pdsb->pDSBuffer ,pdsb->cbBufferSize );
// If the pdse is in focus and it is WRITEPRIMARY, then the
// primary dsbe for this app should be stopped and so must be
// the internal primary dsb.
//
// We also need to set the internal primary format, even when
// not WRITEPRIMARY.
//
if (pdse->tidSound == gpdsinfo->tidSoundFocus || pdse->tidSound == gpdsinfo->tidStuckFocus) {
HRESULT hr;
if (pdse->dwPriority >= DSSCL_WRITEPRIMARY) {
IDsbStopI(pds->pdsbPrimary, FALSE);
}
if (NULL != pdse->pwfxApp) {
hr = IDsbSetFormatI( pds->pdsbPrimary, pdse->pwfxApp, 0 );
} else {
hr = IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, 0 );
}
if( DS_OK != hr )
{
RPF("IDirectSound::CreateSoundBuffer - Couldn't set primary format when creating primary buffer.");
}
}
DsbeDeactivateIfNecessary (pdsbe);
// Return pointer to new buffer
*ppdsbe = pdsbe;
return DS_OK;
}
// Allocate the dsb object
pdsb = (LPDSBUFFER)MemAlloc(sizeof(DSBUFFER));
if(NULL == pdsb) {
DPF(0,"CreateSoundBuffer object alloc fail");
goto CREATE_ERROR_BUFFEREXTERNAL;
}
pdsb->dwSig = DSBUFFSIG;
DPF(1, "Allocating DSBUFFER obj 0x%8x",pdsb);
// Point external object to this
pdsbe->pdsb = pdsb;
pdsb->fdwBufferDesc = dsbdTemp.dwFlags;
pdsb->dwPrimaryNumber = dsbdTemp.dwReserved; // The reserved field is dwPrimaryNumber
pdsb->cbBufferSize = dsbdTemp.dwBufferBytes;
pdsb->pdsb3d = NULL;
pdsb->pds = pds;
pdsb->fdwDsbI = DSB_INTERNALF_STOP;
pdsb->uRefCount = 1;
pdsb->pNext = pds->pdsb;
pds->pdsb = pdsb;
pdsb->pdsbDuplicateNext = pdsb;
pdsb->pdsbDuplicatePrev = pdsb;
// Set up hack internal use external objct
// This will be used by the mixer for calling
// methods like stop
// It will never be used for addref or release
pdsb->dsbe.lpVtbl = gpdsinfo->lpVtblDSb;
pdsb->dsbe.pdse = pdse;
pdsb->dsbe.uRefCount = 1;
pdsb->dsbe.dwPID = DWBUFFER_INTERNAL_PID;
pdsb->dsbe.pNext = NULL;
pdsb->dsbe.pdsb = pdsb;
pdsb->dsbe.dwPriority = pdse->dwPriority;
// If we are allocating the primary and this is the first primary
// then initialize the ds obj to show the primary
// The DSEPrimary will only be used internally
if( dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER ) {
pds->pdsbPrimary = pdsb;
pdsb->fdwDsbI |= DSB_INTERNALF_PRIMARY;
}
// Alloc Process ID list
pDSPID = (LPDSPROCESS)MemAlloc(sizeof(DSPROCESS));
if(NULL == pDSPID) {
DPF(1,"IDSCreateSoundBuffer process alloc fail");
goto CREATE_ERROR_BUFFER;
}
pDSPID->dwPID = HackGetCurrentProcessId();
pDSPID->dwProcessRefCount = 1;
pDSPID->pNext = NULL;
pdsb->plProcess = pDSPID;
// Get the ds object's caps
dsc.dwSize = sizeof( DSCAPS );
hrTemp = DsGetCaps(pdse->pds, &dsc);
ASSERT (DS_OK == hrTemp);
DPF(3,"Caps Flags from Driver %X free buffers %X",
dsc.dwFlags, dsc.dwFreeHwMixingAllBuffers );
// Allocate a buffer to hold the format
// First get max format size
// HACK HACK - NO Need to bring in ACM just for this...
// Assume size will be reasonable
// If we have a format use that size
// Add on 16 bytes of slop space
// Format may be changed to a larger one
if( dsbdTemp.lpwfxFormat != NULL ) {
dw = SIZEOF_WAVEFORMATEX( dsbdTemp.lpwfxFormat );
cbFormatSize = dw + 16;
} else {
cbFormatSize = SIZEOF_WAVEFORMATEX(&pds->wfxDefault);
}
// Now allocate memory
pdsb->pwfx = (LPWAVEFORMATEX)MemAlloc(cbFormatSize);
if(NULL == pdsb->pwfx) {
DPF(1,"IDSHWCreateSoundBuffer object alloc fail");
goto CREATE_ERROR_PROCESS;
}
// Now copy the format
if( dsbdTemp.lpwfxFormat != NULL ) {
// We have a real format given
DPF(3,"Format Given %X", dsbdTemp.lpwfxFormat );
if( !ValidPCMFormat( dsbdTemp.lpwfxFormat ) ) {
RPF("IDirectSound::CreateSoundBuffer - Not a valid PCM format");
// Note that later on we should handle non pcm formats
hrReturn = DSERR_BADFORMAT;
goto CREATE_ERROR_FORMAT;
}
dw = SIZEOF_WAVEFORMATEX( dsbdTemp.lpwfxFormat );
CopyMemory( pdsb->pwfx, dsbdTemp.lpwfxFormat, dw );
} else {
// Not a real format - set to default for now
// Note this is only possible in the primary case.
DPF(3,"No format create default." );
CopyMemory(pdsb->pwfx, &pds->wfxDefault, SIZEOF_WAVEFORMATEX(&pds->wfxDefault));
}
//Set the helInfo stuff
pdsb->helInfo.dwSampleRate = 0;
pdsb->helInfo.hfFormat = 0;
pdsb->helInfo.lVolume = 0;
pdsb->helInfo.lPan = 0;
pdsb->helInfo.dwLVolume = 0xffff;
pdsb->helInfo.dwRVolume = 0xffff;
pdsb->helInfo.dwMVolume = 0xffff;
// IF there is a format to set
if( pdsb->pwfx->wFormatTag == WAVE_FORMAT_PCM ) {
pdsb->helInfo.dwSampleRate = pdsb->pwfx->nSamplesPerSec;
pdsb->helInfo.hfFormat = 0;
if( pdsb->pwfx->wBitsPerSample == 8 ) {
pdsb->helInfo.hfFormat |= (H_8_BITS | H_UNSIGNED);
} else {
pdsb->helInfo.hfFormat |= (H_16_BITS | H_SIGNED);
}
if( pdsb->pwfx->nChannels == 2 ) {
pdsb->helInfo.hfFormat |= (H_STEREO | H_ORDER_LR);
} else {
pdsb->helInfo.hfFormat |= H_MONO;
}
} else {
DPF(0, "****************** set NON PCM format ******************" );
// Note that later on we should handle non pcm formats
hrReturn = DSERR_BADFORMAT;
goto CREATE_ERROR_FORMAT;
}
pdsb->helInfo.hfFormat |= H_LOOP;
pdsb->fdwDsbI |= DSB_INTERNALF_LOOPING;
// If this buffer is emulated on the WAVE APIs
// then create and use that buffer
if( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) {
if( dwForce & DSBCAPS_LOCHARDWARE )
{
RPF("IDirectSound::CreateSoundBuffer - Can't create a hardware buffer when using wave emulation.");
hrReturn = DSERR_INVALIDCALL;
goto CREATE_ERROR_FORMAT;
}
// If the WAVEBLTDST flag is not set, you are not allowed
// to WaveBlt into this buffer!
if(!( dsbdTemp.dwFlags & DSBCAPS_CTRLWAVEBLTDST )) {
// We will not need a mix buffer
pdsb->pMixBuffer = NULL;
} else {
// Buffer will have stuff mixed into it....
// Default mix buffer size of 32 K.
cbMixBufferSize = 0x00008000;
pdsb->cbMixBufferSize = cbMixBufferSize;
pdsb->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
if(NULL == pdsb->pMixBuffer) {
DPF(1,"IDSHWCreateSoundBuffer mix buffer alloc fail");
goto CREATE_ERROR_FORMAT;
}
}
hr = WaveEmulateCreateSoundBuffer( pds, pdsb, &dsbdTemp );
// Set the grace mixer info
pdsb->cSamples = pdsb->cbBufferSize / pdsb->pwfx->nBlockAlign;
switch (pdsb->pwfx->nBlockAlign) {
case 1:
pdsb->uBlockAlignShift = 0;
break;
case 2:
pdsb->uBlockAlignShift = 1;
break;
case 4:
pdsb->uBlockAlignShift = 2;
break;
default:
// Unsupported block align
ASSERT(FALSE);
}
// For emulated primary buffers, we don't use an alias,
// we use the real thing
pdsbe->pDSBufferAlias = NULL;
DsbeDeactivateIfNecessary (pdsbe);
*ppdsbe = pdsbe;
if( hr == DS_OK ) {
return DS_OK;
} else {
hrReturn = hr;
goto CREATE_ERROR_MIX;
}
}
DPF(3," Check for try HW buffers %ld ", dsc.dwFreeHwMixingAllBuffers );
if (!(DSBCAPS_LOCSOFTWARE & dwForce)) {
// if it's static, see if there are _any_ free HwMixingBuffers,
// otherwise see if there are any free _streaming_ buffers
if ( ((DSBCAPS_STATIC & dsbdTemp.dwFlags) && (dsc.dwFreeHwMixingAllBuffers > 0)) ||
(dsc.dwFreeHwMixingStreamingBuffers > 0) )
{
DPF(3," Check for try HW FLAGS %X ", dsc.dwFlags );
DPF(3," Check for try HW format chann %d ", pdsb->pwfx->nChannels);
DPF(3," Check for try HW format bits %d ",pdsb->pwfx->wBitsPerSample);
// Card has secondary buffers in HW
if( ( ( (pdsb->pwfx->nChannels == 1) &&
(dsc.dwFlags & DSCAPS_SECONDARYMONO) ) ||
( (pdsb->pwfx->nChannels == 2) &&
(dsc.dwFlags & DSCAPS_SECONDARYSTEREO) ) ) &&
( ( (pdsb->pwfx->wBitsPerSample == 8) &&
(dsc.dwFlags & DSCAPS_SECONDARY8BIT) ) ||
( (pdsb->pwfx->wBitsPerSample == 16) &&
(dsc.dwFlags & DSCAPS_SECONDARY16BIT) ) ) )
{
// Card can support mono/stereo format requested
// Card can support 8/16 bit format requested
DPF(3," Try a hardware buffer" );
// If it was a primary this flag was already set
dsbdTemp.dwFlags |= DSBCAPS_LOCHARDWARE;
}
}
}
//
// Check whether this is a primary or HW buffer. If
// so then try to use the HAL code
//
fTryHardware = (0 != (dsbdTemp.dwFlags & DSBCAPS_LOCHARDWARE));
fTrySoftware = !(DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags) &&
!(DSBCAPS_LOCHARDWARE & dwForce);
if (!fTryHardware && !fTrySoftware) {
hrReturn = DSERR_INVALIDCALL;
goto CREATE_ERROR_FORMAT;
}
if (fTryHardware) {
// in order to implement sound focus with secondary hardware
// buffers, we need CTRLVOLUME on them.
if (0 == (DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags)) {
dsbdTemp.dwFlags |= DSBCAPS_CTRLVOLUME;
}
hrReturn = DsCreateHardwareBuffer(pds, pdsb, &dsbdTemp, &fTrySoftware);
if (DS_OK == hrReturn) fTrySoftware = FALSE;
}
if (fTrySoftware) hrReturn = DsCreateSoftwareBuffer(pds, pdsb, &dsbdTemp);
if (DS_OK != hrReturn) goto CREATE_ERROR_FORMAT;
//
// If the creating app doesn't have sound focus then we need to
// immediately deactivate the new buffer
//
DsbeDeactivateIfNecessary (pdsbe);
//
//
//
DsbFillSilence( pdsb );
// If the WAVEBLTDST flag is not set, you are not allowed
// to WaveBlt into this buffer!
if(!( dsbdTemp.dwFlags & DSBCAPS_CTRLWAVEBLTDST )) {
// We will not need a mix buffer
pdsb->pMixBuffer = NULL;
} else {
// Buffer will have stuff mixed into it....
// If we've just created the hardware primary buffer, then let's
// allocate a mixer buffer that is certainly large enough
if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
// May need up to 4X the buffer size
cbMixBufferSize = pdsb->cbBufferSize * 4;
} else {
// Default mix buffer size of 32 K.
cbMixBufferSize = 0x00008000;
}
pdsb->cbMixBufferSize = cbMixBufferSize;
pdsb->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
if(NULL == pdsb->pMixBuffer) {
DPF(1,"IDSHWCreateSoundBuffer mix buffer alloc fail");
goto CREATE_ERROR_MIX;
}
}
// Set the grace mixer info
pdsb->cSamples = pdsb->cbBufferSize / pdsb->pwfx->nBlockAlign;
switch (pdsb->pwfx->nBlockAlign) {
case 1:
pdsb->uBlockAlignShift = 0;
break;
case 2:
pdsb->uBlockAlignShift = 1;
break;
case 4:
pdsb->uBlockAlignShift = 2;
break;
default:
// Unsupported block align
ASSERT(FALSE);
}
// If this is the first buffer for this app, and it wasn't a
// primary buffer, and this app has focus, then we need to set
// the format of the primary buffer.
if ((NULL == pdsbe->pNext) && (!(DSB_INTERNALF_PRIMARY & pdsbe->pdsb->fdwDsbI)))
{
if( pdse->tidSound == gpdsinfo->tidSoundFocus || pdse->tidSound == gpdsinfo->tidStuckFocus ) {
HRESULT hr;
if (NULL != pdse->pwfxApp) {
hr = IDsbSetFormatI( pds->pdsbPrimary, pdse->pwfxApp, 0 );
} else {
hr = IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, 0 );
}
if( DS_OK != hr )
{
DPF( 0, "Couldn't set primary format when creating primary buffer.");
}
}
}
// If this is a primary buffer, then create an alias pointer to the data
// buffer. Note that this only reserves linear address space. Physical
// memory is not commited. For secondary buffers, we use the internal
// buffer ptr.
ASSERT(!(pds->fdwInternal & DS_INTERNALF_WAVEEMULATED));
if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
pdsbe->pDSBufferAlias = vxdMemReserveAlias(pdsb->pDSBuffer, pdsb->cbBufferSize);
} else {
pdsbe->pDSBufferAlias = NULL;
}
DPF(2, "Return buffer ext %X, core %X mem ptr %X size %X",
pdsbe, pdsb, pdsb->pDSBuffer ,pdsb->cbBufferSize );
// Return pointer to new buffer
*ppdsbe = pdsbe;
DPF(3,"IDSHWCreateSoundBuffer Exit");
return DS_OK;
CREATE_ERROR_MIX:
if( pdsb->pMixBuffer != NULL ) {
MemFree(pdsb->pMixBuffer);
}
CREATE_ERROR_FORMAT:
MemFree(pdsb->pwfx);
CREATE_ERROR_PROCESS:
MemFree(pdsb->plProcess);
CREATE_ERROR_BUFFER:
// if this buffer was added to the pDS obj list, remove it
if(pds->pdsb == pdsb)
{
pds->pdsb = pdsb->pNext;
} else {
for(pdsb1 = pds->pdsb; pdsb1 != NULL; pdsb1 = pdsb1->pNext)
{
if(pdsb1->pNext == pdsb) {
pdsb1->pNext = pdsb->pNext;
pdsb->pNext = NULL;
break;
}
}
}
DPF(1, "Freeing DSBUFFER obj 0x%8x",pdsb);
pdsb->dwSig = 0xdeaddead;
MemFree(pdsb);
CREATE_ERROR_BUFFEREXTERNAL:
if( pdsbe == pds->pdsbePrimary ) {
// This is the original alloc of the primary
// clean up DS obj
pds->pdsbPrimary = NULL;
pds->pdsbePrimary = NULL;
}
// If this buffer was added to the pDSE list, remove it
if(pdse->pdsbe == pdsbe)
{
pdse->pdsbe = pdsbe->pNext;
} else {
for(pdsbe1 = pdse->pdsbe; pdsbe1 != NULL; pdsbe1 = pdsbe1->pNext)
{
if(pdsbe1->pNext == pdsbe) {
pdsbe1->pNext = pdsbe->pNext;
pdsbe->pNext = NULL;
break;
}
}
}
// If we allocated a wave format, free it.
if (NULL != pdse->pwfxApp) MemFree(pdse->pwfxApp);
//
MemFree(pdsbe);
CREATE_ERROR_LAST:
if( hrReturn != DS_OK ) {
return hrReturn;
} else {
return DSERR_OUTOFMEMORY;
}
}
//--------------------------------------------------------------------------;
//
// LPDIRECTSOUNDBUFFER IDSHWCreateSoundBuffer
//
// Description:
// This function is the member function for CreateSoundBuffer.
//
// Arguments:
// LPDIRECTSOUND pids: Pointer to Direct Sound Object.
//
// LPDSBUFFERCREATE pdsbc: Pointer to a DSBufferCreate structure.
//
// Return (LPDSBUFFER):
// Pointer to a DSBUFFER structure.
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/01/95 Fwong Making sense out of non-sense.
// 11/30/95 angusm Added creation of Focus Thread.
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWCreateSoundBuffer
(
LPDIRECTSOUND pids,
LPDSBUFFERDESC pdsbd,
LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer,
IUnknown FAR *pUnkOuter
)
{
LPDSBUFFEREXTERNAL pdsbe;
LPDSOUNDEXTERNAL pdse;
HRESULT hrReturn;
DPF(3,"IDSHWCreateSoundBuffer");
if( !VALID_DWORD_PTR(lplpDirectSoundBuffer) ) {
RPF("IDirectSound::CreateSoundBuffer - Invalid lplpDirectSoundBuffer");
return DSERR_INVALIDPARAM;
}
*lplpDirectSoundBuffer = NULL;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
if( !VALID_DSOUND_PTR(pdse->pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if( !VALID_DSBUFFERDESC_PTR(pdsbd) ) {
RPF("IDirectSound::CreateSoundBuffer - Invalid Buffer Description or dwSize member.");
return DSERR_INVALIDPARAM;
}
if( 0 != pdsbd->dwReserved ) {
RPF("IDirectSound::CreateSoundBuffer - DSBUFFERDESC.dwReserved must be zero.");
return DSERR_INVALIDPARAM;
}
if( pdsbd->dwFlags & (~DSBCAPS_VALIDFLAGS)) {
RPF("IDirectSound::CreateSoundBuffer - Invalid CAPS flags sent to CreateSoundBuffer");
return DSERR_INVALIDPARAM;
}
if( (DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE) ==
(pdsbd->dwFlags & (DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE)) ) {
RPF("IDirectSound::CreateSoundBuffer - Both DSBCAPS_LOCHARDWARE and DSBCAPS_LOCSOFTWARE flags were specified: failing");
return DSERR_INVALIDPARAM;
}
if( pUnkOuter != NULL ) {
RPF("IDirectSound::CreateSoundBuffer - pUnkOuter must be NULL for this rev!");
return DSERR_NOAGGREGATION;
}
// If this is not a primary then format must be set
if( !(pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) ) {
if( !VALID_WAVEFORMATEX_PTR((pdsbd->lpwfxFormat)) ) {
RPF("IDirectSound::CreateSoundBuffer - Invalid Format pointer");
return DSERR_BADFORMAT;
}
}
//
// If this is a primary, then we only allow DSBCAPS_CTRLVOLUME and
// DSBCAPS_CTRLPAN controls on it. In fact, we should really mask off
// this flag before we call down to the driver to create the buffer
// (just in case the call were to fail), but in fact the primary will be
// created by DirectSoundCreate without that control, and subsequent
// creations will simply create a new external object, so we're OK for
// now. REMIND HACKHACK BUGBUG fix this.
//
if( pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER )
{
if( pdsbd->dwFlags & DSBCAPS_CTRLFREQUENCY ) {
RPF("IDirectSound::CreateSoundBuffer - Primary buffers don't support frequency control.");
return DSERR_CONTROLUNAVAIL;
}
if( pdsbd->dwFlags & DSBCAPS_STATIC ) {
RPF("IDirectSound::CreateSoundBuffer - Primary buffers can't be static!");
return DSERR_INVALIDPARAM;
}
}
ENTER_DLL_CSECT();
hrReturn = DseCreateDsbe(pdse, pdsbd, &pdsbe);
LEAVE_DLL_CSECT();
*lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)pdsbe;
return hrReturn;
} // IDSHWCreateSoundBuffer()
//--------------------------------------------------------------------------;
//
// LPDSBUFFER IDuplicateSoundBuffer
//
// Description:
// This function is the member function for DuplicateSoundBuffer.
//
// Arguments:
// LPDIRECTSOUND pids: Pointer to Direct Sound Object.
//
// LPDSBUFFERCREATE pdsbc: Pointer to a DSBufferCreate structure.
//
// Return (LPDSBUFFER):
// Pointer to a DSBUFFER structure.
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/01/95 Fwong Making sense out of non-sense.
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWDuplicateSoundBuffer
(
LPDIRECTSOUND pids,
LPDIRECTSOUNDBUFFER pidsbCurrent,
LPLPDIRECTSOUNDBUFFER ppidsbD
)
{
LPDSBUFFER pdsbCurrent;
LPDSBUFFEREXTERNAL pdsbeCurrent;
LPDSBUFFER pdsbNew;
LPDSBUFFEREXTERNAL pdsbeNew;
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
DWORD cbMixBufferSize;
DWORD cbFormatSize;
DWORD dw;
LPDSPROCESS pDSPID;
DSCAPS dsc;
HRESULT hrReturn;
HRESULT hr;
DPF(3,"IDSHWDuplicateSoundBuffer");
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if( !VALID_DSBUFFERE_PTR(pidsbCurrent) ) {
RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdsbeCurrent = (LPDSBUFFEREXTERNAL)pidsbCurrent;
pdsbCurrent = pdsbeCurrent->pdsb;
if( !VALID_DSBUFFER_PTR(pdsbCurrent) || (0 == pdsbeCurrent->uRefCount)) {
RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
ASSERT( DSBUFFSIG == pdsbCurrent->dwSig );
// If this is a primary then return failure
if( pdsbCurrent == pds->pdsbPrimary ) {
RPF("IDirectSound::DuplicateSoundBuffer - Can not duplicate primary");
return DSERR_INVALIDCALL;
}
hrReturn = DS_OK;
*ppidsbD = NULL;
ENTER_DLL_CSECT();
cbMixBufferSize = pdsbCurrent->cbMixBufferSize;
// Allocate the external dsb object
pdsbeNew = (LPDSBUFFEREXTERNAL)MemAlloc(sizeof(DSBUFFEREXTERNAL));
if(NULL == pdsbeNew) {
DPF(0,"DuplicateSoundBuffer object (External) alloc fail");
goto DUPLICATE_ERROR_LAST;
}
pdsbeNew->lpVtbl = gpdsinfo->lpVtblDSb;
pdsbeNew->pdse = pdse;
pdsbeNew->uRefCount = 1;
pdsbeNew->dwPID = GetCurrentProcessId();
pdsbeNew->dwPriority = pdsbeCurrent->dwPriority;
pdsbeNew->pNext = pdse->pdsbe;
pdse->pdsbe = pdsbeNew;
// We are not going to dup primaryies no need to mess
// Allocate the dsb object
pdsbNew = (LPDSBUFFER)MemAlloc(sizeof(DSBUFFER));
if(NULL == pdsbNew) {
DPF(0,"DuplicateSoundBuffer object alloc fail");
goto DUPLICATE_ERROR_BUFFEREXTERNAL;
}
pdsbNew->dwSig = DSBUFFSIG;
DPF(1, "Allocating DSBUFFER obj 0x%8x",pdsbNew);
// Point external object to this
pdsbeNew->pdsb = pdsbNew;
pdsbNew->fdwBufferDesc = pdsbCurrent->fdwBufferDesc;
pdsbNew->dwPrimaryNumber = pdsbCurrent->dwPrimaryNumber;
pdsbNew->pDSBuffer = pdsbCurrent->pDSBuffer;
pdsbNew->cbBufferSize = pdsbCurrent->cbBufferSize;
pdsbNew->dwCardAddress = pdsbCurrent->dwCardAddress;
pdsbNew->pdsb3d = NULL;
pdsbNew->pds = pds;
pdsbNew->fdwDsbI = pdsbCurrent->fdwDsbI;
pdsbNew->fdwDsbI |= DSB_INTERNALF_STOP;
pdsbNew->fdwDsbI &= ~DSB_INTERNALF_LOOPING;
pdsbNew->uRefCount = 1;
pdsbNew->pNext = pds->pdsb;
pds->pdsb = pdsbNew;
pdsbNew->pdsbDuplicateNext = pdsbCurrent;
pdsbNew->pdsbDuplicatePrev = pdsbCurrent->pdsbDuplicatePrev;
pdsbCurrent->pdsbDuplicatePrev->pdsbDuplicateNext = pdsbNew;
pdsbCurrent->pdsbDuplicatePrev = pdsbNew;
// Set up hack internal use external objct
// This will be used by the mixer for calling
// methods like stop
// It will never be used for addref or release
pdsbNew->dsbe.lpVtbl = gpdsinfo->lpVtblDSb;
pdsbNew->dsbe.pdse = pdse;
pdsbNew->dsbe.uRefCount = 1;
pdsbNew->dsbe.dwPID = DWBUFFER_INTERNAL_PID;
pdsbNew->dsbe.pNext = NULL;
pdsbNew->dsbe.pdsb = pdsbNew;
pdsbNew->dsbe.dwPriority = pdsbeCurrent->dwPriority;
//Allocate the mix buffer
pdsbNew->cbMixBufferSize = cbMixBufferSize;
pdsbNew->pMixBuffer = NULL;
if( cbMixBufferSize != 0 ) {
pdsbNew->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
if(NULL == pdsbNew->pMixBuffer) {
DPF(1,"IDSHWDuplicateSoundBuffer mix buffer alloc fail");
goto DUPLICATE_ERROR_BUFFER;
}
}
// Alloc Process ID list
pDSPID = (LPDSPROCESS)MemAlloc(sizeof(DSPROCESS));
if(NULL == pDSPID) {
DPF(1,"IDSDuplicateSoundBuffer process alloc fail");
goto DUPLICATE_ERROR_MIX;
}
pDSPID->dwPID = HackGetCurrentProcessId();
pDSPID->dwProcessRefCount = 1;
pDSPID->pNext = NULL;
pdsbNew->plProcess = pDSPID;
// Allocate a buffer to hold the format
dw = SIZEOF_WAVEFORMATEX( pdsbCurrent->pwfx );
cbFormatSize = dw + 16;
// Now allocate memory
pdsbNew->pwfx = NULL;
pdsbNew->pwfx = (LPWAVEFORMATEX)MemAlloc(cbFormatSize);
if(NULL == pdsbNew->pwfx) {
DPF(1,"IDSHWDuplicateSoundBuffer object alloc fail");
goto DUPLICATE_ERROR_PROCESS;
}
dw = SIZEOF_WAVEFORMATEX( pdsbCurrent->pwfx );
CopyMemory( pdsbNew->pwfx, pdsbCurrent->pwfx, dw );
//Set the helInfo stuff
pdsbNew->helInfo.dwSampleRate = pdsbNew->pwfx->nSamplesPerSec;
pdsbNew->helInfo.hfFormat = pdsbCurrent->helInfo.hfFormat;
pdsbNew->helInfo.lVolume = pdsbCurrent->helInfo.lVolume;
pdsbNew->helInfo.lPan = pdsbCurrent->helInfo.lPan;
pdsbNew->helInfo.dwLVolume = pdsbCurrent->helInfo.dwLVolume;
pdsbNew->helInfo.dwRVolume = pdsbCurrent->helInfo.dwRVolume;
pdsbNew->helInfo.dwMVolume = pdsbCurrent->helInfo.dwMVolume;
// No need to handle Wave Emulated separatly since primary
// is the same and emulated are the same as other emulated
// If the other buffer is HW then see if we can make this one.
if (DSB_INTERNALF_HARDWARE & pdsbCurrent->fdwDsbI) {
// Check to see if we can make this a HW buffer
// Get the caps and see if we have it free....
dsc.dwSize = sizeof( DSCAPS );
hr = DsGetCaps(pdse->pds, &dsc);
ASSERT (DS_OK == hr);
if( (dsc.dwFreeHwMixingAllBuffers > 0 ) ) {
DPF(3," Check for try HW FLAGS %X ", dsc.dwFlags );
DPF(3," Check for try HW format chann %d ",
pdsbNew->pwfx->nChannels);
DPF(3," Check for try HW format bits %d ",
pdsbNew->pwfx->wBitsPerSample);
// Card has secondary buffers in HW
// We are OK
} else {
// Other buffer is in HW and we can not make this one in HW
// Fail call.
RPF("IDirectSound::DuplicateSoundBuffer - HW does not have resources to duplicate");
hrReturn = DSERR_ALLOCATED;
goto DUPLICATE_ERROR_FORMAT;
}
}
// Check to see if this is a primary or HW buffer
// If so then use the HAL code
if (DSB_INTERNALF_HARDWARE & pdsbCurrent->fdwDsbI) {
// We are asking for a HW buffer...
DPF(3,"HW Duplicate HW buffer");
DPF(3,"HW Duplicate - sample rate %d", pdsbNew->helInfo.dwSampleRate );
DPF(3,"HW Duplicate - hfForamt %X", pdsbNew->helInfo.hfFormat );
hrReturn = vxdDrvDuplicateSoundBuffer( pds->hHal,
pdsbCurrent->hBuffer,
&pdsbNew->hBuffer );
if (DS_OK != hrReturn) {
DPF(1,"IDSHWDuplicateSoundBuffer buffer alloc fail");
goto DUPLICATE_ERROR_FORMAT;
}
ASSERT(NULL != pdsbNew->hBuffer);
DPF(3,"IDSHWDuplicateSoundBuffer buffer alloc OK");
} else {
DPF(3,"HW Duplicate Emulated secondary buffer");
}
// Should be using same snd data buffer
ASSERT(pdsbNew->pDSBuffer == pdsbCurrent->pDSBuffer);
ASSERT(pdsbNew->cbBufferSize == pdsbCurrent->cbBufferSize);
DPF(3,"--------Dup data for Emulated obj %X buff %X len %X",
pdsbNew, pdsbNew->pDSBuffer, pdsbNew->cbBufferSize );
//
// If the creating app doesn't have sound focus then we need to
// immediately deactivate the new buffer
//
DsbeDeactivateIfNecessary (pdsbeNew);
// Set the grace info
pdsbNew->cSamples = pdsbNew->cbBufferSize / pdsbNew->pwfx->nBlockAlign;
switch (pdsbNew->pwfx->nBlockAlign) {
case 1:
pdsbNew->uBlockAlignShift = 0;
break;
case 2:
pdsbNew->uBlockAlignShift = 1;
break;
case 4:
pdsbNew->uBlockAlignShift = 2;
break;
default:
ASSERT(FALSE);
}
*ppidsbD = (LPDIRECTSOUNDBUFFER)pdsbeNew;
DPF(3,"IDSHWDuplicateSoundBuffer Exit");
LEAVE_DLL_CSECT( );
return DS_OK;
//DUPLICATE_ERROR_DATA:
// Do not free since we are duplicating
DUPLICATE_ERROR_FORMAT:
MemFree(pdsbNew->pwfx);
DUPLICATE_ERROR_PROCESS:
MemFree(pdsbNew->plProcess);
DUPLICATE_ERROR_MIX:
if( pdsbNew->pMixBuffer != NULL ) {
MemFree(pdsbNew->pMixBuffer);
}
DUPLICATE_ERROR_BUFFER:
// Remove it from duplicate list
pdsbNew->pdsbDuplicateNext->pdsbDuplicatePrev = pdsbNew->pdsbDuplicatePrev;
pdsbNew->pdsbDuplicatePrev->pdsbDuplicateNext = pdsbNew->pdsbDuplicateNext;
// Remove from buffer list (inserted at head)
//
ASSERT(pds->pdsb == pdsbNew);
pds->pdsb = pds->pdsb->pNext;
DPF(1, "Freeing DSBUFFER obj 0x%8x",pdsbNew);
pdsbNew->dwSig = 0xdeaddead;
MemFree(pdsbNew);
DUPLICATE_ERROR_BUFFEREXTERNAL:
// Unlink pdsbNew from external list (inserted at head)
//
ASSERT(pdse->pdsbe == pdsbeNew);
pdse->pdsbe = pdse->pdsbe->pNext;
MemFree(pdsbeNew);
DUPLICATE_ERROR_LAST:
LEAVE_DLL_CSECT( );
if( hrReturn != DS_OK ) {
return hrReturn;
} else {
return DSERR_OUTOFMEMORY;
}
} // IDSHWDuplicateSoundBuffer()
#if 0
//--------------------------------------------------------------------------;
//
// IDSHWEnumSoundBuffers
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWEnumSoundBuffers
(
LPDIRECTSOUND pids,
LPDSENUMBUFFERSCALLBACK pfnEnumCB,
LPVOID lpContext
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
LPDSBUFFEREXTERNAL pdsbeSearch;
LPDSBUFFERDESC lpdsbd;
LPWAVEFORMATEX pwfx;
DWORD dw;
BOOL fRet;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::EnumSoundBuffers - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::EnumSoundBuffers - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
DPF(0,"Entering EnumSoundBuffers method");
ENTER_DLL_CSECT();
if(( lpdsbd = MemAlloc( sizeof(DSBUFFERDESC) )) == NULL ) {
RPF("IDirectSound::EnumSoundBuffers - Couldn't allocate DSBUFFERDESC structure!");
LEAVE_DLL_CSECT();
DPF(0,"Leaving EnumSoundBuffers method");
return DSERR_OUTOFMEMORY;
}
pdsbeSearch = pdse->pdsbe;
while( pdsbeSearch != NULL ) {
_fmemset( lpdsbd, 0, sizeof(DSBUFFERDESC));
// In case we want to use non-PCM format structures, we can do so,
// because we're allowing for
dw = SIZEOF_WAVEFORMATEX( pdsbeSearch->pdsb->pwfx ) + 16;
if(( pwfx = MemAlloc( dw )) == NULL ) {
RPF("IDirectSound::EnumSoundBuffers - Couldn't allocate WAVEFORMATEX structure!");
MemFree( lpdsbd );
LEAVE_DLL_CSECT();
DPF(0,"Leaving EnumSoundBuffers method");
return DSERR_OUTOFMEMORY;
}
dw = SIZEOF_WAVEFORMATEX( pdsbeSearch->pdsb->pwfx );
CopyMemory( pwfx, pdsbeSearch->pdsb->pwfx, dw );
lpdsbd->dwSize = sizeof(DSBUFFERDESC);
lpdsbd->cbBuffer = pdsbeSearch->pdsb->cbBufferSize;
lpdsbd->lpwfxFormat = pwfx;
lpdsbd->dwFlags = pdsbeSearch->pdsb->fdwBufferDesc;
lpdsbd->dwReserved = pdsbeSearch->pdsb->dwPrimaryNumber;
lpdsbd->lpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)pdsbeSearch;
pdsbeSearch->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbeSearch );
DPF(1,"EnumSoundBuffers: Calling enumeration callback");
fRet = pfnEnumCB( lpdsbd, lpContext );
MemFree( pwfx );
// Break out early if they told us not to continue...
if( fRet != TRUE ) {
DPF(1,"Ending enumeration prematurely");
break;
}
pdsbeSearch = pdsbeSearch->pNext;
}
MemFree( lpdsbd );
LEAVE_DLL_CSECT();
DPF(0,"Leaving EnumSoundBuffers method");
return DS_OK;
}
#endif // 0
//--------------------------------------------------------------------------;
//
// DsGetCapsNative
//
// Description: This sets capabilty flags for supported hardware
//
// Arguments: pDSCaps pointer to capabilities structure to be filled
// pds pointer to direct sound object
//
// Concurrency: sequential
//
// Assumptions: pds->hHal, pds->dwHeapType, pds->DriverHeap
// are initialized
//
// Return (HRESULT): DS_OK Success
// DS_xxxxx on failure
//
//--------------------------------------------------------------------------;
HRESULT DsGetCapsNative
(
LPDSCAPS pDSCaps,
LPDSOUND pds
)
{
DSDRIVERCAPS drvCaps;
HRESULT hr;
DPF (2, "DsGetCapsNative: Enter Function");
DPF (2, "DsGetCapsNative: pDSCaps = %x", pDSCaps);
DPF (2, "DsGetCapsNative: pds = %x", pds);
ZeroMemory(&drvCaps, sizeof(drvCaps));
hr = vxdDrvGetCaps(pds->hHal, &drvCaps);
if (DS_OK != hr) {
DPF(0, "DsGetCapsNative: vxdDrvGetCaps failure");
return hr;
}
// Check flags returned from driver to see if they are all
// valid flags for a driver
if (drvCaps.dwFlags & (~DSCAPS_VALIDDRIVERFLAGS)) {
RPF ("Sound Device Driver may be broken. Returned non-valid"
"flags to Direct Sound: %x", drvCaps.dwFlags);
ASSERT (0);
}
pDSCaps->dwFlags = drvCaps.dwFlags & DSCAPS_VALIDDRIVERFLAGS;
pDSCaps->dwMinSecondarySampleRate = drvCaps.dwMinSecondarySampleRate;
pDSCaps->dwMaxSecondarySampleRate = drvCaps.dwMaxSecondarySampleRate;
pDSCaps->dwPrimaryBuffers = drvCaps.dwPrimaryBuffers;
pDSCaps->dwMaxHwMixingAllBuffers = drvCaps.dwMaxHwMixingAllBuffers;
pDSCaps->dwMaxHwMixingStaticBuffers = drvCaps.dwMaxHwMixingStaticBuffers;
pDSCaps->dwMaxHwMixingStreamingBuffers = drvCaps.dwMaxHwMixingStreamingBuffers;
pDSCaps->dwFreeHwMixingAllBuffers = drvCaps.dwFreeHwMixingAllBuffers;
pDSCaps->dwFreeHwMixingStaticBuffers = drvCaps.dwFreeHwMixingStaticBuffers;
pDSCaps->dwFreeHwMixingStreamingBuffers = drvCaps.dwFreeHwMixingStreamingBuffers;
pDSCaps->dwMaxHw3DAllBuffers = drvCaps.dwMaxHw3DAllBuffers;
pDSCaps->dwMaxHw3DStaticBuffers = drvCaps.dwMaxHw3DStaticBuffers;
pDSCaps->dwMaxHw3DStreamingBuffers = drvCaps.dwMaxHw3DStreamingBuffers;
pDSCaps->dwFreeHw3DAllBuffers = drvCaps.dwFreeHw3DAllBuffers;
pDSCaps->dwFreeHw3DStaticBuffers = drvCaps.dwFreeHw3DStaticBuffers;
pDSCaps->dwFreeHw3DStreamingBuffers = drvCaps.dwFreeHw3DStreamingBuffers;
pDSCaps->dwTotalHwMemBytes = drvCaps.dwTotalHwMemBytes;
pDSCaps->dwFreeHwMemBytes = drvCaps.dwFreeHwMemBytes;
pDSCaps->dwMaxContigFreeHwMemBytes = drvCaps.dwMaxContigFreeHwMemBytes;
//
// If we're using vmemmgr to manage the hw memory...
//
if ((DSDHEAP_CREATEHEAP == pds->dwHeapType) ||
(DSDHEAP_USEDIRECTDRAWHEAP == pds->dwHeapType))
{
ASSERT(pds->pDriverHeap);
pDSCaps->dwFreeHwMemBytes = VidMemAmountFree(pds->pDriverHeap);
pDSCaps->dwMaxContigFreeHwMemBytes = VidMemLargestFree(pds->pDriverHeap);
}
// REMIND what about these?
pDSCaps->dwUnlockTransferRateHwBuffers = 0;
pDSCaps->dwPlayCpuOverheadSwBuffers = 0;
DPF (2, "DsGetCapsNative: Leave Function");
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// DsGetCapsEmulated
//
// Description: This sets capability flags for emulated hardware
//
// Arguments: pDSCaps pointer to capabilities structure to be filled
// pds pointer to Direct Sound Object
//
// Concurrency: sequential
//
// Assumptions: pds->uDeviceID is initialized
//
// Return (HRESULT): DS_OK Success
// DSERR_GENERIC Error getting capabilities wave
// out device
// DS_xxxxx on failure
//
//--------------------------------------------------------------------------;
HRESULT DsGetCapsEmulated
(
LPDSCAPS pDSCaps,
LPDSOUND pds
)
{
WAVEOUTCAPS woc;
MMRESULT mmr;
DPF (2, "DsGetCapsEmulated: Enter Function");
DPF (2, "DsGetCapsEmulated: pDSCaps = %x", pDSCaps);
DPF (2, "DsGetCapsEmulated: pds = %x", pds);
mmr = waveOutGetDevCaps( pds->uDeviceID, &woc, sizeof(woc) );
if( mmr != MMSYSERR_NOERROR ) {
DPF (0, "DsGetCapsEmulated: WaveOutGetCaps failed");
return DSERR_GENERIC;
}
pDSCaps->dwFlags = 0;
if( woc.dwFormats & WAVE_FORMAT_1M08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_2M08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_4M08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_1S08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_2S08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_4S08 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
}
if( woc.dwFormats & WAVE_FORMAT_1M16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_2M16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_4M16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_1S16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_2S16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_4S16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
if( woc.dwFormats & WAVE_FORMAT_1S16 ) {
pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
}
pDSCaps->dwFlags |= DSCAPS_EMULDRIVER;
pDSCaps->dwMinSecondarySampleRate = 100;
pDSCaps->dwMaxSecondarySampleRate = 100000;
pDSCaps->dwPrimaryBuffers = 1;
pDSCaps->dwMaxHwMixingAllBuffers = 0;
pDSCaps->dwMaxHwMixingStaticBuffers = 0;
pDSCaps->dwMaxHwMixingStreamingBuffers = 0;
pDSCaps->dwFreeHwMixingAllBuffers = 0;
pDSCaps->dwFreeHwMixingStaticBuffers = 0;
pDSCaps->dwFreeHwMixingStreamingBuffers = 0;
pDSCaps->dwMaxHw3DAllBuffers = 0;
pDSCaps->dwMaxHw3DStaticBuffers = 0;
pDSCaps->dwMaxHw3DStreamingBuffers = 0;
pDSCaps->dwFreeHw3DAllBuffers = 0;
pDSCaps->dwFreeHw3DStaticBuffers = 0;
pDSCaps->dwFreeHw3DStreamingBuffers = 0;
pDSCaps->dwTotalHwMemBytes = 0;
pDSCaps->dwFreeHwMemBytes = 0;
pDSCaps->dwMaxContigFreeHwMemBytes = 0;
// REMIND what about these?
pDSCaps->dwUnlockTransferRateHwBuffers = 0;
pDSCaps->dwPlayCpuOverheadSwBuffers = 0;
DPF (2, "DsGetCapsEmulated: Leave Function");
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// DsGetCaps
//
// Description: This function gets the capabilty flags for the given
// device.
//
// Arguments: pds pointer to direct sound object to retrieve
// capabilities on.
// pDSCaps pointer to capabilities structure to be filled
//
// Concurrency: synchronous
//
// Return (HRESULT): DS_OK on Success
// refer to DsGetCapsNative or DsGetCapsEmulated
// error codes
//
//--------------------------------------------------------------------------;
HRESULT DsGetCaps
(
LPDSOUND pds,
LPDSCAPS pDSCaps
)
{
HRESULT hr;
DPF (2, "DsGetCaps: Enter Function");
DPF (2, "DsGetCaps: pds = %x", pds);
DPF (2, "DsGetCaps: pDSCaps = %x", pDSCaps);
ENTER_DLL_CSECT();
if( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) {
DPF (3, "DsGetCaps: getting emulated capabilities");
hr = DsGetCapsEmulated (pDSCaps, pds);
} else {
DPF (3, "DsGetCaps: getting native capabilities");
hr = DsGetCapsNative (pDSCaps, pds);
}
if (DS_OK == hr) {
// Set driver version, as calculated on pds object creation.
pDSCaps->dwReserved1 = pds->dwDriverVersionMinor;
pDSCaps->dwReserved2 = pds->dwDriverVersionMajor;
// Set certified bit.
if( pds->fdwInternal & DS_INTERNALF_CERTIFIED ) {
pDSCaps->dwFlags |= DSCAPS_CERTIFIED;
}
DPF (3, "DsGetCaps: version information:");
DPF (3, "DsGetCaps: dwDriverVersionMinor = %d", pDSCaps->dwReserved1);
DPF (3, "DsGetCaps: dwDriverVersionMajor = %d", pDSCaps->dwReserved2);
DPF (3, "DsGetCaps: Certified? = %d",
pDSCaps->dwFlags & DSCAPS_CERTIFIED);
}
else {
DPF (1, "DsGetCaps: error getting capabilities (%d)", hr);
}
LEAVE_DLL_CSECT();
DPF (2, "DsGetCaps: Leave Function");
return hr;
}
//--------------------------------------------------------------------------;
//
// IDSHWGetCaps
//
// Description: Direct Sound Object member to determine hardware
// capabilities.
//
// Arguments: pids pointer to Direct Sound Object
// pDSCaps pointer to DS Capabilities structures
//
// Return (HRESULT):
// DS_OK Success
// DSERR_UNINITIALIZED if object has not be initialized
// DSERR_INVALIDPARAM a parameter could not be validated
// DSERR_GENERIC any error getting Capabilities
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWGetCaps
(
LPDIRECTSOUND pids,
LPDSCAPS pDSCaps
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
HRESULT hr;
// Validation Code
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::GetCaps - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if object has been initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::GetCaps - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if( !VALID_DSCAPS_PTR(pDSCaps) ) {
RPF("IDirectSound::GetCaps - Invalid DSCAPS structure or dwSize member.");
return DSERR_INVALIDPARAM;
}
hr = DsGetCaps (pdse->pds, pDSCaps);
return hr;
}
//--------------------------------------------------------------------------;
//
// DSDeactivateApp
//
// In: hWnd Handle of application to deactivate
// bSticky DSDEACTIVATEAPPF_NONSTICKY will deactivate only
// non-sticky buffers
// DSDEACTIVATEAPPF_ALL will deactivate all buffers
//--------------------------------------------------------------------------;
void DSDeactivateApp(DWORD tid, enum DSDeactivateAppF bSticky)
{
LPDSOUNDEXTERNAL pdse;
LPDSBUFFEREXTERNAL pdsbe;
DPF(0,"###### Deactivate tid %X ######", tid);
for (pdse = gpdsinfo->pDSoundExternalObj; NULL != pdse; pdse = pdse->pNext)
{
if (tid == pdse->tidSound) {
for (pdsbe = pdse->pdsbe; NULL != pdsbe; pdsbe = pdsbe->pNext)
{
if ((DSDEACTIVATEAPPF_ALL == bSticky) ||
(FALSE == (DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
{
DSBufferDeactivate(pdsbe);
}
}
if (!(pdse->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
mxSignalRemix(pdse->pds, 0);
}
}
}
}
//--------------------------------------------------------------------------;
//
// DSActivateApp
//
//--------------------------------------------------------------------------;
void DSActivateApp(DWORD tid)
{
LPDSOUND pds;
LPDSBUFFER pdsb;
LPDSOUNDEXTERNAL pdse;
LPDSBUFFEREXTERNAL pdsbe;
DWORD dwActivePrio;
BOOL fWritePrimary;
//
// Find the highest priority setting of all pdse under this hwnd
//
dwActivePrio = DSSCL_NORMAL;
for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
if (tid == pdse->tidSound && pdse->dwPriority > dwActivePrio) {
dwActivePrio = pdse->dwPriority;
}
}
DPF(0,"##### Activate tid %X Active Prio %X #####", tid, dwActivePrio);
fWritePrimary = (dwActivePrio >= DSSCL_WRITEPRIMARY);
//
// For all of the app's ds objects, set the format of the internal
// primary buffer to the app's format. Also play or stop the internal
// primary buffer as appropriate for the app we are activating.
//
// If we're WRITEPRIMARY, mark everyone else's external buffers as
// lost
//
for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
DPF(2, "Activating pdse %08Xh", pdse);
if (tid == pdse->tidSound) {
ASSERT(NULL != pdse->pds->pdsbPrimary);
if (NULL == pdse->pwfxApp) {
ASSERT(0 != pdse->pds->wfxDefault.wFormatTag);
IDsbSetFormatI(pdse->pds->pdsbPrimary, &pdse->pds->wfxDefault, 0);
} else {
IDsbSetFormatI(pdse->pds->pdsbPrimary, pdse->pwfxApp, 0);
}
//
// If we're not WRITEPRIMARY, then Play/Stop the primary per the
// the count of playing buffers
//
// We must be sure to call Play/Stop on the internal primary dsb's
// contained dsbe object so that Play/Stop doesn't operate on the
// app's primary dsbe object.
//
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
pdsb = pdsbe->pdsb;
pds = pdsb->pds;
if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
ASSERT(pdsb == pds->pdsbPrimary);
// If the external primary has been played, then cPlayPrimary must be >0.
ASSERT( !( (pdsbe->fdwDsbeI&DSBE_INTERNALF_PLAYING) && (0==pds->cPlayPrimary) ) );
if( (!fWritePrimary) &&
( (pds->cPlayPrimary > 0) ||
(pds->dwBuffersPlaying > 0) ) )
{
DPF(3, "DSActivateApp: playing primary dsb %08Xh, pdsb");
IDirectSoundBuffer_Play((LPDIRECTSOUNDBUFFER)pds->pdsbePrimary,
0, 0, DSBPLAY_LOOPING);
} else {
DPF(3, "DSActivateApp: stopping primary dsb %08Xh, pdsb");
IDsbStopI(pdsb, FALSE);
}
}
}
} else if (fWritePrimary) {
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
//
// Stop all playing buffers
//
if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
IDsbStopI(pdsbe->pdsb, FALSE);
}
//
// Lose all secondary buffers.
//
if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) ) {
pdsbe->fdwDsbeI |= DSBE_INTERNALF_LOST;
}
//
// WRITEPRIMARY primaries should already be lost.
//
ASSERT( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY ) ||
( pdsbe->dwPriority < DSSCL_WRITEPRIMARY ) ||
( pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST ) );
}
}
}
//
// For every pdse that are in focus, we activate all its pdsbe.
// We also signal the mixer to remix for the pdse's pds.
//
for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
if (tid == pdse->tidSound) {
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
DSBufferActivate(pdsbe);
}
if (!(pdse->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
mxSignalRemix(pdse->pds, 0);
}
}
}
}
//--------------------------------------------------------------------------;
//
// void apmResume
//
// Description:
//
// Arguments:
// none
//
// Return (void):
//
// History:
// 09/11/95 FrankYe Created
//
//--------------------------------------------------------------------------;
void apmResume(void)
{
LPDSOUND pds;
ENTER_DLL_CSECT();
if (gpdsinfo->fApmSuspended) {
gpdsinfo->fApmSuspended = FALSE;
for (pds = gpdsinfo->pDSoundObj; pds; pds = pds->pNext) {
IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, IDSBSETFORMATIF_ALWAYS );
}
}
/* Update Focus and Stuck handles */
ActivateFocusWindow();
LEAVE_DLL_CSECT();
}
//--------------------------------------------------------------------------;
//
// void apmSuspend
//
// Description:
//
// Arguments:
// none
//
// Return (void):
//
// History:
// 09/11/95 FrankYe Created
//
//--------------------------------------------------------------------------;
void apmSuspend(void)
{
LPDSOUNDEXTERNAL pdse;
LPDSBUFFEREXTERNAL pdsbe;
ENTER_DLL_CSECT();
DSDeactivateApp(gpdsinfo->tidSoundFocus, DSDEACTIVATEAPPF_ALL);
for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) ) {
//
// Stop all playing buffers
//
if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
IDsbStopI(pdsbe->pdsb, FALSE);
}
//
// Lose all secondary buffers.
//
pdsbe->fdwDsbeI |= DSBE_INTERNALF_LOST;
}
}
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
if (pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
IDsbStopI(pdsbe->pdsb, FALSE);
}
//
// WRITEPRIMARY primaries should already be lost.
//
ASSERT( ( pdsbe->dwPriority < DSSCL_WRITEPRIMARY ) ||
( pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST ) );
}
}
}
gpdsinfo->fApmSuspended = TRUE;
LEAVE_DLL_CSECT();
}
//--------------------------------------------------------------------------;
//
// SubclassWndProc
//
// We use APM notifications to help use get the native DS drivers
// into a state proper for suspending. If we are compiling for
// emulation mode only, then we don't need to catch these APM
// notifications.
//
//--------------------------------------------------------------------------;
#ifndef DSBLD_EMULONLY
LRESULT CALLBACK SubclassWndProc
(
HWND hWnd,
UINT uMessage,
WPARAM wParam,
LPARAM lParam
)
{
DPF(9,"Sublcass Window %X Message %X wParam %X, lParam %X ",
(DWORD)hWnd, (DWORD)uMessage, (DWORD)wParam, (DWORD)lParam );
switch(uMessage)
{
case WM_POWERBROADCAST:
switch (wParam) {
case PBT_APMSUSPEND:
apmSuspend();
return TRUE;
case PBT_APMRESUMESUSPEND:
apmResume();
return TRUE;
}
}
return 0;
} // SubclassWndProc()
#endif
//--------------------------------------------------------------------------;
//
// IDSHWSetCooperativeLevel
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWSetCooperativeLevel
(
LPDIRECTSOUND pids,
HWND hwnd,
DWORD dwPriority
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
LPDSBUFFEREXTERNAL pdsbeSearch;
DWORD dwProcessIdCaller;
DWORD tid;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::SetCooperativeLevel - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::SetCooperativeLevel - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if( !VALID_HWND(hwnd) ) {
RPF("IDirectSound::SetCooperativeLevel - Invalid hwnd");
return DSERR_INVALIDPARAM;
}
if((dwPriority < DSSCL_FIRST) || (dwPriority > DSSCL_LAST)) {
RPF("IDirectSound::SetCooperativeLevel - Invalid DSSCL_* passed to SetCooperativeLevel");
return DSERR_INVALIDPARAM;
}
//
// Due to bugs in the wave emulation code, we don't allow writeprimary
// level on unsupported cards. This should be fixed. BUGBUG REMIND
//
if( ( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) &&
( dwPriority >= DSSCL_WRITEPRIMARY ) )
{
RPF("IDirectSound::SetCooperativeLevel - DSSCL_WRITEPRIMARY level not available on emulated drivers.");
return DSERR_INVALIDCALL;
}
/* set the actual window handle that sound */
/* focus is tracked on to be the top unowned */
/* window. */
hwnd = GetTopUnownedWindow (hwnd);
tid = GetWindowThreadProcessId(hwnd, NULL);
DPF(3,"=== Enter SetCooperativeLevel ===");
ENTER_DLL_CSECT();
dwProcessIdCaller = GetCurrentProcessId();
// We use DSoundHelp to give us APM window notifications. If we are
// building only for emulation mode then we don't need APM notifications
// since APM will be handled entirely by the WAVE drivers that we are
// using for emulation.
#ifndef DSBLD_EMULONLY
// The first time this is called, register the window
if( pdse->hwndCooperative == 0 ) {
DSoundHelp( hwnd, SubclassWndProc, dwProcessIdCaller );
} else {
// If we are given a new window, then release old window and add new
if( pdse->hwndCooperative != hwnd ) {
DSoundHelp( NULL, SubclassWndProc, dwProcessIdCaller );
DSoundHelp( hwnd, SubclassWndProc, dwProcessIdCaller );
}
}
#endif
pdse->tidSound = tid;
pdse->hwndCooperative = hwnd;
pdse->dwPriority = dwPriority;
// Update all buffers under this object to reflect the new priority level
pdsbeSearch = pdse->pdsbe;
while( pdsbeSearch != NULL ) {
pdsbeSearch->dwPriority = dwPriority;
pdsbeSearch = pdsbeSearch->pNext;
}
DseUpdateActivationState(pdse);
LEAVE_DLL_CSECT();
DPF(3,"=== Exit SetCooperativeLevel ===");
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// IDSHWCompact
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWCompact
(
LPDIRECTSOUND pids
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::Compact - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::Compact - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if (DSSCL_NORMAL == pdse->dwPriority) {
RPF("IDirectSound::Compact - Compact with priority DSSCL_NORMAL");
return DSERR_PRIOLEVELNEEDED;
}
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// IDSHWGetSpeakerConfig
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWGetSpeakerConfig
(
LPDIRECTSOUND pids,
LPDWORD pdwConfig
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::GetSpeakerConfig - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::GetSpeakerConfig - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if( !VALID_DWORD_PTR(pdwConfig)) {
RPF("IDirectSound::GetSpeakerConfig - Invalid pointer passed to GetSpeakerConfig()");
return DSERR_INVALIDPARAM;
}
ENTER_DLL_CSECT();
*pdwConfig = pdse->dwSpeakerConfig;
LEAVE_DLL_CSECT();
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// IDSHWSetSpeakerConfig
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWSetSpeakerConfig
(
LPDIRECTSOUND pids,
DWORD dwConfig
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::SetSpeakerConfig - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
RPF("IDirectSound::SetSpeakerConfig - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
if(( dwConfig < DSSPEAKER_FIRST ) || ( dwConfig > DSSPEAKER_LAST )) {
RPF("IDirectSound::SetSpeakerConfig - Invalid Config value");
return DSERR_INVALIDPARAM;
}
ENTER_DLL_CSECT();
// We're not doing a darn thing with this other than saving away the
// value until we get 3D sound...
pdse->dwSpeakerConfig = dwConfig;
LEAVE_DLL_CSECT();
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// IDSHWInitialize
//
// Description:
//
// Arguments:
//
// Return ():
//
// History:
// 02/11/96 angusm Added init code from DirectSoundCreate
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWInitialize
(
LPDIRECTSOUND pids,
GUID FAR *lpGUID
)
{
LPDSOUNDEXTERNAL pdse;
GUID guid, guidLast;
DSDRIVERDESC dsDrvDesc;
UINT cWaves;
UINT uPreferredWaveId;
UINT uWaveId;
BOOL fPreferredOnly;
HRESULT hr;
HRESULT hrClient;
if( !VALID_DSOUNDE_PTR(pids) ) {
RPF("IDirectSound::Initialize - Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_INITIALIZED == pdse->fInitialized) {
return DSERR_ALREADYINITIALIZED;
}
cWaves = waveOutGetNumDevs();
cWaves = min(cWaves, LIMIT_WAVE_DEVICES-1);
if (0 == cWaves) return DSERR_NODRIVER;
if (!wavGetPreferredId(&uPreferredWaveId, &fPreferredOnly)) {
return DSERR_NODRIVER;
}
ENTER_DLL_CSECT();
if (NULL == lpGUID) {
hrClient = DSERR_NODRIVER;
#if defined(RDEBUG) || defined(DEBUG)
if (!gpdsinfo->fEnumOnlyWaveDevs)
#endif
{
hr = wavGetDrvGuidFromId(uPreferredWaveId, &guid);
if (DS_OK == hr) {
hr = hrClient = DseInitializeFromGuid(pdse, &guid);
}
if ((DS_OK != hr) && !fPreferredOnly) {
ZeroMemory(&dsDrvDesc, sizeof(dsDrvDesc));
hr = vxdDrvGetNextDriverDesc(NULL, &guid, &dsDrvDesc);
while (DS_OK == hr) {
if ((DS_OK == wavGetIdFromDrvGuid(&guid, &uWaveId)) &&
wavIsMappable(uWaveId))
{
hr = hrClient = DseInitializeFromGuid(pdse, &guid);
if (DS_OK == hr) break;
}
guidLast = guid;
ZeroMemory(&dsDrvDesc, sizeof(dsDrvDesc));
hr = vxdDrvGetNextDriverDesc(&guidLast, &guid, &dsDrvDesc);
}
}
}
if ((DS_OK != hrClient) && (uPreferredWaveId < cWaves)) {
guid = gpdsinfo->aguidWave[uPreferredWaveId];
hr = hrClient = DseInitializeFromGuid(pdse, &guid);
}
if ((DS_OK != hrClient) && !fPreferredOnly) {
uWaveId = 0;
while (uWaveId < cWaves) {
guid = gpdsinfo->aguidWave[uWaveId];
if (wavIsMappable(uWaveId)) {
hr = hrClient = DseInitializeFromGuid(pdse, &guid);
if (DS_OK == hr) break;
}
uWaveId++;
}
}
} else {
// NULL != lpGUID
hrClient = DseInitializeFromGuid(pdse, lpGUID);
}
/* Check to see if this is the first buffer */
/* created, and start Focus Thread. */
if ((DS_OK == hrClient) && (1 == cSoundObjects())) {
if (!CreateFocusThread()) {
hrClient = DSERR_GENERIC;
DseTerminate(pdse);
}
}
if (DS_OK == hrClient) {
pdse->fInitialized = IDSHWINITIALIZEF_INITIALIZED;
}
LEAVE_DLL_CSECT();
return hrClient;
} // IDSHWInitialize()
// This code is disabled for now...
#ifdef ENABLE_EXCLUSIVEMODE_STUFF
//--------------------------------------------------------------------------;
//
// IDSHWGetExclusiveModeOwner
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWGetExclusiveModeOwner
(
LPDIRECTSOUND pids,
LPHANDLE phProcess
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
DPF(0,"Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
DPF(0,"Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
ENTER_DLL_CSECT();
*phProcess = pds->hExclusiveOwner;
LEAVE_DLL_CSECT();
return DS_OK;
}
//--------------------------------------------------------------------------;
//
// IDSHWSetExclusiveModeOwner
//
// Description:
//
// Arguments:
//
// Return (HRESULT):
// DSERR_UNINITIALIZED if object has not be initialized
//
// History:
// 02/11/96 angusm Added check for initialization
//
//--------------------------------------------------------------------------;
HRESULT FAR PASCAL IDSHWSetExclusiveModeOwner
(
LPDIRECTSOUND pids,
DWORD fdwFlags
)
{
LPDSOUND pds;
LPDSOUNDEXTERNAL pdse;
if( !VALID_DSOUNDE_PTR(pids) ) {
DPF(0,"Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
pdse = (LPDSOUNDEXTERNAL)pids;
/* Check to see if the object is initialized */
if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
RPF("Direct Sound Object is uninitialized.");
return DSERR_UNINITIALIZED;
}
pds = pdse->pds;
if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
DPF(0,"Invalid Object or ref count");
return DSERR_INVALIDPARAM;
}
ENTER_DLL_CSECT();
if( (pds->hExclusiveOwner != NULL) &&
(pds->hExclusiveOwner != (HANDLE)GetCurrentProcessId()) ) {
DPF(0,"Exclusive mode already set");
LEAVE_DLL_CSECT();
return DSERR_GENERIC;
}
if( fdwFlags & DS_EXCLUSIVEF_NONEXCLUSIVE ) {
pds->fdwExclusive = 0;
pds->hExclusiveOwner = 0;
} else {
pds->fdwExclusive = fdwFlags;
pds->hExclusiveOwner = (HANDLE)GetCurrentProcessId();
}
LEAVE_DLL_CSECT();
return DSERR_OK;
}
#endif
void FNGLOBAL DSHWCreateTable
(
LPDSOUNDCALLBACKS lpVtbl
)
{
lpVtbl->QueryInterface = IDSHWQueryInterface;
lpVtbl->AddRef = IDSHWAddRef;
lpVtbl->Release = IDSHWRelease;
lpVtbl->CreateSoundBuffer = IDSHWCreateSoundBuffer;
lpVtbl->GetCaps = IDSHWGetCaps;
lpVtbl->DuplicateSoundBuffer
= IDSHWDuplicateSoundBuffer;
lpVtbl->SetCooperativeLevel = IDSHWSetCooperativeLevel;
lpVtbl->Compact = IDSHWCompact;
lpVtbl->GetSpeakerConfig = IDSHWGetSpeakerConfig;
lpVtbl->SetSpeakerConfig = IDSHWSetSpeakerConfig;
lpVtbl->Initialize = IDSHWInitialize;
} // DSHWCreateTable()
/* GetTopUnownedWindow
* This function finds the top-most unowned window ancesting for the
* given window handle.
*
* IN: a valid Window handle
* OUT: the top-most unowned window ancesting from hWindow
* SIDE EFFECTS: none
* NOTES: This function must be called in a Dll Critical Section
*
* REVISION HISTORY:
* 11/27/95 angusm Initial Version
* 12/06/95 angusm Removed supurpholous call to GetWindow( , GW_OWNER)
* 12/10/95 angusm Code style cleanup
*/
HWND GetTopUnownedWindow (HWND hWindow)
{
HWND hTempWindow = hWindow;
while (NULL != hTempWindow)
{
hWindow = hTempWindow;
ASSERT (hWindow);
hTempWindow = GetParent (hWindow); /* This call will return the owner,
if on exists, for top level
windows. */
}
return hWindow;
}
/* FocusTracker
* This function is a thread that runs in the process space of DDHelp,
* and polls to see which window is the top unowned window. If the window
* has changed the sound focus changes.
*
* IN: the number of miliseconds to wait between polls
* OUT: none
* SIDE EFFECTS: The sound focus will change
* NOTES: 1. The hwndStuckSoundFocus, and validity of the current Focus handle may
* change outside of this thread. (In apmResume and SetCooperativeL.
*
* REVISION HISTORY:
* 11/27/95 angusm Initial Version
* 12/10/95 angusm added FocusLock creation
* 12/10/95 angusm Code style cleanup
* 03/20/96 angusm Added Sticky focus logic
*/
DWORD WINAPI FocusTracker (LPVOID lpvPollInterval)
{
HWND hNewWindowFocus;
BOOL fIsNewWindowValid;
BOOL fIsNewWindowMinimized;
HWND hOldWindowFocus = NULL;
DWORD tidOldWindowFocus = 0;
BOOL fIsOldWindowValid = FALSE;
BOOL fIsOldWindowMinimized = FALSE;
HANDLE hWaitEvent;
HANDLE hFocusLock;
HANDLE hStartupEvent;
DWORD nRetVal;
WINDOWPLACEMENT wndplPlacement;
DWORD tid;
DPF (2, "FocusTracker: Enter Function (lpvPollInterval = %x)",
lpvPollInterval);
/* Create "Wait" Event */
hWaitEvent = CreateEvent (NULL, /* No security attribs */
TRUE, /* manual-reset */
FALSE, /* nonsignaled */
WAKEFOCUSTHREAD); /* event name */
if (NULL == hWaitEvent) { /* On Error ... */
DPF(0, "FocusTracker: Could not create DSWakeFocusThread "
"event; exiting" );
ExitThread (0);
}
/* Grab Focus Lock */
if (FALSE == CreateFocusLock (&hFocusLock)) {
DPF(1, "FocusTracker: Could not create Focus Lock" );
}
/* Open Focus Thread startup
startup verification event */
hStartupEvent = OpenEvent (EVENT_MODIFY_STATE, /* only allowed to pulse */
FALSE, /* non inheritable */
FOCUSSTARTUPEVENT);
if (NULL == hStartupEvent) { /* On Error ... */
DPF(0, "FocusTracker: Could not open Startup Event; exiting" );
if (FALSE == DestroyFocusLock (hFocusLock)) {
DPF (1, "FocusTracker: Could not destroy focus lock.");
}
if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
ExitThread (0);
}
/* Handle Cleanup */
if (FALSE == SetEvent (hStartupEvent)) ASSERT (0);
if (FALSE == CloseHandle (hStartupEvent)) ASSERT (0);
wndplPlacement.length = sizeof(WINDOWPLACEMENT);
while (1) /* Focus Tracking Loop */
{
DWORD dwWaitResult;
hNewWindowFocus = GetTopUnownedWindow (GetForegroundWindow());
if (hOldWindowFocus != hNewWindowFocus)
{
DWORD tidNewFocus;
DPF(3, "FocusTracker: New Focus = %x Old Focus = %x",
hNewWindowFocus, hOldWindowFocus);
tidNewFocus = hNewWindowFocus ? GetWindowThreadProcessId(hNewWindowFocus, NULL) : 0;
fIsNewWindowValid = IsValidDSApp(tidNewFocus);
nRetVal = ENTER_DLL_CSECT_OR_EVENT (hWaitEvent);
if (WAIT_OBJECT_0 == nRetVal) { /* If Wait Event is signaled */
DPF (3, "FocusTracker: breaking on Wait Event");
break;
} /* Else we have taken the DLL_CSECT */
if (hNewWindowFocus) {
GetWindowPlacement (hNewWindowFocus, &wndplPlacement);
fIsNewWindowMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
} else {
fIsNewWindowMinimized = FALSE;
}
if (fIsNewWindowValid && !fIsNewWindowMinimized)
/* New window uses Direct Sound and is not minimized */
{
DPF (3, "FocusTracker: switching to DS app"
" gpdsinfo->tidStuckFocus = %x, "
"tidNewFocus = %x",
gpdsinfo->tidStuckFocus, tidNewFocus);
// If focus is switching back to the hwnd that was stuck
// then we don't need to deactivate the stuck hwnd.
if (gpdsinfo->tidStuckFocus != tidNewFocus) {
DSDeactivateApp (gpdsinfo->tidStuckFocus,
DSDEACTIVATEAPPF_ALL);
gpdsinfo->tidStuckFocus = tidNewFocus;
}
DSActivateApp (tidNewFocus);
gpdsinfo->tidSoundFocus = tidNewFocus;
gpdsinfo->hwndSoundFocus = hNewWindowFocus;
}
else /* New window is not associated with a Direct Sound object,
or the application is minimized */
{
DPF (3, "FocusTracker: switching away from DS app"
" hOldWindowFocus = %x", hOldWindowFocus);
fIsOldWindowValid = IsValidDSApp (tidOldWindowFocus);
if (fIsOldWindowValid && gpdsinfo->hwndSoundFocus) {
DSDeactivateApp (gpdsinfo->tidSoundFocus,
DSDEACTIVATEAPPF_NONSTICKY);
}
if (fIsNewWindowMinimized && fIsNewWindowValid)
/* there is a minimized ds app */
{
gpdsinfo->tidSoundFocus = 0;
gpdsinfo->hwndSoundFocus = NULL;
}
else
{
gpdsinfo->tidSoundFocus = tidNewFocus;
gpdsinfo->hwndSoundFocus = hNewWindowFocus;
}
}
hOldWindowFocus = hNewWindowFocus;
tidOldWindowFocus = tidNewFocus;
fIsOldWindowValid = fIsNewWindowValid;
fIsOldWindowMinimized = fIsNewWindowMinimized;
LEAVE_DLL_CSECT();
} else if (fIsOldWindowValid && fIsOldWindowMinimized)
{
DPF (3, "FocusTracker: switching DS from minimization"
" hOldWindowFocus = %x", hOldWindowFocus);
ASSERT (hOldWindowFocus);
GetWindowPlacement (hOldWindowFocus, &wndplPlacement);
fIsNewWindowMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
/* Old window is a DS app but has been maximized */
if (!fIsNewWindowMinimized)
{
nRetVal = ENTER_DLL_CSECT_OR_EVENT (hWaitEvent);
if (WAIT_OBJECT_0 == nRetVal) { /* If Wait Event is signaled */
DPF (3, "FocusTracker: breaking on Wait Event");
break;
} /* Else we have taken the DLL_CSECT */
tid = GetWindowThreadProcessId(hOldWindowFocus, NULL);
if (gpdsinfo->tidStuckFocus != tid) {
DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
gpdsinfo->tidStuckFocus = tid;
}
DSActivateApp(tid);
gpdsinfo->tidSoundFocus = tid;
gpdsinfo->hwndSoundFocus = hOldWindowFocus;
fIsOldWindowMinimized = fIsNewWindowMinimized;
LEAVE_DLL_CSECT();
}
}
dwWaitResult = WaitForSingleObjectEx(hWaitEvent, (DWORD)lpvPollInterval, FALSE);
if (WAIT_OBJECT_0 == dwWaitResult) break;
ASSERT(WAIT_TIMEOUT == dwWaitResult);
} /* while (1) */
/* Free Focus Lock */
if (FALSE == DestroyFocusLock (hFocusLock)) {
DPF (1, "Could not destroy focus lock.");
}
/* Cleanup Handles */
if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
if (FALSE == CloseHandle (gpdsinfo->hFocusTracker)) ASSERT (0);
DPF (2, "FocusTracker: Exit Function");
ExitThread (0);
return 0; /* This should never be reached. */
}
/* IsValidDSApp
* This function walks the external Direct Sound structures to see if the
* given tid is a valid direct sound thread.
*
* IN: any tid
* OUT: TRUE if it is a Direct Sound thread, FALSE otherwise
* SIDE EFFECTS: none
* NOTES: This function must be called in a Dll Critical Section if you
* need the returned value to be correct. Otherwise, the returned value
* may be a false answer.
*
* REVISION HISTORY:
* 11/27/95 angusm Initial Version
* 12/06/95 angusm appended to NOTES:
* 12/10/95 angusm Added FocusLock calls
* 12/10/95 angusm Code style cleanup
*/
BOOL IsValidDSApp (DWORD dwTid)
{
LPDSOUNDEXTERNAL pdse = gpdsinfo->pDSoundExternalObj;
BOOL fReturnValue = FALSE;
HANDLE hFocusLock;
if (FALSE == GetFocusLock (&hFocusLock)) {
DPF(2, "Dsound: IsValidDSApp: Error getting Focus Lock.");
return FALSE;
}
while (NULL != pdse) {
if (dwTid == (pdse->tidSound)) {
ASSERT (0 != pdse->tidSound);
fReturnValue = TRUE;
break;
}
pdse = pdse->pNext;
}
if (FALSE == ReleaseFocusLock(hFocusLock)) {
DPF (2, "Dsound: IsValidDSApp: Could not release Focus Lock.");
ASSERT (0);
}
return fReturnValue;
}
/* cSoundObjects
* This function walks the external Direct Sound structures to count them.
*
* IN: none
* OUT: The number of external structures if 0 or 1, or 2 for 2 or more
* structures.
* SIDE EFFECTS: none
* NOTES: This function must be called in a Dll Critical Section
*
* REVISION HISTORY:
* 12/1/95 angusm Initial Version
* 12/10/95 angusm Code style cleanup
*/
int cSoundObjects ()
{
LPDSOUNDEXTERNAL pdse;
int cNumObjects = 0;
pdse = gpdsinfo->pDSoundExternalObj;
while ((NULL != pdse) && (2 >= cNumObjects))
{
pdse = pdse->pNext;
cNumObjects++;
}
return cNumObjects;
}
/* CreateFocusThread
* This function creates the Focus Thread.
*
* IN: none
* OUT: TRUE if Thread was created, or FALSE otherwise
* SIDE EFFECTS: a Focus Thread is created, and hWakeFocusThread, and
* hFocusThread handles are created.
* NOTES: This function must be called in a Dll Critical Section
*
* REVISION HISTORY:
* 12/1/95 angusm Initial Version
* 12/10/95 angusm Code style cleanup
*/
BOOL CreateFocusThread ()
{
HANDLE hFocusStartupEvent;
DWORD dwResult;
hFocusStartupEvent = CreateEvent (NULL, /* no security attribs */
FALSE, /* auto-reset */
FALSE, /* non signaled */
FOCUSSTARTUPEVENT);
if (NULL == hFocusStartupEvent) {
DPF (1, "Dsound: CreateFocusThread: Could not create "
"Focus Startup Event");
return FALSE;
}
gpdsinfo->hFocusTracker = HelperCreateDSFocusThread
((LPTHREAD_START_ROUTINE) FocusTracker, /* thread function */
(LPVOID) POLL_INTERVAL, /* parameter */
0, /* normal creation flags */
NULL); /* unwanted threadid */
if (NULL == gpdsinfo->hFocusTracker) {
DPF(1, "Could not start Focus Tracker thread in helper; exiting" );
if (FALSE == CloseHandle (hFocusStartupEvent)) ASSERT (0);
return FALSE;
}
dwResult = WaitForSingleObjectEx(hFocusStartupEvent, INFINITE, FALSE);
ASSERT(WAIT_OBJECT_0 == dwResult);
if (FALSE == CloseHandle (hFocusStartupEvent)) ASSERT (0);
return TRUE;
}
/* EndFocusThread
* This function will send an event to the Focus Thread running in DDHelp,
* and wait to see if it terminates. If it does not, the thread will be
* terminated.
*
* IN: none
* OUT: none
* SIDE EFFECTS: 1. Focus Thread will be killed.
* 2. hWakeFocusThread handle will be closed.
* 3. hFocusTracker hadnle will be closed.
* NOTES: This function must be called in a Dll Critical Section
*
* REVISION HISTORY:
* 11/30/95 angusm Initial Version
* 12/10/95 angusm Code style cleanup
*/
void EndFocusThread ()
{
HANDLE hWaitEvent, hHelper, hOurFocusTracker;
DWORD dwResult;
hWaitEvent = CreateEvent (NULL,
FALSE, /* auto-reset */
TRUE, /* if event object does not
already exists, create one
signaled */
WAKEFOCUSTHREAD); /* event name */
if (NULL == hWaitEvent)
{
DPF (1, "Dsound: EndFocusThread: Could not create "
"wait event");
return;
}
hHelper = OpenProcess (PROCESS_DUP_HANDLE,
FALSE, /* no inheritance */
gpdsinfo->pidHelper); /* Helper PID */
if (NULL == hHelper)
{
DPF (1, "Dsound: EndFocusThread: Could not open process");
if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
return;
}
if (FALSE ==
DuplicateHandle (hHelper, /* source process */
gpdsinfo->hFocusTracker, /* source handle */
GetCurrentProcess(), /* our process */
&hOurFocusTracker, /* our new handle */
SYNCHRONIZE | THREAD_TERMINATE, /* access flags */
FALSE, /* no inheritance */
0)) /* no options */
{ /* On Error ... */
DPF (1, "Dsound: EndFocusThread: Could not duplicate handle");
if (FALSE == CloseHandle (hHelper)) ASSERT (0);
if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
return;
}
if (FALSE == SetEvent (hWaitEvent)) ASSERT (0);
if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
dwResult = WaitForSingleObjectEx(hOurFocusTracker, INFINITE, FALSE);
ASSERT(WAIT_OBJECT_0 == dwResult);
if (FALSE == CloseHandle (hHelper)) ASSERT (0);
if (FALSE == CloseHandle (hOurFocusTracker)) ASSERT (0);
return;
}
/*
* DseUpdateActivationState
*
* Given the current tidSoundFocus and tidSticky, this function activates
* or deactivates all dsbe for a dse
*/
__inline void DseUpdateActivationState(LPDSOUNDEXTERNAL pdse)
{
LPDSBUFFEREXTERNAL pdsbe;
WINDOWPLACEMENT wndplPlacement;
BOOL fIsMinimized;
wndplPlacement.length = sizeof(WINDOWPLACEMENT);
ASSERT (pdse->hwndCooperative);
if (NULL != gpdsinfo->hwndSoundFocus) {
GetWindowPlacement (gpdsinfo->hwndSoundFocus, &wndplPlacement);
fIsMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
}
else fIsMinimized = FALSE;
if ((gpdsinfo->tidSoundFocus == pdse->tidSound) && !fIsMinimized) {
if (gpdsinfo->tidStuckFocus != pdse->tidSound) {
DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
}
gpdsinfo->tidStuckFocus = gpdsinfo->tidSoundFocus;
}
for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext)
{
if ((gpdsinfo->tidSoundFocus != pdsbe->pdse->tidSound) &&
!((gpdsinfo->tidStuckFocus == pdsbe->pdse->tidSound) &&
(DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
{
DSBufferDeactivate (pdsbe);
}
else
{
DSBufferActivate (pdsbe);
}
}
return;
}
/* DsbeDeactivateIfNecessary
*
* This function deactivates a buffer only if the buffer is current in focus.
*/
__inline void DsbeDeactivateIfNecessary (LPDSBUFFEREXTERNAL pdsbe)
{
DPF (2, "DsbeDeactivateIfNecessary: entered pdsbe = %x", pdsbe);
if ((gpdsinfo->tidSoundFocus != pdsbe->pdse->tidSound) &&
!((gpdsinfo->tidStuckFocus == pdsbe->pdse->tidSound) &&
(DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
{
DSBufferDeactivate (pdsbe);
}
return;
}
/* ActivateFocusWindow
*
* This function will set the gpdsinfo->hwndSticky handle properly. In addition
* it will Deactivate the current sticky hwnd and activate the the in focus
* hwnd.
*
* NOTE: This function must be called within a CSECT
*/
__inline void ActivateFocusWindow (void) {
if (gpdsinfo->tidSoundFocus != gpdsinfo->tidStuckFocus) {
DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
gpdsinfo->tidStuckFocus = gpdsinfo->tidSoundFocus;
}
DSActivateApp (gpdsinfo->tidSoundFocus);
}