[DSOUND]
[reactos.git] / reactos / dll / directx / wine / dsound / dsound.c
1 /* DirectSound
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 * Copyright 2004 Robert Reif
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "dsound_private.h"
24
25 /*****************************************************************************
26 * IDirectSound COM components
27 */
28 struct IDirectSound_IUnknown {
29 const IUnknownVtbl *lpVtbl;
30 LONG ref;
31 LPDIRECTSOUND8 pds;
32 };
33
34 static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
35
36 struct IDirectSound_IDirectSound {
37 const IDirectSoundVtbl *lpVtbl;
38 LONG ref;
39 LPDIRECTSOUND8 pds;
40 };
41
42 static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
43
44 /*****************************************************************************
45 * IDirectSound8 COM components
46 */
47 struct IDirectSound8_IUnknown {
48 const IUnknownVtbl *lpVtbl;
49 LONG ref;
50 LPDIRECTSOUND8 pds;
51 };
52
53 static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
54 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
55
56 struct IDirectSound8_IDirectSound {
57 const IDirectSoundVtbl *lpVtbl;
58 LONG ref;
59 LPDIRECTSOUND8 pds;
60 };
61
62 static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
63 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
64
65 struct IDirectSound8_IDirectSound8 {
66 const IDirectSound8Vtbl *lpVtbl;
67 LONG ref;
68 LPDIRECTSOUND8 pds;
69 };
70
71 static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
72 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
73
74 /*****************************************************************************
75 * IDirectSound implementation structure
76 */
77 struct IDirectSoundImpl
78 {
79 LONG ref;
80
81 DirectSoundDevice *device;
82 LPUNKNOWN pUnknown;
83 LPDIRECTSOUND pDS;
84 LPDIRECTSOUND8 pDS8;
85 };
86
87 static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
88
89 static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
90 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
91
92 const char * dumpCooperativeLevel(DWORD level)
93 {
94 #define LE(x) case x: return #x
95 switch (level) {
96 LE(DSSCL_NORMAL);
97 LE(DSSCL_PRIORITY);
98 LE(DSSCL_EXCLUSIVE);
99 LE(DSSCL_WRITEPRIMARY);
100 }
101 #undef LE
102 return wine_dbg_sprintf("Unknown(%08x)", level);
103 }
104
105 static void _dump_DSCAPS(DWORD xmask) {
106 struct {
107 DWORD mask;
108 const char *name;
109 } flags[] = {
110 #define FE(x) { x, #x },
111 FE(DSCAPS_PRIMARYMONO)
112 FE(DSCAPS_PRIMARYSTEREO)
113 FE(DSCAPS_PRIMARY8BIT)
114 FE(DSCAPS_PRIMARY16BIT)
115 FE(DSCAPS_CONTINUOUSRATE)
116 FE(DSCAPS_EMULDRIVER)
117 FE(DSCAPS_CERTIFIED)
118 FE(DSCAPS_SECONDARYMONO)
119 FE(DSCAPS_SECONDARYSTEREO)
120 FE(DSCAPS_SECONDARY8BIT)
121 FE(DSCAPS_SECONDARY16BIT)
122 #undef FE
123 };
124 unsigned int i;
125
126 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
127 if ((flags[i].mask & xmask) == flags[i].mask)
128 TRACE("%s ",flags[i].name);
129 }
130
131 static void _dump_DSBCAPS(DWORD xmask) {
132 struct {
133 DWORD mask;
134 const char *name;
135 } flags[] = {
136 #define FE(x) { x, #x },
137 FE(DSBCAPS_PRIMARYBUFFER)
138 FE(DSBCAPS_STATIC)
139 FE(DSBCAPS_LOCHARDWARE)
140 FE(DSBCAPS_LOCSOFTWARE)
141 FE(DSBCAPS_CTRL3D)
142 FE(DSBCAPS_CTRLFREQUENCY)
143 FE(DSBCAPS_CTRLPAN)
144 FE(DSBCAPS_CTRLVOLUME)
145 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
146 FE(DSBCAPS_STICKYFOCUS)
147 FE(DSBCAPS_GLOBALFOCUS)
148 FE(DSBCAPS_GETCURRENTPOSITION2)
149 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
150 #undef FE
151 };
152 unsigned int i;
153
154 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
155 if ((flags[i].mask & xmask) == flags[i].mask)
156 TRACE("%s ",flags[i].name);
157 }
158
159 /*******************************************************************************
160 * IDirectSoundImpl_DirectSound
161 */
162 static HRESULT DSOUND_QueryInterface(
163 LPDIRECTSOUND8 iface,
164 REFIID riid,
165 LPVOID * ppobj)
166 {
167 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
168 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
169
170 if (ppobj == NULL) {
171 WARN("invalid parameter\n");
172 return E_INVALIDARG;
173 }
174
175 if (IsEqualIID(riid, &IID_IUnknown)) {
176 if (!This->pUnknown) {
177 IDirectSound_IUnknown_Create(iface, &This->pUnknown);
178 if (!This->pUnknown) {
179 WARN("IDirectSound_IUnknown_Create() failed\n");
180 *ppobj = NULL;
181 return E_NOINTERFACE;
182 }
183 }
184 IDirectSound_IUnknown_AddRef(This->pUnknown);
185 *ppobj = This->pUnknown;
186 return S_OK;
187 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
188 if (!This->pDS) {
189 IDirectSound_IDirectSound_Create(iface, &This->pDS);
190 if (!This->pDS) {
191 WARN("IDirectSound_IDirectSound_Create() failed\n");
192 *ppobj = NULL;
193 return E_NOINTERFACE;
194 }
195 }
196 IDirectSound_IDirectSound_AddRef(This->pDS);
197 *ppobj = This->pDS;
198 return S_OK;
199 }
200
201 *ppobj = NULL;
202 WARN("Unknown IID %s\n",debugstr_guid(riid));
203 return E_NOINTERFACE;
204 }
205
206 static HRESULT DSOUND_QueryInterface8(
207 LPDIRECTSOUND8 iface,
208 REFIID riid,
209 LPVOID * ppobj)
210 {
211 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
212 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
213
214 if (ppobj == NULL) {
215 WARN("invalid parameter\n");
216 return E_INVALIDARG;
217 }
218
219 if (IsEqualIID(riid, &IID_IUnknown)) {
220 if (!This->pUnknown) {
221 IDirectSound8_IUnknown_Create(iface, &This->pUnknown);
222 if (!This->pUnknown) {
223 WARN("IDirectSound8_IUnknown_Create() failed\n");
224 *ppobj = NULL;
225 return E_NOINTERFACE;
226 }
227 }
228 IDirectSound8_IUnknown_AddRef(This->pUnknown);
229 *ppobj = This->pUnknown;
230 return S_OK;
231 } else if (IsEqualIID(riid, &IID_IDirectSound)) {
232 if (!This->pDS) {
233 IDirectSound8_IDirectSound_Create(iface, &This->pDS);
234 if (!This->pDS) {
235 WARN("IDirectSound8_IDirectSound_Create() failed\n");
236 *ppobj = NULL;
237 return E_NOINTERFACE;
238 }
239 }
240 IDirectSound8_IDirectSound_AddRef(This->pDS);
241 *ppobj = This->pDS;
242 return S_OK;
243 } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
244 if (!This->pDS8) {
245 IDirectSound8_IDirectSound8_Create(iface, &This->pDS8);
246 if (!This->pDS8) {
247 WARN("IDirectSound8_IDirectSound8_Create() failed\n");
248 *ppobj = NULL;
249 return E_NOINTERFACE;
250 }
251 }
252 IDirectSound8_IDirectSound8_AddRef(This->pDS8);
253 *ppobj = This->pDS8;
254 return S_OK;
255 }
256
257 *ppobj = NULL;
258 WARN("Unknown IID %s\n",debugstr_guid(riid));
259 return E_NOINTERFACE;
260 }
261
262 static ULONG IDirectSoundImpl_AddRef(
263 LPDIRECTSOUND8 iface)
264 {
265 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
266 ULONG ref = InterlockedIncrement(&(This->ref));
267 TRACE("(%p) ref was %d\n", This, ref - 1);
268 return ref;
269 }
270
271 static ULONG IDirectSoundImpl_Release(
272 LPDIRECTSOUND8 iface)
273 {
274 IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
275 ULONG ref = InterlockedDecrement(&(This->ref));
276 TRACE("(%p) ref was %d\n", This, ref + 1);
277
278 if (!ref) {
279 if (This->device)
280 DirectSoundDevice_Release(This->device);
281 HeapFree(GetProcessHeap(),0,This);
282 TRACE("(%p) released\n", This);
283 }
284 return ref;
285 }
286
287 static HRESULT IDirectSoundImpl_Create(
288 LPDIRECTSOUND8 * ppDS)
289 {
290 IDirectSoundImpl* pDS;
291 TRACE("(%p)\n",ppDS);
292
293 /* Allocate memory */
294 pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
295 if (pDS == NULL) {
296 WARN("out of memory\n");
297 *ppDS = NULL;
298 return DSERR_OUTOFMEMORY;
299 }
300
301 pDS->ref = 0;
302 pDS->device = NULL;
303
304 *ppDS = (LPDIRECTSOUND8)pDS;
305
306 return DS_OK;
307 }
308
309 /*******************************************************************************
310 * IDirectSound_IUnknown
311 */
312 static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
313 LPUNKNOWN iface,
314 REFIID riid,
315 LPVOID * ppobj)
316 {
317 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
318 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
319 return DSOUND_QueryInterface(This->pds, riid, ppobj);
320 }
321
322 static ULONG WINAPI IDirectSound_IUnknown_AddRef(
323 LPUNKNOWN iface)
324 {
325 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
326 ULONG ref = InterlockedIncrement(&(This->ref));
327 TRACE("(%p) ref was %d\n", This, ref - 1);
328 return ref;
329 }
330
331 static ULONG WINAPI IDirectSound_IUnknown_Release(
332 LPUNKNOWN iface)
333 {
334 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
335 ULONG ref = InterlockedDecrement(&(This->ref));
336 TRACE("(%p) ref was %d\n", This, ref + 1);
337 if (!ref) {
338 ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
339 IDirectSoundImpl_Release(This->pds);
340 HeapFree(GetProcessHeap(), 0, This);
341 TRACE("(%p) released\n", This);
342 }
343 return ref;
344 }
345
346 static const IUnknownVtbl DirectSound_Unknown_Vtbl =
347 {
348 IDirectSound_IUnknown_QueryInterface,
349 IDirectSound_IUnknown_AddRef,
350 IDirectSound_IUnknown_Release
351 };
352
353 static HRESULT IDirectSound_IUnknown_Create(
354 LPDIRECTSOUND8 pds,
355 LPUNKNOWN * ppunk)
356 {
357 IDirectSound_IUnknown * pdsunk;
358 TRACE("(%p,%p)\n",pds,ppunk);
359
360 if (ppunk == NULL) {
361 ERR("invalid parameter: ppunk == NULL\n");
362 return DSERR_INVALIDPARAM;
363 }
364
365 if (pds == NULL) {
366 ERR("invalid parameter: pds == NULL\n");
367 *ppunk = NULL;
368 return DSERR_INVALIDPARAM;
369 }
370
371 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
372 if (pdsunk == NULL) {
373 WARN("out of memory\n");
374 *ppunk = NULL;
375 return DSERR_OUTOFMEMORY;
376 }
377
378 pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
379 pdsunk->ref = 0;
380 pdsunk->pds = pds;
381
382 IDirectSoundImpl_AddRef(pds);
383 *ppunk = (LPUNKNOWN)pdsunk;
384
385 return DS_OK;
386 }
387
388 /*******************************************************************************
389 * IDirectSound_IDirectSound
390 */
391 static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
392 LPDIRECTSOUND iface,
393 REFIID riid,
394 LPVOID * ppobj)
395 {
396 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
397 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
398 return DSOUND_QueryInterface(This->pds, riid, ppobj);
399 }
400
401 static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
402 LPDIRECTSOUND iface)
403 {
404 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
405 ULONG ref = InterlockedIncrement(&(This->ref));
406 TRACE("(%p) ref was %d\n", This, ref - 1);
407 return ref;
408 }
409
410 static ULONG WINAPI IDirectSound_IDirectSound_Release(
411 LPDIRECTSOUND iface)
412 {
413 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
414 ULONG ref = InterlockedDecrement(&(This->ref));
415 TRACE("(%p) ref was %d\n", This, ref + 1);
416 if (!ref) {
417 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
418 IDirectSoundImpl_Release(This->pds);
419 HeapFree(GetProcessHeap(), 0, This);
420 TRACE("(%p) released\n", This);
421 }
422 return ref;
423 }
424
425 static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
426 LPDIRECTSOUND iface,
427 LPCDSBUFFERDESC dsbd,
428 LPLPDIRECTSOUNDBUFFER ppdsb,
429 LPUNKNOWN lpunk)
430 {
431 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
432 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
433 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
434 }
435
436 static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
437 LPDIRECTSOUND iface,
438 LPDSCAPS lpDSCaps)
439 {
440 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
441 TRACE("(%p,%p)\n",This,lpDSCaps);
442 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
443 }
444
445 static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
446 LPDIRECTSOUND iface,
447 LPDIRECTSOUNDBUFFER psb,
448 LPLPDIRECTSOUNDBUFFER ppdsb)
449 {
450 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
451 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
452 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
453 }
454
455 static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
456 LPDIRECTSOUND iface,
457 HWND hwnd,
458 DWORD level)
459 {
460 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
461 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
462 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
463 }
464
465 static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
466 LPDIRECTSOUND iface)
467 {
468 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
469 TRACE("(%p)\n", This);
470 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
471 }
472
473 static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
474 LPDIRECTSOUND iface,
475 LPDWORD lpdwSpeakerConfig)
476 {
477 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
478 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
479 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
480 }
481
482 static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
483 LPDIRECTSOUND iface,
484 DWORD config)
485 {
486 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
487 TRACE("(%p,0x%08x)\n",This,config);
488 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
489 }
490
491 static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
492 LPDIRECTSOUND iface,
493 LPCGUID lpcGuid)
494 {
495 IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
496 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
497 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
498 }
499
500 static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
501 {
502 IDirectSound_IDirectSound_QueryInterface,
503 IDirectSound_IDirectSound_AddRef,
504 IDirectSound_IDirectSound_Release,
505 IDirectSound_IDirectSound_CreateSoundBuffer,
506 IDirectSound_IDirectSound_GetCaps,
507 IDirectSound_IDirectSound_DuplicateSoundBuffer,
508 IDirectSound_IDirectSound_SetCooperativeLevel,
509 IDirectSound_IDirectSound_Compact,
510 IDirectSound_IDirectSound_GetSpeakerConfig,
511 IDirectSound_IDirectSound_SetSpeakerConfig,
512 IDirectSound_IDirectSound_Initialize
513 };
514
515 static HRESULT IDirectSound_IDirectSound_Create(
516 LPDIRECTSOUND8 pds,
517 LPDIRECTSOUND * ppds)
518 {
519 IDirectSound_IDirectSound * pdsds;
520 TRACE("(%p,%p)\n",pds,ppds);
521
522 if (ppds == NULL) {
523 ERR("invalid parameter: ppds == NULL\n");
524 return DSERR_INVALIDPARAM;
525 }
526
527 if (pds == NULL) {
528 ERR("invalid parameter: pds == NULL\n");
529 *ppds = NULL;
530 return DSERR_INVALIDPARAM;
531 }
532
533 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
534 if (pdsds == NULL) {
535 WARN("out of memory\n");
536 *ppds = NULL;
537 return DSERR_OUTOFMEMORY;
538 }
539
540 pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
541 pdsds->ref = 0;
542 pdsds->pds = pds;
543
544 IDirectSoundImpl_AddRef(pds);
545 *ppds = (LPDIRECTSOUND)pdsds;
546
547 return DS_OK;
548 }
549
550 /*******************************************************************************
551 * IDirectSound8_IUnknown
552 */
553 static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
554 LPUNKNOWN iface,
555 REFIID riid,
556 LPVOID * ppobj)
557 {
558 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
559 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
560 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
561 }
562
563 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
564 LPUNKNOWN iface)
565 {
566 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
567 ULONG ref = InterlockedIncrement(&(This->ref));
568 TRACE("(%p) ref was %d\n", This, ref - 1);
569 return ref;
570 }
571
572 static ULONG WINAPI IDirectSound8_IUnknown_Release(
573 LPUNKNOWN iface)
574 {
575 IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
576 ULONG ref = InterlockedDecrement(&(This->ref));
577 TRACE("(%p) ref was %d\n", This, ref + 1);
578 if (!ref) {
579 ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
580 IDirectSoundImpl_Release(This->pds);
581 HeapFree(GetProcessHeap(), 0, This);
582 TRACE("(%p) released\n", This);
583 }
584 return ref;
585 }
586
587 static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
588 {
589 IDirectSound8_IUnknown_QueryInterface,
590 IDirectSound8_IUnknown_AddRef,
591 IDirectSound8_IUnknown_Release
592 };
593
594 static HRESULT IDirectSound8_IUnknown_Create(
595 LPDIRECTSOUND8 pds,
596 LPUNKNOWN * ppunk)
597 {
598 IDirectSound8_IUnknown * pdsunk;
599 TRACE("(%p,%p)\n",pds,ppunk);
600
601 if (ppunk == NULL) {
602 ERR("invalid parameter: ppunk == NULL\n");
603 return DSERR_INVALIDPARAM;
604 }
605
606 if (pds == NULL) {
607 ERR("invalid parameter: pds == NULL\n");
608 *ppunk = NULL;
609 return DSERR_INVALIDPARAM;
610 }
611
612 pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
613 if (pdsunk == NULL) {
614 WARN("out of memory\n");
615 *ppunk = NULL;
616 return DSERR_OUTOFMEMORY;
617 }
618
619 pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
620 pdsunk->ref = 0;
621 pdsunk->pds = pds;
622
623 IDirectSoundImpl_AddRef(pds);
624 *ppunk = (LPUNKNOWN)pdsunk;
625
626 return DS_OK;
627 }
628
629 /*******************************************************************************
630 * IDirectSound8_IDirectSound
631 */
632 static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
633 LPDIRECTSOUND iface,
634 REFIID riid,
635 LPVOID * ppobj)
636 {
637 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
638 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
639 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
640 }
641
642 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
643 LPDIRECTSOUND iface)
644 {
645 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
646 ULONG ref = InterlockedIncrement(&(This->ref));
647 TRACE("(%p) ref was %d\n", This, ref - 1);
648 return ref;
649 }
650
651 static ULONG WINAPI IDirectSound8_IDirectSound_Release(
652 LPDIRECTSOUND iface)
653 {
654 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
655 ULONG ref = InterlockedDecrement(&(This->ref));
656 TRACE("(%p) ref was %d\n", This, ref + 1);
657 if (!ref) {
658 ((IDirectSoundImpl*)This->pds)->pDS = NULL;
659 IDirectSoundImpl_Release(This->pds);
660 HeapFree(GetProcessHeap(), 0, This);
661 TRACE("(%p) released\n", This);
662 }
663 return ref;
664 }
665
666 static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
667 LPDIRECTSOUND iface,
668 LPCDSBUFFERDESC dsbd,
669 LPLPDIRECTSOUNDBUFFER ppdsb,
670 LPUNKNOWN lpunk)
671 {
672 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
673 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
674 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
675 }
676
677 static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
678 LPDIRECTSOUND iface,
679 LPDSCAPS lpDSCaps)
680 {
681 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
682 TRACE("(%p,%p)\n",This,lpDSCaps);
683 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
684 }
685
686 static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
687 LPDIRECTSOUND iface,
688 LPDIRECTSOUNDBUFFER psb,
689 LPLPDIRECTSOUNDBUFFER ppdsb)
690 {
691 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
692 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
693 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
694 }
695
696 static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
697 LPDIRECTSOUND iface,
698 HWND hwnd,
699 DWORD level)
700 {
701 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
702 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
703 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
704 }
705
706 static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
707 LPDIRECTSOUND iface)
708 {
709 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
710 TRACE("(%p)\n", This);
711 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
712 }
713
714 static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
715 LPDIRECTSOUND iface,
716 LPDWORD lpdwSpeakerConfig)
717 {
718 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
719 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
720 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
721 }
722
723 static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
724 LPDIRECTSOUND iface,
725 DWORD config)
726 {
727 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
728 TRACE("(%p,0x%08x)\n",This,config);
729 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
730 }
731
732 static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
733 LPDIRECTSOUND iface,
734 LPCGUID lpcGuid)
735 {
736 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
737 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
738 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
739 }
740
741 static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
742 {
743 IDirectSound8_IDirectSound_QueryInterface,
744 IDirectSound8_IDirectSound_AddRef,
745 IDirectSound8_IDirectSound_Release,
746 IDirectSound8_IDirectSound_CreateSoundBuffer,
747 IDirectSound8_IDirectSound_GetCaps,
748 IDirectSound8_IDirectSound_DuplicateSoundBuffer,
749 IDirectSound8_IDirectSound_SetCooperativeLevel,
750 IDirectSound8_IDirectSound_Compact,
751 IDirectSound8_IDirectSound_GetSpeakerConfig,
752 IDirectSound8_IDirectSound_SetSpeakerConfig,
753 IDirectSound8_IDirectSound_Initialize
754 };
755
756 static HRESULT IDirectSound8_IDirectSound_Create(
757 LPDIRECTSOUND8 pds,
758 LPDIRECTSOUND * ppds)
759 {
760 IDirectSound8_IDirectSound * pdsds;
761 TRACE("(%p,%p)\n",pds,ppds);
762
763 if (ppds == NULL) {
764 ERR("invalid parameter: ppds == NULL\n");
765 return DSERR_INVALIDPARAM;
766 }
767
768 if (pds == NULL) {
769 ERR("invalid parameter: pds == NULL\n");
770 *ppds = NULL;
771 return DSERR_INVALIDPARAM;
772 }
773
774 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
775 if (pdsds == NULL) {
776 WARN("out of memory\n");
777 *ppds = NULL;
778 return DSERR_OUTOFMEMORY;
779 }
780
781 pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
782 pdsds->ref = 0;
783 pdsds->pds = pds;
784
785 IDirectSoundImpl_AddRef(pds);
786 *ppds = (LPDIRECTSOUND)pdsds;
787
788 return DS_OK;
789 }
790
791 /*******************************************************************************
792 * IDirectSound8_IDirectSound8
793 */
794 static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
795 LPDIRECTSOUND8 iface,
796 REFIID riid,
797 LPVOID * ppobj)
798 {
799 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
800 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
801 return DSOUND_QueryInterface8(This->pds, riid, ppobj);
802 }
803
804 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
805 LPDIRECTSOUND8 iface)
806 {
807 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
808 ULONG ref = InterlockedIncrement(&(This->ref));
809 TRACE("(%p) ref was %d\n", This, ref - 1);
810 return ref;
811 }
812
813 static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
814 LPDIRECTSOUND8 iface)
815 {
816 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
817 ULONG ref = InterlockedDecrement(&(This->ref));
818 TRACE("(%p) ref was %d\n", This, ref + 1);
819 if (!ref) {
820 ((IDirectSoundImpl*)This->pds)->pDS8 = NULL;
821 IDirectSoundImpl_Release(This->pds);
822 HeapFree(GetProcessHeap(), 0, This);
823 TRACE("(%p) released\n", This);
824 }
825 return ref;
826 }
827
828 static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
829 LPDIRECTSOUND8 iface,
830 LPCDSBUFFERDESC dsbd,
831 LPLPDIRECTSOUNDBUFFER ppdsb,
832 LPUNKNOWN lpunk)
833 {
834 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
835 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
836 return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
837 }
838
839 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
840 LPDIRECTSOUND8 iface,
841 LPDSCAPS lpDSCaps)
842 {
843 IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
844 TRACE("(%p,%p)\n",This,lpDSCaps);
845 return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
846 }
847
848 static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
849 LPDIRECTSOUND8 iface,
850 LPDIRECTSOUNDBUFFER psb,
851 LPLPDIRECTSOUNDBUFFER ppdsb)
852 {
853 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
854 TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
855 return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
856 }
857
858 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
859 LPDIRECTSOUND8 iface,
860 HWND hwnd,
861 DWORD level)
862 {
863 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
864 TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
865 return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
866 }
867
868 static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
869 LPDIRECTSOUND8 iface)
870 {
871 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
872 TRACE("(%p)\n", This);
873 return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
874 }
875
876 static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
877 LPDIRECTSOUND8 iface,
878 LPDWORD lpdwSpeakerConfig)
879 {
880 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
881 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
882 return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
883 }
884
885 static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
886 LPDIRECTSOUND8 iface,
887 DWORD config)
888 {
889 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
890 TRACE("(%p,0x%08x)\n",This,config);
891 return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
892 }
893
894 static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
895 LPDIRECTSOUND8 iface,
896 LPCGUID lpcGuid)
897 {
898 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
899 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
900 return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
901 }
902
903 static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
904 LPDIRECTSOUND8 iface,
905 LPDWORD pdwCertified)
906 {
907 IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
908 TRACE("(%p, %p)\n", This, pdwCertified);
909 return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
910 }
911
912 static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
913 {
914 IDirectSound8_IDirectSound8_QueryInterface,
915 IDirectSound8_IDirectSound8_AddRef,
916 IDirectSound8_IDirectSound8_Release,
917 IDirectSound8_IDirectSound8_CreateSoundBuffer,
918 IDirectSound8_IDirectSound8_GetCaps,
919 IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
920 IDirectSound8_IDirectSound8_SetCooperativeLevel,
921 IDirectSound8_IDirectSound8_Compact,
922 IDirectSound8_IDirectSound8_GetSpeakerConfig,
923 IDirectSound8_IDirectSound8_SetSpeakerConfig,
924 IDirectSound8_IDirectSound8_Initialize,
925 IDirectSound8_IDirectSound8_VerifyCertification
926 };
927
928 static HRESULT IDirectSound8_IDirectSound8_Create(
929 LPDIRECTSOUND8 pds,
930 LPDIRECTSOUND8 * ppds)
931 {
932 IDirectSound8_IDirectSound8 * pdsds;
933 TRACE("(%p,%p)\n",pds,ppds);
934
935 if (ppds == NULL) {
936 ERR("invalid parameter: ppds == NULL\n");
937 return DSERR_INVALIDPARAM;
938 }
939
940 if (pds == NULL) {
941 ERR("invalid parameter: pds == NULL\n");
942 *ppds = NULL;
943 return DSERR_INVALIDPARAM;
944 }
945
946 pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
947 if (pdsds == NULL) {
948 WARN("out of memory\n");
949 *ppds = NULL;
950 return DSERR_OUTOFMEMORY;
951 }
952
953 pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
954 pdsds->ref = 0;
955 pdsds->pds = pds;
956
957 IDirectSoundImpl_AddRef(pds);
958 *ppds = (LPDIRECTSOUND8)pdsds;
959
960 return DS_OK;
961 }
962
963 HRESULT DSOUND_Create(
964 REFIID riid,
965 LPDIRECTSOUND *ppDS)
966 {
967 LPDIRECTSOUND8 pDS;
968 HRESULT hr;
969 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
970
971 if (!IsEqualIID(riid, &IID_IUnknown) &&
972 !IsEqualIID(riid, &IID_IDirectSound)) {
973 *ppDS = 0;
974 return E_NOINTERFACE;
975 }
976
977 /* Get dsound configuration */
978 setup_dsound_options();
979
980 hr = IDirectSoundImpl_Create(&pDS);
981 if (hr == DS_OK) {
982 hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
983 if (*ppDS)
984 IDirectSound_IDirectSound_AddRef(*ppDS);
985 else {
986 WARN("IDirectSound_IDirectSound_Create failed\n");
987 IDirectSound8_Release(pDS);
988 }
989 } else {
990 WARN("IDirectSoundImpl_Create failed\n");
991 *ppDS = 0;
992 }
993
994 return hr;
995 }
996
997 /*******************************************************************************
998 * DirectSoundCreate (DSOUND.1)
999 *
1000 * Creates and initializes a DirectSound interface.
1001 *
1002 * PARAMS
1003 * lpcGUID [I] Address of the GUID that identifies the sound device.
1004 * ppDS [O] Address of a variable to receive the interface pointer.
1005 * pUnkOuter [I] Must be NULL.
1006 *
1007 * RETURNS
1008 * Success: DS_OK
1009 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1010 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1011 */
1012 HRESULT WINAPI DirectSoundCreate(
1013 LPCGUID lpcGUID,
1014 LPDIRECTSOUND *ppDS,
1015 IUnknown *pUnkOuter)
1016 {
1017 HRESULT hr;
1018 LPDIRECTSOUND pDS;
1019
1020 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1021
1022 if (ppDS == NULL) {
1023 WARN("invalid parameter: ppDS == NULL\n");
1024 return DSERR_INVALIDPARAM;
1025 }
1026
1027 if (pUnkOuter != NULL) {
1028 WARN("invalid parameter: pUnkOuter != NULL\n");
1029 *ppDS = 0;
1030 return DSERR_INVALIDPARAM;
1031 }
1032
1033 hr = DSOUND_Create(&IID_IDirectSound, &pDS);
1034 if (hr == DS_OK) {
1035 hr = IDirectSound_Initialize(pDS, lpcGUID);
1036 if (hr != DS_OK) {
1037 if (hr != DSERR_ALREADYINITIALIZED) {
1038 IDirectSound_Release(pDS);
1039 pDS = 0;
1040 } else
1041 hr = DS_OK;
1042 }
1043 }
1044
1045 *ppDS = pDS;
1046
1047 return hr;
1048 }
1049
1050 HRESULT DSOUND_Create8(
1051 REFIID riid,
1052 LPDIRECTSOUND8 *ppDS)
1053 {
1054 LPDIRECTSOUND8 pDS;
1055 HRESULT hr;
1056 TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
1057
1058 if (!IsEqualIID(riid, &IID_IUnknown) &&
1059 !IsEqualIID(riid, &IID_IDirectSound) &&
1060 !IsEqualIID(riid, &IID_IDirectSound8)) {
1061 *ppDS = 0;
1062 return E_NOINTERFACE;
1063 }
1064
1065 /* Get dsound configuration */
1066 setup_dsound_options();
1067
1068 hr = IDirectSoundImpl_Create(&pDS);
1069 if (hr == DS_OK) {
1070 hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
1071 if (*ppDS)
1072 IDirectSound8_IDirectSound8_AddRef(*ppDS);
1073 else {
1074 WARN("IDirectSound8_IDirectSound8_Create failed\n");
1075 IDirectSound8_Release(pDS);
1076 }
1077 } else {
1078 WARN("IDirectSoundImpl_Create failed\n");
1079 *ppDS = 0;
1080 }
1081
1082 return hr;
1083 }
1084
1085 /*******************************************************************************
1086 * DirectSoundCreate8 (DSOUND.11)
1087 *
1088 * Creates and initializes a DirectSound8 interface.
1089 *
1090 * PARAMS
1091 * lpcGUID [I] Address of the GUID that identifies the sound device.
1092 * ppDS [O] Address of a variable to receive the interface pointer.
1093 * pUnkOuter [I] Must be NULL.
1094 *
1095 * RETURNS
1096 * Success: DS_OK
1097 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1098 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1099 */
1100 HRESULT WINAPI DirectSoundCreate8(
1101 LPCGUID lpcGUID,
1102 LPDIRECTSOUND8 *ppDS,
1103 IUnknown *pUnkOuter)
1104 {
1105 HRESULT hr;
1106 LPDIRECTSOUND8 pDS;
1107
1108 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1109
1110 if (ppDS == NULL) {
1111 WARN("invalid parameter: ppDS == NULL\n");
1112 return DSERR_INVALIDPARAM;
1113 }
1114
1115 if (pUnkOuter != NULL) {
1116 WARN("invalid parameter: pUnkOuter != NULL\n");
1117 *ppDS = 0;
1118 return DSERR_INVALIDPARAM;
1119 }
1120
1121 hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
1122 if (hr == DS_OK) {
1123 hr = IDirectSound8_Initialize(pDS, lpcGUID);
1124 if (hr != DS_OK) {
1125 if (hr != DSERR_ALREADYINITIALIZED) {
1126 IDirectSound8_Release(pDS);
1127 pDS = 0;
1128 } else
1129 hr = DS_OK;
1130 }
1131 }
1132
1133 *ppDS = pDS;
1134
1135 return hr;
1136 }
1137
1138 /*******************************************************************************
1139 * DirectSoundDevice
1140 */
1141 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
1142 {
1143 DirectSoundDevice * device;
1144 TRACE("(%p)\n", ppDevice);
1145
1146 /* Allocate memory */
1147 device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
1148 if (device == NULL) {
1149 WARN("out of memory\n");
1150 return DSERR_OUTOFMEMORY;
1151 }
1152
1153 device->ref = 1;
1154 device->priolevel = DSSCL_NORMAL;
1155 device->state = STATE_STOPPED;
1156 device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1157
1158 /* 3D listener initial parameters */
1159 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
1160 device->ds3dl.vPosition.x = 0.0;
1161 device->ds3dl.vPosition.y = 0.0;
1162 device->ds3dl.vPosition.z = 0.0;
1163 device->ds3dl.vVelocity.x = 0.0;
1164 device->ds3dl.vVelocity.y = 0.0;
1165 device->ds3dl.vVelocity.z = 0.0;
1166 device->ds3dl.vOrientFront.x = 0.0;
1167 device->ds3dl.vOrientFront.y = 0.0;
1168 device->ds3dl.vOrientFront.z = 1.0;
1169 device->ds3dl.vOrientTop.x = 0.0;
1170 device->ds3dl.vOrientTop.y = 1.0;
1171 device->ds3dl.vOrientTop.z = 0.0;
1172 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1173 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1174 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1175
1176 device->prebuf = ds_snd_queue_max;
1177 device->guid = GUID_NULL;
1178
1179 /* Set default wave format (may need it for waveOutOpen) */
1180 device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
1181 if (device->pwfx == NULL) {
1182 WARN("out of memory\n");
1183 HeapFree(GetProcessHeap(),0,device);
1184 return DSERR_OUTOFMEMORY;
1185 }
1186
1187 /* We rely on the sound driver to return the actual sound format of
1188 * the device if it does not support 22050x8x2 and is given the
1189 * WAVE_DIRECTSOUND flag.
1190 */
1191 device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1192 device->pwfx->nSamplesPerSec = ds_default_sample_rate;
1193 device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
1194 device->pwfx->nChannels = 2;
1195 device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
1196 device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
1197 device->pwfx->cbSize = 0;
1198
1199 InitializeCriticalSection(&(device->mixlock));
1200 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
1201
1202 RtlInitializeResource(&(device->buffer_list_lock));
1203
1204 *ppDevice = device;
1205
1206 return DS_OK;
1207 }
1208
1209 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
1210 {
1211 ULONG ref = InterlockedIncrement(&(device->ref));
1212 TRACE("(%p) ref was %d\n", device, ref - 1);
1213 return ref;
1214 }
1215
1216 ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
1217 {
1218 HRESULT hr;
1219 ULONG ref = InterlockedDecrement(&(device->ref));
1220 TRACE("(%p) ref was %u\n", device, ref + 1);
1221 if (!ref) {
1222 int i;
1223 timeKillEvent(device->timerID);
1224 timeEndPeriod(DS_TIME_RES);
1225
1226 /* The kill event should have allowed the timer process to expire
1227 * but try to grab the lock just in case. Can't hold lock because
1228 * IDirectSoundBufferImpl_Destroy also grabs the lock */
1229 RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
1230 RtlReleaseResource(&(device->buffer_list_lock));
1231
1232 /* It is allowed to release this object even when buffers are playing */
1233 if (device->buffers) {
1234 WARN("%d secondary buffers not released\n", device->nrofbuffers);
1235 for( i=0;i<device->nrofbuffers;i++)
1236 IDirectSoundBufferImpl_Destroy(device->buffers[i]);
1237 }
1238
1239 if (device->primary) {
1240 WARN("primary buffer not released\n");
1241 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
1242 }
1243
1244 hr = DSOUND_PrimaryDestroy(device);
1245 if (hr != DS_OK)
1246 WARN("DSOUND_PrimaryDestroy failed\n");
1247
1248 if (device->driver)
1249 IDsDriver_Close(device->driver);
1250
1251 if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
1252 waveOutClose(device->hwo);
1253
1254 if (device->driver)
1255 IDsDriver_Release(device->driver);
1256
1257 DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
1258
1259 HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
1260 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
1261 if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
1262 HeapFree(GetProcessHeap(), 0, device->buffer);
1263 RtlDeleteResource(&device->buffer_list_lock);
1264 device->mixlock.DebugInfo->Spare[0] = 0;
1265 DeleteCriticalSection(&device->mixlock);
1266 HeapFree(GetProcessHeap(),0,device);
1267 TRACE("(%p) released\n", device);
1268 }
1269 return ref;
1270 }
1271
1272 HRESULT DirectSoundDevice_GetCaps(
1273 DirectSoundDevice * device,
1274 LPDSCAPS lpDSCaps)
1275 {
1276 TRACE("(%p,%p)\n",device,lpDSCaps);
1277
1278 if (device == NULL) {
1279 WARN("not initialized\n");
1280 return DSERR_UNINITIALIZED;
1281 }
1282
1283 if (lpDSCaps == NULL) {
1284 WARN("invalid parameter: lpDSCaps = NULL\n");
1285 return DSERR_INVALIDPARAM;
1286 }
1287
1288 /* check if there is enough room */
1289 if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
1290 WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
1291 return DSERR_INVALIDPARAM;
1292 }
1293
1294 lpDSCaps->dwFlags = device->drvcaps.dwFlags;
1295 if (TRACE_ON(dsound)) {
1296 TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
1297 _dump_DSCAPS(lpDSCaps->dwFlags);
1298 TRACE(")\n");
1299 }
1300 lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate;
1301 lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate;
1302 lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers;
1303 lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
1304 lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
1305 lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
1306 lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers;
1307 lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers;
1308 lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers;
1309 lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers;
1310 lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers;
1311 lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers;
1312 lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers;
1313 lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers;
1314 lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers;
1315 lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes;
1316 lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes;
1317 lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes;
1318
1319 /* driver doesn't have these */
1320 lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
1321 lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
1322
1323 return DS_OK;
1324 }
1325
1326 HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
1327 {
1328 HRESULT hr = DS_OK;
1329 unsigned wod, wodn;
1330 BOOLEAN found = FALSE;
1331 GUID devGUID;
1332 DirectSoundDevice * device = *ppDevice;
1333 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
1334
1335 if (*ppDevice != NULL) {
1336 WARN("already initialized\n");
1337 return DSERR_ALREADYINITIALIZED;
1338 }
1339
1340 /* Default device? */
1341 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
1342 lpcGUID = &DSDEVID_DefaultPlayback;
1343
1344 if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
1345 WARN("invalid parameter: lpcGUID\n");
1346 return DSERR_INVALIDPARAM;
1347 }
1348
1349 /* Enumerate WINMM audio devices and find the one we want */
1350 wodn = waveOutGetNumDevs();
1351 if (!wodn) {
1352 WARN("no driver\n");
1353 return DSERR_NODRIVER;
1354 }
1355
1356 for (wod=0; wod<wodn; wod++) {
1357 if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
1358 found = TRUE;
1359 break;
1360 }
1361 }
1362
1363 if (found == FALSE) {
1364 WARN("No device found matching given ID!\n");
1365 return DSERR_NODRIVER;
1366 }
1367
1368 if (DSOUND_renderer[wod]) {
1369 if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
1370 device = DSOUND_renderer[wod];
1371 DirectSoundDevice_AddRef(device);
1372 *ppDevice = device;
1373 return DS_OK;
1374 } else {
1375 ERR("device GUID doesn't match\n");
1376 hr = DSERR_GENERIC;
1377 return hr;
1378 }
1379 } else {
1380 hr = DirectSoundDevice_Create(&device);
1381 if (hr != DS_OK) {
1382 WARN("DirectSoundDevice_Create failed\n");
1383 return hr;
1384 }
1385 }
1386
1387 *ppDevice = device;
1388 device->guid = devGUID;
1389 device->driver = NULL;
1390
1391 device->drvdesc.dnDevNode = wod;
1392 hr = DSOUND_ReopenDevice(device, FALSE);
1393 if (FAILED(hr))
1394 {
1395 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
1396 return hr;
1397 }
1398
1399 if (device->driver) {
1400 /* the driver is now open, so it's now allowed to call GetCaps */
1401 hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
1402 if (hr != DS_OK) {
1403 WARN("IDsDriver_GetCaps failed\n");
1404 return hr;
1405 }
1406 } else {
1407 WAVEOUTCAPSA woc;
1408 hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
1409 if (hr != DS_OK) {
1410 WARN("waveOutGetDevCaps failed\n");
1411 return hr;
1412 }
1413 ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
1414 if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
1415 (woc.dwFormats & WAVE_FORMAT_2M08) ||
1416 (woc.dwFormats & WAVE_FORMAT_4M08) ||
1417 (woc.dwFormats & WAVE_FORMAT_48M08) ||
1418 (woc.dwFormats & WAVE_FORMAT_96M08)) {
1419 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1420 device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1421 }
1422 if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
1423 (woc.dwFormats & WAVE_FORMAT_2M16) ||
1424 (woc.dwFormats & WAVE_FORMAT_4M16) ||
1425 (woc.dwFormats & WAVE_FORMAT_48M16) ||
1426 (woc.dwFormats & WAVE_FORMAT_96M16)) {
1427 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1428 device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
1429 }
1430 if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
1431 (woc.dwFormats & WAVE_FORMAT_2S08) ||
1432 (woc.dwFormats & WAVE_FORMAT_4S08) ||
1433 (woc.dwFormats & WAVE_FORMAT_48S08) ||
1434 (woc.dwFormats & WAVE_FORMAT_96S08)) {
1435 device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
1436 device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1437 }
1438 if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
1439 (woc.dwFormats & WAVE_FORMAT_2S16) ||
1440 (woc.dwFormats & WAVE_FORMAT_4S16) ||
1441 (woc.dwFormats & WAVE_FORMAT_48S16) ||
1442 (woc.dwFormats & WAVE_FORMAT_96S16)) {
1443 device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
1444 device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
1445 }
1446 if (ds_emuldriver)
1447 device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
1448 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1449 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1450 ZeroMemory(&device->volpan, sizeof(device->volpan));
1451 }
1452
1453 hr = DSOUND_PrimaryCreate(device);
1454 if (hr == DS_OK) {
1455 UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
1456 TIMECAPS time;
1457
1458 DSOUND_renderer[device->drvdesc.dnDevNode] = device;
1459 timeGetDevCaps(&time, sizeof(TIMECAPS));
1460 TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
1461 if (triggertime < time.wPeriodMin)
1462 triggertime = time.wPeriodMin;
1463 if (res < time.wPeriodMin)
1464 res = time.wPeriodMin;
1465 if (timeBeginPeriod(res) == TIMERR_NOCANDO)
1466 WARN("Could not set minimum resolution, don't expect sound\n");
1467 id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
1468 if (!id)
1469 {
1470 WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
1471 id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC);
1472 if (!id) ERR("Could not create timer, sound playback will not occur\n");
1473 }
1474 DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = id;
1475 } else {
1476 WARN("DSOUND_PrimaryCreate failed\n");
1477 }
1478
1479 return hr;
1480 }
1481
1482 HRESULT DirectSoundDevice_CreateSoundBuffer(
1483 DirectSoundDevice * device,
1484 LPCDSBUFFERDESC dsbd,
1485 LPLPDIRECTSOUNDBUFFER ppdsb,
1486 LPUNKNOWN lpunk,
1487 BOOL from8)
1488 {
1489 HRESULT hres = DS_OK;
1490 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
1491
1492 if (device == NULL) {
1493 WARN("not initialized\n");
1494 return DSERR_UNINITIALIZED;
1495 }
1496
1497 if (dsbd == NULL) {
1498 WARN("invalid parameter: dsbd == NULL\n");
1499 return DSERR_INVALIDPARAM;
1500 }
1501
1502 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
1503 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
1504 WARN("invalid parameter: dsbd\n");
1505 return DSERR_INVALIDPARAM;
1506 }
1507
1508 if (ppdsb == NULL) {
1509 WARN("invalid parameter: ppdsb == NULL\n");
1510 return DSERR_INVALIDPARAM;
1511 }
1512 *ppdsb = NULL;
1513
1514 if (TRACE_ON(dsound)) {
1515 TRACE("(structsize=%d)\n",dsbd->dwSize);
1516 TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
1517 _dump_DSBCAPS(dsbd->dwFlags);
1518 TRACE(")\n");
1519 TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
1520 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1521 }
1522
1523 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1524 if (dsbd->lpwfxFormat != NULL) {
1525 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
1526 "primary buffer\n");
1527 return DSERR_INVALIDPARAM;
1528 }
1529
1530 if (device->primary) {
1531 WARN("Primary Buffer already created\n");
1532 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
1533 *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
1534 } else {
1535 hres = primarybuffer_create(device, &device->primary, dsbd);
1536 if (device->primary) {
1537 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
1538 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
1539 if (device->hwbuf)
1540 device->primary->dsbd.dwFlags |= DSBCAPS_LOCHARDWARE;
1541 else
1542 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
1543 } else
1544 WARN("primarybuffer_create() failed\n");
1545 }
1546 } else {
1547 IDirectSoundBufferImpl * dsb;
1548 WAVEFORMATEXTENSIBLE *pwfxe;
1549
1550 if (dsbd->lpwfxFormat == NULL) {
1551 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
1552 "secondary buffer\n");
1553 return DSERR_INVALIDPARAM;
1554 }
1555 pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
1556
1557 if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
1558 {
1559 WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
1560 return DSERR_CONTROLUNAVAIL;
1561 }
1562 if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
1563 {
1564 /* check if cbSize is at least 22 bytes */
1565 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
1566 {
1567 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
1568 return DSERR_INVALIDPARAM;
1569 }
1570
1571 /* cbSize should be 22 bytes, with one possible exception */
1572 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
1573 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
1574 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
1575 {
1576 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
1577 return DSERR_CONTROLUNAVAIL;
1578 }
1579
1580 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
1581 {
1582 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
1583 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
1584 return DSERR_INVALIDPARAM;
1585 }
1586 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
1587 {
1588 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
1589 return DSERR_INVALIDPARAM;
1590 }
1591 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
1592 {
1593 FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
1594 return DSERR_CONTROLUNAVAIL;
1595 }
1596 }
1597
1598 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1599 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1600 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
1601 dsbd->lpwfxFormat->nSamplesPerSec,
1602 dsbd->lpwfxFormat->nAvgBytesPerSec,
1603 dsbd->lpwfxFormat->nBlockAlign,
1604 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
1605
1606 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
1607 WARN("invalid parameter: 3D buffer format must be mono\n");
1608 return DSERR_INVALIDPARAM;
1609 }
1610
1611 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
1612 if (dsb)
1613 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1614 else
1615 WARN("IDirectSoundBufferImpl_Create failed\n");
1616 }
1617
1618 return hres;
1619 }
1620
1621 HRESULT DirectSoundDevice_DuplicateSoundBuffer(
1622 DirectSoundDevice * device,
1623 LPDIRECTSOUNDBUFFER psb,
1624 LPLPDIRECTSOUNDBUFFER ppdsb)
1625 {
1626 HRESULT hres = DS_OK;
1627 IDirectSoundBufferImpl* dsb;
1628 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
1629
1630 if (device == NULL) {
1631 WARN("not initialized\n");
1632 return DSERR_UNINITIALIZED;
1633 }
1634
1635 if (psb == NULL) {
1636 WARN("invalid parameter: psb == NULL\n");
1637 return DSERR_INVALIDPARAM;
1638 }
1639
1640 if (ppdsb == NULL) {
1641 WARN("invalid parameter: ppdsb == NULL\n");
1642 return DSERR_INVALIDPARAM;
1643 }
1644
1645 /* make sure we have a secondary buffer */
1646 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
1647 WARN("trying to duplicate primary buffer\n");
1648 *ppdsb = NULL;
1649 return DSERR_INVALIDCALL;
1650 }
1651
1652 /* duplicate the actual buffer implementation */
1653 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
1654 if (hres == DS_OK)
1655 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1656 else
1657 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
1658
1659 return hres;
1660 }
1661
1662 HRESULT DirectSoundDevice_SetCooperativeLevel(
1663 DirectSoundDevice * device,
1664 HWND hwnd,
1665 DWORD level)
1666 {
1667 TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
1668
1669 if (device == NULL) {
1670 WARN("not initialized\n");
1671 return DSERR_UNINITIALIZED;
1672 }
1673
1674 if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
1675 WARN("level=%s not fully supported\n",
1676 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
1677 }
1678
1679 device->priolevel = level;
1680 return DS_OK;
1681 }
1682
1683 HRESULT DirectSoundDevice_Compact(
1684 DirectSoundDevice * device)
1685 {
1686 TRACE("(%p)\n", device);
1687
1688 if (device == NULL) {
1689 WARN("not initialized\n");
1690 return DSERR_UNINITIALIZED;
1691 }
1692
1693 if (device->priolevel < DSSCL_PRIORITY) {
1694 WARN("incorrect priority level\n");
1695 return DSERR_PRIOLEVELNEEDED;
1696 }
1697
1698 return DS_OK;
1699 }
1700
1701 HRESULT DirectSoundDevice_GetSpeakerConfig(
1702 DirectSoundDevice * device,
1703 LPDWORD lpdwSpeakerConfig)
1704 {
1705 TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
1706
1707 if (device == NULL) {
1708 WARN("not initialized\n");
1709 return DSERR_UNINITIALIZED;
1710 }
1711
1712 if (lpdwSpeakerConfig == NULL) {
1713 WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
1714 return DSERR_INVALIDPARAM;
1715 }
1716
1717 WARN("not fully functional\n");
1718 *lpdwSpeakerConfig = device->speaker_config;
1719 return DS_OK;
1720 }
1721
1722 HRESULT DirectSoundDevice_SetSpeakerConfig(
1723 DirectSoundDevice * device,
1724 DWORD config)
1725 {
1726 TRACE("(%p,0x%08x)\n",device,config);
1727
1728 if (device == NULL) {
1729 WARN("not initialized\n");
1730 return DSERR_UNINITIALIZED;
1731 }
1732
1733 device->speaker_config = config;
1734 WARN("not fully functional\n");
1735 return DS_OK;
1736 }
1737
1738 HRESULT DirectSoundDevice_VerifyCertification(
1739 DirectSoundDevice * device,
1740 LPDWORD pdwCertified)
1741 {
1742 TRACE("(%p, %p)\n",device,pdwCertified);
1743
1744 if (device == NULL) {
1745 WARN("not initialized\n");
1746 return DSERR_UNINITIALIZED;
1747 }
1748
1749 if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
1750 *pdwCertified = DS_CERTIFIED;
1751 else
1752 *pdwCertified = DS_UNCERTIFIED;
1753
1754 return DS_OK;
1755 }
1756
1757 /*
1758 * Add secondary buffer to buffer list.
1759 * Gets exclusive access to buffer for writing.
1760 */
1761 HRESULT DirectSoundDevice_AddBuffer(
1762 DirectSoundDevice * device,
1763 IDirectSoundBufferImpl * pDSB)
1764 {
1765 IDirectSoundBufferImpl **newbuffers;
1766 HRESULT hr = DS_OK;
1767
1768 TRACE("(%p, %p)\n", device, pDSB);
1769
1770 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1771
1772 if (device->buffers)
1773 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1774 else
1775 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
1776
1777 if (newbuffers) {
1778 device->buffers = newbuffers;
1779 device->buffers[device->nrofbuffers] = pDSB;
1780 device->nrofbuffers++;
1781 TRACE("buffer count is now %d\n", device->nrofbuffers);
1782 } else {
1783 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
1784 hr = DSERR_OUTOFMEMORY;
1785 }
1786
1787 RtlReleaseResource(&(device->buffer_list_lock));
1788
1789 return hr;
1790 }
1791
1792 /*
1793 * Remove secondary buffer from buffer list.
1794 * Gets exclusive access to buffer for writing.
1795 */
1796 HRESULT DirectSoundDevice_RemoveBuffer(
1797 DirectSoundDevice * device,
1798 IDirectSoundBufferImpl * pDSB)
1799 {
1800 int i;
1801 HRESULT hr = DS_OK;
1802
1803 TRACE("(%p, %p)\n", device, pDSB);
1804
1805 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
1806
1807 for (i = 0; i < device->nrofbuffers; i++)
1808 if (device->buffers[i] == pDSB)
1809 break;
1810
1811 if (i < device->nrofbuffers) {
1812 /* Put the last buffer of the list in the (now empty) position */
1813 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
1814 device->nrofbuffers--;
1815 device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
1816 TRACE("buffer count is now %d\n", device->nrofbuffers);
1817 }
1818
1819 if (device->nrofbuffers == 0) {
1820 HeapFree(GetProcessHeap(),0,device->buffers);
1821 device->buffers = NULL;
1822 }
1823
1824 RtlReleaseResource(&(device->buffer_list_lock));
1825
1826 return hr;
1827 }