msi: Split process_handle() into two separate functions.
[wine/hacks.git] / dlls / winealsa.drv / dsoutput.c
blob1b7e9b1ce586a74fa29c27ee0c852a9f69ed1b3a
1 /*
2 * Sample Wine Driver for Advanced Linux Sound System (ALSA)
3 * Based on version <final> of the ALSA API
5 * Copyright 2002 Eric Pouech
6 * 2002 Marco Pietrobono
7 * 2003 Christian Costa : WaveIn support
8 * 2006-2007 Maarten Lankhorst
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 /*======================================================================*
26 * Low level dsound output implementation *
27 *======================================================================*/
29 #include "config.h"
30 #include "wine/port.h"
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <string.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <errno.h>
40 #include <limits.h>
41 #include <fcntl.h>
42 #ifdef HAVE_SYS_IOCTL_H
43 # include <sys/ioctl.h>
44 #endif
45 #ifdef HAVE_SYS_MMAN_H
46 # include <sys/mman.h>
47 #endif
48 #include "windef.h"
49 #include "winbase.h"
50 #include "wingdi.h"
51 #include "winerror.h"
52 #include "winuser.h"
53 #include "winnls.h"
54 #include "mmddk.h"
56 #include "alsa.h"
57 #include "wine/library.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
61 #ifdef HAVE_ALSA
63 WINE_DEFAULT_DEBUG_CHANNEL(wave);
64 WINE_DECLARE_DEBUG_CHANNEL(waveloop);
66 typedef struct IDsDriverImpl IDsDriverImpl;
67 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
69 struct IDsDriverImpl
71 /* IUnknown fields */
72 const IDsDriverVtbl *lpVtbl;
73 LONG ref;
74 /* IDsDriverImpl fields */
75 UINT wDevID;
76 IDsDriverBufferImpl*primary;
79 struct IDsDriverBufferImpl
81 /* IUnknown fields */
82 const IDsDriverBufferVtbl *lpVtbl;
83 LONG ref;
84 /* IDsDriverBufferImpl fields */
85 IDsDriverImpl* drv;
87 LPVOID mmap_buffer;
88 DWORD mmap_buflen_bytes;
89 snd_pcm_uframes_t mmap_buflen_frames;
90 snd_pcm_channel_area_t * mmap_areas;
91 snd_pcm_uframes_t mmap_ppos; /* play position */
92 snd_pcm_uframes_t mmap_wpos; /* write position */
93 HANDLE mmap_thread;
94 ALSA_MSG_RING mmap_ring; /* sync object */
97 static void DSDB_CheckXRUN(IDsDriverBufferImpl* pdbi)
99 WINE_WAVEDEV * wwo = &(WOutDev[pdbi->drv->wDevID]);
100 snd_pcm_state_t state = snd_pcm_state(wwo->pcm);
101 snd_pcm_avail_update(wwo->pcm);
103 if ( state == SND_PCM_STATE_XRUN )
105 int err = snd_pcm_prepare(wwo->pcm);
106 WARN_(waveloop)("xrun occurred\n");
107 if ( err < 0 )
108 ERR("recovery from xrun failed, prepare failed: %s\n", snd_strerror(err));
110 else if ( state == SND_PCM_STATE_SUSPENDED )
112 int err = snd_pcm_resume(wwo->pcm);
113 TRACE_(waveloop)("recovery from suspension occurred\n");
114 if (err < 0 && err != -EAGAIN){
115 err = snd_pcm_prepare(wwo->pcm);
116 if (err < 0)
117 ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err));
119 } else if ( state != SND_PCM_STATE_RUNNING ) {
120 WARN_(waveloop)("Unhandled state: %d\n", state);
125 * The helper thread for DirectSound
127 * Basically it does an infinite loop until it is told to die
129 * snd_pcm_wait() is a call that polls the sound buffer and waits
130 * until there is at least 1 period free before it returns.
132 * We then commit the buffer filled by the owner of this
133 * IDSDriverBuffer */
134 static DWORD CALLBACK DBSB_MMAPLoop(LPVOID data)
136 IDsDriverBufferImpl* pdbi = (IDsDriverBufferImpl*)data;
137 WINE_WAVEDEV *wwo = &(WOutDev[pdbi->drv->wDevID]);
138 snd_pcm_uframes_t frames, wanted, ofs;
139 const snd_pcm_channel_area_t *areas;
140 int state = WINE_WS_STOPPED;
141 snd_pcm_state_t alsastate;
143 TRACE_(waveloop)("0x%8p\n", data);
144 TRACE("0x%8p, framelength: %lu, area: %8p\n", data, pdbi->mmap_buflen_frames, pdbi->mmap_areas);
146 if (areas != pdbi->mmap_areas || areas->addr != pdbi->mmap_areas->addr)
147 FIXME("Can't access sound driver's buffer directly.\n");
149 do {
150 enum win_wm_message msg;
151 DWORD param;
152 HANDLE hEvent;
153 int err;
154 snd_pcm_format_t format;
156 if (state != WINE_WS_PLAYING)
158 ALSA_WaitRingMessage(&pdbi->mmap_ring, 1000000);
159 ALSA_RetrieveRingMessage(&pdbi->mmap_ring, &msg, &param, &hEvent);
161 else
162 while (!ALSA_RetrieveRingMessage(&pdbi->mmap_ring, &msg, &param, &hEvent))
164 snd_pcm_wait(wwo->pcm, -1);
165 DSDB_CheckXRUN(pdbi);
167 wanted = frames = pdbi->mmap_buflen_frames;
169 err = snd_pcm_mmap_begin(wwo->pcm, &areas, &ofs, &frames);
170 snd_pcm_mmap_commit(wwo->pcm, ofs, frames);
172 /* mark our current play position */
173 pdbi->mmap_ppos = ofs;
174 TRACE_(waveloop)("Updated position to %lx [%d, 0x%8p, %lu]\n", ofs, err, areas, frames);
175 /* Check to make sure we committed all we want to commit. ALSA
176 * only gives a contiguous linear region, so we need to check this
177 * in case we've reached the end of the buffer, in which case we
178 * can wrap around back to the beginning. */
179 if (frames < wanted) {
180 frames = wanted - frames;
181 snd_pcm_mmap_begin(wwo->pcm, &areas, &ofs, &frames);
182 snd_pcm_mmap_commit(wwo->pcm, ofs, frames);
184 wanted = 0;
185 snd_pcm_mmap_begin(wwo->pcm, &areas, &ofs, &wanted);
186 snd_pcm_mmap_commit(wwo->pcm, ofs, wanted);
187 pdbi->mmap_wpos = ofs;
190 switch (msg) {
191 case WINE_WM_STARTING:
192 if (state == WINE_WS_PLAYING)
193 break;
195 alsastate = snd_pcm_state(wwo->pcm);
196 if ( alsastate == SND_PCM_STATE_SETUP )
198 err = snd_pcm_prepare(wwo->pcm);
199 alsastate = snd_pcm_state(wwo->pcm);
202 snd_pcm_avail_update(wwo->pcm);
204 /* Rewind, and initialise */
205 frames = 0;
206 snd_pcm_mmap_begin(wwo->pcm, &areas, &ofs, &frames);
207 snd_pcm_mmap_commit(wwo->pcm, ofs, frames);
208 snd_pcm_rewind(wwo->pcm, ofs);
209 snd_pcm_hw_params_get_format(wwo->hw_params, &format);
210 snd_pcm_format_set_silence(format, pdbi->mmap_buffer, pdbi->mmap_buflen_frames);
211 pdbi->mmap_ppos = 0;
212 snd_pcm_hw_params_get_period_size(wwo->hw_params, &wanted, NULL);
213 pdbi->mmap_wpos = 2*wanted;
214 if ( alsastate == SND_PCM_STATE_PREPARED )
216 err = snd_pcm_start(wwo->pcm);
217 TRACE("Starting 0x%8p err: %d\n", wwo->pcm, err);
219 state = WINE_WS_PLAYING;
220 break;
222 case WINE_WM_STOPPING:
223 state = WINE_WS_STOPPED;
224 snd_pcm_drain(wwo->pcm);
225 break;
227 case WINE_WM_CLOSING:
228 if (wwo->pcm != NULL)
229 snd_pcm_drain(wwo->pcm);
230 pdbi->mmap_thread = NULL;
231 SetEvent(hEvent);
232 goto out;
233 default:
234 ERR("Unhandled event %s\n", ALSA_getCmdString(msg));
235 break;
237 if (hEvent != INVALID_HANDLE_VALUE)
238 SetEvent(hEvent);
239 } while (1);
240 out:
241 TRACE_(waveloop)("Destroyed MMAP thread\n");
242 TRACE("Destroyed MMAP thread\n");
243 return 0;
247 * Allocate the memory-mapped buffer for direct sound, and set up the
248 * callback.
250 static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
252 WINE_WAVEDEV * wwo = &(WOutDev[pdbi->drv->wDevID]);
253 snd_pcm_format_t format;
254 snd_pcm_uframes_t frames, ofs, avail, psize;
255 unsigned int channels, bits_per_sample, bits_per_frame;
256 int err, mmap_mode;
258 mmap_mode = snd_pcm_type(wwo->pcm);
260 ALSA_InitRingMessage(&pdbi->mmap_ring);
262 if (mmap_mode == SND_PCM_TYPE_HW) {
263 TRACE("mmap'd buffer is a hardware buffer.\n");
265 else {
266 #if 0 /* Horribly hack, shouldn't be used */
267 err = snd_pcm_hw_params_get_period_size(wwo->hw_params, &psize, NULL);
268 /* Set only a buffer of 2 period sizes, to decrease latency */
269 if (err >= 0)
270 err = snd_pcm_hw_params_set_buffer_size_near(wwo->pcm, wwo->hw_params, &psize);
272 psize *= 2;
273 if (err < 0) {
274 ERR("Errno %d (%s) occured when setting buffer size\n", err, strerror(errno));
276 #endif
277 TRACE("mmap'd buffer is an ALSA emulation of hardware buffer.\n");
280 err = snd_pcm_hw_params_get_period_size(wwo->hw_params, &psize, NULL);
281 err = snd_pcm_hw_params_get_format(wwo->hw_params, &format);
282 err = snd_pcm_hw_params_get_buffer_size(wwo->hw_params, &frames);
283 err = snd_pcm_hw_params_get_channels(wwo->hw_params, &channels);
284 bits_per_sample = snd_pcm_format_physical_width(format);
285 bits_per_frame = bits_per_sample * channels;
287 if (TRACE_ON(wave))
288 ALSA_TraceParameters(wwo->hw_params, NULL, FALSE);
290 TRACE("format=%s frames=%ld channels=%d bits_per_sample=%d bits_per_frame=%d\n",
291 snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame);
293 pdbi->mmap_buflen_frames = frames;
294 pdbi->mmap_buflen_bytes = snd_pcm_frames_to_bytes( wwo->pcm, frames );
296 avail = snd_pcm_avail_update(wwo->pcm);
297 if (avail < 0)
299 ERR("No buffer is available: %s.\n", snd_strerror(avail));
300 return DSERR_GENERIC;
302 err = snd_pcm_mmap_begin(wwo->pcm, (const snd_pcm_channel_area_t **)&pdbi->mmap_areas, &ofs, &avail);
303 if ( err < 0 )
305 ERR("Can't map sound device for direct access: %s\n", snd_strerror(err));
306 return DSERR_GENERIC;
308 avail = 0;/* We don't have any data to commit yet */
309 err = snd_pcm_mmap_commit(wwo->pcm, ofs, avail);
310 if (ofs > 0)
311 err = snd_pcm_rewind(wwo->pcm, ofs);
312 pdbi->mmap_buffer = pdbi->mmap_areas->addr;
313 pdbi->mmap_thread = NULL;
315 TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
316 frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);
318 return DS_OK;
321 static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
323 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
324 FIXME("(): stub!\n");
325 return DSERR_UNSUPPORTED;
328 static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
330 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
331 ULONG refCount = InterlockedIncrement(&This->ref);
333 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
335 return refCount;
338 static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
340 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
341 ULONG refCount = InterlockedDecrement(&This->ref);
343 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
345 if (refCount)
346 return refCount;
348 if (This->mmap_thread != NULL)
349 ALSA_AddRingMessage(&This->mmap_ring, WINE_WM_CLOSING, 0, 1);
351 TRACE("mmap buffer %p destroyed\n", This->mmap_buffer);
352 ALSA_DestroyRingMessage(&This->mmap_ring);
354 if (This == This->drv->primary)
355 This->drv->primary = NULL;
356 HeapFree(GetProcessHeap(), 0, This);
357 return 0;
360 static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
361 LPVOID*ppvAudio1,LPDWORD pdwLen1,
362 LPVOID*ppvAudio2,LPDWORD pdwLen2,
363 DWORD dwWritePosition,DWORD dwWriteLen,
364 DWORD dwFlags)
366 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
367 TRACE("(%p)\n",iface);
368 return DSERR_UNSUPPORTED;
371 static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
372 LPVOID pvAudio1,DWORD dwLen1,
373 LPVOID pvAudio2,DWORD dwLen2)
375 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
376 TRACE("(%p)\n",iface);
377 return DSERR_UNSUPPORTED;
380 static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
381 LPWAVEFORMATEX pwfx)
383 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
384 TRACE("(%p,%p)\n",iface,pwfx);
385 return DSERR_BUFFERLOST;
388 static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
390 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
391 TRACE("(%p,%d): stub\n",iface,dwFreq);
392 return DSERR_UNSUPPORTED;
395 static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
397 DWORD vol;
398 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
399 TRACE("(%p,%p)\n",iface,pVolPan);
400 vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
402 if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
403 WARN("wodSetVolume failed\n");
404 return DSERR_INVALIDPARAM;
407 return DS_OK;
410 static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
412 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
413 FIXME("(%p,%d): stub\n",iface,dwNewPos);
414 return DSERR_UNSUPPORTED;
417 static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
418 LPDWORD lpdwPlay, LPDWORD lpdwWrite)
420 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
421 WINE_WAVEDEV * wwo = &(WOutDev[This->drv->wDevID]);
422 snd_pcm_uframes_t hw_pptr, hw_wptr;
423 snd_pcm_state_t state;
425 if (wwo->hw_params == NULL || wwo->pcm == NULL) return DSERR_GENERIC;
427 #if 0 /* Shouldn't be needed */
428 /* we need to track down buffer underruns */
429 DSDB_CheckXRUN(This);
430 #endif
432 state = snd_pcm_state(wwo->pcm);
433 if (state == SND_PCM_STATE_RUNNING)
435 hw_pptr = This->mmap_ppos;
436 hw_wptr = This->mmap_wpos;
438 else
439 hw_pptr = hw_wptr = 0;
441 if (lpdwPlay)
442 *lpdwPlay = snd_pcm_frames_to_bytes(wwo->pcm, hw_pptr) % This->mmap_buflen_bytes;
443 if (lpdwWrite)
444 *lpdwWrite = snd_pcm_frames_to_bytes(wwo->pcm, hw_wptr) % This->mmap_buflen_bytes;
446 TRACE_(waveloop)("hw_pptr=0x%08x, hw_wptr=0x%08x playpos=%d, writepos=%d\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1);
447 return DS_OK;
450 static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
452 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
454 TRACE("(%p,%x,%x,%x)\n",iface,dwRes1,dwRes2,dwFlags);
456 if (This->mmap_thread == NULL)
457 This->mmap_thread = CreateThread(NULL, 0, DBSB_MMAPLoop, (LPVOID)(DWORD)This, 0, NULL);
459 if (This->mmap_thread == NULL)
460 ERR("Cannot create sound thread, don't expect any sound at all\n");
461 else
462 ALSA_AddRingMessage(&This->mmap_ring, WINE_WM_STARTING, 0, 1);
464 return DS_OK;
467 static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
469 IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
471 TRACE("(%p)\n",iface);
473 if (This->mmap_thread != NULL)
474 ALSA_AddRingMessage(&This->mmap_ring, WINE_WM_STOPPING, 0, 1);
476 return DS_OK;
479 static const IDsDriverBufferVtbl dsdbvt =
481 IDsDriverBufferImpl_QueryInterface,
482 IDsDriverBufferImpl_AddRef,
483 IDsDriverBufferImpl_Release,
484 IDsDriverBufferImpl_Lock,
485 IDsDriverBufferImpl_Unlock,
486 IDsDriverBufferImpl_SetFormat,
487 IDsDriverBufferImpl_SetFrequency,
488 IDsDriverBufferImpl_SetVolumePan,
489 IDsDriverBufferImpl_SetPosition,
490 IDsDriverBufferImpl_GetPosition,
491 IDsDriverBufferImpl_Play,
492 IDsDriverBufferImpl_Stop
495 static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
497 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
498 FIXME("(%p): stub!\n",iface);
499 return DSERR_UNSUPPORTED;
502 static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
504 IDsDriverImpl *This = (IDsDriverImpl *)iface;
505 ULONG refCount = InterlockedIncrement(&This->ref);
507 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
509 return refCount;
512 static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
514 IDsDriverImpl *This = (IDsDriverImpl *)iface;
515 ULONG refCount = InterlockedDecrement(&This->ref);
517 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
519 if (refCount)
520 return refCount;
521 HeapFree(GetProcessHeap(),0,This);
522 return 0;
525 static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface, PDSDRIVERDESC pDesc)
527 IDsDriverImpl *This = (IDsDriverImpl *)iface;
528 TRACE("(%p,%p)\n",iface,pDesc);
529 memcpy(pDesc, &(WOutDev[This->wDevID].ds_desc), sizeof(DSDRIVERDESC));
530 pDesc->dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
531 DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK;
532 pDesc->dnDevNode = WOutDev[This->wDevID].waveDesc.dnDevNode;
533 pDesc->wVxdId = 0;
534 pDesc->wReserved = 0;
535 pDesc->ulDeviceNum = This->wDevID;
536 pDesc->dwHeapType = DSDHEAP_NOHEAP;
537 pDesc->pvDirectDrawHeap = NULL;
538 pDesc->dwMemStartAddress = 0;
539 pDesc->dwMemEndAddress = 0;
540 pDesc->dwMemAllocExtra = 0;
541 pDesc->pvReserved1 = NULL;
542 pDesc->pvReserved2 = NULL;
543 return DS_OK;
546 static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
548 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
549 TRACE("(%p)\n",iface);
550 return DS_OK;
553 static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
555 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
556 TRACE("(%p)\n",iface);
557 return DS_OK;
560 static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
562 IDsDriverImpl *This = (IDsDriverImpl *)iface;
563 TRACE("(%p,%p)\n",iface,pCaps);
564 memcpy(pCaps, &(WOutDev[This->wDevID].ds_caps), sizeof(DSDRIVERCAPS));
565 return DS_OK;
568 static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
569 LPWAVEFORMATEX pwfx,
570 DWORD dwFlags, DWORD dwCardAddress,
571 LPDWORD pdwcbBufferSize,
572 LPBYTE *ppbBuffer,
573 LPVOID *ppvObj)
575 IDsDriverImpl *This = (IDsDriverImpl *)iface;
576 IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
577 int err;
579 TRACE("(%p,%p,%x,%x)\n",iface,pwfx,dwFlags,dwCardAddress);
580 /* we only support primary buffers */
581 if (!(dwFlags & DSBCAPS_PRIMARYBUFFER))
582 return DSERR_UNSUPPORTED;
583 if (This->primary)
584 return DSERR_ALLOCATED;
585 if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
586 return DSERR_CONTROLUNAVAIL;
588 *ippdsdb = HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverBufferImpl));
589 if (*ippdsdb == NULL)
590 return DSERR_OUTOFMEMORY;
591 (*ippdsdb)->lpVtbl = &dsdbvt;
592 (*ippdsdb)->ref = 1;
593 (*ippdsdb)->drv = This;
595 err = DSDB_CreateMMAP((*ippdsdb));
596 if ( err != DS_OK )
598 HeapFree(GetProcessHeap(), 0, *ippdsdb);
599 *ippdsdb = NULL;
600 return err;
602 *ppbBuffer = (*ippdsdb)->mmap_buffer;
603 *pdwcbBufferSize = (*ippdsdb)->mmap_buflen_bytes;
605 This->primary = *ippdsdb;
607 /* buffer is ready to go */
608 TRACE("buffer created at %p\n", *ippdsdb);
609 return DS_OK;
612 static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
613 PIDSDRIVERBUFFER pBuffer,
614 LPVOID *ppvObj)
616 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
617 TRACE("(%p,%p): stub\n",iface,pBuffer);
618 return DSERR_INVALIDCALL;
621 static const IDsDriverVtbl dsdvt =
623 IDsDriverImpl_QueryInterface,
624 IDsDriverImpl_AddRef,
625 IDsDriverImpl_Release,
626 IDsDriverImpl_GetDriverDesc,
627 IDsDriverImpl_Open,
628 IDsDriverImpl_Close,
629 IDsDriverImpl_GetCaps,
630 IDsDriverImpl_CreateSoundBuffer,
631 IDsDriverImpl_DuplicateSoundBuffer
634 DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
636 IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
638 TRACE("driver created\n");
640 /* the HAL isn't much better than the HEL if we can't do mmap() */
641 if (!(WOutDev[wDevID].outcaps.dwSupport & WAVECAPS_DIRECTSOUND)) {
642 ERR("DirectSound flag not set\n");
643 MESSAGE("This sound card's driver does not support direct access\n");
644 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
645 return MMSYSERR_NOTSUPPORTED;
648 *idrv = HeapAlloc(GetProcessHeap(),0,sizeof(IDsDriverImpl));
649 if (!*idrv)
650 return MMSYSERR_NOMEM;
651 (*idrv)->lpVtbl = &dsdvt;
652 (*idrv)->ref = 1;
654 (*idrv)->wDevID = wDevID;
655 (*idrv)->primary = NULL;
656 return MMSYSERR_NOERROR;
659 DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
661 memcpy(desc, &(WOutDev[wDevID].ds_desc), sizeof(DSDRIVERDESC));
662 return MMSYSERR_NOERROR;
665 #endif /* HAVE_ALSA */