msvcirt: Add implementation of streambuf::sputbackc.
[wine.git] / dlls / dsound / dsound.c
blob7b93455bbf45130253b705d932f0bf531aab938c
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 "winternl.h"
34 #include "mmddk.h"
35 #include "wingdi.h"
36 #include "mmreg.h"
37 #include "ks.h"
38 #include "ksmedia.h"
39 #include "wine/debug.h"
40 #include "dsound.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;
51 BOOL has_ds8;
52 } IDirectSoundImpl;
54 static const char * dumpCooperativeLevel(DWORD level)
56 #define LE(x) case x: return #x
57 switch (level) {
58 LE(DSSCL_NORMAL);
59 LE(DSSCL_PRIORITY);
60 LE(DSSCL_EXCLUSIVE);
61 LE(DSSCL_WRITEPRIMARY);
63 #undef LE
64 return wine_dbg_sprintf("Unknown(%08x)", level);
67 static void _dump_DSCAPS(DWORD xmask) {
68 struct {
69 DWORD mask;
70 const char *name;
71 } flags[] = {
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)
78 FE(DSCAPS_EMULDRIVER)
79 FE(DSCAPS_CERTIFIED)
80 FE(DSCAPS_SECONDARYMONO)
81 FE(DSCAPS_SECONDARYSTEREO)
82 FE(DSCAPS_SECONDARY8BIT)
83 FE(DSCAPS_SECONDARY16BIT)
84 #undef FE
86 unsigned int i;
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) {
94 struct {
95 DWORD mask;
96 const char *name;
97 } flags[] = {
98 #define FE(x) { x, #x },
99 FE(DSBCAPS_PRIMARYBUFFER)
100 FE(DSBCAPS_STATIC)
101 FE(DSBCAPS_LOCHARDWARE)
102 FE(DSBCAPS_LOCSOFTWARE)
103 FE(DSBCAPS_CTRL3D)
104 FE(DSBCAPS_CTRLFREQUENCY)
105 FE(DSBCAPS_CTRLPAN)
106 FE(DSBCAPS_CTRLVOLUME)
107 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
108 FE(DSBCAPS_STICKYFOCUS)
109 FE(DSBCAPS_GLOBALFOCUS)
110 FE(DSBCAPS_GETCURRENTPOSITION2)
111 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
112 #undef FE
114 unsigned int i;
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 /*******************************************************************************
122 * DirectSoundDevice
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;
136 device->ref = 1;
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));
189 *ppDevice = device;
191 return DS_OK;
194 static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
196 ULONG ref = InterlockedIncrement(&(device->ref));
197 TRACE("(%p) ref was %d\n", device, ref - 1);
198 return ref;
201 static ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
203 HRESULT hr;
204 ULONG ref = InterlockedDecrement(&(device->ref));
205 TRACE("(%p) ref was %u\n", device, ref + 1);
206 if (!ref) {
207 int i;
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);
229 if (hr != DS_OK)
230 WARN("DSOUND_PrimaryDestroy failed\n");
232 if(device->client)
233 IAudioClient_Release(device->client);
234 if(device->render)
235 IAudioRenderClient_Release(device->render);
236 if(device->clock)
237 IAudioClock_Release(device->clock);
238 if(device->volume)
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);
250 return ref;
253 BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
254 DWORD depth, WORD channels)
256 WAVEFORMATEX fmt, *junk;
257 HRESULT hr;
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;
265 fmt.cbSize = 0;
267 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
268 if(SUCCEEDED(hr))
269 CoTaskMemFree(junk);
271 return hr == S_OK;
274 static HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
276 HRESULT hr = DS_OK;
277 GUID devGUID;
278 DirectSoundDevice *device;
279 IMMDevice *mmdevice;
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);
302 if(FAILED(hr))
303 return hr;
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);
311 *ppDevice = device;
312 LeaveCriticalSection(&DSOUND_renderers_lock);
313 return DS_OK;
317 hr = DirectSoundDevice_Create(&device);
318 if(FAILED(hr)){
319 WARN("DirectSoundDevice_Create failed\n");
320 IMMDevice_Release(mmdevice);
321 LeaveCriticalSection(&DSOUND_renderers_lock);
322 return hr;
325 device->mmdevice = mmdevice;
326 device->guid = devGUID;
327 device->sleepev = CreateEventW(0, 0, 0, 0);
329 hr = DSOUND_ReopenDevice(device, FALSE);
330 if (FAILED(hr))
332 HeapFree(GetProcessHeap(), 0, device);
333 LeaveCriticalSection(&DSOUND_renderers_lock);
334 IMMDevice_Release(mmdevice);
335 WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
336 return 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);
387 if (hr == DS_OK) {
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);
391 } else
392 WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
394 *ppDevice = device;
395 list_add_tail(&DSOUND_renderers, &device->entry);
397 LeaveCriticalSection(&DSOUND_renderers_lock);
399 return hr;
402 static HRESULT DirectSoundDevice_CreateSoundBuffer(
403 DirectSoundDevice * device,
404 LPCDSBUFFERDESC dsbd,
405 LPLPDIRECTSOUNDBUFFER ppdsb,
406 LPUNKNOWN lpunk,
407 BOOL from8)
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;
417 if (dsbd == NULL) {
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;
428 if (ppdsb == NULL) {
429 WARN("invalid parameter: ppdsb == NULL\n");
430 return DSERR_INVALIDPARAM;
432 *ppdsb = NULL;
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);
438 TRACE(")\n");
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 "
454 "primary buffer\n");
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);
462 } else {
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;
468 } else
469 WARN("primarybuffer_create() failed\n");
471 } else {
472 IDirectSoundBufferImpl * dsb;
474 if (dsbd->lpwfxFormat == NULL) {
475 WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
476 "secondary buffer\n");
477 return DSERR_INVALIDPARAM;
480 if(dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_PCM &&
481 dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_IEEE_FLOAT &&
482 dsbd->lpwfxFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
483 WARN("We can't mix this format: 0x%x\n", dsbd->lpwfxFormat->wFormatTag);
484 return E_NOTIMPL;
487 if(dsbd->lpwfxFormat->wBitsPerSample < 8 || dsbd->lpwfxFormat->wBitsPerSample % 8 != 0 ||
488 dsbd->lpwfxFormat->nChannels == 0 || dsbd->lpwfxFormat->nSamplesPerSec == 0 ||
489 dsbd->lpwfxFormat->nAvgBytesPerSec == 0 ||
490 dsbd->lpwfxFormat->nBlockAlign != dsbd->lpwfxFormat->nChannels * dsbd->lpwfxFormat->wBitsPerSample / 8) {
491 WARN("Format inconsistency\n");
492 return DSERR_INVALIDPARAM;
495 if (dsbd->lpwfxFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
497 WAVEFORMATEXTENSIBLE *pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
499 /* check if cbSize is at least 22 bytes */
500 if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
502 WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
503 return DSERR_INVALIDPARAM;
506 /* cbSize should be 22 bytes, with one possible exception */
507 if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
508 !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
509 pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
511 WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
512 return DSERR_CONTROLUNAVAIL;
515 if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
517 if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
518 FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
519 return DSERR_INVALIDPARAM;
521 if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
523 WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
524 return DSERR_INVALIDPARAM;
526 if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
528 WARN("Non-packed formats may not function : %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
532 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
533 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
534 dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
535 dsbd->lpwfxFormat->nSamplesPerSec,
536 dsbd->lpwfxFormat->nAvgBytesPerSec,
537 dsbd->lpwfxFormat->nBlockAlign,
538 dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
540 if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
541 WARN("invalid parameter: 3D buffer format must be mono\n");
542 return DSERR_INVALIDPARAM;
545 hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
546 if (dsb) {
547 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
548 if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
549 device->drvcaps.dwFreeHwMixingAllBuffers--;
550 } else
551 WARN("IDirectSoundBufferImpl_Create failed\n");
554 return hres;
557 static HRESULT DirectSoundDevice_DuplicateSoundBuffer(
558 DirectSoundDevice * device,
559 LPDIRECTSOUNDBUFFER psb,
560 LPLPDIRECTSOUNDBUFFER ppdsb)
562 HRESULT hres = DS_OK;
563 IDirectSoundBufferImpl* dsb;
564 TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
566 if (device == NULL) {
567 WARN("not initialized\n");
568 return DSERR_UNINITIALIZED;
571 if (psb == NULL) {
572 WARN("invalid parameter: psb == NULL\n");
573 return DSERR_INVALIDPARAM;
576 if (ppdsb == NULL) {
577 WARN("invalid parameter: ppdsb == NULL\n");
578 return DSERR_INVALIDPARAM;
581 /* make sure we have a secondary buffer */
582 if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
583 WARN("trying to duplicate primary buffer\n");
584 *ppdsb = NULL;
585 return DSERR_INVALIDCALL;
588 /* duplicate the actual buffer implementation */
589 hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
590 if (hres == DS_OK)
591 *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
592 else
593 WARN("IDirectSoundBufferImpl_Duplicate failed\n");
595 return hres;
599 * Add secondary buffer to buffer list.
600 * Gets exclusive access to buffer for writing.
602 HRESULT DirectSoundDevice_AddBuffer(
603 DirectSoundDevice * device,
604 IDirectSoundBufferImpl * pDSB)
606 IDirectSoundBufferImpl **newbuffers;
607 HRESULT hr = DS_OK;
609 TRACE("(%p, %p)\n", device, pDSB);
611 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
613 if (device->buffers)
614 newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
615 else
616 newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
618 if (newbuffers) {
619 device->buffers = newbuffers;
620 device->buffers[device->nrofbuffers] = pDSB;
621 device->nrofbuffers++;
622 TRACE("buffer count is now %d\n", device->nrofbuffers);
623 } else {
624 ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
625 hr = DSERR_OUTOFMEMORY;
628 RtlReleaseResource(&(device->buffer_list_lock));
630 return hr;
634 * Remove secondary buffer from buffer list.
635 * Gets exclusive access to buffer for writing.
637 void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
639 int i;
641 TRACE("(%p, %p)\n", device, pDSB);
643 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
645 if (device->nrofbuffers == 1) {
646 assert(device->buffers[0] == pDSB);
647 HeapFree(GetProcessHeap(), 0, device->buffers);
648 device->buffers = NULL;
649 } else {
650 for (i = 0; i < device->nrofbuffers; i++) {
651 if (device->buffers[i] == pDSB) {
652 /* Put the last buffer of the list in the (now empty) position */
653 device->buffers[i] = device->buffers[device->nrofbuffers - 1];
654 break;
658 device->nrofbuffers--;
659 TRACE("buffer count is now %d\n", device->nrofbuffers);
661 RtlReleaseResource(&(device->buffer_list_lock));
664 /*******************************************************************************
665 * IUnknown Implementation for DirectSound
668 static void directsound_destroy(IDirectSoundImpl *This)
670 if (This->device)
671 DirectSoundDevice_Release(This->device);
672 HeapFree(GetProcessHeap(),0,This);
673 TRACE("(%p) released\n", This);
676 static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
678 return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
681 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
683 IDirectSoundImpl *This = impl_from_IUnknown(iface);
685 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
687 if (!ppv) {
688 WARN("invalid parameter\n");
689 return E_INVALIDARG;
691 *ppv = NULL;
693 if (IsEqualIID(riid, &IID_IUnknown))
694 *ppv = &This->IUnknown_inner;
695 else if (IsEqualIID(riid, &IID_IDirectSound) ||
696 (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
697 *ppv = &This->IDirectSound8_iface;
698 else {
699 WARN("unknown IID %s\n", debugstr_guid(riid));
700 return E_NOINTERFACE;
703 IUnknown_AddRef((IUnknown*)*ppv);
704 return S_OK;
707 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
709 IDirectSoundImpl *This = impl_from_IUnknown(iface);
710 ULONG ref = InterlockedIncrement(&This->ref);
712 TRACE("(%p) ref=%d\n", This, ref);
714 if(ref == 1)
715 InterlockedIncrement(&This->numIfaces);
717 return ref;
720 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
722 IDirectSoundImpl *This = impl_from_IUnknown(iface);
723 ULONG ref = InterlockedDecrement(&This->ref);
725 TRACE("(%p) ref=%d\n", This, ref);
727 if (!ref && !InterlockedDecrement(&This->numIfaces))
728 directsound_destroy(This);
730 return ref;
733 static const IUnknownVtbl unk_vtbl =
735 IUnknownImpl_QueryInterface,
736 IUnknownImpl_AddRef,
737 IUnknownImpl_Release
740 /*******************************************************************************
741 * IDirectSound and IDirectSound8 Implementation
743 static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
745 return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
748 static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
749 void **ppv)
751 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
752 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
753 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
756 static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
758 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
759 ULONG ref = InterlockedIncrement(&This->refds);
761 TRACE("(%p) refds=%d\n", This, ref);
763 if(ref == 1)
764 InterlockedIncrement(&This->numIfaces);
766 return ref;
769 static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
771 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
772 ULONG ref = InterlockedDecrement(&(This->refds));
774 TRACE("(%p) refds=%d\n", This, ref);
776 if (!ref && !InterlockedDecrement(&This->numIfaces))
777 directsound_destroy(This);
779 return ref;
782 static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
783 const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
785 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
786 TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
787 return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
790 static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
792 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
794 TRACE("(%p, %p)\n", This, dscaps);
796 if (!This->device) {
797 WARN("not initialized\n");
798 return DSERR_UNINITIALIZED;
800 if (!dscaps) {
801 WARN("invalid parameter: dscaps = NULL\n");
802 return DSERR_INVALIDPARAM;
804 if (dscaps->dwSize < sizeof(*dscaps)) {
805 WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
806 return DSERR_INVALIDPARAM;
809 dscaps->dwFlags = This->device->drvcaps.dwFlags;
810 dscaps->dwMinSecondarySampleRate = This->device->drvcaps.dwMinSecondarySampleRate;
811 dscaps->dwMaxSecondarySampleRate = This->device->drvcaps.dwMaxSecondarySampleRate;
812 dscaps->dwPrimaryBuffers = This->device->drvcaps.dwPrimaryBuffers;
813 dscaps->dwMaxHwMixingAllBuffers = This->device->drvcaps.dwMaxHwMixingAllBuffers;
814 dscaps->dwMaxHwMixingStaticBuffers = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
815 dscaps->dwMaxHwMixingStreamingBuffers = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
816 dscaps->dwFreeHwMixingAllBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
817 dscaps->dwFreeHwMixingStaticBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
818 dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingAllBuffers;
820 dscaps->dwMaxHw3DAllBuffers = This->device->drvcaps.dwMaxHw3DAllBuffers;
821 dscaps->dwMaxHw3DStaticBuffers = This->device->drvcaps.dwMaxHw3DStaticBuffers;
822 dscaps->dwMaxHw3DStreamingBuffers = This->device->drvcaps.dwMaxHw3DStreamingBuffers;
823 dscaps->dwFreeHw3DAllBuffers = This->device->drvcaps.dwFreeHw3DAllBuffers;
824 dscaps->dwFreeHw3DStaticBuffers = This->device->drvcaps.dwFreeHw3DStaticBuffers;
825 dscaps->dwFreeHw3DStreamingBuffers = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
826 dscaps->dwTotalHwMemBytes = This->device->drvcaps.dwTotalHwMemBytes;
827 dscaps->dwFreeHwMemBytes = This->device->drvcaps.dwFreeHwMemBytes;
828 dscaps->dwMaxContigFreeHwMemBytes = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
829 dscaps->dwUnlockTransferRateHwBuffers = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
830 dscaps->dwPlayCpuOverheadSwBuffers = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
832 if (TRACE_ON(dsound)) {
833 TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
834 _dump_DSCAPS(dscaps->dwFlags);
835 TRACE(")\n");
838 return DS_OK;
841 static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
842 IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
844 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
845 TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
846 return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
849 static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
850 DWORD level)
852 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
853 DirectSoundDevice *device = This->device;
854 DWORD oldlevel;
855 HRESULT hr = S_OK;
857 TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
859 if (!device) {
860 WARN("not initialized\n");
861 return DSERR_UNINITIALIZED;
864 if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
865 WARN("level=%s not fully supported\n",
866 level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
869 RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
870 EnterCriticalSection(&device->mixlock);
871 oldlevel = device->priolevel;
872 device->priolevel = level;
873 if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
874 hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
875 if (FAILED(hr))
876 device->priolevel = oldlevel;
877 else
878 DSOUND_PrimaryOpen(device);
880 LeaveCriticalSection(&device->mixlock);
881 RtlReleaseResource(&device->buffer_list_lock);
882 return hr;
885 static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
887 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
889 TRACE("(%p)\n", This);
891 if (!This->device) {
892 WARN("not initialized\n");
893 return DSERR_UNINITIALIZED;
896 if (This->device->priolevel < DSSCL_PRIORITY) {
897 WARN("incorrect priority level\n");
898 return DSERR_PRIOLEVELNEEDED;
900 return DS_OK;
903 static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
905 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
907 TRACE("(%p, %p)\n", This, config);
909 if (!This->device) {
910 WARN("not initialized\n");
911 return DSERR_UNINITIALIZED;
913 if (!config) {
914 WARN("invalid parameter: config == NULL\n");
915 return DSERR_INVALIDPARAM;
918 WARN("not fully functional\n");
919 *config = This->device->speaker_config;
920 return DS_OK;
923 static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
925 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
927 TRACE("(%p,0x%08x)\n", This, config);
929 if (!This->device) {
930 WARN("not initialized\n");
931 return DSERR_UNINITIALIZED;
934 /* NOP on Vista and above */
936 return DS_OK;
939 static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
941 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
942 TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
943 return DirectSoundDevice_Initialize(&This->device, lpcGuid);
946 static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
948 IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
950 TRACE("(%p, %p)\n", This, certified);
952 if (!This->device) {
953 WARN("not initialized\n");
954 return DSERR_UNINITIALIZED;
957 if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
958 *certified = DS_CERTIFIED;
959 else
960 *certified = DS_UNCERTIFIED;
962 return DS_OK;
965 static const IDirectSound8Vtbl ds8_vtbl =
967 IDirectSound8Impl_QueryInterface,
968 IDirectSound8Impl_AddRef,
969 IDirectSound8Impl_Release,
970 IDirectSound8Impl_CreateSoundBuffer,
971 IDirectSound8Impl_GetCaps,
972 IDirectSound8Impl_DuplicateSoundBuffer,
973 IDirectSound8Impl_SetCooperativeLevel,
974 IDirectSound8Impl_Compact,
975 IDirectSound8Impl_GetSpeakerConfig,
976 IDirectSound8Impl_SetSpeakerConfig,
977 IDirectSound8Impl_Initialize,
978 IDirectSound8Impl_VerifyCertification
981 HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
983 IDirectSoundImpl *obj;
984 HRESULT hr;
986 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
988 *ppv = NULL;
989 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
990 if (!obj) {
991 WARN("out of memory\n");
992 return DSERR_OUTOFMEMORY;
995 setup_dsound_options();
997 obj->IUnknown_inner.lpVtbl = &unk_vtbl;
998 obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
999 obj->ref = 1;
1000 obj->refds = 0;
1001 obj->numIfaces = 1;
1002 obj->device = NULL;
1003 obj->has_ds8 = has_ds8;
1005 /* COM aggregation supported only internally */
1006 if (outer_unk)
1007 obj->outer_unk = outer_unk;
1008 else
1009 obj->outer_unk = &obj->IUnknown_inner;
1011 hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
1012 IUnknown_Release(&obj->IUnknown_inner);
1014 return hr;
1017 HRESULT DSOUND_Create(REFIID riid, void **ppv)
1019 return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
1022 HRESULT DSOUND_Create8(REFIID riid, void **ppv)
1024 return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
1027 /*******************************************************************************
1028 * DirectSoundCreate (DSOUND.1)
1030 * Creates and initializes a DirectSound interface.
1032 * PARAMS
1033 * lpcGUID [I] Address of the GUID that identifies the sound device.
1034 * ppDS [O] Address of a variable to receive the interface pointer.
1035 * pUnkOuter [I] Must be NULL.
1037 * RETURNS
1038 * Success: DS_OK
1039 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1040 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1042 HRESULT WINAPI DirectSoundCreate(
1043 LPCGUID lpcGUID,
1044 LPDIRECTSOUND *ppDS,
1045 IUnknown *pUnkOuter)
1047 HRESULT hr;
1048 LPDIRECTSOUND pDS;
1050 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1052 if (ppDS == NULL) {
1053 WARN("invalid parameter: ppDS == NULL\n");
1054 return DSERR_INVALIDPARAM;
1057 if (pUnkOuter != NULL) {
1058 WARN("invalid parameter: pUnkOuter != NULL\n");
1059 *ppDS = 0;
1060 return DSERR_INVALIDPARAM;
1063 hr = DSOUND_Create(&IID_IDirectSound, (void **)&pDS);
1064 if (hr == DS_OK) {
1065 hr = IDirectSound_Initialize(pDS, lpcGUID);
1066 if (hr != DS_OK) {
1067 if (hr != DSERR_ALREADYINITIALIZED) {
1068 IDirectSound_Release(pDS);
1069 pDS = 0;
1070 } else
1071 hr = DS_OK;
1075 *ppDS = pDS;
1077 return hr;
1080 /*******************************************************************************
1081 * DirectSoundCreate8 (DSOUND.11)
1083 * Creates and initializes a DirectSound8 interface.
1085 * PARAMS
1086 * lpcGUID [I] Address of the GUID that identifies the sound device.
1087 * ppDS [O] Address of a variable to receive the interface pointer.
1088 * pUnkOuter [I] Must be NULL.
1090 * RETURNS
1091 * Success: DS_OK
1092 * Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
1093 * DSERR_NODRIVER, DSERR_OUTOFMEMORY
1095 HRESULT WINAPI DirectSoundCreate8(
1096 LPCGUID lpcGUID,
1097 LPDIRECTSOUND8 *ppDS,
1098 IUnknown *pUnkOuter)
1100 HRESULT hr;
1101 LPDIRECTSOUND8 pDS;
1103 TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
1105 if (ppDS == NULL) {
1106 WARN("invalid parameter: ppDS == NULL\n");
1107 return DSERR_INVALIDPARAM;
1110 if (pUnkOuter != NULL) {
1111 WARN("invalid parameter: pUnkOuter != NULL\n");
1112 *ppDS = 0;
1113 return DSERR_INVALIDPARAM;
1116 hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&pDS);
1117 if (hr == DS_OK) {
1118 hr = IDirectSound8_Initialize(pDS, lpcGUID);
1119 if (hr != DS_OK) {
1120 if (hr != DSERR_ALREADYINITIALIZED) {
1121 IDirectSound8_Release(pDS);
1122 pDS = 0;
1123 } else
1124 hr = DS_OK;
1128 *ppDS = pDS;
1130 return hr;
1133 void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device)
1135 switch (DSSPEAKER_CONFIG(device->speaker_config)) {
1136 case DSSPEAKER_MONO:
1137 device->speaker_angles[0] = M_PI/180.0f * 0.0f;
1138 device->speaker_num[0] = 0;
1139 device->num_speakers = 1;
1140 device->lfe_channel = -1;
1141 break;
1143 case DSSPEAKER_STEREO:
1144 case DSSPEAKER_HEADPHONE:
1145 device->speaker_angles[0] = M_PI/180.0f * -90.0f;
1146 device->speaker_angles[1] = M_PI/180.0f * 90.0f;
1147 device->speaker_num[0] = 0; /* Left */
1148 device->speaker_num[1] = 1; /* Right */
1149 device->num_speakers = 2;
1150 device->lfe_channel = -1;
1151 break;
1153 case DSSPEAKER_QUAD:
1154 device->speaker_angles[0] = M_PI/180.0f * -135.0f;
1155 device->speaker_angles[1] = M_PI/180.0f * -45.0f;
1156 device->speaker_angles[2] = M_PI/180.0f * 45.0f;
1157 device->speaker_angles[3] = M_PI/180.0f * 135.0f;
1158 device->speaker_num[0] = 2; /* Rear left */
1159 device->speaker_num[1] = 0; /* Front left */
1160 device->speaker_num[2] = 1; /* Front right */
1161 device->speaker_num[3] = 3; /* Rear right */
1162 device->num_speakers = 4;
1163 device->lfe_channel = -1;
1164 break;
1166 case DSSPEAKER_5POINT1_BACK:
1167 device->speaker_angles[0] = M_PI/180.0f * -135.0f;
1168 device->speaker_angles[1] = M_PI/180.0f * -45.0f;
1169 device->speaker_angles[2] = M_PI/180.0f * 0.0f;
1170 device->speaker_angles[3] = M_PI/180.0f * 45.0f;
1171 device->speaker_angles[4] = M_PI/180.0f * 135.0f;
1172 device->speaker_angles[5] = 9999.0f;
1173 device->speaker_num[0] = 4; /* Rear left */
1174 device->speaker_num[1] = 0; /* Front left */
1175 device->speaker_num[2] = 2; /* Front centre */
1176 device->speaker_num[3] = 1; /* Front right */
1177 device->speaker_num[4] = 5; /* Rear right */
1178 device->speaker_num[5] = 3; /* LFE */
1179 device->num_speakers = 6;
1180 device->lfe_channel = 3;
1181 break;
1183 case DSSPEAKER_5POINT1_SURROUND:
1184 device->speaker_angles[0] = M_PI/180.0f * -90.0f;
1185 device->speaker_angles[1] = M_PI/180.0f * -30.0f;
1186 device->speaker_angles[2] = M_PI/180.0f * 0.0f;
1187 device->speaker_angles[3] = M_PI/180.0f * 30.0f;
1188 device->speaker_angles[4] = M_PI/180.0f * 90.0f;
1189 device->speaker_angles[5] = 9999.0f;
1190 device->speaker_num[0] = 4; /* Rear left */
1191 device->speaker_num[1] = 0; /* Front left */
1192 device->speaker_num[2] = 2; /* Front centre */
1193 device->speaker_num[3] = 1; /* Front right */
1194 device->speaker_num[4] = 5; /* Rear right */
1195 device->speaker_num[5] = 3; /* LFE */
1196 device->num_speakers = 6;
1197 device->lfe_channel = 3;
1198 break;
1200 default:
1201 WARN("unknown speaker_config %u\n", device->speaker_config);