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