3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 * Copyright 2004 Robert Reif
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.
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.
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
39 #include "wine/debug.h"
41 #include "dsound_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
45 typedef struct IDirectSoundImpl
{
46 IUnknown IUnknown_inner
;
47 IDirectSound8 IDirectSound8_iface
;
48 IUnknown
*outer_unk
; /* internal */
49 LONG ref
, refds
, numIfaces
;
50 DirectSoundDevice
*device
;
54 static const char * dumpCooperativeLevel(DWORD level
)
56 #define LE(x) case x: return #x
61 LE(DSSCL_WRITEPRIMARY
);
64 return wine_dbg_sprintf("Unknown(%08x)", level
);
67 static void _dump_DSCAPS(DWORD xmask
) {
72 #define FE(x) { x, #x },
73 FE(DSCAPS_PRIMARYMONO
)
74 FE(DSCAPS_PRIMARYSTEREO
)
75 FE(DSCAPS_PRIMARY8BIT
)
76 FE(DSCAPS_PRIMARY16BIT
)
77 FE(DSCAPS_CONTINUOUSRATE
)
80 FE(DSCAPS_SECONDARYMONO
)
81 FE(DSCAPS_SECONDARYSTEREO
)
82 FE(DSCAPS_SECONDARY8BIT
)
83 FE(DSCAPS_SECONDARY16BIT
)
88 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
89 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
90 TRACE("%s ",flags
[i
].name
);
93 static void _dump_DSBCAPS(DWORD xmask
) {
98 #define FE(x) { x, #x },
99 FE(DSBCAPS_PRIMARYBUFFER
)
101 FE(DSBCAPS_LOCHARDWARE
)
102 FE(DSBCAPS_LOCSOFTWARE
)
104 FE(DSBCAPS_CTRLFREQUENCY
)
106 FE(DSBCAPS_CTRLVOLUME
)
107 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
108 FE(DSBCAPS_STICKYFOCUS
)
109 FE(DSBCAPS_GLOBALFOCUS
)
110 FE(DSBCAPS_GETCURRENTPOSITION2
)
111 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
116 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
117 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
118 TRACE("%s ",flags
[i
].name
);
121 /*******************************************************************************
124 static HRESULT
DirectSoundDevice_Create(DirectSoundDevice
** ppDevice
)
126 DirectSoundDevice
* device
;
127 TRACE("(%p)\n", ppDevice
);
129 /* Allocate memory */
130 device
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(DirectSoundDevice
));
131 if (device
== NULL
) {
132 WARN("out of memory\n");
133 return DSERR_OUTOFMEMORY
;
137 device
->priolevel
= DSSCL_NORMAL
;
138 device
->state
= STATE_STOPPED
;
139 device
->speaker_config
= DSSPEAKER_COMBINED(DSSPEAKER_STEREO
, DSSPEAKER_GEOMETRY_WIDE
);
141 DSOUND_ParseSpeakerConfig(device
);
143 /* 3D listener initial parameters */
144 device
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
145 device
->ds3dl
.vPosition
.x
= 0.0;
146 device
->ds3dl
.vPosition
.y
= 0.0;
147 device
->ds3dl
.vPosition
.z
= 0.0;
148 device
->ds3dl
.vVelocity
.x
= 0.0;
149 device
->ds3dl
.vVelocity
.y
= 0.0;
150 device
->ds3dl
.vVelocity
.z
= 0.0;
151 device
->ds3dl
.vOrientFront
.x
= 0.0;
152 device
->ds3dl
.vOrientFront
.y
= 0.0;
153 device
->ds3dl
.vOrientFront
.z
= 1.0;
154 device
->ds3dl
.vOrientTop
.x
= 0.0;
155 device
->ds3dl
.vOrientTop
.y
= 1.0;
156 device
->ds3dl
.vOrientTop
.z
= 0.0;
157 device
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
158 device
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
159 device
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
161 device
->prebuf
= ds_snd_queue_max
;
162 device
->guid
= GUID_NULL
;
164 /* Set default wave format (may need it for waveOutOpen) */
165 device
->pwfx
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEFORMATEXTENSIBLE
));
166 device
->primary_pwfx
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEFORMATEXTENSIBLE
));
167 if (!device
->pwfx
|| !device
->primary_pwfx
) {
168 WARN("out of memory\n");
169 HeapFree(GetProcessHeap(),0,device
->primary_pwfx
);
170 HeapFree(GetProcessHeap(),0,device
->pwfx
);
171 HeapFree(GetProcessHeap(),0,device
);
172 return DSERR_OUTOFMEMORY
;
175 device
->pwfx
->wFormatTag
= WAVE_FORMAT_PCM
;
176 device
->pwfx
->nSamplesPerSec
= 22050;
177 device
->pwfx
->wBitsPerSample
= 8;
178 device
->pwfx
->nChannels
= 2;
179 device
->pwfx
->nBlockAlign
= device
->pwfx
->wBitsPerSample
* device
->pwfx
->nChannels
/ 8;
180 device
->pwfx
->nAvgBytesPerSec
= device
->pwfx
->nSamplesPerSec
* device
->pwfx
->nBlockAlign
;
181 device
->pwfx
->cbSize
= 0;
182 memcpy(device
->primary_pwfx
, device
->pwfx
, sizeof(*device
->pwfx
));
184 InitializeCriticalSection(&(device
->mixlock
));
185 device
->mixlock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DirectSoundDevice.mixlock");
187 RtlInitializeResource(&(device
->buffer_list_lock
));
194 static ULONG
DirectSoundDevice_AddRef(DirectSoundDevice
* device
)
196 ULONG ref
= InterlockedIncrement(&(device
->ref
));
197 TRACE("(%p) ref was %d\n", device
, ref
- 1);
201 static ULONG
DirectSoundDevice_Release(DirectSoundDevice
* device
)
204 ULONG ref
= InterlockedDecrement(&(device
->ref
));
205 TRACE("(%p) ref was %u\n", device
, ref
+ 1);
209 SetEvent(device
->sleepev
);
210 if (device
->thread
) {
211 WaitForSingleObject(device
->thread_finished
, INFINITE
);
212 CloseHandle(device
->thread
);
213 CloseHandle(device
->thread_finished
);
215 CloseHandle(device
->sleepev
);
217 EnterCriticalSection(&DSOUND_renderers_lock
);
218 list_remove(&device
->entry
);
219 LeaveCriticalSection(&DSOUND_renderers_lock
);
221 /* It is allowed to release this object even when buffers are playing */
222 if (device
->buffers
) {
223 WARN("%d secondary buffers not released\n", device
->nrofbuffers
);
224 for( i
=0;i
<device
->nrofbuffers
;i
++)
225 secondarybuffer_destroy(device
->buffers
[i
]);
228 hr
= DSOUND_PrimaryDestroy(device
);
230 WARN("DSOUND_PrimaryDestroy failed\n");
233 IAudioClient_Release(device
->client
);
235 IAudioRenderClient_Release(device
->render
);
237 IAudioClock_Release(device
->clock
);
239 IAudioStreamVolume_Release(device
->volume
);
241 HeapFree(GetProcessHeap(), 0, device
->tmp_buffer
);
242 HeapFree(GetProcessHeap(), 0, device
->mix_buffer
);
243 HeapFree(GetProcessHeap(), 0, device
->buffer
);
244 RtlDeleteResource(&device
->buffer_list_lock
);
245 device
->mixlock
.DebugInfo
->Spare
[0] = 0;
246 DeleteCriticalSection(&device
->mixlock
);
247 HeapFree(GetProcessHeap(),0,device
);
248 TRACE("(%p) released\n", device
);
253 BOOL
DSOUND_check_supported(IAudioClient
*client
, DWORD rate
,
254 DWORD depth
, WORD channels
)
256 WAVEFORMATEX fmt
, *junk
;
259 fmt
.wFormatTag
= WAVE_FORMAT_PCM
;
260 fmt
.nChannels
= channels
;
261 fmt
.nSamplesPerSec
= rate
;
262 fmt
.wBitsPerSample
= depth
;
263 fmt
.nBlockAlign
= (channels
* depth
) / 8;
264 fmt
.nAvgBytesPerSec
= rate
* fmt
.nBlockAlign
;
267 hr
= IAudioClient_IsFormatSupported(client
, AUDCLNT_SHAREMODE_SHARED
, &fmt
, &junk
);
274 static HRESULT
DirectSoundDevice_Initialize(DirectSoundDevice
** ppDevice
, LPCGUID lpcGUID
)
278 DirectSoundDevice
*device
;
281 TRACE("(%p,%s)\n",ppDevice
,debugstr_guid(lpcGUID
));
283 if (*ppDevice
!= NULL
) {
284 WARN("already initialized\n");
285 return DSERR_ALREADYINITIALIZED
;
288 /* Default device? */
289 if (!lpcGUID
|| IsEqualGUID(lpcGUID
, &GUID_NULL
))
290 lpcGUID
= &DSDEVID_DefaultPlayback
;
292 if(IsEqualGUID(lpcGUID
, &DSDEVID_DefaultCapture
) ||
293 IsEqualGUID(lpcGUID
, &DSDEVID_DefaultVoiceCapture
))
294 return DSERR_NODRIVER
;
296 if (GetDeviceID(lpcGUID
, &devGUID
) != DS_OK
) {
297 WARN("invalid parameter: lpcGUID\n");
298 return DSERR_INVALIDPARAM
;
301 hr
= get_mmdevice(eRender
, &devGUID
, &mmdevice
);
305 EnterCriticalSection(&DSOUND_renderers_lock
);
307 LIST_FOR_EACH_ENTRY(device
, &DSOUND_renderers
, DirectSoundDevice
, entry
){
308 if(IsEqualGUID(&device
->guid
, &devGUID
)){
309 IMMDevice_Release(mmdevice
);
310 DirectSoundDevice_AddRef(device
);
312 LeaveCriticalSection(&DSOUND_renderers_lock
);
317 hr
= DirectSoundDevice_Create(&device
);
319 WARN("DirectSoundDevice_Create failed\n");
320 IMMDevice_Release(mmdevice
);
321 LeaveCriticalSection(&DSOUND_renderers_lock
);
325 device
->mmdevice
= mmdevice
;
326 device
->guid
= devGUID
;
327 device
->sleepev
= CreateEventW(0, 0, 0, 0);
329 hr
= DSOUND_ReopenDevice(device
, FALSE
);
332 HeapFree(GetProcessHeap(), 0, device
);
333 LeaveCriticalSection(&DSOUND_renderers_lock
);
334 IMMDevice_Release(mmdevice
);
335 WARN("DSOUND_ReopenDevice failed: %08x\n", hr
);
339 ZeroMemory(&device
->drvcaps
, sizeof(device
->drvcaps
));
341 if(DSOUND_check_supported(device
->client
, 11025, 8, 1) ||
342 DSOUND_check_supported(device
->client
, 22050, 8, 1) ||
343 DSOUND_check_supported(device
->client
, 44100, 8, 1) ||
344 DSOUND_check_supported(device
->client
, 48000, 8, 1) ||
345 DSOUND_check_supported(device
->client
, 96000, 8, 1))
346 device
->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
| DSCAPS_PRIMARYMONO
;
348 if(DSOUND_check_supported(device
->client
, 11025, 16, 1) ||
349 DSOUND_check_supported(device
->client
, 22050, 16, 1) ||
350 DSOUND_check_supported(device
->client
, 44100, 16, 1) ||
351 DSOUND_check_supported(device
->client
, 48000, 16, 1) ||
352 DSOUND_check_supported(device
->client
, 96000, 16, 1))
353 device
->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYMONO
;
355 if(DSOUND_check_supported(device
->client
, 11025, 8, 2) ||
356 DSOUND_check_supported(device
->client
, 22050, 8, 2) ||
357 DSOUND_check_supported(device
->client
, 44100, 8, 2) ||
358 DSOUND_check_supported(device
->client
, 48000, 8, 2) ||
359 DSOUND_check_supported(device
->client
, 96000, 8, 2))
360 device
->drvcaps
.dwFlags
|= DSCAPS_PRIMARY8BIT
| DSCAPS_PRIMARYSTEREO
;
362 if(DSOUND_check_supported(device
->client
, 11025, 16, 2) ||
363 DSOUND_check_supported(device
->client
, 22050, 16, 2) ||
364 DSOUND_check_supported(device
->client
, 44100, 16, 2) ||
365 DSOUND_check_supported(device
->client
, 48000, 16, 2) ||
366 DSOUND_check_supported(device
->client
, 96000, 16, 2))
367 device
->drvcaps
.dwFlags
|= DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
369 /* the dsound mixer supports all of the following */
370 device
->drvcaps
.dwFlags
|= DSCAPS_SECONDARY8BIT
| DSCAPS_SECONDARY16BIT
;
371 device
->drvcaps
.dwFlags
|= DSCAPS_SECONDARYMONO
| DSCAPS_SECONDARYSTEREO
;
372 device
->drvcaps
.dwFlags
|= DSCAPS_CONTINUOUSRATE
;
374 device
->drvcaps
.dwPrimaryBuffers
= 1;
375 device
->drvcaps
.dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
376 device
->drvcaps
.dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
377 device
->drvcaps
.dwMaxHwMixingAllBuffers
= 16;
378 device
->drvcaps
.dwMaxHwMixingStaticBuffers
= device
->drvcaps
.dwMaxHwMixingAllBuffers
;
379 device
->drvcaps
.dwMaxHwMixingStreamingBuffers
= device
->drvcaps
.dwMaxHwMixingAllBuffers
;
380 device
->drvcaps
.dwFreeHwMixingAllBuffers
= device
->drvcaps
.dwMaxHwMixingAllBuffers
;
381 device
->drvcaps
.dwFreeHwMixingStaticBuffers
= device
->drvcaps
.dwMaxHwMixingStaticBuffers
;
382 device
->drvcaps
.dwFreeHwMixingStreamingBuffers
= device
->drvcaps
.dwMaxHwMixingStreamingBuffers
;
384 ZeroMemory(&device
->volpan
, sizeof(device
->volpan
));
386 hr
= DSOUND_PrimaryCreate(device
);
388 device
->thread_finished
= CreateEventW(0, 0, 0, 0);
389 device
->thread
= CreateThread(0, 0, DSOUND_mixthread
, device
, 0, 0);
390 SetThreadPriority(device
->thread
, THREAD_PRIORITY_TIME_CRITICAL
);
392 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr
);
395 list_add_tail(&DSOUND_renderers
, &device
->entry
);
397 LeaveCriticalSection(&DSOUND_renderers_lock
);
402 static HRESULT
DirectSoundDevice_CreateSoundBuffer(
403 DirectSoundDevice
* device
,
404 LPCDSBUFFERDESC dsbd
,
405 LPLPDIRECTSOUNDBUFFER ppdsb
,
409 HRESULT hres
= DS_OK
;
410 TRACE("(%p,%p,%p,%p)\n",device
,dsbd
,ppdsb
,lpunk
);
412 if (device
== NULL
) {
413 WARN("not initialized\n");
414 return DSERR_UNINITIALIZED
;
418 WARN("invalid parameter: dsbd == NULL\n");
419 return DSERR_INVALIDPARAM
;
422 if (dsbd
->dwSize
!= sizeof(DSBUFFERDESC
) &&
423 dsbd
->dwSize
!= sizeof(DSBUFFERDESC1
)) {
424 WARN("invalid parameter: dsbd\n");
425 return DSERR_INVALIDPARAM
;
429 WARN("invalid parameter: ppdsb == NULL\n");
430 return DSERR_INVALIDPARAM
;
434 if (TRACE_ON(dsound
)) {
435 TRACE("(structsize=%d)\n",dsbd
->dwSize
);
436 TRACE("(flags=0x%08x:\n",dsbd
->dwFlags
);
437 _dump_DSBCAPS(dsbd
->dwFlags
);
439 TRACE("(bufferbytes=%d)\n",dsbd
->dwBufferBytes
);
440 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
443 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) &&
444 dsbd
->dwFlags
& DSBCAPS_LOCHARDWARE
&&
445 device
->drvcaps
.dwFreeHwMixingAllBuffers
== 0)
447 WARN("ran out of emulated hardware buffers\n");
448 return DSERR_ALLOCATED
;
451 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
452 if (dsbd
->lpwfxFormat
!= NULL
) {
453 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
455 return DSERR_INVALIDPARAM
;
458 if (device
->primary
) {
459 WARN("Primary Buffer already created\n");
460 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8
)(device
->primary
));
461 *ppdsb
= (LPDIRECTSOUNDBUFFER
)(device
->primary
);
463 hres
= primarybuffer_create(device
, &device
->primary
, dsbd
);
464 if (device
->primary
) {
465 *ppdsb
= (IDirectSoundBuffer
*)&device
->primary
->IDirectSoundBuffer8_iface
;
466 device
->primary
->dsbd
.dwFlags
&= ~(DSBCAPS_LOCHARDWARE
| DSBCAPS_LOCSOFTWARE
);
467 device
->primary
->dsbd
.dwFlags
|= DSBCAPS_LOCSOFTWARE
;
469 WARN("primarybuffer_create() failed\n");
472 if (dsbd
->lpwfxFormat
== NULL
) {
473 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
474 "secondary buffer\n");
475 return DSERR_INVALIDPARAM
;
478 if(dsbd
->lpwfxFormat
->wFormatTag
!= WAVE_FORMAT_PCM
&&
479 dsbd
->lpwfxFormat
->wFormatTag
!= WAVE_FORMAT_IEEE_FLOAT
&&
480 dsbd
->lpwfxFormat
->wFormatTag
!= WAVE_FORMAT_EXTENSIBLE
) {
481 WARN("We can't mix this format: 0x%x\n", dsbd
->lpwfxFormat
->wFormatTag
);
485 if(dsbd
->lpwfxFormat
->wBitsPerSample
< 8 || dsbd
->lpwfxFormat
->wBitsPerSample
% 8 != 0 ||
486 dsbd
->lpwfxFormat
->nChannels
== 0 || dsbd
->lpwfxFormat
->nSamplesPerSec
== 0 ||
487 dsbd
->lpwfxFormat
->nAvgBytesPerSec
== 0 ||
488 dsbd
->lpwfxFormat
->nBlockAlign
!= dsbd
->lpwfxFormat
->nChannels
* dsbd
->lpwfxFormat
->wBitsPerSample
/ 8) {
489 WARN("Format inconsistency\n");
490 return DSERR_INVALIDPARAM
;
493 if (dsbd
->lpwfxFormat
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
495 WAVEFORMATEXTENSIBLE
*pwfxe
= (WAVEFORMATEXTENSIBLE
*)dsbd
->lpwfxFormat
;
497 /* check if cbSize is at least 22 bytes */
498 if (pwfxe
->Format
.cbSize
< (sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
)))
500 WARN("Too small a cbSize %u\n", pwfxe
->Format
.cbSize
);
501 return DSERR_INVALIDPARAM
;
504 /* cbSize should be 22 bytes, with one possible exception */
505 if (pwfxe
->Format
.cbSize
> (sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
)) &&
506 !((IsEqualGUID(&pwfxe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) || IsEqualGUID(&pwfxe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) &&
507 pwfxe
->Format
.cbSize
== sizeof(WAVEFORMATEXTENSIBLE
)))
509 WARN("Too big a cbSize %u\n", pwfxe
->Format
.cbSize
);
510 return DSERR_CONTROLUNAVAIL
;
513 if ((!IsEqualGUID(&pwfxe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) && (!IsEqualGUID(&pwfxe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)))
515 if (!IsEqualGUID(&pwfxe
->SubFormat
, &GUID_NULL
))
516 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe
->SubFormat
));
517 return DSERR_INVALIDPARAM
;
519 if (pwfxe
->Samples
.wValidBitsPerSample
> dsbd
->lpwfxFormat
->wBitsPerSample
)
521 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe
->Samples
.wValidBitsPerSample
, pwfxe
->Format
.wBitsPerSample
);
522 return DSERR_INVALIDPARAM
;
524 if (pwfxe
->Samples
.wValidBitsPerSample
&& pwfxe
->Samples
.wValidBitsPerSample
< dsbd
->lpwfxFormat
->wBitsPerSample
)
526 WARN("Non-packed formats may not function : %d/%d\n", pwfxe
->Samples
.wValidBitsPerSample
, dsbd
->lpwfxFormat
->wBitsPerSample
);
530 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
531 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
532 dsbd
->lpwfxFormat
->wFormatTag
, dsbd
->lpwfxFormat
->nChannels
,
533 dsbd
->lpwfxFormat
->nSamplesPerSec
,
534 dsbd
->lpwfxFormat
->nAvgBytesPerSec
,
535 dsbd
->lpwfxFormat
->nBlockAlign
,
536 dsbd
->lpwfxFormat
->wBitsPerSample
, dsbd
->lpwfxFormat
->cbSize
);
538 if (from8
&& (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) && (dsbd
->lpwfxFormat
->nChannels
!= 1)) {
539 WARN("invalid parameter: 3D buffer format must be mono\n");
540 return DSERR_INVALIDPARAM
;
543 if (from8
&& (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) && (dsbd
->dwFlags
& DSBCAPS_CTRLPAN
)) {
544 WARN("invalid parameter: DSBCAPS_CTRL3D and DSBCAPS_CTRLPAN cannot be used together\n");
545 return DSERR_INVALIDPARAM
;
548 hres
= secondarybuffer_create(device
, dsbd
, ppdsb
);
549 if (SUCCEEDED(hres
)) {
550 if (dsbd
->dwFlags
& DSBCAPS_LOCHARDWARE
)
551 device
->drvcaps
.dwFreeHwMixingAllBuffers
--;
553 WARN("IDirectSoundBufferImpl_Create failed\n");
559 static HRESULT
DirectSoundDevice_DuplicateSoundBuffer(
560 DirectSoundDevice
* device
,
561 LPDIRECTSOUNDBUFFER psb
,
562 LPLPDIRECTSOUNDBUFFER ppdsb
)
564 HRESULT hres
= DS_OK
;
565 IDirectSoundBufferImpl
* dsb
;
566 TRACE("(%p,%p,%p)\n",device
,psb
,ppdsb
);
568 if (device
== NULL
) {
569 WARN("not initialized\n");
570 return DSERR_UNINITIALIZED
;
574 WARN("invalid parameter: psb == NULL\n");
575 return DSERR_INVALIDPARAM
;
579 WARN("invalid parameter: ppdsb == NULL\n");
580 return DSERR_INVALIDPARAM
;
583 /* make sure we have a secondary buffer */
584 if (psb
== (IDirectSoundBuffer
*)&device
->primary
->IDirectSoundBuffer8_iface
) {
585 WARN("trying to duplicate primary buffer\n");
587 return DSERR_INVALIDCALL
;
590 /* duplicate the actual buffer implementation */
591 hres
= IDirectSoundBufferImpl_Duplicate(device
, &dsb
, (IDirectSoundBufferImpl
*)psb
);
593 *ppdsb
= (IDirectSoundBuffer
*)&dsb
->IDirectSoundBuffer8_iface
;
595 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
601 * Add secondary buffer to buffer list.
602 * Gets exclusive access to buffer for writing.
604 HRESULT
DirectSoundDevice_AddBuffer(
605 DirectSoundDevice
* device
,
606 IDirectSoundBufferImpl
* pDSB
)
608 IDirectSoundBufferImpl
**newbuffers
;
611 TRACE("(%p, %p)\n", device
, pDSB
);
613 RtlAcquireResourceExclusive(&(device
->buffer_list_lock
), TRUE
);
616 newbuffers
= HeapReAlloc(GetProcessHeap(),0,device
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(device
->nrofbuffers
+1));
618 newbuffers
= HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl
*)*(device
->nrofbuffers
+1));
621 device
->buffers
= newbuffers
;
622 device
->buffers
[device
->nrofbuffers
] = pDSB
;
623 device
->nrofbuffers
++;
624 TRACE("buffer count is now %d\n", device
->nrofbuffers
);
626 ERR("out of memory for buffer list! Current buffer count is %d\n", device
->nrofbuffers
);
627 hr
= DSERR_OUTOFMEMORY
;
630 RtlReleaseResource(&(device
->buffer_list_lock
));
636 * Remove secondary buffer from buffer list.
637 * Gets exclusive access to buffer for writing.
639 void DirectSoundDevice_RemoveBuffer(DirectSoundDevice
* device
, IDirectSoundBufferImpl
* pDSB
)
643 TRACE("(%p, %p)\n", device
, pDSB
);
645 RtlAcquireResourceExclusive(&(device
->buffer_list_lock
), TRUE
);
647 if (device
->nrofbuffers
== 1) {
648 assert(device
->buffers
[0] == pDSB
);
649 HeapFree(GetProcessHeap(), 0, device
->buffers
);
650 device
->buffers
= NULL
;
652 for (i
= 0; i
< device
->nrofbuffers
; i
++) {
653 if (device
->buffers
[i
] == pDSB
) {
654 /* Put the last buffer of the list in the (now empty) position */
655 device
->buffers
[i
] = device
->buffers
[device
->nrofbuffers
- 1];
660 device
->nrofbuffers
--;
661 TRACE("buffer count is now %d\n", device
->nrofbuffers
);
663 RtlReleaseResource(&(device
->buffer_list_lock
));
666 /*******************************************************************************
667 * IUnknown Implementation for DirectSound
670 static void directsound_destroy(IDirectSoundImpl
*This
)
673 DirectSoundDevice_Release(This
->device
);
674 HeapFree(GetProcessHeap(),0,This
);
675 TRACE("(%p) released\n", This
);
678 static inline IDirectSoundImpl
*impl_from_IUnknown(IUnknown
*iface
)
680 return CONTAINING_RECORD(iface
, IDirectSoundImpl
, IUnknown_inner
);
683 static HRESULT WINAPI
IUnknownImpl_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
685 IDirectSoundImpl
*This
= impl_from_IUnknown(iface
);
687 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
690 WARN("invalid parameter\n");
695 if (IsEqualIID(riid
, &IID_IUnknown
))
696 *ppv
= &This
->IUnknown_inner
;
697 else if (IsEqualIID(riid
, &IID_IDirectSound
) ||
698 (IsEqualIID(riid
, &IID_IDirectSound8
) && This
->has_ds8
))
699 *ppv
= &This
->IDirectSound8_iface
;
701 WARN("unknown IID %s\n", debugstr_guid(riid
));
702 return E_NOINTERFACE
;
705 IUnknown_AddRef((IUnknown
*)*ppv
);
709 static ULONG WINAPI
IUnknownImpl_AddRef(IUnknown
*iface
)
711 IDirectSoundImpl
*This
= impl_from_IUnknown(iface
);
712 ULONG ref
= InterlockedIncrement(&This
->ref
);
714 TRACE("(%p) ref=%d\n", This
, ref
);
717 InterlockedIncrement(&This
->numIfaces
);
722 static ULONG WINAPI
IUnknownImpl_Release(IUnknown
*iface
)
724 IDirectSoundImpl
*This
= impl_from_IUnknown(iface
);
725 ULONG ref
= InterlockedDecrement(&This
->ref
);
727 TRACE("(%p) ref=%d\n", This
, ref
);
729 if (!ref
&& !InterlockedDecrement(&This
->numIfaces
))
730 directsound_destroy(This
);
735 static const IUnknownVtbl unk_vtbl
=
737 IUnknownImpl_QueryInterface
,
742 /*******************************************************************************
743 * IDirectSound and IDirectSound8 Implementation
745 static inline IDirectSoundImpl
*impl_from_IDirectSound8(IDirectSound8
*iface
)
747 return CONTAINING_RECORD(iface
, IDirectSoundImpl
, IDirectSound8_iface
);
750 static HRESULT WINAPI
IDirectSound8Impl_QueryInterface(IDirectSound8
*iface
, REFIID riid
,
753 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
754 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppv
);
755 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
758 static ULONG WINAPI
IDirectSound8Impl_AddRef(IDirectSound8
*iface
)
760 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
761 ULONG ref
= InterlockedIncrement(&This
->refds
);
763 TRACE("(%p) refds=%d\n", This
, ref
);
766 InterlockedIncrement(&This
->numIfaces
);
771 static ULONG WINAPI
IDirectSound8Impl_Release(IDirectSound8
*iface
)
773 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
774 ULONG ref
= InterlockedDecrement(&(This
->refds
));
776 TRACE("(%p) refds=%d\n", This
, ref
);
778 if (!ref
&& !InterlockedDecrement(&This
->numIfaces
))
779 directsound_destroy(This
);
784 static HRESULT WINAPI
IDirectSound8Impl_CreateSoundBuffer(IDirectSound8
*iface
,
785 const DSBUFFERDESC
*dsbd
, IDirectSoundBuffer
**ppdsb
, IUnknown
*lpunk
)
787 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
788 TRACE("(%p,%p,%p,%p)\n", This
, dsbd
, ppdsb
, lpunk
);
789 return DirectSoundDevice_CreateSoundBuffer(This
->device
, dsbd
, ppdsb
, lpunk
, This
->has_ds8
);
792 static HRESULT WINAPI
IDirectSound8Impl_GetCaps(IDirectSound8
*iface
, DSCAPS
*dscaps
)
794 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
796 TRACE("(%p, %p)\n", This
, dscaps
);
799 WARN("not initialized\n");
800 return DSERR_UNINITIALIZED
;
803 WARN("invalid parameter: dscaps = NULL\n");
804 return DSERR_INVALIDPARAM
;
806 if (dscaps
->dwSize
< sizeof(*dscaps
)) {
807 WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps
->dwSize
);
808 return DSERR_INVALIDPARAM
;
811 dscaps
->dwFlags
= This
->device
->drvcaps
.dwFlags
;
812 dscaps
->dwMinSecondarySampleRate
= This
->device
->drvcaps
.dwMinSecondarySampleRate
;
813 dscaps
->dwMaxSecondarySampleRate
= This
->device
->drvcaps
.dwMaxSecondarySampleRate
;
814 dscaps
->dwPrimaryBuffers
= This
->device
->drvcaps
.dwPrimaryBuffers
;
815 dscaps
->dwMaxHwMixingAllBuffers
= This
->device
->drvcaps
.dwMaxHwMixingAllBuffers
;
816 dscaps
->dwMaxHwMixingStaticBuffers
= This
->device
->drvcaps
.dwMaxHwMixingStaticBuffers
;
817 dscaps
->dwMaxHwMixingStreamingBuffers
= This
->device
->drvcaps
.dwMaxHwMixingStreamingBuffers
;
818 dscaps
->dwFreeHwMixingAllBuffers
= This
->device
->drvcaps
.dwFreeHwMixingAllBuffers
;
819 dscaps
->dwFreeHwMixingStaticBuffers
= This
->device
->drvcaps
.dwFreeHwMixingAllBuffers
;
820 dscaps
->dwFreeHwMixingStreamingBuffers
= This
->device
->drvcaps
.dwFreeHwMixingAllBuffers
;
822 dscaps
->dwMaxHw3DAllBuffers
= This
->device
->drvcaps
.dwMaxHw3DAllBuffers
;
823 dscaps
->dwMaxHw3DStaticBuffers
= This
->device
->drvcaps
.dwMaxHw3DStaticBuffers
;
824 dscaps
->dwMaxHw3DStreamingBuffers
= This
->device
->drvcaps
.dwMaxHw3DStreamingBuffers
;
825 dscaps
->dwFreeHw3DAllBuffers
= This
->device
->drvcaps
.dwFreeHw3DAllBuffers
;
826 dscaps
->dwFreeHw3DStaticBuffers
= This
->device
->drvcaps
.dwFreeHw3DStaticBuffers
;
827 dscaps
->dwFreeHw3DStreamingBuffers
= This
->device
->drvcaps
.dwFreeHw3DStreamingBuffers
;
828 dscaps
->dwTotalHwMemBytes
= This
->device
->drvcaps
.dwTotalHwMemBytes
;
829 dscaps
->dwFreeHwMemBytes
= This
->device
->drvcaps
.dwFreeHwMemBytes
;
830 dscaps
->dwMaxContigFreeHwMemBytes
= This
->device
->drvcaps
.dwMaxContigFreeHwMemBytes
;
831 dscaps
->dwUnlockTransferRateHwBuffers
= This
->device
->drvcaps
.dwUnlockTransferRateHwBuffers
;
832 dscaps
->dwPlayCpuOverheadSwBuffers
= This
->device
->drvcaps
.dwPlayCpuOverheadSwBuffers
;
834 if (TRACE_ON(dsound
)) {
835 TRACE("(flags=0x%08x:\n", dscaps
->dwFlags
);
836 _dump_DSCAPS(dscaps
->dwFlags
);
843 static HRESULT WINAPI
IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8
*iface
,
844 IDirectSoundBuffer
*psb
, IDirectSoundBuffer
**ppdsb
)
846 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
847 TRACE("(%p,%p,%p)\n", This
, psb
, ppdsb
);
848 return DirectSoundDevice_DuplicateSoundBuffer(This
->device
, psb
, ppdsb
);
851 static HRESULT WINAPI
IDirectSound8Impl_SetCooperativeLevel(IDirectSound8
*iface
, HWND hwnd
,
854 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
855 DirectSoundDevice
*device
= This
->device
;
859 TRACE("(%p,%p,%s)\n", This
, hwnd
, dumpCooperativeLevel(level
));
862 WARN("not initialized\n");
863 return DSERR_UNINITIALIZED
;
866 if (level
== DSSCL_PRIORITY
|| level
== DSSCL_EXCLUSIVE
) {
867 WARN("level=%s not fully supported\n",
868 level
==DSSCL_PRIORITY
? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
871 RtlAcquireResourceExclusive(&device
->buffer_list_lock
, TRUE
);
872 EnterCriticalSection(&device
->mixlock
);
873 oldlevel
= device
->priolevel
;
874 device
->priolevel
= level
;
875 if ((level
== DSSCL_WRITEPRIMARY
) != (oldlevel
== DSSCL_WRITEPRIMARY
)) {
876 hr
= DSOUND_ReopenDevice(device
, level
== DSSCL_WRITEPRIMARY
);
878 device
->priolevel
= oldlevel
;
880 DSOUND_PrimaryOpen(device
);
882 LeaveCriticalSection(&device
->mixlock
);
883 RtlReleaseResource(&device
->buffer_list_lock
);
887 static HRESULT WINAPI
IDirectSound8Impl_Compact(IDirectSound8
*iface
)
889 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
891 TRACE("(%p)\n", This
);
894 WARN("not initialized\n");
895 return DSERR_UNINITIALIZED
;
898 if (This
->device
->priolevel
< DSSCL_PRIORITY
) {
899 WARN("incorrect priority level\n");
900 return DSERR_PRIOLEVELNEEDED
;
905 static HRESULT WINAPI
IDirectSound8Impl_GetSpeakerConfig(IDirectSound8
*iface
, DWORD
*config
)
907 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
909 TRACE("(%p, %p)\n", This
, config
);
912 WARN("not initialized\n");
913 return DSERR_UNINITIALIZED
;
916 WARN("invalid parameter: config == NULL\n");
917 return DSERR_INVALIDPARAM
;
920 WARN("not fully functional\n");
921 *config
= This
->device
->speaker_config
;
925 static HRESULT WINAPI
IDirectSound8Impl_SetSpeakerConfig(IDirectSound8
*iface
, DWORD config
)
927 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
929 TRACE("(%p,0x%08x)\n", This
, config
);
932 WARN("not initialized\n");
933 return DSERR_UNINITIALIZED
;
936 /* NOP on Vista and above */
941 static HRESULT WINAPI
IDirectSound8Impl_Initialize(IDirectSound8
*iface
, const GUID
*lpcGuid
)
943 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
944 TRACE("(%p, %s)\n", This
, debugstr_guid(lpcGuid
));
945 return DirectSoundDevice_Initialize(&This
->device
, lpcGuid
);
948 static HRESULT WINAPI
IDirectSound8Impl_VerifyCertification(IDirectSound8
*iface
, DWORD
*certified
)
950 IDirectSoundImpl
*This
= impl_from_IDirectSound8(iface
);
952 TRACE("(%p, %p)\n", This
, certified
);
955 WARN("not initialized\n");
956 return DSERR_UNINITIALIZED
;
959 if (This
->device
->drvcaps
.dwFlags
& DSCAPS_CERTIFIED
)
960 *certified
= DS_CERTIFIED
;
962 *certified
= DS_UNCERTIFIED
;
967 static const IDirectSound8Vtbl ds8_vtbl
=
969 IDirectSound8Impl_QueryInterface
,
970 IDirectSound8Impl_AddRef
,
971 IDirectSound8Impl_Release
,
972 IDirectSound8Impl_CreateSoundBuffer
,
973 IDirectSound8Impl_GetCaps
,
974 IDirectSound8Impl_DuplicateSoundBuffer
,
975 IDirectSound8Impl_SetCooperativeLevel
,
976 IDirectSound8Impl_Compact
,
977 IDirectSound8Impl_GetSpeakerConfig
,
978 IDirectSound8Impl_SetSpeakerConfig
,
979 IDirectSound8Impl_Initialize
,
980 IDirectSound8Impl_VerifyCertification
983 HRESULT
IDirectSoundImpl_Create(IUnknown
*outer_unk
, REFIID riid
, void **ppv
, BOOL has_ds8
)
985 IDirectSoundImpl
*obj
;
988 TRACE("(%s, %p)\n", debugstr_guid(riid
), ppv
);
991 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
993 WARN("out of memory\n");
994 return DSERR_OUTOFMEMORY
;
997 setup_dsound_options();
999 obj
->IUnknown_inner
.lpVtbl
= &unk_vtbl
;
1000 obj
->IDirectSound8_iface
.lpVtbl
= &ds8_vtbl
;
1005 obj
->has_ds8
= has_ds8
;
1007 /* COM aggregation supported only internally */
1009 obj
->outer_unk
= outer_unk
;
1011 obj
->outer_unk
= &obj
->IUnknown_inner
;
1013 hr
= IUnknown_QueryInterface(&obj
->IUnknown_inner
, riid
, ppv
);
1014 IUnknown_Release(&obj
->IUnknown_inner
);
1019 HRESULT
DSOUND_Create(REFIID riid
, void **ppv
)
1021 return IDirectSoundImpl_Create(NULL
, riid
, ppv
, FALSE
);
1024 HRESULT
DSOUND_Create8(REFIID riid
, void **ppv
)
1026 return IDirectSoundImpl_Create(NULL
, riid
, ppv
, TRUE
);
1029 /*******************************************************************************
1030 * DirectSoundCreate (DSOUND.1)
1032 * Creates and initializes a DirectSound interface.
1035 * lpcGUID [I] Address of the GUID that identifies the sound device.
1036 * ppDS [O] Address of a variable to receive the interface pointer.
1037 * pUnkOuter [I] Must be NULL.
1041 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1042 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1044 HRESULT WINAPI
DirectSoundCreate(
1046 LPDIRECTSOUND
*ppDS
,
1047 IUnknown
*pUnkOuter
)
1052 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID
),ppDS
,pUnkOuter
);
1055 WARN("invalid parameter: ppDS == NULL\n");
1056 return DSERR_INVALIDPARAM
;
1059 if (pUnkOuter
!= NULL
) {
1060 WARN("invalid parameter: pUnkOuter != NULL\n");
1062 return DSERR_INVALIDPARAM
;
1065 hr
= DSOUND_Create(&IID_IDirectSound
, (void **)&pDS
);
1067 hr
= IDirectSound_Initialize(pDS
, lpcGUID
);
1069 if (hr
!= DSERR_ALREADYINITIALIZED
) {
1070 IDirectSound_Release(pDS
);
1082 /*******************************************************************************
1083 * DirectSoundCreate8 (DSOUND.11)
1085 * Creates and initializes a DirectSound8 interface.
1088 * lpcGUID [I] Address of the GUID that identifies the sound device.
1089 * ppDS [O] Address of a variable to receive the interface pointer.
1090 * pUnkOuter [I] Must be NULL.
1094 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1095 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1097 HRESULT WINAPI
DirectSoundCreate8(
1099 LPDIRECTSOUND8
*ppDS
,
1100 IUnknown
*pUnkOuter
)
1105 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID
),ppDS
,pUnkOuter
);
1108 WARN("invalid parameter: ppDS == NULL\n");
1109 return DSERR_INVALIDPARAM
;
1112 if (pUnkOuter
!= NULL
) {
1113 WARN("invalid parameter: pUnkOuter != NULL\n");
1115 return DSERR_INVALIDPARAM
;
1118 hr
= DSOUND_Create8(&IID_IDirectSound8
, (void **)&pDS
);
1120 hr
= IDirectSound8_Initialize(pDS
, lpcGUID
);
1122 if (hr
!= DSERR_ALREADYINITIALIZED
) {
1123 IDirectSound8_Release(pDS
);
1135 void DSOUND_ParseSpeakerConfig(DirectSoundDevice
*device
)
1137 switch (DSSPEAKER_CONFIG(device
->speaker_config
)) {
1138 case DSSPEAKER_MONO
:
1139 device
->speaker_angles
[0] = M_PI
/180.0f
* 0.0f
;
1140 device
->speaker_num
[0] = 0;
1141 device
->num_speakers
= 1;
1142 device
->lfe_channel
= -1;
1145 case DSSPEAKER_STEREO
:
1146 case DSSPEAKER_HEADPHONE
:
1147 device
->speaker_angles
[0] = M_PI
/180.0f
* -90.0f
;
1148 device
->speaker_angles
[1] = M_PI
/180.0f
* 90.0f
;
1149 device
->speaker_num
[0] = 0; /* Left */
1150 device
->speaker_num
[1] = 1; /* Right */
1151 device
->num_speakers
= 2;
1152 device
->lfe_channel
= -1;
1155 case DSSPEAKER_QUAD
:
1156 device
->speaker_angles
[0] = M_PI
/180.0f
* -135.0f
;
1157 device
->speaker_angles
[1] = M_PI
/180.0f
* -45.0f
;
1158 device
->speaker_angles
[2] = M_PI
/180.0f
* 45.0f
;
1159 device
->speaker_angles
[3] = M_PI
/180.0f
* 135.0f
;
1160 device
->speaker_num
[0] = 2; /* Rear left */
1161 device
->speaker_num
[1] = 0; /* Front left */
1162 device
->speaker_num
[2] = 1; /* Front right */
1163 device
->speaker_num
[3] = 3; /* Rear right */
1164 device
->num_speakers
= 4;
1165 device
->lfe_channel
= -1;
1168 case DSSPEAKER_5POINT1_BACK
:
1169 device
->speaker_angles
[0] = M_PI
/180.0f
* -135.0f
;
1170 device
->speaker_angles
[1] = M_PI
/180.0f
* -45.0f
;
1171 device
->speaker_angles
[2] = M_PI
/180.0f
* 0.0f
;
1172 device
->speaker_angles
[3] = M_PI
/180.0f
* 45.0f
;
1173 device
->speaker_angles
[4] = M_PI
/180.0f
* 135.0f
;
1174 device
->speaker_angles
[5] = 9999.0f
;
1175 device
->speaker_num
[0] = 4; /* Rear left */
1176 device
->speaker_num
[1] = 0; /* Front left */
1177 device
->speaker_num
[2] = 2; /* Front centre */
1178 device
->speaker_num
[3] = 1; /* Front right */
1179 device
->speaker_num
[4] = 5; /* Rear right */
1180 device
->speaker_num
[5] = 3; /* LFE */
1181 device
->num_speakers
= 6;
1182 device
->lfe_channel
= 3;
1185 case DSSPEAKER_5POINT1_SURROUND
:
1186 device
->speaker_angles
[0] = M_PI
/180.0f
* -90.0f
;
1187 device
->speaker_angles
[1] = M_PI
/180.0f
* -30.0f
;
1188 device
->speaker_angles
[2] = M_PI
/180.0f
* 0.0f
;
1189 device
->speaker_angles
[3] = M_PI
/180.0f
* 30.0f
;
1190 device
->speaker_angles
[4] = M_PI
/180.0f
* 90.0f
;
1191 device
->speaker_angles
[5] = 9999.0f
;
1192 device
->speaker_num
[0] = 4; /* Rear left */
1193 device
->speaker_num
[1] = 0; /* Front left */
1194 device
->speaker_num
[2] = 2; /* Front centre */
1195 device
->speaker_num
[3] = 1; /* Front right */
1196 device
->speaker_num
[4] = 5; /* Rear right */
1197 device
->speaker_num
[5] = 3; /* LFE */
1198 device
->num_speakers
= 6;
1199 device
->lfe_channel
= 3;
1203 WARN("unknown speaker_config %u\n", device
->speaker_config
);