Jörg Höhle : dsound: Enforce invariant about BlockAlign and nAvgBytesPerSec.

Alexandre Julliard julliard at winehq.org
Tue Oct 6 10:35:52 CDT 2009


Module: wine
Branch: master
Commit: dc3471ca0e7c2209ecf9758359cc62f9d958bf2c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=dc3471ca0e7c2209ecf9758359cc62f9d958bf2c

Author: Jörg Höhle <hoehle at users.sourceforge.net>
Date:   Sun Oct  4 08:05:20 2009 +0200

dsound: Enforce invariant about BlockAlign and nAvgBytesPerSec.

---

 dlls/dsound/buffer.c         |   32 ++++++-------------------
 dlls/dsound/capture.c        |   11 +++-----
 dlls/dsound/dsound_private.h |    1 +
 dlls/dsound/primary.c        |   53 +++++++++++++++++++++++++++++++++--------
 4 files changed, 55 insertions(+), 42 deletions(-)

diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
index 2d64341..4b486fd 100644
--- a/dlls/dsound/buffer.c
+++ b/dlls/dsound/buffer.c
@@ -957,7 +957,7 @@ HRESULT IDirectSoundBufferImpl_Create(
 	LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
 	HRESULT err = DS_OK;
 	DWORD capf = 0;
-	int use_hw, alloc_size, cp_size;
+	int use_hw;
 	TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
 
 	if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
@@ -985,23 +985,13 @@ HRESULT IDirectSoundBufferImpl_Create(
 	/* size depends on version */
 	CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
 
-	/* variable sized struct so calculate size based on format */
-	if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
-		alloc_size = sizeof(WAVEFORMATEX);
-		cp_size = sizeof(PCMWAVEFORMAT);
-	} else 
-		alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
-
-	dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
+	dsb->pwfx = DSOUND_CopyFormat(wfex);
 	if (dsb->pwfx == NULL) {
-		WARN("out of memory\n");
 		HeapFree(GetProcessHeap(),0,dsb);
 		*pdsb = NULL;
 		return DSERR_OUTOFMEMORY;
 	}
 
-	CopyMemory(dsb->pwfx, wfex, cp_size);
-
 	if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
 		dsb->buflen = dsbd->dwBufferBytes + 
 			(dsbd->lpwfxFormat->nBlockAlign - 
@@ -1185,7 +1175,6 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
 {
     IDirectSoundBufferImpl *dsb;
     HRESULT hres = DS_OK;
-    int size;
     TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
 
     dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
@@ -1224,20 +1213,15 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
     DSOUND_RecalcFormat(dsb);
     DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
 
-    /* variable sized struct so calculate size based on format */
-    size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
-
-    dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
+    dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
     if (dsb->pwfx == NULL) {
-            WARN("out of memory\n");
-            HeapFree(GetProcessHeap(),0,dsb->buffer);
-            HeapFree(GetProcessHeap(),0,dsb);
-            *ppdsb = NULL;
-            return DSERR_OUTOFMEMORY;
+        HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
+        HeapFree(GetProcessHeap(),0,dsb->buffer);
+        HeapFree(GetProcessHeap(),0,dsb);
+        *ppdsb = NULL;
+        return DSERR_OUTOFMEMORY;
     }
 
-    CopyMemory(dsb->pwfx, pdsb->pwfx, size);
-
     RtlInitializeResource(&dsb->lock);
 
     /* register buffer */
diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c
index 0e75dd7..95b38af 100644
--- a/dlls/dsound/capture.c
+++ b/dlls/dsound/capture.c
@@ -1365,13 +1365,10 @@ HRESULT IDirectSoundCaptureBufferImpl_Create(
         wfex->nAvgBytesPerSec, wfex->nBlockAlign,
         wfex->wBitsPerSample, wfex->cbSize);
 
-    if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
-        device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
-        CopyMemory(device->pwfx, wfex, sizeof(PCMWAVEFORMAT));
-        device->pwfx->cbSize = 0;
-    } else {
-        device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
-        CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
+    device->pwfx = DSOUND_CopyFormat(wfex);
+    if ( device->pwfx == NULL ) {
+	*ppobj = NULL;
+	return DSERR_OUTOFMEMORY;
     }
 
     *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 221433f..e028358 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -437,6 +437,7 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos);
+LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex);
 HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex, BOOL forced);
 HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave);
 
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index a57a5af..6b3ca35 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -17,6 +17,10 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * TODO:
+ *      When PrimarySetFormat (via ReopenDevice or PrimaryOpen) fails,
+ *       it leaves dsound in unusable (not really open) state.
  */
 
 #include <stdarg.h>
