[DSOUND_NEW]
[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 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
357
358 if (!This->bInitialized)
359 {
360 /* object not yet initialized */
361 return DSERR_UNINITIALIZED;
362 }
363
364 UNIMPLEMENTED;
365 return DS_CERTIFIED;
366 }
367
368 static IDirectSound8Vtbl vt_DirectSound8 =
369 {
370 /* IUnknown methods */
371 IDirectSound8_fnQueryInterface,
372 IDirectSound8_fnAddRef,
373 IDirectSound8_fnRelease,
374 /* IDirectSound methods */
375 IDirectSound8_fnCreateSoundBuffer,
376 IDirectSound8_fnGetCaps,
377 IDirectSound8_fnDuplicateSoundBuffer,
378 IDirectSound8_fnSetCooperativeLevel,
379 IDirectSound8_fnCompact,
380 IDirectSound8_fnGetSpeakerConfig,
381 IDirectSound8_fnSetSpeakerConfig,
382 IDirectSound8_fnInitialize,
383 /* IDirectSound8 methods */
384 IDirectSound8_fnVerifyCertification
385 };
386
387 HRESULT
388 InternalDirectSoundCreate(
389 LPCGUID lpcGUID,
390 LPDIRECTSOUND8 *ppDS,
391 IUnknown *pUnkOuter,
392 BOOL bDirectSound8)
393 {
394 LPCDirectSoundImpl This;
395 HRESULT hr;
396
397 if (!ppDS || pUnkOuter != NULL)
398 {
399 /* invalid parameter passed */
400 return DSERR_INVALIDPARAM;
401 }
402
403 /* allocate CDirectSoundImpl struct */
404 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
405 if (!This)
406 {
407 /* not enough memory */
408 return DSERR_OUTOFMEMORY;
409 }
410
411 /* initialize IDirectSound object */
412 This->ref = 1;
413 This->bDirectSound8 = bDirectSound8;
414 This->lpVtbl = &vt_DirectSound8;
415
416
417 /* initialize direct sound interface */
418 hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID);
419
420 /* check for success */
421 if (!SUCCEEDED(hr))
422 {
423 /* failed */
424 DPRINT("Failed to initialize DirectSound object with %x\n", hr);
425 IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl);
426 return hr;
427 }
428
429 /* store result */
430 *ppDS = (LPDIRECTSOUND8)&This->lpVtbl;
431 DPRINT("DirectSound object %p\n", *ppDS);
432 return DS_OK;
433 }
434
435 HRESULT
436 CALLBACK
437 NewDirectSound(
438 IUnknown* pUnkOuter,
439 REFIID riid,
440 LPVOID* ppvObject)
441 {
442 LPOLESTR pStr;
443 LPCDirectSoundImpl This;
444
445 /* check param */
446 if (!ppvObject)
447 {
448 /* invalid param */
449 return E_INVALIDARG;
450 }
451
452 /* check requested interface */
453 if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IDirectSound) && !IsEqualIID(riid, &IID_IDirectSound8))
454 {
455 *ppvObject = 0;
456 StringFromIID(riid, &pStr);
457 DPRINT("KsPropertySet does not support Interface %ws\n", pStr);
458 CoTaskMemFree(pStr);
459 return E_NOINTERFACE;
460 }
461
462 /* allocate CDirectSoundCaptureImpl struct */
463 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
464 if (!This)
465 {
466 /* not enough memory */
467 return DSERR_OUTOFMEMORY;
468 }
469
470 /* initialize object */
471 This->ref = 1;
472 This->lpVtbl = &vt_DirectSound8;
473 This->bInitialized = FALSE;
474 *ppvObject = (LPVOID)&This->lpVtbl;
475
476 return S_OK;
477 }
478
479
480 HRESULT
481 WINAPI
482 DirectSoundCreate(
483 LPCGUID lpcGUID,
484 LPDIRECTSOUND *ppDS,
485 IUnknown *pUnkOuter)
486 {
487 return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter, FALSE);
488 }
489
490 HRESULT
491 WINAPI
492 DirectSoundCreate8(
493 LPCGUID lpcGUID,
494 LPDIRECTSOUND8 *ppDS,
495 IUnknown *pUnkOuter)
496 {
497 return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter, TRUE);
498 }