dsound: Initialize MTA in IDirectSound::Initialize().
[wine.git] / dlls / dsound / dsound.c
blob7629810db505b7bddb493be50ea0432cdf2f6ae8
1 /* DirectSound
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
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <math.h>
28 #define COBJMACROS
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "mmddk.h"
34 #include "wingdi.h"
35 #include "mmreg.h"
36 #include "ks.h"
37 #include "ksmedia.h"
38 #include "wine/debug.h"
39 #include "dsound.h"
40 #include "dsound_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
44 typedef struct IDirectSoundImpl {
45 IUnknown IUnknown_inner;
46 IDirectSound8 IDirectSound8_iface;
47 IUnknown *outer_unk; /* internal */
48 LONG ref, refds, numIfaces;
49 DirectSoundDevice *device;
50 BOOL has_ds8;
51 } IDirectSoundImpl;
53 static const char * dumpCooperativeLevel(DWORD level)
55 #define LE(x) case x: return #x
56 switch (level) {
57 LE(DSSCL_NORMAL);
58 LE(DSSCL_PRIORITY);
59 LE(DSSCL_EXCLUSIVE);
60 LE(DSSCL_WRITEPRIMARY);
62 #undef LE
63 return wine_dbg_sprintf("Unknown(%08lx)", level);
66 static void _dump_DSCAPS(DWORD xmask) {
67 struct {
68 DWORD mask;
69 const char *name;
70 } flags[] = {
71 #define FE(x) { x, #x },
72 FE(DSCAPS_PRIMARYMONO)
73 FE(DSCAPS_PRIMARYSTEREO)
74 FE(DSCAPS_PRIMARY8BIT)
75 FE(DSCAPS_PRIMARY16BIT)
76 FE(DSCAPS_CONTINUOUSRATE)
77 FE(DSCAPS_EMULDRIVER)
78 FE(DSCAPS_CERTIFIED)
79 FE(DSCAPS_SECONDARYMONO)
80 FE(DSCAPS_SECONDARYSTEREO)
81 FE(DSCAPS_SECONDARY8BIT)
82 FE(DSCAPS_SECONDARY16BIT)
83 #undef FE
85 unsigned int i;
87 for (i = 0; i < ARRAY_SIZE(flags); i++)
88 if ((flags[i].mask & xmask) == flags[i].mask)
89 TRACE("%s ",flags[i].name);
92 static void _dump_DSBCAPS(DWORD xmask) {
93 struct {
94 DWORD mask;
95 const char *name;
96 } flags[] = {
97 #define FE(x) { x, #x },
98 FE(DSBCAPS_PRIMARYBUFFER)
99 FE(DSBCAPS_STATIC)
100 FE(DSBCAPS_LOCHARDWARE)
101 FE(DSBCAPS_LOCSOFTWARE)
102 FE(DSBCAPS_CTRL3D)
103 FE(DSBCAPS_CTRLFREQUENCY)
104 FE(DSBCAPS_CTRLPAN)
105 FE(DSBCAPS_CTRLVOLUME)
106 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
107 FE(DSBCAPS_CTRLFX)
108 FE(DSBCAPS_STICKYFOCUS)
109 FE(DSBCAPS_GLOBALFOCUS)
110 FE(DSBCAPS_GETCURRENTPOSITION2)
111 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
112 FE(DSBCAPS_LOCDEFER)
113 #undef FE
115 unsigned int i;
117 for (i = 0; i < ARRAY_SIZE(flags); i++)
118 if ((flags[i].mask & xmask) == flags[i].mask)
119 TRACE("%s ",flags[i].name);
122 /*******************************************************************************
123 * DirectSoundDevice
125 static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
127 DirectSoundDevice * device;
128 TRACE("(%p)\n", ppDevice);
130 /* Allocate memory */
131 device = calloc(1, sizeof(DirectSoundDevice));
132 if (device == NULL) {
133 WARN("out of memory\n");
134 return DSERR_OUTOFMEMORY;
137 device->ref = 1;
138 device->priolevel = DSSCL_NORMAL;
139 device->stopped = 1;
140 device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
142 DSOUND_ParseSpeakerConfig(device);
144 /* 3D listener initial parameters */
145 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
146 device->ds3dl.vPosition.x = 0.0;
147 device->ds3dl.vPosition.y = 0.0;
148 device->ds3dl.vPosition.z = 0.0;
149 device->ds3dl.vVelocity.x = 0.0;
150 device->ds3dl.vVelocity.y = 0.0;
151 device->ds3dl.vVelocity.z = 0.0;
152 device->ds3dl.vOrientFront.x = 0.0;
153 device->ds3dl.vOrientFront.y = 0.0;
154 device->ds3dl.vOrientFront.z = 1.0;
155 device->ds3dl.vOrientTop.x = 0.0;
156 device->ds3dl.vOrientTop.y = 1.0;
157 device->ds3dl.vOrientTop.z = 0.0;
158 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
159 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
160 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
162 device->guid = GUID_NULL;
164 /* Set default wave format (may need it for waveOutOpen) */
165 device->primary_pwfx = calloc(1, sizeof(WAVEFORMATEXTENSIBLE));
166 if (!device->primary_pwfx) {
167 WARN("out of memory\n");
168 free(device);
169 return DSERR_OUTOFMEMORY;
172 device->primary_pwfx->wFormatTag = WAVE_FORMAT_PCM;
173 device->primary_pwfx->nSamplesPerSec = 22050;
174 device->primary_pwfx->wBitsPerSample = 8;
175 device->primary_pwfx->nChannels = 2;
176 device->primary_pwfx->nBlockAlign = device->primary_pwfx->wBitsPerSample * device->primary_pwfx->nChannels / 8;
177 device->primary_pwfx->nAvgBytesPerSec = device->primary_pwfx->nSamplesPerSec * device->primary_pwfx->nBlockAlign;
178 device->primary_pwfx->cbSize = 0;
180 InitializeCriticalSectionEx(&(device->mixlock), 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
181 device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
183 InitializeSRWLock(&device->buffer_list_lock);
185 *ppDevice = device;
187 return DS_OK;
190 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
192 ULONG ref = InterlockedIncrement(&(device->ref));
193 TRACE("(%p) ref %ld\n", device, ref);
194 return ref;
197 static ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
199 HRESULT hr;
200 ULONG ref = InterlockedDecrement(&(device->ref));
201 TRACE("(%p) ref %ld\n", device, ref);
202 if (!ref) {
203 int i;
205 SetEvent(device->sleepev);
206 if (device->thread) {
207 WaitForSingleObject(device->thread, INFINITE);
208 CloseHandle(device->thread);
210 if (device->mta_cookie)
211 CoDecrementMTAUsage(device->mta_cookie);
213 EnterCriticalSection(&DSOUND_renderers_lock);
214 list_remove(&device->entry);
215 LeaveCriticalSection(&DSOUND_renderers_lock);
217 /* It is allowed to release this object even when buffers are playing */
218 if (device->buffers) {
219 WARN("%d secondary buffers not released\n", device->nrofbuffers);
220 for( i=0;i<device->nrofbuffers;i++)
221 secondarybuffer_destroy(device->buffers[i]);
224 hr = DSOUND_PrimaryDestroy(device);
225 if (hr != DS_OK)
226 WARN("DSOUND_PrimaryDestroy failed\n");
228 if(device->client) {
229 IAudioClient_Stop(device->client);
230 IAudioClient_Release(device->client);
232 if(device->render)
233 IAudioRenderClient_Release(device->render);
234 if(device->volume)
235 IAudioStreamVolume_Release(device->volume);
236 if(device->mmdevice)
237 IMMDevice_Release(device->mmdevice);
238 CloseHandle(device->sleepev);
239 free(device->tmp_buffer);
240 free(device->cp_buffer);
241 free(device->buffer);
242 device->mixlock.DebugInfo->Spare[0] = 0;
243 DeleteCriticalSection(&device->mixlock);
244 TRACE("(%p) released\n", device);
245 free(device);
247 return ref;
250 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
251 DWORD depth, WORD channels)
253 WAVEFORMATEX fmt, *junk;
254 HRESULT hr;
256 fmt.wFormatTag = WAVE_FORMAT_PCM;
257 fmt.nChannels = channels;
258 fmt.nSamplesPerSec = rate;
259 fmt.wBitsPerSample = depth;
260 fmt.nBlockAlign = (channels * depth) / 8;
261 fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
262 fmt.cbSize = 0;
264 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
265 if(SUCCEEDED(hr))
266 CoTaskMemFree(junk);
268 return hr == S_OK;
271 static HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
273 HRESULT hr = DS_OK;
274 GUID devGUID;
275 DirectSoundDevice *device;
276 IMMDevice *mmdevice;
278 TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
280 if (*ppDevice != NULL) {
281 WARN("already initialized\n");
282 return DSERR_ALREADYINITIALIZED;
285 /* Default device? */
286 if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
287 lpcGUID = &DSDEVID_DefaultPlayback;
289 if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
290 IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
291 return DSERR_NODRIVER;
293 hr = GetDeviceID(lpcGUID, &devGUID);
294 if (FAILED(hr)) {
295 WARN("invalid parameter: lpcGUID\n");
296 return hr;
299 hr = get_mmdevice(eRender, &devGUID, &mmdevice);
300 if(FAILED(hr))
301 return hr;
303 EnterCriticalSection(&DSOUND_renderers_lock);
305 LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
306 if(IsEqualGUID(&device->guid, &devGUID)){
307 IMMDevice_Release(mmdevice);
308 DirectSoundDevice_AddRef(device);
309 *ppDevice = device;
310 LeaveCriticalSection(&DSOUND_renderers_lock);
311 return DS_OK;
315 hr = DirectSoundDevice_Create(&device);
316 if(FAILED(hr)){
317 WARN("DirectSoundDevice_Create failed\n");
318 IMMDevice_Release(mmdevice);
319 LeaveCriticalSection(&DSOUND_renderers_lock);
320 return hr;
323 device->mmdevice = mmdevice;
324 device->guid = devGUID;
325 device->sleepev = CreateEventW(0, 0, 0, 0);
326 device->buflen = ds_hel_buflen;
328 hr = DSOUND_ReopenDevice(device, FALSE);
329 if (FAILED(hr))
331 free(device);
332 LeaveCriticalSection(&DSOUND_renderers_lock);
333 IMMDevice_Release(mmdevice);
334 WARN("DSOUND_ReopenDevice failed: %08lx\n", hr);
335 return hr;
337 CoIncrementMTAUsage(&device->mta_cookie);
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 /* pretend that the driver is certified */
375 device->drvcaps.dwFlags |= DSCAPS_CERTIFIED;
377 device->drvcaps.dwPrimaryBuffers = 1;
378 device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
379 device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
380 device->drvcaps.dwMaxHwMixingAllBuffers = 1;
381 device->drvcaps.dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
382 device->drvcaps.dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
383 device->drvcaps.dwFreeHwMixingAllBuffers = 0;
384 device->drvcaps.dwFreeHwMixingStaticBuffers = 0;
385 device->drvcaps.dwFreeHwMixingStreamingBuffers = 0;
387 ZeroMemory(&device->volpan, sizeof(device->volpan));
389 device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
390 SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
392 *ppDevice = device;
393 list_add_tail(&DSOUND_renderers, &device->entry);
395 LeaveCriticalSection(&DSOUND_renderers_lock);
397 return hr;
400 static HRESULT DirectSoundDevice_CreateSoundBuffer(
401 DirectSoundDevice * device,
402 LPCDSBUFFERDESC dsbd,
403 LPLPDIRECTSOUNDBUFFER ppdsb,
404 LPUNKNOWN lpunk,
405 BOOL from8)
407 HRESULT hres = DS_OK;
408 TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
410 if (device == NULL) {
411 WARN("not initialized\n");
412 return DSERR_UNINITIALIZED;
415 if (dsbd == NULL) {
416 WARN("invalid parameter: dsbd == NULL\n");
417 return DSERR_INVALIDPARAM;
420 if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
421 dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
422 WARN("invalid parameter: dsbd\n");
423 return DSERR_INVALIDPARAM;
426 if (ppdsb == NULL) {
427 WARN("invalid parameter: ppdsb == NULL\n");
428 return DSERR_INVALIDPARAM;
430 *ppdsb = NULL;
432 if (TRACE_ON(dsound)) {
433 TRACE("(structsize=%ld)\n",dsbd->dwSize);
434 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
435 _dump_DSBCAPS(dsbd->dwFlags);
436 TRACE(")\n");
437 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
438 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
441 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) &&
442 dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
444 WARN("unable to create hardware buffer\n");
445 return DSERR_UNSUPPORTED;
448 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
449 if (dsbd->lpwfxFormat != NULL) {
450 WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
451 "primary buffer\n");
452 return DSERR_INVALIDPARAM;
455 if (dsbd->dwFlags & DSBCAPS_CTRLFX)
457 WARN("Invalid parameter DSBCAPS_CTRLFX\n");
458 return DSERR_INVALIDPARAM;
461 if (device->primary) {
462 WARN("Primary Buffer already created\n");
463 IDirectSoundBuffer8_AddRef(&device->primary->IDirectSoundBuffer8_iface);
464 *ppdsb = (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface;
465 } else {
466 hres = primarybuffer_create(device, &device->primary, dsbd);
467 if (device->primary) {
468 *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
469 device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
470 device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
471 } else
472 WARN("primarybuffer_create() failed\n");
474 } else {
475 if (dsbd->lpwfxFormat == NULL) {
476 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
477 "secondary buffer\n");
478 return DSERR_INVALIDPARAM;
481 if(dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_PCM &&
482 dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_IEEE_FLOAT &&
483 dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
484 WARN("We can't mix this format: 0x%x\n", dsbd->lpwfxFormat->wFormatTag);
485 return E_NOTIMPL;
488 if(dsbd->lpwfxFormat->wBitsPerSample < 8 || dsbd->lpwfxFormat->wBitsPerSample % 8 != 0 ||
489 dsbd->lpwfxFormat->nChannels == 0 || dsbd->lpwfxFormat->nSamplesPerSec == 0 ||
490 dsbd->lpwfxFormat->nAvgBytesPerSec == 0 ||
491 dsbd->lpwfxFormat->nBlockAlign != dsbd->lpwfxFormat->nChannels * dsbd->lpwfxFormat->wBitsPerSample / 8) {
492 WARN("Format inconsistency\n");
493 return DSERR_INVALIDPARAM;
496 if (dsbd->lpwfxFormat->nChannels > 2 && dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
497 return DSERR_INVALIDPARAM;
499 if (dsbd->lpwfxFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
501 WAVEFORMATEXTENSIBLE *pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
503 /* check if cbSize is at least 22 bytes */
504 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
506 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
507 return DSERR_INVALIDPARAM;
510 /* cbSize should be 22 bytes, with one possible exception */
511 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
512 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
513 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
515 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
516 return DSERR_CONTROLUNAVAIL;
519 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
521 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
522 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
523 return DSERR_INVALIDPARAM;
525 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
527 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
528 return DSERR_INVALIDPARAM;
530 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
532 WARN("Non-packed formats may not function : %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
536 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
537 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
538 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
539 dsbd->lpwfxFormat->nSamplesPerSec,
540 dsbd->lpwfxFormat->nAvgBytesPerSec,
541 dsbd->lpwfxFormat->nBlockAlign,
542 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
544 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
545 WARN("invalid parameter: 3D buffer format must be mono\n");
546 return DSERR_INVALIDPARAM;
549 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->dwFlags & DSBCAPS_CTRLPAN)) {
550 WARN("invalid parameter: DSBCAPS_CTRL3D and DSBCAPS_CTRLPAN cannot be used together\n");
551 return DSERR_INVALIDPARAM;
554 hres = secondarybuffer_create(device, dsbd, ppdsb);
555 if (SUCCEEDED(hres)) {
556 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
557 device->drvcaps.dwFreeHwMixingAllBuffers--;
558 } else
559 WARN("IDirectSoundBufferImpl_Create failed\n");
562 return hres;
565 static HRESULT DirectSoundDevice_DuplicateSoundBuffer(
566 DirectSoundDevice * device,
567 LPDIRECTSOUNDBUFFER psb,
568 LPLPDIRECTSOUNDBUFFER ppdsb)
570 HRESULT hres = DS_OK;
571 IDirectSoundBufferImpl* dsb;
572 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
574 if (device == NULL) {
575 WARN("not initialized\n");
576 return DSERR_UNINITIALIZED;
579 if (psb == NULL) {
580 WARN("invalid parameter: psb == NULL\n");
581 return DSERR_INVALIDPARAM;
584 if (ppdsb == NULL) {
585 WARN("invalid parameter: ppdsb == NULL\n");
586 return DSERR_INVALIDPARAM;
589 /* make sure we have a secondary buffer */
590 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
591 WARN("trying to duplicate primary buffer\n");
592 *ppdsb = NULL;
593 return DSERR_INVALIDCALL;
596 /* duplicate the actual buffer implementation */
597 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
598 if (hres == DS_OK)
599 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
600 else
601 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
603 return hres;
607 * Add secondary buffer to buffer list.
608 * Gets exclusive access to buffer for writing.
610 HRESULT DirectSoundDevice_AddBuffer(
611 DirectSoundDevice * device,
612 IDirectSoundBufferImpl * pDSB)
614 IDirectSoundBufferImpl **newbuffers;
615 HRESULT hr = DS_OK;
617 TRACE("(%p, %p)\n", device, pDSB);
619 AcquireSRWLockExclusive(&device->buffer_list_lock);
621 newbuffers = realloc(device->buffers, sizeof(IDirectSoundBufferImpl*) * (device->nrofbuffers + 1));
623 if (newbuffers) {
624 device->buffers = newbuffers;
625 device->buffers[device->nrofbuffers] = pDSB;
626 device->nrofbuffers++;
627 TRACE("buffer count is now %d\n", device->nrofbuffers);
628 } else {
629 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
630 hr = DSERR_OUTOFMEMORY;
633 ReleaseSRWLockExclusive(&device->buffer_list_lock);
635 return hr;
639 * Remove secondary buffer from buffer list.
640 * Gets exclusive access to buffer for writing.
642 void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
644 int i;
646 TRACE("(%p, %p)\n", device, pDSB);
648 AcquireSRWLockExclusive(&device->buffer_list_lock);
650 if (device->nrofbuffers == 1) {
651 assert(device->buffers[0] == pDSB);
652 free(device->buffers);
653 device->buffers = NULL;
654 } else {
655 for (i = 0; i < device->nrofbuffers; i++) {
656 if (device->buffers[i] == pDSB) {
657 /* Put the last buffer of the list in the (now empty) position */
658 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
659 break;
663 device->nrofbuffers--;
664 TRACE("buffer count is now %d\n", device->nrofbuffers);
666 ReleaseSRWLockExclusive(&device->buffer_list_lock);
669 /*******************************************************************************
670 * IUnknown Implementation for DirectSound
673 static void directsound_destroy(IDirectSoundImpl *This)
675 if (This->device)
676 DirectSoundDevice_Release(This->device);
677 TRACE("(%p) released\n", This);
678 free(This);
681 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
683 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
686 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
688 IDirectSoundImpl *This = impl_from_IUnknown(iface);
690 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
692 if (!ppv) {
693 WARN("invalid parameter\n");
694 return E_INVALIDARG;
696 *ppv = NULL;
698 if (IsEqualIID(riid, &IID_IUnknown))
699 *ppv = &This->IUnknown_inner;
700 else if (IsEqualIID(riid, &IID_IDirectSound) ||
701 (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
702 *ppv = &This->IDirectSound8_iface;
703 else {
704 WARN("unknown IID %s\n", debugstr_guid(riid));
705 return E_NOINTERFACE;
708 IUnknown_AddRef((IUnknown*)*ppv);
709 return S_OK;
712 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
714 IDirectSoundImpl *This = impl_from_IUnknown(iface);
715 ULONG ref = InterlockedIncrement(&This->ref);
717 TRACE("(%p) ref=%ld\n", This, ref);
719 if(ref == 1)
720 InterlockedIncrement(&This->numIfaces);
722 return ref;
725 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
727 IDirectSoundImpl *This = impl_from_IUnknown(iface);
728 ULONG ref = InterlockedDecrement(&This->ref);
730 TRACE("(%p) ref=%ld\n", This, ref);
732 if (!ref && !InterlockedDecrement(&This->numIfaces))
733 directsound_destroy(This);
735 return ref;
738 static const IUnknownVtbl unk_vtbl =
740 IUnknownImpl_QueryInterface,
741 IUnknownImpl_AddRef,
742 IUnknownImpl_Release
745 /*******************************************************************************
746 * IDirectSound and IDirectSound8 Implementation
748 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
750 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
753 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
754 void **ppv)
756 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
757 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
758 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
761 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
763 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
764 ULONG ref = InterlockedIncrement(&This->refds);
766 TRACE("(%p) refds=%ld\n", This, ref);
768 if(ref == 1)
769 InterlockedIncrement(&This->numIfaces);
771 return ref;
774 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
776 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
777 ULONG ref = InterlockedDecrement(&(This->refds));
779 TRACE("(%p) refds=%ld\n", This, ref);
781 if (!ref && !InterlockedDecrement(&This->numIfaces))
782 directsound_destroy(This);
784 return ref;
787 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
788 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
790 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
791 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
792 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
795 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
797 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
799 TRACE("(%p, %p)\n", This, dscaps);
801 if (!This->device) {
802 WARN("not initialized\n");
803 return DSERR_UNINITIALIZED;
805 if (!dscaps) {
806 WARN("invalid parameter: dscaps = NULL\n");
807 return DSERR_INVALIDPARAM;
809 if (dscaps->dwSize < sizeof(*dscaps)) {
810 WARN("invalid parameter: dscaps->dwSize = %ld\n", dscaps->dwSize);
811 return DSERR_INVALIDPARAM;
814 dscaps->dwFlags = This->device->drvcaps.dwFlags;
815 dscaps->dwMinSecondarySampleRate = This->device->drvcaps.dwMinSecondarySampleRate;
816 dscaps->dwMaxSecondarySampleRate = This->device->drvcaps.dwMaxSecondarySampleRate;
817 dscaps->dwPrimaryBuffers = This->device->drvcaps.dwPrimaryBuffers;
818 dscaps->dwMaxHwMixingAllBuffers = This->device->drvcaps.dwMaxHwMixingAllBuffers;
819 dscaps->dwMaxHwMixingStaticBuffers = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
820 dscaps->dwMaxHwMixingStreamingBuffers = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
821 dscaps->dwFreeHwMixingAllBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
822 dscaps->dwFreeHwMixingStaticBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
823 dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
825 dscaps->dwMaxHw3DAllBuffers = This->device->drvcaps.dwMaxHw3DAllBuffers;
826 dscaps->dwMaxHw3DStaticBuffers = This->device->drvcaps.dwMaxHw3DStaticBuffers;
827 dscaps->dwMaxHw3DStreamingBuffers = This->device->drvcaps.dwMaxHw3DStreamingBuffers;
828 dscaps->dwFreeHw3DAllBuffers = This->device->drvcaps.dwFreeHw3DAllBuffers;
829 dscaps->dwFreeHw3DStaticBuffers = This->device->drvcaps.dwFreeHw3DStaticBuffers;
830 dscaps->dwFreeHw3DStreamingBuffers = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
831 dscaps->dwTotalHwMemBytes = This->device->drvcaps.dwTotalHwMemBytes;
832 dscaps->dwFreeHwMemBytes = This->device->drvcaps.dwFreeHwMemBytes;
833 dscaps->dwMaxContigFreeHwMemBytes = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
834 dscaps->dwUnlockTransferRateHwBuffers = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
835 dscaps->dwPlayCpuOverheadSwBuffers = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
837 if (TRACE_ON(dsound)) {
838 TRACE("(flags=0x%08lx:\n", dscaps->dwFlags);
839 _dump_DSCAPS(dscaps->dwFlags);
840 TRACE(")\n");
843 return DS_OK;
846 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
847 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
849 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
850 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
851 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
854 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
855 DWORD level)
857 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
858 DirectSoundDevice *device = This->device;
859 HRESULT hr = S_OK;
861 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
863 if (!device) {
864 WARN("not initialized\n");
865 return DSERR_UNINITIALIZED;
868 if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
869 WARN("level=%s not fully supported\n",
870 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
873 AcquireSRWLockExclusive(&device->buffer_list_lock);
874 EnterCriticalSection(&device->mixlock);
875 if ((level == DSSCL_WRITEPRIMARY) != (device->priolevel == DSSCL_WRITEPRIMARY))
876 hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
877 if (SUCCEEDED(hr))
878 device->priolevel = level;
879 LeaveCriticalSection(&device->mixlock);
880 ReleaseSRWLockExclusive(&device->buffer_list_lock);
881 return hr;
884 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
886 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
888 TRACE("(%p)\n", This);
890 if (!This->device) {
891 WARN("not initialized\n");
892 return DSERR_UNINITIALIZED;
895 if (This->device->priolevel < DSSCL_PRIORITY) {
896 WARN("incorrect priority level\n");
897 return DSERR_PRIOLEVELNEEDED;
899 return DS_OK;
902 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
904 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
906 TRACE("(%p, %p)\n", This, config);
908 if (!This->device) {
909 WARN("not initialized\n");
910 return DSERR_UNINITIALIZED;
912 if (!config) {
913 WARN("invalid parameter: config == NULL\n");
914 return DSERR_INVALIDPARAM;
917 WARN("not fully functional\n");
918 *config = This->device->speaker_config;
919 return DS_OK;
922 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
924 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
926 TRACE("(%p,0x%08lx)\n", This, config);
928 if (!This->device) {
929 WARN("not initialized\n");
930 return DSERR_UNINITIALIZED;
933 /* NOP on Vista and above */
935 return DS_OK;
938 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
940 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
941 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
942 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
945 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
947 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
949 TRACE("(%p, %p)\n", This, certified);
951 if (!This->device) {
952 WARN("not initialized\n");
953 return DSERR_UNINITIALIZED;
956 if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
957 *certified = DS_CERTIFIED;
958 else
959 *certified = DS_UNCERTIFIED;
961 return DS_OK;
964 static const IDirectSound8Vtbl ds8_vtbl =
966 IDirectSound8Impl_QueryInterface,
967 IDirectSound8Impl_AddRef,
968 IDirectSound8Impl_Release,
969 IDirectSound8Impl_CreateSoundBuffer,
970 IDirectSound8Impl_GetCaps,
971 IDirectSound8Impl_DuplicateSoundBuffer,
972 IDirectSound8Impl_SetCooperativeLevel,
973 IDirectSound8Impl_Compact,
974 IDirectSound8Impl_GetSpeakerConfig,
975 IDirectSound8Impl_SetSpeakerConfig,
976 IDirectSound8Impl_Initialize,
977 IDirectSound8Impl_VerifyCertification
980 HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
982 IDirectSoundImpl *obj;
983 HRESULT hr;
985 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
987 *ppv = NULL;
988 obj = calloc(1, sizeof(*obj));
989 if (!obj) {
990 WARN("out of memory\n");
991 return DSERR_OUTOFMEMORY;
994 setup_dsound_options();
996 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
997 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
998 obj->ref = 1;
999 obj->refds = 0;
1000 obj->numIfaces = 1;
1001 obj->device = NULL;
1002 obj->has_ds8 = has_ds8;
1004 /* COM aggregation supported only internally */
1005 if (outer_unk)
1006 obj->outer_unk = outer_unk;
1007 else
1008 obj->outer_unk = &obj->IUnknown_inner;
1010 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1011 IUnknown_Release(&obj->IUnknown_inner);
1013 return hr;
1016 HRESULT DSOUND_Create(REFIID riid, void **ppv)
1018 return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
1021 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
1023 return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
1026 /*******************************************************************************
1027 * DirectSoundCreate (DSOUND.1)
1029 * Creates and initializes a DirectSound interface.
1031 * PARAMS
1032 * lpcGUID [I] Address of the GUID that identifies the sound device.
1033 * ppDS [O] Address of a variable to receive the interface pointer.
1034 * pUnkOuter [I] Must be NULL.
1036 * RETURNS
1037 * Success: DS_OK
1038 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1039 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1041 HRESULT WINAPI DirectSoundCreate(
1042 LPCGUID lpcGUID,
1043 LPDIRECTSOUND *ppDS,
1044 IUnknown *pUnkOuter)
1046 HRESULT hr;
1047 LPDIRECTSOUND pDS;
1049 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1051 if (ppDS == NULL) {
1052 WARN("invalid parameter: ppDS == NULL\n");
1053 return DSERR_INVALIDPARAM;
1056 if (pUnkOuter != NULL) {
1057 WARN("invalid parameter: pUnkOuter != NULL\n");
1058 *ppDS = 0;
1059 return DSERR_INVALIDPARAM;
1062 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
1063 if (hr == DS_OK) {
1064 hr = IDirectSound_Initialize(pDS, lpcGUID);
1065 if (hr != DS_OK) {
1066 if (hr != DSERR_ALREADYINITIALIZED) {
1067 IDirectSound_Release(pDS);
1068 pDS = 0;
1069 } else
1070 hr = DS_OK;
1074 *ppDS = pDS;
1076 return hr;
1079 /*******************************************************************************
1080 * DirectSoundCreate8 (DSOUND.11)
1082 * Creates and initializes a DirectSound8 interface.
1084 * PARAMS
1085 * lpcGUID [I] Address of the GUID that identifies the sound device.
1086 * ppDS [O] Address of a variable to receive the interface pointer.
1087 * pUnkOuter [I] Must be NULL.
1089 * RETURNS
1090 * Success: DS_OK
1091 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1092 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1094 HRESULT WINAPI DirectSoundCreate8(
1095 LPCGUID lpcGUID,
1096 LPDIRECTSOUND8 *ppDS,
1097 IUnknown *pUnkOuter)
1099 HRESULT hr;
1100 LPDIRECTSOUND8 pDS;
1102 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1104 if (ppDS == NULL) {
1105 WARN("invalid parameter: ppDS == NULL\n");
1106 return DSERR_INVALIDPARAM;
1109 if (pUnkOuter != NULL) {
1110 WARN("invalid parameter: pUnkOuter != NULL\n");
1111 *ppDS = 0;
1112 return DSERR_INVALIDPARAM;
1115 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
1116 if (hr == DS_OK) {
1117 hr = IDirectSound8_Initialize(pDS, lpcGUID);
1118 if (hr != DS_OK) {
1119 if (hr != DSERR_ALREADYINITIALIZED) {
1120 IDirectSound8_Release(pDS);
1121 pDS = 0;
1122 } else
1123 hr = DS_OK;
1127 *ppDS = pDS;
1129 return hr;
1132 void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device)
1134 switch (DSSPEAKER_CONFIG(device->speaker_config)) {
1135 case DSSPEAKER_MONO:
1136 device->speaker_angles[0] = M_PI/180.0f * 0.0f;
1137 device->speaker_num[0] = 0;
1138 device->num_speakers = 1;
1139 device->lfe_channel = -1;
1140 break;
1142 case DSSPEAKER_STEREO:
1143 case DSSPEAKER_HEADPHONE:
1144 device->speaker_angles[0] = M_PI/180.0f * -90.0f;
1145 device->speaker_angles[1] = M_PI/180.0f * 90.0f;
1146 device->speaker_num[0] = 0; /* Left */
1147 device->speaker_num[1] = 1; /* Right */
1148 device->num_speakers = 2;
1149 device->lfe_channel = -1;
1150 break;
1152 case DSSPEAKER_QUAD:
1153 device->speaker_angles[0] = M_PI/180.0f * -135.0f;
1154 device->speaker_angles[1] = M_PI/180.0f * -45.0f;
1155 device->speaker_angles[2] = M_PI/180.0f * 45.0f;
1156 device->speaker_angles[3] = M_PI/180.0f * 135.0f;
1157 device->speaker_num[0] = 2; /* Rear left */
1158 device->speaker_num[1] = 0; /* Front left */
1159 device->speaker_num[2] = 1; /* Front right */
1160 device->speaker_num[3] = 3; /* Rear right */
1161 device->num_speakers = 4;
1162 device->lfe_channel = -1;
1163 break;
1165 case DSSPEAKER_5POINT1_BACK:
1166 device->speaker_angles[0] = M_PI/180.0f * -135.0f;
1167 device->speaker_angles[1] = M_PI/180.0f * -45.0f;
1168 device->speaker_angles[2] = M_PI/180.0f * 0.0f;
1169 device->speaker_angles[3] = M_PI/180.0f * 45.0f;
1170 device->speaker_angles[4] = M_PI/180.0f * 135.0f;
1171 device->speaker_angles[5] = 9999.0f;
1172 device->speaker_num[0] = 4; /* Rear left */
1173 device->speaker_num[1] = 0; /* Front left */
1174 device->speaker_num[2] = 2; /* Front centre */
1175 device->speaker_num[3] = 1; /* Front right */
1176 device->speaker_num[4] = 5; /* Rear right */
1177 device->speaker_num[5] = 3; /* LFE */
1178 device->num_speakers = 6;
1179 device->lfe_channel = 3;
1180 break;
1182 case DSSPEAKER_5POINT1_SURROUND:
1183 device->speaker_angles[0] = M_PI/180.0f * -90.0f;
1184 device->speaker_angles[1] = M_PI/180.0f * -30.0f;
1185 device->speaker_angles[2] = M_PI/180.0f * 0.0f;
1186 device->speaker_angles[3] = M_PI/180.0f * 30.0f;
1187 device->speaker_angles[4] = M_PI/180.0f * 90.0f;
1188 device->speaker_angles[5] = 9999.0f;
1189 device->speaker_num[0] = 4; /* Rear left */
1190 device->speaker_num[1] = 0; /* Front left */
1191 device->speaker_num[2] = 2; /* Front centre */
1192 device->speaker_num[3] = 1; /* Front right */
1193 device->speaker_num[4] = 5; /* Rear right */
1194 device->speaker_num[5] = 3; /* LFE */
1195 device->num_speakers = 6;
1196 device->lfe_channel = 3;
1197 break;
1199 default:
1200 WARN("unknown speaker_config %lu\n", device->speaker_config);