| /* 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 "winuser.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); |
| |
| 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 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 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 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 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; |
| } |
| |
| HRESULT IDirectSoundImpl_Create( |
| LPDIRECTSOUND8 * ppDS) |
| { |
| IDirectSoundImpl* pDS; |
| TRACE("(%p)\n",ppDS); |
| |
| /* Allocate memory */ |
| pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl)); |
| if (pDS == NULL) { |
| WARN("out of memory\n"); |
| *ppDS = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pDS->ref = 0; |
| pDS->device = NULL; |
| |
| *ppDS = (LPDIRECTSOUND8)pDS; |
| |
| return DS_OK; |
| } |
| |
| /******************************************************************************* |
| * IDirectSound_IUnknown |
| */ |
| static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface( |
| LPUNKNOWN iface, |
| REFIID riid, |
| LPVOID * ppobj) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| return DSOUND_QueryInterface(This->pds, riid, ppobj); |
| } |
| |
| static ULONG WINAPI IDirectSound_IUnknown_AddRef( |
| LPUNKNOWN iface) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| ULONG ref = InterlockedIncrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref - 1); |
| return ref; |
| } |
| |
| static ULONG WINAPI IDirectSound_IUnknown_Release( |
| LPUNKNOWN iface) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| ULONG ref = InterlockedDecrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref + 1); |
| if (!ref) { |
| IDirectSoundImpl_Release(This->pds); |
| HeapFree(GetProcessHeap(), 0, This); |
| TRACE("(%p) released\n", This); |
| } |
| return ref; |
| } |
| |
| static const IUnknownVtbl DirectSound_Unknown_Vtbl = |
| { |
| IDirectSound_IUnknown_QueryInterface, |
| IDirectSound_IUnknown_AddRef, |
| IDirectSound_IUnknown_Release |
| }; |
| |
| HRESULT IDirectSound_IUnknown_Create( |
| LPDIRECTSOUND8 pds, |
| LPUNKNOWN * ppunk) |
| { |
| IDirectSound_IUnknown * pdsunk; |
| TRACE("(%p,%p)\n",pds,ppunk); |
| |
| if (ppunk == NULL) { |
| ERR("invalid parameter: ppunk == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pds == NULL) { |
| ERR("invalid parameter: pds == NULL\n"); |
| *ppunk = NULL; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk)); |
| if (pdsunk == NULL) { |
| WARN("out of memory\n"); |
| *ppunk = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl; |
| pdsunk->ref = 0; |
| pdsunk->pds = pds; |
| |
| IDirectSoundImpl_AddRef(pds); |
| *ppunk = (LPUNKNOWN)pdsunk; |
| |
| return DS_OK; |
| } |
| |
| /******************************************************************************* |
| * IDirectSound_IDirectSound |
| */ |
| static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface( |
| LPDIRECTSOUND iface, |
| REFIID riid, |
| LPVOID * ppobj) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| return DSOUND_QueryInterface(This->pds, riid, ppobj); |
| } |
| |
| static ULONG WINAPI IDirectSound_IDirectSound_AddRef( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| ULONG ref = InterlockedIncrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref - 1); |
| return ref; |
| } |
| |
| static ULONG WINAPI IDirectSound_IDirectSound_Release( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| ULONG ref = InterlockedDecrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref + 1); |
| if (!ref) { |
| IDirectSoundImpl_Release(This->pds); |
| HeapFree(GetProcessHeap(), 0, This); |
| TRACE("(%p) released\n", This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer( |
| LPDIRECTSOUND iface, |
| LPCDSBUFFERDESC dsbd, |
| LPLPDIRECTSOUNDBUFFER ppdsb, |
| LPUNKNOWN lpunk) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk); |
| return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps( |
| LPDIRECTSOUND iface, |
| LPDSCAPS lpDSCaps) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,%p)\n",This,lpDSCaps); |
| return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer( |
| LPDIRECTSOUND iface, |
| LPDIRECTSOUNDBUFFER psb, |
| LPLPDIRECTSOUNDBUFFER ppdsb) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,%p,%p)\n",This,psb,ppdsb); |
| return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel( |
| LPDIRECTSOUND iface, |
| HWND hwnd, |
| DWORD level) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); |
| return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_Compact( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p)\n", This); |
| return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig( |
| LPDIRECTSOUND iface, |
| LPDWORD lpdwSpeakerConfig) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p, %p)\n", This, lpdwSpeakerConfig); |
| return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig( |
| LPDIRECTSOUND iface, |
| DWORD config) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p,0x%08lx)\n",This,config); |
| return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config); |
| } |
| |
| static HRESULT WINAPI IDirectSound_IDirectSound_Initialize( |
| LPDIRECTSOUND iface, |
| LPCGUID lpcGuid) |
| { |
| IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; |
| TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid)); |
| return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid); |
| } |
| |
| static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl = |
| { |
| IDirectSound_IDirectSound_QueryInterface, |
| IDirectSound_IDirectSound_AddRef, |
| IDirectSound_IDirectSound_Release, |
| IDirectSound_IDirectSound_CreateSoundBuffer, |
| IDirectSound_IDirectSound_GetCaps, |
| IDirectSound_IDirectSound_DuplicateSoundBuffer, |
| IDirectSound_IDirectSound_SetCooperativeLevel, |
| IDirectSound_IDirectSound_Compact, |
| IDirectSound_IDirectSound_GetSpeakerConfig, |
| IDirectSound_IDirectSound_SetSpeakerConfig, |
| IDirectSound_IDirectSound_Initialize |
| }; |
| |
| HRESULT IDirectSound_IDirectSound_Create( |
| LPDIRECTSOUND8 pds, |
| LPDIRECTSOUND * ppds) |
| { |
| IDirectSound_IDirectSound * pdsds; |
| TRACE("(%p,%p)\n",pds,ppds); |
| |
| if (ppds == NULL) { |
| ERR("invalid parameter: ppds == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pds == NULL) { |
| ERR("invalid parameter: pds == NULL\n"); |
| *ppds = NULL; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds)); |
| if (pdsds == NULL) { |
| WARN("out of memory\n"); |
| *ppds = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl; |
| pdsds->ref = 0; |
| pdsds->pds = pds; |
| |
| IDirectSoundImpl_AddRef(pds); |
| *ppds = (LPDIRECTSOUND)pdsds; |
| |
| return DS_OK; |
| } |
| |
| /******************************************************************************* |
| * IDirectSound8_IUnknown |
| */ |
| static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface( |
| LPUNKNOWN iface, |
| REFIID riid, |
| LPVOID * ppobj) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| return DSOUND_QueryInterface8(This->pds, riid, ppobj); |
| } |
| |
| static ULONG WINAPI IDirectSound8_IUnknown_AddRef( |
| LPUNKNOWN iface) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| ULONG ref = InterlockedIncrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref - 1); |
| return ref; |
| } |
| |
| static ULONG WINAPI IDirectSound8_IUnknown_Release( |
| LPUNKNOWN iface) |
| { |
| IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; |
| ULONG ref = InterlockedDecrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref + 1); |
| if (!ref) { |
| IDirectSoundImpl_Release(This->pds); |
| HeapFree(GetProcessHeap(), 0, This); |
| TRACE("(%p) released\n", This); |
| } |
| return ref; |
| } |
| |
| static const IUnknownVtbl DirectSound8_Unknown_Vtbl = |
| { |
| IDirectSound8_IUnknown_QueryInterface, |
| IDirectSound8_IUnknown_AddRef, |
| IDirectSound8_IUnknown_Release |
| }; |
| |
| HRESULT IDirectSound8_IUnknown_Create( |
| LPDIRECTSOUND8 pds, |
| LPUNKNOWN * ppunk) |
| { |
| IDirectSound8_IUnknown * pdsunk; |
| TRACE("(%p,%p)\n",pds,ppunk); |
| |
| if (ppunk == NULL) { |
| ERR("invalid parameter: ppunk == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pds == NULL) { |
| ERR("invalid parameter: pds == NULL\n"); |
| *ppunk = NULL; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk)); |
| if (pdsunk == NULL) { |
| WARN("out of memory\n"); |
| *ppunk = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl; |
| pdsunk->ref = 0; |
| pdsunk->pds = pds; |
| |
| IDirectSoundImpl_AddRef(pds); |
| *ppunk = (LPUNKNOWN)pdsunk; |
| |
| return DS_OK; |
| } |
| |
| /******************************************************************************* |
| * IDirectSound8_IDirectSound |
| */ |
| static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface( |
| LPDIRECTSOUND iface, |
| REFIID riid, |
| LPVOID * ppobj) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| return DSOUND_QueryInterface8(This->pds, riid, ppobj); |
| } |
| |
| static ULONG WINAPI IDirectSound8_IDirectSound_AddRef( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| ULONG ref = InterlockedIncrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref - 1); |
| return ref; |
| } |
| |
| static ULONG WINAPI IDirectSound8_IDirectSound_Release( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| ULONG ref = InterlockedDecrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref + 1); |
| if (!ref) { |
| IDirectSoundImpl_Release(This->pds); |
| HeapFree(GetProcessHeap(), 0, This); |
| TRACE("(%p) released\n", This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer( |
| LPDIRECTSOUND iface, |
| LPCDSBUFFERDESC dsbd, |
| LPLPDIRECTSOUNDBUFFER ppdsb, |
| LPUNKNOWN lpunk) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk); |
| return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps( |
| LPDIRECTSOUND iface, |
| LPDSCAPS lpDSCaps) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%p)\n",This,lpDSCaps); |
| return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer( |
| LPDIRECTSOUND iface, |
| LPDIRECTSOUNDBUFFER psb, |
| LPLPDIRECTSOUNDBUFFER ppdsb) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%p,%p)\n",This,psb,ppdsb); |
| return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel( |
| LPDIRECTSOUND iface, |
| HWND hwnd, |
| DWORD level) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); |
| return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_Compact( |
| LPDIRECTSOUND iface) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p)\n", This); |
| return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig( |
| LPDIRECTSOUND iface, |
| LPDWORD lpdwSpeakerConfig) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p, %p)\n", This, lpdwSpeakerConfig); |
| return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig( |
| LPDIRECTSOUND iface, |
| DWORD config) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,0x%08lx)\n",This,config); |
| return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize( |
| LPDIRECTSOUND iface, |
| LPCGUID lpcGuid) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid)); |
| return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid); |
| } |
| |
| static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl = |
| { |
| IDirectSound8_IDirectSound_QueryInterface, |
| IDirectSound8_IDirectSound_AddRef, |
| IDirectSound8_IDirectSound_Release, |
| IDirectSound8_IDirectSound_CreateSoundBuffer, |
| IDirectSound8_IDirectSound_GetCaps, |
| IDirectSound8_IDirectSound_DuplicateSoundBuffer, |
| IDirectSound8_IDirectSound_SetCooperativeLevel, |
| IDirectSound8_IDirectSound_Compact, |
| IDirectSound8_IDirectSound_GetSpeakerConfig, |
| IDirectSound8_IDirectSound_SetSpeakerConfig, |
| IDirectSound8_IDirectSound_Initialize |
| }; |
| |
| HRESULT IDirectSound8_IDirectSound_Create( |
| LPDIRECTSOUND8 pds, |
| LPDIRECTSOUND * ppds) |
| { |
| IDirectSound8_IDirectSound * pdsds; |
| TRACE("(%p,%p)\n",pds,ppds); |
| |
| if (ppds == NULL) { |
| ERR("invalid parameter: ppds == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pds == NULL) { |
| ERR("invalid parameter: pds == NULL\n"); |
| *ppds = NULL; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds)); |
| if (pdsds == NULL) { |
| WARN("out of memory\n"); |
| *ppds = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl; |
| pdsds->ref = 0; |
| pdsds->pds = pds; |
| |
| IDirectSoundImpl_AddRef(pds); |
| *ppds = (LPDIRECTSOUND)pdsds; |
| |
| return DS_OK; |
| } |
| |
| /******************************************************************************* |
| * IDirectSound8_IDirectSound8 |
| */ |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface( |
| LPDIRECTSOUND8 iface, |
| REFIID riid, |
| LPVOID * ppobj) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| return DSOUND_QueryInterface8(This->pds, riid, ppobj); |
| } |
| |
| static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef( |
| LPDIRECTSOUND8 iface) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| ULONG ref = InterlockedIncrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref - 1); |
| return ref; |
| } |
| |
| static ULONG WINAPI IDirectSound8_IDirectSound8_Release( |
| LPDIRECTSOUND8 iface) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| ULONG ref = InterlockedDecrement(&(This->ref)); |
| TRACE("(%p) ref was %ld\n", This, ref + 1); |
| if (!ref) { |
| IDirectSoundImpl_Release(This->pds); |
| HeapFree(GetProcessHeap(), 0, This); |
| TRACE("(%p) released\n", This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer( |
| LPDIRECTSOUND8 iface, |
| LPCDSBUFFERDESC dsbd, |
| LPLPDIRECTSOUNDBUFFER ppdsb, |
| LPUNKNOWN lpunk) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk); |
| return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps( |
| LPDIRECTSOUND8 iface, |
| LPDSCAPS lpDSCaps) |
| { |
| IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; |
| TRACE("(%p,%p)\n",This,lpDSCaps); |
| return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer( |
| LPDIRECTSOUND8 iface, |
| LPDIRECTSOUNDBUFFER psb, |
| LPLPDIRECTSOUNDBUFFER ppdsb) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p,%p,%p)\n",This,psb,ppdsb); |
| return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel( |
| LPDIRECTSOUND8 iface, |
| HWND hwnd, |
| DWORD level) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); |
| return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact( |
| LPDIRECTSOUND8 iface) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p)\n", This); |
| return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig( |
| LPDIRECTSOUND8 iface, |
| LPDWORD lpdwSpeakerConfig) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p, %p)\n", This, lpdwSpeakerConfig); |
| return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig( |
| LPDIRECTSOUND8 iface, |
| DWORD config) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p,0x%08lx)\n",This,config); |
| return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize( |
| LPDIRECTSOUND8 iface, |
| LPCGUID lpcGuid) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid)); |
| return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid); |
| } |
| |
| static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification( |
| LPDIRECTSOUND8 iface, |
| LPDWORD pdwCertified) |
| { |
| IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; |
| TRACE("(%p, %p)\n", This, pdwCertified); |
| return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified); |
| } |
| |
| static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl = |
| { |
| IDirectSound8_IDirectSound8_QueryInterface, |
| IDirectSound8_IDirectSound8_AddRef, |
| IDirectSound8_IDirectSound8_Release, |
| IDirectSound8_IDirectSound8_CreateSoundBuffer, |
| IDirectSound8_IDirectSound8_GetCaps, |
| IDirectSound8_IDirectSound8_DuplicateSoundBuffer, |
| IDirectSound8_IDirectSound8_SetCooperativeLevel, |
| IDirectSound8_IDirectSound8_Compact, |
| IDirectSound8_IDirectSound8_GetSpeakerConfig, |
| IDirectSound8_IDirectSound8_SetSpeakerConfig, |
| IDirectSound8_IDirectSound8_Initialize, |
| IDirectSound8_IDirectSound8_VerifyCertification |
| }; |
| |
| HRESULT IDirectSound8_IDirectSound8_Create( |
| LPDIRECTSOUND8 pds, |
| LPDIRECTSOUND8 * ppds) |
| { |
| IDirectSound8_IDirectSound8 * pdsds; |
| TRACE("(%p,%p)\n",pds,ppds); |
| |
| if (ppds == NULL) { |
| ERR("invalid parameter: ppds == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pds == NULL) { |
| ERR("invalid parameter: pds == NULL\n"); |
| *ppds = NULL; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds)); |
| if (pdsds == NULL) { |
| WARN("out of memory\n"); |
| *ppds = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl; |
| pdsds->ref = 0; |
| pdsds->pds = pds; |
| |
| IDirectSoundImpl_AddRef(pds); |
| *ppds = (LPDIRECTSOUND8)pdsds; |
| |
| return DS_OK; |
| } |
| |
| HRESULT DSOUND_Create( |
| LPDIRECTSOUND *ppDS, |
| IUnknown *pUnkOuter) |
| { |
| LPDIRECTSOUND8 pDS; |
| HRESULT hr; |
| TRACE("(%p,%p)\n",ppDS,pUnkOuter); |
| |
| /* Get dsound configuration */ |
| setup_dsound_options(); |
| |
| hr = IDirectSoundImpl_Create(&pDS); |
| if (hr == DS_OK) { |
| hr = IDirectSound_IDirectSound_Create(pDS, ppDS); |
| if (*ppDS) |
| IDirectSound_IDirectSound_AddRef(*ppDS); |
| else { |
| WARN("IDirectSound_IDirectSound_Create failed\n"); |
| IDirectSound8_Release(pDS); |
| } |
| } else { |
| WARN("IDirectSoundImpl_Create failed\n"); |
| *ppDS = 0; |
| } |
| |
| return hr; |
| } |
| |
| /******************************************************************************* |
| * DirectSoundCreate (DSOUND.1) |
| * |
| * Creates and initializes a DirectSound interface. |
| * |
| * PARAMS |
| * lpcGUID [I] Address of the GUID that identifies the sound device. |
| * ppDS [O] Address of a variable to receive the interface pointer. |
| * pUnkOuter [I] Must be NULL. |
| * |
| * RETURNS |
| * Success: DS_OK |
| * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION, |
| * DSERR_NODRIVER, DSERR_OUTOFMEMORY |
| */ |
| HRESULT WINAPI DirectSoundCreate( |
| LPCGUID lpcGUID, |
| LPDIRECTSOUND *ppDS, |
| IUnknown *pUnkOuter) |
| { |
| HRESULT hr; |
| LPDIRECTSOUND pDS; |
| |
| TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); |
| |
| if (ppDS == NULL) { |
| WARN("invalid parameter: ppDS == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pUnkOuter != NULL) { |
| WARN("invalid parameter: pUnkOuter != NULL\n"); |
| *ppDS = 0; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| hr = DSOUND_Create(&pDS, pUnkOuter); |
| if (hr == DS_OK) { |
| hr = IDirectSound_Initialize(pDS, lpcGUID); |
| if (hr != DS_OK) { |
| if (hr != DSERR_ALREADYINITIALIZED) { |
| IDirectSound_Release(pDS); |
| pDS = 0; |
| } else |
| hr = DS_OK; |
| } |
| } |
| |
| *ppDS = pDS; |
| |
| return hr; |
| } |
| |
| HRESULT DSOUND_Create8( |
| LPDIRECTSOUND8 *ppDS, |
| IUnknown *pUnkOuter) |
| { |
| LPDIRECTSOUND8 pDS; |
| HRESULT hr; |
| TRACE("(%p,%p)\n",ppDS,pUnkOuter); |
| |
| /* Get dsound configuration */ |
| setup_dsound_options(); |
| |
| hr = IDirectSoundImpl_Create(&pDS); |
| if (hr == DS_OK) { |
| hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS); |
| if (*ppDS) |
| IDirectSound8_IDirectSound8_AddRef(*ppDS); |
| else { |
| WARN("IDirectSound8_IDirectSound8_Create failed\n"); |
| IDirectSound8_Release(pDS); |
| } |
| } else { |
| WARN("IDirectSoundImpl_Create failed\n"); |
| *ppDS = 0; |
| } |
| |
| return hr; |
| } |
| |
| /******************************************************************************* |
| * DirectSoundCreate8 (DSOUND.11) |
| * |
| * Creates and initializes a DirectSound8 interface. |
| * |
| * PARAMS |
| * lpcGUID [I] Address of the GUID that identifies the sound device. |
| * ppDS [O] Address of a variable to receive the interface pointer. |
| * pUnkOuter [I] Must be NULL. |
| * |
| * RETURNS |
| * Success: DS_OK |
| * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION, |
| * DSERR_NODRIVER, DSERR_OUTOFMEMORY |
| */ |
| HRESULT WINAPI DirectSoundCreate8( |
| LPCGUID lpcGUID, |
| LPDIRECTSOUND8 *ppDS, |
| IUnknown *pUnkOuter) |
| { |
| HRESULT hr; |
| LPDIRECTSOUND8 pDS; |
| |
| TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); |
| |
| if (ppDS == NULL) { |
| WARN("invalid parameter: ppDS == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| if (pUnkOuter != NULL) { |
| WARN("invalid parameter: pUnkOuter != NULL\n"); |
| *ppDS = 0; |
| return DSERR_INVALIDPARAM; |
| } |
| |
| hr = DSOUND_Create8(&pDS, pUnkOuter); |
| if (hr == DS_OK) { |
| hr = IDirectSound8_Initialize(pDS, lpcGUID); |
| if (hr != DS_OK) { |
| if (hr != DSERR_ALREADYINITIALIZED) { |
| IDirectSound8_Release(pDS); |
| pDS = 0; |
| } else |
| hr = DS_OK; |
| } |
| } |
| |
| *ppDS = pDS; |
| |
| return hr; |
| } |
| |
| /******************************************************************************* |
| * DirectSoundDevice |
| */ |
| HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) |
| { |
| DirectSoundDevice * device; |
| TRACE("(%p)\n", ppDevice); |
| |
| /* Allocate memory */ |
| device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice)); |
| if (device == NULL) { |
| WARN("out of memory\n"); |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| device->ref = 1; |
| device->driver = NULL; |
| device->priolevel = DSSCL_NORMAL; |
| device->fraglen = 0; |
| device->hwbuf = NULL; |
| device->buffer = NULL; |
| device->buflen = 0; |
| device->writelead = 0; |
| device->state = STATE_STOPPED; |
| device->nrofbuffers = 0; |
| device->buffers = NULL; |
| device->primary = NULL; |
| device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16); |
| device->tmp_buffer = NULL; |
| device->tmp_buffer_len = 0; |
| |
| /* 3D listener initial parameters */ |
| device->listener = NULL; |
| device->ds3dl.dwSize = sizeof(DS3DLISTENER); |
| device->ds3dl.vPosition.x = 0.0; |
| device->ds3dl.vPosition.y = 0.0; |
| device->ds3dl.vPosition.z = 0.0; |
| device->ds3dl.vVelocity.x = 0.0; |
| device->ds3dl.vVelocity.y = 0.0; |
| device->ds3dl.vVelocity.z = 0.0; |
| device->ds3dl.vOrientFront.x = 0.0; |
| device->ds3dl.vOrientFront.y = 0.0; |
| device->ds3dl.vOrientFront.z = 1.0; |
| device->ds3dl.vOrientTop.x = 0.0; |
| device->ds3dl.vOrientTop.y = 1.0; |
| device->ds3dl.vOrientTop.z = 0.0; |
| device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; |
| device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; |
| device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; |
| |
| device->prebuf = ds_snd_queue_max; |
| device->guid = GUID_NULL; |
| |
| /* Set default wave format (may need it for waveOutOpen) */ |
| device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX)); |
| if (device->pwfx == NULL) { |
| WARN("out of memory\n"); |
| HeapFree(GetProcessHeap(),0,device); |
| return DSERR_OUTOFMEMORY; |
| } |
| |
| /* We rely on the sound driver to return the actual sound format of |
| * the device if it does not support 22050x8x2 and is given the |
| * WAVE_DIRECTSOUND flag. |
| */ |
| device->pwfx->wFormatTag = WAVE_FORMAT_PCM; |
| device->pwfx->nSamplesPerSec = 22050; |
| device->pwfx->wBitsPerSample = 8; |
| device->pwfx->nChannels = 2; |
| device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8; |
| device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign; |
| device->pwfx->cbSize = 0; |
| |
| InitializeCriticalSection(&(device->mixlock)); |
| device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUND_mixlock"; |
| |
| RtlInitializeResource(&(device->buffer_list_lock)); |
| |
| *ppDevice = device; |
| |
| return DS_OK; |
| } |
| |
| ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device) |
| { |
| ULONG ref = InterlockedIncrement(&(device->ref)); |
| TRACE("(%p) ref was %ld\n", device, ref - 1); |
| return ref; |
| } |
| |
| ULONG DirectSoundDevice_Release(DirectSoundDevice * device) |
| { |
| HRESULT hr; |
| ULONG ref = InterlockedDecrement(&(device->ref)); |
| TRACE("(%p) ref was %lu\n", device, ref + 1); |
| if (!ref) { |
| int i; |
| timeKillEvent(device->timerID); |
| timeEndPeriod(DS_TIME_RES); |
| /* wait for timer to expire */ |
| Sleep(DS_TIME_RES+1); |
| |
| /* The sleep above should have allowed the timer process to expire |
| * but try to grab the lock just in case. Can't hold lock because |
| * IDirectSoundBufferImpl_Destroy also grabs the lock */ |
| RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE); |
| RtlReleaseResource(&(device->buffer_list_lock)); |
| |
| /* It is allowed to release this object even when buffers are playing */ |
| if (device->buffers) { |
| WARN("%d secondary buffers not released\n", device->nrofbuffers); |
| for( i=0;i<device->nrofbuffers;i++) |
| IDirectSoundBufferImpl_Destroy(device->buffers[i]); |
| } |
| |
| if (device->primary) { |
| WARN("primary buffer not released\n"); |
| IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary); |
| } |
| |
| hr = DSOUND_PrimaryDestroy(device); |
| if (hr != DS_OK) |
| WARN("DSOUND_PrimaryDestroy failed\n"); |
| |
| if (device->driver) |
| IDsDriver_Close(device->driver); |
| |
| if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) |
| waveOutClose(device->hwo); |
| |
| if (device->driver) |
| IDsDriver_Release(device->driver); |
| |
| DSOUND_renderer[device->drvdesc.dnDevNode] = NULL; |
| |
| HeapFree(GetProcessHeap(),0,device->tmp_buffer); |
| HeapFree(GetProcessHeap(),0,device->buffer); |
| RtlDeleteResource(&device->buffer_list_lock); |
| device->mixlock.DebugInfo->Spare[0] = 0; |
| DeleteCriticalSection(&device->mixlock); |
| HeapFree(GetProcessHeap(),0,device); |
| TRACE("(%p) released\n", device); |
| } |
| return ref; |
| } |
| |
| HRESULT DirectSoundDevice_GetCaps( |
| DirectSoundDevice * device, |
| LPDSCAPS lpDSCaps) |
| { |
| TRACE("(%p,%p)\n",device,lpDSCaps); |
| |
| 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; |
| } |
| |
| HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID) |
| { |
| HRESULT hr = DS_OK; |
| unsigned wod, wodn; |
| BOOLEAN found = FALSE; |
| GUID devGUID; |
| DirectSoundDevice * device = *ppDevice; |
| TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID)); |
| |
| if (*ppDevice != NULL) { |
| WARN("already initialized\n"); |
| return DSERR_ALREADYINITIALIZED; |
| } |
| |
| /* Default device? */ |
| if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) |
| lpcGUID = &DSDEVID_DefaultPlayback; |
| |
| if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) { |
| WARN("invalid parameter: lpcGUID\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| /* Enumerate WINMM audio devices and find the one we want */ |
| wodn = waveOutGetNumDevs(); |
| if (!wodn) { |
| WARN("no driver\n"); |
| return DSERR_NODRIVER; |
| } |
| |
| for (wod=0; wod<wodn; wod++) { |
| if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) { |
| found = TRUE; |
| break; |
| } |
| } |
| |
| if (found == FALSE) { |
| WARN("No device found matching given ID!\n"); |
| return DSERR_NODRIVER; |
| } |
| |
| if (DSOUND_renderer[wod]) { |
| if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) { |
| device = DSOUND_renderer[wod]; |
| DirectSoundDevice_AddRef(device); |
| *ppDevice = device; |
| return DS_OK; |
| } else { |
| ERR("device GUID doesn't match\n"); |
| hr = DSERR_GENERIC; |
| return hr; |
| } |
| } else { |
| hr = DirectSoundDevice_Create(&device); |
| if (hr != DS_OK) { |
| WARN("DirectSoundDevice_Create failed\n"); |
| return hr; |
| } |
| } |
| |
| *ppDevice = device; |
| device->guid = devGUID; |
| |
| /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */ |
| waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0); |
| |
| /* Disable the direct sound driver to force emulation if requested. */ |
| if (ds_hw_accel == DS_HW_ACCEL_EMULATION) |
| device->driver = NULL; |
| |
| /* Get driver description */ |
| if (device->driver) { |
| hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc)); |
| if (hr != DS_OK) { |
| WARN("IDsDriver_GetDriverDesc failed\n"); |
| return hr; |
| } |
| } else { |
| /* if no DirectSound interface available, use WINMM API instead */ |
| device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT; |
| } |
| |
| device->drvdesc.dnDevNode = wod; |
| |
| /* If the driver requests being opened through MMSYSTEM |
| * (which is recommended by the DDK), it is supposed to happen |
| * before the DirectSound interface is opened */ |
| if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) |
| { |
| DWORD flags = CALLBACK_FUNCTION; |
| |
| /* disable direct sound if requested */ |
| if (ds_hw_accel != DS_HW_ACCEL_EMULATION) |
| flags |= WAVE_DIRECTSOUND; |
| |
| hr = mmErr(waveOutOpen(&(device->hwo), |
| device->drvdesc.dnDevNode, device->pwfx, |
| (DWORD_PTR)DSOUND_callback, (DWORD)device, |
| flags)); |
| if (hr != DS_OK) { |
| WARN("waveOutOpen failed\n"); |
| return hr; |
| } |
| } |
| |
| if (device->driver) { |
| hr = IDsDriver_Open(device->driver); |
| if (hr != DS_OK) { |
| WARN("IDsDriver_Open failed\n"); |
| return hr; |
| } |
| |
| /* the driver is now open, so it's now allowed to call GetCaps */ |
| hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps)); |
| if (hr != DS_OK) { |
| WARN("IDsDriver_GetCaps failed\n"); |
| return hr; |
| } |
| } else { |
| WAVEOUTCAPSA woc; |
| hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc))); |
| if (hr != DS_OK) { |
| WARN("waveOutGetDevCaps failed\n"); |
| return hr; |
| } |
| ZeroMemory(&device->drvcaps, sizeof(device->drvcaps)); |
| if ((woc.dwFormats & WAVE_FORMAT_1M08) || |
| (woc.dwFormats & WAVE_FORMAT_2M08) || |
| (woc.dwFormats & WAVE_FORMAT_4M08) || |
| (woc.dwFormats & WAVE_FORMAT_48M08) || |
| (woc.dwFormats & WAVE_FORMAT_96M08)) { |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; |
| } |
| if ((woc.dwFormats & WAVE_FORMAT_1M16) || |
| (woc.dwFormats & WAVE_FORMAT_2M16) || |
| (woc.dwFormats & WAVE_FORMAT_4M16) || |
| (woc.dwFormats & WAVE_FORMAT_48M16) || |
| (woc.dwFormats & WAVE_FORMAT_96M16)) { |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; |
| } |
| if ((woc.dwFormats & WAVE_FORMAT_1S08) || |
| (woc.dwFormats & WAVE_FORMAT_2S08) || |
| (woc.dwFormats & WAVE_FORMAT_4S08) || |
| (woc.dwFormats & WAVE_FORMAT_48S08) || |
| (woc.dwFormats & WAVE_FORMAT_96S08)) { |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; |
| } |
| if ((woc.dwFormats & WAVE_FORMAT_1S16) || |
| (woc.dwFormats & WAVE_FORMAT_2S16) || |
| (woc.dwFormats & WAVE_FORMAT_4S16) || |
| (woc.dwFormats & WAVE_FORMAT_48S16) || |
| (woc.dwFormats & WAVE_FORMAT_96S16)) { |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; |
| device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; |
| } |
| if (ds_emuldriver) |
| device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER; |
| device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; |
| device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; |
| device->drvcaps.dwPrimaryBuffers = 1; |
| } |
| |
| hr = DSOUND_PrimaryCreate(device); |
| if (hr == DS_OK) { |
| DSOUND_renderer[device->drvdesc.dnDevNode] = device; |
| timeBeginPeriod(DS_TIME_RES); |
| DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer, |
| (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION); |
| } else { |
| WARN("DSOUND_PrimaryCreate failed\n"); |
| } |
| |
| return hr; |
| } |
| |
| HRESULT DirectSoundDevice_CreateSoundBuffer( |
| DirectSoundDevice * device, |
| LPCDSBUFFERDESC dsbd, |
| LPLPDIRECTSOUNDBUFFER ppdsb, |
| LPUNKNOWN lpunk, |
| BOOL from8) |
| { |
| HRESULT hres = DS_OK; |
| TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk); |
| |
| if (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 (device->primary) { |
| WARN("Primary Buffer already created\n"); |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary)); |
| *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary); |
| } else { |
| device->dsbd = *dsbd; |
| hres = PrimaryBufferImpl_Create(device, (PrimaryBufferImpl**)&(device->primary), &(device->dsbd)); |
| if (device->primary) { |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary)); |
| *ppdsb = (LPDIRECTSOUNDBUFFER)(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(device, (IDirectSoundBufferImpl**)&dsb, dsbd); |
| if (dsb) { |
| hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb); |
| if (*ppdsb) { |
| dsb->secondary = (SecondaryBufferImpl*)*ppdsb; |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb); |
| } else |
| WARN("SecondaryBufferImpl_Create failed\n"); |
| } else |
| WARN("IDirectSoundBufferImpl_Create failed\n"); |
| } |
| |
| return hres; |
| } |
| |
| HRESULT DirectSoundDevice_DuplicateSoundBuffer( |
| DirectSoundDevice * device, |
| LPDIRECTSOUNDBUFFER psb, |
| LPLPDIRECTSOUNDBUFFER ppdsb) |
| { |
| HRESULT hres = DS_OK; |
| IDirectSoundBufferImpl* dsb; |
| TRACE("(%p,%p,%p)\n",device,psb,ppdsb); |
| |
| if (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; |
| } |
| |
| /* make sure we have a secondary buffer */ |
| if ((PrimaryBufferImpl *)psb == device->primary) { |
| WARN("trying to duplicate primary buffer\n"); |
| *ppdsb = NULL; |
| return DSERR_INVALIDCALL; |
| } |
| |
| /* duplicate the actual buffer implementation */ |
| hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, |
| ((SecondaryBufferImpl *)psb)->dsb); |
| |
| if (hres == DS_OK) { |
| /* create a new secondary buffer using the new implementation */ |
| hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb); |
| if (*ppdsb) { |
| dsb->secondary = (SecondaryBufferImpl*)*ppdsb; |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb); |
| } else { |
| WARN("SecondaryBufferImpl_Create failed\n"); |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb); |
| IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb); |
| } |
| } |
| |
| return hres; |
| } |
| |
| HRESULT DirectSoundDevice_SetCooperativeLevel( |
| DirectSoundDevice * device, |
| HWND hwnd, |
| DWORD level) |
| { |
| TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level)); |
| |
| if (device == NULL) { |
| WARN("not initialized\n"); |
| return DSERR_UNINITIALIZED; |
| } |
| |
| if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) { |
| WARN("level=%s not fully supported\n", |
| level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE"); |
| } |
| |
| device->priolevel = level; |
| return DS_OK; |
| } |
| |
| HRESULT DirectSoundDevice_Compact( |
| DirectSoundDevice * device) |
| { |
| TRACE("(%p)\n", device); |
| |
| if (device == NULL) { |
| WARN("not initialized\n"); |
| return DSERR_UNINITIALIZED; |
| } |
| |
| if (device->priolevel != DSSCL_PRIORITY) { |
| WARN("incorrect priority level\n"); |
| return DSERR_PRIOLEVELNEEDED; |
| } |
| |
| return DS_OK; |
| } |
| |
| HRESULT DirectSoundDevice_GetSpeakerConfig( |
| DirectSoundDevice * device, |
| LPDWORD lpdwSpeakerConfig) |
| { |
| TRACE("(%p, %p)\n", device, lpdwSpeakerConfig); |
| |
| if (device == NULL) { |
| WARN("not initialized\n"); |
| return DSERR_UNINITIALIZED; |
| } |
| |
| if (lpdwSpeakerConfig == NULL) { |
| WARN("invalid parameter: lpdwSpeakerConfig == NULL\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| WARN("not fully functional\n"); |
| *lpdwSpeakerConfig = device->speaker_config; |
| return DS_OK; |
| } |
| |
| HRESULT DirectSoundDevice_SetSpeakerConfig( |
| DirectSoundDevice * device, |
| DWORD config) |
| { |
| TRACE("(%p,0x%08lx)\n",device,config); |
| |
| if (device == NULL) { |
| WARN("not initialized\n"); |
| return DSERR_UNINITIALIZED; |
| } |
| |
| device->speaker_config = config; |
| WARN("not fully functional\n"); |
| return DS_OK; |
| } |
| |
| HRESULT DirectSoundDevice_VerifyCertification( |
| DirectSoundDevice * device, |
| LPDWORD pdwCertified) |
| { |
| TRACE("(%p, %p)\n",device,pdwCertified); |
| |
| if (device == NULL) { |
| WARN("not initialized\n"); |
| return DSERR_UNINITIALIZED; |
| } |
| |
| if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED) |
| *pdwCertified = DS_CERTIFIED; |
| else |
| *pdwCertified = DS_UNCERTIFIED; |
| |
| return DS_OK; |
| } |
| |
| /* |
| * Add secondary buffer to buffer list. |
| * Gets exclusive access to buffer for writing. |
| */ |
| HRESULT DirectSoundDevice_AddBuffer( |
| DirectSoundDevice * device, |
| IDirectSoundBufferImpl * pDSB) |
| { |
| IDirectSoundBufferImpl **newbuffers; |
| HRESULT hr = DS_OK; |
| |
| TRACE("(%p, %p)\n", device, pDSB); |
| |
| RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); |
| |
| if (device->buffers) |
| newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1)); |
| else |
| newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1)); |
| |
| if (newbuffers) { |
| device->buffers = newbuffers; |
| device->buffers[device->nrofbuffers] = pDSB; |
| device->nrofbuffers++; |
| TRACE("buffer count is now %d\n", device->nrofbuffers); |
| } else { |
| ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers); |
| hr = DSERR_OUTOFMEMORY; |
| } |
| |
| RtlReleaseResource(&(device->buffer_list_lock)); |
| |
| return hr; |
| } |
| |
| /* |
| * Remove secondary buffer from buffer list. |
| * Gets exclusive access to buffer for writing. |
| */ |
| HRESULT DirectSoundDevice_RemoveBuffer( |
| DirectSoundDevice * device, |
| IDirectSoundBufferImpl * pDSB) |
| { |
| int i; |
| HRESULT hr = DS_OK; |
| |
| TRACE("(%p, %p)\n", device, pDSB); |
| |
| RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); |
| |
| for (i = 0; i < device->nrofbuffers; i++) |
| if (device->buffers[i] == pDSB) |
| break; |
| |
| if (i < device->nrofbuffers) { |
| /* Put the last buffer of the list in the (now empty) position */ |
| device->buffers[i] = device->buffers[device->nrofbuffers - 1]; |
| device->nrofbuffers--; |
| device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers); |
| TRACE("buffer count is now %d\n", device->nrofbuffers); |
| } |
| |
| if (device->nrofbuffers == 0) { |
| HeapFree(GetProcessHeap(),0,device->buffers); |
| device->buffers = NULL; |
| } |
| |
| RtlReleaseResource(&(device->buffer_list_lock)); |
| |
| return hr; |
| } |