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
22 #include "wine/port.h"
33 #ifdef HAVE_SYS_IOCTL_H
34 # include <sys/ioctl.h>
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
42 #ifdef HAVE_SYS_POLL_H
43 # include <sys/poll.h>
56 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(dscapture
);
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
76 IDsDriverPropertySet IDsDriverPropertySet_iface
;
79 IDsCaptureDriverBufferImpl
* capture_buffer
;
82 struct IDsCaptureDriverNotifyImpl
85 IDsDriverNotify IDsDriverNotify_iface
;
88 IDsCaptureDriverBufferImpl
* capture_buffer
;
91 struct IDsCaptureDriverImpl
94 IDsCaptureDriver IDsCaptureDriver_iface
;
97 /* IDsCaptureDriverImpl fields */
99 IDsCaptureDriverBufferImpl
* capture_buffer
;
102 struct IDsCaptureDriverBufferImpl
104 /* IUnknown fields */
105 IDsCaptureDriverBuffer IDsCaptureDriverBuffer_iface
;
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 ? */
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
;
124 LPDSBPOSITIONNOTIFY notifies
;
127 /* IDsDriverPropertySetImpl fields */
128 IDsCaptureDriverPropertySetImpl
* property_set
;
135 HANDLE hStartUpEvent
;
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
,
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
);
188 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
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
);
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
,
257 IDsCaptureDriverPropertySetImpl
*This
= impl_from_IDsDriverPropertySet(iface
);
258 FIXME("(%p,%s,%x,%p)\n",This
,debugstr_guid(PropertySetId
),PropertyId
,
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
,
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
);
292 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
318 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER
)This
->capture_buffer
);
319 This
->capture_buffer
->notify
= NULL
;
320 HeapFree(GetProcessHeap(),0,This
);
321 TRACE("(%p) released\n",This
);
326 static HRESULT WINAPI
IDsCaptureDriverNotifyImpl_SetNotificationPositions(
327 PIDSDRIVERNOTIFY iface
,
329 LPCDSBPOSITIONNOTIFY notify
)
331 IDsCaptureDriverNotifyImpl
*This
= impl_from_IDsDriverNotify(iface
);
332 TRACE("(%p,0x%08x,%p)\n",This
,howmuch
,notify
);
335 WARN("invalid parameter\n");
336 return DSERR_INVALIDPARAM
;
339 if (TRACE_ON(dscapture
)) {
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
));
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
;
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
);
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
);
405 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_QueryInterface(
406 PIDSCDRIVERBUFFER iface
,
410 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
411 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
415 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
416 IsEqualGUID(riid
, &IID_IDsCaptureDriverBuffer
) ) {
417 IDsCaptureDriverBuffer_AddRef(iface
);
422 if ( IsEqualGUID( &IID_IDsDriverNotify
, riid
) ) {
424 IDsCaptureDriverNotifyImpl_Create(This
, &(This
->notify
));
426 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY
)This
->notify
);
427 *ppobj
= This
->notify
;
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
;
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);
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);
467 wwi
= &WInDev
[This
->drv
->wDevID
];
472 /* request thread termination */
473 write(This
->pipe_fd
[1], &x
, sizeof(x
));
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
);
497 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Lock(
498 PIDSCDRIVERBUFFER iface
,
503 DWORD dwWritePosition
,
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
) {
513 *ppvAudio1
= This
->mapping
+ dwWritePosition
;
515 if (dwWritePosition
+ dwWriteLen
< This
->maplen
) {
517 *pdwLen1
= dwWriteLen
;
524 *pdwLen1
= This
->maplen
- dwWritePosition
;
528 *pdwLen2
= dwWriteLen
- (This
->maplen
- dwWritePosition
);
532 *ppvAudio1
= This
->buffer
+ dwWritePosition
;
534 if (dwWritePosition
+ dwWriteLen
< This
->buflen
) {
536 *pdwLen1
= dwWriteLen
;
543 *pdwLen1
= This
->buflen
- dwWritePosition
;
547 *pdwLen2
= dwWriteLen
- (This
->buflen
- dwWritePosition
);
554 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Unlock(
555 PIDSCDRIVERBUFFER iface
,
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
;
567 This
->readptr
= (This
->readptr
+ dwLen1
+ dwLen2
) % This
->buflen
;
572 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_GetPosition(
573 PIDSCDRIVERBUFFER iface
,
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
) {
592 if (This
->is_direct_map
) {
594 *lpdwCapture
= This
->map_writepos
;
596 *lpdwRead
= This
->map_readpos
;
600 *lpdwCapture
= This
->writeptr
;
602 *lpdwRead
= This
->readptr
;
605 TRACE("capturepos=%d, readpos=%d\n", lpdwCapture
?*lpdwCapture
:0,
606 lpdwRead
?*lpdwRead
:0);
610 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_GetStatus(
611 PIDSCDRIVERBUFFER iface
,
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
;
621 *lpdwStatus
= DSCBSTATUS_CAPTURING
;
628 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Start(
629 PIDSCDRIVERBUFFER iface
,
632 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
634 TRACE("(%p,%x)\n",This
,dwFlags
);
636 if (This
->is_capturing
)
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
;
652 WInDev
[This
->drv
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
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
;
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
;
671 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface
)
673 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
675 TRACE("(%p)\n",This
);
677 if (!This
->is_capturing
)
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
;
700 write(This
->pipe_fd
[1], &x
, sizeof(x
));
701 WaitForSingleObject(This
->hExitEvent
, INFINITE
);
702 CloseHandle(This
->hExitEvent
);
703 This
->hExitEvent
= INVALID_HANDLE_VALUE
;
710 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_SetFormat(
711 PIDSCDRIVERBUFFER iface
,
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(
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
);
748 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
773 HeapFree(GetProcessHeap(),0,This
);
774 TRACE("(%p) released\n",This
);
779 static HRESULT WINAPI
IDsCaptureDriverImpl_GetDriverDesc(
783 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
784 TRACE("(%p,%p)\n",This
,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
;
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
;
808 static HRESULT WINAPI
IDsCaptureDriverImpl_Open(PIDSCDRIVER iface
)
810 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
811 TRACE("(%p)\n",This
);
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
;
826 static HRESULT WINAPI
IDsCaptureDriverImpl_GetCaps(
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
;
836 static void DSCDB_CheckEvent(
837 IDsCaptureDriverBufferImpl
*dscb
,
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
;
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
;
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
)
875 for (i
= 0; i
< length
; i
++)
876 ((char *)dst
)[i
] = ((const char *)src
)[i
];
880 static DWORD CALLBACK
DSCDB_Thread(LPVOID lpParameter
)
882 IDsCaptureDriverBufferImpl
*This
= lpParameter
;
883 struct pollfd poll_list
[2];
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
);
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
904 ERR("Error while polling: %s\n",strerror(errno
));
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
);
918 if ((poll_list
[0].revents
& POLLIN
) == POLLIN
) {
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
;
936 fragsize
= info
.ptr
- offset
;
938 DSCDB_CheckEvent(This
, offset
, fragsize
, This
->maplen
);
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
));
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
));
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
);
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
);
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(
1000 LPDWORD pdwcbBufferSize
,
1004 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
1005 IDsCaptureDriverBufferImpl
** ippdscdb
= (IDsCaptureDriverBufferImpl
**)ppvObj
;
1007 audio_buf_info info
;
1008 int audio_fragment
, fsize
, shift
, ret
;
1009 BOOL bNewBuffer
= FALSE
;
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 */
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
;
1058 (*ippdscdb
)->buffer
= NULL
;
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
;
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 */
1077 while ((1 << shift
) <= fsize
)
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;
1093 int min_fsize
= pwfx
->nAvgBytesPerSec
/ 1000;
1094 BOOL found_one
= FALSE
;
1095 while ((1 << min_shift
) <= min_fsize
)
1098 while (new_shift
> min_shift
) {
1099 if (*pdwcbBufferSize
& (-1 >> (32 - new_shift
))) {
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));
1114 /* buffer can't be direct mapped */
1115 audio_fragment
= 0x00100000 + shift
; /* 16 fragments of 2^shift */
1116 (*ippdscdb
)->is_direct_map
= FALSE
;
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
);
1137 WARN("OSS_OpenDevice failed\n");
1138 HeapFree(GetProcessHeap(),0,*ippdscdb
);
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
);
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
);
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
);
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
);
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
);
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
);
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
;
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
;
1269 dscdps
->IDsDriverPropertySet_iface
.lpVtbl
= &dscdpsvt
;
1270 dscdps
->capture_buffer
= dscdb
;
1271 dscdb
->property_set
= dscdps
;
1272 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER
)dscdb
);
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
;
1292 dscdn
->IDsDriverNotify_iface
.lpVtbl
= &dscdnvt
;
1293 dscdn
->capture_buffer
= dscdb
;
1294 dscdb
->notify
= dscdn
;
1295 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER
)dscdb
);
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
));
1316 return MMSYSERR_NOMEM
;
1317 (*idrv
)->IDsCaptureDriver_iface
.lpVtbl
= &dscdvt
;
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 */