dsound: Report buffer notifications in offset order.
This commit is contained in:
parent
5b7e49e84a
commit
ee126c96f1
|
@ -81,6 +81,27 @@ static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
|
|||
return ref;
|
||||
}
|
||||
|
||||
static int notify_compar(const void *l, const void *r)
|
||||
{
|
||||
const DSBPOSITIONNOTIFY *left = l;
|
||||
const DSBPOSITIONNOTIFY *right = r;
|
||||
|
||||
/* place DSBPN_OFFSETSTOP at the start of the sorted array */
|
||||
if(left->dwOffset == DSBPN_OFFSETSTOP){
|
||||
if(right->dwOffset != DSBPN_OFFSETSTOP)
|
||||
return -1;
|
||||
}else if(right->dwOffset == DSBPN_OFFSETSTOP)
|
||||
return 1;
|
||||
|
||||
if(left->dwOffset == right->dwOffset)
|
||||
return 0;
|
||||
|
||||
if(left->dwOffset < right->dwOffset)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
|
||||
DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
|
||||
{
|
||||
|
@ -113,6 +134,7 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSou
|
|||
}
|
||||
CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
|
||||
This->nrofnotifies = howmuch;
|
||||
qsort(This->notifies, howmuch, sizeof(DSBPOSITIONNOTIFY), notify_compar);
|
||||
} else {
|
||||
HeapFree(GetProcessHeap(), 0, This->notifies);
|
||||
This->notifies = NULL;
|
||||
|
|
|
@ -183,48 +183,67 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
|
|||
*/
|
||||
void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len)
|
||||
{
|
||||
int i;
|
||||
DWORD offset;
|
||||
LPDSBPOSITIONNOTIFY event;
|
||||
TRACE("(%p,%d)\n",dsb,len);
|
||||
int first, left, right, check;
|
||||
|
||||
if (dsb->nrofnotifies == 0)
|
||||
return;
|
||||
if(dsb->nrofnotifies == 0)
|
||||
return;
|
||||
|
||||
TRACE("(%p) buflen = %d, playpos = %d, len = %d\n",
|
||||
dsb, dsb->buflen, playpos, len);
|
||||
for (i = 0; i < dsb->nrofnotifies ; i++) {
|
||||
event = dsb->notifies + i;
|
||||
offset = event->dwOffset;
|
||||
TRACE("checking %d, position %d, event = %p\n",
|
||||
i, offset, event->hEventNotify);
|
||||
/* DSBPN_OFFSETSTOP has to be the last element. So this is */
|
||||
/* OK. [Inside DirectX, p274] */
|
||||
/* Windows does not seem to enforce this, and some apps rely */
|
||||
/* on that, so we can't stop there. */
|
||||
/* */
|
||||
/* This also means we can't sort the entries by offset, */
|
||||
/* because DSBPN_OFFSETSTOP == -1 */
|
||||
if (offset == DSBPN_OFFSETSTOP) {
|
||||
if (dsb->state == STATE_STOPPED) {
|
||||
SetEvent(event->hEventNotify);
|
||||
TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((playpos + len) >= dsb->buflen) {
|
||||
if ((offset < ((playpos + len) % dsb->buflen)) ||
|
||||
(offset >= playpos)) {
|
||||
TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
|
||||
SetEvent(event->hEventNotify);
|
||||
}
|
||||
} else {
|
||||
if ((offset >= playpos) && (offset < (playpos + len))) {
|
||||
TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
|
||||
SetEvent(event->hEventNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(dsb->state == STATE_STOPPED){
|
||||
TRACE("Stopped...\n");
|
||||
/* DSBPN_OFFSETSTOP notifies are always at the start of the sorted array */
|
||||
for(left = 0; left < dsb->nrofnotifies; ++left){
|
||||
if(dsb->notifies[left].dwOffset != DSBPN_OFFSETSTOP)
|
||||
break;
|
||||
|
||||
TRACE("Signalling %p\n", dsb->notifies[left].hEventNotify);
|
||||
SetEvent(dsb->notifies[left].hEventNotify);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(first = 0; first < dsb->nrofnotifies && dsb->notifies[first].dwOffset == DSBPN_OFFSETSTOP; ++first)
|
||||
;
|
||||
|
||||
if(first == dsb->nrofnotifies)
|
||||
return;
|
||||
|
||||
check = left = first;
|
||||
right = dsb->nrofnotifies - 1;
|
||||
|
||||
/* find leftmost notify that is greater than playpos */
|
||||
while(left != right){
|
||||
check = left + (right - left) / 2;
|
||||
if(dsb->notifies[check].dwOffset < playpos)
|
||||
left = check + 1;
|
||||
else if(dsb->notifies[check].dwOffset > playpos)
|
||||
right = check;
|
||||
else{
|
||||
left = check;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("Not stopped: first notify: %u (%u), range: [%u,%u)\n", first,
|
||||
dsb->notifies[check].dwOffset, playpos, (playpos + len) % dsb->buflen);
|
||||
|
||||
/* send notifications in range */
|
||||
for(check = left; check < dsb->nrofnotifies; ++check){
|
||||
if(dsb->notifies[check].dwOffset >= playpos + len)
|
||||
break;
|
||||
|
||||
TRACE("Signalling %p (%u)\n", dsb->notifies[check].hEventNotify, dsb->notifies[check].dwOffset);
|
||||
SetEvent(dsb->notifies[check].hEventNotify);
|
||||
}
|
||||
|
||||
if(playpos + len > dsb->buflen){
|
||||
for(check = first; check < left; ++check){
|
||||
if(dsb->notifies[check].dwOffset >= (playpos + len) % dsb->buflen)
|
||||
break;
|
||||
|
||||
TRACE("Signalling %p (%u)\n", dsb->notifies[check].hEventNotify, dsb->notifies[check].dwOffset);
|
||||
SetEvent(dsb->notifies[check].hEventNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline float get_current_sample(const IDirectSoundBufferImpl *dsb,
|
||||
|
|
|
@ -1486,6 +1486,89 @@ done:
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static void test_notifications(LPGUID lpGuid)
|
||||
{
|
||||
HRESULT rc;
|
||||
IDirectSound *dso;
|
||||
IDirectSoundBuffer *buf;
|
||||
IDirectSoundNotify *buf_notif;
|
||||
DSBUFFERDESC bufdesc;
|
||||
WAVEFORMATEX wfx;
|
||||
DSBPOSITIONNOTIFY notifies[2];
|
||||
HANDLE handles[2];
|
||||
DWORD expect;
|
||||
int cycles;
|
||||
|
||||
rc = pDirectSoundCreate(lpGuid, &dso, NULL);
|
||||
ok(rc == DS_OK || rc == DSERR_NODRIVER || rc == DSERR_ALLOCATED,
|
||||
"DirectSoundCreate() failed: %08x\n", rc);
|
||||
if(rc != DS_OK)
|
||||
return;
|
||||
|
||||
rc = IDirectSound_SetCooperativeLevel(dso, get_hwnd(), DSSCL_PRIORITY);
|
||||
ok(rc == DS_OK, "IDirectSound_SetCooperativeLevel() failed: %08x\n", rc);
|
||||
if(rc != DS_OK){
|
||||
IDirectSound_Release(dso);
|
||||
return;
|
||||
}
|
||||
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 1;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.wBitsPerSample = 16;
|
||||
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.cbSize = 0;
|
||||
|
||||
ZeroMemory(&bufdesc, sizeof(bufdesc));
|
||||
bufdesc.dwSize = sizeof(bufdesc);
|
||||
bufdesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY;
|
||||
bufdesc.dwBufferBytes = wfx.nSamplesPerSec * wfx.nBlockAlign / 2; /* 0.5s */
|
||||
bufdesc.lpwfxFormat = &wfx;
|
||||
rc = IDirectSound_CreateSoundBuffer(dso, &bufdesc, &buf, NULL);
|
||||
ok(rc == DS_OK && buf != NULL, "IDirectSound_CreateSoundBuffer() failed "
|
||||
"to create a buffer %08x\n", rc);
|
||||
|
||||
rc = IDirectSoundBuffer_QueryInterface(buf, &IID_IDirectSoundNotify, (void**)&buf_notif);
|
||||
ok(rc == DS_OK, "QueryInterface(IID_IDirectSoundNotify): %08x\n", rc);
|
||||
|
||||
/* create notifications at each end of the buffer */
|
||||
notifies[0].dwOffset = 0;
|
||||
handles[0] = notifies[0].hEventNotify = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
notifies[1].dwOffset = bufdesc.dwBufferBytes - 1;
|
||||
handles[1] = notifies[1].hEventNotify = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
rc = IDirectSoundNotify_SetNotificationPositions(buf_notif, 2, notifies);
|
||||
ok(rc == DS_OK, "SetNotificationPositions: %08x\n", rc);
|
||||
|
||||
IDirectSoundNotify_Release(buf_notif);
|
||||
|
||||
rc = IDirectSoundBuffer_Play(buf, 0, 0, DSBPLAY_LOOPING);
|
||||
ok(rc == DS_OK, "Play: %08x\n", rc);
|
||||
|
||||
expect = 0;
|
||||
for(cycles = 0; cycles < 6 /* 1.5s */; ++cycles){
|
||||
DWORD wait;
|
||||
|
||||
/* since the notifications are on opposite ends of the entire buffer,
|
||||
* they should arrive well-ordered in an alternating sequence. */
|
||||
wait = WaitForMultipleObjects(2, handles, FALSE, 1000);
|
||||
ok(wait <= WAIT_OBJECT_0 + 1 && wait - WAIT_OBJECT_0 == expect,
|
||||
"Got unexpected notification order or timeout: %u\n", wait);
|
||||
|
||||
expect = !expect;
|
||||
}
|
||||
|
||||
rc = IDirectSoundBuffer_Stop(buf);
|
||||
ok(rc == DS_OK, "Stop: %08x\n", rc);
|
||||
|
||||
CloseHandle(notifies[0].hEventNotify);
|
||||
CloseHandle(notifies[1].hEventNotify);
|
||||
|
||||
IDirectSoundBuffer_Release(buf);
|
||||
IDirectSound_Release(dso);
|
||||
}
|
||||
|
||||
static unsigned int number;
|
||||
|
||||
static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
|
||||
|
@ -1516,6 +1599,7 @@ static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
|
|||
test_frequency(lpGuid);
|
||||
test_duplicate(lpGuid);
|
||||
test_invalid_fmts(lpGuid);
|
||||
test_notifications(lpGuid);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
Loading…
Reference in New Issue