[WINHTTP] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / 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 (johannes.anderwald@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 != FALSE) ||
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 (lpcDSBufferDesc->dwBufferBytes != 0)
125 {
126 /* buffer size must be zero for primary sound buffer */
127 return DSERR_INVALIDPARAM;
128 }
129
130 if (This->PrimaryBuffer)
131 {
132 /* primary buffer already exists */
133 IDirectSoundBuffer8_AddRef(This->PrimaryBuffer);
134 *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)This->PrimaryBuffer;
135 return S_OK;
136 }
137
138 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags);
139 if (SUCCEEDED(hResult))
140 {
141 /* store primary buffer */
142 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
143 }
144 return hResult;
145 }
146 else
147 {
148 if (lpcDSBufferDesc->lpwfxFormat == NULL)
149 {
150 /* format must not be null */
151 return DSERR_INVALIDPARAM;
152 }
153
154 if (lpcDSBufferDesc->dwBufferBytes < DSBSIZE_MIN || lpcDSBufferDesc->dwBufferBytes > DSBSIZE_MAX)
155 {
156 /* buffer size must be within bounds for secondary sound buffer*/
157 return DSERR_INVALIDPARAM;
158 }
159
160 if (!This->PrimaryBuffer)
161 {
162 hResult = NewPrimarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc->dwFlags);
163 if (SUCCEEDED(hResult))
164 {
165 /* store primary buffer */
166 This->PrimaryBuffer = (LPDIRECTSOUNDBUFFER8)*lplpDirectSoundBuffer;
167 }
168 else
169 {
170 DPRINT("Failed to create primary buffer with %x\n", hResult);
171 return hResult;
172 }
173
174 }
175
176 ASSERT(This->PrimaryBuffer);
177
178 DPRINT("This %p wFormatTag %x nChannels %u nSamplesPerSec %u nAvgBytesPerSec %u NBlockAlign %u wBitsPerSample %u cbSize %u\n",
179 This, lpcDSBufferDesc->lpwfxFormat->wFormatTag, lpcDSBufferDesc->lpwfxFormat->nChannels, lpcDSBufferDesc->lpwfxFormat->nSamplesPerSec, lpcDSBufferDesc->lpwfxFormat->nAvgBytesPerSec, lpcDSBufferDesc->lpwfxFormat->nBlockAlign, lpcDSBufferDesc->lpwfxFormat->wBitsPerSample, lpcDSBufferDesc->lpwfxFormat->cbSize);
180
181 hResult = NewSecondarySoundBuffer((LPLPDIRECTSOUNDBUFFER8)lplpDirectSoundBuffer, This->Filter, This->dwLevel, lpcDSBufferDesc, This->PrimaryBuffer);
182 return hResult;
183 }
184 }
185
186 HRESULT
187 WINAPI
188 IDirectSound8_fnGetCaps(
189 LPDIRECTSOUND8 iface,
190 LPDSCAPS lpDSCaps)
191 {
192 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
193
194 if (!This->bInitialized)
195 {
196 /* object not yet initialized */
197 return DSERR_UNINITIALIZED;
198 }
199
200 if (!lpDSCaps)
201 {
202 /* object not yet initialized */
203 return DSERR_INVALIDPARAM;
204 }
205
206 if (lpDSCaps->dwSize != sizeof(DSCAPS))
207 {
208 /* object not yet initialized */
209 return DSERR_INVALIDPARAM;
210 }
211
212 UNIMPLEMENTED;
213 return DSERR_GENERIC;
214 }
215
216 HRESULT
217 WINAPI
218 IDirectSound8_fnDuplicateSoundBuffer(
219 LPDIRECTSOUND8 iface,
220 LPDIRECTSOUNDBUFFER lpDsbOriginal,
221 LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate)
222 {
223 UNIMPLEMENTED;
224 return DSERR_OUTOFMEMORY;
225 }
226
227 HRESULT
228 WINAPI
229 IDirectSound8_fnSetCooperativeLevel(
230 LPDIRECTSOUND8 iface,
231 HWND hwnd,
232 DWORD dwLevel)
233 {
234 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
235
236 if (!This->bInitialized)
237 {
238 /* object not yet initialized */
239 return DSERR_UNINITIALIZED;
240 }
241
242 /* store cooperation level */
243 This->dwLevel = dwLevel;
244 return DS_OK;
245 }
246
247 HRESULT
248 WINAPI
249 IDirectSound8_fnCompact(
250 LPDIRECTSOUND8 iface)
251 {
252 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
253
254 if (!This->bInitialized)
255 {
256 /* object not yet initialized */
257 return DSERR_UNINITIALIZED;
258 }
259
260 if (This->dwLevel != DSSCL_PRIORITY)
261 {
262 /* needs priority level */
263 return DSERR_PRIOLEVELNEEDED;
264 }
265
266 /* done */
267 return DS_OK;
268 }
269
270 HRESULT
271 WINAPI
272 IDirectSound8_fnGetSpeakerConfig(
273 LPDIRECTSOUND8 iface,
274 LPDWORD pdwSpeakerConfig)
275 {
276 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
277
278 if (!This->bInitialized)
279 {
280 /* object not yet initialized */
281 return DSERR_UNINITIALIZED;
282 }
283
284
285 UNIMPLEMENTED;
286 return DSERR_INVALIDPARAM;
287 }
288
289 HRESULT
290 WINAPI
291 IDirectSound8_fnSetSpeakerConfig(
292 LPDIRECTSOUND8 iface,
293 DWORD dwSpeakerConfig)
294 {
295 UNIMPLEMENTED;
296 return DSERR_INVALIDPARAM;
297 }
298
299
300 HRESULT
301 WINAPI
302 IDirectSound8_fnInitialize(
303 LPDIRECTSOUND8 iface,
304 LPCGUID pcGuidDevice)
305 {
306 GUID DeviceGuid;
307 LPOLESTR pGuidStr;
308 HRESULT hr;
309 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
310
311 if (!RootInfo)
312 {
313 EnumAudioDeviceInterfaces(&RootInfo);
314 }
315
316 /* sanity check */
317 ASSERT(RootInfo);
318
319 if (This->bInitialized)
320 {
321 /* object has already been initialized */
322 return DSERR_ALREADYINITIALIZED;
323 }
324
325 /* fixme mutual exclusion */
326
327 if (pcGuidDevice == NULL || IsEqualGUID(pcGuidDevice, &GUID_NULL))
328 {
329 /* use default playback device id */
330 pcGuidDevice = &DSDEVID_DefaultPlayback;
331 }
332
333 if (IsEqualIID(pcGuidDevice, &DSDEVID_DefaultCapture) || IsEqualIID(pcGuidDevice, &DSDEVID_DefaultVoiceCapture))
334 {
335 /* this has to be a winetest */
336 return DSERR_NODRIVER;
337 }
338
339 /* now verify the guid */
340 if (GetDeviceID(pcGuidDevice, &DeviceGuid) != DS_OK)
341 {
342 if (SUCCEEDED(StringFromIID(pcGuidDevice, &pGuidStr)))
343 {
344 DPRINT("IDirectSound8_fnInitialize: Unknown GUID %ws\n", pGuidStr);
345 CoTaskMemFree(pGuidStr);
346 }
347 return DSERR_INVALIDPARAM;
348 }
349
350 hr = FindDeviceByGuid(&DeviceGuid, &This->Filter);
351
352 if (SUCCEEDED(hr))
353 {
354 This->bInitialized = TRUE;
355 return DS_OK;
356 }
357
358 DPRINT("Failed to find device\n");
359 return DSERR_INVALIDPARAM;
360 }
361
362 HRESULT
363 WINAPI
364 IDirectSound8_fnVerifyCertification(
365 LPDIRECTSOUND8 iface,
366 LPDWORD pdwCertified)
367 {
368 LPCDirectSoundImpl This = (LPCDirectSoundImpl)CONTAINING_RECORD(iface, CDirectSoundImpl, lpVtbl);
369
370 if (!This->bInitialized)
371 {
372 /* object not yet initialized */
373 return DSERR_UNINITIALIZED;
374 }
375
376 UNIMPLEMENTED;
377 return DS_CERTIFIED;
378 }
379
380 static IDirectSound8Vtbl vt_DirectSound8 =
381 {
382 /* IUnknown methods */
383 IDirectSound8_fnQueryInterface,
384 IDirectSound8_fnAddRef,
385 IDirectSound8_fnRelease,
386 /* IDirectSound methods */
387 IDirectSound8_fnCreateSoundBuffer,
388 IDirectSound8_fnGetCaps,
389 IDirectSound8_fnDuplicateSoundBuffer,
390 IDirectSound8_fnSetCooperativeLevel,
391 IDirectSound8_fnCompact,
392 IDirectSound8_fnGetSpeakerConfig,
393 IDirectSound8_fnSetSpeakerConfig,
394 IDirectSound8_fnInitialize,
395 /* IDirectSound8 methods */
396 IDirectSound8_fnVerifyCertification
397 };
398
399 HRESULT
400 InternalDirectSoundCreate(
401 LPCGUID lpcGUID,
402 LPDIRECTSOUND8 *ppDS,
403 IUnknown *pUnkOuter,
404 BOOL bDirectSound8)
405 {
406 LPCDirectSoundImpl This;
407 HRESULT hr;
408
409 if (!ppDS || pUnkOuter != NULL)
410 {
411 /* invalid parameter passed */
412 return DSERR_INVALIDPARAM;
413 }
414
415 /* allocate CDirectSoundImpl struct */
416 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
417 if (!This)
418 {
419 /* not enough memory */
420 return DSERR_OUTOFMEMORY;
421 }
422
423 /* initialize IDirectSound object */
424 This->ref = 1;
425 This->bDirectSound8 = bDirectSound8;
426 This->lpVtbl = &vt_DirectSound8;
427
428
429 /* initialize direct sound interface */
430 hr = IDirectSound8_Initialize((LPDIRECTSOUND8)&This->lpVtbl, lpcGUID);
431
432 /* check for success */
433 if (!SUCCEEDED(hr))
434 {
435 /* failed */
436 DPRINT("Failed to initialize DirectSound object with %x\n", hr);
437 IDirectSound8_Release((LPDIRECTSOUND8)&This->lpVtbl);
438 return hr;
439 }
440
441 /* store result */
442 *ppDS = (LPDIRECTSOUND8)&This->lpVtbl;
443 DPRINT("DirectSound object %p\n", *ppDS);
444 return DS_OK;
445 }
446
447 HRESULT
448 CALLBACK
449 NewDirectSound(
450 IUnknown* pUnkOuter,
451 REFIID riid,
452 LPVOID* ppvObject)
453 {
454 LPOLESTR pStr;
455 LPCDirectSoundImpl This;
456
457 /* check param */
458 if (!ppvObject)
459 {
460 /* invalid param */
461 return E_INVALIDARG;
462 }
463
464 /* check requested interface */
465 if (!IsEqualIID(riid, &IID_IUnknown) && !IsEqualIID(riid, &IID_IDirectSound) && !IsEqualIID(riid, &IID_IDirectSound8))
466 {
467 *ppvObject = 0;
468 StringFromIID(riid, &pStr);
469 DPRINT("KsPropertySet does not support Interface %ws\n", pStr);
470 CoTaskMemFree(pStr);
471 return E_NOINTERFACE;
472 }
473
474 /* allocate CDirectSoundCaptureImpl struct */
475 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CDirectSoundImpl));
476 if (!This)
477 {
478 /* not enough memory */
479 return DSERR_OUTOFMEMORY;
480 }
481
482 /* initialize object */
483 This->ref = 1;
484 This->lpVtbl = &vt_DirectSound8;
485 This->bInitialized = FALSE;
486 *ppvObject = (LPVOID)&This->lpVtbl;
487
488 return S_OK;
489 }
490
491
492 HRESULT
493 WINAPI
494 DirectSoundCreate(
495 LPCGUID lpcGUID,
496 LPDIRECTSOUND *ppDS,
497 IUnknown *pUnkOuter)
498 {
499 return InternalDirectSoundCreate(lpcGUID, (LPDIRECTSOUND8*)ppDS, pUnkOuter, FALSE);
500 }
501
502 HRESULT
503 WINAPI
504 DirectSoundCreate8(
505 LPCGUID lpcGUID,
506 LPDIRECTSOUND8 *ppDS,
507 IUnknown *pUnkOuter)
508 {
509 return InternalDirectSoundCreate(lpcGUID, ppDS, pUnkOuter, TRUE);
510 }