📄 dsound.c
字号:
/* DirectSound
*
* Copyright 1998 Marcus Meissner
* Copyright 1998 Rob Riggs
* Copyright 2000-2002 TransGaming Technologies, Inc.
* Copyright 2004 Robert Reif
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdio.h>
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "mmsystem.h"
#include "winternl.h"
#include "mmddk.h"
#include "wine/debug.h"
#include "dsound.h"
#include "dsdriver.h"
#include "dsound_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dsound);
static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice);
static ULONG DirectSoundDevice_Release(DirectSoundDevice * device);
static const char * dumpCooperativeLevel(DWORD level)
{
static char unknown[32];
#define LE(x) case x: return #x
switch (level) {
LE(DSSCL_NORMAL);
LE(DSSCL_PRIORITY);
LE(DSSCL_EXCLUSIVE);
LE(DSSCL_WRITEPRIMARY);
}
#undef LE
sprintf(unknown, "Unknown(%08lx)", level);
return unknown;
}
static void _dump_DSCAPS(DWORD xmask) {
struct {
DWORD mask;
const char *name;
} flags[] = {
#define FE(x) { x, #x },
FE(DSCAPS_PRIMARYMONO)
FE(DSCAPS_PRIMARYSTEREO)
FE(DSCAPS_PRIMARY8BIT)
FE(DSCAPS_PRIMARY16BIT)
FE(DSCAPS_CONTINUOUSRATE)
FE(DSCAPS_EMULDRIVER)
FE(DSCAPS_CERTIFIED)
FE(DSCAPS_SECONDARYMONO)
FE(DSCAPS_SECONDARYSTEREO)
FE(DSCAPS_SECONDARY8BIT)
FE(DSCAPS_SECONDARY16BIT)
#undef FE
};
unsigned int i;
for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
if ((flags[i].mask & xmask) == flags[i].mask)
DPRINTF("%s ",flags[i].name);
}
static void _dump_DSBCAPS(DWORD xmask) {
struct {
DWORD mask;
const char *name;
} flags[] = {
#define FE(x) { x, #x },
FE(DSBCAPS_PRIMARYBUFFER)
FE(DSBCAPS_STATIC)
FE(DSBCAPS_LOCHARDWARE)
FE(DSBCAPS_LOCSOFTWARE)
FE(DSBCAPS_CTRL3D)
FE(DSBCAPS_CTRLFREQUENCY)
FE(DSBCAPS_CTRLPAN)
FE(DSBCAPS_CTRLVOLUME)
FE(DSBCAPS_CTRLPOSITIONNOTIFY)
FE(DSBCAPS_STICKYFOCUS)
FE(DSBCAPS_GLOBALFOCUS)
FE(DSBCAPS_GETCURRENTPOSITION2)
FE(DSBCAPS_MUTE3DATMAXDISTANCE)
#undef FE
};
unsigned int i;
for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
if ((flags[i].mask & xmask) == flags[i].mask)
DPRINTF("%s ",flags[i].name);
}
/*******************************************************************************
* IDirectSoundImpl_DirectSound
*/
static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
LPDIRECTSOUND8 iface,
REFIID riid,
LPVOID * ppobj)
{
TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppobj);
FIXME("shouldn't be called directly\n");
return E_NOINTERFACE;
}
static HRESULT WINAPI DSOUND_QueryInterface(
LPDIRECTSOUND8 iface,
REFIID riid,
LPVOID * ppobj)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
if (ppobj == NULL) {
WARN("invalid parameter\n");
return E_INVALIDARG;
}
if (IsEqualIID(riid, &IID_IUnknown)) {
if (!This->pUnknown) {
IDirectSound_IUnknown_Create(iface, &This->pUnknown);
if (!This->pUnknown) {
WARN("IDirectSound_IUnknown_Create() failed\n");
*ppobj = NULL;
return E_NOINTERFACE;
}
}
IDirectSound_IUnknown_AddRef(This->pUnknown);
*ppobj = This->pUnknown;
return S_OK;
} else if (IsEqualIID(riid, &IID_IDirectSound)) {
if (!This->pDS) {
IDirectSound_IDirectSound_Create(iface, &This->pDS);
if (!This->pDS) {
WARN("IDirectSound_IDirectSound_Create() failed\n");
*ppobj = NULL;
return E_NOINTERFACE;
}
}
IDirectSound_IDirectSound_AddRef(This->pDS);
*ppobj = This->pDS;
return S_OK;
}
*ppobj = NULL;
WARN("Unknown IID %s\n",debugstr_guid(riid));
return E_NOINTERFACE;
}
static HRESULT WINAPI DSOUND_QueryInterface8(
LPDIRECTSOUND8 iface,
REFIID riid,
LPVOID * ppobj)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
if (ppobj == NULL) {
WARN("invalid parameter\n");
return E_INVALIDARG;
}
if (IsEqualIID(riid, &IID_IUnknown)) {
if (!This->pUnknown) {
IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
if (!This->pUnknown) {
WARN("IDirectSound8_IUnknown_Create() failed\n");
*ppobj = NULL;
return E_NOINTERFACE;
}
}
IDirectSound8_IUnknown_AddRef(This->pUnknown);
*ppobj = This->pUnknown;
return S_OK;
} else if (IsEqualIID(riid, &IID_IDirectSound)) {
if (!This->pDS) {
IDirectSound8_IDirectSound_Create(iface, &This->pDS);
if (!This->pDS) {
WARN("IDirectSound8_IDirectSound_Create() failed\n");
*ppobj = NULL;
return E_NOINTERFACE;
}
}
IDirectSound8_IDirectSound_AddRef(This->pDS);
*ppobj = This->pDS;
return S_OK;
} else if (IsEqualIID(riid, &IID_IDirectSound8)) {
if (!This->pDS8) {
IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
if (!This->pDS8) {
WARN("IDirectSound8_IDirectSound8_Create() failed\n");
*ppobj = NULL;
return E_NOINTERFACE;
}
}
IDirectSound8_IDirectSound8_AddRef(This->pDS8);
*ppobj = This->pDS8;
return S_OK;
}
*ppobj = NULL;
WARN("Unknown IID %s\n",debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI IDirectSoundImpl_AddRef(
LPDIRECTSOUND8 iface)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
ULONG ref = InterlockedIncrement(&(This->ref));
TRACE("(%p) ref was %ld\n", This, ref - 1);
return ref;
}
static ULONG WINAPI IDirectSoundImpl_Release(
LPDIRECTSOUND8 iface)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
ULONG ref = InterlockedDecrement(&(This->ref));
TRACE("(%p) ref was %ld\n", This, ref + 1);
if (!ref) {
if (This->device)
DirectSoundDevice_Release(This->device);
HeapFree(GetProcessHeap(),0,This);
TRACE("(%p) released\n", This);
}
return ref;
}
static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
LPDIRECTSOUND8 iface,
LPCDSBUFFERDESC dsbd,
LPLPDIRECTSOUNDBUFFER ppdsb,
LPUNKNOWN lpunk)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
FIXME("shouldn't be called directly\n");
return DSERR_GENERIC;
}
static HRESULT WINAPI DSOUND_CreateSoundBuffer(
LPDIRECTSOUND8 iface,
LPCDSBUFFERDESC dsbd,
LPLPDIRECTSOUNDBUFFER ppdsb,
LPUNKNOWN lpunk,
BOOL from8)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
HRESULT hres = DS_OK;
TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
if (This->device == NULL) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (dsbd == NULL) {
WARN("invalid parameter: dsbd == NULL\n");
return DSERR_INVALIDPARAM;
}
if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
WARN("invalid parameter: dsbd\n");
return DSERR_INVALIDPARAM;
}
if (ppdsb == NULL) {
WARN("invalid parameter: ppdsb == NULL\n");
return DSERR_INVALIDPARAM;
}
if (TRACE_ON(dsound)) {
TRACE("(structsize=%ld)\n",dsbd->dwSize);
TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
_dump_DSBCAPS(dsbd->dwFlags);
DPRINTF(")\n");
TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
}
if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
if (dsbd->lpwfxFormat != NULL) {
WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
"primary buffer\n");
return DSERR_INVALIDPARAM;
}
if (This->device->primary) {
WARN("Primary Buffer already created\n");
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary));
*ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary);
} else {
This->device->dsbd = *dsbd;
hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->device->primary), &(This->device->dsbd));
if (This->device->primary) {
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary));
*ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary);
} else
WARN("PrimaryBufferImpl_Create failed\n");
}
} else {
IDirectSoundBufferImpl * dsb;
if (dsbd->lpwfxFormat == NULL) {
WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
"secondary buffer\n");
return DSERR_INVALIDPARAM;
}
TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
"bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
dsbd->lpwfxFormat->nSamplesPerSec,
dsbd->lpwfxFormat->nAvgBytesPerSec,
dsbd->lpwfxFormat->nBlockAlign,
dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
WARN("invalid parameter: 3D buffer format must be mono\n");
return DSERR_INVALIDPARAM;
}
hres = IDirectSoundBufferImpl_Create(This, (IDirectSoundBufferImpl**)&dsb, dsbd);
if (dsb) {
hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
if (*ppdsb) {
dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
} else
WARN("SecondaryBufferImpl_Create failed\n");
} else
WARN("IDirectSoundBufferImpl_Create failed\n");
}
return hres;
}
static HRESULT WINAPI IDirectSoundImpl_GetCaps(
LPDIRECTSOUND8 iface,
LPDSCAPS lpDSCaps)
{
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
DirectSoundDevice *device;
TRACE("(%p,%p)\n",This,lpDSCaps);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
device = This->device;
if (device == NULL) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (lpDSCaps == NULL) {
WARN("invalid parameter: lpDSCaps = NULL\n");
return DSERR_INVALIDPARAM;
}
/* check if there is enough room */
if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
lpDSCaps->dwSize, sizeof(*lpDSCaps));
return DSERR_INVALIDPARAM;
}
lpDSCaps->dwFlags = device->drvcaps.dwFlags;
if (TRACE_ON(dsound)) {
TRACE("(flags=0x%08lx:\n",lpDSCaps->dwFlags);
_dump_DSCAPS(lpDSCaps->dwFlags);
DPRINTF(")\n");
}
lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
/* driver doesn't have these */
lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
LPDIRECTSOUND8 iface,
LPDIRECTSOUNDBUFFER psb,
LPLPDIRECTSOUNDBUFFER ppdsb)
{
IDirectSoundBufferImpl* pdsb;
IDirectSoundBufferImpl* dsb;
HRESULT hres = DS_OK;
int size;
IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
if (This->device == NULL) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (psb == NULL) {
WARN("invalid parameter: psb == NULL\n");
return DSERR_INVALIDPARAM;
}
if (ppdsb == NULL) {
WARN("invalid parameter: ppdsb == NULL\n");
return DSERR_INVALIDPARAM;
}
/* FIXME: hack to make sure we have a secondary buffer */
if ((IDirectSoundImpl *)((SecondaryBufferImpl *)psb)->dsb == This) {
WARN("trying to duplicate primary buffer\n");
*ppdsb = NULL;
return DSERR_INVALIDCALL;
}
pdsb = ((SecondaryBufferImpl *)psb)->dsb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -