Commit dfaef530 authored by Francois Gouget's avatar Francois Gouget Committed by Alexandre Julliard

dsound: Reorder the interfaces to remove the need for forward declarations.

parent 82c298ee
...@@ -119,1075 +119,1076 @@ static void _dump_DSBCAPS(DWORD xmask) { ...@@ -119,1075 +119,1076 @@ static void _dump_DSBCAPS(DWORD xmask) {
TRACE("%s ",flags[i].name); TRACE("%s ",flags[i].name);
} }
static void directsound_destroy(IDirectSoundImpl *This)
{
if (This->device)
DirectSoundDevice_Release(This->device);
HeapFree(GetProcessHeap(),0,This);
TRACE("(%p) released\n", This);
}
/******************************************************************************* /*******************************************************************************
* IUnknown Implementation for DirectSound * DirectSoundDevice
*/ */
static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface) static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
{ {
return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner); DirectSoundDevice * device;
} TRACE("(%p)\n", ppDevice);
static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) /* Allocate memory */
{ device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
IDirectSoundImpl *This = impl_from_IUnknown(iface); if (device == NULL) {
WARN("out of memory\n");
return DSERR_OUTOFMEMORY;
}
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv); device->ref = 1;
device->priolevel = DSSCL_NORMAL;
device->state = STATE_STOPPED;
device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
if (!ppv) { DSOUND_ParseSpeakerConfig(device);
WARN("invalid parameter\n");
return E_INVALIDARG;
}
*ppv = NULL;
if (IsEqualIID(riid, &IID_IUnknown)) /* 3D listener initial parameters */
*ppv = &This->IUnknown_inner; device->ds3dl.dwSize = sizeof(DS3DLISTENER);
else if (IsEqualIID(riid, &IID_IDirectSound) || device->ds3dl.vPosition.x = 0.0;
(IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8)) device->ds3dl.vPosition.y = 0.0;
*ppv = &This->IDirectSound8_iface; device->ds3dl.vPosition.z = 0.0;
else { device->ds3dl.vVelocity.x = 0.0;
WARN("unknown IID %s\n", debugstr_guid(riid)); device->ds3dl.vVelocity.y = 0.0;
return E_NOINTERFACE; 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(WAVEFORMATEXTENSIBLE));
device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE));
if (!device->pwfx || !device->primary_pwfx) {
WARN("out of memory\n");
HeapFree(GetProcessHeap(),0,device->primary_pwfx);
HeapFree(GetProcessHeap(),0,device->pwfx);
HeapFree(GetProcessHeap(),0,device);
return DSERR_OUTOFMEMORY;
} }
IUnknown_AddRef((IUnknown*)*ppv); device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
return S_OK; 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;
memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface) InitializeCriticalSection(&(device->mixlock));
{ device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
IDirectSoundImpl *This = impl_from_IUnknown(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref); RtlInitializeResource(&(device->buffer_list_lock));
if(ref == 1) *ppDevice = device;
InterlockedIncrement(&This->numIfaces);
return ref; return DS_OK;
} }
static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface) static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
{ {
IDirectSoundImpl *This = impl_from_IUnknown(iface); ULONG ref = InterlockedIncrement(&(device->ref));
ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref was %d\n", device, ref - 1);
TRACE("(%p) ref=%d\n", This, ref);
if (!ref && !InterlockedDecrement(&This->numIfaces))
directsound_destroy(This);
return ref; return ref;
} }
static const IUnknownVtbl unk_vtbl = ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
{ {
IUnknownImpl_QueryInterface, HRESULT hr;
IUnknownImpl_AddRef, ULONG ref = InterlockedDecrement(&(device->ref));
IUnknownImpl_Release TRACE("(%p) ref was %u\n", device, ref + 1);
}; if (!ref) {
int i;
/******************************************************************************* SetEvent(device->sleepev);
* IDirectSound and IDirectSound8 Implementation if (device->thread) {
*/ WaitForSingleObject(device->thread, INFINITE);
static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface) CloseHandle(device->thread);
{ }
return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface); CloseHandle(device->sleepev);
}
static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid, EnterCriticalSection(&DSOUND_renderers_lock);
void **ppv) list_remove(&device->entry);
{ LeaveCriticalSection(&DSOUND_renderers_lock);
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
}
static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface) /* It is allowed to release this object even when buffers are playing */
{ if (device->buffers) {
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); WARN("%d secondary buffers not released\n", device->nrofbuffers);
ULONG ref = InterlockedIncrement(&This->refds); for( i=0;i<device->nrofbuffers;i++)
secondarybuffer_destroy(device->buffers[i]);
}
TRACE("(%p) refds=%d\n", This, ref); hr = DSOUND_PrimaryDestroy(device);
if (hr != DS_OK)
WARN("DSOUND_PrimaryDestroy failed\n");
if(ref == 1) if(device->client)
InterlockedIncrement(&This->numIfaces); IAudioClient_Release(device->client);
if(device->render)
IAudioRenderClient_Release(device->render);
if(device->clock)
IAudioClock_Release(device->clock);
if(device->volume)
IAudioStreamVolume_Release(device->volume);
HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
HeapFree(GetProcessHeap(), 0, device->mix_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; return ref;
} }
static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface) BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
DWORD depth, WORD channels)
{ {
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); WAVEFORMATEX fmt, *junk;
ULONG ref = InterlockedDecrement(&(This->refds)); HRESULT hr;
TRACE("(%p) refds=%d\n", This, ref);
if (!ref && !InterlockedDecrement(&This->numIfaces)) fmt.wFormatTag = WAVE_FORMAT_PCM;
directsound_destroy(This); fmt.nChannels = channels;
fmt.nSamplesPerSec = rate;
fmt.wBitsPerSample = depth;
fmt.nBlockAlign = (channels * depth) / 8;
fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
fmt.cbSize = 0;
return ref; hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
} if(SUCCEEDED(hr))
CoTaskMemFree(junk);
static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface, return hr == S_OK;
const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
} }
static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps) HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
{ {
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); HRESULT hr = DS_OK;
GUID devGUID;
DirectSoundDevice *device;
IMMDevice *mmdevice;
TRACE("(%p, %p)\n", This, dscaps); TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
if (!This->device) { if (*ppDevice != NULL) {
WARN("not initialized\n"); WARN("already initialized\n");
return DSERR_UNINITIALIZED; return DSERR_ALREADYINITIALIZED;
}
if (!dscaps) {
WARN("invalid parameter: dscaps = NULL\n");
return DSERR_INVALIDPARAM;
}
if (dscaps->dwSize < sizeof(*dscaps)) {
WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
return DSERR_INVALIDPARAM;
} }
dscaps->dwFlags = This->device->drvcaps.dwFlags; /* Default device? */
dscaps->dwMinSecondarySampleRate = This->device->drvcaps.dwMinSecondarySampleRate; if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
dscaps->dwMaxSecondarySampleRate = This->device->drvcaps.dwMaxSecondarySampleRate; lpcGUID = &DSDEVID_DefaultPlayback;
dscaps->dwPrimaryBuffers = This->device->drvcaps.dwPrimaryBuffers;
dscaps->dwMaxHwMixingAllBuffers = This->device->drvcaps.dwMaxHwMixingAllBuffers;
dscaps->dwMaxHwMixingStaticBuffers = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
dscaps->dwMaxHwMixingStreamingBuffers = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
dscaps->dwFreeHwMixingAllBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
if (This->device->drvcaps.dwFreeHwMixingAllBuffers > 0) { if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
dscaps->dwFreeHwMixingStaticBuffers = This->device->drvcaps.dwFreeHwMixingStaticBuffers; IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers; return DSERR_NODRIVER;
} else {
dscaps->dwFreeHwMixingStaticBuffers = 0; if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
dscaps->dwFreeHwMixingStreamingBuffers = 0; WARN("invalid parameter: lpcGUID\n");
return DSERR_INVALIDPARAM;
} }
dscaps->dwMaxHw3DAllBuffers = This->device->drvcaps.dwMaxHw3DAllBuffers; hr = get_mmdevice(eRender, &devGUID, &mmdevice);
dscaps->dwMaxHw3DStaticBuffers = This->device->drvcaps.dwMaxHw3DStaticBuffers; if(FAILED(hr))
dscaps->dwMaxHw3DStreamingBuffers = This->device->drvcaps.dwMaxHw3DStreamingBuffers; return hr;
dscaps->dwFreeHw3DAllBuffers = This->device->drvcaps.dwFreeHw3DAllBuffers;
dscaps->dwFreeHw3DStaticBuffers = This->device->drvcaps.dwFreeHw3DStaticBuffers;
dscaps->dwFreeHw3DStreamingBuffers = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
dscaps->dwTotalHwMemBytes = This->device->drvcaps.dwTotalHwMemBytes;
dscaps->dwFreeHwMemBytes = This->device->drvcaps.dwFreeHwMemBytes;
dscaps->dwMaxContigFreeHwMemBytes = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
dscaps->dwUnlockTransferRateHwBuffers = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
dscaps->dwPlayCpuOverheadSwBuffers = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
if (TRACE_ON(dsound)) {
TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
_dump_DSCAPS(dscaps->dwFlags);
TRACE(")\n");
}
return DS_OK;
}
static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
}
static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
DWORD level)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
DirectSoundDevice *device = This->device;
DWORD oldlevel;
HRESULT hr = S_OK;
TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
if (!device) { EnterCriticalSection(&DSOUND_renderers_lock);
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) { LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
WARN("level=%s not fully supported\n", if(IsEqualGUID(&device->guid, &devGUID)){
level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE"); IMMDevice_Release(mmdevice);
DirectSoundDevice_AddRef(device);
*ppDevice = device;
LeaveCriticalSection(&DSOUND_renderers_lock);
return DS_OK;
}
} }
RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE); hr = DirectSoundDevice_Create(&device);
EnterCriticalSection(&device->mixlock); if(FAILED(hr)){
oldlevel = device->priolevel; WARN("DirectSoundDevice_Create failed\n");
device->priolevel = level; IMMDevice_Release(mmdevice);
if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) { LeaveCriticalSection(&DSOUND_renderers_lock);
hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY); return hr;
if (FAILED(hr))
device->priolevel = oldlevel;
else
DSOUND_PrimaryOpen(device);
} }
LeaveCriticalSection(&device->mixlock);
RtlReleaseResource(&device->buffer_list_lock);
return hr;
}
static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p)\n", This); device->mmdevice = mmdevice;
device->guid = devGUID;
device->sleepev = CreateEventW(0, 0, 0, 0);
if (!This->device) { hr = DSOUND_ReopenDevice(device, FALSE);
WARN("not initialized\n"); if (FAILED(hr))
return DSERR_UNINITIALIZED; {
HeapFree(GetProcessHeap(), 0, device);
LeaveCriticalSection(&DSOUND_renderers_lock);
IMMDevice_Release(mmdevice);
WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
return hr;
} }
if (This->device->priolevel < DSSCL_PRIORITY) { ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
WARN("incorrect priority level\n");
return DSERR_PRIOLEVELNEEDED;
}
return DS_OK;
}
static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config) if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
{ DSOUND_check_supported(device->client, 22050, 8, 1) ||
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); DSOUND_check_supported(device->client, 44100, 8, 1) ||
DSOUND_check_supported(device->client, 48000, 8, 1) ||
DSOUND_check_supported(device->client, 96000, 8, 1))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
TRACE("(%p, %p)\n", This, config); if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
DSOUND_check_supported(device->client, 22050, 16, 1) ||
DSOUND_check_supported(device->client, 44100, 16, 1) ||
DSOUND_check_supported(device->client, 48000, 16, 1) ||
DSOUND_check_supported(device->client, 96000, 16, 1))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
if (!This->device) { if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
WARN("not initialized\n"); DSOUND_check_supported(device->client, 22050, 8, 2) ||
return DSERR_UNINITIALIZED; DSOUND_check_supported(device->client, 44100, 8, 2) ||
} DSOUND_check_supported(device->client, 48000, 8, 2) ||
if (!config) { DSOUND_check_supported(device->client, 96000, 8, 2))
WARN("invalid parameter: config == NULL\n"); device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
return DSERR_INVALIDPARAM;
}
WARN("not fully functional\n"); if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
*config = This->device->speaker_config; DSOUND_check_supported(device->client, 22050, 16, 2) ||
return DS_OK; DSOUND_check_supported(device->client, 44100, 16, 2) ||
} DSOUND_check_supported(device->client, 48000, 16, 2) ||
DSOUND_check_supported(device->client, 96000, 16, 2))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config) /* the dsound mixer supports all of the following */
{ device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
TRACE("(%p,0x%08x)\n", This, config); device->drvcaps.dwPrimaryBuffers = 1;
device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
device->drvcaps.dwMaxHwMixingAllBuffers = 16;
device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
device->drvcaps.dwFreeHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
device->drvcaps.dwFreeHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
device->drvcaps.dwFreeHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
if (!This->device) { ZeroMemory(&device->volpan, sizeof(device->volpan));
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
/* NOP on Vista and above */ hr = DSOUND_PrimaryCreate(device);
if (hr == DS_OK) {
device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
} else
WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
return DS_OK; *ppDevice = device;
} list_add_tail(&DSOUND_renderers, &device->entry);
static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid) LeaveCriticalSection(&DSOUND_renderers_lock);
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); return hr;
TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
return DirectSoundDevice_Initialize(&This->device, lpcGuid);
} }
static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified) HRESULT DirectSoundDevice_CreateSoundBuffer(
DirectSoundDevice * device,
LPCDSBUFFERDESC dsbd,
LPLPDIRECTSOUNDBUFFER ppdsb,
LPUNKNOWN lpunk,
BOOL from8)
{ {
IDirectSoundImpl *This = impl_from_IDirectSound8(iface); HRESULT hres = DS_OK;
TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
TRACE("(%p, %p)\n", This, certified);
if (!This->device) { if (device == NULL) {
WARN("not initialized\n"); WARN("not initialized\n");
return DSERR_UNINITIALIZED; return DSERR_UNINITIALIZED;
} }
if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED) if (dsbd == NULL) {
*certified = DS_CERTIFIED; WARN("invalid parameter: dsbd == NULL\n");
else return DSERR_INVALIDPARAM;
*certified = DS_UNCERTIFIED; }
return DS_OK;
}
static const IDirectSound8Vtbl ds8_vtbl = if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
{ dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
IDirectSound8Impl_QueryInterface, WARN("invalid parameter: dsbd\n");
IDirectSound8Impl_AddRef, return DSERR_INVALIDPARAM;
IDirectSound8Impl_Release, }
IDirectSound8Impl_CreateSoundBuffer,
IDirectSound8Impl_GetCaps,
IDirectSound8Impl_DuplicateSoundBuffer,
IDirectSound8Impl_SetCooperativeLevel,
IDirectSound8Impl_Compact,
IDirectSound8Impl_GetSpeakerConfig,
IDirectSound8Impl_SetSpeakerConfig,
IDirectSound8Impl_Initialize,
IDirectSound8Impl_VerifyCertification
};
HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8) if (ppdsb == NULL) {
{ WARN("invalid parameter: ppdsb == NULL\n");
IDirectSoundImpl *obj; return DSERR_INVALIDPARAM;
HRESULT hr; }
*ppdsb = NULL;
TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); if (TRACE_ON(dsound)) {
TRACE("(structsize=%d)\n",dsbd->dwSize);
TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
_dump_DSBCAPS(dsbd->dwFlags);
TRACE(")\n");
TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
}
*ppv = NULL; if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) &&
obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj)); dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
if (!obj) { device->drvcaps.dwFreeHwMixingAllBuffers == 0)
WARN("out of memory\n"); {
return DSERR_OUTOFMEMORY; WARN("ran out of emulated hardware buffers\n");
return DSERR_ALLOCATED;
} }
setup_dsound_options(); if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
if (dsbd->lpwfxFormat != NULL) {
WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
"primary buffer\n");
return DSERR_INVALIDPARAM;
}
obj->IUnknown_inner.lpVtbl = &unk_vtbl; if (device->primary) {
obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl; WARN("Primary Buffer already created\n");
obj->ref = 1; IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
obj->refds = 0; *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
obj->numIfaces = 1; } else {
obj->device = NULL; hres = primarybuffer_create(device, &device->primary, dsbd);
obj->has_ds8 = has_ds8; if (device->primary) {
*ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
} else
WARN("primarybuffer_create() failed\n");
}
} else {
IDirectSoundBufferImpl * dsb;
WAVEFORMATEXTENSIBLE *pwfxe;
/* COM aggregation supported only internally */ if (dsbd->lpwfxFormat == NULL) {
if (outer_unk) WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
obj->outer_unk = outer_unk; "secondary buffer\n");
else return DSERR_INVALIDPARAM;
obj->outer_unk = &obj->IUnknown_inner; }
pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv); if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
IUnknown_Release(&obj->IUnknown_inner); {
/* check if cbSize is at least 22 bytes */
if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
{
WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
return DSERR_INVALIDPARAM;
}
return hr; /* cbSize should be 22 bytes, with one possible exception */
} if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
!((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
{
WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
return DSERR_CONTROLUNAVAIL;
}
HRESULT DSOUND_Create(REFIID riid, void **ppv) if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
{ {
return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE); if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
} FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
return DSERR_INVALIDPARAM;
}
if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
{
WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
return DSERR_INVALIDPARAM;
}
if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
{
FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
return DSERR_CONTROLUNAVAIL;
}
}
HRESULT DSOUND_Create8(REFIID riid, void **ppv) TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
{ "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE); 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, &dsb, dsbd);
if (dsb) {
*ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
device->drvcaps.dwFreeHwMixingAllBuffers--;
} else
WARN("IDirectSoundBufferImpl_Create failed\n");
}
return hres;
} }
/******************************************************************************* HRESULT DirectSoundDevice_DuplicateSoundBuffer(
* DirectSoundCreate (DSOUND.1) DirectSoundDevice * device,
* LPDIRECTSOUNDBUFFER psb,
* Creates and initializes a DirectSound interface. LPLPDIRECTSOUNDBUFFER ppdsb)
*
* 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; HRESULT hres = DS_OK;
LPDIRECTSOUND pDS; IDirectSoundBufferImpl* dsb;
TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); if (device == NULL) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (ppDS == NULL) { if (psb == NULL) {
WARN("invalid parameter: ppDS == NULL\n"); WARN("invalid parameter: psb == NULL\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
if (pUnkOuter != NULL) { if (ppdsb == NULL) {
WARN("invalid parameter: pUnkOuter != NULL\n"); WARN("invalid parameter: ppdsb == NULL\n");
*ppDS = 0;
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS); /* make sure we have a secondary buffer */
if (hr == DS_OK) { if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
hr = IDirectSound_Initialize(pDS, lpcGUID); WARN("trying to duplicate primary buffer\n");
if (hr != DS_OK) { *ppdsb = NULL;
if (hr != DSERR_ALREADYINITIALIZED) { return DSERR_INVALIDCALL;
IDirectSound_Release(pDS);
pDS = 0;
} else
hr = DS_OK;
}
} }
*ppDS = pDS; /* duplicate the actual buffer implementation */
hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
if (hres == DS_OK)
*ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
else
WARN("IDirectSoundBufferImpl_Duplicate failed\n");
return hr; return hres;
} }
/******************************************************************************* /*
* DirectSoundCreate8 (DSOUND.11) * Add secondary buffer to buffer list.
* * Gets exclusive access to buffer for writing.
* 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( HRESULT DirectSoundDevice_AddBuffer(
LPCGUID lpcGUID, DirectSoundDevice * device,
LPDIRECTSOUND8 *ppDS, IDirectSoundBufferImpl * pDSB)
IUnknown *pUnkOuter)
{ {
HRESULT hr; IDirectSoundBufferImpl **newbuffers;
LPDIRECTSOUND8 pDS; HRESULT hr = DS_OK;
TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); TRACE("(%p, %p)\n", device, pDSB);
if (ppDS == NULL) { RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
WARN("invalid parameter: ppDS == NULL\n");
return DSERR_INVALIDPARAM;
}
if (pUnkOuter != NULL) { if (device->buffers)
WARN("invalid parameter: pUnkOuter != NULL\n"); newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
*ppDS = 0; else
return DSERR_INVALIDPARAM; newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
}
hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS); if (newbuffers) {
if (hr == DS_OK) { device->buffers = newbuffers;
hr = IDirectSound8_Initialize(pDS, lpcGUID); device->buffers[device->nrofbuffers] = pDSB;
if (hr != DS_OK) { device->nrofbuffers++;
if (hr != DSERR_ALREADYINITIALIZED) { TRACE("buffer count is now %d\n", device->nrofbuffers);
IDirectSound8_Release(pDS); } else {
pDS = 0; ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
} else hr = DSERR_OUTOFMEMORY;
hr = DS_OK;
}
} }
*ppDS = pDS; RtlReleaseResource(&(device->buffer_list_lock));
return hr; return hr;
} }
void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) /*
* Remove secondary buffer from buffer list.
* Gets exclusive access to buffer for writing.
*/
void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
{ {
switch (DSSPEAKER_CONFIG(device->speaker_config)) { int i;
case DSSPEAKER_MONO:
device->speaker_angles[0] = M_PI/180.0f * 0.0f;
device->speaker_num[0] = 0;
device->num_speakers = 1;
device->lfe_channel = -1;
break;
case DSSPEAKER_STEREO: TRACE("(%p, %p)\n", device, pDSB);
case DSSPEAKER_HEADPHONE:
device->speaker_angles[0] = M_PI/180.0f * -90.0f;
device->speaker_angles[1] = M_PI/180.0f * 90.0f;
device->speaker_num[0] = 0; /* Left */
device->speaker_num[1] = 1; /* Right */
device->num_speakers = 2;
device->lfe_channel = -1;
break;
case DSSPEAKER_QUAD:
device->speaker_angles[0] = M_PI/180.0f * -135.0f;
device->speaker_angles[1] = M_PI/180.0f * -45.0f;
device->speaker_angles[2] = M_PI/180.0f * 45.0f;
device->speaker_angles[3] = M_PI/180.0f * 135.0f;
device->speaker_num[0] = 2; /* Rear left */
device->speaker_num[1] = 0; /* Front left */
device->speaker_num[2] = 1; /* Front right */
device->speaker_num[3] = 3; /* Rear right */
device->num_speakers = 4;
device->lfe_channel = -1;
break;
case DSSPEAKER_5POINT1_BACK:
device->speaker_angles[0] = M_PI/180.0f * -135.0f;
device->speaker_angles[1] = M_PI/180.0f * -45.0f;
device->speaker_angles[2] = M_PI/180.0f * 0.0f;
device->speaker_angles[3] = M_PI/180.0f * 45.0f;
device->speaker_angles[4] = M_PI/180.0f * 135.0f;
device->speaker_angles[5] = 9999.0f;
device->speaker_num[0] = 4; /* Rear left */
device->speaker_num[1] = 0; /* Front left */
device->speaker_num[2] = 2; /* Front centre */
device->speaker_num[3] = 1; /* Front right */
device->speaker_num[4] = 5; /* Rear right */
device->speaker_num[5] = 3; /* LFE */
device->num_speakers = 6;
device->lfe_channel = 3;
break;
case DSSPEAKER_5POINT1_SURROUND: RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
device->speaker_angles[0] = M_PI/180.0f * -90.0f;
device->speaker_angles[1] = M_PI/180.0f * -30.0f;
device->speaker_angles[2] = M_PI/180.0f * 0.0f;
device->speaker_angles[3] = M_PI/180.0f * 30.0f;
device->speaker_angles[4] = M_PI/180.0f * 90.0f;
device->speaker_angles[5] = 9999.0f;
device->speaker_num[0] = 4; /* Rear left */
device->speaker_num[1] = 0; /* Front left */
device->speaker_num[2] = 2; /* Front centre */
device->speaker_num[3] = 1; /* Front right */
device->speaker_num[4] = 5; /* Rear right */
device->speaker_num[5] = 3; /* LFE */
device->num_speakers = 6;
device->lfe_channel = 3;
break;
default: if (device->nrofbuffers == 1) {
WARN("unknown speaker_config %u\n", device->speaker_config); assert(device->buffers[0] == pDSB);
HeapFree(GetProcessHeap(), 0, device->buffers);
device->buffers = NULL;
} else {
for (i = 0; i < device->nrofbuffers; i++) {
if (device->buffers[i] == pDSB) {
/* Put the last buffer of the list in the (now empty) position */
device->buffers[i] = device->buffers[device->nrofbuffers - 1];
break;
}
}
} }
device->nrofbuffers--;
TRACE("buffer count is now %d\n", device->nrofbuffers);
RtlReleaseResource(&(device->buffer_list_lock));
} }
/******************************************************************************* /*******************************************************************************
* DirectSoundDevice * IUnknown Implementation for DirectSound
*/ */
static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
{
DirectSoundDevice * device;
TRACE("(%p)\n", ppDevice);
/* Allocate memory */ static void directsound_destroy(IDirectSoundImpl *This)
device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice)); {
if (device == NULL) { if (This->device)
WARN("out of memory\n"); DirectSoundDevice_Release(This->device);
return DSERR_OUTOFMEMORY; HeapFree(GetProcessHeap(),0,This);
} TRACE("(%p) released\n", This);
}
device->ref = 1; static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
device->priolevel = DSSCL_NORMAL; {
device->state = STATE_STOPPED; return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); }
DSOUND_ParseSpeakerConfig(device); static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
IDirectSoundImpl *This = impl_from_IUnknown(iface);
/* 3D listener initial parameters */ TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
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; if (!ppv) {
device->guid = GUID_NULL; WARN("invalid parameter\n");
return E_INVALIDARG;
}
*ppv = NULL;
/* Set default wave format (may need it for waveOutOpen) */ if (IsEqualIID(riid, &IID_IUnknown))
device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE)); *ppv = &This->IUnknown_inner;
device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE)); else if (IsEqualIID(riid, &IID_IDirectSound) ||
if (!device->pwfx || !device->primary_pwfx) { (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
WARN("out of memory\n"); *ppv = &This->IDirectSound8_iface;
HeapFree(GetProcessHeap(),0,device->primary_pwfx); else {
HeapFree(GetProcessHeap(),0,device->pwfx); WARN("unknown IID %s\n", debugstr_guid(riid));
HeapFree(GetProcessHeap(),0,device); return E_NOINTERFACE;
return DSERR_OUTOFMEMORY;
} }
device->pwfx->wFormatTag = WAVE_FORMAT_PCM; IUnknown_AddRef((IUnknown*)*ppv);
device->pwfx->nSamplesPerSec = 22050; return S_OK;
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;
memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
InitializeCriticalSection(&(device->mixlock)); static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock"); {
IDirectSoundImpl *This = impl_from_IUnknown(iface);
ULONG ref = InterlockedIncrement(&This->ref);
RtlInitializeResource(&(device->buffer_list_lock)); TRACE("(%p) ref=%d\n", This, ref);
*ppDevice = device; if(ref == 1)
InterlockedIncrement(&This->numIfaces);
return DS_OK; return ref;
} }
static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device) static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
{ {
ULONG ref = InterlockedIncrement(&(device->ref)); IDirectSoundImpl *This = impl_from_IUnknown(iface);
TRACE("(%p) ref was %d\n", device, ref - 1); ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
if (!ref && !InterlockedDecrement(&This->numIfaces))
directsound_destroy(This);
return ref; return ref;
} }
ULONG DirectSoundDevice_Release(DirectSoundDevice * device) static const IUnknownVtbl unk_vtbl =
{ {
HRESULT hr; IUnknownImpl_QueryInterface,
ULONG ref = InterlockedDecrement(&(device->ref)); IUnknownImpl_AddRef,
TRACE("(%p) ref was %u\n", device, ref + 1); IUnknownImpl_Release
if (!ref) { };
int i;
SetEvent(device->sleepev); /*******************************************************************************
if (device->thread) { * IDirectSound and IDirectSound8 Implementation
WaitForSingleObject(device->thread, INFINITE); */
CloseHandle(device->thread); static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
} {
CloseHandle(device->sleepev); return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
}
EnterCriticalSection(&DSOUND_renderers_lock); static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
list_remove(&device->entry); void **ppv)
LeaveCriticalSection(&DSOUND_renderers_lock); {
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
}
/* It is allowed to release this object even when buffers are playing */ static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
if (device->buffers) { {
WARN("%d secondary buffers not released\n", device->nrofbuffers); IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
for( i=0;i<device->nrofbuffers;i++) ULONG ref = InterlockedIncrement(&This->refds);
secondarybuffer_destroy(device->buffers[i]);
}
hr = DSOUND_PrimaryDestroy(device); TRACE("(%p) refds=%d\n", This, ref);
if (hr != DS_OK)
WARN("DSOUND_PrimaryDestroy failed\n");
if(device->client) if(ref == 1)
IAudioClient_Release(device->client); InterlockedIncrement(&This->numIfaces);
if(device->render)
IAudioRenderClient_Release(device->render);
if(device->clock)
IAudioClock_Release(device->clock);
if(device->volume)
IAudioStreamVolume_Release(device->volume);
HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
HeapFree(GetProcessHeap(), 0, device->mix_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; return ref;
} }
BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
DWORD depth, WORD channels)
{ {
WAVEFORMATEX fmt, *junk; IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
HRESULT hr; ULONG ref = InterlockedDecrement(&(This->refds));
fmt.wFormatTag = WAVE_FORMAT_PCM; TRACE("(%p) refds=%d\n", This, ref);
fmt.nChannels = channels;
fmt.nSamplesPerSec = rate;
fmt.wBitsPerSample = depth;
fmt.nBlockAlign = (channels * depth) / 8;
fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
fmt.cbSize = 0;
hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk); if (!ref && !InterlockedDecrement(&This->numIfaces))
if(SUCCEEDED(hr)) directsound_destroy(This);
CoTaskMemFree(junk);
return hr == S_OK; return ref;
} }
HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID) static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
{ {
HRESULT hr = DS_OK; IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
GUID devGUID; TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
DirectSoundDevice *device; return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
IMMDevice *mmdevice; }
TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
if (*ppDevice != NULL) {
WARN("already initialized\n");
return DSERR_ALREADYINITIALIZED;
}
/* Default device? */ static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) {
lpcGUID = &DSDEVID_DefaultPlayback; IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) || TRACE("(%p, %p)\n", This, dscaps);
IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
return DSERR_NODRIVER;
if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) { if (!This->device) {
WARN("invalid parameter: lpcGUID\n"); WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
if (!dscaps) {
WARN("invalid parameter: dscaps = NULL\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
if (dscaps->dwSize < sizeof(*dscaps)) {
hr = get_mmdevice(eRender, &devGUID, &mmdevice); WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
if(FAILED(hr)) return DSERR_INVALIDPARAM;
return hr;
EnterCriticalSection(&DSOUND_renderers_lock);
LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
if(IsEqualGUID(&device->guid, &devGUID)){
IMMDevice_Release(mmdevice);
DirectSoundDevice_AddRef(device);
*ppDevice = device;
LeaveCriticalSection(&DSOUND_renderers_lock);
return DS_OK;
}
} }
hr = DirectSoundDevice_Create(&device); dscaps->dwFlags = This->device->drvcaps.dwFlags;
if(FAILED(hr)){ dscaps->dwMinSecondarySampleRate = This->device->drvcaps.dwMinSecondarySampleRate;
WARN("DirectSoundDevice_Create failed\n"); dscaps->dwMaxSecondarySampleRate = This->device->drvcaps.dwMaxSecondarySampleRate;
IMMDevice_Release(mmdevice); dscaps->dwPrimaryBuffers = This->device->drvcaps.dwPrimaryBuffers;
LeaveCriticalSection(&DSOUND_renderers_lock); dscaps->dwMaxHwMixingAllBuffers = This->device->drvcaps.dwMaxHwMixingAllBuffers;
return hr; dscaps->dwMaxHwMixingStaticBuffers = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
dscaps->dwMaxHwMixingStreamingBuffers = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
dscaps->dwFreeHwMixingAllBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
if (This->device->drvcaps.dwFreeHwMixingAllBuffers > 0) {
dscaps->dwFreeHwMixingStaticBuffers = This->device->drvcaps.dwFreeHwMixingStaticBuffers;
dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers;
} else {
dscaps->dwFreeHwMixingStaticBuffers = 0;
dscaps->dwFreeHwMixingStreamingBuffers = 0;
} }
device->mmdevice = mmdevice; dscaps->dwMaxHw3DAllBuffers = This->device->drvcaps.dwMaxHw3DAllBuffers;
device->guid = devGUID; dscaps->dwMaxHw3DStaticBuffers = This->device->drvcaps.dwMaxHw3DStaticBuffers;
device->sleepev = CreateEventW(0, 0, 0, 0); dscaps->dwMaxHw3DStreamingBuffers = This->device->drvcaps.dwMaxHw3DStreamingBuffers;
dscaps->dwFreeHw3DAllBuffers = This->device->drvcaps.dwFreeHw3DAllBuffers;
dscaps->dwFreeHw3DStaticBuffers = This->device->drvcaps.dwFreeHw3DStaticBuffers;
dscaps->dwFreeHw3DStreamingBuffers = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
dscaps->dwTotalHwMemBytes = This->device->drvcaps.dwTotalHwMemBytes;
dscaps->dwFreeHwMemBytes = This->device->drvcaps.dwFreeHwMemBytes;
dscaps->dwMaxContigFreeHwMemBytes = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
dscaps->dwUnlockTransferRateHwBuffers = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
dscaps->dwPlayCpuOverheadSwBuffers = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
hr = DSOUND_ReopenDevice(device, FALSE); if (TRACE_ON(dsound)) {
if (FAILED(hr)) TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
{ _dump_DSCAPS(dscaps->dwFlags);
HeapFree(GetProcessHeap(), 0, device); TRACE(")\n");
LeaveCriticalSection(&DSOUND_renderers_lock);
IMMDevice_Release(mmdevice);
WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
return hr;
} }
ZeroMemory(&device->drvcaps, sizeof(device->drvcaps)); return DS_OK;
}
if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
DSOUND_check_supported(device->client, 22050, 8, 1) ||
DSOUND_check_supported(device->client, 44100, 8, 1) ||
DSOUND_check_supported(device->client, 48000, 8, 1) ||
DSOUND_check_supported(device->client, 96000, 8, 1))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
if(DSOUND_check_supported(device->client, 11025, 16, 1) || static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
DSOUND_check_supported(device->client, 22050, 16, 1) || IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
DSOUND_check_supported(device->client, 44100, 16, 1) || {
DSOUND_check_supported(device->client, 48000, 16, 1) || IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
DSOUND_check_supported(device->client, 96000, 16, 1)) TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO; return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
}
if(DSOUND_check_supported(device->client, 11025, 8, 2) || static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
DSOUND_check_supported(device->client, 22050, 8, 2) || DWORD level)
DSOUND_check_supported(device->client, 44100, 8, 2) || {
DSOUND_check_supported(device->client, 48000, 8, 2) || IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
DSOUND_check_supported(device->client, 96000, 8, 2)) DirectSoundDevice *device = This->device;
device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO; DWORD oldlevel;
HRESULT hr = S_OK;
if(DSOUND_check_supported(device->client, 11025, 16, 2) || TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
DSOUND_check_supported(device->client, 22050, 16, 2) ||
DSOUND_check_supported(device->client, 44100, 16, 2) ||
DSOUND_check_supported(device->client, 48000, 16, 2) ||
DSOUND_check_supported(device->client, 96000, 16, 2))
device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
/* the dsound mixer supports all of the following */ if (!device) {
device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT; WARN("not initialized\n");
device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO; return DSERR_UNINITIALIZED;
device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE; }
device->drvcaps.dwPrimaryBuffers = 1; if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; WARN("level=%s not fully supported\n",
device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
device->drvcaps.dwMaxHwMixingAllBuffers = 16; }
device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
device->drvcaps.dwFreeHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
device->drvcaps.dwFreeHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
device->drvcaps.dwFreeHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
ZeroMemory(&device->volpan, sizeof(device->volpan)); RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
EnterCriticalSection(&device->mixlock);
oldlevel = device->priolevel;
device->priolevel = level;
if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
if (FAILED(hr))
device->priolevel = oldlevel;
else
DSOUND_PrimaryOpen(device);
}
LeaveCriticalSection(&device->mixlock);
RtlReleaseResource(&device->buffer_list_lock);
return hr;
}
hr = DSOUND_PrimaryCreate(device); static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
if (hr == DS_OK) { {
device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0); IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
} else
WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
*ppDevice = device; TRACE("(%p)\n", This);
list_add_tail(&DSOUND_renderers, &device->entry);
LeaveCriticalSection(&DSOUND_renderers_lock); if (!This->device) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
}
return hr; if (This->device->priolevel < DSSCL_PRIORITY) {
WARN("incorrect priority level\n");
return DSERR_PRIOLEVELNEEDED;
}
return DS_OK;
} }
HRESULT DirectSoundDevice_CreateSoundBuffer( static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
DirectSoundDevice * device,
LPCDSBUFFERDESC dsbd,
LPLPDIRECTSOUNDBUFFER ppdsb,
LPUNKNOWN lpunk,
BOOL from8)
{ {
HRESULT hres = DS_OK; IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
if (device == NULL) { TRACE("(%p, %p)\n", This, config);
if (!This->device) {
WARN("not initialized\n"); WARN("not initialized\n");
return DSERR_UNINITIALIZED; return DSERR_UNINITIALIZED;
} }
if (!config) {
if (dsbd == NULL) { WARN("invalid parameter: config == NULL\n");
WARN("invalid parameter: dsbd == NULL\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
if (dsbd->dwSize != sizeof(DSBUFFERDESC) && WARN("not fully functional\n");
dsbd->dwSize != sizeof(DSBUFFERDESC1)) { *config = This->device->speaker_config;
WARN("invalid parameter: dsbd\n"); return DS_OK;
return DSERR_INVALIDPARAM; }
}
if (ppdsb == NULL) { static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
WARN("invalid parameter: ppdsb == NULL\n"); {
return DSERR_INVALIDPARAM; IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
}
*ppdsb = NULL;
if (TRACE_ON(dsound)) { TRACE("(%p,0x%08x)\n", This, config);
TRACE("(structsize=%d)\n",dsbd->dwSize);
TRACE("(flags=0x%08x:\n",dsbd->dwFlags); if (!This->device) {
_dump_DSBCAPS(dsbd->dwFlags); WARN("not initialized\n");
TRACE(")\n"); return DSERR_UNINITIALIZED;
TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
} }
if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) && /* NOP on Vista and above */
dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
device->drvcaps.dwFreeHwMixingAllBuffers == 0) return DS_OK;
{ }
WARN("ran out of emulated hardware buffers\n");
return DSERR_ALLOCATED; static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
return DirectSoundDevice_Initialize(&This->device, lpcGuid);
}
static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
{
IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
TRACE("(%p, %p)\n", This, certified);
if (!This->device) {
WARN("not initialized\n");
return DSERR_UNINITIALIZED;
} }
if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) { if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
if (dsbd->lpwfxFormat != NULL) { *certified = DS_CERTIFIED;
WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for " else
"primary buffer\n"); *certified = DS_UNCERTIFIED;
return DSERR_INVALIDPARAM;
}
if (device->primary) { return DS_OK;
WARN("Primary Buffer already created\n"); }
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
*ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
} else {
hres = primarybuffer_create(device, &device->primary, dsbd);
if (device->primary) {
*ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
} else
WARN("primarybuffer_create() failed\n");
}
} else {
IDirectSoundBufferImpl * dsb;
WAVEFORMATEXTENSIBLE *pwfxe;
if (dsbd->lpwfxFormat == NULL) { static const IDirectSound8Vtbl ds8_vtbl =
WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for " {
"secondary buffer\n"); IDirectSound8Impl_QueryInterface,
return DSERR_INVALIDPARAM; IDirectSound8Impl_AddRef,
} IDirectSound8Impl_Release,
pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat; IDirectSound8Impl_CreateSoundBuffer,
IDirectSound8Impl_GetCaps,
IDirectSound8Impl_DuplicateSoundBuffer,
IDirectSound8Impl_SetCooperativeLevel,
IDirectSound8Impl_Compact,
IDirectSound8Impl_GetSpeakerConfig,
IDirectSound8Impl_SetSpeakerConfig,
IDirectSound8Impl_Initialize,
IDirectSound8Impl_VerifyCertification
};
if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
{ {
/* check if cbSize is at least 22 bytes */ IDirectSoundImpl *obj;
if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))) HRESULT hr;
{
WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
return DSERR_INVALIDPARAM;
}
/* cbSize should be 22 bytes, with one possible exception */ TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
!((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
{
WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
return DSERR_CONTROLUNAVAIL;
}
if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) *ppv = NULL;
{ obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL)) if (!obj) {
FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat)); WARN("out of memory\n");
return DSERR_INVALIDPARAM; return DSERR_OUTOFMEMORY;
} }
if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
{ setup_dsound_options();
WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
return DSERR_INVALIDPARAM; obj->IUnknown_inner.lpVtbl = &unk_vtbl;
} obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample) obj->ref = 1;
{ obj->refds = 0;
FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample); obj->numIfaces = 1;
return DSERR_CONTROLUNAVAIL; obj->device = NULL;
} obj->has_ds8 = has_ds8;
}
TRACE("(formattag=0x%04x,chans=%d,samplerate=%d," /* COM aggregation supported only internally */
"bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", if (outer_unk)
dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels, obj->outer_unk = outer_unk;
dsbd->lpwfxFormat->nSamplesPerSec, else
dsbd->lpwfxFormat->nAvgBytesPerSec, obj->outer_unk = &obj->IUnknown_inner;
dsbd->lpwfxFormat->nBlockAlign,
dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) { hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
WARN("invalid parameter: 3D buffer format must be mono\n"); IUnknown_Release(&obj->IUnknown_inner);
return DSERR_INVALIDPARAM;
}
hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd); return hr;
if (dsb) { }
*ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
device->drvcaps.dwFreeHwMixingAllBuffers--;
} else
WARN("IDirectSoundBufferImpl_Create failed\n");
}
return hres; HRESULT DSOUND_Create(REFIID riid, void **ppv)
{
return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
} }
HRESULT DirectSoundDevice_DuplicateSoundBuffer( HRESULT DSOUND_Create8(REFIID riid, void **ppv)
DirectSoundDevice * device,
LPDIRECTSOUNDBUFFER psb,
LPLPDIRECTSOUNDBUFFER ppdsb)
{ {
HRESULT hres = DS_OK; return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
IDirectSoundBufferImpl* dsb; }
TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
if (device == NULL) { /*******************************************************************************
WARN("not initialized\n"); * DirectSoundCreate (DSOUND.1)
return DSERR_UNINITIALIZED; *
} * 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;
if (psb == NULL) { TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
WARN("invalid parameter: psb == NULL\n");
if (ppDS == NULL) {
WARN("invalid parameter: ppDS == NULL\n");
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
if (ppdsb == NULL) { if (pUnkOuter != NULL) {
WARN("invalid parameter: ppdsb == NULL\n"); WARN("invalid parameter: pUnkOuter != NULL\n");
*ppDS = 0;
return DSERR_INVALIDPARAM; return DSERR_INVALIDPARAM;
} }
/* make sure we have a secondary buffer */ hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) { if (hr == DS_OK) {
WARN("trying to duplicate primary buffer\n"); hr = IDirectSound_Initialize(pDS, lpcGUID);
*ppdsb = NULL; if (hr != DS_OK) {
return DSERR_INVALIDCALL; if (hr != DSERR_ALREADYINITIALIZED) {
IDirectSound_Release(pDS);
pDS = 0;
} else
hr = DS_OK;
}
} }
/* duplicate the actual buffer implementation */ *ppDS = pDS;
hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
if (hres == DS_OK)
*ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
else
WARN("IDirectSoundBufferImpl_Duplicate failed\n");
return hres; return hr;
} }
/* /*******************************************************************************
* Add secondary buffer to buffer list. * DirectSoundCreate8 (DSOUND.11)
* Gets exclusive access to buffer for writing. *
* 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 DirectSoundDevice_AddBuffer( HRESULT WINAPI DirectSoundCreate8(
DirectSoundDevice * device, LPCGUID lpcGUID,
IDirectSoundBufferImpl * pDSB) LPDIRECTSOUND8 *ppDS,
IUnknown *pUnkOuter)
{ {
IDirectSoundBufferImpl **newbuffers; HRESULT hr;
HRESULT hr = DS_OK; LPDIRECTSOUND8 pDS;
TRACE("(%p, %p)\n", device, pDSB); TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); if (ppDS == NULL) {
WARN("invalid parameter: ppDS == NULL\n");
return DSERR_INVALIDPARAM;
}
if (device->buffers) if (pUnkOuter != NULL) {
newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1)); WARN("invalid parameter: pUnkOuter != NULL\n");
else *ppDS = 0;
newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1)); return DSERR_INVALIDPARAM;
}
if (newbuffers) { hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
device->buffers = newbuffers; if (hr == DS_OK) {
device->buffers[device->nrofbuffers] = pDSB; hr = IDirectSound8_Initialize(pDS, lpcGUID);
device->nrofbuffers++; if (hr != DS_OK) {
TRACE("buffer count is now %d\n", device->nrofbuffers); if (hr != DSERR_ALREADYINITIALIZED) {
} else { IDirectSound8_Release(pDS);
ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers); pDS = 0;
hr = DSERR_OUTOFMEMORY; } else
hr = DS_OK;
}
} }
RtlReleaseResource(&(device->buffer_list_lock)); *ppDS = pDS;
return hr; return hr;
} }
/* void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device)
* Remove secondary buffer from buffer list.
* Gets exclusive access to buffer for writing.
*/
void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
{ {
int i; switch (DSSPEAKER_CONFIG(device->speaker_config)) {
case DSSPEAKER_MONO:
device->speaker_angles[0] = M_PI/180.0f * 0.0f;
device->speaker_num[0] = 0;
device->num_speakers = 1;
device->lfe_channel = -1;
break;
TRACE("(%p, %p)\n", device, pDSB); case DSSPEAKER_STEREO:
case DSSPEAKER_HEADPHONE:
device->speaker_angles[0] = M_PI/180.0f * -90.0f;
device->speaker_angles[1] = M_PI/180.0f * 90.0f;
device->speaker_num[0] = 0; /* Left */
device->speaker_num[1] = 1; /* Right */
device->num_speakers = 2;
device->lfe_channel = -1;
break;
RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); case DSSPEAKER_QUAD:
device->speaker_angles[0] = M_PI/180.0f * -135.0f;
device->speaker_angles[1] = M_PI/180.0f * -45.0f;
device->speaker_angles[2] = M_PI/180.0f * 45.0f;
device->speaker_angles[3] = M_PI/180.0f * 135.0f;
device->speaker_num[0] = 2; /* Rear left */
device->speaker_num[1] = 0; /* Front left */
device->speaker_num[2] = 1; /* Front right */
device->speaker_num[3] = 3; /* Rear right */
device->num_speakers = 4;
device->lfe_channel = -1;
break;
if (device->nrofbuffers == 1) { case DSSPEAKER_5POINT1_BACK:
assert(device->buffers[0] == pDSB); device->speaker_angles[0] = M_PI/180.0f * -135.0f;
HeapFree(GetProcessHeap(), 0, device->buffers); device->speaker_angles[1] = M_PI/180.0f * -45.0f;
device->buffers = NULL; device->speaker_angles[2] = M_PI/180.0f * 0.0f;
} else { device->speaker_angles[3] = M_PI/180.0f * 45.0f;
for (i = 0; i < device->nrofbuffers; i++) { device->speaker_angles[4] = M_PI/180.0f * 135.0f;
if (device->buffers[i] == pDSB) { device->speaker_angles[5] = 9999.0f;
/* Put the last buffer of the list in the (now empty) position */ device->speaker_num[0] = 4; /* Rear left */
device->buffers[i] = device->buffers[device->nrofbuffers - 1]; device->speaker_num[1] = 0; /* Front left */
break; device->speaker_num[2] = 2; /* Front centre */
} device->speaker_num[3] = 1; /* Front right */
} device->speaker_num[4] = 5; /* Rear right */
} device->speaker_num[5] = 3; /* LFE */
device->nrofbuffers--; device->num_speakers = 6;
TRACE("buffer count is now %d\n", device->nrofbuffers); device->lfe_channel = 3;
break;
RtlReleaseResource(&(device->buffer_list_lock)); case DSSPEAKER_5POINT1_SURROUND:
device->speaker_angles[0] = M_PI/180.0f * -90.0f;
device->speaker_angles[1] = M_PI/180.0f * -30.0f;
device->speaker_angles[2] = M_PI/180.0f * 0.0f;
device->speaker_angles[3] = M_PI/180.0f * 30.0f;
device->speaker_angles[4] = M_PI/180.0f * 90.0f;
device->speaker_angles[5] = 9999.0f;
device->speaker_num[0] = 4; /* Rear left */
device->speaker_num[1] = 0; /* Front left */
device->speaker_num[2] = 2; /* Front centre */
device->speaker_num[3] = 1; /* Front right */
device->speaker_num[4] = 5; /* Rear right */
device->speaker_num[5] = 3; /* LFE */
device->num_speakers = 6;
device->lfe_channel = 3;
break;
default:
WARN("unknown speaker_config %u\n", device->speaker_config);
}
} }
...@@ -111,24 +111,10 @@ typedef struct BufferMemory ...@@ -111,24 +111,10 @@ typedef struct BufferMemory
struct list buffers; struct list buffers;
} BufferMemory; } BufferMemory;
ULONG DirectSoundDevice_Release(DirectSoundDevice * device) DECLSPEC_HIDDEN;
HRESULT DirectSoundDevice_Initialize(
DirectSoundDevice ** ppDevice,
LPCGUID lpcGUID) DECLSPEC_HIDDEN;
HRESULT DirectSoundDevice_AddBuffer( HRESULT DirectSoundDevice_AddBuffer(
DirectSoundDevice * device, DirectSoundDevice * device,
IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN; IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN;
void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN; void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN;
HRESULT DirectSoundDevice_CreateSoundBuffer(
DirectSoundDevice * device,
LPCDSBUFFERDESC dsbd,
LPLPDIRECTSOUNDBUFFER ppdsb,
LPUNKNOWN lpunk,
BOOL from8) DECLSPEC_HIDDEN;
HRESULT DirectSoundDevice_DuplicateSoundBuffer(
DirectSoundDevice * device,
LPDIRECTSOUNDBUFFER psb,
LPLPDIRECTSOUNDBUFFER ppdsb) DECLSPEC_HIDDEN;
/***************************************************************************** /*****************************************************************************
* IDirectSoundBuffer implementation structure * IDirectSoundBuffer implementation structure
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment