[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