[DSOUND]
[reactos.git] / reactos / dll / directx / dsound_new / notify.c
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 (janderwald@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
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
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
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
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 return DSERR_GENERIC;
161 }
162 }
163 }
164
165 /* enlarge notify count */
166 Notify->NotifyCount = dwPositionNotifies;
167
168 if (This->EventListHead)
169 {
170 Notify->lpNext = This->EventListHead;
171 }
172
173 /* insert at front */
174 (void)InterlockedExchangePointer((LPVOID*)&This->EventListHead, Notify);
175
176 return DS_OK;
177 }
178
179 static IDirectSoundNotifyVtbl vt_DirectSoundNotify =
180 {
181 /* IUnknown methods */
182 IDirectSoundNotify_fnQueryInterface,
183 IDirectSoundNotify_fnAddRef,
184 IDirectSoundNotify_fnRelease,
185 /* IDirectSoundNotify */
186 IDirectSoundNotify_fnSetNotificationPositions
187 };
188
189
190 VOID
191 DoNotifyPositionEvents(
192 LPDIRECTSOUNDNOTIFY iface,
193 DWORD OldPosition,
194 DWORD NewPosition)
195 {
196 DWORD Index;
197 LPNOTIFYEVENT CurEventList;
198
199 LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);
200
201 CurEventList = This->EventListHead;
202
203 while(CurEventList)
204 {
205 for(Index = 0; Index < CurEventList->NotifyCount; Index++)
206 {
207 if (NewPosition > OldPosition)
208 {
209 /* buffer progress no overlap */
210 if (OldPosition < CurEventList->Notify[Index].Position && CurEventList->Notify[Index].Position <= NewPosition)
211 {
212 /* process event */
213 SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
214 }
215 }
216 else
217 {
218 /* buffer wrap-arround */
219 if (OldPosition < CurEventList->Notify[Index].Position || NewPosition > CurEventList->Notify[Index].Position)
220 {
221 /* process event */
222 SetEvent(CurEventList->Notify[Index].KsEventData.EventHandle.Event);
223 }
224 }
225 }
226
227 /* iterate to next event list */
228 CurEventList = CurEventList->lpNext;
229 }
230 }
231
232 HRESULT
233 NewDirectSoundNotify(
234 LPDIRECTSOUNDNOTIFY * Notify,
235 BOOL bLoop,
236 BOOL bMix,
237 HANDLE hPin,
238 DWORD BufferSize)
239 {
240 LPCDirectSoundNotifyImpl This = HeapAlloc(GetProcessHeap(), 0, sizeof(CDirectSoundNotifyImpl));
241
242 if (!This)
243 return DSERR_OUTOFMEMORY;
244
245 This->lpVtbl = &vt_DirectSoundNotify;
246 This->bLoop = bLoop;
247 This->bMix = bMix;
248 This->hPin = hPin;
249 This->ref = 1;
250 This->EventListHead = NULL;
251 This->BufferSize = BufferSize;
252
253 *Notify = (LPDIRECTSOUNDNOTIFY)&This->lpVtbl;
254 return DS_OK;
255
256 }