xref: /reactos/dll/directx/dsound_new/notify.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Configuration of network devices
4  * FILE:            dll/directx/dsound_new/notify.c
5  * PURPOSE:         IDirectSoundNotify implementation
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 
11 #include "precomp.h"
12 
13 typedef struct tagNOTIFYEVENT
14 {
15     DWORD NotifyCount;
16     PLOOPEDSTREAMING_POSITION_EVENT_DATA Notify;
17     struct tagNOTIFYEVENT *lpNext;
18 }NOTIFYEVENT, *LPNOTIFYEVENT;
19 
20 typedef struct
21 {
22     IDirectSoundNotifyVtbl * lpVtbl;
23     LONG ref;
24 
25     LPNOTIFYEVENT EventListHead;
26     BOOL bLoop;
27     BOOL bMix;
28     HANDLE hPin;
29     DWORD BufferSize;
30 
31 }CDirectSoundNotifyImpl, *LPCDirectSoundNotifyImpl;
32 
33 static
34 ULONG
35 WINAPI
IDirectSoundNotify_fnAddRef(LPDIRECTSOUNDNOTIFY iface)36 IDirectSoundNotify_fnAddRef(
37     LPDIRECTSOUNDNOTIFY iface)
38 {
39     ULONG ref;
40     LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
41 
42     /* increment reference count */
43     ref = InterlockedIncrement(&This->ref);
44 
45     return ref;
46 }
47 
48 static
49 ULONG
50 WINAPI
IDirectSoundNotify_fnRelease(LPDIRECTSOUNDNOTIFY iface)51 IDirectSoundNotify_fnRelease(
52     LPDIRECTSOUNDNOTIFY iface)
53 {
54     ULONG ref;
55     LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
56 
57     ref = InterlockedDecrement(&(This->ref));
58 
59     if (!ref)
60     {
61         HeapFree(GetProcessHeap(), 0, This);
62     }
63 
64     return ref;
65 }
66 
67 HRESULT
68 WINAPI
IDirectSoundNotify_fnQueryInterface(LPDIRECTSOUNDNOTIFY iface,IN REFIID riid,LPVOID * ppobj)69 IDirectSoundNotify_fnQueryInterface(
70     LPDIRECTSOUNDNOTIFY iface,
71     IN REFIID riid,
72     LPVOID* ppobj)
73 {
74     LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
75 
76     /* check if the interface is supported */
77     if (IsEqualIID(riid, &IID_IDirectSoundNotify) || IsEqualIID(riid, &IID_IUnknown))
78     {
79         *ppobj = (LPVOID)&This->lpVtbl;
80         InterlockedIncrement(&This->ref);
81         return S_OK;
82     }
83 
84     return E_NOINTERFACE;
85 }
86 
87 HRESULT
88 WINAPI
IDirectSoundNotify_fnSetNotificationPositions(LPDIRECTSOUNDNOTIFY iface,DWORD dwPositionNotifies,LPCDSBPOSITIONNOTIFY pcPositionNotifies)89 IDirectSoundNotify_fnSetNotificationPositions(
90     LPDIRECTSOUNDNOTIFY iface,
91     DWORD dwPositionNotifies,
92     LPCDSBPOSITIONNOTIFY pcPositionNotifies)
93 {
94     DWORD Index;
95     LPNOTIFYEVENT Notify;
96     DWORD Result;
97     KSEVENT Request;
98 
99     LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
100 
101     if (dwPositionNotifies > DSBNOTIFICATIONS_MAX)
102     {
103         /* invalid param */
104         return DSERR_INVALIDPARAM;
105     }
106 
107     /* verify notification event handles */
108     for(Index = 0; Index < dwPositionNotifies; Index++)
109     {
110         ASSERT(pcPositionNotifies[Index].hEventNotify);
111         ASSERT(pcPositionNotifies[Index].dwOffset < This->BufferSize || pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP);
112 
113         if (pcPositionNotifies[Index].hEventNotify == NULL)
114             return DSERR_INVALIDPARAM;
115 
116         if (pcPositionNotifies[Index].dwOffset > This->BufferSize && pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP)
117             return DSERR_INVALIDPARAM;
118     }
119 
120     /* allocate new array */
121     Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFYEVENT));
122     if (!Notify)
123     {
124         /* not enough memory */
125         return DSERR_OUTOFMEMORY;
126     }
127 
128     /* allocate new array */
129     Notify->Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwPositionNotifies * sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA));
130     if (!Notify->Notify)
131     {
132         /* not enough memory */
133         HeapFree(GetProcessHeap(), 0, Notify);
134         return DSERR_OUTOFMEMORY;
135     }
136 
137     /* FIXME support non-looped streaming */
138     ASSERT(This->bLoop);
139 
140     /* prepare request */
141     Request.Set = KSEVENTSETID_LoopedStreaming;
142     Request.Id = KSEVENT_LOOPEDSTREAMING_POSITION;
143     Request.Flags = KSEVENT_TYPE_ENABLE;
144 
145     for(Index = 0; Index < dwPositionNotifies; Index++)
146     {
147         /* initialize event entries */
148         Notify->Notify[Index].Position = pcPositionNotifies[Index].dwOffset;
149         Notify->Notify[Index].KsEventData.EventHandle.Event = pcPositionNotifies[Index].hEventNotify;
150         Notify->Notify[Index].KsEventData.NotificationType = KSEVENTF_EVENT_HANDLE;
151 
152         if (This->bMix == FALSE)
153         {
154             /* format is supported natively */
155             Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Request, sizeof(KSEVENT), (PVOID)&Notify->Notify[Index], sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA), NULL);
156 
157             if (Result != ERROR_SUCCESS)
158             {
159                 DPRINT1("Failed to enable event %p Position %u\n", pcPositionNotifies[Index].hEventNotify, pcPositionNotifies[Index].dwOffset);
160             }
161         }
162     }
163 
164     /* enlarge notify count */
165     Notify->NotifyCount = dwPositionNotifies;
166 
167     if (This->EventListHead)
168     {
169         Notify->lpNext = This->EventListHead;
170     }
171 
172     /* insert at front */
173     (void)InterlockedExchangePointer((LPVOID*)&This->EventListHead, Notify);
174 
175     return DS_OK;
176 }
177 
178 static IDirectSoundNotifyVtbl vt_DirectSoundNotify =
179 {
180     /* IUnknown methods */
181     IDirectSoundNotify_fnQueryInterface,
182     IDirectSoundNotify_fnAddRef,
183     IDirectSoundNotify_fnRelease,
184     /* IDirectSoundNotify */
185     IDirectSoundNotify_fnSetNotificationPositions
186 };
187 
188 
189 VOID
DoNotifyPositionEvents(LPDIRECTSOUNDNOTIFY iface,DWORD OldPosition,DWORD NewPosition)190 DoNotifyPositionEvents(
191     LPDIRECTSOUNDNOTIFY iface,
192     DWORD OldPosition,
193     DWORD NewPosition)
194 {
195     DWORD Index;
196     LPNOTIFYEVENT CurEventList;
197 
198     LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
199 
200     CurEventList = This->EventListHead;
201 
202     while(CurEventList)
203     {
204         for(Index = 0; Index < CurEventList->NotifyCount; Index++)
205         {
206             if (NewPosition > OldPosition)
207             {
208                 /* buffer progress no overlap */
209                 if (OldPosition < CurEventList->Notify[Index].Position && CurEventList->Notify[Index].Position <= NewPosition)
210                 {
211                     /* process event */
212                     SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
213                 }
214             }
215             else
216             {
217                 /* buffer wrap-arround */
218                 if (OldPosition < CurEventList->Notify[Index].Position || NewPosition > CurEventList->Notify[Index].Position)
219                 {
220                     /* process event */
221                     SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
222                 }
223             }
224         }
225 
226         /* iterate to next event list */
227         CurEventList = CurEventList->lpNext;
228     }
229 }
230 
231 HRESULT
NewDirectSoundNotify(LPDIRECTSOUNDNOTIFY * Notify,BOOL bLoop,BOOL bMix,HANDLE hPin,DWORD BufferSize)232 NewDirectSoundNotify(
233     LPDIRECTSOUNDNOTIFY * Notify,
234     BOOL bLoop,
235     BOOL bMix,
236     HANDLE hPin,
237     DWORD BufferSize)
238 {
239     LPCDirectSoundNotifyImpl This = HeapAlloc(GetProcessHeap(), 0, sizeof(CDirectSoundNotifyImpl));
240 
241     if (!This)
242         return DSERR_OUTOFMEMORY;
243 
244     This->lpVtbl = &vt_DirectSoundNotify;
245     This->bLoop = bLoop;
246     This->bMix = bMix;
247     This->hPin = hPin;
248     This->ref = 1;
249     This->EventListHead = NULL;
250     This->BufferSize = BufferSize;
251 
252     *Notify = (LPDIRECTSOUNDNOTIFY)&This->lpVtbl;
253     return DS_OK;
254 
255 }
256