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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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>
45 #ifdef HAVE_SYS_POLL_H
46 # include <sys/poll.h>
59 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
67 /*======================================================================*
68 * Low level DSOUND definitions *
69 *======================================================================*/
71 typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl
;
72 typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl
;
73 typedef struct IDsDriverImpl IDsDriverImpl
;
74 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl
;
76 struct IDsDriverPropertySetImpl
79 const IDsDriverPropertySetVtbl
*lpVtbl
;
82 IDsDriverBufferImpl
* buffer
;
85 struct IDsDriverNotifyImpl
88 const IDsDriverNotifyVtbl
*lpVtbl
;
91 /* IDsDriverNotifyImpl fields */
92 LPDSBPOSITIONNOTIFY notifies
;
95 IDsDriverBufferImpl
* buffer
;
100 /* IUnknown fields */
101 const IDsDriverVtbl
*lpVtbl
;
104 /* IDsDriverImpl fields */
106 IDsDriverBufferImpl
* primary
;
109 IDsDriverBufferImpl
** secondaries
;
112 struct IDsDriverBufferImpl
114 /* IUnknown fields */
115 const IDsDriverBufferVtbl
*lpVtbl
;
118 /* IDsDriverBufferImpl fields */
121 WAVEFORMATPCMEX wfex
;
127 /* IDsDriverNotifyImpl fields */
128 IDsDriverNotifyImpl
* notify
;
131 /* IDsDriverPropertySetImpl fields */
132 IDsDriverPropertySetImpl
* property_set
;
135 static HRESULT WINAPI
IDsDriverPropertySetImpl_Create(
136 IDsDriverBufferImpl
* dsdb
,
137 IDsDriverPropertySetImpl
**pdsdps
);
139 static HRESULT WINAPI
IDsDriverNotifyImpl_Create(
140 IDsDriverBufferImpl
* dsdb
,
141 IDsDriverNotifyImpl
**pdsdn
);
143 /*======================================================================*
144 * Low level DSOUND property set implementation *
145 *======================================================================*/
147 static HRESULT WINAPI
IDsDriverPropertySetImpl_QueryInterface(
148 PIDSDRIVERPROPERTYSET iface
,
152 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
153 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
155 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
156 IsEqualGUID(riid
, &IID_IDsDriverPropertySet
) ) {
157 IDsDriverPropertySet_AddRef(iface
);
158 *ppobj
= (LPVOID
)This
;
162 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
165 return E_NOINTERFACE
;
168 static ULONG WINAPI
IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface
)
170 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
171 ULONG refCount
= InterlockedIncrement(&This
->ref
);
173 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
178 static ULONG WINAPI
IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface
)
180 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
181 ULONG refCount
= InterlockedDecrement(&This
->ref
);
183 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
186 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
187 HeapFree(GetProcessHeap(),0,This
);
188 TRACE("(%p) released\n",This
);
193 static HRESULT WINAPI
IDsDriverPropertySetImpl_Get(
194 PIDSDRIVERPROPERTYSET iface
,
195 PDSPROPERTY pDsProperty
,
196 LPVOID pPropertyParams
,
197 ULONG cbPropertyParams
,
198 LPVOID pPropertyData
,
199 ULONG cbPropertyData
,
200 PULONG pcbReturnedData
)
202 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
203 FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
,pcbReturnedData
);
204 return DSERR_UNSUPPORTED
;
207 static HRESULT WINAPI
IDsDriverPropertySetImpl_Set(
208 PIDSDRIVERPROPERTYSET iface
,
209 PDSPROPERTY pDsProperty
,
210 LPVOID pPropertyParams
,
211 ULONG cbPropertyParams
,
212 LPVOID pPropertyData
,
213 ULONG cbPropertyData
)
215 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
216 FIXME("(%p,%p,%p,%x,%p,%x)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
);
217 return DSERR_UNSUPPORTED
;
220 static HRESULT WINAPI
IDsDriverPropertySetImpl_QuerySupport(
221 PIDSDRIVERPROPERTYSET iface
,
222 REFGUID PropertySetId
,
226 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
227 FIXME("(%p,%s,%x,%p)\n",This
,debugstr_guid(PropertySetId
),PropertyId
,pSupport
);
228 return DSERR_UNSUPPORTED
;
231 static const IDsDriverPropertySetVtbl dsdpsvt
=
233 IDsDriverPropertySetImpl_QueryInterface
,
234 IDsDriverPropertySetImpl_AddRef
,
235 IDsDriverPropertySetImpl_Release
,
236 IDsDriverPropertySetImpl_Get
,
237 IDsDriverPropertySetImpl_Set
,
238 IDsDriverPropertySetImpl_QuerySupport
,
241 /*======================================================================*
242 * Low level DSOUND notify implementation *
243 *======================================================================*/
245 static HRESULT WINAPI
IDsDriverNotifyImpl_QueryInterface(
246 PIDSDRIVERNOTIFY iface
,
250 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
251 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
253 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
254 IsEqualGUID(riid
, &IID_IDsDriverNotify
) ) {
255 IDsDriverNotify_AddRef(iface
);
260 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
263 return E_NOINTERFACE
;
266 static ULONG WINAPI
IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface
)
268 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
269 ULONG refCount
= InterlockedIncrement(&This
->ref
);
271 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
276 static ULONG WINAPI
IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface
)
278 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
279 ULONG refCount
= InterlockedDecrement(&This
->ref
);
281 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
284 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
285 HeapFree(GetProcessHeap(), 0, This
->notifies
);
286 HeapFree(GetProcessHeap(),0,This
);
287 TRACE("(%p) released\n",This
);
292 static HRESULT WINAPI
IDsDriverNotifyImpl_SetNotificationPositions(
293 PIDSDRIVERNOTIFY iface
,
295 LPCDSBPOSITIONNOTIFY notify
)
297 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
298 TRACE("(%p,0x%08x,%p)\n",This
,howmuch
,notify
);
301 WARN("invalid parameter\n");
302 return DSERR_INVALIDPARAM
;
305 if (TRACE_ON(wave
)) {
307 for (i
=0;i
<howmuch
;i
++)
308 TRACE("notify at %d to 0x%08x\n",
309 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
312 /* Make an internal copy of the caller-supplied array.
313 * Replace the existing copy if one is already present. */
315 This
->notifies
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
316 This
->notifies
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
318 This
->notifies
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
319 howmuch
* sizeof(DSBPOSITIONNOTIFY
));
321 memcpy(This
->notifies
, notify
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
322 This
->nrofnotifies
= howmuch
;
327 static const IDsDriverNotifyVtbl dsdnvt
=
329 IDsDriverNotifyImpl_QueryInterface
,
330 IDsDriverNotifyImpl_AddRef
,
331 IDsDriverNotifyImpl_Release
,
332 IDsDriverNotifyImpl_SetNotificationPositions
,
335 /*======================================================================*
336 * Low level DSOUND implementation *
337 *======================================================================*/
339 static HRESULT
DSDB_MapBuffer(IDsDriverBufferImpl
*dsdb
)
341 TRACE("(%p), format=%dx%dx%d\n", dsdb
, dsdb
->wfex
.Format
.nSamplesPerSec
,
342 dsdb
->wfex
.Format
.wBitsPerSample
, dsdb
->wfex
.Format
.nChannels
);
343 if (!dsdb
->mapping
) {
344 dsdb
->mapping
= mmap(NULL
, dsdb
->maplen
, PROT_WRITE
, MAP_SHARED
,
346 if (dsdb
->mapping
== (LPBYTE
)-1) {
347 ERR("Could not map sound device for direct access (%s)\n", strerror(errno
));
348 ERR("Please run winecfg, open \"Audio\" page and set\n"
349 "\"Hardware Acceleration\" to \"Emulation\".\n");
350 return DSERR_GENERIC
;
352 TRACE("The sound device has been mapped for direct access at %p, size=%d\n", dsdb
->mapping
, dsdb
->maplen
);
354 /* for some reason, es1371 and sblive! sometimes have junk in here.
355 * clear it, or we get junk noise */
356 /* some libc implementations are buggy: their memset reads from the buffer...
357 * to work around it, we have to zero the block by hand. We don't do the expected:
358 * memset(dsdb->mapping,0, dsdb->maplen);
361 unsigned char* p1
= dsdb
->mapping
;
362 unsigned len
= dsdb
->maplen
;
363 unsigned char silence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 128 : 0;
364 unsigned long ulsilence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 0x80808080 : 0;
366 if (len
>= 16) /* so we can have at least a 4 long area to store... */
368 /* the mmap:ed value is (at least) dword aligned
369 * so, start filling the complete unsigned long:s
372 unsigned long* p4
= (unsigned long*)p1
;
374 while (b
--) *p4
++ = ulsilence
;
375 /* prepare for filling the rest */
377 p1
= (unsigned char*)p4
;
379 /* in all cases, fill the remaining bytes */
380 while (len
-- != 0) *p1
++ = silence
;
386 static HRESULT
DSDB_UnmapBuffer(IDsDriverBufferImpl
*dsdb
)
388 TRACE("(%p)\n",dsdb
);
390 if (munmap(dsdb
->mapping
, dsdb
->maplen
) < 0) {
391 ERR("(%p): Could not unmap sound device (%s)\n", dsdb
, strerror(errno
));
392 return DSERR_GENERIC
;
394 dsdb
->mapping
= NULL
;
395 TRACE("(%p): sound device unmapped\n", dsdb
);
400 static HRESULT WINAPI
IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
402 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
403 TRACE("(%p,%s,%p)\n",iface
,debugstr_guid(riid
),*ppobj
);
405 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
406 IsEqualGUID(riid
, &IID_IDsDriverBuffer
) ) {
407 IDsDriverBuffer_AddRef(iface
);
408 *ppobj
= (LPVOID
)This
;
412 if ( IsEqualGUID( &IID_IDsDriverNotify
, riid
) ) {
414 IDsDriverNotifyImpl_Create(This
, &(This
->notify
));
416 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY
)This
->notify
);
417 *ppobj
= (LPVOID
)This
->notify
;
424 if ( IsEqualGUID( &IID_IDsDriverPropertySet
, riid
) ) {
425 if (!This
->property_set
)
426 IDsDriverPropertySetImpl_Create(This
, &(This
->property_set
));
427 if (This
->property_set
) {
428 IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET
)This
->property_set
);
429 *ppobj
= (LPVOID
)This
->property_set
;
436 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
440 return E_NOINTERFACE
;
443 static ULONG WINAPI
IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface
)
445 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
446 ULONG refCount
= InterlockedIncrement(&This
->ref
);
448 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
453 static ULONG WINAPI
IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface
)
455 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
456 ULONG refCount
= InterlockedDecrement(&This
->ref
);
458 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
463 if (This
== This
->drv
->primary
)
464 This
->drv
->primary
= NULL
;
467 for (i
= 0; i
< This
->drv
->nrofsecondaries
; i
++)
468 if (This
->drv
->secondaries
[i
] == This
)
470 if (i
< This
->drv
->nrofsecondaries
) {
471 /* Put the last buffer of the list in the (now empty) position */
472 This
->drv
->secondaries
[i
] = This
->drv
->secondaries
[This
->drv
->nrofsecondaries
- 1];
473 This
->drv
->nrofsecondaries
--;
474 This
->drv
->secondaries
= HeapReAlloc(GetProcessHeap(),0,
475 This
->drv
->secondaries
,
476 sizeof(PIDSDRIVERBUFFER
)*This
->drv
->nrofsecondaries
);
477 TRACE("(%p) buffer count is now %d\n", This
, This
->drv
->nrofsecondaries
);
480 WOutDev
[This
->drv
->wDevID
].ossdev
->ds_caps
.dwFreeHwMixingAllBuffers
++;
481 WOutDev
[This
->drv
->wDevID
].ossdev
->ds_caps
.dwFreeHwMixingStreamingBuffers
++;
484 DSDB_UnmapBuffer(This
);
485 HeapFree(GetProcessHeap(),0,This
);
486 TRACE("(%p) released\n",This
);
490 static HRESULT WINAPI
IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface
,
491 LPVOID
*ppvAudio1
,LPDWORD pdwLen1
,
492 LPVOID
*ppvAudio2
,LPDWORD pdwLen2
,
493 DWORD dwWritePosition
,DWORD dwWriteLen
,
496 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
497 /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
498 * and that we don't support secondary buffers, this method will never be called */
499 TRACE("(%p): stub\n",iface
);
500 return DSERR_UNSUPPORTED
;
503 static HRESULT WINAPI
IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface
,
504 LPVOID pvAudio1
,DWORD dwLen1
,
505 LPVOID pvAudio2
,DWORD dwLen2
)
507 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
508 TRACE("(%p): stub\n",iface
);
509 return DSERR_UNSUPPORTED
;
512 static HRESULT WINAPI
IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface
,
515 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
517 TRACE("(%p,%p)\n",iface
,pwfx
);
518 /* On our request (GetDriverDesc flags), DirectSound has by now used
519 * waveOutClose/waveOutOpen to set the format...
520 * unfortunately, this means our mmap() is now gone...
521 * so we need to somehow signal to our DirectSound implementation
522 * that it should completely recreate this HW buffer...
523 * this unexpected error code should do the trick... */
524 return DSERR_BUFFERLOST
;
527 static HRESULT WINAPI
IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface
, DWORD dwFreq
)
529 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
530 TRACE("(%p,%d): stub\n",iface
,dwFreq
);
531 return DSERR_UNSUPPORTED
;
534 static HRESULT WINAPI
IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface
, PDSVOLUMEPAN pVolPan
)
537 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
538 TRACE("(%p,%p)\n",This
,pVolPan
);
540 vol
= pVolPan
->dwTotalLeftAmpFactor
| (pVolPan
->dwTotalRightAmpFactor
<< 16);
542 if (wodSetVolume(This
->drv
->wDevID
, vol
) != MMSYSERR_NOERROR
) {
543 WARN("wodSetVolume failed\n");
544 return DSERR_INVALIDPARAM
;
550 static HRESULT WINAPI
IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface
, DWORD dwNewPos
)
552 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
553 TRACE("(%p,%d): stub\n",iface
,dwNewPos
);
554 return DSERR_UNSUPPORTED
;
557 static HRESULT WINAPI
IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface
,
558 LPDWORD lpdwPlay
, LPDWORD lpdwWrite
)
560 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
564 TRACE("(%p)\n",iface
);
565 if (WOutDev
[This
->drv
->wDevID
].state
== WINE_WS_CLOSED
) {
566 ERR("device not open, but accessing?\n");
567 return DSERR_UNINITIALIZED
;
569 if (ioctl(This
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
570 ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
571 WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
572 return DSERR_GENERIC
;
574 ptr
= info
.ptr
& ~3; /* align the pointer, just in case */
575 if (lpdwPlay
) *lpdwPlay
= ptr
;
577 /* add some safety margin (not strictly necessary, but...) */
578 if (WOutDev
[This
->drv
->wDevID
].ossdev
->duplex_out_caps
.dwSupport
& WAVECAPS_SAMPLEACCURATE
)
579 *lpdwWrite
= ptr
+ 32;
581 *lpdwWrite
= ptr
+ WOutDev
[This
->drv
->wDevID
].dwFragmentSize
;
582 while (*lpdwWrite
> This
->buflen
)
583 *lpdwWrite
-= This
->buflen
;
585 TRACE("playpos=%d, writepos=%d\n", lpdwPlay
?*lpdwPlay
:0, lpdwWrite
?*lpdwWrite
:0);
589 static HRESULT WINAPI
IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface
, DWORD dwRes1
, DWORD dwRes2
, DWORD dwFlags
)
591 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
593 TRACE("(%p,%x,%x,%x)\n",iface
,dwRes1
,dwRes2
,dwFlags
);
594 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= TRUE
;
595 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
596 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
597 if (errno
== EINVAL
) {
598 /* Don't give up yet. OSS trigger support is inconsistent. */
599 if (WOutDev
[This
->drv
->wDevID
].ossdev
->open_count
== 1) {
600 /* try the opposite input enable */
601 if (WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
== FALSE
)
602 WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
= TRUE
;
604 WOutDev
[This
->drv
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
606 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
607 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) >= 0)
611 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
612 WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
613 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
614 return DSERR_GENERIC
;
619 static HRESULT WINAPI
IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface
)
621 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
623 TRACE("(%p)\n",iface
);
624 /* no more playing */
625 WOutDev
[This
->drv
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
626 enable
= getEnables(WOutDev
[This
->drv
->wDevID
].ossdev
);
627 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
628 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
629 return DSERR_GENERIC
;
632 /* the play position must be reset to the beginning of the buffer */
633 if (ioctl(This
->fd
, SNDCTL_DSP_RESET
, 0) < 0) {
634 ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
->dev_name
, strerror(errno
));
635 return DSERR_GENERIC
;
638 /* Most OSS drivers just can't stop the playback without closing the device...
639 * so we need to somehow signal to our DirectSound implementation
640 * that it should completely recreate this HW buffer...
641 * this unexpected error code should do the trick... */
642 /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
643 if (WOutDev
[This
->drv
->wDevID
].ossdev
->open_count
== 1)
644 return DSERR_BUFFERLOST
;
649 static const IDsDriverBufferVtbl dsdbvt
=
651 IDsDriverBufferImpl_QueryInterface
,
652 IDsDriverBufferImpl_AddRef
,
653 IDsDriverBufferImpl_Release
,
654 IDsDriverBufferImpl_Lock
,
655 IDsDriverBufferImpl_Unlock
,
656 IDsDriverBufferImpl_SetFormat
,
657 IDsDriverBufferImpl_SetFrequency
,
658 IDsDriverBufferImpl_SetVolumePan
,
659 IDsDriverBufferImpl_SetPosition
,
660 IDsDriverBufferImpl_GetPosition
,
661 IDsDriverBufferImpl_Play
,
662 IDsDriverBufferImpl_Stop
665 static HRESULT WINAPI
IDsDriverImpl_QueryInterface(PIDSDRIVER iface
, REFIID riid
, LPVOID
*ppobj
)
667 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
668 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
670 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
671 IsEqualGUID(riid
, &IID_IDsDriver
) ) {
672 IDsDriver_AddRef(iface
);
673 *ppobj
= (LPVOID
)This
;
677 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
681 return E_NOINTERFACE
;
684 static ULONG WINAPI
IDsDriverImpl_AddRef(PIDSDRIVER iface
)
686 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
687 ULONG refCount
= InterlockedIncrement(&This
->ref
);
689 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
694 static ULONG WINAPI
IDsDriverImpl_Release(PIDSDRIVER iface
)
696 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
697 ULONG refCount
= InterlockedDecrement(&This
->ref
);
699 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
702 HeapFree(GetProcessHeap(),0,This
);
703 TRACE("(%p) released\n",This
);
708 static HRESULT WINAPI
IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface
,
711 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
712 TRACE("(%p,%p)\n",iface
,pDesc
);
714 /* copy version from driver */
715 memcpy(pDesc
, &(WOutDev
[This
->wDevID
].ossdev
->ds_desc
), sizeof(DSDRIVERDESC
));
717 pDesc
->dwFlags
|= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
|
718 DSDDESC_USESYSTEMMEMORY
| DSDDESC_DONTNEEDPRIMARYLOCK
|
719 DSDDESC_DONTNEEDSECONDARYLOCK
;
720 pDesc
->dnDevNode
= WOutDev
[This
->wDevID
].waveDesc
.dnDevNode
;
722 pDesc
->wReserved
= 0;
723 pDesc
->ulDeviceNum
= This
->wDevID
;
724 pDesc
->dwHeapType
= DSDHEAP_NOHEAP
;
725 pDesc
->pvDirectDrawHeap
= NULL
;
726 pDesc
->dwMemStartAddress
= 0;
727 pDesc
->dwMemEndAddress
= 0;
728 pDesc
->dwMemAllocExtra
= 0;
729 pDesc
->pvReserved1
= NULL
;
730 pDesc
->pvReserved2
= NULL
;
734 static HRESULT WINAPI
IDsDriverImpl_Open(PIDSDRIVER iface
)
736 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
738 TRACE("(%p)\n",iface
);
740 /* make sure the card doesn't start playing before we want it to */
741 WOutDev
[This
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
742 WOutDev
[This
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
743 enable
= getEnables(WOutDev
[This
->wDevID
].ossdev
);
744 if (ioctl(WOutDev
[This
->wDevID
].ossdev
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
745 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
746 return DSERR_GENERIC
;
751 static HRESULT WINAPI
IDsDriverImpl_Close(PIDSDRIVER iface
)
753 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
754 TRACE("(%p)\n",iface
);
756 ERR("problem with DirectSound: primary not released\n");
757 return DSERR_GENERIC
;
762 static HRESULT WINAPI
IDsDriverImpl_GetCaps(PIDSDRIVER iface
, PDSDRIVERCAPS pCaps
)
764 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
765 TRACE("(%p,%p)\n",iface
,pCaps
);
766 memcpy(pCaps
, &(WOutDev
[This
->wDevID
].ossdev
->ds_caps
), sizeof(DSDRIVERCAPS
));
770 static HRESULT WINAPI
DSD_CreatePrimaryBuffer(PIDSDRIVER iface
,
774 LPDWORD pdwcbBufferSize
,
778 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
779 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
783 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
786 return DSERR_ALLOCATED
;
787 if (dwFlags
& (DSBCAPS_CTRLFREQUENCY
| DSBCAPS_CTRLPAN
))
788 return DSERR_CONTROLUNAVAIL
;
790 *ippdsdb
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverBufferImpl
));
791 if (*ippdsdb
== NULL
)
792 return DSERR_OUTOFMEMORY
;
793 (*ippdsdb
)->lpVtbl
= &dsdbvt
;
795 (*ippdsdb
)->drv
= This
;
796 copy_format(pwfx
, &(*ippdsdb
)->wfex
);
797 (*ippdsdb
)->fd
= WOutDev
[This
->wDevID
].ossdev
->fd
;
798 (*ippdsdb
)->dwFlags
= dwFlags
;
800 /* check how big the DMA buffer is now */
801 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
802 ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
803 WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
804 HeapFree(GetProcessHeap(),0,*ippdsdb
);
806 return DSERR_GENERIC
;
808 (*ippdsdb
)->maplen
= (*ippdsdb
)->buflen
= info
.fragstotal
* info
.fragsize
;
810 /* map the DMA buffer */
811 err
= DSDB_MapBuffer(*ippdsdb
);
813 HeapFree(GetProcessHeap(),0,*ippdsdb
);
818 /* primary buffer is ready to go */
819 *pdwcbBufferSize
= (*ippdsdb
)->maplen
;
820 *ppbBuffer
= (*ippdsdb
)->mapping
;
822 /* some drivers need some extra nudging after mapping */
823 WOutDev
[This
->wDevID
].ossdev
->bInputEnabled
= FALSE
;
824 WOutDev
[This
->wDevID
].ossdev
->bOutputEnabled
= FALSE
;
825 enable
= getEnables(WOutDev
[This
->wDevID
].ossdev
);
826 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
827 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
828 WOutDev
[This
->wDevID
].ossdev
->dev_name
, strerror(errno
));
829 return DSERR_GENERIC
;
832 This
->primary
= *ippdsdb
;
837 static HRESULT WINAPI
DSD_CreateSecondaryBuffer(PIDSDRIVER iface
,
841 LPDWORD pdwcbBufferSize
,
845 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
846 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
847 FIXME("(%p,%p,%x,%x,%p,%p,%p): stub\n",This
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
850 return DSERR_UNSUPPORTED
;
853 static HRESULT WINAPI
IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface
,
857 LPDWORD pdwcbBufferSize
,
861 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
863 if (dwFlags
& DSBCAPS_PRIMARYBUFFER
)
864 return DSD_CreatePrimaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
866 return DSD_CreateSecondaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
869 static HRESULT WINAPI
IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface
,
870 PIDSDRIVERBUFFER pBuffer
,
873 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
874 TRACE("(%p,%p): stub\n",iface
,pBuffer
);
875 return DSERR_INVALIDCALL
;
878 static const IDsDriverVtbl dsdvt
=
880 IDsDriverImpl_QueryInterface
,
881 IDsDriverImpl_AddRef
,
882 IDsDriverImpl_Release
,
883 IDsDriverImpl_GetDriverDesc
,
886 IDsDriverImpl_GetCaps
,
887 IDsDriverImpl_CreateSoundBuffer
,
888 IDsDriverImpl_DuplicateSoundBuffer
891 static HRESULT WINAPI
IDsDriverPropertySetImpl_Create(
892 IDsDriverBufferImpl
* dsdb
,
893 IDsDriverPropertySetImpl
**pdsdps
)
895 IDsDriverPropertySetImpl
* dsdps
;
896 TRACE("(%p,%p)\n",dsdb
,pdsdps
);
898 dsdps
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(dsdps
));
900 WARN("out of memory\n");
901 return DSERR_OUTOFMEMORY
;
905 dsdps
->lpVtbl
= &dsdpsvt
;
906 dsdps
->buffer
= dsdb
;
907 dsdb
->property_set
= dsdps
;
908 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
914 static HRESULT WINAPI
IDsDriverNotifyImpl_Create(
915 IDsDriverBufferImpl
* dsdb
,
916 IDsDriverNotifyImpl
**pdsdn
)
918 IDsDriverNotifyImpl
* dsdn
;
919 TRACE("(%p,%p)\n",dsdb
,pdsdn
);
921 dsdn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(dsdn
));
924 WARN("out of memory\n");
925 return DSERR_OUTOFMEMORY
;
929 dsdn
->lpVtbl
= &dsdnvt
;
932 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
938 DWORD
wodDsCreate(UINT wDevID
, PIDSDRIVER
* drv
)
940 IDsDriverImpl
** idrv
= (IDsDriverImpl
**)drv
;
941 TRACE("(%d,%p)\n",wDevID
,drv
);
943 /* the HAL isn't much better than the HEL if we can't do mmap() */
944 if (!(WOutDev
[wDevID
].ossdev
->duplex_out_caps
.dwSupport
& WAVECAPS_DIRECTSOUND
)) {
945 ERR("DirectSound flag not set\n");
946 MESSAGE("This sound card's driver does not support direct access\n");
947 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
948 return MMSYSERR_NOTSUPPORTED
;
951 *idrv
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverImpl
));
953 return MMSYSERR_NOMEM
;
954 (*idrv
)->lpVtbl
= &dsdvt
;
956 (*idrv
)->wDevID
= wDevID
;
957 (*idrv
)->primary
= NULL
;
958 (*idrv
)->nrofsecondaries
= 0;
959 (*idrv
)->secondaries
= NULL
;
961 return MMSYSERR_NOERROR
;
964 DWORD
wodDsDesc(UINT wDevID
, PDSDRIVERDESC desc
)
966 TRACE("(%d,%p)\n",wDevID
,desc
);
967 memcpy(desc
, &(WOutDev
[wDevID
].ossdev
->ds_desc
), sizeof(DSDRIVERDESC
));
968 return MMSYSERR_NOERROR
;
971 #endif /* HAVE_OSS */