Sync up with trunk r61578.
[reactos.git] / dll / directx / wine / dsound / primary.c
1 /* DirectSound
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * TODO:
22 * When PrimarySetFormat (via ReopenDevice or PrimaryOpen) fails,
23 * it leaves dsound in unusable (not really open) state.
24 */
25
26 #include <stdarg.h>
27
28 #define WIN32_NO_STATUS
29 #define _INC_WINDOWS
30 #define COM_NO_WINDOWS_H
31 #define COBJMACROS
32 #define NONAMELESSSTRUCT
33 #define NONAMELESSUNION
34 //#include "windef.h"
35 //#include "winbase.h"
36 //#include "winuser.h"
37 //#include "mmsystem.h"
38 #include <winternl.h>
39 #include <mmddk.h>
40 #include <wine/debug.h>
41 #include <dsound.h>
42 #include "dsound_private.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
45
46 static DWORD DSOUND_fraglen(DirectSoundDevice *device)
47 {
48 REFERENCE_TIME period;
49 HRESULT hr;
50 DWORD ret;
51
52 hr = IAudioClient_GetDevicePeriod(device->client, &period, NULL);
53 if(FAILED(hr)){
54 /* just guess at 10ms */
55 WARN("GetDevicePeriod failed: %08x\n", hr);
56 ret = MulDiv(device->pwfx->nBlockAlign, device->pwfx->nSamplesPerSec, 100);
57 }else
58 ret = MulDiv(device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign, period, 10000000);
59
60 ret -= ret % device->pwfx->nBlockAlign;
61 return ret;
62 }
63
64 static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client,
65 BOOL forcewave, WAVEFORMATEX **wfx)
66 {
67 WAVEFORMATEXTENSIBLE *retwfe = NULL;
68 WAVEFORMATEX *w;
69 HRESULT hr;
70
71 if (!forcewave) {
72 WAVEFORMATEXTENSIBLE *mixwfe;
73 hr = IAudioClient_GetMixFormat(client, (WAVEFORMATEX**)&mixwfe);
74
75 if (FAILED(hr))
76 return hr;
77
78 if (mixwfe->Format.nChannels > 2) {
79 static int once;
80 if (!once++)
81 FIXME("Limiting channels to 2 due to lack of multichannel support\n");
82
83 mixwfe->Format.nChannels = 2;
84 mixwfe->Format.nBlockAlign = mixwfe->Format.nChannels * mixwfe->Format.wBitsPerSample / 8;
85 mixwfe->Format.nAvgBytesPerSec = mixwfe->Format.nSamplesPerSec * mixwfe->Format.nBlockAlign;
86 mixwfe->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
87 }
88
89 if (!IsEqualGUID(&mixwfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
90 WAVEFORMATEXTENSIBLE testwfe = *mixwfe;
91
92 testwfe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
93 testwfe.Samples.wValidBitsPerSample = testwfe.Format.wBitsPerSample = 32;
94 testwfe.Format.nBlockAlign = testwfe.Format.nChannels * testwfe.Format.wBitsPerSample / 8;
95 testwfe.Format.nAvgBytesPerSec = testwfe.Format.nSamplesPerSec * testwfe.Format.nBlockAlign;
96
97 if (FAILED(IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &testwfe.Format, (WAVEFORMATEX**)&retwfe)))
98 w = DSOUND_CopyFormat(&mixwfe->Format);
99 else if (retwfe)
100 w = DSOUND_CopyFormat(&retwfe->Format);
101 else
102 w = DSOUND_CopyFormat(&testwfe.Format);
103 CoTaskMemFree(retwfe);
104 retwfe = NULL;
105 } else
106 w = DSOUND_CopyFormat(&mixwfe->Format);
107 CoTaskMemFree(mixwfe);
108 } else if (device->primary_pwfx->wFormatTag == WAVE_FORMAT_PCM ||
109 device->primary_pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
110 WAVEFORMATEX *wi = device->primary_pwfx;
111 WAVEFORMATEXTENSIBLE *wfe;
112
113 /* Convert to WAVEFORMATEXTENSIBLE */
114 w = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
115 wfe = (WAVEFORMATEXTENSIBLE*)w;
116 if (!wfe)
117 return DSERR_OUTOFMEMORY;
118
119 wfe->Format = *wi;
120 w->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
121 w->cbSize = sizeof(*wfe) - sizeof(*w);
122 w->nBlockAlign = w->nChannels * w->wBitsPerSample / 8;
123 w->nAvgBytesPerSec = w->nSamplesPerSec * w->nBlockAlign;
124
125 wfe->dwChannelMask = 0;
126 if (wi->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
127 w->wBitsPerSample = 32;
128 wfe->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
129 } else
130 wfe->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
131 wfe->Samples.wValidBitsPerSample = w->wBitsPerSample;
132 } else
133 w = DSOUND_CopyFormat(device->primary_pwfx);
134
135 if (!w)
136 return DSERR_OUTOFMEMORY;
137
138 hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, w, (WAVEFORMATEX**)&retwfe);
139 if (retwfe) {
140 memcpy(w, retwfe, sizeof(WAVEFORMATEX) + retwfe->Format.cbSize);
141 CoTaskMemFree(retwfe);
142 }
143 if (FAILED(hr)) {
144 WARN("IsFormatSupported failed: %08x\n", hr);
145 HeapFree(GetProcessHeap(), 0, w);
146 return hr;
147 }
148 *wfx = w;
149 return S_OK;
150 }
151
152 HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
153 {
154 UINT prebuf_frames;
155 REFERENCE_TIME prebuf_rt;
156 WAVEFORMATEX *wfx = NULL;
157 HRESULT hres;
158 REFERENCE_TIME period;
159 DWORD period_ms;
160
161 TRACE("(%p, %d)\n", device, forcewave);
162
163 if(device->client){
164 IAudioClient_Release(device->client);
165 device->client = NULL;
166 }
167 if(device->render){
168 IAudioRenderClient_Release(device->render);
169 device->render = NULL;
170 }
171 if(device->clock){
172 IAudioClock_Release(device->clock);
173 device->clock = NULL;
174 }
175 if(device->volume){
176 IAudioStreamVolume_Release(device->volume);
177 device->volume = NULL;
178 }
179
180 hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
181 CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
182 if(FAILED(hres)) {
183 WARN("Activate failed: %08x\n", hres);
184 return hres;
185 }
186
187 hres = DSOUND_WaveFormat(device, device->client, forcewave, &wfx);
188 if (FAILED(hres)) {
189 IAudioClient_Release(device->client);
190 device->client = NULL;
191 return hres;
192 }
193 HeapFree(GetProcessHeap(), 0, device->pwfx);
194 device->pwfx = wfx;
195
196 prebuf_frames = device->prebuf * DSOUND_fraglen(device) / device->pwfx->nBlockAlign;
197 prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec;
198
199 hres = IAudioClient_Initialize(device->client,
200 AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
201 AUDCLNT_STREAMFLAGS_EVENTCALLBACK, prebuf_rt, 0, device->pwfx, NULL);
202 if(FAILED(hres)){
203 IAudioClient_Release(device->client);
204 device->client = NULL;
205 WARN("Initialize failed: %08x\n", hres);
206 return hres;
207 }
208 IAudioClient_SetEventHandle(device->client, device->sleepev);
209
210 hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
211 (void**)&device->render);
212 if(FAILED(hres)){
213 IAudioClient_Release(device->client);
214 device->client = NULL;
215 WARN("GetService failed: %08x\n", hres);
216 return hres;
217 }
218
219 hres = IAudioClient_GetService(device->client, &IID_IAudioClock,
220 (void**)&device->clock);
221 if(FAILED(hres)){
222 IAudioClient_Release(device->client);
223 IAudioRenderClient_Release(device->render);
224 device->client = NULL;
225 device->render = NULL;
226 WARN("GetService failed: %08x\n", hres);
227 return hres;
228 }
229
230 hres = IAudioClient_GetService(device->client, &IID_IAudioStreamVolume,
231 (void**)&device->volume);
232 if(FAILED(hres)){
233 IAudioClient_Release(device->client);
234 IAudioRenderClient_Release(device->render);
235 IAudioClock_Release(device->clock);
236 device->client = NULL;
237 device->render = NULL;
238 device->clock = NULL;
239 WARN("GetService failed: %08x\n", hres);
240 return hres;
241 }
242
243 /* Now kick off the timer so the event fires periodically */
244 hres = IAudioClient_Start(device->client);
245 if (FAILED(hres))
246 WARN("starting failed with %08x\n", hres);
247
248 hres = IAudioClient_GetStreamLatency(device->client, &period);
249 if (FAILED(hres)) {
250 WARN("GetStreamLatency failed with %08x\n", hres);
251 period_ms = 10;
252 } else
253 period_ms = (period + 9999) / 10000;
254 TRACE("period %u ms fraglen %u prebuf %u\n", period_ms, device->fraglen, device->prebuf);
255
256 if (period_ms < 3)
257 device->sleeptime = 5;
258 else
259 device->sleeptime = period_ms * 5 / 2;
260
261 return S_OK;
262 }
263
264 HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
265 {
266 IDirectSoundBufferImpl** dsb = device->buffers;
267 LPBYTE newbuf;
268 int i;
269
270 TRACE("(%p)\n", device);
271
272 device->fraglen = DSOUND_fraglen(device);
273
274 /* on original windows, the buffer it set to a fixed size, no matter what the settings are.
275 on windows this size is always fixed (tested on win-xp) */
276 if (!device->buflen)
277 device->buflen = ds_hel_buflen;
278 device->buflen -= device->buflen % device->pwfx->nBlockAlign;
279 while(device->buflen < device->fraglen * device->prebuf){
280 device->buflen += ds_hel_buflen;
281 device->buflen -= device->buflen % device->pwfx->nBlockAlign;
282 }
283
284 HeapFree(GetProcessHeap(), 0, device->mix_buffer);
285 device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
286 device->mix_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, device->mix_buffer_len);
287 if (!device->mix_buffer)
288 return DSERR_OUTOFMEMORY;
289
290 if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
291 else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
292
293 /* reallocate emulated primary buffer */
294 if (device->buffer)
295 newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer, device->buflen);
296 else
297 newbuf = HeapAlloc(GetProcessHeap(),0, device->buflen);
298
299 if (!newbuf) {
300 ERR("failed to allocate primary buffer\n");
301 return DSERR_OUTOFMEMORY;
302 /* but the old buffer might still exist and must be re-prepared */
303 }
304
305 device->writelead = (device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign;
306
307 device->buffer = newbuf;
308
309 TRACE("buflen: %u, fraglen: %u, mix_buffer_len: %u\n",
310 device->buflen, device->fraglen, device->mix_buffer_len);
311
312 if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
313 (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
314 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
315 &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
316 device->normfunction = normfunctions[4];
317 else
318 device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
319
320 FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
321 FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
322 device->playpos = 0;
323
324 if (device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
325 (device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
326 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
327 device->normfunction = normfunctions[4];
328 else
329 device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
330
331 for (i = 0; i < device->nrofbuffers; i++) {
332 RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE);
333 DSOUND_RecalcFormat(dsb[i]);
334 RtlReleaseResource(&dsb[i]->lock);
335 }
336
337 return DS_OK;
338 }
339
340
341 static void DSOUND_PrimaryClose(DirectSoundDevice *device)
342 {
343 HRESULT hr;
344
345 TRACE("(%p)\n", device);
346
347 if(device->client){
348 hr = IAudioClient_Stop(device->client);
349 if(FAILED(hr))
350 WARN("Stop failed: %08x\n", hr);
351 }
352
353 /* clear the queue */
354 device->in_mmdev_bytes = 0;
355 }
356
357 HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
358 {
359 HRESULT err = DS_OK;
360 TRACE("(%p)\n", device);
361
362 device->buflen = ds_hel_buflen;
363 err = DSOUND_PrimaryOpen(device);
364
365 if (err != DS_OK) {
366 WARN("DSOUND_PrimaryOpen failed\n");
367 return err;
368 }
369
370 device->state = STATE_STOPPED;
371 return DS_OK;
372 }
373
374 HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
375 {
376 TRACE("(%p)\n", device);
377
378 /* **** */
379 EnterCriticalSection(&(device->mixlock));
380
381 DSOUND_PrimaryClose(device);
382
383 if(device->primary && (device->primary->ref || device->primary->numIfaces))
384 WARN("Destroying primary buffer while references held (%u %u)\n", device->primary->ref, device->primary->numIfaces);
385
386 HeapFree(GetProcessHeap(), 0, device->primary);
387 device->primary = NULL;
388
389 HeapFree(GetProcessHeap(),0,device->primary_pwfx);
390 HeapFree(GetProcessHeap(),0,device->pwfx);
391 device->pwfx=NULL;
392
393 LeaveCriticalSection(&(device->mixlock));
394 /* **** */
395
396 return DS_OK;
397 }
398
399 HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
400 {
401 HRESULT hr;
402
403 TRACE("(%p)\n", device);
404
405 hr = IAudioClient_Start(device->client);
406 if(FAILED(hr) && hr != AUDCLNT_E_NOT_STOPPED){
407 WARN("Start failed: %08x\n", hr);
408 return hr;
409 }
410
411 return DS_OK;
412 }
413
414 HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
415 {
416 HRESULT hr;
417
418 TRACE("(%p)\n", device);
419
420 hr = IAudioClient_Stop(device->client);
421 if(FAILED(hr)){
422 WARN("Stop failed: %08x\n", hr);
423 return hr;
424 }
425
426 return DS_OK;
427 }
428
429 HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos)
430 {
431 TRACE("(%p,%p,%p)\n", device, playpos, writepos);
432
433 /* check if playpos was requested */
434 if (playpos)
435 *playpos = device->playing_offs_bytes;
436
437 /* check if writepos was requested */
438 if (writepos)
439 /* the writepos is the first non-queued position */
440 *writepos = (device->playing_offs_bytes + device->in_mmdev_bytes) % device->buflen;
441
442 TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:-1, writepos?*writepos:-1, device, GetTickCount());
443 return DS_OK;
444 }
445
446 WAVEFORMATEX *DSOUND_CopyFormat(const WAVEFORMATEX *wfex)
447 {
448 WAVEFORMATEX *pwfx;
449 if(wfex->wFormatTag == WAVE_FORMAT_PCM){
450 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX));
451 CopyMemory(pwfx, wfex, sizeof(PCMWAVEFORMAT));
452 pwfx->cbSize = 0;
453 }else{
454 pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEX) + wfex->cbSize);
455 CopyMemory(pwfx, wfex, sizeof(WAVEFORMATEX) + wfex->cbSize);
456 }
457
458 if(pwfx->wFormatTag == WAVE_FORMAT_PCM ||
459 (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
460 IsEqualGUID(&((const WAVEFORMATEXTENSIBLE*)pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))
461 pwfx->nBlockAlign = (pwfx->nChannels * pwfx->wBitsPerSample) / 8;
462
463 return pwfx;
464 }
465
466 HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passed_fmt)
467 {
468 HRESULT err = S_OK;
469 WAVEFORMATEX *old_fmt;
470 WAVEFORMATEXTENSIBLE *fmtex, *passed_fmtex = (WAVEFORMATEXTENSIBLE*)passed_fmt;
471 BOOL forced = (device->priolevel == DSSCL_WRITEPRIMARY);
472
473 TRACE("(%p,%p)\n", device, passed_fmt);
474
475 if (device->priolevel == DSSCL_NORMAL) {
476 WARN("failed priority check!\n");
477 return DSERR_PRIOLEVELNEEDED;
478 }
479
480 /* Let's be pedantic! */
481 if (passed_fmt == NULL) {
482 WARN("invalid parameter: passed_fmt==NULL!\n");
483 return DSERR_INVALIDPARAM;
484 }
485 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
486 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
487 passed_fmt->wFormatTag, passed_fmt->nChannels, passed_fmt->nSamplesPerSec,
488 passed_fmt->nAvgBytesPerSec, passed_fmt->nBlockAlign,
489 passed_fmt->wBitsPerSample, passed_fmt->cbSize);
490
491 if(passed_fmt->wBitsPerSample < 8 || passed_fmt->wBitsPerSample % 8 != 0 ||
492 passed_fmt->nChannels == 0 || passed_fmt->nSamplesPerSec == 0 ||
493 passed_fmt->nAvgBytesPerSec == 0 ||
494 passed_fmt->nBlockAlign != passed_fmt->nChannels * passed_fmt->wBitsPerSample / 8)
495 return DSERR_INVALIDPARAM;
496
497 if(passed_fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
498 if(passed_fmtex->Samples.wValidBitsPerSample > passed_fmtex->Format.wBitsPerSample)
499 return DSERR_INVALIDPARAM;
500 }
501
502 /* **** */
503 RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
504 EnterCriticalSection(&(device->mixlock));
505
506 if (device->priolevel == DSSCL_WRITEPRIMARY) {
507 old_fmt = device->primary_pwfx;
508 device->primary_pwfx = DSOUND_CopyFormat(passed_fmt);
509 fmtex = (WAVEFORMATEXTENSIBLE *)device->primary_pwfx;
510 if (device->primary_pwfx == NULL) {
511 err = DSERR_OUTOFMEMORY;
512 goto out;
513 }
514
515 if (fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
516 fmtex->Samples.wValidBitsPerSample == 0) {
517 TRACE("Correcting 0 valid bits per sample\n");
518 fmtex->Samples.wValidBitsPerSample = fmtex->Format.wBitsPerSample;
519 }
520
521 DSOUND_PrimaryClose(device);
522
523 err = DSOUND_ReopenDevice(device, forced);
524 if (FAILED(err)) {
525 ERR("No formats could be opened\n");
526 goto done;
527 }
528
529 err = DSOUND_PrimaryOpen(device);
530 if (err != DS_OK) {
531 ERR("DSOUND_PrimaryOpen failed\n");
532 goto done;
533 }
534
535 done:
536 if (err != DS_OK)
537 device->primary_pwfx = old_fmt;
538 else
539 HeapFree(GetProcessHeap(), 0, old_fmt);
540 } else {
541 HeapFree(GetProcessHeap(), 0, device->primary_pwfx);
542 device->primary_pwfx = DSOUND_CopyFormat(passed_fmt);
543 }
544
545 out:
546 LeaveCriticalSection(&(device->mixlock));
547 RtlReleaseResource(&(device->buffer_list_lock));
548 /* **** */
549
550 return err;
551 }
552
553 /*******************************************************************************
554 * PrimaryBuffer
555 */
556 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer(IDirectSoundBuffer *iface)
557 {
558 /* IDirectSoundBuffer and IDirectSoundBuffer8 use the same iface. */
559 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
560 }
561
562 /* This sets this format for the primary buffer only */
563 static HRESULT WINAPI PrimaryBufferImpl_SetFormat(IDirectSoundBuffer *iface,
564 const WAVEFORMATEX *wfex)
565 {
566 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
567 TRACE("(%p,%p)\n", iface, wfex);
568 return primarybuffer_SetFormat(This->device, wfex);
569 }
570
571 static HRESULT WINAPI PrimaryBufferImpl_SetVolume(IDirectSoundBuffer *iface, LONG vol)
572 {
573 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
574 DirectSoundDevice *device = This->device;
575 HRESULT hr;
576 float lvol, rvol;
577
578 TRACE("(%p,%d)\n", iface, vol);
579
580 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
581 WARN("control unavailable\n");
582 return DSERR_CONTROLUNAVAIL;
583 }
584
585 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
586 WARN("invalid parameter: vol = %d\n", vol);
587 return DSERR_INVALIDPARAM;
588 }
589
590 /* **** */
591 EnterCriticalSection(&device->mixlock);
592
593 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
594 if(FAILED(hr)){
595 LeaveCriticalSection(&device->mixlock);
596 WARN("GetChannelVolume failed: %08x\n", hr);
597 return hr;
598 }
599
600 if(device->pwfx->nChannels > 1){
601 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
602 if(FAILED(hr)){
603 LeaveCriticalSection(&device->mixlock);
604 WARN("GetChannelVolume failed: %08x\n", hr);
605 return hr;
606 }
607 }else
608 rvol = 1;
609
610 device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
611 device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
612
613 DSOUND_AmpFactorToVolPan(&device->volpan);
614 if (vol != device->volpan.lVolume) {
615 device->volpan.lVolume=vol;
616 DSOUND_RecalcVolPan(&device->volpan);
617 lvol = (float)((DWORD)(device->volpan.dwTotalLeftAmpFactor & 0xFFFF) / (float)0xFFFF);
618 hr = IAudioStreamVolume_SetChannelVolume(device->volume, 0, lvol);
619 if(FAILED(hr)){
620 LeaveCriticalSection(&device->mixlock);
621 WARN("SetChannelVolume failed: %08x\n", hr);
622 return hr;
623 }
624
625 if(device->pwfx->nChannels > 1){
626 rvol = (float)((DWORD)(device->volpan.dwTotalRightAmpFactor & 0xFFFF) / (float)0xFFFF);
627 hr = IAudioStreamVolume_SetChannelVolume(device->volume, 1, rvol);
628 if(FAILED(hr)){
629 LeaveCriticalSection(&device->mixlock);
630 WARN("SetChannelVolume failed: %08x\n", hr);
631 return hr;
632 }
633 }
634 }
635
636 LeaveCriticalSection(&(device->mixlock));
637 /* **** */
638
639 return DS_OK;
640 }
641
642 static HRESULT WINAPI PrimaryBufferImpl_GetVolume(IDirectSoundBuffer *iface, LONG *vol)
643 {
644 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
645 DirectSoundDevice *device = This->device;
646 float lvol, rvol;
647 HRESULT hr;
648 TRACE("(%p,%p)\n", iface, vol);
649
650 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
651 WARN("control unavailable\n");
652 return DSERR_CONTROLUNAVAIL;
653 }
654
655 if (vol == NULL) {
656 WARN("invalid parameter: vol = NULL\n");
657 return DSERR_INVALIDPARAM;
658 }
659
660 EnterCriticalSection(&device->mixlock);
661
662 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
663 if(FAILED(hr)){
664 LeaveCriticalSection(&device->mixlock);
665 WARN("GetChannelVolume failed: %08x\n", hr);
666 return hr;
667 }
668
669 if(device->pwfx->nChannels > 1){
670 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
671 if(FAILED(hr)){
672 LeaveCriticalSection(&device->mixlock);
673 WARN("GetChannelVolume failed: %08x\n", hr);
674 return hr;
675 }
676 }else
677 rvol = 1;
678
679 device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
680 device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
681
682 DSOUND_AmpFactorToVolPan(&device->volpan);
683 *vol = device->volpan.lVolume;
684
685 LeaveCriticalSection(&device->mixlock);
686
687 return DS_OK;
688 }
689
690 static HRESULT WINAPI PrimaryBufferImpl_SetFrequency(IDirectSoundBuffer *iface, DWORD freq)
691 {
692 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
693 TRACE("(%p,%d)\n",This,freq);
694
695 /* You cannot set the frequency of the primary buffer */
696 WARN("control unavailable\n");
697 return DSERR_CONTROLUNAVAIL;
698 }
699
700 static HRESULT WINAPI PrimaryBufferImpl_Play(IDirectSoundBuffer *iface, DWORD reserved1,
701 DWORD reserved2, DWORD flags)
702 {
703 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
704 DirectSoundDevice *device = This->device;
705 TRACE("(%p,%08x,%08x,%08x)\n", iface, reserved1, reserved2, flags);
706
707 if (!(flags & DSBPLAY_LOOPING)) {
708 WARN("invalid parameter: flags = %08x\n", flags);
709 return DSERR_INVALIDPARAM;
710 }
711
712 /* **** */
713 EnterCriticalSection(&(device->mixlock));
714
715 if (device->state == STATE_STOPPED)
716 device->state = STATE_STARTING;
717 else if (device->state == STATE_STOPPING)
718 device->state = STATE_PLAYING;
719
720 LeaveCriticalSection(&(device->mixlock));
721 /* **** */
722
723 return DS_OK;
724 }
725
726 static HRESULT WINAPI PrimaryBufferImpl_Stop(IDirectSoundBuffer *iface)
727 {
728 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
729 DirectSoundDevice *device = This->device;
730 TRACE("(%p)\n", iface);
731
732 /* **** */
733 EnterCriticalSection(&(device->mixlock));
734
735 if (device->state == STATE_PLAYING)
736 device->state = STATE_STOPPING;
737 else if (device->state == STATE_STARTING)
738 device->state = STATE_STOPPED;
739
740 LeaveCriticalSection(&(device->mixlock));
741 /* **** */
742
743 return DS_OK;
744 }
745
746 static ULONG WINAPI PrimaryBufferImpl_AddRef(IDirectSoundBuffer *iface)
747 {
748 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
749 ULONG ref = InterlockedIncrement(&(This->ref));
750 TRACE("(%p) ref was %d\n", This, ref - 1);
751 if(ref == 1)
752 InterlockedIncrement(&This->numIfaces);
753 return ref;
754 }
755
756 /* Decreases *out by 1 to no less than 0.
757 * Returns the new value of *out. */
758 LONG capped_refcount_dec(LONG *out)
759 {
760 LONG ref, oldref;
761 do {
762 ref = *out;
763 if(!ref)
764 return 0;
765 oldref = InterlockedCompareExchange(out, ref - 1, ref);
766 } while(oldref != ref);
767 return ref - 1;
768 }
769
770 static ULONG WINAPI PrimaryBufferImpl_Release(IDirectSoundBuffer *iface)
771 {
772 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
773 ULONG ref;
774
775 ref = capped_refcount_dec(&This->ref);
776 if(!ref)
777 capped_refcount_dec(&This->numIfaces);
778
779 TRACE("(%p) primary ref is now %d\n", This, ref);
780
781 return ref;
782 }
783
784 static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(IDirectSoundBuffer *iface,
785 DWORD *playpos, DWORD *writepos)
786 {
787 HRESULT hres;
788 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
789 DirectSoundDevice *device = This->device;
790 TRACE("(%p,%p,%p)\n", iface, playpos, writepos);
791
792 /* **** */
793 EnterCriticalSection(&(device->mixlock));
794
795 hres = DSOUND_PrimaryGetPosition(device, playpos, writepos);
796 if (hres != DS_OK) {
797 WARN("DSOUND_PrimaryGetPosition failed\n");
798 LeaveCriticalSection(&(device->mixlock));
799 return hres;
800 }
801 if (writepos) {
802 if (device->state != STATE_STOPPED)
803 /* apply the documented 10ms lead to writepos */
804 *writepos += device->writelead;
805 while (*writepos >= device->buflen) *writepos -= device->buflen;
806 }
807
808 LeaveCriticalSection(&(device->mixlock));
809 /* **** */
810
811 TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
812 return DS_OK;
813 }
814
815 static HRESULT WINAPI PrimaryBufferImpl_GetStatus(IDirectSoundBuffer *iface, DWORD *status)
816 {
817 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
818 DirectSoundDevice *device = This->device;
819 TRACE("(%p,%p)\n", iface, status);
820
821 if (status == NULL) {
822 WARN("invalid parameter: status == NULL\n");
823 return DSERR_INVALIDPARAM;
824 }
825
826 *status = 0;
827 if ((device->state == STATE_STARTING) ||
828 (device->state == STATE_PLAYING))
829 *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING;
830
831 TRACE("status=%x\n", *status);
832 return DS_OK;
833 }
834
835
836 static HRESULT WINAPI PrimaryBufferImpl_GetFormat(IDirectSoundBuffer *iface, WAVEFORMATEX *lpwf,
837 DWORD wfsize, DWORD *wfwritten)
838 {
839 DWORD size;
840 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
841 DirectSoundDevice *device = This->device;
842 TRACE("(%p,%p,%d,%p)\n", iface, lpwf, wfsize, wfwritten);
843
844 size = sizeof(WAVEFORMATEX) + device->primary_pwfx->cbSize;
845
846 if (lpwf) { /* NULL is valid */
847 if (wfsize >= size) {
848 CopyMemory(lpwf,device->primary_pwfx,size);
849 if (wfwritten)
850 *wfwritten = size;
851 } else {
852 WARN("invalid parameter: wfsize too small\n");
853 if (wfwritten)
854 *wfwritten = 0;
855 return DSERR_INVALIDPARAM;
856 }
857 } else {
858 if (wfwritten)
859 *wfwritten = sizeof(WAVEFORMATEX) + device->primary_pwfx->cbSize;
860 else {
861 WARN("invalid parameter: wfwritten == NULL\n");
862 return DSERR_INVALIDPARAM;
863 }
864 }
865
866 return DS_OK;
867 }
868
869 static HRESULT WINAPI PrimaryBufferImpl_Lock(IDirectSoundBuffer *iface, DWORD writecursor,
870 DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
871 DWORD *audiobytes2, DWORD flags)
872 {
873 HRESULT hres;
874 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
875 DirectSoundDevice *device = This->device;
876 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
877 iface,
878 writecursor,
879 writebytes,
880 lplpaudioptr1,
881 audiobytes1,
882 lplpaudioptr2,
883 audiobytes2,
884 flags,
885 GetTickCount()
886 );
887
888 if (!audiobytes1)
889 return DSERR_INVALIDPARAM;
890
891 if (device->priolevel != DSSCL_WRITEPRIMARY) {
892 WARN("failed priority check!\n");
893 return DSERR_PRIOLEVELNEEDED;
894 }
895
896 /* when this flag is set, writecursor is meaningless and must be calculated */
897 if (flags & DSBLOCK_FROMWRITECURSOR) {
898 /* GetCurrentPosition does too much magic to duplicate here */
899 hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writecursor);
900 if (hres != DS_OK) {
901 WARN("IDirectSoundBuffer_GetCurrentPosition failed\n");
902 return hres;
903 }
904 }
905
906 /* when this flag is set, writebytes is meaningless and must be set */
907 if (flags & DSBLOCK_ENTIREBUFFER)
908 writebytes = device->buflen;
909
910 if (writecursor >= device->buflen) {
911 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
912 writecursor, device->buflen);
913 return DSERR_INVALIDPARAM;
914 }
915
916 if (writebytes > device->buflen) {
917 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
918 writebytes, device->buflen);
919 return DSERR_INVALIDPARAM;
920 }
921
922 if (writecursor+writebytes <= device->buflen) {
923 *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor;
924 *audiobytes1 = writebytes;
925 if (lplpaudioptr2)
926 *(LPBYTE*)lplpaudioptr2 = NULL;
927 if (audiobytes2)
928 *audiobytes2 = 0;
929 TRACE("->%d.0\n",writebytes);
930 } else {
931 *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor;
932 *audiobytes1 = device->buflen-writecursor;
933 if (lplpaudioptr2)
934 *(LPBYTE*)lplpaudioptr2 = device->buffer;
935 if (audiobytes2)
936 *audiobytes2 = writebytes-(device->buflen-writecursor);
937 TRACE("->%d.%d\n",*audiobytes1,audiobytes2?*audiobytes2:0);
938 }
939 return DS_OK;
940 }
941
942 static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition(IDirectSoundBuffer *iface, DWORD newpos)
943 {
944 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
945 TRACE("(%p,%d)\n",This,newpos);
946
947 /* You cannot set the position of the primary buffer */
948 WARN("invalid call\n");
949 return DSERR_INVALIDCALL;
950 }
951
952 static HRESULT WINAPI PrimaryBufferImpl_SetPan(IDirectSoundBuffer *iface, LONG pan)
953 {
954 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
955 DirectSoundDevice *device = This->device;
956 float lvol, rvol;
957 HRESULT hr;
958 TRACE("(%p,%d)\n", iface, pan);
959
960 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
961 WARN("control unavailable\n");
962 return DSERR_CONTROLUNAVAIL;
963 }
964
965 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
966 WARN("invalid parameter: pan = %d\n", pan);
967 return DSERR_INVALIDPARAM;
968 }
969
970 /* **** */
971 EnterCriticalSection(&device->mixlock);
972
973 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
974 if(FAILED(hr)){
975 LeaveCriticalSection(&device->mixlock);
976 WARN("GetChannelVolume failed: %08x\n", hr);
977 return hr;
978 }
979
980 if(device->pwfx->nChannels > 1){
981 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
982 if(FAILED(hr)){
983 LeaveCriticalSection(&device->mixlock);
984 WARN("GetChannelVolume failed: %08x\n", hr);
985 return hr;
986 }
987 }else
988 rvol = 1;
989
990 device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
991 device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
992
993 DSOUND_AmpFactorToVolPan(&device->volpan);
994 if (pan != device->volpan.lPan) {
995 device->volpan.lPan=pan;
996 DSOUND_RecalcVolPan(&device->volpan);
997
998 lvol = (float)((DWORD)(device->volpan.dwTotalLeftAmpFactor & 0xFFFF) / (float)0xFFFF);
999 hr = IAudioStreamVolume_SetChannelVolume(device->volume, 0, lvol);
1000 if(FAILED(hr)){
1001 LeaveCriticalSection(&device->mixlock);
1002 WARN("SetChannelVolume failed: %08x\n", hr);
1003 return hr;
1004 }
1005
1006 if(device->pwfx->nChannels > 1){
1007 rvol = (float)((DWORD)(device->volpan.dwTotalRightAmpFactor & 0xFFFF) / (float)0xFFFF);
1008 hr = IAudioStreamVolume_SetChannelVolume(device->volume, 1, rvol);
1009 if(FAILED(hr)){
1010 LeaveCriticalSection(&device->mixlock);
1011 WARN("SetChannelVolume failed: %08x\n", hr);
1012 return hr;
1013 }
1014 }
1015 }
1016
1017 LeaveCriticalSection(&device->mixlock);
1018 /* **** */
1019
1020 return DS_OK;
1021 }
1022
1023 static HRESULT WINAPI PrimaryBufferImpl_GetPan(IDirectSoundBuffer *iface, LONG *pan)
1024 {
1025 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1026 DirectSoundDevice *device = This->device;
1027 float lvol, rvol;
1028 HRESULT hr;
1029 TRACE("(%p,%p)\n", iface, pan);
1030
1031 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
1032 WARN("control unavailable\n");
1033 return DSERR_CONTROLUNAVAIL;
1034 }
1035
1036 if (pan == NULL) {
1037 WARN("invalid parameter: pan == NULL\n");
1038 return DSERR_INVALIDPARAM;
1039 }
1040
1041 EnterCriticalSection(&device->mixlock);
1042
1043 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 0, &lvol);
1044 if(FAILED(hr)){
1045 LeaveCriticalSection(&device->mixlock);
1046 WARN("GetChannelVolume failed: %08x\n", hr);
1047 return hr;
1048 }
1049
1050 if(device->pwfx->nChannels > 1){
1051 hr = IAudioStreamVolume_GetChannelVolume(device->volume, 1, &rvol);
1052 if(FAILED(hr)){
1053 LeaveCriticalSection(&device->mixlock);
1054 WARN("GetChannelVolume failed: %08x\n", hr);
1055 return hr;
1056 }
1057 }else
1058 rvol = 1;
1059
1060 device->volpan.dwTotalLeftAmpFactor = ((UINT16)(lvol * (DWORD)0xFFFF));
1061 device->volpan.dwTotalRightAmpFactor = ((UINT16)(rvol * (DWORD)0xFFFF));
1062
1063 DSOUND_AmpFactorToVolPan(&device->volpan);
1064 *pan = device->volpan.lPan;
1065
1066 LeaveCriticalSection(&device->mixlock);
1067
1068 return DS_OK;
1069 }
1070
1071 static HRESULT WINAPI PrimaryBufferImpl_Unlock(IDirectSoundBuffer *iface, void *p1, DWORD x1,
1072 void *p2, DWORD x2)
1073 {
1074 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1075 DirectSoundDevice *device = This->device;
1076 TRACE("(%p,%p,%d,%p,%d)\n", iface, p1, x1, p2, x2);
1077
1078 if (device->priolevel != DSSCL_WRITEPRIMARY) {
1079 WARN("failed priority check!\n");
1080 return DSERR_PRIOLEVELNEEDED;
1081 }
1082
1083 if ((p1 && ((BYTE*)p1 < device->buffer || (BYTE*)p1 >= device->buffer + device->buflen)) ||
1084 (p2 && ((BYTE*)p2 < device->buffer || (BYTE*)p2 >= device->buffer + device->buflen)))
1085 return DSERR_INVALIDPARAM;
1086
1087 return DS_OK;
1088 }
1089
1090 static HRESULT WINAPI PrimaryBufferImpl_Restore(IDirectSoundBuffer *iface)
1091 {
1092 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1093 FIXME("(%p):stub\n",This);
1094 return DS_OK;
1095 }
1096
1097 static HRESULT WINAPI PrimaryBufferImpl_GetFrequency(IDirectSoundBuffer *iface, DWORD *freq)
1098 {
1099 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1100 DirectSoundDevice *device = This->device;
1101 TRACE("(%p,%p)\n", iface, freq);
1102
1103 if (freq == NULL) {
1104 WARN("invalid parameter: freq == NULL\n");
1105 return DSERR_INVALIDPARAM;
1106 }
1107
1108 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
1109 WARN("control unavailable\n");
1110 return DSERR_CONTROLUNAVAIL;
1111 }
1112
1113 *freq = device->pwfx->nSamplesPerSec;
1114 TRACE("-> %d\n", *freq);
1115
1116 return DS_OK;
1117 }
1118
1119 static HRESULT WINAPI PrimaryBufferImpl_Initialize(IDirectSoundBuffer *iface, IDirectSound *dsound,
1120 const DSBUFFERDESC *dbsd)
1121 {
1122 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1123 WARN("(%p) already initialized\n", This);
1124 return DSERR_ALREADYINITIALIZED;
1125 }
1126
1127 static HRESULT WINAPI PrimaryBufferImpl_GetCaps(IDirectSoundBuffer *iface, DSBCAPS *caps)
1128 {
1129 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1130 DirectSoundDevice *device = This->device;
1131 TRACE("(%p,%p)\n", iface, caps);
1132
1133 if (caps == NULL) {
1134 WARN("invalid parameter: caps == NULL\n");
1135 return DSERR_INVALIDPARAM;
1136 }
1137
1138 if (caps->dwSize < sizeof(*caps)) {
1139 WARN("invalid parameter: caps->dwSize = %d\n", caps->dwSize);
1140 return DSERR_INVALIDPARAM;
1141 }
1142
1143 caps->dwFlags = This->dsbd.dwFlags;
1144 caps->dwBufferBytes = device->buflen;
1145
1146 /* Windows reports these as zero */
1147 caps->dwUnlockTransferRate = 0;
1148 caps->dwPlayCpuOverhead = 0;
1149
1150 return DS_OK;
1151 }
1152
1153 static HRESULT WINAPI PrimaryBufferImpl_QueryInterface(IDirectSoundBuffer *iface, REFIID riid,
1154 void **ppobj)
1155 {
1156 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
1157
1158 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppobj);
1159
1160 if (ppobj == NULL) {
1161 WARN("invalid parameter\n");
1162 return E_INVALIDARG;
1163 }
1164
1165 *ppobj = NULL; /* assume failure */
1166
1167 if ( IsEqualGUID(riid, &IID_IUnknown) ||
1168 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) {
1169 IDirectSoundBuffer_AddRef(iface);
1170 *ppobj = iface;
1171 return S_OK;
1172 }
1173
1174 /* DirectSoundBuffer and DirectSoundBuffer8 are different and */
1175 /* a primary buffer can't have a DirectSoundBuffer8 interface */
1176 if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) {
1177 WARN("app requested DirectSoundBuffer8 on primary buffer\n");
1178 return E_NOINTERFACE;
1179 }
1180
1181 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1182 ERR("app requested IDirectSoundNotify on primary buffer\n");
1183 /* FIXME: should we support this? */
1184 return E_NOINTERFACE;
1185 }
1186
1187 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1188 ERR("app requested IDirectSound3DBuffer on primary buffer\n");
1189 return E_NOINTERFACE;
1190 }
1191
1192 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1193 *ppobj = &This->IDirectSound3DListener_iface;
1194 IDirectSound3DListener_AddRef(&This->IDirectSound3DListener_iface);
1195 return S_OK;
1196 }
1197
1198 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
1199 *ppobj = &This->IKsPropertySet_iface;
1200 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
1201 return S_OK;
1202 }
1203
1204 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1205 return E_NOINTERFACE;
1206 }
1207
1208 static const IDirectSoundBufferVtbl dspbvt =
1209 {
1210 PrimaryBufferImpl_QueryInterface,
1211 PrimaryBufferImpl_AddRef,
1212 PrimaryBufferImpl_Release,
1213 PrimaryBufferImpl_GetCaps,
1214 PrimaryBufferImpl_GetCurrentPosition,
1215 PrimaryBufferImpl_GetFormat,
1216 PrimaryBufferImpl_GetVolume,
1217 PrimaryBufferImpl_GetPan,
1218 PrimaryBufferImpl_GetFrequency,
1219 PrimaryBufferImpl_GetStatus,
1220 PrimaryBufferImpl_Initialize,
1221 PrimaryBufferImpl_Lock,
1222 PrimaryBufferImpl_Play,
1223 PrimaryBufferImpl_SetCurrentPosition,
1224 PrimaryBufferImpl_SetFormat,
1225 PrimaryBufferImpl_SetVolume,
1226 PrimaryBufferImpl_SetPan,
1227 PrimaryBufferImpl_SetFrequency,
1228 PrimaryBufferImpl_Stop,
1229 PrimaryBufferImpl_Unlock,
1230 PrimaryBufferImpl_Restore
1231 };
1232
1233 HRESULT primarybuffer_create(DirectSoundDevice *device, IDirectSoundBufferImpl **ppdsb,
1234 const DSBUFFERDESC *dsbd)
1235 {
1236 IDirectSoundBufferImpl *dsb;
1237 TRACE("%p,%p,%p)\n",device,ppdsb,dsbd);
1238
1239 if (dsbd->lpwfxFormat) {
1240 WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n");
1241 *ppdsb = NULL;
1242 return DSERR_INVALIDPARAM;
1243 }
1244
1245 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1246
1247 if (dsb == NULL) {
1248 WARN("out of memory\n");
1249 *ppdsb = NULL;
1250 return DSERR_OUTOFMEMORY;
1251 }
1252
1253 dsb->ref = 0;
1254 dsb->ref3D = 0;
1255 dsb->refiks = 0;
1256 dsb->numIfaces = 0;
1257 dsb->device = device;
1258 dsb->IDirectSoundBuffer8_iface.lpVtbl = (IDirectSoundBuffer8Vtbl *)&dspbvt;
1259 dsb->IDirectSound3DListener_iface.lpVtbl = &ds3dlvt;
1260 dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
1261 dsb->dsbd = *dsbd;
1262
1263 /* IDirectSound3DListener */
1264 device->ds3dl.dwSize = sizeof(DS3DLISTENER);
1265 device->ds3dl.vPosition.x = 0.0;
1266 device->ds3dl.vPosition.y = 0.0;
1267 device->ds3dl.vPosition.z = 0.0;
1268 device->ds3dl.vVelocity.x = 0.0;
1269 device->ds3dl.vVelocity.y = 0.0;
1270 device->ds3dl.vVelocity.z = 0.0;
1271 device->ds3dl.vOrientFront.x = 0.0;
1272 device->ds3dl.vOrientFront.y = 0.0;
1273 device->ds3dl.vOrientFront.z = 1.0;
1274 device->ds3dl.vOrientTop.x = 0.0;
1275 device->ds3dl.vOrientTop.y = 1.0;
1276 device->ds3dl.vOrientTop.z = 0.0;
1277 device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1278 device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1279 device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1280 device->ds3dl_need_recalc = TRUE;
1281
1282 TRACE("Created primary buffer at %p\n", dsb);
1283 TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
1284 "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1285 device->pwfx->wFormatTag, device->pwfx->nChannels,
1286 device->pwfx->nSamplesPerSec, device->pwfx->nAvgBytesPerSec,
1287 device->pwfx->nBlockAlign, device->pwfx->wBitsPerSample,
1288 device->pwfx->cbSize);
1289
1290 IDirectSoundBuffer_AddRef(&dsb->IDirectSoundBuffer8_iface);
1291 *ppdsb = dsb;
1292 return S_OK;
1293 }