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