wineoss: split up audio.c

Robert Reif reif at earthlink.net
Sun Oct 24 11:11:58 CDT 2004


This patch splits up audio.c into three separate .c/.h file pairs:

audio.h: data structure definitions and global function prototypes
audio.c: OSS functions and waveIn and waveOut driver functions

dscapture.h: direct sound capture global function prototypes
dscapture.c: direct sound capture driver implementation

dsrender.h: direct sound renderer global function prototypes
dsrender.c: direct sound renderer driver implementation

This patch just rearranges the code.  No changes have been
made other than removing static from some functions.
-------------- next part --------------
diff -u -N wine.cvs/dlls/winmm/wineoss/audio.c wine/dlls/winmm/wineoss/audio.c
--- wine.cvs/dlls/winmm/wineoss/audio.c	2004-09-14 21:15:53.000000000 -0400
+++ wine/dlls/winmm/wineoss/audio.c	2004-10-24 12:07:58.000000000 -0400
@@ -29,9 +29,6 @@
 
 /*#define EMULATE_SB16*/
 
-/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
-#define USE_PIPE_SYNC
-
 /* an exact wodGetPosition is usually not worth the extra context switches,
  * as we're going to have near fragment accuracy anyway */
 #define EXACT_WODPOSITION
@@ -74,6 +71,10 @@
 #include "oss.h"
 #include "wine/debug.h"
 
+#include "audio.h"
+#include "dsrender.h"
+#include "dscapture.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(wave);
 
 /* Allow 1% deviation for sample rates (some ES137x cards) */
@@ -81,7 +82,11 @@
 
 #ifdef HAVE_OSS
 
-#define MAX_WAVEDRV 	(6)
+OSS_DEVICE      OSS_Devices[MAX_WAVEDRV];
+WINE_WAVEOUT    WOutDev[MAX_WAVEDRV];
+WINE_WAVEIN     WInDev[MAX_WAVEDRV];
+unsigned        numOutDev;
+unsigned        numInDev;
 
 /* state diagram for waveOut writing:
  *
@@ -100,141 +105,6 @@
  * +---------+-------------+---------------+---------------------------------+
  */
 
-/* states of the playing device */
-#define	WINE_WS_PLAYING		0
-#define	WINE_WS_PAUSED		1
-#define	WINE_WS_STOPPED		2
-#define WINE_WS_CLOSED		3
-
-/* events to be send to device */
-enum win_wm_message {
-    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
-    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
-};
-
-#ifdef USE_PIPE_SYNC
-#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
-#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
-#define RESET_OMR(omr) do { } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
-       pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
-#else
-#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
-#define CLEAR_OMR(omr) do { } while (0)
-#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
-#define WAIT_OMR(omr, sleep) \
-  do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
-#endif
-
-typedef struct {
-    enum win_wm_message 	msg;	/* message identifier */
-    DWORD	                param;  /* parameter for this message */
-    HANDLE	                hEvent;	/* if message is synchronous, handle of event for synchro */
-} OSS_MSG;
-
-/* implement an in-process message ring for better performance
- * (compared to passing thru the server)
- * this ring will be used by the input (resp output) record (resp playback) routine
- */
-#define OSS_RING_BUFFER_INCREMENT	64
-typedef struct {
-    int                         ring_buffer_size;
-    OSS_MSG			* messages;
-    int				msg_tosave;
-    int				msg_toget;
-#ifdef USE_PIPE_SYNC
-    int				msg_pipe[2];
-#else
-    HANDLE			msg_event;
-#endif
-    CRITICAL_SECTION		msg_crst;
-} OSS_MSG_RING;
-
-typedef struct tagOSS_DEVICE {
-    char*                       dev_name;
-    char*                       mixer_name;
-    char*                       interface_name;
-    unsigned                    open_count;
-    WAVEOUTCAPSA                out_caps;
-    WAVEOUTCAPSA                duplex_out_caps;
-    WAVEINCAPSA                 in_caps;
-    DWORD                       in_caps_support;
-    unsigned                    open_access;
-    int                         fd;
-    DWORD                       owner_tid;
-    int                         sample_rate;
-    int                         stereo;
-    int                         format;
-    unsigned                    audio_fragment;
-    BOOL                        full_duplex;
-    BOOL                        bTriggerSupport;
-    BOOL                        bOutputEnabled;
-    BOOL                        bInputEnabled;
-    DSDRIVERDESC                ds_desc;
-    DSDRIVERCAPS                ds_caps;
-    DSCDRIVERCAPS               dsc_caps;
-} OSS_DEVICE;
-
-static OSS_DEVICE   OSS_Devices[MAX_WAVEDRV];
-
-typedef struct {
-    OSS_DEVICE*                 ossdev;
-    volatile int		state;			/* one of the WINE_WS_ manifest constants */
-    WAVEOPENDESC		waveDesc;
-    WORD			wFlags;
-    WAVEFORMATPCMEX             waveFormat;
-    DWORD			volume;
-
-    /* OSS information */
-    DWORD			dwFragmentSize;		/* size of OSS buffer fragment */
-    DWORD                       dwBufferSize;           /* size of whole OSS buffer in bytes */
-    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
-    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
-    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
-
-    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
-    DWORD			dwLoops;		/* private copy of loop counter */
-
-    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */
-    DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
-    BOOL                        bNeedPost;              /* whether audio still needs to be physically started */
-
-    /* synchronization stuff */
-    HANDLE			hStartUpEvent;
-    HANDLE			hThread;
-    DWORD			dwThreadID;
-    OSS_MSG_RING		msgRing;
-} WINE_WAVEOUT;
-
-typedef struct {
-    OSS_DEVICE*                 ossdev;
-    volatile int		state;
-    DWORD			dwFragmentSize;		/* OpenSound '/dev/dsp' give us that size */
-    WAVEOPENDESC		waveDesc;
-    WORD			wFlags;
-    WAVEFORMATPCMEX             waveFormat;
-    LPWAVEHDR			lpQueuePtr;
-    DWORD			dwTotalRecorded;
-    DWORD			dwTotalRead;
-
-    /* synchronization stuff */
-    HANDLE			hThread;
-    DWORD			dwThreadID;
-    HANDLE			hStartUpEvent;
-    OSS_MSG_RING		msgRing;
-} WINE_WAVEIN;
-
-static WINE_WAVEOUT	WOutDev   [MAX_WAVEDRV];
-static WINE_WAVEIN	WInDev    [MAX_WAVEDRV];
-static unsigned         numOutDev;
-static unsigned         numInDev;
-
-static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
-static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);
-static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
-static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc);
-
 /* These strings used only for tracing */
 static const char * getCmdString(enum win_wm_message msg)
 {
@@ -256,7 +126,7 @@
     return unknown;
 };
 
-static int getEnables(OSS_DEVICE *ossdev)
+int getEnables(OSS_DEVICE *ossdev)
 {
     return ( (ossdev->bOutputEnabled ? PCM_ENABLE_OUTPUT : 0) |
              (ossdev->bInputEnabled  ? PCM_ENABLE_INPUT  : 0) );
@@ -412,7 +282,7 @@
     return FALSE;
 }
 
-static void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
+void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
 {
     ZeroMemory(wf2, sizeof(wf2));
     if (wf1->wFormatTag == WAVE_FORMAT_PCM)
@@ -535,7 +405,7 @@
  * open the device for both waveout and wavein streams...
  * this is hackish, but it's the way OSS interface is done...
  */
-static DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
+DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
                             int* frag, int strict_format,
                             int sample_rate, int stereo, int fmt)
 {
@@ -641,7 +511,7 @@
  *
  *
  */
-static void	OSS_CloseDevice(OSS_DEVICE* ossdev)
+void	OSS_CloseDevice(OSS_DEVICE* ossdev)
 {
     TRACE("(%p)\n",ossdev);
     if (ossdev->open_count>0) {
@@ -1900,7 +1770,7 @@
 /**************************************************************************
  * 				wodOpen				[internal]
  */
-static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
 {
     int			audio_fragment;
     WINE_WAVEOUT*	wwo;
@@ -2331,7 +2201,7 @@
 /**************************************************************************
  * 				wodSetVolume			[internal]
  */
-static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
+DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
 {
     int		mixer;
     int		volume;
@@ -2412,1110 +2282,216 @@
 }
 
 /*======================================================================*
- *                  Low level DSOUND definitions                        *
- *======================================================================*/
-
-typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl;
-typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl;
-typedef struct IDsDriverImpl IDsDriverImpl;
-typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
-
-struct IDsDriverPropertySetImpl
-{
-    /* IUnknown fields */
-    IDsDriverPropertySetVtbl   *lpVtbl;
-    DWORD                       ref;
-
-    IDsDriverBufferImpl*        buffer;
-};
-
-struct IDsDriverNotifyImpl
-{
-    /* IUnknown fields */
-    IDsDriverNotifyVtbl        *lpVtbl;
-    DWORD                       ref;
-
-    /* IDsDriverNotifyImpl fields */
-    LPDSBPOSITIONNOTIFY         notifies;
-    int                         nrofnotifies;
-
-    IDsDriverBufferImpl*        buffer;
-};
-
-struct IDsDriverImpl
-{
-    /* IUnknown fields */
-    IDsDriverVtbl              *lpVtbl;
-    DWORD                       ref;
-
-    /* IDsDriverImpl fields */
-    UINT                        wDevID;
-    IDsDriverBufferImpl*        primary;
-
-    int                         nrofsecondaries;
-    IDsDriverBufferImpl**       secondaries;
-};
-
-struct IDsDriverBufferImpl
-{
-    /* IUnknown fields */
-    IDsDriverBufferVtbl        *lpVtbl;
-    DWORD                       ref;
-
-    /* IDsDriverBufferImpl fields */
-    IDsDriverImpl*              drv;
-    DWORD                       buflen;
-    WAVEFORMATPCMEX             wfex;
-    LPBYTE                      mapping;
-    DWORD                       maplen;
-    int                         fd;
-    DWORD                       dwFlags;
-
-    /* IDsDriverNotifyImpl fields */
-    IDsDriverNotifyImpl*        notify;
-    int                         notify_index;
-
-    /* IDsDriverPropertySetImpl fields */
-    IDsDriverPropertySetImpl*   property_set;
-};
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverPropertySetImpl **pdsdps);
-
-static HRESULT WINAPI IDsDriverNotifyImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverNotifyImpl **pdsdn);
-
-/*======================================================================*
- *                  Low level DSOUND property set implementation        *
+ *                  Low level WAVE IN implementation			*
  *======================================================================*/
 
-static HRESULT WINAPI IDsDriverPropertySetImpl_QueryInterface(
-    PIDSDRIVERPROPERTYSET iface,
-    REFIID riid,
-    LPVOID *ppobj)
+/**************************************************************************
+ * 			widNotifyClient			[internal]
+ */
+static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
 {
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    TRACE("wMsg = 0x%04x (%s) dwParm1 = %04lX dwParam2 = %04lX\n", wMsg,
+        wMsg == WIM_OPEN ? "WIM_OPEN" : wMsg == WIM_CLOSE ? "WIM_CLOSE" :
+        wMsg == WIM_DATA ? "WIM_DATA" : "Unknown", dwParam1, dwParam2);
 
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
-        IDsDriverPropertySet_AddRef(iface);
-        *ppobj = (LPVOID)This;
-        return DS_OK;
+    switch (wMsg) {
+    case WIM_OPEN:
+    case WIM_CLOSE:
+    case WIM_DATA:
+	if (wwi->wFlags != DCB_NULL &&
+	    !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
+			    (HDRVR)wwi->waveDesc.hWave, wMsg,
+			    wwi->waveDesc.dwInstance, dwParam1, dwParam2)) {
+	    WARN("can't notify client !\n");
+	    return MMSYSERR_ERROR;
+	}
+	break;
+    default:
+	FIXME("Unknown callback message %u\n", wMsg);
+	return MMSYSERR_INVALPARAM;
     }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
+    return MMSYSERR_NOERROR;
 }
 
-static ULONG WINAPI IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface)
+/**************************************************************************
+ * 			widGetDevCaps				[internal]
+ */
+static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSA lpCaps, DWORD dwSize)
 {
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
+    TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
 
-static ULONG WINAPI IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface)
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
+    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
 
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
+    if (wDevID >= numInDev) {
+	TRACE("numOutDev reached !\n");
+	return MMSYSERR_BADDEVICEID;
     }
-    return ref;
-}
 
-static HRESULT WINAPI IDsDriverPropertySetImpl_Get(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData,
-    PULONG pcbReturnedData )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Set(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_QuerySupport(
-    PIDSDRIVERPROPERTYSET iface,
-    REFGUID PropertySetId,
-    ULONG PropertyId,
-    PULONG pSupport )
-{
-    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
-    FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,pSupport);
-    return DSERR_UNSUPPORTED;
+    memcpy(lpCaps, &WInDev[wDevID].ossdev->in_caps, min(dwSize, sizeof(*lpCaps)));
+    return MMSYSERR_NOERROR;
 }
 
-IDsDriverPropertySetVtbl dsdpsvt =
+/**************************************************************************
+ * 				widRecorder_ReadHeaders		[internal]
+ */
+static void widRecorder_ReadHeaders(WINE_WAVEIN * wwi)
 {
-    IDsDriverPropertySetImpl_QueryInterface,
-    IDsDriverPropertySetImpl_AddRef,
-    IDsDriverPropertySetImpl_Release,
-    IDsDriverPropertySetImpl_Get,
-    IDsDriverPropertySetImpl_Set,
-    IDsDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- *                  Low level DSOUND notify implementation              *
- *======================================================================*/
+    enum win_wm_message tmp_msg;
+    DWORD		tmp_param;
+    HANDLE		tmp_ev;
+    WAVEHDR*		lpWaveHdr;
 
-static HRESULT WINAPI IDsDriverNotifyImpl_QueryInterface(
-    PIDSDRIVERNOTIFY iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    while (OSS_RetrieveRingMessage(&wwi->msgRing, &tmp_msg, &tmp_param, &tmp_ev)) {
+        if (tmp_msg == WINE_WM_HEADER) {
+	    LPWAVEHDR*	wh;
+	    lpWaveHdr = (LPWAVEHDR)tmp_param;
+	    lpWaveHdr->lpNext = 0;
 
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
-        IDsDriverNotify_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
+	    if (wwi->lpQueuePtr == 0)
+		wwi->lpQueuePtr = lpWaveHdr;
+	    else {
+	        for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
+	        *wh = lpWaveHdr;
+	    }
+	} else {
+            ERR("should only have headers left\n");
+        }
     }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
 }
 
-static ULONG WINAPI IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
+/**************************************************************************
+ * 				widRecorder			[internal]
+ */
+static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
 {
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
+    WORD		uDevID = (DWORD)pmt;
+    WINE_WAVEIN*	wwi = (WINE_WAVEIN*)&WInDev[uDevID];
+    WAVEHDR*		lpWaveHdr;
+    DWORD		dwSleepTime;
+    DWORD		bytesRead;
+    LPVOID		buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wwi->dwFragmentSize);
+    char               *pOffset = buffer;
+    audio_buf_info 	info;
+    int 		xs;
+    enum win_wm_message msg;
+    DWORD		param;
+    HANDLE		ev;
+    int                 enable;
 
-    return InterlockedIncrement(&(This->ref));
-}
+    wwi->state = WINE_WS_STOPPED;
+    wwi->dwTotalRecorded = 0;
+    wwi->dwTotalRead = 0;
+    wwi->lpQueuePtr = NULL;
 
