acb86fd518f867472a5061f4a6065f185e668b03
[reactos.git] / reactos / dll / directx / dsound_new / directsound.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Configuration of network devices
4 * FILE: dll/directx/dsound_new/directsound.c
5 * PURPOSE: Handles IDirectSound interface
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9
10 #include "precomp.h"
11
12 typedef struct
13 {
14 IDirectSound8Vtbl *lpVtbl;
15 LONG ref;
16 GUID DeviceGUID;
17 BOOL bInitialized;
18 DWORD dwLevel;
19 LPFILTERINFO Filter;
20 LPDIRECTSOUNDBUFFER8 PrimaryBuffer;
21
22
23 }CDirectSoundImpl, *LPCDirectSoundImpl;
24
25 HRESULT
26 WINAPI
27 IDirectSound8_fnQueryInterface(
28 LPDIRECTSOUND8 iface,
29 REFIID riid,
30 LPVOID * ppobj)
31 {
32 LPOLESTR pStr;
33 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
34
35
36 if (IsEqualIID(riid, &IID_IUnknown) ||
37 IsEqualIID(riid, &IID_IDirectSound) ||
38 IsEqualIID(riid, &IID_IDirectSound8))
39 {
40 *ppobj = (LPVOID)&This->lpVtbl;
41 InterlockedIncrement(&This->ref);
42 return S_OK;
43 }
44
45 if (SUCCEEDED(StringFromIID(riid, &pStr)))
46 {
47 DPRINT("No Interface for class %s\n", pStr);
48 CoTaskMemFree(pStr);
49 }
50 return E_NOINTERFACE;
51 }
52
53 ULONG
54 WINAPI
55 IDirectSound8_fnAddRef(
56 LPDIRECTSOUND8 iface)
57 {
58 ULONG ref;
59 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
60
61 ref = InterlockedIncrement(&This->ref);
62
63 return ref;
64 }
65
66 ULONG
67 WINAPI
68 IDirectSound8_fnRelease(
69 LPDIRECTSOUND8 iface)
70 {
71 ULONG ref;
72 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
73
74 ref = InterlockedDecrement(&(This->ref));
75
76 if (!ref)
77 {
78 HeapFree(GetProcessHeap(), 0, This);
79 }
80
81 return ref;
82 }
83
84 HRESULT
85 WINAPI
86 IDirectSound8_fnCreateSoundBuffer(
87 LPDIRECTSOUND8 iface,
88 LPCDSBUFFERDESC lpcDSBufferDesc,
89 LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer,
90 IUnknown FAR* pUnkOuter)
91 {
92 HRESULT hResult;
93 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
94
95 if (!This->bInitialized)
96 {
97 /* object not yet initialized */
98 return DSERR_UNINITIALIZED;
99 }
100
101 if (!lpcDSBufferDesc || !lplpDirectSoundBuffer || pUnkOuter != NULL)
102 {
103 DPRINT("Invalid parameter %p %p %p\n", lpcDSBufferDesc, lplpDirectSoundBuffer, pUnkOuter);
104 return DSERR_INVALIDPARAM;
105 }
106
107 /* check buffer description */
108 if ((lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC) && lpcDSBufferDesc->dwSize != sizeof(DSBUFFERDESC1)) || lpcDSBufferDesc->dwReserved != 0)
109 {
110 DPRINT("Invalid buffer description size %u expected %u dwReserved %u\n", lpcDSBufferDesc->dwSize, sizeof(DSBUFFERDESC1), lpcDSBufferDesc->dwReserved);
111 return DSERR_INVALIDPARAM;
112 }
113
114 DPRINT("This %p dwFlags %x dwBufferBytes %u lpwfxFormat %p dwSize %u\n", This, lpcDSBufferDesc->dwFlags, lpcDSBufferDesc->dwBufferBytes, lpcDSBufferDesc->lpwfxFormat, lpcDSBufferDesc->dwSize);
115
116 if (lpcDSBufferDesc->dwFlags & DSBCAPS_PRIMARYBUFFER)
117 {
118 if (lpcDSBufferDesc->lpwfxFormat != NULL)
119 {
120 /* format must be null for primary sound buffer */
121 return DSERR_INVALIDPARAM;
122 }
123
124 if (This->PrimaryBuffer)
125 {
126 /* primary buffer already exists */
127 IDirectSoundBuffer8_AddRef(This->PrimaryBuffer);
128 *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)This->PrimaryBuffer;
129 return S_OK;
130 }
131
132 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel);
133 if (SUCCEEDED(hResult))
134 {
135 /* store primary buffer */
136 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
137 }
138 return hResult;
139 }
140 else
141 {
142 if (lpcDSBufferDesc->lpwfxFormat == NULL)
143 {
144 /* format must not be null */
145 return DSERR_INVALIDPARAM;
146 }
147
148 if (!This->PrimaryBuffer)
149 {
150 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel);
151 if (SUCCEEDED(hResult))
152 {
153 /* store primary buffer */
154 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
155 }
156 else
157 {
158 DPRINT("Failed to create primary buffer with %x\n", hResult);
159 return hResult;
160 }
161
162 }
163
164 ASSERT(This->PrimaryBuffer);
165
166 DPRINT("This %p wFormatTag %x nChannels %u nSamplesPerSec %u nAvgBytesPerSec %u NBlockAlign %u wBitsPerSample %u cbSize %u\n",
167 This, lpcDSBufferDesc->lpwfxFormat->wFormatTag, lpcDSBufferDesc->lpwfxFormat->nChannels, lpcDSBufferDesc->lpwfxFormat->nSamplesPerSec, lpcDSBufferDesc->lpwfxFormat->nAvgBytesPerSec, lpcDSBufferDesc->lpwfxFormat->nBlockAlign, lpcDSBufferDesc->lpwfxFormat->wBitsPerSample, lpcDSBufferDesc->lpwfxFormat->cbSize);
168
169 hResult = NewSecondarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc, This->PrimaryBuffer);
170 return hResult;
171 }
172 }
173
174 HRESULT
175 WINAPI
176 IDirectSound8_fnGetCaps(
177 LPDIRECTSOUND8 iface,
178 LPDSCAPS lpDSCaps)
179 {
180 UNIMPLEMENTED;
181 return DSERR_GENERIC;
182 }
183
184 HRESULT
185 WINAPI
186 IDirectSound8_fnDuplicateSoundBuffer(
187 LPDIRECTSOUND8 iface,
188 LPDIRECTSOUNDBUFFER lpDsbOriginal,
189 LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate)
190 {
191 UNIMPLEMENTED;
192 return DSERR_OUTOFMEMORY;
193 }
194
195 HRESULT
196 WINAPI
197 IDirectSound8_fnSetCooperativeLevel(
198 LPDIRECTSOUND8 iface,
199 HWND hwnd,
200 DWORD dwLevel)
201 {
202 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
203
204 if (!This->bInitialized)
205 {
206 /* object not yet initialized */
207 return DSERR_UNINITIALIZED;
208 }
209
210 /* store cooperation level */
211 This->dwLevel = dwLevel;
212 return DS_OK;
213 }
214
215 HRESULT
216 WINAPI
217 IDirectSound8_fnCompact(
218 LPDIRECTSOUND8 iface)
219 {
220 UNIMPLEMENTED;
221 return DSERR_INVALIDPARAM;
222 }
223
224 HRESULT
225 WINAPI
226 IDirectSound8_fnGetSpeakerConfig(
227 LPDIRECTSOUND8 iface,
228 LPDWORD pdwSpeakerConfig)
229 {
230 UNIMPLEMENTED;
231 return DSERR_INVALIDPARAM;
232 }
233
234 HRESULT
235 WINAPI
236 IDirectSound8_fnSetSpeakerConfig(
237 LPDIRECTSOUND8 iface,
238 DWORD dwSpeakerConfig)
239 {
240 UNIMPLEMENTED;
241 return DSERR_INVALIDPARAM;
242 }
243
244
245 HRESULT
246 WINAPI
247 IDirectSound8_fnInitialize(
248 LPDIRECTSOUND8 iface,
249 LPCGUID pcGuidDevice)
250 {
251 GUID DeviceGuid;
252 LPOLESTR pGuidStr;
253 HRESULT hr;
254 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
255
256 if (!RootInfo)
257 {
258 EnumAudioDeviceInterfaces(&RootInfo);
259 }
260
261 /* sanity check */
262 ASSERT(RootInfo);
263
264 if (This->bInitialized)
265 {
266 /* object has already been initialized */
267 return DSERR_ALREADYINITIALIZED;
268 }
269
270 /* fixme mutual exlucsion */
271
272 if (pcGuidDevice == NULL || IsEqualGUID(pcGuidDevice, &GUID_NULL))
273 {
274 /* use default playback device id */
275 pcGuidDevice = &DSDEVID_DefaultPlayback;
276 }
277
278 /* now verify the guid */
279 if (GetDeviceID(pcGuidDevice, &DeviceGuid) != DS_OK)
280 {
281 if (SUCCEEDED(StringFromIID(pcGuidDevice, &pGuidStr)))
282 {
283 DPRINT("IDirectSound8_fnInitialize: Unknown GUID %ws\n", pGuidStr);
284 CoTaskMemFree(pGuidStr);
285 }
286 return DSERR_INVALIDPARAM;
287 }
288
289 hr = FindDeviceByGuid(&DeviceGuid, &This->Filter);
290
291 if (SUCCEEDED(hr))
292 {
293 This->bInitialized = TRUE;
294 return DS_OK;
295 }
296
297 DPRINT("Failed to find device\n");
298 return DSERR_INVALIDPARAM;
299 }
300
301 HRESULT
302 WINAPI
303 IDirectSound8_fnVerifyCertification(
304 LPDIRECTSOUND8 iface,
305 LPDWORD pdwCertified)
306 {
307 UNIMPLEMENTED;
308 return DS_CERTIFIED;
309 }
310
311 static IDirectSound8Vtbl vt_DirectSound8 =
312 {
313 /* IUnknown methods */
314 IDirectSound8_fnQueryInterface,
315 IDirectSound8_fnAddRef,
316 IDirectSound8_fnRelease,
317 /* IDirectSound methods */
318 IDirectSound8_fnCreateSoundBuffer,
319 IDirectSound8_fnGetCaps,
320 IDirectSound8_fnDuplicateSoundBuffer,
321 IDirectSound8_fnSetCooperativeLevel,
322 IDirectSound8_fnCompact,
323 IDirectSound8_fnGetSpeakerConfig,
324 IDirectSound8_fnSetSpeakerConfig,
325 IDirectSound8_fnInitialize,
326 /* IDirectSound8 methods */
327 IDirectSound8_fnVerifyCertification
328 };
329
330 HRESULT
331 InternalDirectSoundCreate(
332 LPCGUID lpcGUID,
333 LPDIRECTSOUND8 *ppDS,
334 IUnknown *pUnkOuter)
335 {
336 LPCDirectSoundImpl This;
337 HRESULT hr;
338
339 if (!ppDS || pUnkOuter != NULL)
340 {
341 /* invalid parameter passed */
342 return DSERR_INVALIDPARAM;
343 }
344
345 /* allocate CDirectSoundImpl struct */
346 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
347 if (!This)
348 {
349 /* not enough memory */
350 return DSERR_OUTOFMEMORY;
351 }
352
353 /* initialize IDirectSound object */
354 This->ref = 1;
355 This->lpVtbl = &vt_DirectSound8;
356
357
358 /* initialize direct sound interface */
359 hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID);
360
361 /* check for success */
362 if (!SUCCEEDED(hr))
363 {
364 /* failed */
365 DPRINT("Failed to initialize DirectSound object with %x\n", hr);
366 IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl);
367 return hr;
368 }
369
370 /* store result */
371 *ppDS = (LPDIRECTSOUND8)&This->lpVtbl;
372 DPRINT("DirectSound object %p\n", *ppDS);
373 return DS_OK;
374 }
375
376 HRESULT
377 WINAPI
378 DirectSoundCreate(
379 LPCGUID lpcGUID,
380 LPDIRECTSOUND *ppDS,
381 IUnknown *pUnkOuter)
382 {
383 return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter);
384 }
385
386 HRESULT
387 WINAPI
388 DirectSoundCreate8(
389 LPCGUID lpcGUID,
390 LPDIRECTSOUND8 *ppDS,
391 IUnknown *pUnkOuter)
392 {
393 return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter);
394 }