usp10: Update ScriptCPtoX to handle RTL runs.
[wine] / dlls / wineoss.drv / dscapture.c
1 /*
2  * Direct Sound Capture driver
3  *
4  * Copyright 2004 Robert Reif
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_IOCTL_H
34 # include <sys/ioctl.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
39 #ifdef HAVE_POLL_H
40 #include <poll.h>
41 #endif
42 #ifdef HAVE_SYS_POLL_H
43 # include <sys/poll.h>
44 #endif
45
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "mmddk.h"
52 #include "mmreg.h"
53 #include "dsound.h"
54 #include "dsdriver.h"
55 #include "oss.h"
56 #include "wine/debug.h"
57
58 #include "audio.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(dscapture);
61
62 #ifdef HAVE_OSS
63
64 /*======================================================================*
65  *           Low level DSOUND capture definitions                       *
66  *======================================================================*/
67
68 typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
69 typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
70 typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
71 typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
72
73 struct IDsCaptureDriverPropertySetImpl
74 {
75     /* IUnknown fields */
76     IDsDriverPropertySet                IDsDriverPropertySet_iface;
77     LONG                                ref;
78
79     IDsCaptureDriverBufferImpl*         capture_buffer;
80 };
81
82 struct IDsCaptureDriverNotifyImpl
83 {
84     /* IUnknown fields */
85     IDsDriverNotify                     IDsDriverNotify_iface;
86     LONG                                ref;
87
88     IDsCaptureDriverBufferImpl*         capture_buffer;
89 };
90
91 struct IDsCaptureDriverImpl
92 {
93     /* IUnknown fields */
94     IDsCaptureDriver                    IDsCaptureDriver_iface;
95     LONG                                ref;
96
97     /* IDsCaptureDriverImpl fields */
98     UINT                                wDevID;
99     IDsCaptureDriverBufferImpl*         capture_buffer;
100 };
101
102 struct IDsCaptureDriverBufferImpl
103 {
104     /* IUnknown fields */
105     IDsCaptureDriverBuffer              IDsCaptureDriverBuffer_iface;
106     LONG                                ref;
107
108     /* IDsCaptureDriverBufferImpl fields */
109     IDsCaptureDriverImpl*               drv;
110     LPBYTE                              buffer;         /* user buffer */
111     DWORD                               buflen;         /* user buffer length */
112     LPBYTE                              mapping;        /* DMA buffer */
113     DWORD                               maplen;         /* DMA buffer length */
114     BOOL                                is_direct_map;  /* DMA == user ? */
115     DWORD                               fragsize;
116     DWORD                               map_writepos;   /* DMA write offset */
117     DWORD                               map_readpos;    /* DMA read offset */
118     DWORD                               writeptr;       /* user write offset */
119     DWORD                               readptr;        /* user read offset */
120
121     /* IDsDriverNotifyImpl fields */
122     IDsCaptureDriverNotifyImpl*         notify;
123     int                                 notify_index;
124     LPDSBPOSITIONNOTIFY                 notifies;
125     int                                 nrofnotifies;
126
127     /* IDsDriverPropertySetImpl fields */
128     IDsCaptureDriverPropertySetImpl*    property_set;
129
130     BOOL                                is_capturing;
131     BOOL                                is_looping;
132     WAVEFORMATEX                        wfx;
133     HANDLE                              hThread;
134     DWORD                               dwThreadID;
135     HANDLE                              hStartUpEvent;
136     HANDLE                              hExitEvent;
137     int                                 pipe_fd[2];
138     int                                 fd;
139 };
140
141 static inline IDsCaptureDriverPropertySetImpl *impl_from_IDsDriverPropertySet(IDsDriverPropertySet *iface)
142 {
143     return CONTAINING_RECORD(iface, IDsCaptureDriverPropertySetImpl, IDsDriverPropertySet_iface);
144 }
145
146 static inline IDsCaptureDriverNotifyImpl *impl_from_IDsDriverNotify(IDsDriverNotify *iface)
147 {
148     return CONTAINING_RECORD(iface, IDsCaptureDriverNotifyImpl, IDsDriverNotify_iface);
149 }
150
151 static inline IDsCaptureDriverImpl *impl_from_IDsCaptureDriver(IDsCaptureDriver *iface)
152 {
153     return CONTAINING_RECORD(iface, IDsCaptureDriverImpl, IDsCaptureDriver_iface);
154 }
155
156 static inline IDsCaptureDriverBufferImpl *impl_from_IDsCaptureDriverBuffer(IDsCaptureDriverBuffer *iface)
157 {
158     return CONTAINING_RECORD(iface, IDsCaptureDriverBufferImpl, IDsCaptureDriverBuffer_iface);
159 }
160
161 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
162     IDsCaptureDriverBufferImpl * dscdb,
163     IDsCaptureDriverPropertySetImpl **pdscdps);
164
165 static HRESULT IDsCaptureDriverNotifyImpl_Create(
166     IDsCaptureDriverBufferImpl * dsdcb,
167     IDsCaptureDriverNotifyImpl **pdscdn);
168
169 /*======================================================================*
170  *           Low level DSOUND capture property set implementation       *
171  *======================================================================*/
172
173 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
174     PIDSDRIVERPROPERTYSET iface,
175     REFIID riid,
176     LPVOID *ppobj)
177 {
178     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
179     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
180
181     if ( IsEqualGUID(riid, &IID_IUnknown) ||
182          IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
183         IDsDriverPropertySet_AddRef(iface);
184         *ppobj = This;
185         return DS_OK;
186     }
187
188     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
189
190     *ppobj = 0;
191     return E_NOINTERFACE;
192 }
193
194 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
195     PIDSDRIVERPROPERTYSET iface)
196 {
197     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
198     ULONG refCount = InterlockedIncrement(&This->ref);
199
200     TRACE("(%p) ref was %d\n", This, refCount - 1);
201
202     return refCount;
203 }
204
205 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
206     PIDSDRIVERPROPERTYSET iface)
207 {
208     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
209     ULONG refCount = InterlockedDecrement(&This->ref);
210
211     TRACE("(%p) ref was %d\n", This, refCount + 1);
212
213     if (!refCount) {
214         IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
215         This->capture_buffer->property_set = NULL;
216         HeapFree(GetProcessHeap(),0,This);
217         TRACE("(%p) released\n",This);
218     }
219     return refCount;
220 }
221
222 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
223     PIDSDRIVERPROPERTYSET iface,
224     PDSPROPERTY pDsProperty,
225     LPVOID pPropertyParams,
226     ULONG cbPropertyParams,
227     LPVOID pPropertyData,
228     ULONG cbPropertyData,
229     PULONG pcbReturnedData )
230 {
231     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
232     FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,
233           cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
234     return DSERR_UNSUPPORTED;
235 }
236
237 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
238     PIDSDRIVERPROPERTYSET iface,
239     PDSPROPERTY pDsProperty,
240     LPVOID pPropertyParams,
241     ULONG cbPropertyParams,
242     LPVOID pPropertyData,
243     ULONG cbPropertyData )
244 {
245     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
246     FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,
247           cbPropertyParams,pPropertyData,cbPropertyData);
248     return DSERR_UNSUPPORTED;
249 }
250
251 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
252     PIDSDRIVERPROPERTYSET iface,
253     REFGUID PropertySetId,
254     ULONG PropertyId,
255     PULONG pSupport )
256 {
257     IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
258     FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
259           pSupport);
260     return DSERR_UNSUPPORTED;
261 }
262
263 static const IDsDriverPropertySetVtbl dscdpsvt =
264 {
265     IDsCaptureDriverPropertySetImpl_QueryInterface,
266     IDsCaptureDriverPropertySetImpl_AddRef,
267     IDsCaptureDriverPropertySetImpl_Release,
268     IDsCaptureDriverPropertySetImpl_Get,
269     IDsCaptureDriverPropertySetImpl_Set,
270     IDsCaptureDriverPropertySetImpl_QuerySupport,
271 };
272
273 /*======================================================================*
274  *                  Low level DSOUND capture notify implementation      *
275  *======================================================================*/
276
277 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
278     PIDSDRIVERNOTIFY iface,
279     REFIID riid,
280     LPVOID *ppobj)
281 {
282     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
283     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
284
285     if ( IsEqualGUID(riid, &IID_IUnknown) ||
286          IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
287         IDsDriverNotify_AddRef(iface);
288         *ppobj = This;
289         return DS_OK;
290     }
291
292     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
293
294     *ppobj = 0;
295     return E_NOINTERFACE;
296 }
297
298 static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
299     PIDSDRIVERNOTIFY iface)
300 {
301     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
302     ULONG refCount = InterlockedIncrement(&This->ref);
303
304     TRACE("(%p) ref was %d\n", This, refCount - 1);
305
306     return refCount;
307 }
308
309 static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
310     PIDSDRIVERNOTIFY iface)
311 {
312     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
313     ULONG refCount = InterlockedDecrement(&This->ref);
314
315     TRACE("(%p) ref was %d\n", This, refCount + 1);
316
317     if (!refCount) {
318         IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
319         This->capture_buffer->notify = NULL;
320         HeapFree(GetProcessHeap(),0,This);
321         TRACE("(%p) released\n",This);
322     }
323     return refCount;
324 }
325
326 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
327     PIDSDRIVERNOTIFY iface,
328     DWORD howmuch,
329     LPCDSBPOSITIONNOTIFY notify)
330 {
331     IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
332     TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
333
334     if (!notify) {
335         WARN("invalid parameter\n");
336         return DSERR_INVALIDPARAM;
337     }
338
339     if (TRACE_ON(dscapture)) {
340         DWORD i;
341         for (i=0;i<howmuch;i++)
342             TRACE("notify at %d to 0x%08lx\n",
343                 notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
344     }
345
346     /* Make an internal copy of the caller-supplied array.
347      * Replace the existing copy if one is already present. */
348     if (This->capture_buffer->notifies)
349         This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
350             HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
351             howmuch * sizeof(DSBPOSITIONNOTIFY));
352     else
353         This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
354             HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
355
356     memcpy(This->capture_buffer->notifies, notify,
357            howmuch * sizeof(DSBPOSITIONNOTIFY));
358     This->capture_buffer->nrofnotifies = howmuch;
359
360     return S_OK;
361 }
362
363 static const IDsDriverNotifyVtbl dscdnvt =
364 {
365     IDsCaptureDriverNotifyImpl_QueryInterface,
366     IDsCaptureDriverNotifyImpl_AddRef,
367     IDsCaptureDriverNotifyImpl_Release,
368     IDsCaptureDriverNotifyImpl_SetNotificationPositions,
369 };
370
371 /*======================================================================*
372  *                  Low level DSOUND capture implementation             *
373  *======================================================================*/
374
375 static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
376 {
377     if (!dscdb->mapping) {
378         dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
379                               WInDev[dscdb->drv->wDevID].ossdev.fd, 0);
380         if (dscdb->mapping == (LPBYTE)-1) {
381             TRACE("(%p): Could not map sound device for direct access (%s)\n",
382                   dscdb, strerror(errno));
383             return DSERR_GENERIC;
384         }
385         TRACE("(%p): sound device has been mapped for direct access at %p, "
386               "size=%d\n", dscdb, dscdb->mapping, dscdb->maplen);
387     }
388     return DS_OK;
389 }
390
391 static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
392 {
393     if (dscdb->mapping) {
394         if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
395             ERR("(%p): Could not unmap sound device (%s)\n",
396                 dscdb, strerror(errno));
397             return DSERR_GENERIC;
398         }
399         dscdb->mapping = NULL;
400         TRACE("(%p): sound device unmapped\n", dscdb);
401     }
402     return DS_OK;
403 }
404
405 static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
406     PIDSCDRIVERBUFFER iface,
407     REFIID riid,
408     LPVOID *ppobj)
409 {
410     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
411     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
412
413     *ppobj = 0;
414
415     if ( IsEqualGUID(riid, &IID_IUnknown) ||
416          IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
417         IDsCaptureDriverBuffer_AddRef(iface);
418         *ppobj = This;
419         return DS_OK;
420     }
421
422     if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
423         if (!This->notify)
424             IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
425         if (This->notify) {
426             IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
427             *ppobj = This->notify;
428             return DS_OK;
429         }
430         return E_FAIL;
431     }
432
433     if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
434         if (!This->property_set)
435             IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
436         if (This->property_set) {
437             IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
438             *ppobj = This->property_set;
439             return DS_OK;
440         }
441         return E_FAIL;
442     }
443
444     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
445     return DSERR_UNSUPPORTED;
446 }
447
448 static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
449 {
450     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
451     ULONG refCount = InterlockedIncrement(&This->ref);
452
453     TRACE("(%p) ref was %d\n", This, refCount - 1);
454
455     return refCount;
456 }
457
458 static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
459 {
460     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
461     ULONG refCount = InterlockedDecrement(&This->ref);
462     TRACE("(%p) ref was %d\n", This, refCount + 1);
463
464     if (!refCount) {
465         WINE_WAVEIN*        wwi;
466
467         wwi = &WInDev[This->drv->wDevID];
468
469         if (This->hThread) {
470             int x = 0;
471
472             /* request thread termination */
473             write(This->pipe_fd[1], &x, sizeof(x));
474
475             /* wait for reply */
476             WaitForSingleObject(This->hExitEvent, INFINITE);
477             CloseHandle(This->hExitEvent);
478         }
479
480         close(This->pipe_fd[0]);
481         close(This->pipe_fd[1]);
482
483         DSCDB_UnmapBuffer(This);
484
485         OSS_CloseDevice(&wwi->ossdev);
486         wwi->state = WINE_WS_CLOSED;
487         wwi->dwFragmentSize = 0;
488         This->drv->capture_buffer = NULL;
489
490         HeapFree(GetProcessHeap(), 0, This->notifies);
491         HeapFree(GetProcessHeap(),0,This);
492         TRACE("(%p) released\n",This);
493     }
494     return refCount;
495 }
496
497 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
498     PIDSCDRIVERBUFFER iface,
499     LPVOID* ppvAudio1,
500     LPDWORD pdwLen1,
501     LPVOID* ppvAudio2,
502     LPDWORD pdwLen2,
503     DWORD dwWritePosition,
504     DWORD dwWriteLen,
505     DWORD dwFlags)
506 {
507     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
508     TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n",This,ppvAudio1,pdwLen1,
509           ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
510
511     if (This->is_direct_map) {
512         if (ppvAudio1)
513             *ppvAudio1 = This->mapping + dwWritePosition;
514
515         if (dwWritePosition + dwWriteLen < This->maplen) {
516             if (pdwLen1)
517                 *pdwLen1 = dwWriteLen;
518             if (ppvAudio2)
519                 *ppvAudio2 = 0;
520             if (pdwLen2)
521                 *pdwLen2 = 0;
522         } else {
523             if (pdwLen1)
524                 *pdwLen1 = This->maplen - dwWritePosition;
525             if (ppvAudio2)
526                 *ppvAudio2 = 0;
527             if (pdwLen2)
528                 *pdwLen2 = dwWriteLen - (This->maplen - dwWritePosition);
529         }
530     } else {
531         if (ppvAudio1)
532             *ppvAudio1 = This->buffer + dwWritePosition;
533
534         if (dwWritePosition + dwWriteLen < This->buflen) {
535             if (pdwLen1)
536                 *pdwLen1 = dwWriteLen;
537             if (ppvAudio2)
538                 *ppvAudio2 = 0;
539             if (pdwLen2)
540                 *pdwLen2 = 0;
541         } else {
542             if (pdwLen1)
543                 *pdwLen1 = This->buflen - dwWritePosition;
544             if (ppvAudio2)
545                 *ppvAudio2 = 0;
546             if (pdwLen2)
547                 *pdwLen2 = dwWriteLen - (This->buflen - dwWritePosition);
548         }
549     }
550
551     return DS_OK;
552 }
553
554 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
555     PIDSCDRIVERBUFFER iface,
556     LPVOID pvAudio1,
557     DWORD dwLen1,
558     LPVOID pvAudio2,
559     DWORD dwLen2)
560 {
561     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
562     TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
563
564     if (This->is_direct_map)
565         This->map_readpos = (This->map_readpos + dwLen1 + dwLen2) % This->maplen;
566     else
567         This->readptr = (This->readptr + dwLen1 + dwLen2) % This->buflen;
568
569     return DS_OK;
570 }
571
572 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
573     PIDSCDRIVERBUFFER iface,
574     LPDWORD lpdwCapture,
575     LPDWORD lpdwRead)
576 {
577     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
578     TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
579
580     if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
581         ERR("device not open, but accessing?\n");
582         return DSERR_UNINITIALIZED;
583     }
584
585     if (!This->is_capturing) {
586         if (lpdwCapture)
587             *lpdwCapture = 0;
588         if (lpdwRead)
589             *lpdwRead = 0;
590     }
591
592     if (This->is_direct_map) {
593         if (lpdwCapture)
594             *lpdwCapture = This->map_writepos;
595         if (lpdwRead) {
596             *lpdwRead = This->map_readpos;
597         }
598     } else {
599         if (lpdwCapture)
600             *lpdwCapture = This->writeptr;
601         if (lpdwRead)
602             *lpdwRead = This->readptr;
603     }
604
605     TRACE("capturepos=%d, readpos=%d\n", lpdwCapture?*lpdwCapture:0,
606           lpdwRead?*lpdwRead:0);
607     return DS_OK;
608 }
609
610 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
611     PIDSCDRIVERBUFFER iface,
612     LPDWORD lpdwStatus)
613 {
614     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
615     TRACE("(%p,%p)\n",This,lpdwStatus);
616
617     if (This->is_capturing) {
618         if (This->is_looping)
619             *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
620         else
621             *lpdwStatus = DSCBSTATUS_CAPTURING;
622     } else
623         *lpdwStatus = 0;
624
625     return DS_OK;
626 }
627
628 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
629     PIDSCDRIVERBUFFER iface,
630     DWORD dwFlags)
631 {
632     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
633     int enable;
634     TRACE("(%p,%x)\n",This,dwFlags);
635
636     if (This->is_capturing)
637         return DS_OK;
638
639     if (dwFlags & DSCBSTART_LOOPING)
640         This->is_looping = TRUE;
641
642     WInDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
643     enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
644     if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
645         if (errno == EINVAL) {
646             /* Don't give up yet. OSS trigger support is inconsistent. */
647             if (WInDev[This->drv->wDevID].ossdev.open_count == 1) {
648                 /* try the opposite output enable */
649                 if (WInDev[This->drv->wDevID].ossdev.bOutputEnabled == FALSE)
650                     WInDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
651                 else
652                     WInDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
653                 /* try it again */
654                 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
655                 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
656                     This->is_capturing = TRUE;
657                     return DS_OK;
658                 }
659             }
660         }
661         ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
662             WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
663         WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
664         return DSERR_GENERIC;
665     }
666
667     This->is_capturing = TRUE;
668     return DS_OK;
669 }
670
671 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
672 {
673     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
674     int enable;
675     TRACE("(%p)\n",This);
676
677     if (!This->is_capturing)
678         return DS_OK;
679
680     /* no more capturing */
681     WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
682     enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
683     if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
684         ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
685             WInDev[This->drv->wDevID].ossdev.dev_name,  strerror(errno));
686         return DSERR_GENERIC;
687     }
688
689     /* send a final event if necessary */
690     if (This->nrofnotifies > 0) {
691         if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
692             SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
693     }
694
695     This->is_capturing = FALSE;
696     This->is_looping = FALSE;
697
698     if (This->hThread) {
699         int x = 0;
700         write(This->pipe_fd[1], &x, sizeof(x));
701         WaitForSingleObject(This->hExitEvent, INFINITE);
702         CloseHandle(This->hExitEvent);
703         This->hExitEvent = INVALID_HANDLE_VALUE;
704         This->hThread = 0;
705     }
706
707     return DS_OK;
708 }
709
710 static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
711     PIDSCDRIVERBUFFER iface,
712     LPWAVEFORMATEX pwfx)
713 {
714     IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
715     FIXME("(%p): stub!\n",This);
716     return DSERR_UNSUPPORTED;
717 }
718
719 static const IDsCaptureDriverBufferVtbl dscdbvt =
720 {
721     IDsCaptureDriverBufferImpl_QueryInterface,
722     IDsCaptureDriverBufferImpl_AddRef,
723     IDsCaptureDriverBufferImpl_Release,
724     IDsCaptureDriverBufferImpl_Lock,
725     IDsCaptureDriverBufferImpl_Unlock,
726     IDsCaptureDriverBufferImpl_SetFormat,
727     IDsCaptureDriverBufferImpl_GetPosition,
728     IDsCaptureDriverBufferImpl_GetStatus,
729     IDsCaptureDriverBufferImpl_Start,
730     IDsCaptureDriverBufferImpl_Stop
731 };
732
733 static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
734     PIDSCDRIVER iface,
735     REFIID riid,
736     LPVOID *ppobj)
737 {
738     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
739     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
740
741     if ( IsEqualGUID(riid, &IID_IUnknown) ||
742          IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
743         IDsCaptureDriver_AddRef(iface);
744         *ppobj = This;
745         return DS_OK;
746     }
747
748     FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
749
750     *ppobj = 0;
751
752     return E_NOINTERFACE;
753 }
754
755 static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
756 {
757     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
758     ULONG refCount = InterlockedIncrement(&This->ref);
759
760     TRACE("(%p) ref was %d\n", This, refCount - 1);
761
762     return refCount;
763 }
764
765 static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
766 {
767     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
768     ULONG refCount = InterlockedDecrement(&This->ref);
769
770     TRACE("(%p) ref was %d\n", This, refCount + 1);
771
772     if (!refCount) {
773         HeapFree(GetProcessHeap(),0,This);
774         TRACE("(%p) released\n",This);
775     }
776     return refCount;
777 }
778
779 static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
780     PIDSCDRIVER iface,
781     PDSDRIVERDESC pDesc)
782 {
783     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
784     TRACE("(%p,%p)\n",This,pDesc);
785
786     if (!pDesc) {
787         TRACE("invalid parameter\n");
788         return DSERR_INVALIDPARAM;
789     }
790
791     /* copy version from driver */
792     *pDesc = WInDev[This->wDevID].ossdev.ds_desc;
793
794     pDesc->dnDevNode            = WInDev[This->wDevID].waveDesc.dnDevNode;
795     pDesc->wVxdId               = 0;
796     pDesc->wReserved            = 0;
797     pDesc->ulDeviceNum          = This->wDevID;
798     pDesc->dwHeapType           = DSDHEAP_NOHEAP;
799     pDesc->pvDirectDrawHeap     = NULL;
800     pDesc->dwMemStartAddress    = 0;
801     pDesc->dwMemEndAddress      = 0;
802     pDesc->dwMemAllocExtra      = 0;
803     pDesc->pvReserved1          = NULL;
804     pDesc->pvReserved2          = NULL;
805     return DS_OK;
806 }
807
808 static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
809 {
810     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
811     TRACE("(%p)\n",This);
812     return DS_OK;
813 }
814
815 static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
816 {
817     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
818     TRACE("(%p)\n",This);
819     if (This->capture_buffer) {
820         ERR("problem with DirectSound: capture buffer not released\n");
821         return DSERR_GENERIC;
822     }
823     return DS_OK;
824 }
825
826 static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
827     PIDSCDRIVER iface,
828     PDSCDRIVERCAPS pCaps)
829 {
830     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
831     TRACE("(%p,%p)\n",This,pCaps);
832     *pCaps = WInDev[This->wDevID].ossdev.dsc_caps;
833     return DS_OK;
834 }
835
836 static void DSCDB_CheckEvent(
837     IDsCaptureDriverBufferImpl *dscb,
838     DWORD writepos,
839     DWORD len,
840     DWORD buflen)
841 {
842     LPDSBPOSITIONNOTIFY event = dscb->notifies + dscb->notify_index;
843     DWORD offset = event->dwOffset;
844     TRACE("(%p,%d,%d,%d)\n", dscb, writepos, len, buflen);
845
846     TRACE("(%p) buflen = %d, writeptr = %d\n",
847         dscb, dscb->buflen, dscb->writeptr);
848     TRACE("checking %d, position %d, event = %p\n",
849         dscb->notify_index, offset, event->hEventNotify);
850
851     if ((writepos + len) > offset) {
852          TRACE("signalled event %p (%d) %d\n",
853                event->hEventNotify, dscb->notify_index, offset);
854          SetEvent(event->hEventNotify);
855          dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
856          return;
857     } else if ((writepos + len) > buflen) {
858         writepos = writepos + len - buflen;
859         if ((writepos + len) > offset) {
860              TRACE("signalled event %p (%d) %d\n",
861                    event->hEventNotify, dscb->notify_index, offset);
862              SetEvent(event->hEventNotify);
863              dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
864              return;
865         }
866     }
867
868     return;
869 }
870
871 /* FIXME: using memcpy can cause strange crashes so use this fake one */
872 static void * my_memcpy(void * dst, const void * src, int length)
873 {
874     int i;
875     for (i = 0; i < length; i++)
876         ((char *)dst)[i] = ((const char *)src)[i];
877     return dst;
878 }
879
880 static DWORD CALLBACK DSCDB_Thread(LPVOID lpParameter)
881 {
882     IDsCaptureDriverBufferImpl *This = lpParameter;
883     struct pollfd poll_list[2];
884     int retval;
885     DWORD offset = 0;
886     DWORD map_offset = 0;
887     TRACE("(%p)\n", lpParameter);
888
889     poll_list[0].fd = This->fd;                /* data available */
890     poll_list[1].fd = This->pipe_fd[0];        /* message from parent process */
891     poll_list[0].events = POLLIN;
892     poll_list[1].events = POLLIN;
893
894     /* let other process know we are running */
895     SetEvent(This->hStartUpEvent);
896
897     while (1) {
898         /* wait for something to happen */
899         retval = poll(poll_list,(unsigned long)2,-1);
900         /* Retval will always be greater than 0 or -1 in this case.
901          * Since we're doing it while blocking
902          */
903         if (retval < 0) {
904             ERR("Error while polling: %s\n",strerror(errno));
905             continue;
906         }
907
908         /* check for exit command */
909         if ((poll_list[1].revents & POLLIN) == POLLIN) {
910             TRACE("(%p) done\n", lpParameter);
911             /* acknowledge command and exit */
912             SetEvent(This->hExitEvent);
913             ExitThread(0);
914             return 0;
915         }
916
917         /* check for data */
918         if ((poll_list[0].revents & POLLIN) == POLLIN) {
919             count_info info;
920             int fragsize, first, second;
921
922             /* get the current DMA position */
923             if (ioctl(This->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
924                 ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
925                     WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
926                 return DSERR_GENERIC;
927             }
928
929             if (This->is_direct_map) {
930                 offset = This->map_writepos;
931                 This->map_writepos = info.ptr;
932
933                 if (info.ptr < offset)
934                     fragsize = info.ptr + This->maplen - offset;
935                 else
936                     fragsize = info.ptr - offset;
937
938                 DSCDB_CheckEvent(This, offset, fragsize, This->maplen);
939             } else {
940                 map_offset = This->map_writepos;
941                 offset = This->writeptr;
942
943                 /* test for mmap buffer wrap */
944                 if (info.ptr < map_offset) {
945                     /* mmap buffer wrapped */
946                     fragsize = info.ptr + This->maplen - map_offset;
947
948                     /* check for user buffer wrap */
949                     if ((offset + fragsize) > This->buflen) {
950                         /* both buffers wrapped
951                          * figure out which wrapped first
952                          */
953                         if ((This->maplen - map_offset) > (This->buflen - offset)) {
954                             /* user buffer wrapped first */
955                             first = This->buflen - offset;
956                             second = (This->maplen - map_offset) - first;
957                             my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
958                             my_memcpy(This->buffer, This->mapping + map_offset + first, second);
959                             my_memcpy(This->buffer + second, This->mapping, fragsize - (first + second));
960                         } else {
961                             /* mmap buffer wrapped first */
962                             first = This->maplen - map_offset;
963                             second = (This->buflen - offset) - first;
964                             my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
965                             my_memcpy(This->buffer + offset + first, This->mapping, second);
966                             my_memcpy(This->buffer, This->mapping + second, fragsize - (first + second));
967                         }
968                     } else {
969                         /* only mmap buffer wrapped */
970                         first = This->maplen - map_offset;
971                         my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
972                         my_memcpy(This->buffer + offset + first, This->mapping, fragsize - first);
973                     }
974                 } else {
975                     /* mmap buffer didn't wrap */
976                     fragsize = info.ptr - map_offset;
977
978                     /* check for user buffer wrap */
979                     if ((offset + fragsize) > This->buflen) {
980                         first = This->buflen - offset;
981                         my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
982                         my_memcpy(This->buffer, This->mapping + map_offset + first, fragsize - first);
983                     } else
984                         my_memcpy(This->buffer + offset, This->mapping + map_offset, fragsize);
985                 }
986
987                 This->map_writepos = info.ptr;
988                 This->writeptr = (This->writeptr + fragsize) % This->buflen;
989                 DSCDB_CheckEvent(This, offset, fragsize, This->buflen);
990             }
991         }
992     }
993 }
994
995 static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
996     PIDSCDRIVER iface,
997     LPWAVEFORMATEX pwfx,
998     DWORD dwFlags,
999     DWORD dwCardAddress,
1000     LPDWORD pdwcbBufferSize,
1001     LPBYTE *ppbBuffer,
1002     LPVOID *ppvObj)
1003 {
1004     IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
1005     IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
1006     HRESULT err;
1007     audio_buf_info info;
1008     int audio_fragment, fsize, shift, ret;
1009     BOOL bNewBuffer = FALSE;
1010     WINE_WAVEIN* wwi;
1011     TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
1012           pdwcbBufferSize,ppbBuffer,ppvObj);
1013
1014     if (This->capture_buffer) {
1015         TRACE("already allocated\n");
1016         return DSERR_ALLOCATED;
1017     }
1018
1019     /* must be given a buffer size */
1020     if (pdwcbBufferSize == NULL || *pdwcbBufferSize == 0) {
1021        TRACE("invalid parameter: pdwcbBufferSize\n");
1022        return DSERR_INVALIDPARAM;
1023     }
1024
1025     /* must be given a buffer pointer */
1026     if (ppbBuffer == NULL) {
1027        TRACE("invalid parameter: ppbBuffer\n");
1028        return DSERR_INVALIDPARAM;
1029     }
1030
1031     /* may or may not be given a buffer */
1032     if (*ppbBuffer == NULL) {
1033         TRACE("creating buffer\n");
1034         bNewBuffer = TRUE;     /* not given a buffer so create one */
1035     } else
1036         TRACE("using supplied buffer\n");
1037
1038     *ippdscdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
1039     if (*ippdscdb == NULL) {
1040         TRACE("out of memory\n");
1041         return DSERR_OUTOFMEMORY;
1042     }
1043
1044     (*ippdscdb)->IDsCaptureDriverBuffer_iface.lpVtbl = &dscdbvt;
1045     (*ippdscdb)->ref          = 1;
1046     (*ippdscdb)->drv          = This;
1047     (*ippdscdb)->notify       = NULL;
1048     (*ippdscdb)->notify_index = 0;
1049     (*ippdscdb)->notifies     = NULL;
1050     (*ippdscdb)->nrofnotifies = 0;
1051     (*ippdscdb)->property_set = NULL;
1052     (*ippdscdb)->is_capturing = FALSE;
1053     (*ippdscdb)->is_looping   = FALSE;
1054     (*ippdscdb)->wfx          = *pwfx;
1055     (*ippdscdb)->buflen       = *pdwcbBufferSize;
1056
1057     if (bNewBuffer)
1058         (*ippdscdb)->buffer = NULL;
1059     else
1060         (*ippdscdb)->buffer = *ppbBuffer;
1061
1062     wwi = &WInDev[This->wDevID];
1063
1064     if (wwi->state == WINE_WS_CLOSED) {
1065         unsigned int frag_size;
1066
1067         if (wwi->ossdev.open_count > 0) {
1068             /* opened already so use existing fragment size */
1069             audio_fragment = wwi->ossdev.audio_fragment;
1070         } else {
1071             /* calculate a fragment size */
1072             unsigned int mask = 0xffffffff;
1073
1074             /* calculate largest fragment size less than 10 ms. */
1075             fsize = pwfx->nAvgBytesPerSec / 100;        /* 10 ms chunk */
1076             shift = 0;
1077             while ((1 << shift) <= fsize)
1078                 shift++;
1079             shift--;
1080             fsize = 1 << shift;
1081             TRACE("shift = %d, fragment size = %d\n", shift, fsize);
1082             TRACE("BufferSize=%d(%08x)\n", *pdwcbBufferSize, *pdwcbBufferSize);
1083
1084             /* See if we can directly map the buffer first.
1085              * (buffer length is multiple of a power of 2)
1086              */
1087             mask = (mask >> (32 - shift));
1088             TRACE("mask=%08x\n", mask);
1089             if (*pdwcbBufferSize & mask) {
1090                 /* no so try a smaller fragment size greater than 1 ms */
1091                 int new_shift = shift - 1;
1092                 int min_shift = 0;
1093                 int min_fsize = pwfx->nAvgBytesPerSec / 1000;
1094                 BOOL found_one = FALSE;
1095                 while ((1 << min_shift) <= min_fsize)
1096                     min_shift++;
1097                 min_shift--;
1098                 while (new_shift > min_shift) {
1099                     if (*pdwcbBufferSize & (-1 >> (32 - new_shift))) {
1100                         new_shift--;
1101                         continue;
1102                     } else {
1103                         found_one = TRUE;
1104                         break;
1105                     }
1106                 }
1107                 if (found_one) {
1108                     /* found a smaller one that will work */
1109                     audio_fragment = ((*pdwcbBufferSize >> new_shift) << 16) | new_shift;
1110                     (*ippdscdb)->is_direct_map = TRUE;
1111                     TRACE("new shift = %d, fragment size = %d\n",
1112                           new_shift, 1 << (audio_fragment & 0xffff));
1113                 } else {
1114                     /* buffer can't be direct mapped */
1115                     audio_fragment = 0x00100000 + shift;        /* 16 fragments of 2^shift */
1116                     (*ippdscdb)->is_direct_map = FALSE;
1117                 }
1118             } else {
1119                 /* good fragment size */
1120                 audio_fragment = ((*pdwcbBufferSize >> shift) << 16) | shift;
1121                 (*ippdscdb)->is_direct_map = TRUE;
1122             }
1123         }
1124         frag_size = 1 << (audio_fragment & 0xffff);
1125         TRACE("is_direct_map = %s\n", (*ippdscdb)->is_direct_map ? "TRUE" : "FALSE");
1126         TRACE("requesting %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1127               audio_fragment >> 16, frag_size, frag_size * (audio_fragment >> 16),
1128               (frag_size * 1000) / pwfx->nAvgBytesPerSec);
1129
1130         ret = OSS_OpenDevice(&wwi->ossdev, O_RDWR, &audio_fragment, 1,
1131                              pwfx->nSamplesPerSec,
1132                              (pwfx->nChannels > 1) ? 1 : 0,
1133                              (pwfx->wBitsPerSample == 16)
1134                              ? AFMT_S16_LE : AFMT_U8);
1135
1136         if (ret != 0) {
1137             WARN("OSS_OpenDevice failed\n");
1138             HeapFree(GetProcessHeap(),0,*ippdscdb);
1139             *ippdscdb = NULL;
1140             return DSERR_GENERIC;
1141         }
1142
1143         wwi->state = WINE_WS_STOPPED;
1144
1145         /* find out what fragment and buffer sizes OSS gave us */
1146         if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1147              ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1148                  wwi->ossdev.dev_name, strerror(errno));
1149              OSS_CloseDevice(&wwi->ossdev);
1150              wwi->state = WINE_WS_CLOSED;
1151              HeapFree(GetProcessHeap(),0,*ippdscdb);
1152              *ippdscdb = NULL;
1153              return DSERR_GENERIC;
1154         }
1155
1156         TRACE("got %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1157               info.fragstotal, info.fragsize, info.fragstotal * info.fragsize,
1158               info.fragsize * 1000 / pwfx->nAvgBytesPerSec);
1159
1160         wwi->dwTotalRecorded = 0;
1161         memcpy(&wwi->waveFormat, pwfx, sizeof(PCMWAVEFORMAT));
1162         wwi->dwFragmentSize = info.fragsize;
1163
1164         /* make sure we got what we asked for */
1165         if ((*ippdscdb)->buflen != info.fragstotal * info.fragsize) {
1166             TRACE("Couldn't create requested buffer\n");
1167             if ((*ippdscdb)->is_direct_map) {
1168                 (*ippdscdb)->is_direct_map = FALSE;
1169                 TRACE("is_direct_map = FALSE\n");
1170             }
1171         } else if (info.fragsize != frag_size) {
1172             TRACE("same buffer length but different fragment size\n");
1173         }
1174     }
1175     (*ippdscdb)->fd = WInDev[This->wDevID].ossdev.fd;
1176
1177     if (pipe((*ippdscdb)->pipe_fd) < 0) {
1178         TRACE("pipe() failed (%s)\n", strerror(errno));
1179         OSS_CloseDevice(&wwi->ossdev);
1180         wwi->state = WINE_WS_CLOSED;
1181         HeapFree(GetProcessHeap(),0,*ippdscdb);
1182         *ippdscdb = NULL;
1183         return DSERR_GENERIC;
1184     }
1185
1186     /* check how big the DMA buffer is now */
1187     if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1188         ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1189             wwi->ossdev.dev_name, strerror(errno));
1190         OSS_CloseDevice(&wwi->ossdev);
1191         wwi->state = WINE_WS_CLOSED;
1192         close((*ippdscdb)->pipe_fd[0]);
1193         close((*ippdscdb)->pipe_fd[1]);
1194         HeapFree(GetProcessHeap(),0,*ippdscdb);
1195         *ippdscdb = NULL;
1196         return DSERR_GENERIC;
1197     }
1198
1199     (*ippdscdb)->maplen = info.fragstotal * info.fragsize;
1200     (*ippdscdb)->fragsize = info.fragsize;
1201     (*ippdscdb)->map_writepos = 0;
1202     (*ippdscdb)->map_readpos = 0;
1203
1204     /* map the DMA buffer */
1205     err = DSCDB_MapBuffer(*ippdscdb);
1206     if (err != DS_OK) {
1207         OSS_CloseDevice(&wwi->ossdev);
1208         wwi->state = WINE_WS_CLOSED;
1209         close((*ippdscdb)->pipe_fd[0]);
1210         close((*ippdscdb)->pipe_fd[1]);
1211         HeapFree(GetProcessHeap(),0,*ippdscdb);
1212         *ippdscdb = NULL;
1213         return err;
1214     }
1215
1216     /* create the buffer if necessary */
1217     if (!(*ippdscdb)->buffer)
1218         (*ippdscdb)->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(*ippdscdb)->buflen);
1219
1220     if ((*ippdscdb)->buffer == NULL) {
1221         OSS_CloseDevice(&wwi->ossdev);
1222         wwi->state = WINE_WS_CLOSED;
1223         close((*ippdscdb)->pipe_fd[0]);
1224         close((*ippdscdb)->pipe_fd[1]);
1225         HeapFree(GetProcessHeap(),0,*ippdscdb);
1226         *ippdscdb = NULL;
1227         return DSERR_OUTOFMEMORY;
1228     }
1229
1230     This->capture_buffer = *ippdscdb;
1231
1232     (*ippdscdb)->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1233     (*ippdscdb)->hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1234
1235     (*ippdscdb)->hThread = CreateThread(NULL, 0,  DSCDB_Thread, *ippdscdb, 0, &((*ippdscdb)->dwThreadID));
1236     WaitForSingleObject((*ippdscdb)->hStartUpEvent, INFINITE);
1237     CloseHandle((*ippdscdb)->hStartUpEvent);
1238     (*ippdscdb)->hStartUpEvent = INVALID_HANDLE_VALUE;
1239
1240     return DS_OK;
1241 }
1242
1243 static const IDsCaptureDriverVtbl dscdvt =
1244 {
1245     IDsCaptureDriverImpl_QueryInterface,
1246     IDsCaptureDriverImpl_AddRef,
1247     IDsCaptureDriverImpl_Release,
1248     IDsCaptureDriverImpl_GetDriverDesc,
1249     IDsCaptureDriverImpl_Open,
1250     IDsCaptureDriverImpl_Close,
1251     IDsCaptureDriverImpl_GetCaps,
1252     IDsCaptureDriverImpl_CreateCaptureBuffer
1253 };
1254
1255 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
1256     IDsCaptureDriverBufferImpl * dscdb,
1257     IDsCaptureDriverPropertySetImpl **pdscdps)
1258 {
1259     IDsCaptureDriverPropertySetImpl * dscdps;
1260     TRACE("(%p,%p)\n",dscdb,pdscdps);
1261
1262     dscdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdps));
1263     if (dscdps == NULL) {
1264         WARN("out of memory\n");
1265         return DSERR_OUTOFMEMORY;
1266     }
1267
1268     dscdps->ref = 0;
1269     dscdps->IDsDriverPropertySet_iface.lpVtbl = &dscdpsvt;
1270     dscdps->capture_buffer = dscdb;
1271     dscdb->property_set = dscdps;
1272     IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1273
1274     *pdscdps = dscdps;
1275     return DS_OK;
1276 }
1277
1278 static HRESULT IDsCaptureDriverNotifyImpl_Create(
1279     IDsCaptureDriverBufferImpl * dscdb,
1280     IDsCaptureDriverNotifyImpl **pdscdn)
1281 {
1282     IDsCaptureDriverNotifyImpl * dscdn;
1283     TRACE("(%p,%p)\n",dscdb,pdscdn);
1284
1285     dscdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdn));
1286     if (dscdn == NULL) {
1287         WARN("out of memory\n");
1288         return DSERR_OUTOFMEMORY;
1289     }
1290
1291     dscdn->ref = 0;
1292     dscdn->IDsDriverNotify_iface.lpVtbl = &dscdnvt;
1293     dscdn->capture_buffer = dscdb;
1294     dscdb->notify = dscdn;
1295     IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1296
1297     *pdscdn = dscdn;
1298     return DS_OK;
1299 }
1300
1301 DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
1302 {
1303     IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
1304     TRACE("(%d,%p)\n",wDevID,drv);
1305
1306     /* the HAL isn't much better than the HEL if we can't do mmap() */
1307     if (!(WInDev[wDevID].ossdev.in_caps_support & WAVECAPS_DIRECTSOUND)) {
1308         ERR("DirectSoundCapture flag not set\n");
1309         MESSAGE("This sound card's driver does not support direct access\n");
1310         MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1311         return MMSYSERR_NOTSUPPORTED;
1312     }
1313
1314     *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
1315     if (!*idrv)
1316         return MMSYSERR_NOMEM;
1317     (*idrv)->IDsCaptureDriver_iface.lpVtbl = &dscdvt;
1318     (*idrv)->ref        = 1;
1319
1320     (*idrv)->wDevID     = wDevID;
1321     (*idrv)->capture_buffer = NULL;
1322     return MMSYSERR_NOERROR;
1323 }
1324
1325 DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1326 {
1327     memcpy(desc, &(WInDev[wDevID].ossdev.ds_desc), sizeof(DSDRIVERDESC));
1328     return MMSYSERR_NOERROR;
1329 }
1330
1331 #endif /* HAVE_OSS */