+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Configuration of network devices
+ * FILE: dll/directx/dsound_new/notify.c
+ * PURPOSE: IDirectSoundNotify implementation
+ *
+ * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
+ */
+
+
+#include "precomp.h"
+
+typedef struct tagNOTIFYEVENT
+{
+ DWORD NotifyCount;
+ PLOOPEDSTREAMING_POSITION_EVENT_DATA Notify;
+ struct tagNOTIFYEVENT *lpNext;
+}NOTIFYEVENT, *LPNOTIFYEVENT;
+
+typedef struct
+{
+ IDirectSoundNotifyVtbl * lpVtbl;
+ LONG ref;
+
+ LPNOTIFYEVENT EventListHead;
+ BOOL bLoop;
+ BOOL bMix;
+ HANDLE hPin;
+ DWORD BufferSize;
+
+}CDirectSoundNotifyImpl, *LPCDirectSoundNotifyImpl;
+
+static
+ULONG
+WINAPI
+IDirectSoundNotify_fnAddRef(
+ LPDIRECTSOUNDNOTIFY iface)
+{
+ ULONG ref;
+ LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
+
+ /* increment reference count */
+ ref = InterlockedIncrement(&This->ref);
+
+ return ref;
+}
+
+static
+ULONG
+WINAPI
+IDirectSoundNotify_fnRelease(
+ LPDIRECTSOUNDNOTIFY iface)
+{
+ ULONG ref;
+ LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
+
+ ref = InterlockedDecrement(&(This->ref));
+
+ if (!ref)
+ {
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+HRESULT
+WINAPI
+IDirectSoundNotify_fnQueryInterface(
+ LPDIRECTSOUNDNOTIFY iface,
+ IN REFIID riid,
+ LPVOID* ppobj)
+{
+ LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
+
+ /* check if the interface is supported */
+ if (IsEqualIID(riid, &IID_IDirectSoundNotify) || IsEqualIID(riid, &IID_IUnknown))
+ {
+ *ppobj = (LPVOID)&This->lpVtbl;
+ InterlockedIncrement(&This->ref);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+HRESULT
+WINAPI
+IDirectSoundNotify_fnSetNotificationPositions(
+ LPDIRECTSOUNDNOTIFY iface,
+ DWORD dwPositionNotifies,
+ LPCDSBPOSITIONNOTIFY pcPositionNotifies)
+{
+ DWORD Index;
+ LPNOTIFYEVENT Notify;
+ DWORD Result;
+ KSEVENT Request;
+
+ LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
+
+ if (dwPositionNotifies > DSBNOTIFICATIONS_MAX)
+ {
+ /* invalid param */
+ return DSERR_INVALIDPARAM;
+ }
+
+ /* verify notification event handles */
+ for(Index = 0; Index < dwPositionNotifies; Index++)
+ {
+ ASSERT(pcPositionNotifies[Index].hEventNotify);
+ ASSERT(pcPositionNotifies[Index].dwOffset < This->BufferSize || pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP);
+
+ if (pcPositionNotifies[Index].hEventNotify == NULL)
+ return DSERR_INVALIDPARAM;
+
+ if (pcPositionNotifies[Index].dwOffset > This->BufferSize && pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP)
+ return DSERR_INVALIDPARAM;
+ }
+
+ /* allocate new array */
+ Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFYEVENT));
+ if (!Notify)
+ {
+ /* not enough memory */
+ return DSERR_OUTOFMEMORY;
+ }
+
+ /* allocate new array */
+ Notify->Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwPositionNotifies * sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA));
+ if (!Notify->Notify)
+ {
+ /* not enough memory */
+ HeapFree(GetProcessHeap(), 0, Notify);
+ return DSERR_OUTOFMEMORY;
+ }
+
+ /* FIXME support non-looped streaming */
+ ASSERT(This->bLoop);
+
+ /* prepare request */
+ Request.Set = KSEVENTSETID_LoopedStreaming;
+ Request.Id = KSEVENT_LOOPEDSTREAMING_POSITION;
+ Request.Flags = KSEVENT_TYPE_ENABLE;
+
+ for(Index = 0; Index < dwPositionNotifies; Index++)
+ {
+ /* initialize event entries */
+ Notify->Notify[Index].Position = pcPositionNotifies[Index].dwOffset;
+ Notify->Notify[Index].KsEventData.EventHandle.Event = pcPositionNotifies[Index].hEventNotify;
+ Notify->Notify[Index].KsEventData.NotificationType = KSEVENTF_EVENT_HANDLE;
+
+ if (This->bMix == FALSE)
+ {
+ /* format is supported natively */
+ Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Request, sizeof(KSEVENT), (PVOID)&Notify->Notify[Index], sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA), NULL);
+
+ if (Result != ERROR_SUCCESS)
+ {
+ DPRINT1("Failed to enable event %p Position %u\n", pcPositionNotifies[Index].hEventNotify, pcPositionNotifies[Index].dwOffset);
+ return DSERR_GENERIC;
+ }
+ }
+ }
+
+ /* enlarge notify count */
+ Notify->NotifyCount = dwPositionNotifies;
+
+ if (This->EventListHead)
+ {
+ Notify->lpNext = This->EventListHead;
+ }
+
+ /* insert at front */
+ (void)InterlockedExchangePointer((LPVOID*)&This->EventListHead, Notify);
+
+ return DS_OK;
+}
+
+static IDirectSoundNotifyVtbl vt_DirectSoundNotify =
+{
+ /* IUnknown methods */
+ IDirectSoundNotify_fnQueryInterface,
+ IDirectSoundNotify_fnAddRef,
+ IDirectSoundNotify_fnRelease,
+ /* IDirectSoundNotify */
+ IDirectSoundNotify_fnSetNotificationPositions
+};
+
+
+VOID
+DoNotifyPositionEvents(
+ LPDIRECTSOUNDNOTIFY iface,
+ DWORD OldPosition,
+ DWORD NewPosition)
+{
+ DWORD Index;
+ LPNOTIFYEVENT CurEventList;
+
+ LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
+
+ CurEventList = This->EventListHead;
+
+ while(CurEventList)
+ {
+ for(Index = 0; Index < CurEventList->NotifyCount; Index++)
+ {
+ if (NewPosition > OldPosition)
+ {
+ /* buffer progress no overlap */
+ if (OldPosition < CurEventList->Notify[Index].Position && CurEventList->Notify[Index].Position <= NewPosition)
+ {
+ /* process event */
+ SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
+ }
+ }
+ else
+ {
+ /* buffer wrap-arround */
+ if (OldPosition < CurEventList->Notify[Index].Position || NewPosition > CurEventList->Notify[Index].Position)
+ {
+ /* process event */
+ SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
+ }
+ }
+ }
+
+ /* iterate to next event list */
+ CurEventList = CurEventList->lpNext;
+ }
+}
+
+HRESULT
+NewDirectSoundNotify(
+ LPDIRECTSOUNDNOTIFY * Notify,
+ BOOL bLoop,
+ BOOL bMix,
+ HANDLE hPin,
+ DWORD BufferSize)
+{
+ LPCDirectSoundNotifyImpl This = HeapAlloc(GetProcessHeap(), 0, sizeof(CDirectSoundNotifyImpl));
+
+ if (!This)
+ return DSERR_OUTOFMEMORY;
+
+ This->lpVtbl = &vt_DirectSoundNotify;
+ This->bLoop = bLoop;
+ This->bMix = bMix;
+ This->hPin = hPin;
+ This->ref = 1;
+ This->EventListHead = NULL;
+ This->BufferSize = BufferSize;
+
+ *Notify = (LPDIRECTSOUNDNOTIFY)&This->lpVtbl;
+ return DS_OK;
+
+}