2 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
4 * Copyright 1994 Martin Ayotte
5 * 1999 Eric Pouech (async playing in waveOut/waveIn)
6 * 2000 Eric Pouech (loops in waveOut)
7 * 2002 Eric Pouech (full duplex)
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/port.h"
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h>
39 #ifdef HAVE_SYS_MMAN_H
40 # 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(wave
);
64 /*======================================================================*
65 * Low level DSOUND definitions *
66 *======================================================================*/
68 typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl
;
69 typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl
;
70 typedef struct IDsDriverImpl IDsDriverImpl
;
71 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl
;
73 struct IDsDriverPropertySetImpl
76 IDsDriverPropertySetVtbl
*lpVtbl
;
79 IDsDriverBufferImpl
* buffer
;
82 struct IDsDriverNotifyImpl
85 IDsDriverNotifyVtbl
*lpVtbl
;
88 /* IDsDriverNotifyImpl fields */
89 LPDSBPOSITIONNOTIFY notifies
;
92 IDsDriverBufferImpl
* buffer
;
98 IDsDriverVtbl
*lpVtbl
;
101 /* IDsDriverImpl fields */
103 IDsDriverBufferImpl
* primary
;
106 IDsDriverBufferImpl
** secondaries
;
109 struct IDsDriverBufferImpl
111 /* IUnknown fields */
112 IDsDriverBufferVtbl
*lpVtbl
;
115 /* IDsDriverBufferImpl fields */
118 WAVEFORMATPCMEX wfex
;
124 /* IDsDriverNotifyImpl fields */
125 IDsDriverNotifyImpl
* notify
;
128 /* IDsDriverPropertySetImpl fields */
129 IDsDriverPropertySetImpl
* property_set
;
132 static HRESULT WINAPI
IDsDriverPropertySetImpl_Create(
133 IDsDriverBufferImpl
* dsdb
,
134 IDsDriverPropertySetImpl
**pdsdps
);
136 static HRESULT WINAPI
IDsDriverNotifyImpl_Create(
137 IDsDriverBufferImpl
* dsdb
,
138 IDsDriverNotifyImpl
**pdsdn
);
140 /*======================================================================*
141 * Low level DSOUND property set implementation *
142 *======================================================================*/
144 static HRESULT WINAPI
IDsDriverPropertySetImpl_QueryInterface(
145 PIDSDRIVERPROPERTYSET iface
,
149 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
150 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
152 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
153 IsEqualGUID(riid
, &IID_IDsDriverPropertySet
) ) {
154 IDsDriverPropertySet_AddRef(iface
);
155 *ppobj
= (LPVOID
)This
;
159 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
162 return E_NOINTERFACE
;
165 static ULONG WINAPI
IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface
)
167 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
168 ULONG refCount
= InterlockedIncrement(&This
->ref
);
170 TRACE("(%p) ref was %ld\n", This
, refCount
- 1);
175 static ULONG WINAPI
IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface
)
177 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
178 ULONG refCount
= InterlockedDecrement(&This
->ref
);
180 TRACE("(%p) ref was %ld\n", This
, refCount
+ 1);
183 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
184 HeapFree(GetProcessHeap(),0,This
);
185 TRACE("(%p) released\n",This
);
190 static HRESULT WINAPI
IDsDriverPropertySetImpl_Get(
191 PIDSDRIVERPROPERTYSET iface
,
192 PDSPROPERTY pDsProperty
,
193 LPVOID pPropertyParams
,
194 ULONG cbPropertyParams
,
195 LPVOID pPropertyData
,
196 ULONG cbPropertyData
,
197 PULONG pcbReturnedData
)
199 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
200 FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
,pcbReturnedData
);
201 return DSERR_UNSUPPORTED
;
204 static HRESULT WINAPI
IDsDriverPropertySetImpl_Set(
205 PIDSDRIVERPROPERTYSET iface
,
206 PDSPROPERTY pDsProperty
,
207 LPVOID pPropertyParams
,
208 ULONG cbPropertyParams
,
209 LPVOID pPropertyData
,
210 ULONG cbPropertyData
)
212 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
213 FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
);
214 return DSERR_UNSUPPORTED
;
217 static HRESULT WINAPI
IDsDriverPropertySetImpl_QuerySupport(
218 PIDSDRIVERPROPERTYSET iface
,
219 REFGUID PropertySetId
,
223 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
224 FIXME("(%p,%s,%lx,%p)\n",This
,debugstr_guid(PropertySetId
),PropertyId
,pSupport
);
225 return DSERR_UNSUPPORTED
;
228 IDsDriverPropertySetVtbl dsdpsvt
=
230 IDsDriverPropertySetImpl_QueryInterface
,
231 IDsDriverPropertySetImpl_AddRef
,
232 IDsDriverPropertySetImpl_Release
,
233 IDsDriverPropertySetImpl_Get
,
234 IDsDriverPropertySetImpl_Set
,
235 IDsDriverPropertySetImpl_QuerySupport
,
238 /*======================================================================*
239 * Low level DSOUND notify implementation *
240 *======================================================================*/
242 static HRESULT WINAPI
IDsDriverNotifyImpl_QueryInterface(
243 PIDSDRIVERNOTIFY iface
,
247 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
248 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
250 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
251 IsEqualGUID(riid
, &IID_IDsDriverNotify
) ) {
252 IDsDriverNotify_AddRef(iface
);
257 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
260 return E_NOINTERFACE
;
263 static ULONG WINAPI
IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface
)
265 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
266 ULONG refCount
= InterlockedIncrement(&This
->ref
);
268 TRACE("(%p) ref was %ld\n", This
, refCount
- 1);
273 static ULONG WINAPI
IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface
)
275 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
276 ULONG refCount
= InterlockedDecrement(&This
->ref
);
278 TRACE("(%p) ref was %ld\n", This
, refCount
+ 1);
281 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
282 HeapFree(GetProcessHeap(), 0, This
->notifies
);
283 HeapFree(GetProcessHeap(),0,This
);
284 TRACE("(%p) released\n",This
);
289 static HRESULT WINAPI
IDsDriverNotifyImpl_SetNotificationPositions(
290 PIDSDRIVERNOTIFY iface
,
292 LPCDSBPOSITIONNOTIFY notify
)
294 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
295 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
298 WARN("invalid parameter\n");
299 return DSERR_INVALIDPARAM
;
302 if (TRACE_ON(wave
)) {
304 for (i
=0;i
<howmuch
;i
++)
305 TRACE("notify at %ld to 0x%08lx\n",
306 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
309 /* Make an internal copy of the caller-supplied array.
310 * Replace the existing copy if one is already present. */
312 This
->notifies
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
313 This
->notifies
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
315 This
->notifies
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
316 howmuch
* sizeof(DSBPOSITIONNOTIFY
));
318 memcpy(This
->notifies
, notify
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
319 This
->nrofnotifies
= howmuch
;
324 IDsDriverNotifyVtbl dsdnvt
=
326 IDsDriverNotifyImpl_QueryInterface
,
327 IDsDriverNotifyImpl_AddRef
,
328 IDsDriverNotifyImpl_Release
,
329 IDsDriverNotifyImpl_SetNotificationPositions
,
332 /*======================================================================*
333 * Low level DSOUND implementation *
334 *======================================================================*/
336 static HRESULT
DSDB_MapBuffer(IDsDriverBufferImpl
*dsdb
)
338 TRACE("(%p), format=%ldx%dx%d\n", dsdb
, dsdb
->wfex
.Format
.nSamplesPerSec
,
339 dsdb
->wfex
.Format
.wBitsPerSample
, dsdb
->wfex
.Format
.nChannels
);
340 if (!dsdb
->mapping
) {
341 dsdb
->mapping
= mmap(NULL
, dsdb
->maplen
, PROT_WRITE
, MAP_SHARED
,
343 if (dsdb
->mapping
== (LPBYTE
)-1) {
344 ERR("Could not map sound device for direct access (%s)\n", strerror(errno
));
345 ERR("Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n");
346 return DSERR_GENERIC
;
348 TRACE("The sound device has been mapped for direct access at %p, size=%ld\n", dsdb
->mapping
, dsdb
->maplen
);
350 /* for some reason, es1371 and sblive! sometimes have junk in here.
351 * clear it, or we get junk noise */
352 /* some libc implementations are buggy: their memset reads from the buffer...
353 * to work around it, we have to zero the block by hand. We don't do the expected:
354 * memset(dsdb->mapping,0, dsdb->maplen);
357 unsigned char* p1
= dsdb
->mapping
;
358 unsigned len
= dsdb
->maplen
;
359 unsigned char silence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 128 : 0;
360 unsigned long ulsilence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 0x80808080 : 0;
362 if (len
>= 16) /* so we can have at least a 4 long area to store... */
364 /* the mmap:ed value is (at least) dword aligned
365 * so, start filling the complete unsigned long:s
368 unsigned long* p4
= (unsigned long*)p1
;
370 while (b
--) *p4
++ = ulsilence
;
371 /* prepare for filling the rest */
373 p1
= (unsigned char*)p4
;
375 /* in all cases, fill the remaining bytes */
376 while (len
-- != 0) *p1
++ = silence
;
382 static HRESULT
DSDB_UnmapBuffer(IDsDriverBufferImpl
*dsdb
)
384 TRACE("(%p)\n",dsdb
);
386 if (munmap(dsdb
->mapping
, dsdb
->maplen
) < 0) {
387 ERR("(%p): Could not unmap sound device (%s)\n", dsdb
, strerror(errno
));
388 return DSERR_GENERIC
;
390 dsdb
->mapping
= NULL
;
391 TRACE("(%p): sound device unmapped\n", dsdb
);
396 static HRESULT WINAPI
IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
398 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
399 TRACE("(%p,%s,%p)\n",iface
,debugstr_guid(riid
),*ppobj
);
401 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
402 IsEqualGUID(riid
, &IID_IDsDriverBuffer
) ) {
403 IDsDriverBuffer_AddRef(iface
);
404 *ppobj
= (LPVOID
)This
;
408 if ( IsEqualGUID( &IID_IDsDriverNotify
, riid
) ) {
410 IDsDriverNotifyImpl_Create(This
, &(This
->notify
));
412 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY
)This
->notify
);
413 *ppobj
= (LPVOID
)This
->notify
;
420 if ( IsEqualGUID( &IID_IDsDriverPropertySet
, riid
) ) {
421 if (!This
->property_set
)
422 IDsDriverPropertySetImpl_Create(This
, &(This
->property_set
));
423 if (This
->property_set
) {
424 IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET
)This
->property_set
);
425 *ppobj
= (LPVOID
)This
->property_set
;
432 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
436 return E_NOINTERFACE
;
439 static ULONG WINAPI
IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface
)
441 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
442 ULONG refCount
= InterlockedIncrement(&This
->ref
);
444 TRACE("(%p) ref was %ld\n", This
, refCount
- 1);
449 static ULONG WINAPI
IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface
)
451 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
452 ULONG refCount
= InterlockedDecrement(&This
->ref
);
454 TRACE("(%p) ref was %ld\n", This
, refCount
+ 1);
459 if (This
== This
->drv
->primary
)
460 This
->drv
->primary
= NULL
;
463 for (i
= 0; i
< This
->drv
->nrofsecondaries
; i
++)
464 if (This
->drv
->secondaries
[i
] == This
)
466 if (i
< This
->drv
->nrofsecondaries
) {
467 /* Put the last buffer of the list in the (now empty) position */
468 This
->drv
->secondaries
[i
] = This
->drv
->secondaries
[This
->drv
->nrofsecondaries
- 1];
469 This
->drv
->nrofsecondaries
--;
470 This
->drv
->secondaries
= HeapReAlloc(GetProcessHeap(),0,
471 This
->drv
->secondaries
,
472 sizeof(PIDSDRIVERBUFFER
)*This
->drv
->nrofsecondaries
);
473 TRACE("(%p) buffer count is now %d\n", This
, This
->drv
->nrofsecondaries
);
476 WOutDev
[This
->drv
->wDevID
].ossdev
->ds_caps
.dwFreeHwMixingAllBuffers
++;
477 WOutDev
[This
->drv
->wDevID
].ossdev
->ds_caps
.dwFreeHwMixingStreamingBuffers
++;
480 DSDB_UnmapBuffer(This
);
481 HeapFree(GetProcessHeap(),0,This
);
482 TRACE("(%p) released\n",This
);
486 static HRESULT WINAPI
IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface
,
487 LPVOID
*ppvAudio1
,LPDWORD pdwLen1
,
488 LPVOID
*ppvAudio2
,LPDWORD pdwLen2
,
489 DWORD dwWritePosition
,DWORD dwWriteLen
,
492 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
493 /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
494 * and that we don't support secondary buffers, this method will never be called */
495 TRACE("(%p): stub\n",iface
);
496 return DSERR_UNSUPPORTED
;
499 static HRESULT WINAPI
IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface
,
500 LPVOID pvAudio1
,DWORD dwLen1
,
501 LPVOID pvAudio2
,DWORD dwLen2
)
503 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
504 TRACE("(%p): stub\n",iface
);
505 return DSERR_UNSUPPORTED
;
508 static HRESULT WINAPI
IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface
,
511 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
513 TRACE("(%p,%p)\n",iface
,pwfx
);
514 /* On our request (GetDriverDesc flags), DirectSound has by now used
515 * waveOutClose/waveOutOpen to set the format...
516 * unfortunately, this means our mmap() is now gone...
517 * so we need to somehow signal to our DirectSound implementation
518 * that it should completely recreate this HW buffer...
519 * this unexpected error code should do the trick... */
520 return DSERR_BUFFERLOST
;
523 static HRESULT WINAPI
IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface
, DWORD dwFreq
)
525 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
526 TRACE("(%p,%ld): stub\n",iface
,dwFreq
);
527 return DSERR_UNSUPPORTED
;
530 static HRESULT WINAPI
IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface
, PDSVOLUMEPAN pVolPan
)
533 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
534 TRACE("(%p,%p)\n",This
,pVolPan
);
536 vol
= pVolPan
->dwTotalLeftAmpFactor
| (pVolPan
->dwTotalRightAmpFactor
<< 16);
538 if (wodSetVolume(This
->drv
->wDevID
, vol
) != MMSYSERR_NOERROR
) {
539 WARN("wodSetVolume failed\n");
540 return DSERR_INVALIDPARAM
;
546 static HRESULT WINAPI
IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface
, DWORD dwNewPos
)
548 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
549 TRACE("(%p,%ld): stub\n",iface
,dwNewPos
);
550 return DSERR_UNSUPPORTED
;
553 static HRESULT WINAPI
IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface
,
554 LPDWORD lpdwPlay
, LPDWORD lpdwWrite
)
556 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
560 TRACE("(%p)\n",iface
);
561 if (WOutDev
[This
->drv
->wDevID
].state
== WINE_WS_CLOSED
) {
562 ERR("device not open, but accessing?\n");
563 return DSERR_UNINITIALIZED
;
565 if (ioctl(This
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
566 ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
567 WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
568 return DSERR_GENERIC
;
570 ptr
= info
.ptr
& ~3; /* align the pointer, just in case */
571 if (lpdwPlay
) *lpdwPlay
= ptr
;
573 /* add some safety margin (not strictly necessary, but...) */
574 if (WOutDev
[This
->drv
->wDevID
].ossdev
->duplex_out_caps
.dwSupport
& WAVECAPS_SAMPLEACCURATE
)
575 *lpdwWrite
= ptr
+ 32;
577 *lpdwWrite
= ptr
+ WOutDev
[This
->drv
->wDevID
].dwFragmentSize
;
578 while (*lpdwWrite
> This
->buflen
)
579 *lpdwWrite
-= This
->buflen
;
581 TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay
?*lpdwPlay
:0, lpdwWrite
?*lpdwWrite
:0);
585 static HRESULT WINAPI
IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface
, DWORD dwRes1
, DWORD dwRes2
, DWORD dwFlags
)
587 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
589 TRACE("(%p,%lx,%lx,%lx)\n",iface
,dwRes1
,dwRes2
,dwFlags
);
590 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= TRUE
;
591 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
592 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
593 if (errno
== EINVAL
) {
594 /* Don't give up yet. OSS trigger support is inconsistent. */
595 if (WOutDev
[This
->drv
->wDevID
].ossdev
->open_count
== 1) {
596 /* try the opposite input enable */
597 if (WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
== FALSE
)
598 WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
= TRUE
;
600 WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
602 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
603 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) >= 0)
607 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
608 WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
609 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
610 return DSERR_GENERIC
;
615 static HRESULT WINAPI
IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface
)
617 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
619 TRACE("(%p)\n",iface
);
620 /* no more playing */
621 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
622 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
623 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
624 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
625 return DSERR_GENERIC
;
628 /* the play position must be reset to the beginning of the buffer */
629 if (ioctl(This
->fd
, SNDCTL_DSP_RESET
, 0) < 0) {
630 ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
631 return DSERR_GENERIC
;
634 /* Most OSS drivers just can't stop the playback without closing the device...
635 * so we need to somehow signal to our DirectSound implementation
636 * that it should completely recreate this HW buffer...
637 * this unexpected error code should do the trick... */
638 /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
639 if (WOutDev
[This
->drv
->wDevID
].ossdev
->open_count
== 1)
640 return DSERR_BUFFERLOST
;
645 static IDsDriverBufferVtbl dsdbvt
=
647 IDsDriverBufferImpl_QueryInterface
,
648 IDsDriverBufferImpl_AddRef
,
649 IDsDriverBufferImpl_Release
,
650 IDsDriverBufferImpl_Lock
,
651 IDsDriverBufferImpl_Unlock
,
652 IDsDriverBufferImpl_SetFormat
,
653 IDsDriverBufferImpl_SetFrequency
,
654 IDsDriverBufferImpl_SetVolumePan
,
655 IDsDriverBufferImpl_SetPosition
,
656 IDsDriverBufferImpl_GetPosition
,
657 IDsDriverBufferImpl_Play
,
658 IDsDriverBufferImpl_Stop
661 static HRESULT WINAPI
IDsDriverImpl_QueryInterface(PIDSDRIVER iface
, REFIID riid
, LPVOID
*ppobj
)
663 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
664 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
666 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
667 IsEqualGUID(riid
, &IID_IDsDriver
) ) {
668 IDsDriver_AddRef(iface
);
669 *ppobj
= (LPVOID
)This
;
673 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
677 return E_NOINTERFACE
;
680 static ULONG WINAPI
IDsDriverImpl_AddRef(PIDSDRIVER iface
)
682 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
683 ULONG refCount
= InterlockedIncrement(&This
->ref
);
685 TRACE("(%p) ref was %ld\n", This
, refCount
- 1);
690 static ULONG WINAPI
IDsDriverImpl_Release(PIDSDRIVER iface
)
692 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
693 ULONG refCount
= InterlockedDecrement(&This
->ref
);
695 TRACE("(%p) ref was %ld\n", This
, refCount
+ 1);
698 HeapFree(GetProcessHeap(),0,This
);
699 TRACE("(%p) released\n",This
);
704 static HRESULT WINAPI
IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface
,
707 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
708 TRACE("(%p,%p)\n",iface
,pDesc
);
710 /* copy version from driver */
711 memcpy(pDesc
, &(WOutDev
[This
->wDevID
].ossdev
->ds_desc
), sizeof(DSDRIVERDESC
));
713 pDesc
->dwFlags
|= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
|
714 DSDDESC_USESYSTEMMEMORY
| DSDDESC_DONTNEEDPRIMARYLOCK
|
715 DSDDESC_DONTNEEDSECONDARYLOCK
;
716 pDesc
->dnDevNode
= WOutDev
[This
->wDevID
].waveDesc
.dnDevNode
;
718 pDesc
->wReserved
= 0;
719 pDesc
->ulDeviceNum
= This
->wDevID
;
720 pDesc
->dwHeapType
= DSDHEAP_NOHEAP
;
721 pDesc
->pvDirectDrawHeap
= NULL
;
722 pDesc
->dwMemStartAddress
= 0;
723 pDesc
->dwMemEndAddress
= 0;
724 pDesc
->dwMemAllocExtra
= 0;
725 pDesc
->pvReserved1
= NULL
;
726 pDesc
->pvReserved2
= NULL
;
730 static HRESULT WINAPI
IDsDriverImpl_Open(PIDSDRIVER iface
)
732 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
734 TRACE("(%p)\n",iface
);
736 /* make sure the card doesn't start playing before we want it to */
737 WOutDev
[This
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
738 WOutDev
[This
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
739 enable
= getEnables(WOutDev
[This
->wDevID
].ossdev
);
740 if (ioctl(WOutDev
[This
->wDevID
].ossdev
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
741 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
742 return DSERR_GENERIC
;
747 static HRESULT WINAPI
IDsDriverImpl_Close(PIDSDRIVER iface
)
749 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
750 TRACE("(%p)\n",iface
);
752 ERR("problem with DirectSound: primary not released\n");
753 return DSERR_GENERIC
;
758 static HRESULT WINAPI
IDsDriverImpl_GetCaps(PIDSDRIVER iface
, PDSDRIVERCAPS pCaps
)
760 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
761 TRACE("(%p,%p)\n",iface
,pCaps
);
762 memcpy(pCaps
, &(WOutDev
[This
->wDevID
].ossdev
->ds_caps
), sizeof(DSDRIVERCAPS
));
766 static HRESULT WINAPI
DSD_CreatePrimaryBuffer(PIDSDRIVER iface
,
770 LPDWORD pdwcbBufferSize
,
774 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
775 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
779 TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
782 return DSERR_ALLOCATED
;
783 if (dwFlags
& (DSBCAPS_CTRLFREQUENCY
| DSBCAPS_CTRLPAN
))
784 return DSERR_CONTROLUNAVAIL
;
786 *ippdsdb
= (IDsDriverBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverBufferImpl
));
787 if (*ippdsdb
== NULL
)
788 return DSERR_OUTOFMEMORY
;
789 (*ippdsdb
)->lpVtbl
= &dsdbvt
;
791 (*ippdsdb
)->drv
= This
;
792 copy_format(pwfx
, &(*ippdsdb
)->wfex
);
793 (*ippdsdb
)->fd
= WOutDev
[This
->wDevID
].ossdev
->fd
;
794 (*ippdsdb
)->dwFlags
= dwFlags
;
796 /* check how big the DMA buffer is now */
797 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
798 ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
799 WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
800 HeapFree(GetProcessHeap(),0,*ippdsdb
);
802 return DSERR_GENERIC
;
804 (*ippdsdb
)->maplen
= (*ippdsdb
)->buflen
= info
.fragstotal
* info
.fragsize
;
806 /* map the DMA buffer */
807 err
= DSDB_MapBuffer(*ippdsdb
);
809 HeapFree(GetProcessHeap(),0,*ippdsdb
);
814 /* primary buffer is ready to go */
815 *pdwcbBufferSize
= (*ippdsdb
)->maplen
;
816 *ppbBuffer
= (*ippdsdb
)->mapping
;
818 /* some drivers need some extra nudging after mapping */
819 WOutDev
[This
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
820 WOutDev
[This
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
821 enable
= getEnables(WOutDev
[This
->wDevID
].ossdev
);
822 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
823 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
824 WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
825 return DSERR_GENERIC
;
828 This
->primary
= *ippdsdb
;
833 static HRESULT WINAPI
DSD_CreateSecondaryBuffer(PIDSDRIVER iface
,
837 LPDWORD pdwcbBufferSize
,
841 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
842 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
843 FIXME("(%p,%p,%lx,%lx,%p,%p,%p): stub\n",This
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
846 return DSERR_UNSUPPORTED
;
849 static HRESULT WINAPI
IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface
,
853 LPDWORD pdwcbBufferSize
,
857 TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
859 if (dwFlags
& DSBCAPS_PRIMARYBUFFER
)
860 return DSD_CreatePrimaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
862 return DSD_CreateSecondaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
865 static HRESULT WINAPI
IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface
,
866 PIDSDRIVERBUFFER pBuffer
,
869 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
870 TRACE("(%p,%p): stub\n",iface
,pBuffer
);
871 return DSERR_INVALIDCALL
;
874 static IDsDriverVtbl dsdvt
=
876 IDsDriverImpl_QueryInterface
,
877 IDsDriverImpl_AddRef
,
878 IDsDriverImpl_Release
,
879 IDsDriverImpl_GetDriverDesc
,
882 IDsDriverImpl_GetCaps
,
883 IDsDriverImpl_CreateSoundBuffer
,
884 IDsDriverImpl_DuplicateSoundBuffer
887 static HRESULT WINAPI
IDsDriverPropertySetImpl_Create(
888 IDsDriverBufferImpl
* dsdb
,
889 IDsDriverPropertySetImpl
**pdsdps
)
891 IDsDriverPropertySetImpl
* dsdps
;
892 TRACE("(%p,%p)\n",dsdb
,pdsdps
);
894 dsdps
= (IDsDriverPropertySetImpl
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(dsdps
));
896 WARN("out of memory\n");
897 return DSERR_OUTOFMEMORY
;
901 dsdps
->lpVtbl
= &dsdpsvt
;
902 dsdps
->buffer
= dsdb
;
903 dsdb
->property_set
= dsdps
;
904 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
910 static HRESULT WINAPI
IDsDriverNotifyImpl_Create(
911 IDsDriverBufferImpl
* dsdb
,
912 IDsDriverNotifyImpl
**pdsdn
)
914 IDsDriverNotifyImpl
* dsdn
;
915 TRACE("(%p,%p)\n",dsdb
,pdsdn
);
917 dsdn
= (IDsDriverNotifyImpl
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(dsdn
));
920 WARN("out of memory\n");
921 return DSERR_OUTOFMEMORY
;
925 dsdn
->lpVtbl
= &dsdnvt
;
928 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
934 DWORD
wodDsCreate(UINT wDevID
, PIDSDRIVER
* drv
)
936 IDsDriverImpl
** idrv
= (IDsDriverImpl
**)drv
;
937 TRACE("(%d,%p)\n",wDevID
,drv
);
939 /* the HAL isn't much better than the HEL if we can't do mmap() */
940 if (!(WOutDev
[wDevID
].ossdev
->duplex_out_caps
.dwSupport
& WAVECAPS_DIRECTSOUND
)) {
941 ERR("DirectSound flag not set\n");
942 MESSAGE("This sound card's driver does not support direct access\n");
943 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
944 return MMSYSERR_NOTSUPPORTED
;
947 *idrv
= (IDsDriverImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverImpl
));
949 return MMSYSERR_NOMEM
;
950 (*idrv
)->lpVtbl
= &dsdvt
;
952 (*idrv
)->wDevID
= wDevID
;
953 (*idrv
)->primary
= NULL
;
954 (*idrv
)->nrofsecondaries
= 0;
955 (*idrv
)->secondaries
= NULL
;
957 return MMSYSERR_NOERROR
;
960 DWORD
wodDsDesc(UINT wDevID
, PDSDRIVERDESC desc
)
962 TRACE("(%d,%p)\n",wDevID
,desc
);
963 memcpy(desc
, &(WOutDev
[wDevID
].ossdev
->ds_desc
), sizeof(DSDRIVERDESC
));
964 return MMSYSERR_NOERROR
;
967 #endif /* HAVE_OSS */