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>
48 #ifdef HAVE_SYS_ERRNO_H
49 #include <sys/errno.h>
51 #include <sys/soundcard.h>
62 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
68 /*======================================================================*
69 * Low level DSOUND definitions *
70 *======================================================================*/
72 typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl
;
73 typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl
;
74 typedef struct IDsDriverImpl IDsDriverImpl
;
75 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl
;
77 struct IDsDriverPropertySetImpl
80 const IDsDriverPropertySetVtbl
*lpVtbl
;
83 IDsDriverBufferImpl
* buffer
;
86 struct IDsDriverNotifyImpl
89 const IDsDriverNotifyVtbl
*lpVtbl
;
92 /* IDsDriverNotifyImpl fields */
93 LPDSBPOSITIONNOTIFY notifies
;
96 IDsDriverBufferImpl
* buffer
;
101 /* IUnknown fields */
102 const IDsDriverVtbl
*lpVtbl
;
105 /* IDsDriverImpl fields */
107 IDsDriverBufferImpl
* primary
;
110 IDsDriverBufferImpl
** secondaries
;
113 struct IDsDriverBufferImpl
115 /* IUnknown fields */
116 const IDsDriverBufferVtbl
*lpVtbl
;
119 /* IDsDriverBufferImpl fields */
122 WAVEFORMATPCMEX wfex
;
128 /* IDsDriverNotifyImpl fields */
129 IDsDriverNotifyImpl
* notify
;
132 /* IDsDriverPropertySetImpl fields */
133 IDsDriverPropertySetImpl
* property_set
;
136 static HRESULT
IDsDriverPropertySetImpl_Create(
137 IDsDriverBufferImpl
* dsdb
,
138 IDsDriverPropertySetImpl
**pdsdps
);
140 static HRESULT
IDsDriverNotifyImpl_Create(
141 IDsDriverBufferImpl
* dsdb
,
142 IDsDriverNotifyImpl
**pdsdn
);
144 /*======================================================================*
145 * Low level DSOUND property set implementation *
146 *======================================================================*/
148 static HRESULT WINAPI
IDsDriverPropertySetImpl_QueryInterface(
149 PIDSDRIVERPROPERTYSET iface
,
153 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
154 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
156 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
157 IsEqualGUID(riid
, &IID_IDsDriverPropertySet
) ) {
158 IDsDriverPropertySet_AddRef(iface
);
163 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
166 return E_NOINTERFACE
;
169 static ULONG WINAPI
IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface
)
171 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
172 ULONG refCount
= InterlockedIncrement(&This
->ref
);
174 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
179 static ULONG WINAPI
IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface
)
181 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
182 ULONG refCount
= InterlockedDecrement(&This
->ref
);
184 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
187 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
188 HeapFree(GetProcessHeap(),0,This
);
189 TRACE("(%p) released\n",This
);
194 static HRESULT WINAPI
IDsDriverPropertySetImpl_Get(
195 PIDSDRIVERPROPERTYSET iface
,
196 PDSPROPERTY pDsProperty
,
197 LPVOID pPropertyParams
,
198 ULONG cbPropertyParams
,
199 LPVOID pPropertyData
,
200 ULONG cbPropertyData
,
201 PULONG pcbReturnedData
)
203 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
204 FIXME("(%p,%p,%p,%x,%p,%x,%p)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
,pcbReturnedData
);
205 return DSERR_UNSUPPORTED
;
208 static HRESULT WINAPI
IDsDriverPropertySetImpl_Set(
209 PIDSDRIVERPROPERTYSET iface
,
210 PDSPROPERTY pDsProperty
,
211 LPVOID pPropertyParams
,
212 ULONG cbPropertyParams
,
213 LPVOID pPropertyData
,
214 ULONG cbPropertyData
)
216 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
217 FIXME("(%p,%p,%p,%x,%p,%x)\n",This
,pDsProperty
,pPropertyParams
,cbPropertyParams
,pPropertyData
,cbPropertyData
);
218 return DSERR_UNSUPPORTED
;
221 static HRESULT WINAPI
IDsDriverPropertySetImpl_QuerySupport(
222 PIDSDRIVERPROPERTYSET iface
,
223 REFGUID PropertySetId
,
227 IDsDriverPropertySetImpl
*This
= (IDsDriverPropertySetImpl
*)iface
;
228 FIXME("(%p,%s,%x,%p)\n",This
,debugstr_guid(PropertySetId
),PropertyId
,pSupport
);
229 return DSERR_UNSUPPORTED
;
232 static const IDsDriverPropertySetVtbl dsdpsvt
=
234 IDsDriverPropertySetImpl_QueryInterface
,
235 IDsDriverPropertySetImpl_AddRef
,
236 IDsDriverPropertySetImpl_Release
,
237 IDsDriverPropertySetImpl_Get
,
238 IDsDriverPropertySetImpl_Set
,
239 IDsDriverPropertySetImpl_QuerySupport
,
242 /*======================================================================*
243 * Low level DSOUND notify implementation *
244 *======================================================================*/
246 static HRESULT WINAPI
IDsDriverNotifyImpl_QueryInterface(
247 PIDSDRIVERNOTIFY iface
,
251 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
252 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
254 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
255 IsEqualGUID(riid
, &IID_IDsDriverNotify
) ) {
256 IDsDriverNotify_AddRef(iface
);
261 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
264 return E_NOINTERFACE
;
267 static ULONG WINAPI
IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface
)
269 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
270 ULONG refCount
= InterlockedIncrement(&This
->ref
);
272 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
277 static ULONG WINAPI
IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface
)
279 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
280 ULONG refCount
= InterlockedDecrement(&This
->ref
);
282 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
285 IDsDriverBuffer_Release((PIDSDRIVERBUFFER
)This
->buffer
);
286 HeapFree(GetProcessHeap(), 0, This
->notifies
);
287 HeapFree(GetProcessHeap(),0,This
);
288 TRACE("(%p) released\n",This
);
293 static HRESULT WINAPI
IDsDriverNotifyImpl_SetNotificationPositions(
294 PIDSDRIVERNOTIFY iface
,
296 LPCDSBPOSITIONNOTIFY notify
)
298 IDsDriverNotifyImpl
*This
= (IDsDriverNotifyImpl
*)iface
;
299 TRACE("(%p,0x%08x,%p)\n",This
,howmuch
,notify
);
302 WARN("invalid parameter\n");
303 return DSERR_INVALIDPARAM
;
306 if (TRACE_ON(wave
)) {
308 for (i
=0;i
<howmuch
;i
++)
309 TRACE("notify at %d to 0x%08lx\n",
310 notify
[i
].dwOffset
,(DWORD_PTR
)notify
[i
].hEventNotify
);
313 /* Make an internal copy of the caller-supplied array.
314 * Replace the existing copy if one is already present. */
316 This
->notifies
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
317 This
->notifies
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
319 This
->notifies
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
320 howmuch
* sizeof(DSBPOSITIONNOTIFY
));
322 memcpy(This
->notifies
, notify
, howmuch
* sizeof(DSBPOSITIONNOTIFY
));
323 This
->nrofnotifies
= howmuch
;
328 static const IDsDriverNotifyVtbl dsdnvt
=
330 IDsDriverNotifyImpl_QueryInterface
,
331 IDsDriverNotifyImpl_AddRef
,
332 IDsDriverNotifyImpl_Release
,
333 IDsDriverNotifyImpl_SetNotificationPositions
,
336 /*======================================================================*
337 * Low level DSOUND implementation *
338 *======================================================================*/
340 static HRESULT
DSDB_MapBuffer(IDsDriverBufferImpl
*dsdb
)
342 TRACE("(%p), format=%dx%dx%d\n", dsdb
, dsdb
->wfex
.Format
.nSamplesPerSec
,
343 dsdb
->wfex
.Format
.wBitsPerSample
, dsdb
->wfex
.Format
.nChannels
);
344 if (!dsdb
->mapping
) {
345 dsdb
->mapping
= mmap(NULL
, dsdb
->maplen
, PROT_WRITE
, MAP_SHARED
,
347 if (dsdb
->mapping
== (LPBYTE
)-1) {
348 WARN("Could not map sound device for direct access (%s)\n", strerror(errno
));
349 return DSERR_GENERIC
;
351 TRACE("The sound device has been mapped for direct access at %p, size=%d\n", dsdb
->mapping
, dsdb
->maplen
);
353 /* for some reason, es1371 and sblive! sometimes have junk in here.
354 * clear it, or we get junk noise */
355 /* some libc implementations are buggy: their memset reads from the buffer...
356 * to work around it, we have to zero the block by hand. We don't do the expected:
357 * memset(dsdb->mapping,0, dsdb->maplen);
360 unsigned char* p1
= dsdb
->mapping
;
361 unsigned len
= dsdb
->maplen
;
362 unsigned char silence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 128 : 0;
363 unsigned long ulsilence
= (dsdb
->wfex
.Format
.wBitsPerSample
== 8) ? 0x80808080 : 0;
365 if (len
>= 16) /* so we can have at least a 4 long area to store... */
367 /* the mmap:ed value is (at least) dword aligned
368 * so, start filling the complete unsigned long:s
371 unsigned long* p4
= (unsigned long*)p1
;
373 while (b
--) *p4
++ = ulsilence
;
374 /* prepare for filling the rest */
376 p1
= (unsigned char*)p4
;
378 /* in all cases, fill the remaining bytes */
379 while (len
-- != 0) *p1
++ = silence
;
385 static HRESULT
DSDB_UnmapBuffer(IDsDriverBufferImpl
*dsdb
)
387 TRACE("(%p)\n",dsdb
);
389 if (munmap(dsdb
->mapping
, dsdb
->maplen
) < 0) {
390 ERR("(%p): Could not unmap sound device (%s)\n", dsdb
, strerror(errno
));
391 return DSERR_GENERIC
;
393 dsdb
->mapping
= NULL
;
394 TRACE("(%p): sound device unmapped\n", dsdb
);
399 static HRESULT WINAPI
IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
401 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
402 TRACE("(%p,%s,%p)\n",iface
,debugstr_guid(riid
),*ppobj
);
404 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
405 IsEqualGUID(riid
, &IID_IDsDriverBuffer
) ) {
406 IDsDriverBuffer_AddRef(iface
);
411 if ( IsEqualGUID( &IID_IDsDriverNotify
, riid
) ) {
413 IDsDriverNotifyImpl_Create(This
, &(This
->notify
));
415 IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY
)This
->notify
);
416 *ppobj
= This
->notify
;
423 if ( IsEqualGUID( &IID_IDsDriverPropertySet
, riid
) ) {
424 if (!This
->property_set
)
425 IDsDriverPropertySetImpl_Create(This
, &(This
->property_set
));
426 if (This
->property_set
) {
427 IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET
)This
->property_set
);
428 *ppobj
= This
->property_set
;
435 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
439 return E_NOINTERFACE
;
442 static ULONG WINAPI
IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface
)
444 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
445 ULONG refCount
= InterlockedIncrement(&This
->ref
);
447 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
452 static ULONG WINAPI
IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface
)
454 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
455 ULONG refCount
= InterlockedDecrement(&This
->ref
);
457 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
462 if (This
== This
->drv
->primary
)
463 This
->drv
->primary
= NULL
;
466 for (i
= 0; i
< This
->drv
->nrofsecondaries
; i
++)
467 if (This
->drv
->secondaries
[i
] == This
)
469 if (i
< This
->drv
->nrofsecondaries
) {
470 /* Put the last buffer of the list in the (now empty) position */
471 This
->drv
->secondaries
[i
] = This
->drv
->secondaries
[This
->drv
->nrofsecondaries
- 1];
472 This
->drv
->nrofsecondaries
--;
473 This
->drv
->secondaries
= HeapReAlloc(GetProcessHeap(),0,
474 This
->drv
->secondaries
,
475 sizeof(PIDSDRIVERBUFFER
)*This
->drv
->nrofsecondaries
);
476 TRACE("(%p) buffer count is now %d\n", This
, This
->drv
->nrofsecondaries
);
479 WOutDev
[This
->drv
->wDevID
].ossdev
.ds_caps
.dwFreeHwMixingAllBuffers
++;
480 WOutDev
[This
->drv
->wDevID
].ossdev
.ds_caps
.dwFreeHwMixingStreamingBuffers
++;
483 DSDB_UnmapBuffer(This
);
484 HeapFree(GetProcessHeap(),0,This
);
485 TRACE("(%p) released\n",This
);
489 static HRESULT WINAPI
IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface
,
490 LPVOID
*ppvAudio1
,LPDWORD pdwLen1
,
491 LPVOID
*ppvAudio2
,LPDWORD pdwLen2
,
492 DWORD dwWritePosition
,DWORD dwWriteLen
,
495 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
496 /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
497 * and that we don't support secondary buffers, this method will never be called */
498 TRACE("(%p): stub\n",iface
);
499 return DSERR_UNSUPPORTED
;
502 static HRESULT WINAPI
IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface
,
503 LPVOID pvAudio1
,DWORD dwLen1
,
504 LPVOID pvAudio2
,DWORD dwLen2
)
506 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
507 TRACE("(%p): stub\n",iface
);
508 return DSERR_UNSUPPORTED
;
511 static HRESULT WINAPI
IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface
,
514 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
516 TRACE("(%p,%p)\n",iface
,pwfx
);
517 /* On our request (GetDriverDesc flags), DirectSound has by now used
518 * waveOutClose/waveOutOpen to set the format...
519 * unfortunately, this means our mmap() is now gone...
520 * so we need to somehow signal to our DirectSound implementation
521 * that it should completely recreate this HW buffer...
522 * this unexpected error code should do the trick... */
523 return DSERR_BUFFERLOST
;
526 static HRESULT WINAPI
IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface
, DWORD dwFreq
)
528 /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
529 TRACE("(%p,%d): stub\n",iface
,dwFreq
);
530 return DSERR_UNSUPPORTED
;
533 static HRESULT WINAPI
IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface
, PDSVOLUMEPAN pVolPan
)
536 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
537 TRACE("(%p,%p)\n",This
,pVolPan
);
539 vol
= pVolPan
->dwTotalLeftAmpFactor
| (pVolPan
->dwTotalRightAmpFactor
<< 16);
541 if (wodSetVolume(This
->drv
->wDevID
, vol
) != MMSYSERR_NOERROR
) {
542 WARN("wodSetVolume failed\n");
543 return DSERR_INVALIDPARAM
;
549 static HRESULT WINAPI
IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface
, DWORD dwNewPos
)
551 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
552 TRACE("(%p,%d): stub\n",iface
,dwNewPos
);
553 return DSERR_UNSUPPORTED
;
556 static HRESULT WINAPI
IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface
,
557 LPDWORD lpdwPlay
, LPDWORD lpdwWrite
)
559 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
563 TRACE("(%p)\n",iface
);
564 if (WOutDev
[This
->drv
->wDevID
].state
== WINE_WS_CLOSED
) {
565 ERR("device not open, but accessing?\n");
566 return DSERR_UNINITIALIZED
;
568 if (ioctl(This
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
569 ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
570 WOutDev
[This
->drv
->wDevID
].ossdev
.dev_name
, strerror(errno
));
571 return DSERR_GENERIC
;
573 ptr
= info
.ptr
& ~3; /* align the pointer, just in case */
574 if (lpdwPlay
) *lpdwPlay
= ptr
;
576 /* add some safety margin (not strictly necessary, but...) */
577 if (WOutDev
[This
->drv
->wDevID
].ossdev
.duplex_out_caps
.dwSupport
& WAVECAPS_SAMPLEACCURATE
)
578 *lpdwWrite
= ptr
+ 32;
580 *lpdwWrite
= ptr
+ WOutDev
[This
->drv
->wDevID
].dwFragmentSize
;
581 while (*lpdwWrite
>= This
->buflen
)
582 *lpdwWrite
-= This
->buflen
;
584 TRACE("playpos=%d, writepos=%d\n", lpdwPlay
?*lpdwPlay
:0, lpdwWrite
?*lpdwWrite
:0);
588 static HRESULT WINAPI
IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface
, DWORD dwRes1
, DWORD dwRes2
, DWORD dwFlags
)
590 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
592 TRACE("(%p,%x,%x,%x)\n",iface
,dwRes1
,dwRes2
,dwFlags
);
593 WOutDev
[This
->drv
->wDevID
].ossdev
.bOutputEnabled
= TRUE
;
594 enable
= getEnables(&WOutDev
[This
->drv
->wDevID
].ossdev
);
595 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
596 if (errno
== EINVAL
) {
597 /* Don't give up yet. OSS trigger support is inconsistent. */
598 if (WOutDev
[This
->drv
->wDevID
].ossdev
.open_count
== 1) {
599 /* try the opposite input enable */
600 if (WOutDev
[This
->drv
->wDevID
].ossdev
.bInputEnabled
== FALSE
)
601 WOutDev
[This
->drv
->wDevID
].ossdev
.bInputEnabled
= TRUE
;
603 WOutDev
[This
->drv
->wDevID
].ossdev
.bInputEnabled
= FALSE
;
605 enable
= getEnables(&WOutDev
[This
->drv
->wDevID
].ossdev
);
606 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) >= 0)
610 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
611 WOutDev
[This
->drv
->wDevID
].ossdev
.dev_name
, strerror(errno
));
612 WOutDev
[This
->drv
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
613 return DSERR_GENERIC
;
618 static HRESULT WINAPI
IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface
)
620 IDsDriverBufferImpl
*This
= (IDsDriverBufferImpl
*)iface
;
622 TRACE("(%p)\n",iface
);
623 /* no more playing */
624 WOutDev
[This
->drv
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
625 enable
= getEnables(&WOutDev
[This
->drv
->wDevID
].ossdev
);
626 if (ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
627 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
.dev_name
, strerror(errno
));
628 return DSERR_GENERIC
;
631 /* the play position must be reset to the beginning of the buffer */
632 if (ioctl(This
->fd
, SNDCTL_DSP_RESET
, 0) < 0) {
633 ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev
[This
->drv
->wDevID
].ossdev
.dev_name
, strerror(errno
));
634 return DSERR_GENERIC
;
637 /* Most OSS drivers just can't stop the playback without closing the device...
638 * so we need to somehow signal to our DirectSound implementation
639 * that it should completely recreate this HW buffer...
640 * this unexpected error code should do the trick... */
641 /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
642 if (WOutDev
[This
->drv
->wDevID
].ossdev
.open_count
== 1)
643 return DSERR_BUFFERLOST
;
648 static const IDsDriverBufferVtbl dsdbvt
=
650 IDsDriverBufferImpl_QueryInterface
,
651 IDsDriverBufferImpl_AddRef
,
652 IDsDriverBufferImpl_Release
,
653 IDsDriverBufferImpl_Lock
,
654 IDsDriverBufferImpl_Unlock
,
655 IDsDriverBufferImpl_SetFormat
,
656 IDsDriverBufferImpl_SetFrequency
,
657 IDsDriverBufferImpl_SetVolumePan
,
658 IDsDriverBufferImpl_SetPosition
,
659 IDsDriverBufferImpl_GetPosition
,
660 IDsDriverBufferImpl_Play
,
661 IDsDriverBufferImpl_Stop
664 static HRESULT WINAPI
IDsDriverImpl_QueryInterface(PIDSDRIVER iface
, REFIID riid
, LPVOID
*ppobj
)
666 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
667 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
669 if ( IsEqualGUID(riid
, &IID_IUnknown
) ||
670 IsEqualGUID(riid
, &IID_IDsDriver
) ) {
671 IDsDriver_AddRef(iface
);
676 FIXME( "Unknown IID %s\n", debugstr_guid( riid
) );
680 return E_NOINTERFACE
;
683 static ULONG WINAPI
IDsDriverImpl_AddRef(PIDSDRIVER iface
)
685 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
686 ULONG refCount
= InterlockedIncrement(&This
->ref
);
688 TRACE("(%p) ref was %d\n", This
, refCount
- 1);
693 static ULONG WINAPI
IDsDriverImpl_Release(PIDSDRIVER iface
)
695 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
696 ULONG refCount
= InterlockedDecrement(&This
->ref
);
698 TRACE("(%p) ref was %d\n", This
, refCount
+ 1);
701 HeapFree(GetProcessHeap(),0,This
);
702 TRACE("(%p) released\n",This
);
707 static HRESULT WINAPI
IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface
,
710 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
711 TRACE("(%p,%p)\n",iface
,pDesc
);
713 /* copy version from driver */
714 *pDesc
= WOutDev
[This
->wDevID
].ossdev
.ds_desc
;
716 pDesc
->dwFlags
|= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
|
717 DSDDESC_USESYSTEMMEMORY
| DSDDESC_DONTNEEDPRIMARYLOCK
|
718 DSDDESC_DONTNEEDSECONDARYLOCK
;
719 pDesc
->dnDevNode
= WOutDev
[This
->wDevID
].waveDesc
.dnDevNode
;
721 pDesc
->wReserved
= 0;
722 pDesc
->ulDeviceNum
= This
->wDevID
;
723 pDesc
->dwHeapType
= DSDHEAP_NOHEAP
;
724 pDesc
->pvDirectDrawHeap
= NULL
;
725 pDesc
->dwMemStartAddress
= 0;
726 pDesc
->dwMemEndAddress
= 0;
727 pDesc
->dwMemAllocExtra
= 0;
728 pDesc
->pvReserved1
= NULL
;
729 pDesc
->pvReserved2
= NULL
;
733 static HRESULT WINAPI
IDsDriverImpl_Open(PIDSDRIVER iface
)
735 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
737 TRACE("(%p)\n",iface
);
739 /* make sure the card doesn't start playing before we want it to */
740 WOutDev
[This
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
741 WOutDev
[This
->wDevID
].ossdev
.bInputEnabled
= FALSE
;
742 enable
= getEnables(&WOutDev
[This
->wDevID
].ossdev
);
743 if (ioctl(WOutDev
[This
->wDevID
].ossdev
.fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
744 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev
[This
->wDevID
].ossdev
.dev_name
, strerror(errno
));
745 return DSERR_GENERIC
;
750 static HRESULT WINAPI
IDsDriverImpl_Close(PIDSDRIVER iface
)
752 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
753 TRACE("(%p)\n",iface
);
755 ERR("problem with DirectSound: primary not released\n");
756 return DSERR_GENERIC
;
761 static HRESULT WINAPI
IDsDriverImpl_GetCaps(PIDSDRIVER iface
, PDSDRIVERCAPS pCaps
)
763 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
764 TRACE("(%p,%p)\n",iface
,pCaps
);
765 *pCaps
= WOutDev
[This
->wDevID
].ossdev
.ds_caps
;
769 static HRESULT
DSD_CreatePrimaryBuffer(PIDSDRIVER iface
,
773 LPDWORD pdwcbBufferSize
,
777 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
778 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
782 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
785 return DSERR_ALLOCATED
;
786 if (dwFlags
& (DSBCAPS_CTRLFREQUENCY
| DSBCAPS_CTRLPAN
))
787 return DSERR_CONTROLUNAVAIL
;
789 *ippdsdb
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverBufferImpl
));
790 if (*ippdsdb
== NULL
)
791 return DSERR_OUTOFMEMORY
;
792 (*ippdsdb
)->lpVtbl
= &dsdbvt
;
794 (*ippdsdb
)->drv
= This
;
795 copy_format(pwfx
, &(*ippdsdb
)->wfex
);
796 (*ippdsdb
)->fd
= WOutDev
[This
->wDevID
].ossdev
.fd
;
797 (*ippdsdb
)->dwFlags
= dwFlags
;
799 /* check how big the DMA buffer is now */
800 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
801 ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
802 WOutDev
[This
->wDevID
].ossdev
.dev_name
, strerror(errno
));
803 HeapFree(GetProcessHeap(),0,*ippdsdb
);
805 return DSERR_GENERIC
;
807 (*ippdsdb
)->maplen
= (*ippdsdb
)->buflen
= info
.fragstotal
* info
.fragsize
;
809 /* map the DMA buffer */
810 err
= DSDB_MapBuffer(*ippdsdb
);
812 HeapFree(GetProcessHeap(),0,*ippdsdb
);
817 /* primary buffer is ready to go */
818 *pdwcbBufferSize
= (*ippdsdb
)->maplen
;
819 *ppbBuffer
= (*ippdsdb
)->mapping
;
821 /* some drivers need some extra nudging after mapping */
822 WOutDev
[This
->wDevID
].ossdev
.bInputEnabled
= FALSE
;
823 WOutDev
[This
->wDevID
].ossdev
.bOutputEnabled
= FALSE
;
824 enable
= getEnables(&WOutDev
[This
->wDevID
].ossdev
);
825 if (ioctl((*ippdsdb
)->fd
, SNDCTL_DSP_SETTRIGGER
, &enable
) < 0) {
826 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
827 WOutDev
[This
->wDevID
].ossdev
.dev_name
, strerror(errno
));
828 return DSERR_GENERIC
;
831 This
->primary
= *ippdsdb
;
836 static HRESULT
DSD_CreateSecondaryBuffer(PIDSDRIVER iface
,
840 LPDWORD pdwcbBufferSize
,
844 IDsDriverImpl
*This
= (IDsDriverImpl
*)iface
;
845 IDsDriverBufferImpl
** ippdsdb
= (IDsDriverBufferImpl
**)ppvObj
;
846 FIXME("(%p,%p,%x,%x,%p,%p,%p): stub\n",This
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
849 return DSERR_UNSUPPORTED
;
852 static HRESULT WINAPI
IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface
,
856 LPDWORD pdwcbBufferSize
,
860 TRACE("(%p,%p,%x,%x,%p,%p,%p)\n",iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
862 if (dwFlags
& DSBCAPS_PRIMARYBUFFER
)
863 return DSD_CreatePrimaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
865 return DSD_CreateSecondaryBuffer(iface
,pwfx
,dwFlags
,dwCardAddress
,pdwcbBufferSize
,ppbBuffer
,ppvObj
);
868 static HRESULT WINAPI
IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface
,
869 PIDSDRIVERBUFFER pBuffer
,
872 /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
873 TRACE("(%p,%p): stub\n",iface
,pBuffer
);
874 return DSERR_INVALIDCALL
;
877 static const IDsDriverVtbl dsdvt
=
879 IDsDriverImpl_QueryInterface
,
880 IDsDriverImpl_AddRef
,
881 IDsDriverImpl_Release
,
882 IDsDriverImpl_GetDriverDesc
,
885 IDsDriverImpl_GetCaps
,
886 IDsDriverImpl_CreateSoundBuffer
,
887 IDsDriverImpl_DuplicateSoundBuffer
890 static HRESULT
IDsDriverPropertySetImpl_Create(
891 IDsDriverBufferImpl
* dsdb
,
892 IDsDriverPropertySetImpl
**pdsdps
)
894 IDsDriverPropertySetImpl
* dsdps
;
895 TRACE("(%p,%p)\n",dsdb
,pdsdps
);
897 dsdps
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*dsdps
));
899 WARN("out of memory\n");
900 return DSERR_OUTOFMEMORY
;
904 dsdps
->lpVtbl
= &dsdpsvt
;
905 dsdps
->buffer
= dsdb
;
906 dsdb
->property_set
= dsdps
;
907 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
913 static HRESULT
IDsDriverNotifyImpl_Create(
914 IDsDriverBufferImpl
* dsdb
,
915 IDsDriverNotifyImpl
**pdsdn
)
917 IDsDriverNotifyImpl
* dsdn
;
918 TRACE("(%p,%p)\n",dsdb
,pdsdn
);
920 dsdn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*dsdn
));
923 WARN("out of memory\n");
924 return DSERR_OUTOFMEMORY
;
928 dsdn
->lpVtbl
= &dsdnvt
;
931 IDsDriverBuffer_AddRef((PIDSDRIVER
)dsdb
);
937 DWORD
wodDsCreate(UINT wDevID
, PIDSDRIVER
* drv
)
939 IDsDriverImpl
** idrv
= (IDsDriverImpl
**)drv
;
940 TRACE("(%d,%p)\n",wDevID
,drv
);
942 /* the HAL isn't much better than the HEL if we can't do mmap() */
943 if (!(WOutDev
[wDevID
].ossdev
.duplex_out_caps
.dwSupport
& WAVECAPS_DIRECTSOUND
)) {
944 WARN("Warn DirectSound flag not set, falling back to HEL layer\n");
945 return MMSYSERR_NOTSUPPORTED
;
948 *idrv
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDsDriverImpl
));
950 return MMSYSERR_NOMEM
;
951 (*idrv
)->lpVtbl
= &dsdvt
;
953 (*idrv
)->wDevID
= wDevID
;
954 (*idrv
)->primary
= NULL
;
955 (*idrv
)->nrofsecondaries
= 0;
956 (*idrv
)->secondaries
= NULL
;
958 return MMSYSERR_NOERROR
;
961 DWORD
wodDsDesc(UINT wDevID
, PDSDRIVERDESC desc
)
963 TRACE("(%d,%p)\n",wDevID
,desc
);
964 *desc
= WOutDev
[wDevID
].ossdev
.ds_desc
;
965 return MMSYSERR_NOERROR
;