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