@@ -437,11 +441,36 @@ HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LP
 	return DS_OK;
 }
 
+LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex)
+{
+	DWORD size = wfex->wFormatTag == WAVE_FORMAT_PCM ?
+		sizeof(WAVEFORMATEX) : sizeof(WAVEFORMATEX) + wfex->cbSize;
+	LPWAVEFORMATEX pwfx = HeapAlloc(GetProcessHeap(),0,size);
+	if (pwfx == NULL) {
+		WARN("out of memory\n");
+	} else if (wfex->wFormatTag != WAVE_FORMAT_PCM) {
+		CopyMemory(pwfx, wfex, size);
+	} else {
+		CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
+		pwfx->cbSize=0;
+		if (pwfx->nBlockAlign != pwfx->nChannels * pwfx->wBitsPerSample/8) {
+			WARN("Fixing bad nBlockAlign (%u)\n", pwfx->nBlockAlign);
+			pwfx->nBlockAlign  = pwfx->nChannels * pwfx->wBitsPerSample/8;
+		}
+		if (pwfx->nAvgBytesPerSec != pwfx->nSamplesPerSec * pwfx->nBlockAlign) {
+			WARN("Fixing bad nAvgBytesPerSec (%u)\n", pwfx->nAvgBytesPerSec);
+			pwfx->nAvgBytesPerSec  = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
+		}
+	}
+	return pwfx;
+}
+
 HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex, BOOL forced)
 {
 	HRESULT err = DSERR_BUFFERLOST;
-	int i, alloc_size, cp_size;
+	int i;
 	DWORD nSamplesPerSec, bpp, chans;
+	LPWAVEFORMATEX oldpwfx;
 	TRACE("(%p,%p)\n", device, wfex);
 
 	if (device->priolevel == DSSCL_NORMAL) {
@@ -464,19 +493,19 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
 	RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 	EnterCriticalSection(&(device->mixlock));
 
-        if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
-            alloc_size = sizeof(WAVEFORMATEX);
-            cp_size = sizeof(PCMWAVEFORMAT);
-        } else
-            alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
-
-        device->pwfx = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,device->pwfx,alloc_size);
-
 	nSamplesPerSec = device->pwfx->nSamplesPerSec;
 	bpp = device->pwfx->wBitsPerSample;
 	chans = device->pwfx->nChannels;
 
-        CopyMemory(device->pwfx, wfex, cp_size);
+	oldpwfx = device->pwfx;
+	device->pwfx = DSOUND_CopyFormat(wfex);
+	if (device->pwfx == NULL) {
+		device->pwfx = oldpwfx;
+		err = DSERR_OUTOFMEMORY;
+		goto done;
+	}
+	/* TODO: on failure below (bad format?), reinstall oldpwfx */
+	HeapFree(GetProcessHeap(), 0, oldpwfx);
 
 	if (!(device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) && device->hwbuf) {
 		err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx);
@@ -484,8 +513,10 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
 		/* On bad format, try to re-create, big chance it will work then, only do this if we <HAVE> to */
 		if (forced && (device->pwfx->nSamplesPerSec/100 != wfex->nSamplesPerSec/100 || err == DSERR_BADFORMAT))
 		{
+			DWORD cp_size = wfex->wFormatTag == WAVE_FORMAT_PCM ?
+				sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) + wfex->cbSize;
 			err = DSERR_BUFFERLOST;
-		        CopyMemory(device->pwfx, wfex, cp_size);
+			CopyMemory(device->pwfx, wfex, cp_size);
 		}
 
 		if (err != DSERR_BUFFERLOST && FAILED(err)) {




More information about the wine-cvs mailing list