//--------------------------------------------------------------------------; // // 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; }