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>
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>
52 #ifdef HAVE_SYS_ERRNO_H
53 #include <sys/errno.h>
65 #include "wine/debug.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
83 IDsDriverPropertySet IDsDriverPropertySet_iface
;
86 IDsCaptureDriverBufferImpl
* capture_buffer
;
89 struct IDsCaptureDriverNotifyImpl
92 IDsDriverNotify IDsDriverNotify_iface
;
95 IDsCaptureDriverBufferImpl
* capture_buffer
;
98 struct IDsCaptureDriverImpl
100 /* IUnknown fields */
101 IDsCaptureDriver IDsCaptureDriver_iface
;
104 /* IDsCaptureDriverImpl fields */
106 IDsCaptureDriverBufferImpl
* capture_buffer
;
109 struct IDsCaptureDriverBufferImpl
111 /* IUnknown fields */
112 IDsCaptureDriverBuffer IDsCaptureDriverBuffer_iface
;
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 ? */
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
;
131 LPDSBPOSITIONNOTIFY notifies
;
134 /* IDsDriverPropertySetImpl fields */
135 IDsCaptureDriverPropertySetImpl
* property_set
;
142 HANDLE hStartUpEvent
;
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
,
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
);
195 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
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
);
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
,
264 IDsCaptureDriverPropertySetImpl
*This
= impl_from_IDsDriverPropertySet(iface
);
265 FIXME("(%p,%s,%x,%p)\n",This
,debugstr_guid(PropertySetId
),PropertyId
,
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
,
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
);
299 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
325 IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER
)This
->capture_buffer
);
326 This
->capture_buffer
->notify
= NULL
;
327 HeapFree(GetProcessHeap(),0,This
);
328 TRACE("(%p) released\n",This
);
333 static HRESULT WINAPI
IDsCaptureDriverNotifyImpl_SetNotificationPositions(
334 PIDSDRIVERNOTIFY iface
,
336 LPCDSBPOSITIONNOTIFY notify
)
338 IDsCaptureDriverNotifyImpl
*This
= impl_from_IDsDriverNotify(iface
);
339 TRACE("(%p,0x%08x,%p)\n",This
,howmuch
,notify
);
342 WARN("invalid parameter\n");
343 return DSERR_INVALIDPARAM
;
346 if (TRACE_ON(dscapture
)) {
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
));
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
;
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
);
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
);
412 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_QueryInterface(
413 PIDSCDRIVERBUFFER iface
,
417 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
418 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
422 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
423 IsEqualGUID(riid
, &IID_IDsCaptureDriverBuffer
) ) {
424 IDsCaptureDriverBuffer_AddRef(iface
);
429 if ( IsEqualGUID( &IID_IDsDriverNotify
, riid
) ) {
431 IDsCaptureDriverNotifyImpl_Create(This
, &(This
->notify
));
433 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY
)This
->notify
);
434 *ppobj
= This
->notify
;
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
;
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);
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);
474 wwi
= &WInDev
[This
->drv
->wDevID
];
479 /* request thread termination */
480 write(This
->pipe_fd
[1], &x
, sizeof(x
));
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
);
504 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Lock(
505 PIDSCDRIVERBUFFER iface
,
510 DWORD dwWritePosition
,
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
) {
520 *ppvAudio1
= This
->mapping
+ dwWritePosition
;
522 if (dwWritePosition
+ dwWriteLen
< This
->maplen
) {
524 *pdwLen1
= dwWriteLen
;
531 *pdwLen1
= This
->maplen
- dwWritePosition
;
535 *pdwLen2
= dwWriteLen
- (This
->maplen
- dwWritePosition
);
539 *ppvAudio1
= This
->buffer
+ dwWritePosition
;
541 if (dwWritePosition
+ dwWriteLen
< This
->buflen
) {
543 *pdwLen1
= dwWriteLen
;
550 *pdwLen1
= This
->buflen
- dwWritePosition
;
554 *pdwLen2
= dwWriteLen
- (This
->buflen
- dwWritePosition
);
561 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Unlock(
562 PIDSCDRIVERBUFFER iface
,
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
;
574 This
->readptr
= (This
->readptr
+ dwLen1
+ dwLen2
) % This
->buflen
;
579 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_GetPosition(
580 PIDSCDRIVERBUFFER iface
,
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
) {
599 if (This
->is_direct_map
) {
601 *lpdwCapture
= This
->map_writepos
;
603 *lpdwRead
= This
->map_readpos
;
607 *lpdwCapture
= This
->writeptr
;
609 *lpdwRead
= This
->readptr
;
612 TRACE("capturepos=%d, readpos=%d\n", lpdwCapture
?*lpdwCapture
:0,
613 lpdwRead
?*lpdwRead
:0);
617 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_GetStatus(
618 PIDSCDRIVERBUFFER iface
,
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
;
628 *lpdwStatus
= DSCBSTATUS_CAPTURING
;
635 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Start(
636 PIDSCDRIVERBUFFER iface
,
639 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
641 TRACE("(%p,%x)\n",This
,dwFlags
);
643 if (This
->is_capturing
)
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
;
659 WInDev
[This
->drv
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
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
;
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
;
678 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface
)
680 IDsCaptureDriverBufferImpl
*This
= impl_from_IDsCaptureDriverBuffer(iface
);
682 TRACE("(%p)\n",This
);
684 if (!This
->is_capturing
)
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
;
707 write(This
->pipe_fd
[1], &x
, sizeof(x
));
708 WaitForSingleObject(This
->hExitEvent
, INFINITE
);
709 CloseHandle(This
->hExitEvent
);
710 This
->hExitEvent
= INVALID_HANDLE_VALUE
;
717 static HRESULT WINAPI
IDsCaptureDriverBufferImpl_SetFormat(
718 PIDSCDRIVERBUFFER iface
,
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(
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
);
755 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
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);
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);
780 HeapFree(GetProcessHeap(),0,This
);
781 TRACE("(%p) released\n",This
);
786 static HRESULT WINAPI
IDsCaptureDriverImpl_GetDriverDesc(
790 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
791 TRACE("(%p,%p)\n",This
,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
;
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
;
815 static HRESULT WINAPI
IDsCaptureDriverImpl_Open(PIDSCDRIVER iface
)
817 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
818 TRACE("(%p)\n",This
);
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
;
833 static HRESULT WINAPI
IDsCaptureDriverImpl_GetCaps(
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
;
843 static void DSCDB_CheckEvent(
844 IDsCaptureDriverBufferImpl
*dscb
,
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
;
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
;
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
)
882 for (i
= 0; i
< length
; i
++)
883 ((char *)dst
)[i
] = ((const char *)src
)[i
];
887 static DWORD CALLBACK
DSCDB_Thread(LPVOID lpParameter
)
889 IDsCaptureDriverBufferImpl
*This
= lpParameter
;
890 struct pollfd poll_list
[2];
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
);
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
911 ERR("Error while polling: %s\n",strerror(errno
));
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
);
925 if ((poll_list
[0].revents
& POLLIN
) == POLLIN
) {
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
;
943 fragsize
= info
.ptr
- offset
;
945 DSCDB_CheckEvent(This
, offset
, fragsize
, This
->maplen
);
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
));
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
));
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
);
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
);
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(
1004 LPWAVEFORMATEX pwfx
,
1006 DWORD dwCardAddress
,
1007 LPDWORD pdwcbBufferSize
,
1011 IDsCaptureDriverImpl
*This
= impl_from_IDsCaptureDriver(iface
);
1012 IDsCaptureDriverBufferImpl
** ippdscdb
= (IDsCaptureDriverBufferImpl
**)ppvObj
;
1014 audio_buf_info info
;
1015 int audio_fragment
, fsize
, shift
, ret
;
1016 BOOL bNewBuffer
= FALSE
;
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 */
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
;
1065 (*ippdscdb
)->buffer
= NULL
;
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
;
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 */
1084 while ((1 << shift
) <= fsize
)
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;
1100 int min_fsize
= pwfx
->nAvgBytesPerSec
/ 1000;
1101 BOOL found_one
= FALSE
;
1102 while ((1 << min_shift
) <= min_fsize
)
1105 while (new_shift
> min_shift
) {
1106 if (*pdwcbBufferSize
& (-1 >> (32 - new_shift
))) {
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));
1121 /* buffer can't be direct mapped */
1122 audio_fragment
= 0x00100000 + shift
; /* 16 fragments of 2^shift */
1123 (*ippdscdb
)->is_direct_map
= FALSE
;
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
);
1144 WARN("OSS_OpenDevice failed\n");
1145 HeapFree(GetProcessHeap(),0,*ippdscdb
);
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
);
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
);
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
);
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
);
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
);
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
);
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
;
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
;
1276 dscdps
->IDsDriverPropertySet_iface
.lpVtbl
= &dscdpsvt
;
1277 dscdps
->capture_buffer
= dscdb
;
1278 dscdb
->property_set
= dscdps
;
1279 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER
)dscdb
);
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
;
1299 dscdn
->IDsDriverNotify_iface
.lpVtbl
= &dscdnvt
;
1300 dscdn
->capture_buffer
= dscdb
;
1301 dscdb
->notify
= dscdn
;
1302 IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER
)dscdb
);
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
));
1323 return MMSYSERR_NOMEM
;
1324 (*idrv
)->IDsCaptureDriver_iface
.lpVtbl
= &dscdvt
;
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
;