mirror of https://github.com/lianthony/NT4.0
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.
423 lines
11 KiB
423 lines
11 KiB
//--------------------------------------------------------------------------;
|
|
//
|
|
// File: idsi.c
|
|
//
|
|
// Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Abstract:
|
|
// This file contains worker functions called internally by
|
|
// IDirectSound member functions. These functions operate on
|
|
// DSOUND objects (i.e., internal direct sound objects) and
|
|
// do not perform parameter validation nor do they take the
|
|
// DLL critical sections. In all cases, the calling function
|
|
// is responsible for doing this.
|
|
//
|
|
// Contents:
|
|
// IDsCreateSoundBufferI
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
#include "dsoundpr.h"
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT DsInitializeDefaultFormat
|
|
//
|
|
// Description:
|
|
// Fills in the wfxDefault member of the ds object. The format
|
|
// is based on the system default stored in the dsinfo but may
|
|
// deviate depending on the capabilities of the ds object.
|
|
//
|
|
// Note that this may be called before the ds object has been
|
|
// completely constructed, as it is called from DirectSoundCreate.
|
|
//
|
|
// Arguments:
|
|
// LPDSOUND pds
|
|
//
|
|
// Return (DSVAL):
|
|
//
|
|
// History:
|
|
// 07/17/95 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
#define FNAME "DsInitializeDefaultFormat: "
|
|
HRESULT DsInitializeDefaultFormat(LPDSOUND pds)
|
|
{
|
|
LPWAVEFORMATEX pwfx;
|
|
DSDRIVERCAPS dsDrvCaps;
|
|
HRESULT hr;
|
|
|
|
// DirectSound supports only PCM formats for now.
|
|
// This function assumes PCM formats.
|
|
ASSERT(WAVE_FORMAT_PCM == gpdsinfo->pwfxUserDefault->wFormatTag);
|
|
|
|
pwfx = &pds->wfxDefault;
|
|
|
|
//
|
|
// Handle wave emulated ds objects
|
|
//
|
|
if (DS_INTERNALF_WAVEEMULATED & pds->fdwInternal) {
|
|
BOOL fBreak;
|
|
MMRESULT mmr;
|
|
int i, j, k;
|
|
|
|
//
|
|
// Start with the user default
|
|
//
|
|
CopyMemory(pwfx, gpdsinfo->pwfxUserDefault, sizeof(pds->wfxDefault));
|
|
|
|
// We search for a format that works.
|
|
//
|
|
// i loop cycles through nChannels
|
|
// j loop cycles through sample rate
|
|
// k loop cycles through bit resolution
|
|
//
|
|
// We loop like this so that the number of channels is least likely
|
|
// to deviate from the user format, sample rate is next least likely.
|
|
//
|
|
i = 0;
|
|
do {
|
|
|
|
j = 0;
|
|
do {
|
|
|
|
k = 0;
|
|
do {
|
|
|
|
// Fix up nBlockAlign and nAvgBytesPerSec
|
|
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample/8;
|
|
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
|
|
|
|
mmr = waveOutOpen(NULL, pds->uDeviceID, pwfx, 0, 0, WAVE_FORMAT_QUERY);
|
|
fBreak = (MMSYSERR_NOERROR == mmr);
|
|
|
|
if (fBreak) break;
|
|
|
|
if (pwfx->wBitsPerSample == 16) {
|
|
pwfx->wBitsPerSample = 8;
|
|
} else {
|
|
pwfx->wBitsPerSample = 16;
|
|
}
|
|
|
|
} while (++k < 2);
|
|
|
|
if (fBreak) break;
|
|
|
|
if (pwfx->nSamplesPerSec == 44100) {
|
|
pwfx->nSamplesPerSec = 22050;
|
|
} else if (pwfx->nSamplesPerSec == 22050) {
|
|
pwfx->nSamplesPerSec = 11025;
|
|
} else if (pwfx->nSamplesPerSec == 11025) {
|
|
pwfx->nSamplesPerSec = 8000;
|
|
} else {
|
|
pwfx->nSamplesPerSec = 44100;
|
|
}
|
|
|
|
} while (++j < 4);
|
|
|
|
if (fBreak) break;
|
|
|
|
if (pwfx->nChannels == 2) {
|
|
pwfx->nChannels = 1;
|
|
} else {
|
|
pwfx->nChannels = 2;
|
|
}
|
|
|
|
} while (++i < 2);
|
|
|
|
if (MMSYSERR_NOERROR != mmr) {
|
|
DPF(0, FNAME "error: waveOutOpen.Query returned %08Xh", mmr);
|
|
// Couldn't come up with anything. Put back user default.
|
|
CopyMemory(pwfx, gpdsinfo->pwfxUserDefault, sizeof(pds->wfxDefault));
|
|
return DSERR_GENERIC;
|
|
}
|
|
|
|
return DS_OK;
|
|
}
|
|
|
|
// If we fall through, we are not on a wave emulated object
|
|
ASSERT(0 == (DS_INTERNALF_WAVEEMULATED & pds->fdwInternal));
|
|
|
|
//
|
|
// Handle non-wave emulated ds objects
|
|
//
|
|
FillMemory(&dsDrvCaps, sizeof(dsDrvCaps), 0);
|
|
hr = vxdDrvGetCaps(pds->hHal, &dsDrvCaps);
|
|
if (DS_OK != hr) {
|
|
DPF(0, FNAME "error: vxdDrvGetDriverCaps returned %08Xh", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Start with the user default
|
|
//
|
|
CopyMemory(pwfx, gpdsinfo->pwfxUserDefault, sizeof(pds->wfxDefault));
|
|
|
|
// Adjust resolution
|
|
if (pwfx->wBitsPerSample == 16) {
|
|
if (!(DSCAPS_PRIMARY16BIT & dsDrvCaps.dwFlags)) {
|
|
// Try 8-bit
|
|
pwfx->wBitsPerSample = 8;
|
|
ASSERT(DSCAPS_PRIMARY8BIT & dsDrvCaps.dwFlags);
|
|
}
|
|
} else {
|
|
if (!(DSCAPS_PRIMARY8BIT & dsDrvCaps.dwFlags)) {
|
|
// Try 16-bit
|
|
pwfx->wBitsPerSample = 16;
|
|
ASSERT(DSCAPS_PRIMARY16BIT & dsDrvCaps.dwFlags);
|
|
}
|
|
}
|
|
|
|
// Adjust mono/stereo
|
|
if (pwfx->nChannels == 2) {
|
|
if (!(DSCAPS_PRIMARYSTEREO & dsDrvCaps.dwFlags)) {
|
|
// Try mono
|
|
pwfx->nChannels = 1;
|
|
ASSERT(DSCAPS_PRIMARYMONO & dsDrvCaps.dwFlags);
|
|
}
|
|
} else {
|
|
if (!(DSCAPS_PRIMARYMONO & dsDrvCaps.dwFlags)) {
|
|
// Try stereo
|
|
pwfx->nChannels = 2;
|
|
ASSERT(DSCAPS_PRIMARYSTEREO & dsDrvCaps.dwFlags);
|
|
}
|
|
}
|
|
|
|
// Fix up nBlockAlign and nAvgBytesPerSec
|
|
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample/8;
|
|
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
|
|
|
|
return DS_OK;
|
|
}
|
|
#undef FNAME
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT DsCreateHardwareBuffer
|
|
//
|
|
// Description:
|
|
//
|
|
// Arguments:
|
|
// LPDSOUND pds
|
|
//
|
|
// LPDSBUFFER pdsb
|
|
//
|
|
// LPDSBUFFERDESC pdsbd
|
|
//
|
|
// LPBOOL pfTrySoftware: If an error is encountered such that we
|
|
// should not retry creating the buffer as a software buffer,
|
|
// then this routine will write FALSE to this flag. Otherwise
|
|
// this routine WILL NOT WRITE to this flag.
|
|
//
|
|
// Return (DSVAL):
|
|
//
|
|
// History:
|
|
// 07/17/95 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
HRESULT DsCreateHardwareBuffer
|
|
(
|
|
LPDSOUND pds,
|
|
LPDSBUFFER pdsb,
|
|
LPDSBUFFERDESC pdsbd,
|
|
LPBOOL pfTrySoftware
|
|
)
|
|
{
|
|
LPWAVEFORMATEX pwfx = pdsb->pwfx;
|
|
DWORD dwcbBufferSize = pdsb->cbBufferSize;
|
|
DWORD dwFlags = pdsbd->dwFlags;
|
|
LPBYTE pBuffer = NULL;
|
|
HANDLE hBuffer = NULL;
|
|
DSVAL dsv = DS_OK;
|
|
|
|
pdsb->dwCardAddress = 0;
|
|
|
|
//
|
|
// We are asking for a HW buffer...
|
|
//
|
|
DPF(3,"HW Create HW buffer");
|
|
DPF(3,"HW Create - sample rate %d", pdsb->helInfo.dwSampleRate );
|
|
DPF(3,"HW Create - hfForamt %X", pdsb->helInfo.hfFormat );
|
|
|
|
//
|
|
// See whether we should use system memory for the sound buffer
|
|
//
|
|
if( (DSDDESC_USESYSTEMMEMORY & pds->fdwDriverDesc) &&
|
|
!(pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER ) ) {
|
|
|
|
// Allocate the buffer sound buffer in system memory
|
|
pBuffer = (LPBYTE)MemAlloc(dwcbBufferSize);
|
|
if(NULL == pBuffer) {
|
|
DPF(0,"DSDDESC_USESYSTEMMEMORY buffer alloc failed");
|
|
dsv = DSERR_OUTOFMEMORY;
|
|
*pfTrySoftware = FALSE;
|
|
goto retDestruct;
|
|
}
|
|
DPF(1, " allocated system memory at %08Xh", pBuffer);
|
|
}
|
|
|
|
//
|
|
// see whether to allocate on-card memory
|
|
//
|
|
if( (NULL != pds->pDriverHeap) && !(pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) ) {
|
|
// Use dmemmgr to allocate on-card buffer and pass
|
|
// that allocation to the driver
|
|
|
|
pdsb->dwCardAddress = VidMemAlloc( pds->pDriverHeap,
|
|
dwcbBufferSize + pds->dwMemAllocExtra,
|
|
1);
|
|
|
|
if (0 == pdsb->dwCardAddress) {
|
|
dsv = DSERR_ALLOCATED;
|
|
goto retDestruct;
|
|
}
|
|
|
|
DPF(1, " allocated card memory at %08Xh", pdsb->dwCardAddress);
|
|
}
|
|
|
|
//
|
|
// now ask driver to create sound buffer
|
|
//
|
|
dsv = vxdDrvCreateSoundBuffer( pds->hHal, pwfx,
|
|
dwFlags & DSBCAPS_DRIVERFLAGSMASK,
|
|
pdsb->dwCardAddress, &dwcbBufferSize,
|
|
&pBuffer, &hBuffer );
|
|
|
|
if (DS_OK != dsv) {
|
|
DPF(0,"vxdDrvCreateSoundBuffer failed");
|
|
hBuffer = NULL;
|
|
goto retDestruct;
|
|
}
|
|
|
|
//
|
|
// see whether we should set format via mmsystem
|
|
//
|
|
if ( (DSDDESC_DOMMSYSTEMSETFORMAT & pds->fdwDriverDesc) &&
|
|
(DSBCAPS_PRIMARYBUFFER & pdsbd->dwFlags) )
|
|
{
|
|
//
|
|
// We need to set the wave format by doing a waveOutOpen on the
|
|
// mmsystem wave device
|
|
//
|
|
UINT uDeviceID;
|
|
MMRESULT mmr;
|
|
|
|
DPF(3, "CreateSoundBuffer: DSDCAPS_DOMMSYSTEMSETFORMAT");
|
|
|
|
ASSERT(pds->hwo);
|
|
waveOutGetID(pds->hwo, &uDeviceID);
|
|
|
|
HelperWaveClose( (DWORD)(pds->hwo) );
|
|
pds->hwo = NULL;
|
|
|
|
mmr = (MMRESULT)HelperWaveOpen(&(pds->hwo),
|
|
uDeviceID,
|
|
pwfx);
|
|
|
|
if (MMSYSERR_NOERROR != mmr) {
|
|
pds->hwo = NULL;
|
|
if (MMSYSERR_ALLOCATED == mmr) dsv = DSERR_BUFFERLOST;
|
|
if (MMSYSERR_NOMEM == mmr) dsv = DSERR_OUTOFMEMORY;
|
|
if (DS_OK == dsv) dsv = DSERR_GENERIC;
|
|
|
|
*pfTrySoftware = FALSE;
|
|
goto retDestruct;
|
|
}
|
|
}
|
|
|
|
//
|
|
// all went okay
|
|
//
|
|
DPF(3,"IDSHWCreateSoundBuffer buffer alloc OK");
|
|
DPF(3," lin addr %X", pBuffer );
|
|
DPF(3," length %X", dwcbBufferSize );
|
|
|
|
ASSERT(NULL != hBuffer);
|
|
pdsb->hBuffer = hBuffer;
|
|
pdsb->pDSBuffer = pBuffer;
|
|
pdsb->cbBufferSize = dwcbBufferSize;
|
|
|
|
pdsb->fdwDsbI &= (~DSB_INTERNALF_EMULATED);
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_HARDWARE;
|
|
|
|
retDestruct:
|
|
if (DS_OK == dsv) return dsv;
|
|
|
|
// release buffer
|
|
if (NULL != hBuffer) {
|
|
vxdBufferRelease(hBuffer);
|
|
hBuffer = NULL;
|
|
}
|
|
|
|
// free card memory
|
|
if (0 != pdsb->dwCardAddress) {
|
|
ASSERT(NULL != pds->pDriverHeap);
|
|
ASSERT(!(pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER));
|
|
VidMemFree(pds->pDriverHeap, pdsb->dwCardAddress);
|
|
pdsb->dwCardAddress = 0;
|
|
}
|
|
|
|
// free sysalloc mem
|
|
if( (DSDDESC_USESYSTEMMEMORY & pds->fdwDriverDesc) &&
|
|
(0 == (pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) &&
|
|
(NULL != pBuffer) ) {
|
|
MemFree(pBuffer);
|
|
pBuffer = NULL;
|
|
}
|
|
|
|
return dsv;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// HRESULT DsCreateSoftwareBuffer
|
|
//
|
|
// Description:
|
|
//
|
|
// Arguments:
|
|
// LPDSOUND pds
|
|
//
|
|
// LPDSBUFFER pdsb
|
|
//
|
|
// LPDSBUFFERDESC pdsbd
|
|
//
|
|
// Return (DSVAL):
|
|
//
|
|
// History:
|
|
// 07/17/95 FrankYe Created
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
HRESULT DsCreateSoftwareBuffer
|
|
(
|
|
LPDSOUND pds,
|
|
LPDSBUFFER pdsb,
|
|
LPDSBUFFERDESC pdsbd
|
|
)
|
|
{
|
|
|
|
DPF(3,"HW Create Emulated secondary buffer");
|
|
|
|
// Allocate the buffer
|
|
pdsb->pDSBuffer = (LPBYTE)MemAlloc(pdsbd->dwBufferBytes);
|
|
if(NULL == pdsb->pDSBuffer) {
|
|
DPF(1,"IDSHWCreateSoundBuffer buffer alloc fail");
|
|
return DSERR_OUTOFMEMORY;
|
|
}
|
|
|
|
pdsb->cbBufferSize = pdsbd->dwBufferBytes;
|
|
|
|
pdsb->fdwDsbI &= (~DSB_INTERNALF_HARDWARE);
|
|
pdsb->fdwDsbI |= DSB_INTERNALF_EMULATED;
|
|
|
|
// Make sure both copies of the flags reflect that this
|
|
// is a software buffer.
|
|
pdsbd->dwFlags &= (~DSBCAPS_LOCHARDWARE);
|
|
pdsbd->dwFlags |= DSBCAPS_LOCSOFTWARE;
|
|
pdsb->fdwBufferDesc &= (~DSBCAPS_LOCHARDWARE);
|
|
pdsb->fdwBufferDesc |= DSBCAPS_LOCSOFTWARE;
|
|
|
|
|
|
DPF(3,"--------Alloc data for Emulated obj %X buff %X len %X",
|
|
pdsb, pdsb->pDSBuffer, pdsb->cbBufferSize );
|
|
|
|
return DS_OK;
|
|
}
|