-static ULONG WINAPI IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
+    SetEvent(wwi->hStartUpEvent);
 
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
-        if (This->notifies != NULL)
-            HeapFree(GetProcessHeap(), 0, This->notifies);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
+    /* disable input so capture will begin when triggered */
+    wwi->ossdev->bInputEnabled = FALSE;
+    enable = getEnables(wwi->ossdev);
+    if (ioctl(wwi->ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
+	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev->dev_name, strerror(errno));
 
-static HRESULT WINAPI IDsDriverNotifyImpl_SetNotificationPositions(
-    PIDSDRIVERNOTIFY iface,
-    DWORD howmuch,
-    LPCDSBPOSITIONNOTIFY notify)
-{
-    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
-    TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+    /* the soundblaster live needs a micro wake to get its recording started
+     * (or GETISPACE will have 0 frags all the time)
+     */
+    read(wwi->ossdev->fd, &xs, 4);
 
-    if (!notify) {
-        WARN("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
+    /* make sleep time to be # of ms to output a fragment */
+    dwSleepTime = (wwi->dwFragmentSize * 1000) / wwi->waveFormat.Format.nAvgBytesPerSec;
+    TRACE("sleeptime=%ld ms\n", dwSleepTime);
 
-    if (TRACE_ON(wave)) {
-        int i;
-        for (i=0;i<howmuch;i++)
-            TRACE("notify at %ld to 0x%08lx\n",
-                notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
-    }
+    for (;;) {
+	/* wait for dwSleepTime or an event in thread's queue */
+	/* FIXME: could improve wait time depending on queue state,
+	 * ie, number of queued fragments
+	 */
 
-    /* Make an internal copy of the caller-supplied array.
-     * Replace the existing copy if one is already present. */
-    if (This->notifies)
-        This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-        This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
-    else
-        This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-        howmuch * sizeof(DSBPOSITIONNOTIFY));
+	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
+        {
+            lpWaveHdr = wwi->lpQueuePtr;
 
-    memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
-    This->nrofnotifies = howmuch;
+	    ioctl(wwi->ossdev->fd, SNDCTL_DSP_GETISPACE, &info);
+            TRACE("info={frag=%d fsize=%d ftotal=%d bytes=%d}\n", info.fragments, info.fragsize, info.fragstotal, info.bytes);
 
-    return S_OK;
-}
+            /* read all the fragments accumulated so far */
+            while ((info.fragments > 0) && (wwi->lpQueuePtr))
+            {
+                info.fragments --;
 
-IDsDriverNotifyVtbl dsdnvt =
-{
-    IDsDriverNotifyImpl_QueryInterface,
-    IDsDriverNotifyImpl_AddRef,
-    IDsDriverNotifyImpl_Release,
-    IDsDriverNotifyImpl_SetNotificationPositions,
-};
+                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded >= wwi->dwFragmentSize)
+                {
+                    /* directly read fragment in wavehdr */
+                    bytesRead = read(wwi->ossdev->fd,
+		      		     lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
+                                     wwi->dwFragmentSize);
 
-/*======================================================================*
- *                  Low level DSOUND implementation                     *
- *======================================================================*/
+                    TRACE("bytesRead=%ld (direct)\n", bytesRead);
+                    if (bytesRead != (DWORD) -1)
+		    {
+			/* update number of bytes recorded in current buffer and by this device */
+                        lpWaveHdr->dwBytesRecorded += bytesRead;
+			wwi->dwTotalRead           += bytesRead;
+			wwi->dwTotalRecorded = wwi->dwTotalRead;
 
-static HRESULT DSDB_MapBuffer(IDsDriverBufferImpl *dsdb)
-{
-    TRACE("(%p), format=%ldx%dx%d\n", dsdb, dsdb->wfex.Format.nSamplesPerSec,
-          dsdb->wfex.Format.wBitsPerSample, dsdb->wfex.Format.nChannels);
-    if (!dsdb->mapping) {
-        dsdb->mapping = mmap(NULL, dsdb->maplen, PROT_WRITE, MAP_SHARED,
-                             dsdb->fd, 0);
-        if (dsdb->mapping == (LPBYTE)-1) {
-            ERR("Could not map sound device for direct access (%s)\n", strerror(errno));
-            ERR("Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n");
-            return DSERR_GENERIC;
-        }
-        TRACE("The sound device has been mapped for direct access at %p, size=%ld\n", dsdb->mapping, dsdb->maplen);
+			/* buffer is full. notify client */
+			if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
+			{
+			    /* must copy the value of next waveHdr, because we have no idea of what
+			     * will be done with the content of lpWaveHdr in callback
+			     */
+			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
 
-	/* for some reason, es1371 and sblive! sometimes have junk in here.
-	 * clear it, or we get junk noise */
-	/* some libc implementations are buggy: their memset reads from the buffer...
-	 * to work around it, we have to zero the block by hand. We don't do the expected:
-	 * memset(dsdb->mapping,0, dsdb->maplen);
-	 */
-	{
-            unsigned char*      p1 = dsdb->mapping;
-            unsigned            len = dsdb->maplen;
-	    unsigned char	silence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 128 : 0;
-	    unsigned long	ulsilence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 0x80808080 : 0;
+			    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
+			    lpWaveHdr->dwFlags |=  WHDR_DONE;
 
-	    if (len >= 16) /* so we can have at least a 4 long area to store... */
-	    {
-		/* the mmap:ed value is (at least) dword aligned
-		 * so, start filling the complete unsigned long:s
-		 */
-		int		b = len >> 2;
-		unsigned long*	p4 = (unsigned long*)p1;
+			    wwi->lpQueuePtr = lpNext;
+			    widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
+			    lpWaveHdr = lpNext;
+			}
+                    } else {
+                        TRACE("read(%s, %p, %ld) failed (%s)\n", wwi->ossdev->dev_name,
+                            lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
+                            wwi->dwFragmentSize, strerror(errno));
+                    }
+                }
+                else
+		{
+                    /* read the fragment in a local buffer */
+                    bytesRead = read(wwi->ossdev->fd, buffer, wwi->dwFragmentSize);
+                    pOffset = buffer;
 
-		while (b--) *p4++ = ulsilence;
-		/* prepare for filling the rest */
-		len &= 3;
-		p1 = (unsigned char*)p4;
-	    }
-	    /* in all cases, fill the remaining bytes */
-	    while (len-- != 0) *p1++ = silence;
-	}
-    }
-    return DS_OK;
-}
+                    TRACE("bytesRead=%ld (local)\n", bytesRead);
 
-static HRESULT DSDB_UnmapBuffer(IDsDriverBufferImpl *dsdb)
-{
-    TRACE("(%p)\n",dsdb);
-    if (dsdb->mapping) {
-        if (munmap(dsdb->mapping, dsdb->maplen) < 0) {
-            ERR("(%p): Could not unmap sound device (%s)\n", dsdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        dsdb->mapping = NULL;
-        TRACE("(%p): sound device unmapped\n", dsdb);
-    }
-    return DS_OK;
-}
+                    if (bytesRead == (DWORD) -1) {
+                        TRACE("read(%s, %p, %ld) failed (%s)\n", wwi->ossdev->dev_name,
+                            buffer, wwi->dwFragmentSize, strerror(errno));
+                        continue;
+                    }
 
-static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),*ppobj);
+                    /* copy data in client buffers */
+                    while (bytesRead != (DWORD) -1 && bytesRead > 0)
+                    {
+                        DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
 
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverBuffer) ) {
-	IDsDriverBuffer_AddRef(iface);
-	*ppobj = (LPVOID)This;
-	return DS_OK;
-    }
+                        memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
+                               pOffset,
+                               dwToCopy);
 
-    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
-        if (!This->notify)
-            IDsDriverNotifyImpl_Create(This, &(This->notify));
-        if (This->notify) {
-            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-            *ppobj = (LPVOID)This->notify;
-            return DS_OK;
-        }
-        *ppobj = 0;
-        return E_FAIL;
-    }
+                        /* update number of bytes recorded in current buffer and by this device */
+                        lpWaveHdr->dwBytesRecorded += dwToCopy;
+                        wwi->dwTotalRead           += dwToCopy;
+			wwi->dwTotalRecorded = wwi->dwTotalRead;
+                        bytesRead -= dwToCopy;
+                        pOffset   += dwToCopy;
 
-    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
-        if (!This->property_set)
-            IDsDriverPropertySetImpl_Create(This, &(This->property_set));
-        if (This->property_set) {
-            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
-            *ppobj = (LPVOID)This->property_set;
-            return DS_OK;
-        }
-	*ppobj = 0;
-	return E_FAIL;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref)
-        return ref;
-
-    if (This == This->drv->primary)
-	This->drv->primary = NULL;
-    else {
-        int i;
-        for (i = 0; i < This->drv->nrofsecondaries; i++)
-            if (This->drv->secondaries[i] == This)
-                break;
-        if (i < This->drv->nrofsecondaries) {
-            /* Put the last buffer of the list in the (now empty) position */
-            This->drv->secondaries[i] = This->drv->secondaries[This->drv->nrofsecondaries - 1];
-            This->drv->nrofsecondaries--;
-            This->drv->secondaries = HeapReAlloc(GetProcessHeap(),0,
-                This->drv->secondaries,
-                sizeof(PIDSDRIVERBUFFER)*This->drv->nrofsecondaries);
-            TRACE("(%p) buffer count is now %d\n", This, This->drv->nrofsecondaries);
-        }
-
-        WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingAllBuffers++;
-        WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingStreamingBuffers++;
-    }
-
-    DSDB_UnmapBuffer(This);
-    HeapFree(GetProcessHeap(),0,This);
-    TRACE("(%p) released\n",This);
-    return 0;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
-					       LPVOID*ppvAudio1,LPDWORD pdwLen1,
-					       LPVOID*ppvAudio2,LPDWORD pdwLen2,
-					       DWORD dwWritePosition,DWORD dwWriteLen,
-					       DWORD dwFlags)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
-     * and that we don't support secondary buffers, this method will never be called */
-    TRACE("(%p): stub\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
-						 LPVOID pvAudio1,DWORD dwLen1,
-						 LPVOID pvAudio2,DWORD dwLen2)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    TRACE("(%p): stub\n",iface);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
-						    LPWAVEFORMATEX pwfx)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-
-    TRACE("(%p,%p)\n",iface,pwfx);
-    /* On our request (GetDriverDesc flags), DirectSound has by now used
-     * waveOutClose/waveOutOpen to set the format...
-     * unfortunately, this means our mmap() is now gone...
-     * so we need to somehow signal to our DirectSound implementation
-     * that it should completely recreate this HW buffer...
-     * this unexpected error code should do the trick... */
-    return DSERR_BUFFERLOST;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
-{
-    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-    TRACE("(%p,%ld): stub\n",iface,dwFreq);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
-{
-    DWORD vol;
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    TRACE("(%p,%p)\n",This,pVolPan);
-
-    vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
-
-    if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
-	WARN("wodSetVolume failed\n");
-	return DSERR_INVALIDPARAM;
-    }
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
-{
-    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
-    TRACE("(%p,%ld): stub\n",iface,dwNewPos);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
-						      LPDWORD lpdwPlay, LPDWORD lpdwWrite)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    count_info info;
-    DWORD ptr;
-
-    TRACE("(%p)\n",iface);
-    if (WOutDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
-	ERR("device not open, but accessing?\n");
-	return DSERR_UNINITIALIZED;
-    }
-    if (ioctl(This->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
-            WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-    ptr = info.ptr & ~3; /* align the pointer, just in case */
-    if (lpdwPlay) *lpdwPlay = ptr;
-    if (lpdwWrite) {
-	/* add some safety margin (not strictly necessary, but...) */
-	if (WOutDev[This->drv->wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
-	    *lpdwWrite = ptr + 32;
-	else
-	    *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
-	while (*lpdwWrite > This->buflen)
-	    *lpdwWrite -= This->buflen;
-    }
-    TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags);
-    WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
-    enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
-    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	if (errno == EINVAL) {
-	    /* Don't give up yet. OSS trigger support is inconsistent. */
-	    if (WOutDev[This->drv->wDevID].ossdev->open_count == 1) {
-		/* try the opposite input enable */
-		if (WOutDev[This->drv->wDevID].ossdev->bInputEnabled == FALSE)
-		    WOutDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
-		else
-		    WOutDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
-		/* try it again */
-    		enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
-                if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0)
-		    return DS_OK;
-	    }
-	}
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-	WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
-{
-    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p)\n",iface);
-    /* no more playing */
-    WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
-    enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
-    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-#if 0
-    /* the play position must be reset to the beginning of the buffer */
-    if (ioctl(This->fd, SNDCTL_DSP_RESET, 0) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-#endif
-    /* Most OSS drivers just can't stop the playback without closing the device...
-     * so we need to somehow signal to our DirectSound implementation
-     * that it should completely recreate this HW buffer...
-     * this unexpected error code should do the trick... */
-    /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
-    if (WOutDev[This->drv->wDevID].ossdev->open_count == 1)
-	return DSERR_BUFFERLOST;
-
-    return DS_OK;
-}
-
-static IDsDriverBufferVtbl dsdbvt =
-{
-    IDsDriverBufferImpl_QueryInterface,
-    IDsDriverBufferImpl_AddRef,
-    IDsDriverBufferImpl_Release,
-    IDsDriverBufferImpl_Lock,
-    IDsDriverBufferImpl_Unlock,
-    IDsDriverBufferImpl_SetFormat,
-    IDsDriverBufferImpl_SetFrequency,
-    IDsDriverBufferImpl_SetVolumePan,
-    IDsDriverBufferImpl_SetPosition,
-    IDsDriverBufferImpl_GetPosition,
-    IDsDriverBufferImpl_Play,
-    IDsDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriver) ) {
-	IDsDriver_AddRef(iface);
-	*ppobj = (LPVOID)This;
-	return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface,
-                                                  PDSDRIVERDESC pDesc)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%p)\n",iface,pDesc);
-
-    /* copy version from driver */
-    memcpy(pDesc, &(WOutDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-
-    pDesc->dwFlags |= DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
-        DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK |
-        DSDDESC_DONTNEEDSECONDARYLOCK;
-    pDesc->dnDevNode		= WOutDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId		= 0;
-    pDesc->wReserved		= 0;
-    pDesc->ulDeviceNum		= This->wDevID;
-    pDesc->dwHeapType		= DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap	= NULL;
-    pDesc->dwMemStartAddress	= 0;
-    pDesc->dwMemEndAddress	= 0;
-    pDesc->dwMemAllocExtra	= 0;
-    pDesc->pvReserved1		= NULL;
-    pDesc->pvReserved2		= NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    int enable;
-    TRACE("(%p)\n",iface);
-
-    /* make sure the card doesn't start playing before we want it to */
-    WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
-    enable = getEnables(WOutDev[This->wDevID].ossdev);
-    if (ioctl(WOutDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p)\n",iface);
-    if (This->primary) {
-	ERR("problem with DirectSound: primary not released\n");
-	return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    TRACE("(%p,%p)\n",iface,pCaps);
-    memcpy(pCaps, &(WOutDev[This->wDevID].ossdev->ds_caps), sizeof(DSDRIVERCAPS));
-    return DS_OK;
-}
-
-static HRESULT WINAPI DSD_CreatePrimaryBuffer(PIDSDRIVER iface,
-                                              LPWAVEFORMATEX pwfx,
-                                              DWORD dwFlags,
-                                              DWORD dwCardAddress,
-                                              LPDWORD pdwcbBufferSize,
-                                              LPBYTE *ppbBuffer,
-                                              LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
-    HRESULT err;
-    audio_buf_info info;
-    int enable = 0;
-    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (This->primary)
-	return DSERR_ALLOCATED;
-    if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
-	return DSERR_CONTROLUNAVAIL;
-
-    *ippdsdb = (IDsDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverBufferImpl));
-    if (*ippdsdb == NULL)
-	return DSERR_OUTOFMEMORY;
-    (*ippdsdb)->lpVtbl  = &dsdbvt;
-    (*ippdsdb)->ref	= 1;
-    (*ippdsdb)->drv	= This;
-    copy_format(pwfx, &(*ippdsdb)->wfex);
-    (*ippdsdb)->fd      = WOutDev[This->wDevID].ossdev->fd;
-    (*ippdsdb)->dwFlags = dwFlags;
-
-    /* check how big the DMA buffer is now */
-    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
-            WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
-	HeapFree(GetProcessHeap(),0,*ippdsdb);
-	*ippdsdb = NULL;
-	return DSERR_GENERIC;
-    }
-    (*ippdsdb)->maplen = (*ippdsdb)->buflen = info.fragstotal * info.fragsize;
-
-    /* map the DMA buffer */
-    err = DSDB_MapBuffer(*ippdsdb);
-    if (err != DS_OK) {
-	HeapFree(GetProcessHeap(),0,*ippdsdb);
-	*ippdsdb = NULL;
-	return err;
-    }
-
-    /* primary buffer is ready to go */
-    *pdwcbBufferSize    = (*ippdsdb)->maplen;
-    *ppbBuffer          = (*ippdsdb)->mapping;
-
-    /* some drivers need some extra nudging after mapping */
-    WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
-    enable = getEnables(WOutDev[This->wDevID].ossdev);
-    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
-	return DSERR_GENERIC;
-    }
-
-    This->primary = *ippdsdb;
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI DSD_CreateSecondaryBuffer(PIDSDRIVER iface,
-                                                LPWAVEFORMATEX pwfx,
-                                                DWORD dwFlags,
-                                                DWORD dwCardAddress,
-                                                LPDWORD pdwcbBufferSize,
-                                                LPBYTE *ppbBuffer,
-                                                LPVOID *ppvObj)
-{
-    IDsDriverImpl *This = (IDsDriverImpl *)iface;
-    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
-    FIXME("(%p,%p,%lx,%lx,%p,%p,%p): stub\n",This,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    *ippdsdb = 0;
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
-                                                      LPWAVEFORMATEX pwfx,
-                                                      DWORD dwFlags,
-                                                      DWORD dwCardAddress,
-                                                      LPDWORD pdwcbBufferSize,
-                                                      LPBYTE *ppbBuffer,
-                                                      LPVOID *ppvObj)
-{
-    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (dwFlags & DSBCAPS_PRIMARYBUFFER)
-        return DSD_CreatePrimaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    return DSD_CreateSecondaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-}
-
-static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
-							 PIDSDRIVERBUFFER pBuffer,
-							 LPVOID *ppvObj)
-{
-    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
-    TRACE("(%p,%p): stub\n",iface,pBuffer);
-    return DSERR_INVALIDCALL;
-}
-
-static IDsDriverVtbl dsdvt =
-{
-    IDsDriverImpl_QueryInterface,
-    IDsDriverImpl_AddRef,
-    IDsDriverImpl_Release,
-    IDsDriverImpl_GetDriverDesc,
-    IDsDriverImpl_Open,
-    IDsDriverImpl_Close,
-    IDsDriverImpl_GetCaps,
-    IDsDriverImpl_CreateSoundBuffer,
-    IDsDriverImpl_DuplicateSoundBuffer
-};
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverPropertySetImpl **pdsdps)
-{
-    IDsDriverPropertySetImpl * dsdps;
-    TRACE("(%p,%p)\n",dsdb,pdsdps);
-
-    dsdps = (IDsDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdps));
-    if (dsdps == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dsdps->ref = 0;
-    dsdps->lpVtbl = &dsdpsvt;
-    dsdps->buffer = dsdb;
-    dsdb->property_set = dsdps;
-    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
-    *pdsdps = dsdps;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverNotifyImpl_Create(
-    IDsDriverBufferImpl * dsdb,
-    IDsDriverNotifyImpl **pdsdn)
-{
-    IDsDriverNotifyImpl * dsdn;
-    TRACE("(%p,%p)\n",dsdb,pdsdn);
-
-    dsdn = (IDsDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdn));
-
-    if (dsdn == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dsdn->ref = 0;
-    dsdn->lpVtbl = &dsdnvt;
-    dsdn->buffer = dsdb;
-    dsdb->notify = dsdn;
-    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
-    *pdsdn = dsdn;
-    return DS_OK;
-};
-
-static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
-{
-    IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
-    TRACE("(%d,%p)\n",wDevID,drv);
-
-    /* the HAL isn't much better than the HEL if we can't do mmap() */
-    if (!(WOutDev[wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
-	ERR("DirectSound flag not set\n");
-	MESSAGE("This sound card's driver does not support direct access\n");
-	MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
-	return MMSYSERR_NOTSUPPORTED;
-    }
-
-    *idrv = (IDsDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverImpl));
-    if (!*idrv)
-	return MMSYSERR_NOMEM;
-    (*idrv)->lpVtbl          = &dsdvt;
-    (*idrv)->ref             = 1;
-    (*idrv)->wDevID          = wDevID;
-    (*idrv)->primary         = NULL;
-    (*idrv)->nrofsecondaries = 0;
-    (*idrv)->secondaries     = NULL;
-
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    TRACE("(%d,%p)\n",wDevID,desc);
-    memcpy(desc, &(WOutDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-    return MMSYSERR_NOERROR;
-}
-
-/*======================================================================*
- *                  Low level WAVE IN implementation			*
- *======================================================================*/
-
-/**************************************************************************
- * 			widNotifyClient			[internal]
- */
-static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
-{
-    TRACE("wMsg = 0x%04x (%s) dwParm1 = %04lX dwParam2 = %04lX\n", wMsg,
-        wMsg == WIM_OPEN ? "WIM_OPEN" : wMsg == WIM_CLOSE ? "WIM_CLOSE" :
-        wMsg == WIM_DATA ? "WIM_DATA" : "Unknown", dwParam1, dwParam2);
-
-    switch (wMsg) {
-    case WIM_OPEN:
-    case WIM_CLOSE:
-    case WIM_DATA:
-	if (wwi->wFlags != DCB_NULL &&
-	    !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
-			    (HDRVR)wwi->waveDesc.hWave, wMsg,
-			    wwi->waveDesc.dwInstance, dwParam1, dwParam2)) {
-	    WARN("can't notify client !\n");
-	    return MMSYSERR_ERROR;
-	}
-	break;
-    default:
-	FIXME("Unknown callback message %u\n", wMsg);
-	return MMSYSERR_INVALPARAM;
-    }
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 			widGetDevCaps				[internal]
- */
-static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSA lpCaps, DWORD dwSize)
-{
-    TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
-
-    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
-
-    if (wDevID >= numInDev) {
-	TRACE("numOutDev reached !\n");
-	return MMSYSERR_BADDEVICEID;
-    }
-
-    memcpy(lpCaps, &WInDev[wDevID].ossdev->in_caps, min(dwSize, sizeof(*lpCaps)));
-    return MMSYSERR_NOERROR;
-}
-
-/**************************************************************************
- * 				widRecorder_ReadHeaders		[internal]
- */
-static void widRecorder_ReadHeaders(WINE_WAVEIN * wwi)
-{
-    enum win_wm_message tmp_msg;
-    DWORD		tmp_param;
-    HANDLE		tmp_ev;
-    WAVEHDR*		lpWaveHdr;
-
-    while (OSS_RetrieveRingMessage(&wwi->msgRing, &tmp_msg, &tmp_param, &tmp_ev)) {
-        if (tmp_msg == WINE_WM_HEADER) {
-	    LPWAVEHDR*	wh;
-	    lpWaveHdr = (LPWAVEHDR)tmp_param;
-	    lpWaveHdr->lpNext = 0;
-
-	    if (wwi->lpQueuePtr == 0)
-		wwi->lpQueuePtr = lpWaveHdr;
-	    else {
-	        for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
-	        *wh = lpWaveHdr;
-	    }
-	} else {
-            ERR("should only have headers left\n");
-        }
-    }
-}
-
-/**************************************************************************
- * 				widRecorder			[internal]
- */
-static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
-{
-    WORD		uDevID = (DWORD)pmt;
-    WINE_WAVEIN*	wwi = (WINE_WAVEIN*)&WInDev[uDevID];
-    WAVEHDR*		lpWaveHdr;
-    DWORD		dwSleepTime;
-    DWORD		bytesRead;
-    LPVOID		buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wwi->dwFragmentSize);
-    char               *pOffset = buffer;
-    audio_buf_info 	info;
-    int 		xs;
-    enum win_wm_message msg;
-    DWORD		param;
-    HANDLE		ev;
-    int                 enable;
-
-    wwi->state = WINE_WS_STOPPED;
-    wwi->dwTotalRecorded = 0;
-    wwi->dwTotalRead = 0;
-    wwi->lpQueuePtr = NULL;
-
-    SetEvent(wwi->hStartUpEvent);
-
-    /* disable input so capture will begin when triggered */
-    wwi->ossdev->bInputEnabled = FALSE;
-    enable = getEnables(wwi->ossdev);
-    if (ioctl(wwi->ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
-	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", wwi->ossdev->dev_name, strerror(errno));
-
-    /* the soundblaster live needs a micro wake to get its recording started
-     * (or GETISPACE will have 0 frags all the time)
-     */
-    read(wwi->ossdev->fd, &xs, 4);
-
-    /* make sleep time to be # of ms to output a fragment */
-    dwSleepTime = (wwi->dwFragmentSize * 1000) / wwi->waveFormat.Format.nAvgBytesPerSec;
-    TRACE("sleeptime=%ld ms\n", dwSleepTime);
-
-    for (;;) {
-	/* wait for dwSleepTime or an event in thread's queue */
-	/* FIXME: could improve wait time depending on queue state,
-	 * ie, number of queued fragments
-	 */
-
-	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
-        {
-            lpWaveHdr = wwi->lpQueuePtr;
-
-	    ioctl(wwi->ossdev->fd, SNDCTL_DSP_GETISPACE, &info);
-            TRACE("info={frag=%d fsize=%d ftotal=%d bytes=%d}\n", info.fragments, info.fragsize, info.fragstotal, info.bytes);
-
-            /* read all the fragments accumulated so far */
-            while ((info.fragments > 0) && (wwi->lpQueuePtr))
-            {
-                info.fragments --;
-
-                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded >= wwi->dwFragmentSize)
-                {
-                    /* directly read fragment in wavehdr */
-                    bytesRead = read(wwi->ossdev->fd,
-		      		     lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                                     wwi->dwFragmentSize);
-
-                    TRACE("bytesRead=%ld (direct)\n", bytesRead);
-                    if (bytesRead != (DWORD) -1)
-		    {
-			/* update number of bytes recorded in current buffer and by this device */
-                        lpWaveHdr->dwBytesRecorded += bytesRead;
-			wwi->dwTotalRead           += bytesRead;
-			wwi->dwTotalRecorded = wwi->dwTotalRead;
-
-			/* buffer is full. notify client */
-			if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
-			{
-			    /* must copy the value of next waveHdr, because we have no idea of what
-			     * will be done with the content of lpWaveHdr in callback
-			     */
-			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-
-			    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
-			    lpWaveHdr->dwFlags |=  WHDR_DONE;
-
-			    wwi->lpQueuePtr = lpNext;
-			    widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
-			    lpWaveHdr = lpNext;
-			}
-                    } else {
-                        TRACE("read(%s, %p, %ld) failed (%s)\n", wwi->ossdev->dev_name,
-                            lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                            wwi->dwFragmentSize, strerror(errno));
-                    }
-                }
-                else
-		{
-                    /* read the fragment in a local buffer */
-                    bytesRead = read(wwi->ossdev->fd, buffer, wwi->dwFragmentSize);
-                    pOffset = buffer;
-
-                    TRACE("bytesRead=%ld (local)\n", bytesRead);
-
-                    if (bytesRead == (DWORD) -1) {
-                        TRACE("read(%s, %p, %ld) failed (%s)\n", wwi->ossdev->dev_name,
-                            buffer, wwi->dwFragmentSize, strerror(errno));
-                        continue;
-                    }
-
-                    /* copy data in client buffers */
-                    while (bytesRead != (DWORD) -1 && bytesRead > 0)
-                    {
-                        DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
-
-                        memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
-                               pOffset,
-                               dwToCopy);
-
-                        /* update number of bytes recorded in current buffer and by this device */
-                        lpWaveHdr->dwBytesRecorded += dwToCopy;
-                        wwi->dwTotalRead           += dwToCopy;
-			wwi->dwTotalRecorded = wwi->dwTotalRead;
-                        bytesRead -= dwToCopy;
-                        pOffset   += dwToCopy;
-
-                        /* client buffer is full. notify client */
-                        if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
-                        {
-			    /* must copy the value of next waveHdr, because we have no idea of what
-			     * will be done with the content of lpWaveHdr in callback
-			     */
-			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
-			    TRACE("lpNext=%p\n", lpNext);
+                        /* client buffer is full. notify client */
+                        if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
+                        {
+			    /* must copy the value of next waveHdr, because we have no idea of what
+			     * will be done with the content of lpWaveHdr in callback
+			     */
+			    LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
+			    TRACE("lpNext=%p\n", lpNext);
 
                             lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
                             lpWaveHdr->dwFlags |=  WHDR_DONE;
@@ -3703,7 +2679,7 @@
 /**************************************************************************
  * 				widOpen				[internal]
  */
-static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
 {
     WINE_WAVEIN*	wwi;
     audio_buf_info      info;
@@ -4049,846 +3025,6 @@
     return MMSYSERR_NOTSUPPORTED;
 }
 
-/*======================================================================*
- *           Low level DSOUND capture definitions                       *
- *======================================================================*/
-
-typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
-typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
-typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
-typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
-
-struct IDsCaptureDriverPropertySetImpl
-{
-    /* IUnknown fields */
-    IDsDriverPropertySetVtbl           *lpVtbl;
-    DWORD                               ref;
-
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverNotifyImpl
-{
-    /* IUnknown fields */
-    IDsDriverNotifyVtbl                *lpVtbl;
-    DWORD                               ref;
-
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverImpl
-{
-    /* IUnknown fields */
-    IDsCaptureDriverVtbl               *lpVtbl;
-    DWORD                               ref;
-
-    /* IDsCaptureDriverImpl fields */
-    UINT                                wDevID;
-    IDsCaptureDriverBufferImpl*         capture_buffer;
-};
-
-struct IDsCaptureDriverBufferImpl
-{
-    /* IUnknown fields */
-    IDsCaptureDriverBufferVtbl         *lpVtbl;
-    DWORD                               ref;
-
-    /* IDsCaptureDriverBufferImpl fields */
-    IDsCaptureDriverImpl*               drv;
-    DWORD                               buflen;
-    LPBYTE                              buffer;
-    DWORD                               writeptr;
-    LPBYTE                              mapping;
-    DWORD                               maplen;
-
-    /* IDsDriverNotifyImpl fields */
-    IDsCaptureDriverNotifyImpl*         notify;
-    int                                 notify_index;
-    LPDSBPOSITIONNOTIFY                 notifies;
-    int                                 nrofnotifies;
-
-    /* IDsDriverPropertySetImpl fields */
-    IDsCaptureDriverPropertySetImpl*    property_set;
-
-    BOOL                                is_capturing;
-    BOOL                                is_looping;
-};
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverPropertySetImpl **pdscdps);
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
-    IDsCaptureDriverBufferImpl * dsdcb,
-    IDsCaptureDriverNotifyImpl **pdscdn);
-
-/*======================================================================*
- *           Low level DSOUND capture property set implementation       *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
-    PIDSDRIVERPROPERTYSET iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
-        IDsDriverPropertySet_AddRef(iface);
-        *ppobj = (LPVOID)This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
-    PIDSDRIVERPROPERTYSET iface)
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
-    PIDSDRIVERPROPERTYSET iface)
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
-        This->capture_buffer->property_set = NULL;
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData,
-    PULONG pcbReturnedData )
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,
-          cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
-    PIDSDRIVERPROPERTYSET iface,
-    PDSPROPERTY pDsProperty,
-    LPVOID pPropertyParams,
-    ULONG cbPropertyParams,
-    LPVOID pPropertyData,
-    ULONG cbPropertyData )
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,
-          cbPropertyParams,pPropertyData,cbPropertyData);
-    return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
-    PIDSDRIVERPROPERTYSET iface,
-    REFGUID PropertySetId,
-    ULONG PropertyId,
-    PULONG pSupport )
-{
-    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
-    FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
-          pSupport);
-    return DSERR_UNSUPPORTED;
-}
-
-IDsDriverPropertySetVtbl dscdpsvt =
-{
-    IDsCaptureDriverPropertySetImpl_QueryInterface,
-    IDsCaptureDriverPropertySetImpl_AddRef,
-    IDsCaptureDriverPropertySetImpl_Release,
-    IDsCaptureDriverPropertySetImpl_Get,
-    IDsCaptureDriverPropertySetImpl_Set,
-    IDsCaptureDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- *                  Low level DSOUND capture notify implementation      *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
-    PIDSDRIVERNOTIFY iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
-        IDsDriverNotify_AddRef(iface);
-        *ppobj = This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
-    PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
-    PIDSDRIVERNOTIFY iface)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
-        This->capture_buffer->notify = NULL;
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
-    PIDSDRIVERNOTIFY iface,
-    DWORD howmuch,
-    LPCDSBPOSITIONNOTIFY notify)
-{
-    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
-    TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
-
-    if (!notify) {
-        WARN("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (TRACE_ON(wave)) {
-        int i;
-        for (i=0;i<howmuch;i++)
-            TRACE("notify at %ld to 0x%08lx\n",
-                notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
-    }
-
-    /* Make an internal copy of the caller-supplied array.
-     * Replace the existing copy if one is already present. */
-    if (This->capture_buffer->notifies)
-        This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
-            HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
-            howmuch * sizeof(DSBPOSITIONNOTIFY));
-    else
-        This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
-            HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
-
-    memcpy(This->capture_buffer->notifies, notify,
-           howmuch * sizeof(DSBPOSITIONNOTIFY));
-    This->capture_buffer->nrofnotifies = howmuch;
-
-    return S_OK;
-}
-
-IDsDriverNotifyVtbl dscdnvt =
-{
-    IDsCaptureDriverNotifyImpl_QueryInterface,
-    IDsCaptureDriverNotifyImpl_AddRef,
-    IDsCaptureDriverNotifyImpl_Release,
-    IDsCaptureDriverNotifyImpl_SetNotificationPositions,
-};
-
-/*======================================================================*
- *                  Low level DSOUND capture implementation             *
- *======================================================================*/
-
-static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
-    if (!dscdb->mapping) {
-        dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
-                              WInDev[dscdb->drv->wDevID].ossdev->fd, 0);
-        if (dscdb->mapping == (LPBYTE)-1) {
-            TRACE("(%p): Could not map sound device for direct access (%s)\n",
-                  dscdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        TRACE("(%p): sound device has been mapped for direct access at %p, size=%ld\n", dscdb, dscdb->mapping, dscdb->maplen);
-    }
-    return DS_OK;
-}
-
-static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
-    if (dscdb->mapping) {
-        if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
-            ERR("(%p): Could not unmap sound device (%s)\n",
-                dscdb, strerror(errno));
-            return DSERR_GENERIC;
-        }
-        dscdb->mapping = NULL;
-        TRACE("(%p): sound device unmapped\n", dscdb);
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
-    PIDSCDRIVERBUFFER iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    *ppobj = 0;
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
-        IDsCaptureDriverBuffer_AddRef(iface);
-        *ppobj = (LPVOID)This;
-        return DS_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
-        if (!This->notify)
-            IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
-        if (This->notify) {
-            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
-            *ppobj = (LPVOID)This->notify;
-            return DS_OK;
-        }
-        return E_FAIL;
-    }
-
-    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
-        if (!This->property_set)
-            IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
-        if (This->property_set) {
-            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
-            *ppobj = (LPVOID)This->property_set;
-            return DS_OK;
-        }
-        return E_FAIL;
-    }
-
-    FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
-    return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        DSCDB_UnmapBuffer(This);
-        if (This->notifies != NULL)
-            HeapFree(GetProcessHeap(), 0, This->notifies);
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
-    PIDSCDRIVERBUFFER iface,
-    LPVOID* ppvAudio1,
-    LPDWORD pdwLen1,
-    LPVOID* ppvAudio2,
-    LPDWORD pdwLen2,
-    DWORD dwWritePosition,
-    DWORD dwWriteLen,
-    DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    FIXME("(%p,%p,%p,%p,%p,%ld,%ld,0x%08lx): stub!\n",This,ppvAudio1,pdwLen1,
-          ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
-    PIDSCDRIVERBUFFER iface,
-    LPVOID pvAudio1,
-    DWORD dwLen1,
-    LPVOID pvAudio2,
-    DWORD dwLen2)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    FIXME("(%p,%p,%ld,%p,%ld): stub!\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
-    PIDSCDRIVERBUFFER iface,
-    LPDWORD lpdwCapture,
-    LPDWORD lpdwRead)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    count_info info;
-    DWORD ptr;
-    TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
-
-    if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
-        ERR("device not open, but accessing?\n");
-        return DSERR_UNINITIALIZED;
-    }
-
-    if (!This->is_capturing) {
-        if (lpdwCapture)
-            *lpdwCapture = 0;
-        if (lpdwRead)
-            *lpdwRead = 0;
-    }
-
-    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
-            WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-        return DSERR_GENERIC;
-    }
-    ptr = info.ptr & ~3; /* align the pointer, just in case */
-    if (lpdwCapture) *lpdwCapture = ptr;
-    if (lpdwRead) {
-        /* add some safety margin (not strictly necessary, but...) */
-        if (WInDev[This->drv->wDevID].ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
-            *lpdwRead = ptr + 32;
-        else
-            *lpdwRead = ptr + WInDev[This->drv->wDevID].dwFragmentSize;
-        while (*lpdwRead > This->buflen)
-            *lpdwRead -= This->buflen;
-    }
-    TRACE("capturepos=%ld, readpos=%ld\n", lpdwCapture?*lpdwCapture:0, lpdwRead?*lpdwRead:0);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
-    PIDSCDRIVERBUFFER iface,
-    LPDWORD lpdwStatus)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    TRACE("(%p,%p)\n",This,lpdwStatus);
-
-    if (This->is_capturing) {
-        if (This->is_looping)
-            *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
-        else
-            *lpdwStatus = DSCBSTATUS_CAPTURING;
-    } else
-        *lpdwStatus = 0;
-
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
-    PIDSCDRIVERBUFFER iface,
-    DWORD dwFlags)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p,%lx)\n",This,dwFlags);
-
-    if (This->is_capturing)
-        return DS_OK;
-
-    if (dwFlags & DSCBSTART_LOOPING)
-        This->is_looping = TRUE;
-
-    WInDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
-    enable = getEnables(WInDev[This->drv->wDevID].ossdev);
-    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        if (errno == EINVAL) {
-            /* Don't give up yet. OSS trigger support is inconsistent. */
-            if (WInDev[This->drv->wDevID].ossdev->open_count == 1) {
-                /* try the opposite output enable */
-                if (WInDev[This->drv->wDevID].ossdev->bOutputEnabled == FALSE)
-                    WInDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
-                else
-                    WInDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
-                /* try it again */
-                enable = getEnables(WInDev[This->drv->wDevID].ossdev);
-                if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
-                    This->is_capturing = TRUE;
-                    return DS_OK;
-                }
-            }
-        }
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
-        WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
-        return DSERR_GENERIC;
-    }
-
-    This->is_capturing = TRUE;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    int enable;
-    TRACE("(%p)\n",This);
-
-    if (!This->is_capturing)
-        return DS_OK;
-
-    /* no more captureing */
-    WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
-    enable = getEnables(WInDev[This->drv->wDevID].ossdev);
-    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WInDev[This->drv->wDevID].ossdev->dev_name,  strerror(errno));
-        return DSERR_GENERIC;
-    }
-
-    /* send a final event if necessary */
-    if (This->nrofnotifies > 0) {
-        if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
-            SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
-    }
-
-    This->is_capturing = FALSE;
-    This->is_looping = FALSE;
-
-    /* Most OSS drivers just can't stop capturing without closing the device...
-     * so we need to somehow signal to our DirectSound implementation
-     * that it should completely recreate this HW buffer...
-     * this unexpected error code should do the trick... */
-    return DSERR_BUFFERLOST;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
-    PIDSCDRIVERBUFFER iface,
-    LPWAVEFORMATEX pwfx)
-{
-    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
-    FIXME("(%p): stub!\n",This);
-    return DSERR_UNSUPPORTED;
-}
-
-static IDsCaptureDriverBufferVtbl dscdbvt =
-{
-    IDsCaptureDriverBufferImpl_QueryInterface,
-    IDsCaptureDriverBufferImpl_AddRef,
-    IDsCaptureDriverBufferImpl_Release,
-    IDsCaptureDriverBufferImpl_Lock,
-    IDsCaptureDriverBufferImpl_Unlock,
-    IDsCaptureDriverBufferImpl_SetFormat,
-    IDsCaptureDriverBufferImpl_GetPosition,
-    IDsCaptureDriverBufferImpl_GetStatus,
-    IDsCaptureDriverBufferImpl_Start,
-    IDsCaptureDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
-    PIDSCDRIVER iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if ( IsEqualGUID(riid, &IID_IUnknown) ||
-         IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
-        IDsCaptureDriver_AddRef(iface);
-        *ppobj = (LPVOID)This;
-        return DS_OK;
-    }
-
-    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
-    *ppobj = 0;
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    DWORD ref;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-
-    ref = InterlockedDecrement(&(This->ref));
-    if (ref == 0) {
-        HeapFree(GetProcessHeap(),0,This);
-        TRACE("(%p) released\n",This);
-    }
-    return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
-    PIDSCDRIVER iface,
-    PDSDRIVERDESC pDesc)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p,%p)\n",This,pDesc);
-
-    if (!pDesc) {
-        TRACE("invalid parameter\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    /* copy version from driver */
-    memcpy(pDesc, &(WInDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-
-    pDesc->dwFlags |= DSDDESC_USESYSTEMMEMORY;
-    pDesc->dnDevNode            = WInDev[This->wDevID].waveDesc.dnDevNode;
-    pDesc->wVxdId               = 0;
-    pDesc->wReserved            = 0;
-    pDesc->ulDeviceNum          = This->wDevID;
-    pDesc->dwHeapType           = DSDHEAP_NOHEAP;
-    pDesc->pvDirectDrawHeap     = NULL;
-    pDesc->dwMemStartAddress    = 0;
-    pDesc->dwMemEndAddress      = 0;
-    pDesc->dwMemAllocExtra      = 0;
-    pDesc->pvReserved1          = NULL;
-    pDesc->pvReserved2          = NULL;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p)\n",This);
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p)\n",This);
-    if (This->capture_buffer) {
-        ERR("problem with DirectSound: capture buffer not released\n");
-        return DSERR_GENERIC;
-    }
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
-    PIDSCDRIVER iface,
-    PDSCDRIVERCAPS pCaps)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    TRACE("(%p,%p)\n",This,pCaps);
-    memcpy(pCaps, &(WInDev[This->wDevID].ossdev->dsc_caps), sizeof(DSCDRIVERCAPS));
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
-    PIDSCDRIVER iface,
-    LPWAVEFORMATEX pwfx,
-    DWORD dwFlags,
-    DWORD dwCardAddress,
-    LPDWORD pdwcbBufferSize,
-    LPBYTE *ppbBuffer,
-    LPVOID *ppvObj)
-{
-    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
-    IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
-    HRESULT err;
-    audio_buf_info info;
-    int enable;
-    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
-          pdwcbBufferSize,ppbBuffer,ppvObj);
-
-    if (This->capture_buffer) {
-        TRACE("already allocated\n");
-        return DSERR_ALLOCATED;
-    }
-
-    *ippdscdb = (IDsCaptureDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
-    if (*ippdscdb == NULL) {
-        TRACE("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    (*ippdscdb)->lpVtbl = &dscdbvt;
-    (*ippdscdb)->ref          = 1;
-    (*ippdscdb)->drv          = This;
-    (*ippdscdb)->notify       = NULL;
-    (*ippdscdb)->notify_index = 0;
-    (*ippdscdb)->notifies     = NULL;
-    (*ippdscdb)->nrofnotifies = 0;
-    (*ippdscdb)->property_set = NULL;
-    (*ippdscdb)->is_capturing = FALSE;
-    (*ippdscdb)->is_looping   = FALSE;
-
-    if (WInDev[This->wDevID].state == WINE_WS_CLOSED) {
-        WAVEOPENDESC desc;
-        desc.hWave = 0;
-        desc.lpFormat = pwfx;
-        desc.dwCallback = 0;
-        desc.dwInstance = 0;
-        desc.uMappedDeviceID = 0;
-        desc.dnDevNode = 0;
-        err = widOpen(This->wDevID, &desc, dwFlags | WAVE_DIRECTSOUND);
-        if (err != MMSYSERR_NOERROR) {
-            TRACE("widOpen failed\n");
-            return err;
-        }
-    }
-
-    /* check how big the DMA buffer is now */
-    if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
-            WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return DSERR_GENERIC;
-    }
-    (*ippdscdb)->maplen = (*ippdscdb)->buflen = info.fragstotal * info.fragsize;
-
-    /* map the DMA buffer */
-    err = DSCDB_MapBuffer(*ippdscdb);
-    if (err != DS_OK) {
-        HeapFree(GetProcessHeap(),0,*ippdscdb);
-        *ippdscdb = NULL;
-        return err;
-    }
-
-    /* capture buffer is ready to go */
-    *pdwcbBufferSize    = (*ippdscdb)->maplen;
-    *ppbBuffer          = (*ippdscdb)->mapping;
-
-    /* some drivers need some extra nudging after mapping */
-    WInDev[This->wDevID].ossdev->bInputEnabled = FALSE;
-    enable = getEnables(WInDev[This->wDevID].ossdev);
-    if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
-        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
-            WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
-        return DSERR_GENERIC;
-    }
-
-    This->capture_buffer = *ippdscdb;
-
-    return DS_OK;
-}
-
-static IDsCaptureDriverVtbl dscdvt =
-{
-    IDsCaptureDriverImpl_QueryInterface,
-    IDsCaptureDriverImpl_AddRef,
-    IDsCaptureDriverImpl_Release,
-    IDsCaptureDriverImpl_GetDriverDesc,
-    IDsCaptureDriverImpl_Open,
-    IDsCaptureDriverImpl_Close,
-    IDsCaptureDriverImpl_GetCaps,
-    IDsCaptureDriverImpl_CreateCaptureBuffer
-};
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverPropertySetImpl **pdscdps)
-{
-    IDsCaptureDriverPropertySetImpl * dscdps;
-    TRACE("(%p,%p)\n",dscdb,pdscdps);
-
-    dscdps = (IDsCaptureDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdps));
-    if (dscdps == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dscdps->ref = 0;
-    dscdps->lpVtbl = &dscdpsvt;
-    dscdps->capture_buffer = dscdb;
-    dscdb->property_set = dscdps;
-    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
-    *pdscdps = dscdps;
-    return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
-    IDsCaptureDriverBufferImpl * dscdb,
-    IDsCaptureDriverNotifyImpl **pdscdn)
-{
-    IDsCaptureDriverNotifyImpl * dscdn;
-    TRACE("(%p,%p)\n",dscdb,pdscdn);
-
-    dscdn = (IDsCaptureDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdn));
-    if (dscdn == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    dscdn->ref = 0;
-    dscdn->lpVtbl = &dscdnvt;
-    dscdn->capture_buffer = dscdb;
-    dscdb->notify = dscdn;
-    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
-    *pdscdn = dscdn;
-    return DS_OK;
-};
-
-static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
-{
-    IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
-    TRACE("(%d,%p)\n",wDevID,drv);
-
-    /* the HAL isn't much better than the HEL if we can't do mmap() */
-    if (!(WInDev[wDevID].ossdev->in_caps_support & WAVECAPS_DIRECTSOUND)) {
-        ERR("DirectSoundCapture flag not set\n");
-        MESSAGE("This sound card's driver does not support direct access\n");
-        MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
-        return MMSYSERR_NOTSUPPORTED;
-    }
-
-    *idrv = (IDsCaptureDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
-    if (!*idrv)
-        return MMSYSERR_NOMEM;
-    (*idrv)->lpVtbl	= &dscdvt;
-    (*idrv)->ref	= 1;
-
-    (*idrv)->wDevID	= wDevID;
-    (*idrv)->capture_buffer = NULL;
-    return MMSYSERR_NOERROR;
-}
-
-static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
-    memcpy(desc, &(WInDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-    return MMSYSERR_NOERROR;
-}
-
 #else /* !HAVE_OSS */
 
 /**************************************************************************
diff -u -N wine.cvs/dlls/winmm/wineoss/audio.h wine/dlls/winmm/wineoss/audio.h
--- wine.cvs/dlls/winmm/wineoss/audio.h	1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/winmm/wineoss/audio.h	2004-10-17 20:35:04.000000000 -0400
@@ -0,0 +1,174 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/*
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
+ *
+ * Copyright 1994 Martin Ayotte
+ *           1999 Eric Pouech (async playing in waveOut/waveIn)
+ *	     2000 Eric Pouech (loops in waveOut)
+ *           2002 Eric Pouech (full duplex)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_OSS
+
+/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
+#define USE_PIPE_SYNC
+
+#define MAX_WAVEDRV 	(6)
+
+/* states of the playing device */
+#define	WINE_WS_PLAYING		0
+#define	WINE_WS_PAUSED		1
+#define	WINE_WS_STOPPED		2
+#define WINE_WS_CLOSED		3
+
+/* events to be send to device */
+enum win_wm_message {
+    WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
+    WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
+};
+
+#ifdef USE_PIPE_SYNC
+#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
+#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
+#define RESET_OMR(omr) do { } while (0)
+#define WAIT_OMR(omr, sleep) \
+  do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
+       pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
+#else
+#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
+#define CLEAR_OMR(omr) do { } while (0)
+#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
+#define WAIT_OMR(omr, sleep) \
+  do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
+#endif
+
+typedef struct {
+    enum win_wm_message 	msg;	/* message identifier */
+    DWORD	                param;  /* parameter for this message */
+    HANDLE	                hEvent;	/* if message is synchronous, handle of event for synchro */
+} OSS_MSG;
+
+/* implement an in-process message ring for better performance
+ * (compared to passing thru the server)
+ * this ring will be used by the input (resp output) record (resp playback) routine
+ */
+#define OSS_RING_BUFFER_INCREMENT	64
+typedef struct {
+    int                         ring_buffer_size;
+    OSS_MSG			* messages;
+    int				msg_tosave;
+    int				msg_toget;
+#ifdef USE_PIPE_SYNC
+    int				msg_pipe[2];
+#else
+    HANDLE			msg_event;
+#endif
+    CRITICAL_SECTION		msg_crst;
+} OSS_MSG_RING;
+
+typedef struct tagOSS_DEVICE {
+    char*                       dev_name;
+    char*                       mixer_name;
+    char*                       interface_name;
+    unsigned                    open_count;
+    WAVEOUTCAPSA                out_caps;
+    WAVEOUTCAPSA                duplex_out_caps;
+    WAVEINCAPSA                 in_caps;
+    DWORD                       in_caps_support;
+    unsigned                    open_access;
+    int                         fd;
+    DWORD                       owner_tid;
+    int                         sample_rate;
+    int                         stereo;
+    int                         format;
+    unsigned                    audio_fragment;
+    BOOL                        full_duplex;
+    BOOL                        bTriggerSupport;
+    BOOL                        bOutputEnabled;
+    BOOL                        bInputEnabled;
+    DSDRIVERDESC                ds_desc;
+    DSDRIVERCAPS                ds_caps;
+    DSCDRIVERCAPS               dsc_caps;
+} OSS_DEVICE;
+
+typedef struct {
+    OSS_DEVICE*                 ossdev;
+    volatile int		state;			/* one of the WINE_WS_ manifest constants */
+    WAVEOPENDESC		waveDesc;
+    WORD			wFlags;
+    WAVEFORMATPCMEX             waveFormat;
+    DWORD			volume;
+
+    /* OSS information */
+    DWORD			dwFragmentSize;		/* size of OSS buffer fragment */
+    DWORD                       dwBufferSize;           /* size of whole OSS buffer in bytes */
+    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
+    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
+    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
+
+    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
+    DWORD			dwLoops;		/* private copy of loop counter */
+
+    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */
+    DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
+    BOOL                        bNeedPost;              /* whether audio still needs to be physically started */
+
+    /* synchronization stuff */
+    HANDLE			hStartUpEvent;
+    HANDLE			hThread;
+    DWORD			dwThreadID;
+    OSS_MSG_RING		msgRing;
+} WINE_WAVEOUT;
+
+typedef struct {
+    OSS_DEVICE*                 ossdev;
+    volatile int		state;
+    DWORD			dwFragmentSize;		/* OpenSound '/dev/dsp' give us that size */
+    WAVEOPENDESC		waveDesc;
+    WORD			wFlags;
+    WAVEFORMATPCMEX             waveFormat;
+    LPWAVEHDR			lpQueuePtr;
+    DWORD			dwTotalRecorded;
+    DWORD			dwTotalRead;
+
+    /* synchronization stuff */
+    HANDLE			hThread;
+    DWORD			dwThreadID;
+    HANDLE			hStartUpEvent;
+    OSS_MSG_RING		msgRing;
+} WINE_WAVEIN;
+
+extern OSS_DEVICE       OSS_Devices[MAX_WAVEDRV];
+extern WINE_WAVEOUT	WOutDev[MAX_WAVEDRV];
+extern WINE_WAVEIN	WInDev[MAX_WAVEDRV];
+extern unsigned         numOutDev;
+extern unsigned         numInDev;
+
+extern int getEnables(OSS_DEVICE *ossdev);
+extern void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2);
+
+extern DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
+                            int* frag, int strict_format,
+                            int sample_rate, int stereo, int fmt);
+
+extern void OSS_CloseDevice(OSS_DEVICE* ossdev);
+
+extern DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags);
+extern DWORD wodSetVolume(WORD wDevID, DWORD dwParam);
+extern DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags);
+
+#endif /* HAVE_OSS */
Common subdirectories: wine.cvs/dlls/winmm/wineoss/CVS and wine/dlls/winmm/wineoss/CVS
diff -u -N wine.cvs/dlls/winmm/wineoss/dscapture.c wine/dlls/winmm/wineoss/dscapture.c
--- wine.cvs/dlls/winmm/wineoss/dscapture.c	1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/winmm/wineoss/dscapture.c	2004-10-24 11:48:35.000000000 -0400
@@ -0,0 +1,902 @@
+/*
+ * Direct Sound Capture driver
+ *
+ * Copyright 2004 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/winuser16.h"
+#include "mmddk.h"
+#include "mmreg.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "oss.h"
+#include "wine/debug.h"
+
+#include "audio.h"
+#include "dscapture.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
+#ifdef HAVE_OSS
+
+/*======================================================================*
+ *           Low level DSOUND capture definitions                       *
+ *======================================================================*/
+
+typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
+typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
+typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
+typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
+
+struct IDsCaptureDriverPropertySetImpl
+{
+    /* IUnknown fields */
+    IDsDriverPropertySetVtbl           *lpVtbl;
+    DWORD                               ref;
+
+    IDsCaptureDriverBufferImpl*         capture_buffer;
+};
+
+struct IDsCaptureDriverNotifyImpl
+{
+    /* IUnknown fields */
+    IDsDriverNotifyVtbl                *lpVtbl;
+    DWORD                               ref;
+
+    IDsCaptureDriverBufferImpl*         capture_buffer;
+};
+
+struct IDsCaptureDriverImpl
+{
+    /* IUnknown fields */
+    IDsCaptureDriverVtbl               *lpVtbl;
+    DWORD                               ref;
+
+    /* IDsCaptureDriverImpl fields */
+    UINT                                wDevID;
+    IDsCaptureDriverBufferImpl*         capture_buffer;
+};
+
+struct IDsCaptureDriverBufferImpl
+{
+    /* IUnknown fields */
+    IDsCaptureDriverBufferVtbl         *lpVtbl;
+    DWORD                               ref;
+
+    /* IDsCaptureDriverBufferImpl fields */
+    IDsCaptureDriverImpl*               drv;
+    DWORD                               buflen;
+    LPBYTE                              buffer;
+    DWORD                               writeptr;
+    LPBYTE                              mapping;
+    DWORD                               maplen;
+
+    /* IDsDriverNotifyImpl fields */
+    IDsCaptureDriverNotifyImpl*         notify;
+    int                                 notify_index;
+    LPDSBPOSITIONNOTIFY                 notifies;
+    int                                 nrofnotifies;
+
+    /* IDsDriverPropertySetImpl fields */
+    IDsCaptureDriverPropertySetImpl*    property_set;
+
+    BOOL                                is_capturing;
+    BOOL                                is_looping;
+};
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
+    IDsCaptureDriverBufferImpl * dscdb,
+    IDsCaptureDriverPropertySetImpl **pdscdps);
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
+    IDsCaptureDriverBufferImpl * dsdcb,
+    IDsCaptureDriverNotifyImpl **pdscdn);
+
+/*======================================================================*
+ *           Low level DSOUND capture property set implementation       *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
+    PIDSDRIVERPROPERTYSET iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
+        IDsDriverPropertySet_AddRef(iface);
+        *ppobj = (LPVOID)This;
+        return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
+    PIDSDRIVERPROPERTYSET iface)
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
+    PIDSDRIVERPROPERTYSET iface)
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
+        This->capture_buffer->property_set = NULL;
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
+    PIDSDRIVERPROPERTYSET iface,
+    PDSPROPERTY pDsProperty,
+    LPVOID pPropertyParams,
+    ULONG cbPropertyParams,
+    LPVOID pPropertyData,
+    ULONG cbPropertyData,
+    PULONG pcbReturnedData )
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,
+          cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
+    PIDSDRIVERPROPERTYSET iface,
+    PDSPROPERTY pDsProperty,
+    LPVOID pPropertyParams,
+    ULONG cbPropertyParams,
+    LPVOID pPropertyData,
+    ULONG cbPropertyData )
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,
+          cbPropertyParams,pPropertyData,cbPropertyData);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
+    PIDSDRIVERPROPERTYSET iface,
+    REFGUID PropertySetId,
+    ULONG PropertyId,
+    PULONG pSupport )
+{
+    IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+    FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
+          pSupport);
+    return DSERR_UNSUPPORTED;
+}
+
+IDsDriverPropertySetVtbl dscdpsvt =
+{
+    IDsCaptureDriverPropertySetImpl_QueryInterface,
+    IDsCaptureDriverPropertySetImpl_AddRef,
+    IDsCaptureDriverPropertySetImpl_Release,
+    IDsCaptureDriverPropertySetImpl_Get,
+    IDsCaptureDriverPropertySetImpl_Set,
+    IDsCaptureDriverPropertySetImpl_QuerySupport,
+};
+
+/*======================================================================*
+ *                  Low level DSOUND capture notify implementation      *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
+    PIDSDRIVERNOTIFY iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
+        IDsDriverNotify_AddRef(iface);
+        *ppobj = This;
+        return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
+    PIDSDRIVERNOTIFY iface)
+{
+    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
+    PIDSDRIVERNOTIFY iface)
+{
+    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
+        This->capture_buffer->notify = NULL;
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
+    PIDSDRIVERNOTIFY iface,
+    DWORD howmuch,
+    LPCDSBPOSITIONNOTIFY notify)
+{
+    IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+    TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+
+    if (!notify) {
+        WARN("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (TRACE_ON(wave)) {
+        int i;
+        for (i=0;i<howmuch;i++)
+            TRACE("notify at %ld to 0x%08lx\n",
+                notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+    }
+
+    /* Make an internal copy of the caller-supplied array.
+     * Replace the existing copy if one is already present. */
+    if (This->capture_buffer->notifies)
+        This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
+            HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
+            howmuch * sizeof(DSBPOSITIONNOTIFY));
+    else
+        This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
+            HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
+
+    memcpy(This->capture_buffer->notifies, notify,
+           howmuch * sizeof(DSBPOSITIONNOTIFY));
+    This->capture_buffer->nrofnotifies = howmuch;
+
+    return S_OK;
+}
+
+IDsDriverNotifyVtbl dscdnvt =
+{
+    IDsCaptureDriverNotifyImpl_QueryInterface,
+    IDsCaptureDriverNotifyImpl_AddRef,
+    IDsCaptureDriverNotifyImpl_Release,
+    IDsCaptureDriverNotifyImpl_SetNotificationPositions,
+};
+
+/*======================================================================*
+ *                  Low level DSOUND capture implementation             *
+ *======================================================================*/
+
+static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
+{
+    if (!dscdb->mapping) {
+        dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
+                              WInDev[dscdb->drv->wDevID].ossdev->fd, 0);
+        if (dscdb->mapping == (LPBYTE)-1) {
+            TRACE("(%p): Could not map sound device for direct access (%s)\n",
+                  dscdb, strerror(errno));
+            return DSERR_GENERIC;
+        }
+        TRACE("(%p): sound device has been mapped for direct access at %p, size=%ld\n", dscdb, dscdb->mapping, dscdb->maplen);
+    }
+    return DS_OK;
+}
+
+static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
+{
+    if (dscdb->mapping) {
+        if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
+            ERR("(%p): Could not unmap sound device (%s)\n",
+                dscdb, strerror(errno));
+            return DSERR_GENERIC;
+        }
+        dscdb->mapping = NULL;
+        TRACE("(%p): sound device unmapped\n", dscdb);
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
+    PIDSCDRIVERBUFFER iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    *ppobj = 0;
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
+        IDsCaptureDriverBuffer_AddRef(iface);
+        *ppobj = (LPVOID)This;
+        return DS_OK;
+    }
+
+    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
+        if (!This->notify)
+            IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
+        if (This->notify) {
+            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
+            *ppobj = (LPVOID)This->notify;
+            return DS_OK;
+        }
+        return E_FAIL;
+    }
+
+    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
+        if (!This->property_set)
+            IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
+        if (This->property_set) {
+            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
+            *ppobj = (LPVOID)This->property_set;
+            return DS_OK;
+        }
+        return E_FAIL;
+    }
+
+    FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
+    return DSERR_UNSUPPORTED;
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        DSCDB_UnmapBuffer(This);
+        if (This->notifies != NULL)
+            HeapFree(GetProcessHeap(), 0, This->notifies);
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
+    PIDSCDRIVERBUFFER iface,
+    LPVOID* ppvAudio1,
+    LPDWORD pdwLen1,
+    LPVOID* ppvAudio2,
+    LPDWORD pdwLen2,
+    DWORD dwWritePosition,
+    DWORD dwWriteLen,
+    DWORD dwFlags)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    FIXME("(%p,%p,%p,%p,%p,%ld,%ld,0x%08lx): stub!\n",This,ppvAudio1,pdwLen1,
+          ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
+    PIDSCDRIVERBUFFER iface,
+    LPVOID pvAudio1,
+    DWORD dwLen1,
+    LPVOID pvAudio2,
+    DWORD dwLen2)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    FIXME("(%p,%p,%ld,%p,%ld): stub!\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
+    PIDSCDRIVERBUFFER iface,
+    LPDWORD lpdwCapture,
+    LPDWORD lpdwRead)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    count_info info;
+    DWORD ptr;
+    TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
+
+    if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
+        ERR("device not open, but accessing?\n");
+        return DSERR_UNINITIALIZED;
+    }
+
+    if (!This->is_capturing) {
+        if (lpdwCapture)
+            *lpdwCapture = 0;
+        if (lpdwRead)
+            *lpdwRead = 0;
+    }
+
+    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
+            WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+        return DSERR_GENERIC;
+    }
+    ptr = info.ptr & ~3; /* align the pointer, just in case */
+    if (lpdwCapture) *lpdwCapture = ptr;
+    if (lpdwRead) {
+        /* add some safety margin (not strictly necessary, but...) */
+        if (WInDev[This->drv->wDevID].ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
+            *lpdwRead = ptr + 32;
+        else
+            *lpdwRead = ptr + WInDev[This->drv->wDevID].dwFragmentSize;
+        while (*lpdwRead > This->buflen)
+            *lpdwRead -= This->buflen;
+    }
+    TRACE("capturepos=%ld, readpos=%ld\n", lpdwCapture?*lpdwCapture:0, lpdwRead?*lpdwRead:0);
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
+    PIDSCDRIVERBUFFER iface,
+    LPDWORD lpdwStatus)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    TRACE("(%p,%p)\n",This,lpdwStatus);
+
+    if (This->is_capturing) {
+        if (This->is_looping)
+            *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
+        else
+            *lpdwStatus = DSCBSTATUS_CAPTURING;
+    } else
+        *lpdwStatus = 0;
+
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
+    PIDSCDRIVERBUFFER iface,
+    DWORD dwFlags)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    int enable;
+    TRACE("(%p,%lx)\n",This,dwFlags);
+
+    if (This->is_capturing)
+        return DS_OK;
+
+    if (dwFlags & DSCBSTART_LOOPING)
+        This->is_looping = TRUE;
+
+    WInDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
+    enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+        if (errno == EINVAL) {
+            /* Don't give up yet. OSS trigger support is inconsistent. */
+            if (WInDev[This->drv->wDevID].ossdev->open_count == 1) {
+                /* try the opposite output enable */
+                if (WInDev[This->drv->wDevID].ossdev->bOutputEnabled == FALSE)
+                    WInDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
+                else
+                    WInDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+                /* try it again */
+                enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+                if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
+                    This->is_capturing = TRUE;
+                    return DS_OK;
+                }
+            }
+        }
+        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+            WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+        WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+        return DSERR_GENERIC;
+    }
+
+    This->is_capturing = TRUE;
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    int enable;
+    TRACE("(%p)\n",This);
+
+    if (!This->is_capturing)
+        return DS_OK;
+
+    /* no more captureing */
+    WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+    enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+    if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+            WInDev[This->drv->wDevID].ossdev->dev_name,  strerror(errno));
+        return DSERR_GENERIC;
+    }
+
+    /* send a final event if necessary */
+    if (This->nrofnotifies > 0) {
+        if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
+            SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
+    }
+
+    This->is_capturing = FALSE;
+    This->is_looping = FALSE;
+
+    /* Most OSS drivers just can't stop capturing without closing the device...
+     * so we need to somehow signal to our DirectSound implementation
+     * that it should completely recreate this HW buffer...
+     * this unexpected error code should do the trick... */
+    return DSERR_BUFFERLOST;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
+    PIDSCDRIVERBUFFER iface,
+    LPWAVEFORMATEX pwfx)
+{
+    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+    FIXME("(%p): stub!\n",This);
+    return DSERR_UNSUPPORTED;
+}
+
+static IDsCaptureDriverBufferVtbl dscdbvt =
+{
+    IDsCaptureDriverBufferImpl_QueryInterface,
+    IDsCaptureDriverBufferImpl_AddRef,
+    IDsCaptureDriverBufferImpl_Release,
+    IDsCaptureDriverBufferImpl_Lock,
+    IDsCaptureDriverBufferImpl_Unlock,
+    IDsCaptureDriverBufferImpl_SetFormat,
+    IDsCaptureDriverBufferImpl_GetPosition,
+    IDsCaptureDriverBufferImpl_GetStatus,
+    IDsCaptureDriverBufferImpl_Start,
+    IDsCaptureDriverBufferImpl_Stop
+};
+
+static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
+    PIDSCDRIVER iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
+        IDsCaptureDriver_AddRef(iface);
+        *ppobj = (LPVOID)This;
+        return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
+    PIDSCDRIVER iface,
+    PDSDRIVERDESC pDesc)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p,%p)\n",This,pDesc);
+
+    if (!pDesc) {
+        TRACE("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    /* copy version from driver */
+    memcpy(pDesc, &(WInDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+
+    pDesc->dwFlags |= DSDDESC_USESYSTEMMEMORY;
+    pDesc->dnDevNode            = WInDev[This->wDevID].waveDesc.dnDevNode;
+    pDesc->wVxdId               = 0;
+    pDesc->wReserved            = 0;
+    pDesc->ulDeviceNum          = This->wDevID;
+    pDesc->dwHeapType           = DSDHEAP_NOHEAP;
+    pDesc->pvDirectDrawHeap     = NULL;
+    pDesc->dwMemStartAddress    = 0;
+    pDesc->dwMemEndAddress      = 0;
+    pDesc->dwMemAllocExtra      = 0;
+    pDesc->pvReserved1          = NULL;
+    pDesc->pvReserved2          = NULL;
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p)\n",This);
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p)\n",This);
+    if (This->capture_buffer) {
+        ERR("problem with DirectSound: capture buffer not released\n");
+        return DSERR_GENERIC;
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
+    PIDSCDRIVER iface,
+    PDSCDRIVERCAPS pCaps)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    TRACE("(%p,%p)\n",This,pCaps);
+    memcpy(pCaps, &(WInDev[This->wDevID].ossdev->dsc_caps), sizeof(DSCDRIVERCAPS));
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
+    PIDSCDRIVER iface,
+    LPWAVEFORMATEX pwfx,
+    DWORD dwFlags,
+    DWORD dwCardAddress,
+    LPDWORD pdwcbBufferSize,
+    LPBYTE *ppbBuffer,
+    LPVOID *ppvObj)
+{
+    IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+    IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
+    HRESULT err;
+    audio_buf_info info;
+    int enable;
+    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
+          pdwcbBufferSize,ppbBuffer,ppvObj);
+
+    if (This->capture_buffer) {
+        TRACE("already allocated\n");
+        return DSERR_ALLOCATED;
+    }
+
+    *ippdscdb = (IDsCaptureDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
+    if (*ippdscdb == NULL) {
+        TRACE("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    (*ippdscdb)->lpVtbl = &dscdbvt;
+    (*ippdscdb)->ref          = 1;
+    (*ippdscdb)->drv          = This;
+    (*ippdscdb)->notify       = NULL;
+    (*ippdscdb)->notify_index = 0;
+    (*ippdscdb)->notifies     = NULL;
+    (*ippdscdb)->nrofnotifies = 0;
+    (*ippdscdb)->property_set = NULL;
+    (*ippdscdb)->is_capturing = FALSE;
+    (*ippdscdb)->is_looping   = FALSE;
+
+    if (WInDev[This->wDevID].state == WINE_WS_CLOSED) {
+        WAVEOPENDESC desc;
+        desc.hWave = 0;
+        desc.lpFormat = pwfx;
+        desc.dwCallback = 0;
+        desc.dwInstance = 0;
+        desc.uMappedDeviceID = 0;
+        desc.dnDevNode = 0;
+        err = widOpen(This->wDevID, &desc, dwFlags | WAVE_DIRECTSOUND);
+        if (err != MMSYSERR_NOERROR) {
+            TRACE("widOpen failed\n");
+            return err;
+        }
+    }
+
+    /* check how big the DMA buffer is now */
+    if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
+            WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
+        HeapFree(GetProcessHeap(),0,*ippdscdb);
+        *ippdscdb = NULL;
+        return DSERR_GENERIC;
+    }
+    (*ippdscdb)->maplen = (*ippdscdb)->buflen = info.fragstotal * info.fragsize;
+
+    /* map the DMA buffer */
+    err = DSCDB_MapBuffer(*ippdscdb);
+    if (err != DS_OK) {
+        HeapFree(GetProcessHeap(),0,*ippdscdb);
+        *ippdscdb = NULL;
+        return err;
+    }
+
+    /* capture buffer is ready to go */
+    *pdwcbBufferSize    = (*ippdscdb)->maplen;
+    *ppbBuffer          = (*ippdscdb)->mapping;
+
+    /* some drivers need some extra nudging after mapping */
+    WInDev[This->wDevID].ossdev->bInputEnabled = FALSE;
+    enable = getEnables(WInDev[This->wDevID].ossdev);
+    if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+            WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
+        return DSERR_GENERIC;
+    }
+
+    This->capture_buffer = *ippdscdb;
+
+    return DS_OK;
+}
+
+static IDsCaptureDriverVtbl dscdvt =
+{
+    IDsCaptureDriverImpl_QueryInterface,
+    IDsCaptureDriverImpl_AddRef,
+    IDsCaptureDriverImpl_Release,
+    IDsCaptureDriverImpl_GetDriverDesc,
+    IDsCaptureDriverImpl_Open,
+    IDsCaptureDriverImpl_Close,
+    IDsCaptureDriverImpl_GetCaps,
+    IDsCaptureDriverImpl_CreateCaptureBuffer
+};
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
+    IDsCaptureDriverBufferImpl * dscdb,
+    IDsCaptureDriverPropertySetImpl **pdscdps)
+{
+    IDsCaptureDriverPropertySetImpl * dscdps;
+    TRACE("(%p,%p)\n",dscdb,pdscdps);
+
+    dscdps = (IDsCaptureDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdps));
+    if (dscdps == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    dscdps->ref = 0;
+    dscdps->lpVtbl = &dscdpsvt;
+    dscdps->capture_buffer = dscdb;
+    dscdb->property_set = dscdps;
+    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
+
+    *pdscdps = dscdps;
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
+    IDsCaptureDriverBufferImpl * dscdb,
+    IDsCaptureDriverNotifyImpl **pdscdn)
+{
+    IDsCaptureDriverNotifyImpl * dscdn;
+    TRACE("(%p,%p)\n",dscdb,pdscdn);
+
+    dscdn = (IDsCaptureDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdn));
+    if (dscdn == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    dscdn->ref = 0;
+    dscdn->lpVtbl = &dscdnvt;
+    dscdn->capture_buffer = dscdb;
+    dscdb->notify = dscdn;
+    IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
+
+    *pdscdn = dscdn;
+    return DS_OK;
+}
+
+DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
+{
+    IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
+    TRACE("(%d,%p)\n",wDevID,drv);
+
+    /* the HAL isn't much better than the HEL if we can't do mmap() */
+    if (!(WInDev[wDevID].ossdev->in_caps_support & WAVECAPS_DIRECTSOUND)) {
+        ERR("DirectSoundCapture flag not set\n");
+        MESSAGE("This sound card's driver does not support direct access\n");
+        MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
+        return MMSYSERR_NOTSUPPORTED;
+    }
+
+    *idrv = (IDsCaptureDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
+    if (!*idrv)
+        return MMSYSERR_NOMEM;
+    (*idrv)->lpVtbl	= &dscdvt;
+    (*idrv)->ref	= 1;
+
+    (*idrv)->wDevID	= wDevID;
+    (*idrv)->capture_buffer = NULL;
+    return MMSYSERR_NOERROR;
+}
+
+DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
+{
+    memcpy(desc, &(WInDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+    return MMSYSERR_NOERROR;
+}
+
+#endif /* HAVE_OSS */
diff -u -N wine.cvs/dlls/winmm/wineoss/dscapture.h wine/dlls/winmm/wineoss/dscapture.h
--- wine.cvs/dlls/winmm/wineoss/dscapture.h	1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/winmm/wineoss/dscapture.h	2004-10-17 17:22:40.000000000 -0400
@@ -0,0 +1,26 @@
+/*
+ * Direct Sound Capture driver
+ *
+ * Copyright 2004 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_OSS
+
+extern DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);
+extern DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc);
+
+#endif /* HAVE_OSS */
diff -u -N wine.cvs/dlls/winmm/wineoss/dsrender.c wine/dlls/winmm/wineoss/dsrender.c
--- wine.cvs/dlls/winmm/wineoss/dsrender.c	1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/winmm/wineoss/dsrender.c	2004-10-24 11:32:24.000000000 -0400
@@ -0,0 +1,960 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/*
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
+ *
+ * Copyright 1994 Martin Ayotte
+ *           1999 Eric Pouech (async playing in waveOut/waveIn)
+ *	     2000 Eric Pouech (loops in waveOut)
+ *           2002 Eric Pouech (full duplex)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/winuser16.h"
+#include "mmddk.h"
+#include "mmreg.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "oss.h"
+#include "wine/debug.h"
+
+#include "audio.h"
+#include "dsrender.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
+#ifdef HAVE_OSS
+
+/*======================================================================*
+ *                  Low level DSOUND definitions                        *
+ *======================================================================*/
+
+typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl;
+typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl;
+typedef struct IDsDriverImpl IDsDriverImpl;
+typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
+
+struct IDsDriverPropertySetImpl
+{
+    /* IUnknown fields */
+    IDsDriverPropertySetVtbl   *lpVtbl;
+    DWORD                       ref;
+
+    IDsDriverBufferImpl*        buffer;
+};
+
+struct IDsDriverNotifyImpl
+{
+    /* IUnknown fields */
+    IDsDriverNotifyVtbl        *lpVtbl;
+    DWORD                       ref;
+
+    /* IDsDriverNotifyImpl fields */
+    LPDSBPOSITIONNOTIFY         notifies;
+    int                         nrofnotifies;
+
+    IDsDriverBufferImpl*        buffer;
+};
+
+struct IDsDriverImpl
+{
+    /* IUnknown fields */
+    IDsDriverVtbl              *lpVtbl;
+    DWORD                       ref;
+
+    /* IDsDriverImpl fields */
+    UINT                        wDevID;
+    IDsDriverBufferImpl*        primary;
+
+    int                         nrofsecondaries;
+    IDsDriverBufferImpl**       secondaries;
+};
+
+struct IDsDriverBufferImpl
+{
+    /* IUnknown fields */
+    IDsDriverBufferVtbl        *lpVtbl;
+    DWORD                       ref;
+
+    /* IDsDriverBufferImpl fields */
+    IDsDriverImpl*              drv;
+    DWORD                       buflen;
+    WAVEFORMATPCMEX             wfex;
+    LPBYTE                      mapping;
+    DWORD                       maplen;
+    int                         fd;
+    DWORD                       dwFlags;
+
+    /* IDsDriverNotifyImpl fields */
+    IDsDriverNotifyImpl*        notify;
+    int                         notify_index;
+
+    /* IDsDriverPropertySetImpl fields */
+    IDsDriverPropertySetImpl*   property_set;
+};
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
+    IDsDriverBufferImpl * dsdb,
+    IDsDriverPropertySetImpl **pdsdps);
+
+static HRESULT WINAPI IDsDriverNotifyImpl_Create(
+    IDsDriverBufferImpl * dsdb,
+    IDsDriverNotifyImpl **pdsdn);
+
+/*======================================================================*
+ *                  Low level DSOUND property set implementation        *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_QueryInterface(
+    PIDSDRIVERPROPERTYSET iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
+        IDsDriverPropertySet_AddRef(iface);
+        *ppobj = (LPVOID)This;
+        return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface)
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface)
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Get(
+    PIDSDRIVERPROPERTYSET iface,
+    PDSPROPERTY pDsProperty,
+    LPVOID pPropertyParams,
+    ULONG cbPropertyParams,
+    LPVOID pPropertyData,
+    ULONG cbPropertyData,
+    PULONG pcbReturnedData )
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Set(
+    PIDSDRIVERPROPERTYSET iface,
+    PDSPROPERTY pDsProperty,
+    LPVOID pPropertyParams,
+    ULONG cbPropertyParams,
+    LPVOID pPropertyData,
+    ULONG cbPropertyData )
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_QuerySupport(
+    PIDSDRIVERPROPERTYSET iface,
+    REFGUID PropertySetId,
+    ULONG PropertyId,
+    PULONG pSupport )
+{
+    IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+    FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,pSupport);
+    return DSERR_UNSUPPORTED;
+}
+
+IDsDriverPropertySetVtbl dsdpsvt =
+{
+    IDsDriverPropertySetImpl_QueryInterface,
+    IDsDriverPropertySetImpl_AddRef,
+    IDsDriverPropertySetImpl_Release,
+    IDsDriverPropertySetImpl_Get,
+    IDsDriverPropertySetImpl_Set,
+    IDsDriverPropertySetImpl_QuerySupport,
+};
+
+/*======================================================================*
+ *                  Low level DSOUND notify implementation              *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsDriverNotifyImpl_QueryInterface(
+    PIDSDRIVERNOTIFY iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
+        IDsDriverNotify_AddRef(iface);
+        *ppobj = This;
+        return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
+{
+    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
+{
+    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
+        if (This->notifies != NULL)
+            HeapFree(GetProcessHeap(), 0, This->notifies);
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsDriverNotifyImpl_SetNotificationPositions(
+    PIDSDRIVERNOTIFY iface,
+    DWORD howmuch,
+    LPCDSBPOSITIONNOTIFY notify)
+{
+    IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+    TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+
+    if (!notify) {
+        WARN("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (TRACE_ON(wave)) {
+        int i;
+        for (i=0;i<howmuch;i++)
+            TRACE("notify at %ld to 0x%08lx\n",
+                notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+    }
+
+    /* Make an internal copy of the caller-supplied array.
+     * Replace the existing copy if one is already present. */
+    if (This->notifies)
+        This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+        This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
+    else
+        This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+        howmuch * sizeof(DSBPOSITIONNOTIFY));
+
+    memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
+    This->nrofnotifies = howmuch;
+
+    return S_OK;
+}
+
+IDsDriverNotifyVtbl dsdnvt =
+{
+    IDsDriverNotifyImpl_QueryInterface,
+    IDsDriverNotifyImpl_AddRef,
+    IDsDriverNotifyImpl_Release,
+    IDsDriverNotifyImpl_SetNotificationPositions,
+};
+
+/*======================================================================*
+ *                  Low level DSOUND implementation                     *
+ *======================================================================*/
+
+static HRESULT DSDB_MapBuffer(IDsDriverBufferImpl *dsdb)
+{
+    TRACE("(%p), format=%ldx%dx%d\n", dsdb, dsdb->wfex.Format.nSamplesPerSec,
+          dsdb->wfex.Format.wBitsPerSample, dsdb->wfex.Format.nChannels);
+    if (!dsdb->mapping) {
+        dsdb->mapping = mmap(NULL, dsdb->maplen, PROT_WRITE, MAP_SHARED,
+                             dsdb->fd, 0);
+        if (dsdb->mapping == (LPBYTE)-1) {
+            ERR("Could not map sound device for direct access (%s)\n", strerror(errno));
+            ERR("Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n");
+            return DSERR_GENERIC;
+        }
+        TRACE("The sound device has been mapped for direct access at %p, size=%ld\n", dsdb->mapping, dsdb->maplen);
+
+	/* for some reason, es1371 and sblive! sometimes have junk in here.
+	 * clear it, or we get junk noise */
+	/* some libc implementations are buggy: their memset reads from the buffer...
+	 * to work around it, we have to zero the block by hand. We don't do the expected:
+	 * memset(dsdb->mapping,0, dsdb->maplen);
+	 */
+	{
+            unsigned char*      p1 = dsdb->mapping;
+            unsigned            len = dsdb->maplen;
+	    unsigned char	silence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 128 : 0;
+	    unsigned long	ulsilence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 0x80808080 : 0;
+
+	    if (len >= 16) /* so we can have at least a 4 long area to store... */
+	    {
+		/* the mmap:ed value is (at least) dword aligned
+		 * so, start filling the complete unsigned long:s
+		 */
+		int		b = len >> 2;
+		unsigned long*	p4 = (unsigned long*)p1;
+
+		while (b--) *p4++ = ulsilence;
+		/* prepare for filling the rest */
+		len &= 3;
+		p1 = (unsigned char*)p4;
+	    }
+	    /* in all cases, fill the remaining bytes */
+	    while (len-- != 0) *p1++ = silence;
+	}
+    }
+    return DS_OK;
+}
+
+static HRESULT DSDB_UnmapBuffer(IDsDriverBufferImpl *dsdb)
+{
+    TRACE("(%p)\n",dsdb);
+    if (dsdb->mapping) {
+        if (munmap(dsdb->mapping, dsdb->maplen) < 0) {
+            ERR("(%p): Could not unmap sound device (%s)\n", dsdb, strerror(errno));
+            return DSERR_GENERIC;
+        }
+        dsdb->mapping = NULL;
+        TRACE("(%p): sound device unmapped\n", dsdb);
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),*ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriverBuffer) ) {
+	IDsDriverBuffer_AddRef(iface);
+	*ppobj = (LPVOID)This;
+	return DS_OK;
+    }
+
+    if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
+        if (!This->notify)
+            IDsDriverNotifyImpl_Create(This, &(This->notify));
+        if (This->notify) {
+            IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
+            *ppobj = (LPVOID)This->notify;
+            return DS_OK;
+        }
+        *ppobj = 0;
+        return E_FAIL;
+    }
+
+    if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
+        if (!This->property_set)
+            IDsDriverPropertySetImpl_Create(This, &(This->property_set));
+        if (This->property_set) {
+            IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
+            *ppobj = (LPVOID)This->property_set;
+            return DS_OK;
+        }
+	*ppobj = 0;
+	return E_FAIL;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref)
+        return ref;
+
+    if (This == This->drv->primary)
+	This->drv->primary = NULL;
+    else {
+        int i;
+        for (i = 0; i < This->drv->nrofsecondaries; i++)
+            if (This->drv->secondaries[i] == This)
+                break;
+        if (i < This->drv->nrofsecondaries) {
+            /* Put the last buffer of the list in the (now empty) position */
+            This->drv->secondaries[i] = This->drv->secondaries[This->drv->nrofsecondaries - 1];
+            This->drv->nrofsecondaries--;
+            This->drv->secondaries = HeapReAlloc(GetProcessHeap(),0,
+                This->drv->secondaries,
+                sizeof(PIDSDRIVERBUFFER)*This->drv->nrofsecondaries);
+            TRACE("(%p) buffer count is now %d\n", This, This->drv->nrofsecondaries);
+        }
+
+        WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingAllBuffers++;
+        WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingStreamingBuffers++;
+    }
+
+    DSDB_UnmapBuffer(This);
+    HeapFree(GetProcessHeap(),0,This);
+    TRACE("(%p) released\n",This);
+    return 0;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
+					       LPVOID*ppvAudio1,LPDWORD pdwLen1,
+					       LPVOID*ppvAudio2,LPDWORD pdwLen2,
+					       DWORD dwWritePosition,DWORD dwWriteLen,
+					       DWORD dwFlags)
+{
+    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+    /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
+     * and that we don't support secondary buffers, this method will never be called */
+    TRACE("(%p): stub\n",iface);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
+						 LPVOID pvAudio1,DWORD dwLen1,
+						 LPVOID pvAudio2,DWORD dwLen2)
+{
+    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+    TRACE("(%p): stub\n",iface);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
+						    LPWAVEFORMATEX pwfx)
+{
+    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+
+    TRACE("(%p,%p)\n",iface,pwfx);
+    /* On our request (GetDriverDesc flags), DirectSound has by now used
+     * waveOutClose/waveOutOpen to set the format...
+     * unfortunately, this means our mmap() is now gone...
+     * so we need to somehow signal to our DirectSound implementation
+     * that it should completely recreate this HW buffer...
+     * this unexpected error code should do the trick... */
+    return DSERR_BUFFERLOST;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
+{
+    /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+    TRACE("(%p,%ld): stub\n",iface,dwFreq);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
+{
+    DWORD vol;
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    TRACE("(%p,%p)\n",This,pVolPan);
+
+    vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
+
+    if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
+	WARN("wodSetVolume failed\n");
+	return DSERR_INVALIDPARAM;
+    }
+
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
+{
+    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
+    TRACE("(%p,%ld): stub\n",iface,dwNewPos);
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
+						      LPDWORD lpdwPlay, LPDWORD lpdwWrite)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    count_info info;
+    DWORD ptr;
+
+    TRACE("(%p)\n",iface);
+    if (WOutDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
+	ERR("device not open, but accessing?\n");
+	return DSERR_UNINITIALIZED;
+    }
+    if (ioctl(This->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
+            WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+	return DSERR_GENERIC;
+    }
+    ptr = info.ptr & ~3; /* align the pointer, just in case */
+    if (lpdwPlay) *lpdwPlay = ptr;
+    if (lpdwWrite) {
+	/* add some safety margin (not strictly necessary, but...) */
+	if (WOutDev[This->drv->wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
+	    *lpdwWrite = ptr + 32;
+	else
+	    *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
+	while (*lpdwWrite > This->buflen)
+	    *lpdwWrite -= This->buflen;
+    }
+    TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0);
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    int enable;
+    TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags);
+    WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
+    enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+	if (errno == EINVAL) {
+	    /* Don't give up yet. OSS trigger support is inconsistent. */
+	    if (WOutDev[This->drv->wDevID].ossdev->open_count == 1) {
+		/* try the opposite input enable */
+		if (WOutDev[This->drv->wDevID].ossdev->bInputEnabled == FALSE)
+		    WOutDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
+		else
+		    WOutDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+		/* try it again */
+    		enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+                if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0)
+		    return DS_OK;
+	    }
+	}
+        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+            WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+	WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+	return DSERR_GENERIC;
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
+{
+    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+    int enable;
+    TRACE("(%p)\n",iface);
+    /* no more playing */
+    WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+    enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+    if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+	return DSERR_GENERIC;
+    }
+#if 0
+    /* the play position must be reset to the beginning of the buffer */
+    if (ioctl(This->fd, SNDCTL_DSP_RESET, 0) < 0) {
+	ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+	return DSERR_GENERIC;
+    }
+#endif
+    /* Most OSS drivers just can't stop the playback without closing the device...
+     * so we need to somehow signal to our DirectSound implementation
+     * that it should completely recreate this HW buffer...
+     * this unexpected error code should do the trick... */
+    /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
+    if (WOutDev[This->drv->wDevID].ossdev->open_count == 1)
+	return DSERR_BUFFERLOST;
+
+    return DS_OK;
+}
+
+static IDsDriverBufferVtbl dsdbvt =
+{
+    IDsDriverBufferImpl_QueryInterface,
+    IDsDriverBufferImpl_AddRef,
+    IDsDriverBufferImpl_Release,
+    IDsDriverBufferImpl_Lock,
+    IDsDriverBufferImpl_Unlock,
+    IDsDriverBufferImpl_SetFormat,
+    IDsDriverBufferImpl_SetFrequency,
+    IDsDriverBufferImpl_SetVolumePan,
+    IDsDriverBufferImpl_SetPosition,
+    IDsDriverBufferImpl_GetPosition,
+    IDsDriverBufferImpl_Play,
+    IDsDriverBufferImpl_Stop
+};
+
+static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if ( IsEqualGUID(riid, &IID_IUnknown) ||
+         IsEqualGUID(riid, &IID_IDsDriver) ) {
+	IDsDriver_AddRef(iface);
+	*ppobj = (LPVOID)This;
+	return DS_OK;
+    }
+
+    FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+    *ppobj = 0;
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    DWORD ref;
+    TRACE("(%p) ref was %ld\n", This, This->ref);
+
+    ref = InterlockedDecrement(&(This->ref));
+    if (ref == 0) {
+        HeapFree(GetProcessHeap(),0,This);
+        TRACE("(%p) released\n",This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface,
+                                                  PDSDRIVERDESC pDesc)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    TRACE("(%p,%p)\n",iface,pDesc);
+
+    /* copy version from driver */
+    memcpy(pDesc, &(WOutDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+
+    pDesc->dwFlags |= DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
+        DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK |
+        DSDDESC_DONTNEEDSECONDARYLOCK;
+    pDesc->dnDevNode		= WOutDev[This->wDevID].waveDesc.dnDevNode;
+    pDesc->wVxdId		= 0;
+    pDesc->wReserved		= 0;
+    pDesc->ulDeviceNum		= This->wDevID;
+    pDesc->dwHeapType		= DSDHEAP_NOHEAP;
+    pDesc->pvDirectDrawHeap	= NULL;
+    pDesc->dwMemStartAddress	= 0;
+    pDesc->dwMemEndAddress	= 0;
+    pDesc->dwMemAllocExtra	= 0;
+    pDesc->pvReserved1		= NULL;
+    pDesc->pvReserved2		= NULL;
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    int enable;
+    TRACE("(%p)\n",iface);
+
+    /* make sure the card doesn't start playing before we want it to */
+    WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
+    enable = getEnables(WOutDev[This->wDevID].ossdev);
+    if (ioctl(WOutDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+	ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+	return DSERR_GENERIC;
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    TRACE("(%p)\n",iface);
+    if (This->primary) {
+	ERR("problem with DirectSound: primary not released\n");
+	return DSERR_GENERIC;
+    }
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    TRACE("(%p,%p)\n",iface,pCaps);
+    memcpy(pCaps, &(WOutDev[This->wDevID].ossdev->ds_caps), sizeof(DSDRIVERCAPS));
+    return DS_OK;
+}
+
+static HRESULT WINAPI DSD_CreatePrimaryBuffer(PIDSDRIVER iface,
+                                              LPWAVEFORMATEX pwfx,
+                                              DWORD dwFlags,
+                                              DWORD dwCardAddress,
+                                              LPDWORD pdwcbBufferSize,
+                                              LPBYTE *ppbBuffer,
+                                              LPVOID *ppvObj)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
+    HRESULT err;
+    audio_buf_info info;
+    int enable = 0;
+    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+    if (This->primary)
+	return DSERR_ALLOCATED;
+    if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
+	return DSERR_CONTROLUNAVAIL;
+
+    *ippdsdb = (IDsDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverBufferImpl));
+    if (*ippdsdb == NULL)
+	return DSERR_OUTOFMEMORY;
+    (*ippdsdb)->lpVtbl  = &dsdbvt;
+    (*ippdsdb)->ref	= 1;
+    (*ippdsdb)->drv	= This;
+    copy_format(pwfx, &(*ippdsdb)->wfex);
+    (*ippdsdb)->fd      = WOutDev[This->wDevID].ossdev->fd;
+    (*ippdsdb)->dwFlags = dwFlags;
+
+    /* check how big the DMA buffer is now */
+    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
+            WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+	HeapFree(GetProcessHeap(),0,*ippdsdb);
+	*ippdsdb = NULL;
+	return DSERR_GENERIC;
+    }
+    (*ippdsdb)->maplen = (*ippdsdb)->buflen = info.fragstotal * info.fragsize;
+
+    /* map the DMA buffer */
+    err = DSDB_MapBuffer(*ippdsdb);
+    if (err != DS_OK) {
+	HeapFree(GetProcessHeap(),0,*ippdsdb);
+	*ippdsdb = NULL;
+	return err;
+    }
+
+    /* primary buffer is ready to go */
+    *pdwcbBufferSize    = (*ippdsdb)->maplen;
+    *ppbBuffer          = (*ippdsdb)->mapping;
+
+    /* some drivers need some extra nudging after mapping */
+    WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
+    enable = getEnables(WOutDev[This->wDevID].ossdev);
+    if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+        ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+            WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+	return DSERR_GENERIC;
+    }
+
+    This->primary = *ippdsdb;
+
+    return DS_OK;
+}
+
+static HRESULT WINAPI DSD_CreateSecondaryBuffer(PIDSDRIVER iface,
+                                                LPWAVEFORMATEX pwfx,
+                                                DWORD dwFlags,
+                                                DWORD dwCardAddress,
+                                                LPDWORD pdwcbBufferSize,
+                                                LPBYTE *ppbBuffer,
+                                                LPVOID *ppvObj)
+{
+    IDsDriverImpl *This = (IDsDriverImpl *)iface;
+    IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
+    FIXME("(%p,%p,%lx,%lx,%p,%p,%p): stub\n",This,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+    *ippdsdb = 0;
+    return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
+                                                      LPWAVEFORMATEX pwfx,
+                                                      DWORD dwFlags,
+                                                      DWORD dwCardAddress,
+                                                      LPDWORD pdwcbBufferSize,
+                                                      LPBYTE *ppbBuffer,
+                                                      LPVOID *ppvObj)
+{
+    TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+    if (dwFlags & DSBCAPS_PRIMARYBUFFER)
+        return DSD_CreatePrimaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+    return DSD_CreateSecondaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+}
+
+static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
+							 PIDSDRIVERBUFFER pBuffer,
+							 LPVOID *ppvObj)
+{
+    /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
+    TRACE("(%p,%p): stub\n",iface,pBuffer);
+    return DSERR_INVALIDCALL;
+}
+
+static IDsDriverVtbl dsdvt =
+{
+    IDsDriverImpl_QueryInterface,
+    IDsDriverImpl_AddRef,
+    IDsDriverImpl_Release,
+    IDsDriverImpl_GetDriverDesc,
+    IDsDriverImpl_Open,
+    IDsDriverImpl_Close,
+    IDsDriverImpl_GetCaps,
+    IDsDriverImpl_CreateSoundBuffer,
+    IDsDriverImpl_DuplicateSoundBuffer
+};
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
+    IDsDriverBufferImpl * dsdb,
+    IDsDriverPropertySetImpl **pdsdps)
+{
+    IDsDriverPropertySetImpl * dsdps;
+    TRACE("(%p,%p)\n",dsdb,pdsdps);
+
+    dsdps = (IDsDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdps));
+    if (dsdps == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    dsdps->ref = 0;
+    dsdps->lpVtbl = &dsdpsvt;
+    dsdps->buffer = dsdb;
+    dsdb->property_set = dsdps;
+    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
+
+    *pdsdps = dsdps;
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverNotifyImpl_Create(
+    IDsDriverBufferImpl * dsdb,
+    IDsDriverNotifyImpl **pdsdn)
+{
+    IDsDriverNotifyImpl * dsdn;
+    TRACE("(%p,%p)\n",dsdb,pdsdn);
+
+    dsdn = (IDsDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdn));
+
+    if (dsdn == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    dsdn->ref = 0;
+    dsdn->lpVtbl = &dsdnvt;
+    dsdn->buffer = dsdb;
+    dsdb->notify = dsdn;
+    IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
+
+    *pdsdn = dsdn;
+    return DS_OK;
+};
+
+DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
+{
+    IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
+    TRACE("(%d,%p)\n",wDevID,drv);
+
+    /* the HAL isn't much better than the HEL if we can't do mmap() */
+    if (!(WOutDev[wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
+	ERR("DirectSound flag not set\n");
+	MESSAGE("This sound card's driver does not support direct access\n");
+	MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
+	return MMSYSERR_NOTSUPPORTED;
+    }
+
+    *idrv = (IDsDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverImpl));
+    if (!*idrv)
+	return MMSYSERR_NOMEM;
+    (*idrv)->lpVtbl          = &dsdvt;
+    (*idrv)->ref             = 1;
+    (*idrv)->wDevID          = wDevID;
+    (*idrv)->primary         = NULL;
+    (*idrv)->nrofsecondaries = 0;
+    (*idrv)->secondaries     = NULL;
+
+    return MMSYSERR_NOERROR;
+}
+
+DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
+{
+    TRACE("(%d,%p)\n",wDevID,desc);
+    memcpy(desc, &(WOutDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+    return MMSYSERR_NOERROR;
+}
+
+#endif /* HAVE_OSS */
diff -u -N wine.cvs/dlls/winmm/wineoss/dsrender.h wine/dlls/winmm/wineoss/dsrender.h
--- wine.cvs/dlls/winmm/wineoss/dsrender.h	1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/winmm/wineoss/dsrender.h	2004-10-17 17:48:46.000000000 -0400
@@ -0,0 +1,30 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/*
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
+ *
+ * Copyright 1994 Martin Ayotte
+ *           1999 Eric Pouech (async playing in waveOut/waveIn)
+ *	     2000 Eric Pouech (loops in waveOut)
+ *           2002 Eric Pouech (full duplex)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_OSS
+
+extern DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
+extern DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
+
+#endif /* HAVE_OSS */
diff -u -N wine.cvs/dlls/winmm/wineoss/Makefile.in wine/dlls/winmm/wineoss/Makefile.in
--- wine.cvs/dlls/winmm/wineoss/Makefile.in	2004-07-28 07:28:07.000000000 -0400
+++ wine/dlls/winmm/wineoss/Makefile.in	2004-10-17 18:04:15.000000000 -0400
@@ -8,6 +8,8 @@
 
 C_SRCS = \
 	audio.c \
+	dscapture.c \
+	dsrender.c \
 	midi.c \
 	midipatch.c \
 	mixer.c \


More information about the wine-patches mailing list