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