reactos/dll/directx/dsound_new/notify.c

256 lines
6.9 KiB
C

/*
* 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;
}