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