[PATCH 3/5] dsound: fix format handling on invalid format to never fail
Maarten Lankhorst
m.b.lankhorst at gmail.com
Wed Jan 2 07:46:45 CST 2013
For the users still on oss4 this is probably useful. This is more of
a theoretical concern than practical, since nobody uses primary mode.
And even if someone did, they would have to find a format that was
unsupported, like IEEE float would probably be the easiest to trigger.
This patch now forces everything to a single call to DSOUND_ReopenDevice,
which will either fail and keep previous state, or succeed.
---
dlls/dsound/dsound.c | 48 +++----
dlls/dsound/dsound_convert.c | 18 ---
dlls/dsound/dsound_main.c | 2 +-
dlls/dsound/dsound_private.h | 5 +-
dlls/dsound/mixer.c | 53 +++----
dlls/dsound/primary.c | 335 +++++++++++++++++++------------------------
6 files changed, 189 insertions(+), 272 deletions(-)
diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index 6fda72f..b419bd4 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -306,7 +306,6 @@ static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface
{
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));
@@ -323,15 +322,10 @@ static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface
RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
EnterCriticalSection(&device->mixlock);
- oldlevel = device->priolevel;
- device->priolevel = level;
- if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
+ if ((level == DSSCL_WRITEPRIMARY) != (device->priolevel == DSSCL_WRITEPRIMARY))
hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
- if (FAILED(hr))
- device->priolevel = oldlevel;
- else
- DSOUND_PrimaryOpen(device);
- }
+ if (SUCCEEDED(hr))
+ device->priolevel = level;
LeaveCriticalSection(&device->mixlock);
RtlReleaseResource(&device->buffer_list_lock);
return hr;
@@ -626,24 +620,20 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
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) {
+ if (!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;
}
- 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;
- memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
+ device->primary_pwfx->wFormatTag = WAVE_FORMAT_PCM;
+ device->primary_pwfx->nSamplesPerSec = 22050;
+ device->primary_pwfx->wBitsPerSample = 8;
+ device->primary_pwfx->nChannels = 2;
+ device->primary_pwfx->nBlockAlign = 2;
+ device->primary_pwfx->nAvgBytesPerSec = 44100;
+ device->primary_pwfx->cbSize = 0;
InitializeCriticalSection(&(device->mixlock));
device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
@@ -692,17 +682,16 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
if (hr != DS_OK)
WARN("DSOUND_PrimaryDestroy failed\n");
- if(device->client)
+ if(device->client) {
+ IAudioClient_Stop(device->client);
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;
@@ -812,6 +801,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
device->mmdevice = mmdevice;
device->guid = devGUID;
device->sleepev = CreateEventW(0, 0, 0, 0);
+ device->buflen = ds_hel_buflen;
hr = DSOUND_ReopenDevice(device, FALSE);
if (FAILED(hr))
@@ -867,12 +857,8 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
ZeroMemory(&device->volpan, sizeof(device->volpan));
- 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);
+ device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
+ SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
*ppDevice = device;
list_add_tail(&DSOUND_renderers, &device->entry);
diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c
index d3d686a..d410d5e 100644
--- a/dlls/dsound/dsound_convert.c
+++ b/dlls/dsound/dsound_convert.c
@@ -222,27 +222,9 @@ static void norm32(float *src, INT *dst, unsigned len)
}
}
-static void normieee32(float *src, float *dst, unsigned len)
-{
- TRACE("%p - %p %d\n", src, dst, len);
- len /= 4;
- while (len--)
- {
- if(*src > 1)
- *dst = 1;
- else if(*src < -1)
- *dst = -1;
- else
- *dst = *src;
- ++dst;
- ++src;
- }
-}
-
const normfunc normfunctions[5] = {
(normfunc)norm8,
(normfunc)norm16,
(normfunc)norm24,
(normfunc)norm32,
- (normfunc)normieee32
};
diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index aa3d647..0df15b1 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -91,7 +91,7 @@ GUID DSOUND_capture_guids[MAXWAVEDRIVERS];
WCHAR wine_vxd_drv[] = { 'w','i','n','e','m','m','.','v','x','d', 0 };
/* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */
-int ds_hel_buflen = 32768 * 2;
+int ds_hel_buflen = 32768;
static HINSTANCE instance;
/*
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index bdd3a37..15abc93 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -77,7 +77,7 @@ struct DirectSoundDevice
CRITICAL_SECTION mixlock;
IDirectSoundBufferImpl *primary;
DWORD speaker_config;
- float *mix_buffer, *tmp_buffer;
+ float *tmp_buffer;
DWORD tmp_buffer_len, mix_buffer_len;
DSVOLUMEPAN volpan;
@@ -90,7 +90,6 @@ struct DirectSoundDevice
IMMDevice *mmdevice;
IAudioClient *client;
- IAudioClock *clock;
IAudioStreamVolume *volume;
IAudioRenderClient *render;
@@ -199,13 +198,11 @@ HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BO
/* primary.c */
-HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device) DECLSPEC_HIDDEN;
HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) DECLSPEC_HIDDEN;
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN;
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN;
LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex) DECLSPEC_HIDDEN;
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) DECLSPEC_HIDDEN;
-HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) DECLSPEC_HIDDEN;
HRESULT primarybuffer_create(DirectSoundDevice *device, IDirectSoundBufferImpl **ppdsb,
const DSBUFFERDESC *dsbd) DECLSPEC_HIDDEN;
void primarybuffer_destroy(IDirectSoundBufferImpl *This) DECLSPEC_HIDDEN;
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 1bf4857..3c5492b 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -603,8 +603,7 @@ done:
* secondary->buffer (secondary format)
* =[Resample]=> device->tmp_buffer (float format)
* =[Volume]=> device->tmp_buffer (float format)
- * =[Mix]=> device->mix_buffer (float format)
- * =[Reformat]=> device->buffer (device format)
+ * =[Reformat]=> device->buffer (device format, skipped on float)
*/
static void DSOUND_PerformMix(DirectSoundDevice *device)
{
@@ -643,8 +642,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
if (device->priolevel != DSSCL_WRITEPRIMARY) {
BOOL all_stopped = FALSE;
int nfiller;
- BOOL native = device->normfunction == normfunctions[4];
- DWORD bpp = device->pwfx->wBitsPerSample>>3;
+ void *buffer = NULL;
/* the sound of silence */
nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
@@ -658,43 +656,30 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
TRACE("Buffer restarting\n");
}
- if (native) {
- void *buffer = NULL;
+ hr = IAudioRenderClient_GetBuffer(device->render, maxq / block, (void*)&buffer);
+ if(FAILED(hr)){
+ WARN("GetBuffer failed: %08x\n", hr);
+ LeaveCriticalSection(&device->mixlock);
+ return;
+ }
- hr = IAudioRenderClient_GetBuffer(device->render, maxq / block, (void*)&buffer);
- if(FAILED(hr)){
- WARN("GetBuffer failed: %08x\n", hr);
- LeaveCriticalSection(&device->mixlock);
- return;
- }
- memset(buffer, nfiller, maxq);
+ memset(buffer, nfiller, maxq);
+ if (!device->normfunction)
DSOUND_MixToPrimary(device, buffer, writepos, maxq, &all_stopped);
-
- hr = IAudioRenderClient_ReleaseBuffer(device->render, maxq / block, 0);
- if(FAILED(hr))
- ERR("ReleaseBuffer failed: %08x\n", hr);
-
- device->pad += maxq;
- } else {
- memset(device->mix_buffer, nfiller, maxq);
+ else {
/* do the mixing */
- DSOUND_MixToPrimary(device, device->mix_buffer, writepos, maxq, &all_stopped);
+ DSOUND_MixToPrimary(device, (float*)device->buffer, writepos, maxq, &all_stopped);
- if (maxq + writepos > device->buflen) {
- DWORD todo = device->buflen - writepos;
+ device->normfunction(device->buffer, buffer, maxq);
+ }
- device->normfunction(device->mix_buffer, device->buffer + writepos, todo);
- DSOUND_WaveQueue(device, device->buffer + writepos, todo);
+ hr = IAudioRenderClient_ReleaseBuffer(device->render, maxq / block, 0);
+ if(FAILED(hr))
+ ERR("ReleaseBuffer failed: %08x\n", hr);
- device->normfunction(device->mix_buffer + todo / bpp, device->buffer, (maxq - todo));
- DSOUND_WaveQueue(device, device->buffer, maxq - todo);
- } else {
- device->normfunction(device->mix_buffer, device->buffer + writepos, maxq);
- DSOUND_WaveQueue(device, device->buffer + writepos, maxq);
- }
- }
+ device->pad += maxq;
if (maxq) {
if (device->state == STATE_STARTING ||
@@ -712,6 +697,8 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
DSOUND_PrimaryStop(device);
}
} else if (device->state != STATE_STOPPED) {
+ if (maxq > device->buflen)
+ maxq = device->buflen;
if (writepos + maxq > device->buflen) {
DSOUND_WaveQueue(device, device->buffer + writepos, device->buflen - writepos);
DSOUND_WaveQueue(device, device->buffer, writepos + maxq - device->buflen);
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index cef4db5..8828d05 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -128,16 +128,8 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client
return S_OK;
}
-HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
+static void DSOUND_ReleaseDevice(DirectSoundDevice *device)
{
- WAVEFORMATEX *wfx = NULL;
- HRESULT hres;
- REFERENCE_TIME period, buflen = 800000;
- UINT32 frames;
- DWORD period_ms;
-
- TRACE("(%p, %d)\n", device, forcewave);
-
if(device->client){
IAudioClient_Release(device->client);
device->client = NULL;
@@ -146,10 +138,6 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
IAudioRenderClient_Release(device->render);
device->render = NULL;
}
- if(device->clock){
- IAudioClock_Release(device->clock);
- device->clock = NULL;
- }
if(device->volume){
IAudioStreamVolume_Release(device->volume);
device->volume = NULL;
@@ -160,158 +148,82 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
device->playpos %= device->buflen;
device->pad = 0;
}
-
- hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
- CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
- if(FAILED(hres)) {
- WARN("Activate failed: %08x\n", hres);
- return hres;
- }
-
- hres = DSOUND_WaveFormat(device, device->client, forcewave, &wfx);
- if (FAILED(hres)) {
- IAudioClient_Release(device->client);
- device->client = NULL;
- return hres;
- }
- HeapFree(GetProcessHeap(), 0, device->pwfx);
- device->pwfx = wfx;
-
- hres = IAudioClient_Initialize(device->client,
- AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buflen, 0, device->pwfx, NULL);
- if(FAILED(hres)){
- IAudioClient_Release(device->client);
- device->client = NULL;
- WARN("Initialize failed: %08x\n", hres);
- return hres;
- }
- IAudioClient_SetEventHandle(device->client, device->sleepev);
-
- hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
- (void**)&device->render);
- if(FAILED(hres)){
- IAudioClient_Release(device->client);
- device->client = NULL;
- WARN("GetService failed: %08x\n", hres);
- return hres;
- }
-
- hres = IAudioClient_GetService(device->client, &IID_IAudioClock,
- (void**)&device->clock);
- if(FAILED(hres)){
- IAudioClient_Release(device->client);
- IAudioRenderClient_Release(device->render);
- device->client = NULL;
- device->render = NULL;
- WARN("GetService failed: %08x\n", hres);
- return hres;
- }
-
- hres = IAudioClient_GetService(device->client, &IID_IAudioStreamVolume,
- (void**)&device->volume);
- if(FAILED(hres)){
- IAudioClient_Release(device->client);
- IAudioRenderClient_Release(device->render);
- IAudioClock_Release(device->clock);
- device->client = NULL;
- device->render = NULL;
- device->clock = NULL;
- WARN("GetService failed: %08x\n", hres);
- return hres;
- }
-
- /* Now kick off the timer so the event fires periodically */
- hres = IAudioClient_Start(device->client);
- if (FAILED(hres))
- WARN("starting failed with %08x\n", hres);
-
- hres = IAudioClient_GetStreamLatency(device->client, &period);
- if (FAILED(hres)) {
- WARN("GetStreamLatency failed with %08x\n", hres);
- period = 100000;
- }
- period_ms = (period + 9999) / 10000;
-
- hres = IAudioClient_GetBufferSize(device->client, &frames);
- if (FAILED(hres)) {
- WARN("GetBufferSize failed with %08x\n", hres);
- frames = (UINT64)device->pwfx->nSamplesPerSec * buflen / 10000000;
- }
-
- device->fraglen = MulDiv(device->pwfx->nSamplesPerSec, period, 10000000) * device->pwfx->nBlockAlign;
- device->aclen = frames * device->pwfx->nBlockAlign;
- TRACE("period %u ms fraglen %u buflen %u\n", period_ms, device->fraglen, device->aclen);
-
- if (period_ms < 3)
- device->sleeptime = 5;
- else
- device->sleeptime = period_ms * 5 / 2;
-
- return S_OK;
}
-HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
+static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx, DWORD aclen, BOOL forcewave)
{
- IDirectSoundBufferImpl** dsb = device->buffers;
- LPBYTE newbuf;
- DWORD i;
-
- TRACE("(%p)\n", device);
+ IDirectSoundBufferImpl** dsb = device->buffers;
+ LPBYTE newbuf;
+ DWORD i, new_buflen;
+ BOOL mixfloat = FALSE;
- /* on original windows, the buffer it set to a fixed size, no matter what the settings are.
- on windows this size is always fixed (tested on win-xp) */
- if (!device->buflen)
- device->buflen = ds_hel_buflen;
- device->buflen -= device->buflen % device->pwfx->nBlockAlign;
+ TRACE("(%p)\n", device);
- HeapFree(GetProcessHeap(), 0, device->mix_buffer);
- device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
- device->mix_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, device->mix_buffer_len);
- if (!device->mix_buffer)
- return DSERR_OUTOFMEMORY;
+ new_buflen = device->buflen;
+ new_buflen -= new_buflen % wfx->nBlockAlign;
- if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
- else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
+ if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
+ mixfloat = TRUE;
/* reallocate emulated primary buffer */
- if (device->buffer)
- newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, device->buflen);
- else
- newbuf = HeapAlloc(GetProcessHeap(),0, device->buflen);
+ if (forcewave) {
+ if (device->buffer)
+ newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, new_buflen);
+ else
+ newbuf = HeapAlloc(GetProcessHeap(), 0, new_buflen);
+
+ if (!newbuf) {
+ ERR("failed to allocate primary buffer\n");
+ return DSERR_OUTOFMEMORY;
+ }
+ device->mix_buffer_len = 0;
+ } else if (!mixfloat) {
+ DWORD alloc_len = aclen / (wfx->nBlockAlign / 8) * sizeof(float);
- if (!newbuf) {
- ERR("failed to allocate primary buffer\n");
- return DSERR_OUTOFMEMORY;
- /* but the old buffer might still exist and must be re-prepared */
- }
+ if (device->buffer)
+ newbuf = HeapReAlloc(GetProcessHeap(), 0, device->buffer, alloc_len);
+ else
+ newbuf = HeapAlloc(GetProcessHeap(), 0, alloc_len);
- device->writelead = (device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign;
+ if (!newbuf) {
+ ERR("failed to allocate primary buffer\n");
+ return DSERR_OUTOFMEMORY;
+ }
+ device->mix_buffer_len = alloc_len;
+ } else {
+ HeapFree(GetProcessHeap(), 0, device->buffer);
+ newbuf = NULL;
+ device->mix_buffer_len = 0;
+ }
device->buffer = newbuf;
+ device->buflen = new_buflen;
+ HeapFree(GetProcessHeap(), 0, device->pwfx);
+ device->pwfx = wfx;
+
+ if (device->state == STATE_PLAYING)
+ device->state = STATE_STARTING;
+ else if (device->state == STATE_STOPPING)
+ device->state = STATE_STOPPED;
+
+ device->writelead = (wfx->nSamplesPerSec / 100) * wfx->nBlockAlign;
TRACE("buflen: %u, fraglen: %u, mix_buffer_len: %u\n",
- device->buflen, device->fraglen, device->mix_buffer_len);
+ device->buflen, device->fraglen, device->mix_buffer_len);
- if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
- (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
- &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
- device->normfunction = normfunctions[4];
+ if (!forcewave && !mixfloat)
+ device->normfunction = normfunctions[wfx->nBlockAlign/8 - 1];
else
- device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
+ device->normfunction = NULL;
- FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
- FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
+ if (device->mix_buffer_len)
+ FillMemory(device->buffer, device->mix_buffer_len, 0);
+ else if (device->buffer)
+ FillMemory(device->buffer, device->buflen, (wfx->wBitsPerSample == 8) ? 128 : 0);
device->playpos = 0;
- if (device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
- (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
- device->normfunction = normfunctions[4];
- else
- device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
-
for (i = 0; i < device->nrofbuffers; i++) {
RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE);
DSOUND_RecalcFormat(dsb[i]);
@@ -321,35 +233,103 @@ HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
return DS_OK;
}
-
-static void DSOUND_PrimaryClose(DirectSoundDevice *device)
+HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
{
- HRESULT hr;
+ HRESULT hres;
+ REFERENCE_TIME period;
+ UINT32 frames;
+ DWORD period_ms;
+ IAudioClient *client = NULL;
+ IAudioRenderClient *render = NULL;
+ IAudioStreamVolume *volume = NULL;
+ DWORD fraglen, aclen;
+ WAVEFORMATEX *wfx = NULL;
- TRACE("(%p)\n", device);
+ TRACE("(%p, %d)\n", device, forcewave);
- if(device->client){
- hr = IAudioClient_Stop(device->client);
- if(FAILED(hr))
- WARN("Stop failed: %08x\n", hr);
+ hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
+ CLSCTX_INPROC_SERVER, NULL, (void **)&client);
+ if(FAILED(hres)){
+ WARN("Activate failed: %08x\n", hres);
+ return hres;
}
-}
-HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
-{
- HRESULT err = DS_OK;
- TRACE("(%p)\n", device);
+ hres = DSOUND_WaveFormat(device, client, forcewave, &wfx);
+ if (FAILED(hres)) {
+ IAudioClient_Release(client);
+ return hres;
+ }
- device->buflen = ds_hel_buflen;
- err = DSOUND_PrimaryOpen(device);
+ hres = IAudioClient_Initialize(client,
+ AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 800000, 0, wfx, NULL);
+ if(FAILED(hres)){
+ IAudioClient_Release(client);
+ ERR("Initialize failed: %08x\n", hres);
+ return hres;
+ }
- if (err != DS_OK) {
- WARN("DSOUND_PrimaryOpen failed\n");
- return err;
- }
+ IAudioClient_SetEventHandle(client, device->sleepev);
- device->state = STATE_STOPPED;
- return DS_OK;
+ hres = IAudioClient_GetService(client, &IID_IAudioRenderClient, (void**)&render);
+ if(FAILED(hres))
+ goto err_service;
+
+ hres = IAudioClient_GetService(client, &IID_IAudioStreamVolume, (void**)&volume);
+ if(FAILED(hres))
+ goto err_service;
+
+ /* Now kick off the timer so the event fires periodically */
+ hres = IAudioClient_Start(client);
+ if (FAILED(hres)) {
+ WARN("Start failed with %08x\n", hres);
+ goto err;
+ }
+ hres = IAudioClient_GetStreamLatency(client, &period);
+ if (FAILED(hres)) {
+ WARN("GetStreamLatency failed with %08x\n", hres);
+ goto err;
+ }
+ hres = IAudioClient_GetBufferSize(client, &frames);
+ if (FAILED(hres)) {
+ WARN("GetBufferSize failed with %08x\n", hres);
+ goto err;
+ }
+
+ period_ms = (period + 9999) / 10000;
+ fraglen = MulDiv(wfx->nSamplesPerSec, period, 10000000) * wfx->nBlockAlign;
+ aclen = frames * wfx->nBlockAlign;
+ TRACE("period %u ms fraglen %u buflen %u\n", period_ms, fraglen, aclen);
+
+ hres = DSOUND_PrimaryOpen(device, wfx, aclen, forcewave);
+ if(FAILED(hres))
+ goto err;
+
+ DSOUND_ReleaseDevice(device);
+ device->client = client;
+ device->render = render;
+ device->volume = volume;
+ device->fraglen = fraglen;
+ device->aclen = aclen;
+
+ if (period_ms < 3)
+ device->sleeptime = 5;
+ else
+ device->sleeptime = period_ms * 5 / 2;
+
+ return S_OK;
+
+err_service:
+ ERR("GetService failed: %08x\n", hres);
+err:
+ if (volume)
+ IAudioStreamVolume_Release(volume);
+ if (render)
+ IAudioRenderClient_Release(render);
+ if (client)
+ IAudioClient_Release(client);
+ HeapFree(GetProcessHeap(), 0, wfx);
+ return hres;
}
HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
@@ -359,8 +339,6 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
/* **** */
EnterCriticalSection(&(device->mixlock));
- DSOUND_PrimaryClose(device);
-
if(device->primary && (device->primary->ref || device->primary->numIfaces))
WARN("Destroying primary buffer while references held (%u %u)\n", device->primary->ref, device->primary->numIfaces);
@@ -443,7 +421,6 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe
HRESULT err = S_OK;
WAVEFORMATEX *old_fmt;
WAVEFORMATEXTENSIBLE *fmtex, *passed_fmtex = (WAVEFORMATEXTENSIBLE*)passed_fmt;
- BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY);
TRACE("(%p,%p)\n", device, passed_fmt);
@@ -493,24 +470,12 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe
fmtex->Samples.wValidBitsPerSample = fmtex->Format.wBitsPerSample;
}
- DSOUND_PrimaryClose(device);
-
- err = DSOUND_ReopenDevice(device, forced);
+ err = DSOUND_ReopenDevice(device, TRUE);
if (FAILED(err)) {
ERR("No formats could be opened\n");
- goto done;
- }
-
- err = DSOUND_PrimaryOpen(device);
- if (err != DS_OK) {
- ERR("DSOUND_PrimaryOpen failed\n");
- goto done;
- }
-
-done:
- if (err != DS_OK)
+ HeapFree(GetProcessHeap(), 0, device->primary_pwfx);
device->primary_pwfx = old_fmt;
- else
+ } else
HeapFree(GetProcessHeap(), 0, old_fmt);
} else if (passed_fmt->wFormatTag == WAVE_FORMAT_PCM ||
passed_fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
--
1.8.0.3
More information about the wine-patches
mailing list