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