c2e16879316069be614df49a63eda618a66da78b
[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 BOOL bDirectSound8;
19 DWORD dwLevel;
20 LPFILTERINFO Filter;
21 LPDIRECTSOUNDBUFFER8 PrimaryBuffer;
22
23
24 }CDirectSoundImpl, *LPCDirectSoundImpl;
25
26 HRESULT
27 WINAPI
28 IDirectSound8_fnQueryInterface(
29 LPDIRECTSOUND8 iface,
30 REFIID riid,
31 LPVOID * ppobj)
32 {
33 LPOLESTR pStr;
34 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
35
36 if ((IsEqualIID(riid, &IID_IDirectSound) && This->bDirectSound8 == FALSE) ||
37 (IsEqualIID(riid, &IID_IDirectSound8) && This->bDirectSound8 == TRUE) ||
38 (IsEqualIID(riid, &IID_IUnknown)))
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 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
181
182 if (!This->bInitialized)
183 {
184 /* object not yet initialized */
185 return DSERR_UNINITIALIZED;
186 }
187
188 if (!lpDSCaps)
189 {
190 /* object not yet initialized */
191 return DSERR_INVALIDPARAM;
192 }
193
194 if (lpDSCaps->dwSize != sizeof(DSCAPS))
195 {
196 /* object not yet initialized */
197 return DSERR_INVALIDPARAM;
198 }
199
200 UNIMPLEMENTED;
201 return DSERR_GENERIC;
202 }
203
204 HRESULT
205 WINAPI
206 IDirectSound8_fnDuplicateSoundBuffer(
207 LPDIRECTSOUND8 iface,
208 LPDIRECTSOUNDBUFFER lpDsbOriginal,
209 LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate)
210 {
211 UNIMPLEMENTED;
212 return DSERR_OUTOFMEMORY;
213 }
214
215 HRESULT
216 WINAPI
217 IDirectSound8_fnSetCooperativeLevel(
218 LPDIRECTSOUND8 iface,
219 HWND hwnd,
220 DWORD dwLevel)
221 {
222 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
223
224 if (!This->bInitialized)
225 {
226 /* object not yet initialized */
227 return DSERR_UNINITIALIZED;
228 }
229
230 /* store cooperation level */
231 This->dwLevel = dwLevel;
232 return DS_OK;
233 }
234
235 HRESULT
236 WINAPI
237 IDirectSound8_fnCompact(
238 LPDIRECTSOUND8 iface)
239 {
240 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
241
242 if (!This->bInitialized)
243 {
244 /* object not yet initialized */
245 return DSERR_UNINITIALIZED;
246 }
247
248 if (This->dwLevel != DSSCL_PRIORITY)
249 {
250 /* needs priority level */
251 return DSERR_PRIOLEVELNEEDED;
252 }
253
254 /* done */
255 return DS_OK;
256 }
257
258 HRESULT
259 WINAPI
260 IDirectSound8_fnGetSpeakerConfig(
261 LPDIRECTSOUND8 iface,
262 LPDWORD pdwSpeakerConfig)
263 {
264 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
265
266 if (!This->bInitialized)
267 {
268 /* object not yet initialized */
269 return DSERR_UNINITIALIZED;
270 }
271
272
273 UNIMPLEMENTED;
274 return DSERR_INVALIDPARAM;
275 }
276
277 HRESULT
278 WINAPI
279 IDirectSound8_fnSetSpeakerConfig(
280 LPDIRECTSOUND8 iface,
281 DWORD dwSpeakerConfig)
282 {
283 UNIMPLEMENTED;
284 return DSERR_INVALIDPARAM;
285 }
286
287
288 HRESULT
289 WINAPI
290 IDirectSound8_fnInitialize(
291 LPDIRECTSOUND8 iface,
292 LPCGUID pcGuidDevice)
293 {
294 GUID DeviceGuid;
295 LPOLESTR pGuidStr;
296 HRESULT hr;
297 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
298
299 if (!RootInfo)
300 {
301 EnumAudioDeviceInterfaces(&RootInfo);
302 }
303
304 /* sanity check */
305 ASSERT(RootInfo);
306
307 if (This->bInitialized)
308 {
309 /* object has already been initialized */
310 return DSERR_ALREADYINITIALIZED;
311 }
312
313 /* fixme mutual exlucsion */
314
315 if (pcGuidDevice == NULL || IsEqualGUID(pcGuidDevice, &GUID_NULL))
316 {
317 /* use default playback device id */
318 pcGuidDevice = &DSDEVID_DefaultPlayback;
319 }
320
321 if (IsEqualIID(pcGuidDevice, &DSDEVID_DefaultCapture) || IsEqualIID(pcGuidDevice, &DSDEVID_DefaultVoiceCapture))
322 {
323 /* this has to be a winetest */
324 return DSERR_NODRIVER;
325 }
326
327 /* now verify the guid */
328 if (GetDeviceID(pcGuidDevice, &DeviceGuid) != DS_OK)
329 {
330 if (SUCCEEDED(StringFromIID(pcGuidDevice, &pGuidStr)))
331 {
332 DPRINT("IDirectSound8_fnInitialize: Unknown GUID %ws\n", pGuidStr);
333 CoTaskMemFree(pGuidStr);
334 }
335 return DSERR_INVALIDPARAM;
336 }
337
338 hr = FindDeviceByGuid(&DeviceGuid, &This->Filter);
339
340 if (SUCCEEDED(hr))
341 {
342 This->bInitialized = TRUE;
343 return DS_OK;
344 }
345
346 DPRINT("Failed to find device\n");
347 return DSERR_INVALIDPARAM;
348 }
349
350 HRESULT
351 WINAPI
352 IDirectSound8_fnVerifyCertification(
353 LPDIRECTSOUND8 iface,
354 LPDWORD pdwCertified)
355 {
356 UNIMPLEMENTED;
357 return DS_CERTIFIED;
358 }
359
360 static IDirectSound8Vtbl vt_DirectSound8 =
361 {
362 /* IUnknown methods */
363 IDirectSound8_fnQueryInterface,
364 IDirectSound8_fnAddRef,
365 IDirectSound8_fnRelease,
366 /* IDirectSound methods */
367 IDirectSound8_fnCreateSoundBuffer,
368 IDirectSound8_fnGetCaps,
369 IDirectSound8_fnDuplicateSoundBuffer,
370 IDirectSound8_fnSetCooperativeLevel,
371 IDirectSound8_fnCompact,
372 IDirectSound8_fnGetSpeakerConfig,
373 IDirectSound8_fnSetSpeakerConfig,
374 IDirectSound8_fnInitialize,
375 /* IDirectSound8 methods */
376 IDirectSound8_fnVerifyCertification
377 };
378
379 HRESULT
380 InternalDirectSoundCreate(
381 LPCGUID lpcGUID,
382 LPDIRECTSOUND8 *ppDS,
383 IUnknown *pUnkOuter,
384 BOOL bDirectSound8)
385 {
386 LPCDirectSoundImpl This;
387 HRESULT hr;
388
389 if (!ppDS || pUnkOuter != NULL)
390 {
391 /* invalid parameter passed */
392 return DSERR_INVALIDPARAM;
393 }
394
395 /* allocate CDirectSoundImpl struct */
396 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
397 if (!This)
398 {
399 /* not enough memory */
400 return DSERR_OUTOFMEMORY;
401 }
402
403 /* initialize IDirectSound object */
404 This->ref = 1;
405 This->bDirectSound8 = bDirectSound8;
406 This->lpVtbl = &vt_DirectSound8;
407
408
409 /* initialize direct sound interface */
410 hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID);
411
412 /* check for success */
413 if (!SUCCEEDED(hr))
414 {
415 /* failed */
416 DPRINT("Failed to initialize DirectSound object with %x\n", hr);
417 IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl);
418 return hr;
419 }
420
421 /* store result */
422 *ppDS = (LPDIRECTSOUND8)&This->lpVtbl;
423 DPRINT("DirectSound object %p\n", *ppDS);
424 return DS_OK;
425 }
426
427 HRESULT
428 CALLBACK
429 NewDirectSound(
430 IUnknown* pUnkOuter,
431 REFIID riid,
432 LPVOID* ppvObject)
433 {
434 LPOLESTR pStr;
435 LPCDirectSoundImpl This;
436
437 /* check requested interface */
438 if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IDirectSound) && !IsEqualIID(riid, &IID_IDirectSound8))
439 {
440 *ppvObject = 0;
441 StringFromIID(riid, &pStr);
442 DPRINT("KsPropertySet does not support Interface %ws\n", pStr);
443 CoTaskMemFree(pStr);
444 return E_NOINTERFACE;
445 }
446
447 /* allocate CDirectSoundCaptureImpl struct */
448 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
449 if (!This)
450 {
451 /* not enough memory */
452 return DSERR_OUTOFMEMORY;
453 }
454
455 /* initialize object */
456 This->ref = 1;
457 This->lpVtbl = &vt_DirectSound8;
458 This->bInitialized = FALSE;
459 *ppvObject = (LPVOID)&This->lpVtbl;
460
461 return S_OK;
462 }
463
464
465 HRESULT
466 WINAPI
467 DirectSoundCreate(
468 LPCGUID lpcGUID,
469 LPDIRECTSOUND *ppDS,
470 IUnknown *pUnkOuter)
471 {
472 return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter, FALSE);
473 }
474
475 HRESULT
476 WINAPI
477 DirectSoundCreate8(
478 LPCGUID lpcGUID,
479 LPDIRECTSOUND8 *ppDS,
480 IUnknown *pUnkOuter)
481 {
482 return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter, TRUE);
483 }