reactos/dll/directx/dsound_new/directsound.c

510 lines
13 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Configuration of network devices
* FILE: dll/directx/dsound_new/directsound.c
* PURPOSE: Handles IDirectSound interface
*
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "precomp.h"
typedef struct
{
IDirectSound8Vtbl *lpVtbl;
LONG ref;
GUID DeviceGUID;
BOOL bInitialized;
BOOL bDirectSound8;
DWORD dwLevel;
LPFILTERINFO Filter;
LPDIRECTSOUNDBUFFER8 PrimaryBuffer;
}CDirectSoundImpl, *LPCDirectSoundImpl;
HRESULT
WINAPI
IDirectSound8_fnQueryInterface(
LPDIRECTSOUND8 iface,
REFIID riid,
LPVOID * ppobj)
{
LPOLESTR pStr;
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if ((IsEqualIID(riid, &IID_IDirectSound) && This->bDirectSound8 == FALSE) ||
(IsEqualIID(riid, &IID_IDirectSound8) && This->bDirectSound8 != FALSE) ||
(IsEqualIID(riid, &IID_IUnknown)))
{
*ppobj = (LPVOID)&This->lpVtbl;
InterlockedIncrement(&This->ref);
return S_OK;
}
if (SUCCEEDED(StringFromIID(riid, &pStr)))
{
DPRINT("No Interface for class %s\n", pStr);
CoTaskMemFree(pStr);
}
return E_NOINTERFACE;
}
ULONG
WINAPI
IDirectSound8_fnAddRef(
LPDIRECTSOUND8 iface)
{
ULONG ref;
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
ref = InterlockedIncrement(&This->ref);
return ref;
}
ULONG
WINAPI
IDirectSound8_fnRelease(
LPDIRECTSOUND8 iface)
{
ULONG ref;
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
ref = InterlockedDecrement(&(This->ref));
if (!ref)
{
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
HRESULT
WINAPI
IDirectSound8_fnCreateSoundBuffer(
LPDIRECTSOUND8 iface,
LPCDSBUFFERDESC lpcDSBufferDesc,
LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer,
IUnknown FAR* pUnkOuter)
{
HRESULT hResult;
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
if (!lpcDSBufferDesc || !lplpDirectSoundBuffer || pUnkOuter != NULL)
{
DPRINT("Invalid parameter %p %p %p\n", lpcDSBufferDesc, lplpDirectSoundBuffer, pUnkOuter);
return DSERR_INVALIDPARAM;
}
/* check buffer description */
if ((lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC) && lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC1)) || lpcDSBufferDesc->dwReserved != 0)
{
DPRINT("Invalid buffer description size %u expected %u dwReserved %u\n", lpcDSBufferDesc->dwSize, sizeof(DSBUFFERDESC1), lpcDSBufferDesc->dwReserved);
return DSERR_INVALIDPARAM;
}
DPRINT("This %p dwFlags %x dwBufferBytes %u lpwfxFormat %p dwSize %u\n", This, lpcDSBufferDesc->dwFlags, lpcDSBufferDesc->dwBufferBytes, lpcDSBufferDesc->lpwfxFormat, lpcDSBufferDesc->dwSize);
if (lpcDSBufferDesc->dwFlags & DSBCAPS_PRIMARYBUFFER)
{
if (lpcDSBufferDesc->lpwfxFormat != NULL)
{
/* format must be null for primary sound buffer */
return DSERR_INVALIDPARAM;
}
if (lpcDSBufferDesc->dwBufferBytes != 0)
{
/* buffer size must be zero for primary sound buffer */
return DSERR_INVALIDPARAM;
}
if (This->PrimaryBuffer)
{
/* primary buffer already exists */
IDirectSoundBuffer8_AddRef(This->PrimaryBuffer);
*lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)This->PrimaryBuffer;
return S_OK;
}
hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags);
if (SUCCEEDED(hResult))
{
/* store primary buffer */
This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
}
return hResult;
}
else
{
if (lpcDSBufferDesc->lpwfxFormat == NULL)
{
/* format must not be null */
return DSERR_INVALIDPARAM;
}
if (lpcDSBufferDesc->dwBufferBytes < DSBSIZE_MIN || lpcDSBufferDesc->dwBufferBytes > DSBSIZE_MAX)
{
/* buffer size must be within bounds for secondary sound buffer*/
return DSERR_INVALIDPARAM;
}
if (!This->PrimaryBuffer)
{
hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags);
if (SUCCEEDED(hResult))
{
/* store primary buffer */
This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
}
else
{
DPRINT("Failed to create primary buffer with %x\n", hResult);
return hResult;
}
}
ASSERT(This->PrimaryBuffer);
DPRINT("This %p wFormatTag %x nChannels %u nSamplesPerSec %u nAvgBytesPerSec %u NBlockAlign %u wBitsPerSample %u cbSize %u\n",
This, lpcDSBufferDesc->lpwfxFormat->wFormatTag, lpcDSBufferDesc->lpwfxFormat->nChannels, lpcDSBufferDesc->lpwfxFormat->nSamplesPerSec, lpcDSBufferDesc->lpwfxFormat->nAvgBytesPerSec, lpcDSBufferDesc->lpwfxFormat->nBlockAlign, lpcDSBufferDesc->lpwfxFormat->wBitsPerSample, lpcDSBufferDesc->lpwfxFormat->cbSize);
hResult = NewSecondarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc, This->PrimaryBuffer);
return hResult;
}
}
HRESULT
WINAPI
IDirectSound8_fnGetCaps(
LPDIRECTSOUND8 iface,
LPDSCAPS lpDSCaps)
{
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
if (!lpDSCaps)
{
/* object not yet initialized */
return DSERR_INVALIDPARAM;
}
if (lpDSCaps->dwSize != sizeof(DSCAPS))
{
/* object not yet initialized */
return DSERR_INVALIDPARAM;
}
UNIMPLEMENTED;
return DSERR_GENERIC;
}
HRESULT
WINAPI
IDirectSound8_fnDuplicateSoundBuffer(
LPDIRECTSOUND8 iface,
LPDIRECTSOUNDBUFFER lpDsbOriginal,
LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate)
{
UNIMPLEMENTED;
return DSERR_OUTOFMEMORY;
}
HRESULT
WINAPI
IDirectSound8_fnSetCooperativeLevel(
LPDIRECTSOUND8 iface,
HWND hwnd,
DWORD dwLevel)
{
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
/* store cooperation level */
This->dwLevel = dwLevel;
return DS_OK;
}
HRESULT
WINAPI
IDirectSound8_fnCompact(
LPDIRECTSOUND8 iface)
{
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
if (This->dwLevel != DSSCL_PRIORITY)
{
/* needs priority level */
return DSERR_PRIOLEVELNEEDED;
}
/* done */
return DS_OK;
}
HRESULT
WINAPI
IDirectSound8_fnGetSpeakerConfig(
LPDIRECTSOUND8 iface,
LPDWORD pdwSpeakerConfig)
{
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
UNIMPLEMENTED;
return DSERR_INVALIDPARAM;
}
HRESULT
WINAPI
IDirectSound8_fnSetSpeakerConfig(
LPDIRECTSOUND8 iface,
DWORD dwSpeakerConfig)
{
UNIMPLEMENTED;
return DSERR_INVALIDPARAM;
}
HRESULT
WINAPI
IDirectSound8_fnInitialize(
LPDIRECTSOUND8 iface,
LPCGUID pcGuidDevice)
{
GUID DeviceGuid;
LPOLESTR pGuidStr;
HRESULT hr;
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!RootInfo)
{
EnumAudioDeviceInterfaces(&RootInfo);
}
/* sanity check */
ASSERT(RootInfo);
if (This->bInitialized)
{
/* object has already been initialized */
return DSERR_ALREADYINITIALIZED;
}
/* fixme mutual exclusion */
if (pcGuidDevice == NULL || IsEqualGUID(pcGuidDevice, &GUID_NULL))
{
/* use default playback device id */
pcGuidDevice = &DSDEVID_DefaultPlayback;
}
if (IsEqualIID(pcGuidDevice, &DSDEVID_DefaultCapture) || IsEqualIID(pcGuidDevice, &DSDEVID_DefaultVoiceCapture))
{
/* this has to be a winetest */
return DSERR_NODRIVER;
}
/* now verify the guid */
if (GetDeviceID(pcGuidDevice, &DeviceGuid) != DS_OK)
{
if (SUCCEEDED(StringFromIID(pcGuidDevice, &pGuidStr)))
{
DPRINT("IDirectSound8_fnInitialize: Unknown GUID %ws\n", pGuidStr);
CoTaskMemFree(pGuidStr);
}
return DSERR_INVALIDPARAM;
}
hr = FindDeviceByGuid(&DeviceGuid, &This->Filter);
if (SUCCEEDED(hr))
{
This->bInitialized = TRUE;
return DS_OK;
}
DPRINT("Failed to find device\n");
return DSERR_INVALIDPARAM;
}
HRESULT
WINAPI
IDirectSound8_fnVerifyCertification(
LPDIRECTSOUND8 iface,
LPDWORD pdwCertified)
{
LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
if (!This->bInitialized)
{
/* object not yet initialized */
return DSERR_UNINITIALIZED;
}
UNIMPLEMENTED;
return DS_CERTIFIED;
}
static IDirectSound8Vtbl vt_DirectSound8 =
{
/* IUnknown methods */
IDirectSound8_fnQueryInterface,
IDirectSound8_fnAddRef,
IDirectSound8_fnRelease,
/* IDirectSound methods */
IDirectSound8_fnCreateSoundBuffer,
IDirectSound8_fnGetCaps,
IDirectSound8_fnDuplicateSoundBuffer,
IDirectSound8_fnSetCooperativeLevel,
IDirectSound8_fnCompact,
IDirectSound8_fnGetSpeakerConfig,
IDirectSound8_fnSetSpeakerConfig,
IDirectSound8_fnInitialize,
/* IDirectSound8 methods */
IDirectSound8_fnVerifyCertification
};
HRESULT
InternalDirectSoundCreate(
LPCGUID lpcGUID,
LPDIRECTSOUND8 *ppDS,
IUnknown *pUnkOuter,
BOOL bDirectSound8)
{
LPCDirectSoundImpl This;
HRESULT hr;
if (!ppDS || pUnkOuter != NULL)
{
/* invalid parameter passed */
return DSERR_INVALIDPARAM;
}
/* allocate CDirectSoundImpl struct */
This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
if (!This)
{
/* not enough memory */
return DSERR_OUTOFMEMORY;
}
/* initialize IDirectSound object */
This->ref = 1;
This->bDirectSound8 = bDirectSound8;
This->lpVtbl = &vt_DirectSound8;
/* initialize direct sound interface */
hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID);
/* check for success */
if (!SUCCEEDED(hr))
{
/* failed */
DPRINT("Failed to initialize DirectSound object with %x\n", hr);
IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl);
return hr;
}
/* store result */
*ppDS = (LPDIRECTSOUND8)&This->lpVtbl;
DPRINT("DirectSound object %p\n", *ppDS);
return DS_OK;
}
HRESULT
CALLBACK
NewDirectSound(
IUnknown* pUnkOuter,
REFIID riid,
LPVOID* ppvObject)
{
LPOLESTR pStr;
LPCDirectSoundImpl This;
/* check param */
if (!ppvObject)
{
/* invalid param */
return E_INVALIDARG;
}
/* check requested interface */
if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IDirectSound) && !IsEqualIID(riid, &IID_IDirectSound8))
{
*ppvObject = 0;
StringFromIID(riid, &pStr);
DPRINT("KsPropertySet does not support Interface %ws\n", pStr);
CoTaskMemFree(pStr);
return E_NOINTERFACE;
}
/* allocate CDirectSoundCaptureImpl struct */
This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
if (!This)
{
/* not enough memory */
return DSERR_OUTOFMEMORY;
}
/* initialize object */
This->ref = 1;
This->lpVtbl = &vt_DirectSound8;
This->bInitialized = FALSE;
*ppvObject = (LPVOID)&This->lpVtbl;
return S_OK;
}
HRESULT
WINAPI
DirectSoundCreate(
LPCGUID lpcGUID,
LPDIRECTSOUND *ppDS,
IUnknown *pUnkOuter)
{
return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter, FALSE);
}
HRESULT
WINAPI
DirectSoundCreate8(
LPCGUID lpcGUID,
LPDIRECTSOUND8 *ppDS,
IUnknown *pUnkOuter)
{
return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter, TRUE);
}