This region of the audio buffer is forbidden to be written to by the DirectSound specification. The documentation states: "The write cursor is the point after which it is safe to write data into the buffer. The block between the play cursor and the write cursor is already committed to be played, and cannot be changed safely." However, some applications still do this, which has lead to audio glitches only when using the Wine DirectSound implementation. Experiments showed that the native DirctSound implementation will still play the old audio the first time around when the buffer region gets overwritten. Use an approach of copying the next forbidden region into a "committed buffer" to add the same behavior to the Wine implementation.
Signed-off-by: Eduard Permyakov epermyakov@codeweavers.com --- dlls/dsound/buffer.c | 20 ++++++++++++++++++++ dlls/dsound/dsound_convert.c | 30 ++++++++++++++++++++---------- dlls/dsound/dsound_private.h | 5 ++++- dlls/dsound/mixer.c | 19 +++++++++++++++++++ 4 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c index dc3b54906ce..bbc7de805a8 100644 --- a/dlls/dsound/buffer.c +++ b/dlls/dsound/buffer.c @@ -1081,6 +1081,13 @@ HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *ds /* calculate fragment size and write lead */ DSOUND_RecalcFormat(dsb);
+ dsb->committedbuff = HeapAlloc(GetProcessHeap(), 0, dsb->writelead); + if(!dsb->committedbuff) { + IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface); + return DSERR_OUTOFMEMORY; + } + FillMemory(dsb->committedbuff, dsb->writelead, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0); + if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) { dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); dsb->ds3db_ds3db.vPosition.x = 0.0; @@ -1135,6 +1142,7 @@ void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
HeapFree(GetProcessHeap(), 0, This->notifies); HeapFree(GetProcessHeap(), 0, This->pwfx); + HeapFree(GetProcessHeap(), 0, This->committedbuff);
if (This->filters) { int i; @@ -1157,6 +1165,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate( { IDirectSoundBufferImpl *dsb; HRESULT hres = DS_OK; + VOID *committedbuff; TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb)); @@ -1166,6 +1175,14 @@ HRESULT IDirectSoundBufferImpl_Duplicate( return DSERR_OUTOFMEMORY; }
+ committedbuff = HeapAlloc(GetProcessHeap(),0,pdsb->writelead); + if (committedbuff == NULL) { + HeapFree(GetProcessHeap(),0,dsb); + *ppdsb = NULL; + return DSERR_OUTOFMEMORY; + } + FillMemory(committedbuff, pdsb->writelead, pdsb->pwfx->wBitsPerSample == 8 ? 128 : 0); + AcquireSRWLockShared(&pdsb->lock);
CopyMemory(dsb, pdsb, sizeof(*dsb)); @@ -1175,6 +1192,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate( ReleaseSRWLockShared(&pdsb->lock);
if (dsb->pwfx == NULL) { + HeapFree(GetProcessHeap(),0,committedbuff); HeapFree(GetProcessHeap(),0,dsb); *ppdsb = NULL; return DSERR_OUTOFMEMORY; @@ -1192,6 +1210,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate( dsb->notifies = NULL; dsb->nrofnotifies = 0; dsb->device = device; + dsb->committedbuff = committedbuff; DSOUND_RecalcFormat(dsb);
InitializeSRWLock(&dsb->lock); @@ -1202,6 +1221,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate( list_remove(&dsb->entry); dsb->buffer->ref--; HeapFree(GetProcessHeap(),0,dsb->pwfx); + HeapFree(GetProcessHeap(),0,dsb->committedbuff); HeapFree(GetProcessHeap(),0,dsb); dsb = NULL; }else diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index 4735178a9a8..fc2b0cd0797 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -55,17 +55,27 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound); #define le32(x) (x) #endif
+static BYTE *buff_byte(const IDirectSoundBufferImpl *dsb, DWORD offset) +{ + if(offset >= dsb->sec_mixpos && offset < dsb->sec_mixpos + dsb->writelead) { + return (BYTE*)dsb->committedbuff + (offset - dsb->sec_mixpos); + }else if(offset < (dsb->sec_mixpos + dsb->writelead) % dsb->buflen) { + return (BYTE*)dsb->committedbuff + (dsb->buflen - dsb->sec_mixpos + offset); + }else{ + return dsb->buffer->memory + offset; + } +} + static float get8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) { - const BYTE* buf = dsb->buffer->memory; - buf += pos + channel; + const BYTE *buf = buff_byte(dsb, pos + channel); return (buf[0] - 0x80) / (float)0x80; }
static float get16(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) { - const BYTE* buf = dsb->buffer->memory; - const SHORT *sbuf = (const SHORT*)(buf + pos + 2 * channel); + const BYTE *buf = buff_byte(dsb, pos + 2 * channel); + const SHORT *sbuf = (const SHORT*)(buf); SHORT sample = (SHORT)le16(*sbuf); return sample / (float)0x8000; } @@ -73,8 +83,8 @@ static float get16(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) static float get24(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) { LONG sample; - const BYTE* buf = dsb->buffer->memory; - buf += pos + 3 * channel; + const BYTE *buf = buff_byte(dsb, pos + 3 * channel); + /* The next expression deliberately has an overflow for buf[2] >= 0x80, this is how negative values are made. */ @@ -84,16 +94,16 @@ static float get24(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
static float get32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) { - const BYTE* buf = dsb->buffer->memory; - const LONG *sbuf = (const LONG*)(buf + pos + 4 * channel); + const BYTE *buf = buff_byte(dsb, pos + 4 * channel); + const LONG *sbuf = (const LONG*)(buf); LONG sample = le32(*sbuf); return sample / (float)0x80000000U; }
static float getieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) { - const BYTE* buf = dsb->buffer->memory; - const float *sbuf = (const float*)(buf + pos + 4 * channel); + const BYTE *buf = buff_byte(dsb, pos + 4 * channel); + const float *sbuf = (const float*)(buf); /* The value will be clipped later, when put into some non-float buffer */ return *sbuf; } diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index bdb9ebee544..a79d62c54da 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -153,7 +153,10 @@ struct IDirectSoundBufferImpl LONG64 freqAccNum; /* used for mixing */ DWORD sec_mixpos; - + /* Holds a copy of the next 'writelead' bytes, to be used for mixing. This makes it + * so that these bytes get played once even if this region of the buffer gets overwritten, + * which is more in-line with native DirectSound behavior. */ + LPVOID committedbuff; /* IDirectSoundNotify fields */ LPDSBPOSITIONNOTIFY notifies; int nrofnotifies; diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 124d1e4fba1..32656fbd618 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -391,6 +391,18 @@ static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, LONG64 *freqAccNu dsb->sec_mixpos = ipos; }
+static void copy_circular(VOID *dstbuff, VOID *srcbuff, DWORD srcoff, DWORD srcsize, DWORD cpysize) +{ + DWORD overflow; + if(cpysize > srcsize - srcoff) { + overflow = cpysize - (srcsize - srcoff); + memcpy(dstbuff, (BYTE*)srcbuff + srcoff, srcsize - srcoff); + memcpy((BYTE*)dstbuff + (srcsize - srcoff), srcbuff, overflow); + }else{ + memcpy(dstbuff, (BYTE*)srcbuff + srcoff, cpysize); + } +} + /** * Calculate the distance between two buffer offsets, taking wraparound * into account. @@ -518,6 +530,8 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, INT ilen = DSOUND_BufPtrDiff(dsb->buflen, dsb->sec_mixpos, oldpos); DSOUND_CheckEvent(dsb, oldpos, ilen); } + TRACE("committing %u bytes from offset %u\n", dsb->writelead, dsb->sec_mixpos); + copy_circular(dsb->committedbuff, dsb->buffer->memory, dsb->sec_mixpos, dsb->buflen, dsb->writelead);
return frames; } @@ -551,6 +565,11 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD } }
+ if(dsb->leadin) { + TRACE("committing %u bytes from offset %u\n", dsb->writelead, dsb->sec_mixpos); + copy_circular(dsb->committedbuff, dsb->buffer->memory, dsb->sec_mixpos, dsb->buflen, dsb->writelead); + } + dsb->leadin = FALSE;
TRACE("frames (primary) = %i\n", frames);
The test plays a WAV buffer using DirectSound and sets up a loopback capture to snoop on the actual rendered (sent to speakers) audio contents. This allows comparing the theoretically played audio (what is written to the DirectSound secondary buffer) and the actually played audio (what is sent to the speakers). This allows drawing some conclusions about the behavior of DirectSound, especially in the niche case of overwriting the mixing region in a playing buffer.
Signed-off-by: Eduard Permyakov epermyakov@codeweavers.com --- dlls/dsound/tests/dsound.c | 328 +++++++++++++++++++++++++++++++++++- dlls/dsound/tests/dsound8.c | 7 +- 2 files changed, 332 insertions(+), 3 deletions(-)
diff --git a/dlls/dsound/tests/dsound.c b/dlls/dsound/tests/dsound.c index a4f59efaad9..f8309a1c296 100644 --- a/dlls/dsound/tests/dsound.c +++ b/dlls/dsound/tests/dsound.c @@ -26,19 +26,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS #include <windows.h>
#include "wine/test.h" #include "mmsystem.h" -#define COBJMACROS #include "dsound.h" #include "dsconf.h" #include "initguid.h" #include "ks.h" #include "ksmedia.h" +#include "mmdeviceapi.h" +#include "audioclient.h"
#include "dsound_test.h"
+#define PADDING (65536) + DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, @@ -1618,6 +1622,327 @@ static void test_notifications(LPGUID lpGuid) IDirectSound_Release(dso); }
+/* Test what happens when we overwrite the current mixing position (between + * the play cursor and the write cursor). While this is invalid use of the API, + * some apps do this and we should handle it the same way Windows would. + * + * The main thing we want to check here is if we overwrite the "forbidden" region + * between the play cursor and write cursor, will the newly overwritten data be + * rendered (i.e. sent to speakers) instead of the old data? + */ +static void test_mix_position_overwrite(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso = NULL; + LPDIRECTSOUNDBUFFER primary = NULL, secondary = NULL; + LPDIRECTSOUNDNOTIFY notify = NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + DSBPOSITIONNOTIFY dsbpn[2]; + LPVOID ptr1 = NULL, ptr2 = NULL; + DWORD size1, size2, ret, status; + DWORD playpos, writepos, delta; + HANDLE event; + int i, ref; + static unsigned char wavbuff[705600] = {0}; + static unsigned char rendered[705600] = {0}; + IMMDeviceEnumerator *devenum; + IMMDevice *defdev; + IAudioClient *client = NULL; + IAudioCaptureClient *capture = NULL; + unsigned renderstats[256] = {0}; + DWORD cap_read = 0, cap_frames, cap_flags; + BYTE *cap_data; + UINT32 cap_packet_len; + + trace("testing overwriting mixing position in a buffer.\n"); + init_format(&wfx, WAVE_FORMAT_PCM, 44100, 16, 2); + memset(wavbuff, 0x77, sizeof(wavbuff)); + + /* Create the DirectSound object */ + rc = DirectSoundCreate(lpGuid, &dso, NULL); + ok(rc == DS_OK || rc == DSERR_NODRIVER || rc == DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n", rc); + if (rc != DS_OK) + return; + + /* Set cooperative level */ + rc = IDirectSound_SetCooperativeLevel(dso, get_hwnd(), DSSCL_EXCLUSIVE); + ok(rc == DS_OK, "IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + if (rc != DS_OK) + goto exit0; + + /* Create a loopback audio capture client to snoop on the rendered audio buffer */ + rc = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, + CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum); + ok(SUCCEEDED(rc), "Failed to get device enumerator: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit1; + + rc = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, + eMultimedia, &defdev); + ok(SUCCEEDED(rc), "Failed to get default audio endpoint: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit2; + + rc = IMMDevice_Activate(defdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&client); + ok(rc == S_OK || rc == AUDCLNT_E_DEVICE_IN_USE, "Failed to activate audio client: %08x\n", rc); + if(rc != S_OK) { + trace("Could not create loopback capture audio client. Skipping...\n"); + goto exit3; + } + + rc = IAudioClient_Initialize(client, + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 5*10000000, 0, &wfx, NULL); + ok(rc == S_OK || rc == AUDCLNT_E_UNSUPPORTED_FORMAT, "Failed to initialize audio client: %08x\n", rc); + if(rc != S_OK) { + trace("Could not create loopback capture audio client. Skipping...\n"); + goto exit4; + } + + rc = IAudioClient_GetService(client, &IID_IAudioCaptureClient, (void**)&capture); + ok(rc == S_OK || rc == AUDCLNT_E_WRONG_ENDPOINT_TYPE, "Failed to get audio client service: %08x\n", rc); + if(rc != S_OK) { + trace("Could not create loopback capture audio client. Skipping...\n"); + goto exit4; + } + + rc = IAudioClient_Start(client); /* start recording */ + ok(SUCCEEDED(rc), "Failed to start audio capture client: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit5; + + /* Create the primary buffer */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize = sizeof(bufdesc); + bufdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + bufdesc.dwBufferBytes = 0; + bufdesc.dwReserved = 0; + bufdesc.lpwfxFormat = NULL; + bufdesc.guid3DAlgorithm = GUID_NULL; + + rc = IDirectSound_CreateSoundBuffer(dso, &bufdesc, &primary, NULL); + ok(rc == DS_OK && primary != NULL, + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n", rc); + if(rc != DS_OK || primary == NULL) + goto exit5; + + /* Set the primary buffer format */ + rc = IDirectSoundBuffer_SetFormat(primary, &wfx); + ok(rc == DS_OK, "IDirectSoundBuffer_SetFormat() failed: %08x\n", rc); + if (rc != DS_OK) + goto exit6; + + /* Set the secondary buffer description and format */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize = sizeof(bufdesc); + bufdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME + | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes = sizeof(wavbuff); + bufdesc.dwReserved = 0; + bufdesc.lpwfxFormat = &wfx; + bufdesc.guid3DAlgorithm = GUID_NULL; + + rc = IDirectSound_CreateSoundBuffer(dso, &bufdesc, &secondary, NULL); + ok((rc == DS_OK && secondary != NULL) || broken(rc == DSERR_CONTROLUNAVAIL), /* vmware drivers on w2k */ + "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n", rc); + if(rc != DS_OK) + goto exit6; + + rc = IDirectSoundBuffer_SetPan(secondary, 0); + ok(rc == DS_OK, "IDirectSoundBuffer_SetPan failed: %08x\n", rc); + if(rc != DS_OK) + goto exit7; + + /* Copy WAV contents to buffer */ + rc = IDirectSoundBuffer_Lock(secondary, 0, sizeof(wavbuff), &ptr1, &size1, &ptr2, &size2, 0); + ok(rc == DS_OK && ptr1 != NULL, + "IDirectSoundBuffer_Lock failed to lock the buffer %08x\n", rc); + ok(size1 == sizeof(wavbuff), "Could not lock entire buffer\n"); + ok(ptr2 == NULL && size2 == 0, "Unexpectedly got a second buffer segment\n"); + if(rc != DS_OK) + goto exit7; + + trace("copying %u bytes from %p to %p\n", size1, ptr1, wavbuff); + memcpy(ptr1, wavbuff, size1); + rc = IDirectSoundBuffer_Unlock(secondary, ptr1, size1, ptr2, size2); + ok(rc == DS_OK, "IDirectSoundBuffer_Unlock failed to unlock buffer: %08x\n", rc); + if(rc != DS_OK) + goto exit7; + + /* Set up a notification position */ + rc = IDirectSoundBuffer_QueryInterface(secondary, &IID_IDirectSoundNotify, (void**)¬ify); + ok(rc == DS_OK && notify != NULL, + "IDirectSoundBuffer_QueryInterface() failed to create a notification %08x\n", rc); + + event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEventW failed: %08x\n", GetLastError()); + if(event == NULL) + goto exit7; + + dsbpn[0].dwOffset = 235199; + dsbpn[0].hEventNotify = event; + dsbpn[1].dwOffset = 470399; + dsbpn[1].hEventNotify = event; + rc = IDirectSoundNotify_SetNotificationPositions(notify, 2,dsbpn); + ok(rc == DS_OK,"IDirectSoundNotify_SetNotificationPositions failed: %08x\n", rc); + if(rc != DS_OK) + goto exit8; + + /* Play the buffer and wait on the notification */ + rc = IDirectSoundBuffer_Play(secondary, 0, 0, DSBPLAY_LOOPING); + ok(rc == DS_OK,"IDirectSoundBuffer_Play failed: %08x\n", rc); + if(rc != DS_OK) + goto exit8; + + rc = IDirectSoundBuffer_GetStatus(secondary, &status); + ok(rc == DS_OK,"IDirectSoundBuffer_GetStatus failed: %08x\n", rc); + ok(status == (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING), "Unexpected buffer status: %08x\n", status); + + ret = WaitForMultipleObjects(1, &event, FALSE, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForMultipleObjects unexpected return value: %08x\n", ret); + if(ret != WAIT_OBJECT_0) + goto exit9; + + /* Get the buffer play and write cursors. Attempt to overwrite the area between the play and + * write cursor. This is the stuff that the API docs tell you to never, ever do. + */ + rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &playpos, &writepos); + ok(rc == DS_OK, "IDirectSoundBuffer_GetCurrentPosition error: %08x\n", rc); + if(rc != DS_OK) + goto exit9; + + delta = writepos - playpos; + ok(writepos >= playpos, "Unexpected writepos (%u) and playpos (%u)\n", writepos, playpos); + trace("playpos = %u, writepos = %u, delta = %u\n", playpos, writepos, delta); + + rc = IDirectSoundBuffer_Lock(secondary, playpos, delta + PADDING, &ptr1, &size1, &ptr2, &size2, 0); + ok(rc == DS_OK && ptr1 != NULL, + "IDirectSoundBuffer_Lock failed to lock the buffer %08x\n", rc); + ok(size1 == (delta + PADDING), "Could not lock specified region (%u bytes)\n", delta + PADDING); + if(rc != DS_OK) + goto exit9; + + memset(ptr1, 0xaa, delta + PADDING); + + rc = IDirectSoundBuffer_Unlock(secondary, ptr1, size1, ptr2, size2); + ok(rc == DS_OK, "IDirectSoundBuffer_Unlock failed to unlock buffer: %08x\n", rc); + if(rc != DS_OK) + goto exit9; + + /* Make sure we've played the overwritten segment */ + ret = WaitForMultipleObjects(1, &event, FALSE, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForMultipleObjects unexpected return value: %08x\n", ret); + if(ret != WAIT_OBJECT_0) + goto exit9; + + /* Now try to read back the data - did we actually overwrite it? */ + rc = IDirectSoundBuffer_Lock(secondary, playpos, delta + PADDING, &ptr1, &size1, &ptr2, &size2, 0); + ok(rc == DS_OK && ptr1 != NULL, + "IDirectSoundBuffer_Lock failed to lock the buffer %08x\n", rc); + ok(size1 == (delta + PADDING), "Could not lock specified region (%u bytes)\n", delta + PADDING); + if(rc != DS_OK) + goto exit9; + + for(i = 0; i < delta + PADDING; i++) { + ok(*(((unsigned char*)ptr1) + i) == 0xaa, + "Unexpected buffer contents at offset: %u\n", playpos + i); + } + + rc = IDirectSoundBuffer_Unlock(secondary, ptr1, size1, ptr2, size2); + ok(rc == DS_OK, "IDirectSoundBuffer_Unlock failed to unlock buffer: %08x\n", rc); + if(rc != DS_OK) + goto exit9; + + /* Now check the data in the capture buffer - were the overwritten buffer contents actually rendered? */ + rc = IAudioCaptureClient_GetNextPacketSize(capture, &cap_packet_len); + ok(SUCCEEDED(rc), "IAudioCaptureClient_GetNextPacketSize failed: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit9; + + while(cap_read < sizeof(rendered) && cap_packet_len > 0) { + + DWORD cap_bytes, copysz; + rc = IAudioCaptureClient_GetBuffer(capture, &cap_data, &cap_frames, &cap_flags, NULL, NULL); + ok(SUCCEEDED(rc), "IAudioCaptureClient_GetBuffer failed: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit9; + + cap_bytes = cap_frames * wfx.nBlockAlign; + copysz = (cap_read + cap_bytes > sizeof(rendered)) ? (sizeof(rendered) - cap_read) : cap_bytes; + memcpy(rendered + cap_read, cap_data, copysz); + cap_read += copysz; + + rc = IAudioCaptureClient_ReleaseBuffer(capture, cap_frames); + ok(SUCCEEDED(rc), "IAudioCaptureClient_ReleaseBuffer failed: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit9; + + rc = IAudioCaptureClient_GetNextPacketSize(capture, &cap_packet_len); + ok(SUCCEEDED(rc), "IAudioCaptureClient_GetNextPacketSize failed: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit9; + } + trace("captured %u bytes of sound data [%u samples]\n", cap_read, cap_read / wfx.nBlockAlign); + + for(i = 0; i < cap_read; i++) { + renderstats[rendered[i]]++; + } + trace("rendered audio statistics:\n"); + for(i = 0; i < 256; i++) { + if(renderstats[i] == 0) + continue; + trace(" 0x%02x: %u\n", i, renderstats[i]); + } + + for(i = 1; i < cap_read; i++) { + BYTE curr = rendered[i], prev = rendered[i - 1]; + if((curr >> 4) == 0x7 && (prev >> 4) == 0x0) + trace(" -> change from 0x00 to 0x77 at offset: %u\n", i); + if((curr >> 4) == 0x0 && (prev >> 4) == 0x7) + trace(" -> change from 0x77 to 0x00 at offset: %u\n", i); + + if((curr >> 4) == 0x7 && (prev >> 4) == 0xa) + trace(" -> change from 0xaa to 0x77 at offset: %u\n", i); + if((curr >> 4) == 0xa && (prev >> 4) == 0x7) + trace(" -> change from 0x77 to 0xaa at offset: %u\n", i); + } + + rc = IAudioClient_Stop(client); + ok(SUCCEEDED(rc), "Failed to stop audio capture client: %08x\n", rc); + if(!SUCCEEDED(rc)) + goto exit9; + +exit9: + rc = IDirectSoundBuffer_Stop(secondary); + ok(rc==DS_OK,"IDirectSoundBuffer_Stop failed %08x\n", rc); +exit8: + CloseHandle(event); +exit7: + ref = IDirectSoundBuffer_Release(secondary); + ok(ref == 0,"IDirectSoundBuffer_Release() secondary has %d references, " + "should have 0\n", ref); +exit6: + ref = IDirectSoundBuffer_Release(primary); + ok(ref == 0, "IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n", ref); +exit5: + IAudioCaptureClient_Release(capture); +exit4: + IAudioClient_Release(client); +exit3: + IMMDevice_Release(defdev); +exit2: + IMMDeviceEnumerator_Release(devenum); +exit1: + /* Set the CooperativeLevel back to normal */ + rc = IDirectSound_SetCooperativeLevel(dso, get_hwnd(), DSSCL_NORMAL); + ok(rc == DS_OK, "IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); +exit0: + ref = IDirectSound_Release(dso); + ok(ref == 0,"IDirectSound_Release() has %d references, should have 0\n", ref); +} + static unsigned int number;
static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, @@ -1649,6 +1974,7 @@ static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, test_duplicate(lpGuid); test_invalid_fmts(lpGuid); test_notifications(lpGuid); + test_mix_position_overwrite(lpGuid); }
return TRUE; diff --git a/dlls/dsound/tests/dsound8.c b/dlls/dsound/tests/dsound8.c index e3adbfbe70e..6f4f1ca0cde 100644 --- a/dlls/dsound/tests/dsound8.c +++ b/dlls/dsound/tests/dsound8.c @@ -42,11 +42,14 @@
#include "uuids.h" #include "wingdi.h" -#include "mmdeviceapi.h" -#include "audioclient.h" #include "propkey.h" #include "devpkey.h"
+#undef INITGUID +#include <guiddef.h> +#include "mmdeviceapi.h" +#include "audioclient.h" + #include "dsound_test.h"
static const GUID testdmo_clsid = {0x1234};
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=95945
Your paranoid android.
=== w8 (32 bit report) ===
dsound: dsound.c:1064: Test failed: got 00000000