c2man: Fix .spec file flag recognition.
[wine/testsucceed.git] / dlls / wineoss.drv / dscapture.c
blobe815e846dc91ad4bd3cb15885f11b0cfa2cae72b
1 /*
2 * Direct Sound Capture driver
4 * Copyright 2004 Robert Reif
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
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
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"
58 #include "audio.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(dscapture);
62 #ifdef HAVE_OSS
64 /*======================================================================*
65 * Low level DSOUND capture definitions *
66 *======================================================================*/
68 typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
69 typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
70 typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
71 typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
73 struct IDsCaptureDriverPropertySetImpl
75 /* IUnknown fields */
76 IDsDriverPropertySet IDsDriverPropertySet_iface;
77 LONG ref;
79 IDsCaptureDriverBufferImpl* capture_buffer;
82 struct IDsCaptureDriverNotifyImpl
84 /* IUnknown fields */
85 IDsDriverNotify IDsDriverNotify_iface;
86 LONG ref;
88 IDsCaptureDriverBufferImpl* capture_buffer;
91 struct IDsCaptureDriverImpl
93 /* IUnknown fields */
94 IDsCaptureDriver IDsCaptureDriver_iface;
95 LONG ref;
97 /* IDsCaptureDriverImpl fields */
98 UINT wDevID;
99 IDsCaptureDriverBufferImpl* capture_buffer;
102 struct IDsCaptureDriverBufferImpl
104 /* IUnknown fields */
105 IDsCaptureDriverBuffer IDsCaptureDriverBuffer_iface;
106 LONG ref;
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 */
121 /* IDsDriverNotifyImpl fields */
122 IDsCaptureDriverNotifyImpl* notify;
123 int notify_index;
124 LPDSBPOSITIONNOTIFY notifies;
125 int nrofnotifies;
127 /* IDsDriverPropertySetImpl fields */
128 IDsCaptureDriverPropertySetImpl* property_set;
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;
141 static inline IDsCaptureDriverPropertySetImpl *impl_from_IDsDriverPropertySet(IDsDriverPropertySet *iface)
143 return CONTAINING_RECORD(iface, IDsCaptureDriverPropertySetImpl, IDsDriverPropertySet_iface);
146 static inline IDsCaptureDriverNotifyImpl *impl_from_IDsDriverNotify(IDsDriverNotify *iface)
148 return CONTAINING_RECORD(iface, IDsCaptureDriverNotifyImpl, IDsDriverNotify_iface);
151 static inline IDsCaptureDriverImpl *impl_from_IDsCaptureDriver(IDsCaptureDriver *iface)
153 return CONTAINING_RECORD(iface, IDsCaptureDriverImpl, IDsCaptureDriver_iface);
156 static inline IDsCaptureDriverBufferImpl *impl_from_IDsCaptureDriverBuffer(IDsCaptureDriverBuffer *iface)
158 return CONTAINING_RECORD(iface, IDsCaptureDriverBufferImpl, IDsCaptureDriverBuffer_iface);
161 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
162 IDsCaptureDriverBufferImpl * dscdb,
163 IDsCaptureDriverPropertySetImpl **pdscdps);
165 static HRESULT IDsCaptureDriverNotifyImpl_Create(
166 IDsCaptureDriverBufferImpl * dsdcb,
167 IDsCaptureDriverNotifyImpl **pdscdn);
169 /*======================================================================*
170 * Low level DSOUND capture property set implementation *
171 *======================================================================*/
173 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
174 PIDSDRIVERPROPERTYSET iface,
175 REFIID riid,
176 LPVOID *ppobj)
178 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
179 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
181 if ( IsEqualGUID(riid, &IID_IUnknown) ||
182 IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
183 IDsDriverPropertySet_AddRef(iface);
184 *ppobj = This;
185 return DS_OK;
188 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
190 *ppobj = 0;
191 return E_NOINTERFACE;
194 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
195 PIDSDRIVERPROPERTYSET iface)
197 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
198 ULONG refCount = InterlockedIncrement(&This->ref);
200 TRACE("(%p) ref was %d\n", This, refCount - 1);
202 return refCount;
205 static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
206 PIDSDRIVERPROPERTYSET iface)
208 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
209 ULONG refCount = InterlockedDecrement(&This->ref);
211 TRACE("(%p) ref was %d\n", This, refCount + 1);
213 if (!refCount) {
214 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
215 This->capture_buffer->property_set = NULL;
216 HeapFree(GetProcessHeap(),0,This);
217 TRACE("(%p) released\n",This);
219 return refCount;
222 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
223 PIDSDRIVERPROPERTYSET iface,
224 PDSPROPERTY pDsProperty,
225 LPVOID pPropertyParams,
226 ULONG cbPropertyParams,
227 LPVOID pPropertyData,
228 ULONG cbPropertyData,
229 PULONG pcbReturnedData )
231 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
232 FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This,pDsProperty,pPropertyParams,
233 cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
234 return DSERR_UNSUPPORTED;
237 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
238 PIDSDRIVERPROPERTYSET iface,
239 PDSPROPERTY pDsProperty,
240 LPVOID pPropertyParams,
241 ULONG cbPropertyParams,
242 LPVOID pPropertyData,
243 ULONG cbPropertyData )
245 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
246 FIXME("(%p,%p,%p,%x,%p,%x)\n",This,pDsProperty,pPropertyParams,
247 cbPropertyParams,pPropertyData,cbPropertyData);
248 return DSERR_UNSUPPORTED;
251 static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
252 PIDSDRIVERPROPERTYSET iface,
253 REFGUID PropertySetId,
254 ULONG PropertyId,
255 PULONG pSupport )
257 IDsCaptureDriverPropertySetImpl *This = impl_from_IDsDriverPropertySet(iface);
258 FIXME("(%p,%s,%x,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
259 pSupport);
260 return DSERR_UNSUPPORTED;
263 static const IDsDriverPropertySetVtbl dscdpsvt =
265 IDsCaptureDriverPropertySetImpl_QueryInterface,
266 IDsCaptureDriverPropertySetImpl_AddRef,
267 IDsCaptureDriverPropertySetImpl_Release,
268 IDsCaptureDriverPropertySetImpl_Get,
269 IDsCaptureDriverPropertySetImpl_Set,
270 IDsCaptureDriverPropertySetImpl_QuerySupport,
273 /*======================================================================*
274 * Low level DSOUND capture notify implementation *
275 *======================================================================*/
277 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
278 PIDSDRIVERNOTIFY iface,
279 REFIID riid,
280 LPVOID *ppobj)
282 IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
283 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
285 if ( IsEqualGUID(riid, &IID_IUnknown) ||
286 IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
287 IDsDriverNotify_AddRef(iface);
288 *ppobj = This;
289 return DS_OK;
292 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
294 *ppobj = 0;
295 return E_NOINTERFACE;
298 static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
299 PIDSDRIVERNOTIFY iface)
301 IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
302 ULONG refCount = InterlockedIncrement(&This->ref);
304 TRACE("(%p) ref was %d\n", This, refCount - 1);
306 return refCount;
309 static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
310 PIDSDRIVERNOTIFY iface)
312 IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
313 ULONG refCount = InterlockedDecrement(&This->ref);
315 TRACE("(%p) ref was %d\n", This, refCount + 1);
317 if (!refCount) {
318 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
319 This->capture_buffer->notify = NULL;
320 HeapFree(GetProcessHeap(),0,This);
321 TRACE("(%p) released\n",This);
323 return refCount;
326 static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
327 PIDSDRIVERNOTIFY iface,
328 DWORD howmuch,
329 LPCDSBPOSITIONNOTIFY notify)
331 IDsCaptureDriverNotifyImpl *This = impl_from_IDsDriverNotify(iface);
332 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
334 if (!notify) {
335 WARN("invalid parameter\n");
336 return DSERR_INVALIDPARAM;
339 if (TRACE_ON(dscapture)) {
340 DWORD i;
341 for (i=0;i<howmuch;i++)
342 TRACE("notify at %d to 0x%08lx\n",
343 notify[i].dwOffset,(DWORD_PTR)notify[i].hEventNotify);
346 /* Make an internal copy of the caller-supplied array.
347 * Replace the existing copy if one is already present. */
348 if (This->capture_buffer->notifies)
349 This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
350 HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
351 howmuch * sizeof(DSBPOSITIONNOTIFY));
352 else
353 This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
354 HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
356 memcpy(This->capture_buffer->notifies, notify,
357 howmuch * sizeof(DSBPOSITIONNOTIFY));
358 This->capture_buffer->nrofnotifies = howmuch;
360 return S_OK;
363 static const IDsDriverNotifyVtbl dscdnvt =
365 IDsCaptureDriverNotifyImpl_QueryInterface,
366 IDsCaptureDriverNotifyImpl_AddRef,
367 IDsCaptureDriverNotifyImpl_Release,
368 IDsCaptureDriverNotifyImpl_SetNotificationPositions,
371 /*======================================================================*
372 * Low level DSOUND capture implementation *
373 *======================================================================*/
375 static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
377 if (!dscdb->mapping) {
378 dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
379 WInDev[dscdb->drv->wDevID].ossdev.fd, 0);
380 if (dscdb->mapping == (LPBYTE)-1) {
381 TRACE("(%p): Could not map sound device for direct access (%s)\n",
382 dscdb, strerror(errno));
383 return DSERR_GENERIC;
385 TRACE("(%p): sound device has been mapped for direct access at %p, "
386 "size=%d\n", dscdb, dscdb->mapping, dscdb->maplen);
388 return DS_OK;
391 static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
393 if (dscdb->mapping) {
394 if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
395 ERR("(%p): Could not unmap sound device (%s)\n",
396 dscdb, strerror(errno));
397 return DSERR_GENERIC;
399 dscdb->mapping = NULL;
400 TRACE("(%p): sound device unmapped\n", dscdb);
402 return DS_OK;
405 static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
406 PIDSCDRIVERBUFFER iface,
407 REFIID riid,
408 LPVOID *ppobj)
410 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
411 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
413 *ppobj = 0;
415 if ( IsEqualGUID(riid, &IID_IUnknown) ||
416 IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
417 IDsCaptureDriverBuffer_AddRef(iface);
418 *ppobj = This;
419 return DS_OK;
422 if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
423 if (!This->notify)
424 IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
425 if (This->notify) {
426 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
427 *ppobj = This->notify;
428 return DS_OK;
430 return E_FAIL;
433 if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
434 if (!This->property_set)
435 IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
436 if (This->property_set) {
437 IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
438 *ppobj = This->property_set;
439 return DS_OK;
441 return E_FAIL;
444 FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
445 return DSERR_UNSUPPORTED;
448 static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
450 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
451 ULONG refCount = InterlockedIncrement(&This->ref);
453 TRACE("(%p) ref was %d\n", This, refCount - 1);
455 return refCount;
458 static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
460 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
461 ULONG refCount = InterlockedDecrement(&This->ref);
462 TRACE("(%p) ref was %d\n", This, refCount + 1);
464 if (!refCount) {
465 WINE_WAVEIN* wwi;
467 wwi = &WInDev[This->drv->wDevID];
469 if (This->hThread) {
470 int x = 0;
472 /* request thread termination */
473 write(This->pipe_fd[1], &x, sizeof(x));
475 /* wait for reply */
476 WaitForSingleObject(This->hExitEvent, INFINITE);
477 CloseHandle(This->hExitEvent);
480 close(This->pipe_fd[0]);
481 close(This->pipe_fd[1]);
483 DSCDB_UnmapBuffer(This);
485 OSS_CloseDevice(&wwi->ossdev);
486 wwi->state = WINE_WS_CLOSED;
487 wwi->dwFragmentSize = 0;
488 This->drv->capture_buffer = NULL;
490 HeapFree(GetProcessHeap(), 0, This->notifies);
491 HeapFree(GetProcessHeap(),0,This);
492 TRACE("(%p) released\n",This);
494 return refCount;
497 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
498 PIDSCDRIVERBUFFER iface,
499 LPVOID* ppvAudio1,
500 LPDWORD pdwLen1,
501 LPVOID* ppvAudio2,
502 LPDWORD pdwLen2,
503 DWORD dwWritePosition,
504 DWORD dwWriteLen,
505 DWORD dwFlags)
507 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
508 TRACE("(%p,%p,%p,%p,%p,%d,%d,0x%08x)\n",This,ppvAudio1,pdwLen1,
509 ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
511 if (This->is_direct_map) {
512 if (ppvAudio1)
513 *ppvAudio1 = This->mapping + dwWritePosition;
515 if (dwWritePosition + dwWriteLen < This->maplen) {
516 if (pdwLen1)
517 *pdwLen1 = dwWriteLen;
518 if (ppvAudio2)
519 *ppvAudio2 = 0;
520 if (pdwLen2)
521 *pdwLen2 = 0;
522 } else {
523 if (pdwLen1)
524 *pdwLen1 = This->maplen - dwWritePosition;
525 if (ppvAudio2)
526 *ppvAudio2 = 0;
527 if (pdwLen2)
528 *pdwLen2 = dwWriteLen - (This->maplen - dwWritePosition);
530 } else {
531 if (ppvAudio1)
532 *ppvAudio1 = This->buffer + dwWritePosition;
534 if (dwWritePosition + dwWriteLen < This->buflen) {
535 if (pdwLen1)
536 *pdwLen1 = dwWriteLen;
537 if (ppvAudio2)
538 *ppvAudio2 = 0;
539 if (pdwLen2)
540 *pdwLen2 = 0;
541 } else {
542 if (pdwLen1)
543 *pdwLen1 = This->buflen - dwWritePosition;
544 if (ppvAudio2)
545 *ppvAudio2 = 0;
546 if (pdwLen2)
547 *pdwLen2 = dwWriteLen - (This->buflen - dwWritePosition);
551 return DS_OK;
554 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
555 PIDSCDRIVERBUFFER iface,
556 LPVOID pvAudio1,
557 DWORD dwLen1,
558 LPVOID pvAudio2,
559 DWORD dwLen2)
561 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
562 TRACE("(%p,%p,%d,%p,%d)\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
564 if (This->is_direct_map)
565 This->map_readpos = (This->map_readpos + dwLen1 + dwLen2) % This->maplen;
566 else
567 This->readptr = (This->readptr + dwLen1 + dwLen2) % This->buflen;
569 return DS_OK;
572 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
573 PIDSCDRIVERBUFFER iface,
574 LPDWORD lpdwCapture,
575 LPDWORD lpdwRead)
577 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
578 TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
580 if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
581 ERR("device not open, but accessing?\n");
582 return DSERR_UNINITIALIZED;
585 if (!This->is_capturing) {
586 if (lpdwCapture)
587 *lpdwCapture = 0;
588 if (lpdwRead)
589 *lpdwRead = 0;
592 if (This->is_direct_map) {
593 if (lpdwCapture)
594 *lpdwCapture = This->map_writepos;
595 if (lpdwRead) {
596 *lpdwRead = This->map_readpos;
598 } else {
599 if (lpdwCapture)
600 *lpdwCapture = This->writeptr;
601 if (lpdwRead)
602 *lpdwRead = This->readptr;
605 TRACE("capturepos=%d, readpos=%d\n", lpdwCapture?*lpdwCapture:0,
606 lpdwRead?*lpdwRead:0);
607 return DS_OK;
610 static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
611 PIDSCDRIVERBUFFER iface,
612 LPDWORD lpdwStatus)
614 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
615 TRACE("(%p,%p)\n",This,lpdwStatus);
617 if (This->is_capturing) {
618 if (This->is_looping)
619 *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
620 else
621 *lpdwStatus = DSCBSTATUS_CAPTURING;
622 } else
623 *lpdwStatus = 0;
625 return DS_OK;
628 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
629 PIDSCDRIVERBUFFER iface,
630 DWORD dwFlags)
632 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
633 int enable;
634 TRACE("(%p,%x)\n",This,dwFlags);
636 if (This->is_capturing)
637 return DS_OK;
639 if (dwFlags & DSCBSTART_LOOPING)
640 This->is_looping = TRUE;
642 WInDev[This->drv->wDevID].ossdev.bInputEnabled = TRUE;
643 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
644 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
645 if (errno == EINVAL) {
646 /* Don't give up yet. OSS trigger support is inconsistent. */
647 if (WInDev[This->drv->wDevID].ossdev.open_count == 1) {
648 /* try the opposite output enable */
649 if (WInDev[This->drv->wDevID].ossdev.bOutputEnabled == FALSE)
650 WInDev[This->drv->wDevID].ossdev.bOutputEnabled = TRUE;
651 else
652 WInDev[This->drv->wDevID].ossdev.bOutputEnabled = FALSE;
653 /* try it again */
654 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
655 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
656 This->is_capturing = TRUE;
657 return DS_OK;
661 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
662 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
663 WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
664 return DSERR_GENERIC;
667 This->is_capturing = TRUE;
668 return DS_OK;
671 static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
673 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
674 int enable;
675 TRACE("(%p)\n",This);
677 if (!This->is_capturing)
678 return DS_OK;
680 /* no more capturing */
681 WInDev[This->drv->wDevID].ossdev.bInputEnabled = FALSE;
682 enable = getEnables(&WInDev[This->drv->wDevID].ossdev);
683 if (ioctl(WInDev[This->drv->wDevID].ossdev.fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
684 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
685 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
686 return DSERR_GENERIC;
689 /* send a final event if necessary */
690 if (This->nrofnotifies > 0) {
691 if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
692 SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
695 This->is_capturing = FALSE;
696 This->is_looping = FALSE;
698 if (This->hThread) {
699 int x = 0;
700 write(This->pipe_fd[1], &x, sizeof(x));
701 WaitForSingleObject(This->hExitEvent, INFINITE);
702 CloseHandle(This->hExitEvent);
703 This->hExitEvent = INVALID_HANDLE_VALUE;
704 This->hThread = 0;
707 return DS_OK;
710 static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
711 PIDSCDRIVERBUFFER iface,
712 LPWAVEFORMATEX pwfx)
714 IDsCaptureDriverBufferImpl *This = impl_from_IDsCaptureDriverBuffer(iface);
715 FIXME("(%p): stub!\n",This);
716 return DSERR_UNSUPPORTED;
719 static const IDsCaptureDriverBufferVtbl dscdbvt =
721 IDsCaptureDriverBufferImpl_QueryInterface,
722 IDsCaptureDriverBufferImpl_AddRef,
723 IDsCaptureDriverBufferImpl_Release,
724 IDsCaptureDriverBufferImpl_Lock,
725 IDsCaptureDriverBufferImpl_Unlock,
726 IDsCaptureDriverBufferImpl_SetFormat,
727 IDsCaptureDriverBufferImpl_GetPosition,
728 IDsCaptureDriverBufferImpl_GetStatus,
729 IDsCaptureDriverBufferImpl_Start,
730 IDsCaptureDriverBufferImpl_Stop
733 static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
734 PIDSCDRIVER iface,
735 REFIID riid,
736 LPVOID *ppobj)
738 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
739 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
741 if ( IsEqualGUID(riid, &IID_IUnknown) ||
742 IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
743 IDsCaptureDriver_AddRef(iface);
744 *ppobj = This;
745 return DS_OK;
748 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
750 *ppobj = 0;
752 return E_NOINTERFACE;
755 static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
757 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
758 ULONG refCount = InterlockedIncrement(&This->ref);
760 TRACE("(%p) ref was %d\n", This, refCount - 1);
762 return refCount;
765 static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
767 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
768 ULONG refCount = InterlockedDecrement(&This->ref);
770 TRACE("(%p) ref was %d\n", This, refCount + 1);
772 if (!refCount) {
773 HeapFree(GetProcessHeap(),0,This);
774 TRACE("(%p) released\n",This);
776 return refCount;
779 static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
780 PIDSCDRIVER iface,
781 PDSDRIVERDESC pDesc)
783 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
784 TRACE("(%p,%p)\n",This,pDesc);
786 if (!pDesc) {
787 TRACE("invalid parameter\n");
788 return DSERR_INVALIDPARAM;
791 /* copy version from driver */
792 *pDesc = WInDev[This->wDevID].ossdev.ds_desc;
794 pDesc->dnDevNode = WInDev[This->wDevID].waveDesc.dnDevNode;
795 pDesc->wVxdId = 0;
796 pDesc->wReserved = 0;
797 pDesc->ulDeviceNum = This->wDevID;
798 pDesc->dwHeapType = DSDHEAP_NOHEAP;
799 pDesc->pvDirectDrawHeap = NULL;
800 pDesc->dwMemStartAddress = 0;
801 pDesc->dwMemEndAddress = 0;
802 pDesc->dwMemAllocExtra = 0;
803 pDesc->pvReserved1 = NULL;
804 pDesc->pvReserved2 = NULL;
805 return DS_OK;
808 static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
810 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
811 TRACE("(%p)\n",This);
812 return DS_OK;
815 static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
817 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
818 TRACE("(%p)\n",This);
819 if (This->capture_buffer) {
820 ERR("problem with DirectSound: capture buffer not released\n");
821 return DSERR_GENERIC;
823 return DS_OK;
826 static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
827 PIDSCDRIVER iface,
828 PDSCDRIVERCAPS pCaps)
830 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
831 TRACE("(%p,%p)\n",This,pCaps);
832 *pCaps = WInDev[This->wDevID].ossdev.dsc_caps;
833 return DS_OK;
836 static void DSCDB_CheckEvent(
837 IDsCaptureDriverBufferImpl *dscb,
838 DWORD writepos,
839 DWORD len,
840 DWORD buflen)
842 LPDSBPOSITIONNOTIFY event = dscb->notifies + dscb->notify_index;
843 DWORD offset = event->dwOffset;
844 TRACE("(%p,%d,%d,%d)\n", dscb, writepos, len, buflen);
846 TRACE("(%p) buflen = %d, writeptr = %d\n",
847 dscb, dscb->buflen, dscb->writeptr);
848 TRACE("checking %d, position %d, event = %p\n",
849 dscb->notify_index, offset, event->hEventNotify);
851 if ((writepos + len) > offset) {
852 TRACE("signalled event %p (%d) %d\n",
853 event->hEventNotify, dscb->notify_index, offset);
854 SetEvent(event->hEventNotify);
855 dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
856 return;
857 } else if ((writepos + len) > buflen) {
858 writepos = writepos + len - buflen;
859 if ((writepos + len) > offset) {
860 TRACE("signalled event %p (%d) %d\n",
861 event->hEventNotify, dscb->notify_index, offset);
862 SetEvent(event->hEventNotify);
863 dscb->notify_index = (dscb->notify_index + 1) % dscb->nrofnotifies;
864 return;
868 return;
871 /* FIXME: using memcpy can cause strange crashes so use this fake one */
872 static void * my_memcpy(void * dst, const void * src, int length)
874 int i;
875 for (i = 0; i < length; i++)
876 ((char *)dst)[i] = ((const char *)src)[i];
877 return dst;
880 static DWORD CALLBACK DSCDB_Thread(LPVOID lpParameter)
882 IDsCaptureDriverBufferImpl *This = lpParameter;
883 struct pollfd poll_list[2];
884 int retval;
885 DWORD offset = 0;
886 DWORD map_offset = 0;
887 TRACE("(%p)\n", lpParameter);
889 poll_list[0].fd = This->fd; /* data available */
890 poll_list[1].fd = This->pipe_fd[0]; /* message from parent process */
891 poll_list[0].events = POLLIN;
892 poll_list[1].events = POLLIN;
894 /* let other process know we are running */
895 SetEvent(This->hStartUpEvent);
897 while (1) {
898 /* wait for something to happen */
899 retval = poll(poll_list,(unsigned long)2,-1);
900 /* Retval will always be greater than 0 or -1 in this case.
901 * Since we're doing it while blocking
903 if (retval < 0) {
904 ERR("Error while polling: %s\n",strerror(errno));
905 continue;
908 /* check for exit command */
909 if ((poll_list[1].revents & POLLIN) == POLLIN) {
910 TRACE("(%p) done\n", lpParameter);
911 /* acknowledge command and exit */
912 SetEvent(This->hExitEvent);
913 ExitThread(0);
914 return 0;
917 /* check for data */
918 if ((poll_list[0].revents & POLLIN) == POLLIN) {
919 count_info info;
920 int fragsize, first, second;
922 /* get the current DMA position */
923 if (ioctl(This->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
924 ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
925 WInDev[This->drv->wDevID].ossdev.dev_name, strerror(errno));
926 return DSERR_GENERIC;
929 if (This->is_direct_map) {
930 offset = This->map_writepos;
931 This->map_writepos = info.ptr;
933 if (info.ptr < offset)
934 fragsize = info.ptr + This->maplen - offset;
935 else
936 fragsize = info.ptr - offset;
938 DSCDB_CheckEvent(This, offset, fragsize, This->maplen);
939 } else {
940 map_offset = This->map_writepos;
941 offset = This->writeptr;
943 /* test for mmap buffer wrap */
944 if (info.ptr < map_offset) {
945 /* mmap buffer wrapped */
946 fragsize = info.ptr + This->maplen - map_offset;
948 /* check for user buffer wrap */
949 if ((offset + fragsize) > This->buflen) {
950 /* both buffers wrapped
951 * figure out which wrapped first
953 if ((This->maplen - map_offset) > (This->buflen - offset)) {
954 /* user buffer wrapped first */
955 first = This->buflen - offset;
956 second = (This->maplen - map_offset) - first;
957 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
958 my_memcpy(This->buffer, This->mapping + map_offset + first, second);
959 my_memcpy(This->buffer + second, This->mapping, fragsize - (first + second));
960 } else {
961 /* mmap buffer wrapped first */
962 first = This->maplen - map_offset;
963 second = (This->buflen - offset) - first;
964 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
965 my_memcpy(This->buffer + offset + first, This->mapping, second);
966 my_memcpy(This->buffer, This->mapping + second, fragsize - (first + second));
968 } else {
969 /* only mmap buffer wrapped */
970 first = This->maplen - map_offset;
971 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
972 my_memcpy(This->buffer + offset + first, This->mapping, fragsize - first);
974 } else {
975 /* mmap buffer didn't wrap */
976 fragsize = info.ptr - map_offset;
978 /* check for user buffer wrap */
979 if ((offset + fragsize) > This->buflen) {
980 first = This->buflen - offset;
981 my_memcpy(This->buffer + offset, This->mapping + map_offset, first);
982 my_memcpy(This->buffer, This->mapping + map_offset + first, fragsize - first);
983 } else
984 my_memcpy(This->buffer + offset, This->mapping + map_offset, fragsize);
987 This->map_writepos = info.ptr;
988 This->writeptr = (This->writeptr + fragsize) % This->buflen;
989 DSCDB_CheckEvent(This, offset, fragsize, This->buflen);
995 static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
996 PIDSCDRIVER iface,
997 LPWAVEFORMATEX pwfx,
998 DWORD dwFlags,
999 DWORD dwCardAddress,
1000 LPDWORD pdwcbBufferSize,
1001 LPBYTE *ppbBuffer,
1002 LPVOID *ppvObj)
1004 IDsCaptureDriverImpl *This = impl_from_IDsCaptureDriver(iface);
1005 IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
1006 HRESULT err;
1007 audio_buf_info info;
1008 int audio_fragment, fsize, shift, ret;
1009 BOOL bNewBuffer = FALSE;
1010 WINE_WAVEIN* wwi;
1011 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
1012 pdwcbBufferSize,ppbBuffer,ppvObj);
1014 if (This->capture_buffer) {
1015 TRACE("already allocated\n");
1016 return DSERR_ALLOCATED;
1019 /* must be given a buffer size */
1020 if (pdwcbBufferSize == NULL || *pdwcbBufferSize == 0) {
1021 TRACE("invalid parameter: pdwcbBufferSize\n");
1022 return DSERR_INVALIDPARAM;
1025 /* must be given a buffer pointer */
1026 if (ppbBuffer == NULL) {
1027 TRACE("invalid parameter: ppbBuffer\n");
1028 return DSERR_INVALIDPARAM;
1031 /* may or may not be given a buffer */
1032 if (*ppbBuffer == NULL) {
1033 TRACE("creating buffer\n");
1034 bNewBuffer = TRUE; /* not given a buffer so create one */
1035 } else
1036 TRACE("using supplied buffer\n");
1038 *ippdscdb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
1039 if (*ippdscdb == NULL) {
1040 TRACE("out of memory\n");
1041 return DSERR_OUTOFMEMORY;
1044 (*ippdscdb)->IDsCaptureDriverBuffer_iface.lpVtbl = &dscdbvt;
1045 (*ippdscdb)->ref = 1;
1046 (*ippdscdb)->drv = This;
1047 (*ippdscdb)->notify = NULL;
1048 (*ippdscdb)->notify_index = 0;
1049 (*ippdscdb)->notifies = NULL;
1050 (*ippdscdb)->nrofnotifies = 0;
1051 (*ippdscdb)->property_set = NULL;
1052 (*ippdscdb)->is_capturing = FALSE;
1053 (*ippdscdb)->is_looping = FALSE;
1054 (*ippdscdb)->wfx = *pwfx;
1055 (*ippdscdb)->buflen = *pdwcbBufferSize;
1057 if (bNewBuffer)
1058 (*ippdscdb)->buffer = NULL;
1059 else
1060 (*ippdscdb)->buffer = *ppbBuffer;
1062 wwi = &WInDev[This->wDevID];
1064 if (wwi->state == WINE_WS_CLOSED) {
1065 unsigned int frag_size;
1067 if (wwi->ossdev.open_count > 0) {
1068 /* opened already so use existing fragment size */
1069 audio_fragment = wwi->ossdev.audio_fragment;
1070 } else {
1071 /* calculate a fragment size */
1072 unsigned int mask = 0xffffffff;
1074 /* calculate largest fragment size less than 10 ms. */
1075 fsize = pwfx->nAvgBytesPerSec / 100; /* 10 ms chunk */
1076 shift = 0;
1077 while ((1 << shift) <= fsize)
1078 shift++;
1079 shift--;
1080 fsize = 1 << shift;
1081 TRACE("shift = %d, fragment size = %d\n", shift, fsize);
1082 TRACE("BufferSize=%d(%08x)\n", *pdwcbBufferSize, *pdwcbBufferSize);
1084 /* See if we can directly map the buffer first.
1085 * (buffer length is multiple of a power of 2)
1087 mask = (mask >> (32 - shift));
1088 TRACE("mask=%08x\n", mask);
1089 if (*pdwcbBufferSize & mask) {
1090 /* no so try a smaller fragment size greater than 1 ms */
1091 int new_shift = shift - 1;
1092 int min_shift = 0;
1093 int min_fsize = pwfx->nAvgBytesPerSec / 1000;
1094 BOOL found_one = FALSE;
1095 while ((1 << min_shift) <= min_fsize)
1096 min_shift++;
1097 min_shift--;
1098 while (new_shift > min_shift) {
1099 if (*pdwcbBufferSize & (-1 >> (32 - new_shift))) {
1100 new_shift--;
1101 continue;
1102 } else {
1103 found_one = TRUE;
1104 break;
1107 if (found_one) {
1108 /* found a smaller one that will work */
1109 audio_fragment = ((*pdwcbBufferSize >> new_shift) << 16) | new_shift;
1110 (*ippdscdb)->is_direct_map = TRUE;
1111 TRACE("new shift = %d, fragment size = %d\n",
1112 new_shift, 1 << (audio_fragment & 0xffff));
1113 } else {
1114 /* buffer can't be direct mapped */
1115 audio_fragment = 0x00100000 + shift; /* 16 fragments of 2^shift */
1116 (*ippdscdb)->is_direct_map = FALSE;
1118 } else {
1119 /* good fragment size */
1120 audio_fragment = ((*pdwcbBufferSize >> shift) << 16) | shift;
1121 (*ippdscdb)->is_direct_map = TRUE;
1124 frag_size = 1 << (audio_fragment & 0xffff);
1125 TRACE("is_direct_map = %s\n", (*ippdscdb)->is_direct_map ? "TRUE" : "FALSE");
1126 TRACE("requesting %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1127 audio_fragment >> 16, frag_size, frag_size * (audio_fragment >> 16),
1128 (frag_size * 1000) / pwfx->nAvgBytesPerSec);
1130 ret = OSS_OpenDevice(&wwi->ossdev, O_RDWR, &audio_fragment, 1,
1131 pwfx->nSamplesPerSec,
1132 (pwfx->nChannels > 1) ? 1 : 0,
1133 (pwfx->wBitsPerSample == 16)
1134 ? AFMT_S16_LE : AFMT_U8);
1136 if (ret != 0) {
1137 WARN("OSS_OpenDevice failed\n");
1138 HeapFree(GetProcessHeap(),0,*ippdscdb);
1139 *ippdscdb = NULL;
1140 return DSERR_GENERIC;
1143 wwi->state = WINE_WS_STOPPED;
1145 /* find out what fragment and buffer sizes OSS gave us */
1146 if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1147 ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1148 wwi->ossdev.dev_name, strerror(errno));
1149 OSS_CloseDevice(&wwi->ossdev);
1150 wwi->state = WINE_WS_CLOSED;
1151 HeapFree(GetProcessHeap(),0,*ippdscdb);
1152 *ippdscdb = NULL;
1153 return DSERR_GENERIC;
1156 TRACE("got %d %d byte fragments (%d bytes) (%d ms/fragment)\n",
1157 info.fragstotal, info.fragsize, info.fragstotal * info.fragsize,
1158 info.fragsize * 1000 / pwfx->nAvgBytesPerSec);
1160 wwi->dwTotalRecorded = 0;
1161 memcpy(&wwi->waveFormat, pwfx, sizeof(PCMWAVEFORMAT));
1162 wwi->dwFragmentSize = info.fragsize;
1164 /* make sure we got what we asked for */
1165 if ((*ippdscdb)->buflen != info.fragstotal * info.fragsize) {
1166 TRACE("Couldn't create requested buffer\n");
1167 if ((*ippdscdb)->is_direct_map) {
1168 (*ippdscdb)->is_direct_map = FALSE;
1169 TRACE("is_direct_map = FALSE\n");
1171 } else if (info.fragsize != frag_size) {
1172 TRACE("same buffer length but different fragment size\n");
1175 (*ippdscdb)->fd = WInDev[This->wDevID].ossdev.fd;
1177 if (pipe((*ippdscdb)->pipe_fd) < 0) {
1178 TRACE("pipe() failed (%s)\n", strerror(errno));
1179 OSS_CloseDevice(&wwi->ossdev);
1180 wwi->state = WINE_WS_CLOSED;
1181 HeapFree(GetProcessHeap(),0,*ippdscdb);
1182 *ippdscdb = NULL;
1183 return DSERR_GENERIC;
1186 /* check how big the DMA buffer is now */
1187 if (ioctl(wwi->ossdev.fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1188 ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
1189 wwi->ossdev.dev_name, strerror(errno));
1190 OSS_CloseDevice(&wwi->ossdev);
1191 wwi->state = WINE_WS_CLOSED;
1192 close((*ippdscdb)->pipe_fd[0]);
1193 close((*ippdscdb)->pipe_fd[1]);
1194 HeapFree(GetProcessHeap(),0,*ippdscdb);
1195 *ippdscdb = NULL;
1196 return DSERR_GENERIC;
1199 (*ippdscdb)->maplen = info.fragstotal * info.fragsize;
1200 (*ippdscdb)->fragsize = info.fragsize;
1201 (*ippdscdb)->map_writepos = 0;
1202 (*ippdscdb)->map_readpos = 0;
1204 /* map the DMA buffer */
1205 err = DSCDB_MapBuffer(*ippdscdb);
1206 if (err != DS_OK) {
1207 OSS_CloseDevice(&wwi->ossdev);
1208 wwi->state = WINE_WS_CLOSED;
1209 close((*ippdscdb)->pipe_fd[0]);
1210 close((*ippdscdb)->pipe_fd[1]);
1211 HeapFree(GetProcessHeap(),0,*ippdscdb);
1212 *ippdscdb = NULL;
1213 return err;
1216 /* create the buffer if necessary */
1217 if (!(*ippdscdb)->buffer)
1218 (*ippdscdb)->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(*ippdscdb)->buflen);
1220 if ((*ippdscdb)->buffer == NULL) {
1221 OSS_CloseDevice(&wwi->ossdev);
1222 wwi->state = WINE_WS_CLOSED;
1223 close((*ippdscdb)->pipe_fd[0]);
1224 close((*ippdscdb)->pipe_fd[1]);
1225 HeapFree(GetProcessHeap(),0,*ippdscdb);
1226 *ippdscdb = NULL;
1227 return DSERR_OUTOFMEMORY;
1230 This->capture_buffer = *ippdscdb;
1232 (*ippdscdb)->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1233 (*ippdscdb)->hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1235 (*ippdscdb)->hThread = CreateThread(NULL, 0, DSCDB_Thread, *ippdscdb, 0, &((*ippdscdb)->dwThreadID));
1236 WaitForSingleObject((*ippdscdb)->hStartUpEvent, INFINITE);
1237 CloseHandle((*ippdscdb)->hStartUpEvent);
1238 (*ippdscdb)->hStartUpEvent = INVALID_HANDLE_VALUE;
1240 return DS_OK;
1243 static const IDsCaptureDriverVtbl dscdvt =
1245 IDsCaptureDriverImpl_QueryInterface,
1246 IDsCaptureDriverImpl_AddRef,
1247 IDsCaptureDriverImpl_Release,
1248 IDsCaptureDriverImpl_GetDriverDesc,
1249 IDsCaptureDriverImpl_Open,
1250 IDsCaptureDriverImpl_Close,
1251 IDsCaptureDriverImpl_GetCaps,
1252 IDsCaptureDriverImpl_CreateCaptureBuffer
1255 static HRESULT IDsCaptureDriverPropertySetImpl_Create(
1256 IDsCaptureDriverBufferImpl * dscdb,
1257 IDsCaptureDriverPropertySetImpl **pdscdps)
1259 IDsCaptureDriverPropertySetImpl * dscdps;
1260 TRACE("(%p,%p)\n",dscdb,pdscdps);
1262 dscdps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdps));
1263 if (dscdps == NULL) {
1264 WARN("out of memory\n");
1265 return DSERR_OUTOFMEMORY;
1268 dscdps->ref = 0;
1269 dscdps->IDsDriverPropertySet_iface.lpVtbl = &dscdpsvt;
1270 dscdps->capture_buffer = dscdb;
1271 dscdb->property_set = dscdps;
1272 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1274 *pdscdps = dscdps;
1275 return DS_OK;
1278 static HRESULT IDsCaptureDriverNotifyImpl_Create(
1279 IDsCaptureDriverBufferImpl * dscdb,
1280 IDsCaptureDriverNotifyImpl **pdscdn)
1282 IDsCaptureDriverNotifyImpl * dscdn;
1283 TRACE("(%p,%p)\n",dscdb,pdscdn);
1285 dscdn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscdn));
1286 if (dscdn == NULL) {
1287 WARN("out of memory\n");
1288 return DSERR_OUTOFMEMORY;
1291 dscdn->ref = 0;
1292 dscdn->IDsDriverNotify_iface.lpVtbl = &dscdnvt;
1293 dscdn->capture_buffer = dscdb;
1294 dscdb->notify = dscdn;
1295 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
1297 *pdscdn = dscdn;
1298 return DS_OK;
1301 DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
1303 IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
1304 TRACE("(%d,%p)\n",wDevID,drv);
1306 /* the HAL isn't much better than the HEL if we can't do mmap() */
1307 if (!(WInDev[wDevID].ossdev.in_caps_support & WAVECAPS_DIRECTSOUND)) {
1308 ERR("DirectSoundCapture flag not set\n");
1309 MESSAGE("This sound card's driver does not support direct access\n");
1310 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1311 return MMSYSERR_NOTSUPPORTED;
1314 *idrv = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
1315 if (!*idrv)
1316 return MMSYSERR_NOMEM;
1317 (*idrv)->IDsCaptureDriver_iface.lpVtbl = &dscdvt;
1318 (*idrv)->ref = 1;
1320 (*idrv)->wDevID = wDevID;
1321 (*idrv)->capture_buffer = NULL;
1322 return MMSYSERR_NOERROR;
1325 DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1327 memcpy(desc, &(WInDev[wDevID].ossdev.ds_desc), sizeof(DSDRIVERDESC));
1328 return MMSYSERR_NOERROR;
1331 #endif /* HAVE_OSS */