/* * 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 (johannes.anderwald@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); } } } /* 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; }