audio.c: OSS functions and waveIn and waveOut driver functions.
dscapture.c: direct sound capture driver implementation.
dsrender.c: direct sound renderer driver implementation.
C_SRCS = \
audio.c \
+ dscapture.c \
+ dsrender.c \
midi.c \
midipatch.c \
mixer.c \
-/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
*
/*#define EMULATE_SB16*/
-/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
-#define USE_PIPE_SYNC
-
/* an exact wodGetPosition is usually not worth the extra context switches,
* as we're going to have near fragment accuracy anyway */
#define EXACT_WODPOSITION
#include "oss.h"
#include "wine/debug.h"
+#include "audio.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(wave);
/* Allow 1% deviation for sample rates (some ES137x cards) */
#ifdef HAVE_OSS
-#define MAX_WAVEDRV (6)
+OSS_DEVICE OSS_Devices[MAX_WAVEDRV];
+WINE_WAVEOUT WOutDev[MAX_WAVEDRV];
+WINE_WAVEIN WInDev[MAX_WAVEDRV];
+unsigned numOutDev;
+unsigned numInDev;
/* state diagram for waveOut writing:
*
* +---------+-------------+---------------+---------------------------------+
*/
-/* states of the playing device */
-#define WINE_WS_PLAYING 0
-#define WINE_WS_PAUSED 1
-#define WINE_WS_STOPPED 2
-#define WINE_WS_CLOSED 3
-
-/* events to be send to device */
-enum win_wm_message {
- WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
- WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
-};
-
-#ifdef USE_PIPE_SYNC
-#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
-#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
-#define RESET_OMR(omr) do { } while (0)
-#define WAIT_OMR(omr, sleep) \
- do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
- pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
-#else
-#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
-#define CLEAR_OMR(omr) do { } while (0)
-#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
-#define WAIT_OMR(omr, sleep) \
- do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
-#endif
-
-typedef struct {
- enum win_wm_message msg; /* message identifier */
- DWORD param; /* parameter for this message */
- HANDLE hEvent; /* if message is synchronous, handle of event for synchro */
-} OSS_MSG;
-
-/* implement an in-process message ring for better performance
- * (compared to passing thru the server)
- * this ring will be used by the input (resp output) record (resp playback) routine
- */
-#define OSS_RING_BUFFER_INCREMENT 64
-typedef struct {
- int ring_buffer_size;
- OSS_MSG * messages;
- int msg_tosave;
- int msg_toget;
-#ifdef USE_PIPE_SYNC
- int msg_pipe[2];
-#else
- HANDLE msg_event;
-#endif
- CRITICAL_SECTION msg_crst;
-} OSS_MSG_RING;
-
-typedef struct tagOSS_DEVICE {
- char* dev_name;
- char* mixer_name;
- char* interface_name;
- unsigned open_count;
- WAVEOUTCAPSA out_caps;
- WAVEOUTCAPSA duplex_out_caps;
- WAVEINCAPSA in_caps;
- DWORD in_caps_support;
- unsigned open_access;
- int fd;
- DWORD owner_tid;
- int sample_rate;
- int stereo;
- int format;
- unsigned audio_fragment;
- BOOL full_duplex;
- BOOL bTriggerSupport;
- BOOL bOutputEnabled;
- BOOL bInputEnabled;
- DSDRIVERDESC ds_desc;
- DSDRIVERCAPS ds_caps;
- DSCDRIVERCAPS dsc_caps;
-} OSS_DEVICE;
-
-static OSS_DEVICE OSS_Devices[MAX_WAVEDRV];
-
-typedef struct {
- OSS_DEVICE* ossdev;
- volatile int state; /* one of the WINE_WS_ manifest constants */
- WAVEOPENDESC waveDesc;
- WORD wFlags;
- WAVEFORMATPCMEX waveFormat;
- DWORD volume;
-
- /* OSS information */
- DWORD dwFragmentSize; /* size of OSS buffer fragment */
- DWORD dwBufferSize; /* size of whole OSS buffer in bytes */
- LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */
- LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */
- DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */
-
- LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */
- DWORD dwLoops; /* private copy of loop counter */
-
- DWORD dwPlayedTotal; /* number of bytes actually played since opening */
- DWORD dwWrittenTotal; /* number of bytes written to OSS buffer since opening */
- BOOL bNeedPost; /* whether audio still needs to be physically started */
-
- /* synchronization stuff */
- HANDLE hStartUpEvent;
- HANDLE hThread;
- DWORD dwThreadID;
- OSS_MSG_RING msgRing;
-} WINE_WAVEOUT;
-
-typedef struct {
- OSS_DEVICE* ossdev;
- volatile int state;
- DWORD dwFragmentSize; /* OpenSound '/dev/dsp' give us that size */
- WAVEOPENDESC waveDesc;
- WORD wFlags;
- WAVEFORMATPCMEX waveFormat;
- LPWAVEHDR lpQueuePtr;
- DWORD dwTotalRecorded;
- DWORD dwTotalRead;
-
- /* synchronization stuff */
- HANDLE hThread;
- DWORD dwThreadID;
- HANDLE hStartUpEvent;
- OSS_MSG_RING msgRing;
-} WINE_WAVEIN;
-
-static WINE_WAVEOUT WOutDev [MAX_WAVEDRV];
-static WINE_WAVEIN WInDev [MAX_WAVEDRV];
-static unsigned numOutDev;
-static unsigned numInDev;
-
-static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
-static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);
-static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
-static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc);
-
/* These strings used only for tracing */
static const char * getCmdString(enum win_wm_message msg)
{
return unknown;
};
-static int getEnables(OSS_DEVICE *ossdev)
+int getEnables(OSS_DEVICE *ossdev)
{
return ( (ossdev->bOutputEnabled ? PCM_ENABLE_OUTPUT : 0) |
(ossdev->bInputEnabled ? PCM_ENABLE_INPUT : 0) );
return FALSE;
}
-static void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
+void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
{
ZeroMemory(wf2, sizeof(wf2));
if (wf1->wFormatTag == WAVE_FORMAT_PCM)
* open the device for both waveout and wavein streams...
* this is hackish, but it's the way OSS interface is done...
*/
-static DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
+DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
int* frag, int strict_format,
int sample_rate, int stereo, int fmt)
{
*
*
*/
-static void OSS_CloseDevice(OSS_DEVICE* ossdev)
+void OSS_CloseDevice(OSS_DEVICE* ossdev)
{
TRACE("(%p)\n",ossdev);
if (ossdev->open_count>0) {
/**************************************************************************
* wodOpen [internal]
*/
-static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{
int audio_fragment;
WINE_WAVEOUT* wwo;
/**************************************************************************
* wodSetVolume [internal]
*/
-static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
+DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
{
int mixer;
int volume;
return MMSYSERR_NOTSUPPORTED;
}
-/*======================================================================*
- * Low level DSOUND definitions *
- *======================================================================*/
-
-typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl;
-typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl;
-typedef struct IDsDriverImpl IDsDriverImpl;
-typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
-
-struct IDsDriverPropertySetImpl
-{
- /* IUnknown fields */
- IDsDriverPropertySetVtbl *lpVtbl;
- DWORD ref;
-
- IDsDriverBufferImpl* buffer;
-};
-
-struct IDsDriverNotifyImpl
-{
- /* IUnknown fields */
- IDsDriverNotifyVtbl *lpVtbl;
- DWORD ref;
-
- /* IDsDriverNotifyImpl fields */
- LPDSBPOSITIONNOTIFY notifies;
- int nrofnotifies;
-
- IDsDriverBufferImpl* buffer;
-};
-
-struct IDsDriverImpl
-{
- /* IUnknown fields */
- IDsDriverVtbl *lpVtbl;
- DWORD ref;
-
- /* IDsDriverImpl fields */
- UINT wDevID;
- IDsDriverBufferImpl* primary;
-
- int nrofsecondaries;
- IDsDriverBufferImpl** secondaries;
-};
-
-struct IDsDriverBufferImpl
-{
- /* IUnknown fields */
- IDsDriverBufferVtbl *lpVtbl;
- DWORD ref;
-
- /* IDsDriverBufferImpl fields */
- IDsDriverImpl* drv;
- DWORD buflen;
- WAVEFORMATPCMEX wfex;
- LPBYTE mapping;
- DWORD maplen;
- int fd;
- DWORD dwFlags;
-
- /* IDsDriverNotifyImpl fields */
- IDsDriverNotifyImpl* notify;
- int notify_index;
-
- /* IDsDriverPropertySetImpl fields */
- IDsDriverPropertySetImpl* property_set;
-};
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
- IDsDriverBufferImpl * dsdb,
- IDsDriverPropertySetImpl **pdsdps);
-
-static HRESULT WINAPI IDsDriverNotifyImpl_Create(
- IDsDriverBufferImpl * dsdb,
- IDsDriverNotifyImpl **pdsdn);
-
-/*======================================================================*
- * Low level DSOUND property set implementation *
- *======================================================================*/
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_QueryInterface(
- PIDSDRIVERPROPERTYSET iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
- IDsDriverPropertySet_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface)
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface)
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Get(
- PIDSDRIVERPROPERTYSET iface,
- PDSPROPERTY pDsProperty,
- LPVOID pPropertyParams,
- ULONG cbPropertyParams,
- LPVOID pPropertyData,
- ULONG cbPropertyData,
- PULONG pcbReturnedData )
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Set(
- PIDSDRIVERPROPERTYSET iface,
- PDSPROPERTY pDsProperty,
- LPVOID pPropertyParams,
- ULONG cbPropertyParams,
- LPVOID pPropertyData,
- ULONG cbPropertyData )
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_QuerySupport(
- PIDSDRIVERPROPERTYSET iface,
- REFGUID PropertySetId,
- ULONG PropertyId,
- PULONG pSupport )
-{
- IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
- FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,pSupport);
- return DSERR_UNSUPPORTED;
-}
-
-IDsDriverPropertySetVtbl dsdpsvt =
-{
- IDsDriverPropertySetImpl_QueryInterface,
- IDsDriverPropertySetImpl_AddRef,
- IDsDriverPropertySetImpl_Release,
- IDsDriverPropertySetImpl_Get,
- IDsDriverPropertySetImpl_Set,
- IDsDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- * Low level DSOUND notify implementation *
- *======================================================================*/
-
-static HRESULT WINAPI IDsDriverNotifyImpl_QueryInterface(
- PIDSDRIVERNOTIFY iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
- IDsDriverNotify_AddRef(iface);
- *ppobj = This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
-{
- IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
-{
- IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
- if (This->notifies != NULL)
- HeapFree(GetProcessHeap(), 0, This->notifies);
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsDriverNotifyImpl_SetNotificationPositions(
- PIDSDRIVERNOTIFY iface,
- DWORD howmuch,
- LPCDSBPOSITIONNOTIFY notify)
-{
- IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
- TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
-
- if (!notify) {
- WARN("invalid parameter\n");
- return DSERR_INVALIDPARAM;
- }
-
- if (TRACE_ON(wave)) {
- int i;
- for (i=0;i<howmuch;i++)
- TRACE("notify at %ld to 0x%08lx\n",
- notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
- }
-
- /* Make an internal copy of the caller-supplied array.
- * Replace the existing copy if one is already present. */
- if (This->notifies)
- This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
- else
- This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
- howmuch * sizeof(DSBPOSITIONNOTIFY));
-
- memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
- This->nrofnotifies = howmuch;
-
- return S_OK;
-}
-
-IDsDriverNotifyVtbl dsdnvt =
-{
- IDsDriverNotifyImpl_QueryInterface,
- IDsDriverNotifyImpl_AddRef,
- IDsDriverNotifyImpl_Release,
- IDsDriverNotifyImpl_SetNotificationPositions,
-};
-
-/*======================================================================*
- * Low level DSOUND implementation *
- *======================================================================*/
-
-static HRESULT DSDB_MapBuffer(IDsDriverBufferImpl *dsdb)
-{
- TRACE("(%p), format=%ldx%dx%d\n", dsdb, dsdb->wfex.Format.nSamplesPerSec,
- dsdb->wfex.Format.wBitsPerSample, dsdb->wfex.Format.nChannels);
- if (!dsdb->mapping) {
- dsdb->mapping = mmap(NULL, dsdb->maplen, PROT_WRITE, MAP_SHARED,
- dsdb->fd, 0);
- if (dsdb->mapping == (LPBYTE)-1) {
- ERR("Could not map sound device for direct access (%s)\n", strerror(errno));
- ERR("Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n");
- return DSERR_GENERIC;
- }
- TRACE("The sound device has been mapped for direct access at %p, size=%ld\n", dsdb->mapping, dsdb->maplen);
-
- /* for some reason, es1371 and sblive! sometimes have junk in here.
- * clear it, or we get junk noise */
- /* some libc implementations are buggy: their memset reads from the buffer...
- * to work around it, we have to zero the block by hand. We don't do the expected:
- * memset(dsdb->mapping,0, dsdb->maplen);
- */
- {
- unsigned char* p1 = dsdb->mapping;
- unsigned len = dsdb->maplen;
- unsigned char silence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 128 : 0;
- unsigned long ulsilence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 0x80808080 : 0;
-
- if (len >= 16) /* so we can have at least a 4 long area to store... */
- {
- /* the mmap:ed value is (at least) dword aligned
- * so, start filling the complete unsigned long:s
- */
- int b = len >> 2;
- unsigned long* p4 = (unsigned long*)p1;
-
- while (b--) *p4++ = ulsilence;
- /* prepare for filling the rest */
- len &= 3;
- p1 = (unsigned char*)p4;
- }
- /* in all cases, fill the remaining bytes */
- while (len-- != 0) *p1++ = silence;
- }
- }
- return DS_OK;
-}
-
-static HRESULT DSDB_UnmapBuffer(IDsDriverBufferImpl *dsdb)
-{
- TRACE("(%p)\n",dsdb);
- if (dsdb->mapping) {
- if (munmap(dsdb->mapping, dsdb->maplen) < 0) {
- ERR("(%p): Could not unmap sound device (%s)\n", dsdb, strerror(errno));
- return DSERR_GENERIC;
- }
- dsdb->mapping = NULL;
- TRACE("(%p): sound device unmapped\n", dsdb);
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),*ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriverBuffer) ) {
- IDsDriverBuffer_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
- if (!This->notify)
- IDsDriverNotifyImpl_Create(This, &(This->notify));
- if (This->notify) {
- IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
- *ppobj = (LPVOID)This->notify;
- return DS_OK;
- }
- *ppobj = 0;
- return E_FAIL;
- }
-
- if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
- if (!This->property_set)
- IDsDriverPropertySetImpl_Create(This, &(This->property_set));
- if (This->property_set) {
- IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
- *ppobj = (LPVOID)This->property_set;
- return DS_OK;
- }
- *ppobj = 0;
- return E_FAIL;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
-
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref)
- return ref;
-
- if (This == This->drv->primary)
- This->drv->primary = NULL;
- else {
- int i;
- for (i = 0; i < This->drv->nrofsecondaries; i++)
- if (This->drv->secondaries[i] == This)
- break;
- if (i < This->drv->nrofsecondaries) {
- /* Put the last buffer of the list in the (now empty) position */
- This->drv->secondaries[i] = This->drv->secondaries[This->drv->nrofsecondaries - 1];
- This->drv->nrofsecondaries--;
- This->drv->secondaries = HeapReAlloc(GetProcessHeap(),0,
- This->drv->secondaries,
- sizeof(PIDSDRIVERBUFFER)*This->drv->nrofsecondaries);
- TRACE("(%p) buffer count is now %d\n", This, This->drv->nrofsecondaries);
- }
-
- WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingAllBuffers++;
- WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingStreamingBuffers++;
- }
-
- DSDB_UnmapBuffer(This);
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- return 0;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
- LPVOID*ppvAudio1,LPDWORD pdwLen1,
- LPVOID*ppvAudio2,LPDWORD pdwLen2,
- DWORD dwWritePosition,DWORD dwWriteLen,
- DWORD dwFlags)
-{
- /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
- /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
- * and that we don't support secondary buffers, this method will never be called */
- TRACE("(%p): stub\n",iface);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
- LPVOID pvAudio1,DWORD dwLen1,
- LPVOID pvAudio2,DWORD dwLen2)
-{
- /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
- TRACE("(%p): stub\n",iface);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
- LPWAVEFORMATEX pwfx)
-{
- /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
-
- TRACE("(%p,%p)\n",iface,pwfx);
- /* On our request (GetDriverDesc flags), DirectSound has by now used
- * waveOutClose/waveOutOpen to set the format...
- * unfortunately, this means our mmap() is now gone...
- * so we need to somehow signal to our DirectSound implementation
- * that it should completely recreate this HW buffer...
- * this unexpected error code should do the trick... */
- return DSERR_BUFFERLOST;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
-{
- /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
- TRACE("(%p,%ld): stub\n",iface,dwFreq);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
-{
- DWORD vol;
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- TRACE("(%p,%p)\n",This,pVolPan);
-
- vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
-
- if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
- WARN("wodSetVolume failed\n");
- return DSERR_INVALIDPARAM;
- }
-
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
-{
- /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
- TRACE("(%p,%ld): stub\n",iface,dwNewPos);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
- LPDWORD lpdwPlay, LPDWORD lpdwWrite)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- count_info info;
- DWORD ptr;
-
- TRACE("(%p)\n",iface);
- if (WOutDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
- ERR("device not open, but accessing?\n");
- return DSERR_UNINITIALIZED;
- }
- if (ioctl(This->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
- WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
- ptr = info.ptr & ~3; /* align the pointer, just in case */
- if (lpdwPlay) *lpdwPlay = ptr;
- if (lpdwWrite) {
- /* add some safety margin (not strictly necessary, but...) */
- if (WOutDev[This->drv->wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
- *lpdwWrite = ptr + 32;
- else
- *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
- while (*lpdwWrite > This->buflen)
- *lpdwWrite -= This->buflen;
- }
- TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0);
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- int enable;
- TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags);
- WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
- enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
- if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- if (errno == EINVAL) {
- /* Don't give up yet. OSS trigger support is inconsistent. */
- if (WOutDev[This->drv->wDevID].ossdev->open_count == 1) {
- /* try the opposite input enable */
- if (WOutDev[This->drv->wDevID].ossdev->bInputEnabled == FALSE)
- WOutDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
- else
- WOutDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
- /* try it again */
- enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
- if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0)
- return DS_OK;
- }
- }
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
- WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
- return DSERR_GENERIC;
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
-{
- IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
- int enable;
- TRACE("(%p)\n",iface);
- /* no more playing */
- WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
- enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
- if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
-#if 0
- /* the play position must be reset to the beginning of the buffer */
- if (ioctl(This->fd, SNDCTL_DSP_RESET, 0) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
-#endif
- /* Most OSS drivers just can't stop the playback without closing the device...
- * so we need to somehow signal to our DirectSound implementation
- * that it should completely recreate this HW buffer...
- * this unexpected error code should do the trick... */
- /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
- if (WOutDev[This->drv->wDevID].ossdev->open_count == 1)
- return DSERR_BUFFERLOST;
-
- return DS_OK;
-}
-
-static IDsDriverBufferVtbl dsdbvt =
-{
- IDsDriverBufferImpl_QueryInterface,
- IDsDriverBufferImpl_AddRef,
- IDsDriverBufferImpl_Release,
- IDsDriverBufferImpl_Lock,
- IDsDriverBufferImpl_Unlock,
- IDsDriverBufferImpl_SetFormat,
- IDsDriverBufferImpl_SetFrequency,
- IDsDriverBufferImpl_SetVolumePan,
- IDsDriverBufferImpl_SetPosition,
- IDsDriverBufferImpl_GetPosition,
- IDsDriverBufferImpl_Play,
- IDsDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriver) ) {
- IDsDriver_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
-
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface,
- PDSDRIVERDESC pDesc)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- TRACE("(%p,%p)\n",iface,pDesc);
-
- /* copy version from driver */
- memcpy(pDesc, &(WOutDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-
- pDesc->dwFlags |= DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
- DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK |
- DSDDESC_DONTNEEDSECONDARYLOCK;
- pDesc->dnDevNode = WOutDev[This->wDevID].waveDesc.dnDevNode;
- pDesc->wVxdId = 0;
- pDesc->wReserved = 0;
- pDesc->ulDeviceNum = This->wDevID;
- pDesc->dwHeapType = DSDHEAP_NOHEAP;
- pDesc->pvDirectDrawHeap = NULL;
- pDesc->dwMemStartAddress = 0;
- pDesc->dwMemEndAddress = 0;
- pDesc->dwMemAllocExtra = 0;
- pDesc->pvReserved1 = NULL;
- pDesc->pvReserved2 = NULL;
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- int enable;
- TRACE("(%p)\n",iface);
-
- /* make sure the card doesn't start playing before we want it to */
- WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
- enable = getEnables(WOutDev[This->wDevID].ossdev);
- if (ioctl(WOutDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- TRACE("(%p)\n",iface);
- if (This->primary) {
- ERR("problem with DirectSound: primary not released\n");
- return DSERR_GENERIC;
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- TRACE("(%p,%p)\n",iface,pCaps);
- memcpy(pCaps, &(WOutDev[This->wDevID].ossdev->ds_caps), sizeof(DSDRIVERCAPS));
- return DS_OK;
-}
-
-static HRESULT WINAPI DSD_CreatePrimaryBuffer(PIDSDRIVER iface,
- LPWAVEFORMATEX pwfx,
- DWORD dwFlags,
- DWORD dwCardAddress,
- LPDWORD pdwcbBufferSize,
- LPBYTE *ppbBuffer,
- LPVOID *ppvObj)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
- HRESULT err;
- audio_buf_info info;
- int enable = 0;
- TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
- if (This->primary)
- return DSERR_ALLOCATED;
- if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
- return DSERR_CONTROLUNAVAIL;
-
- *ippdsdb = (IDsDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverBufferImpl));
- if (*ippdsdb == NULL)
- return DSERR_OUTOFMEMORY;
- (*ippdsdb)->lpVtbl = &dsdbvt;
- (*ippdsdb)->ref = 1;
- (*ippdsdb)->drv = This;
- copy_format(pwfx, &(*ippdsdb)->wfex);
- (*ippdsdb)->fd = WOutDev[This->wDevID].ossdev->fd;
- (*ippdsdb)->dwFlags = dwFlags;
-
- /* check how big the DMA buffer is now */
- if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
- WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
- HeapFree(GetProcessHeap(),0,*ippdsdb);
- *ippdsdb = NULL;
- return DSERR_GENERIC;
- }
- (*ippdsdb)->maplen = (*ippdsdb)->buflen = info.fragstotal * info.fragsize;
-
- /* map the DMA buffer */
- err = DSDB_MapBuffer(*ippdsdb);
- if (err != DS_OK) {
- HeapFree(GetProcessHeap(),0,*ippdsdb);
- *ippdsdb = NULL;
- return err;
- }
-
- /* primary buffer is ready to go */
- *pdwcbBufferSize = (*ippdsdb)->maplen;
- *ppbBuffer = (*ippdsdb)->mapping;
-
- /* some drivers need some extra nudging after mapping */
- WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
- enable = getEnables(WOutDev[This->wDevID].ossdev);
- if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
- WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
-
- This->primary = *ippdsdb;
-
- return DS_OK;
-}
-
-static HRESULT WINAPI DSD_CreateSecondaryBuffer(PIDSDRIVER iface,
- LPWAVEFORMATEX pwfx,
- DWORD dwFlags,
- DWORD dwCardAddress,
- LPDWORD pdwcbBufferSize,
- LPBYTE *ppbBuffer,
- LPVOID *ppvObj)
-{
- IDsDriverImpl *This = (IDsDriverImpl *)iface;
- IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
- FIXME("(%p,%p,%lx,%lx,%p,%p,%p): stub\n",This,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
- *ippdsdb = 0;
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
- LPWAVEFORMATEX pwfx,
- DWORD dwFlags,
- DWORD dwCardAddress,
- LPDWORD pdwcbBufferSize,
- LPBYTE *ppbBuffer,
- LPVOID *ppvObj)
-{
- TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
- if (dwFlags & DSBCAPS_PRIMARYBUFFER)
- return DSD_CreatePrimaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-
- return DSD_CreateSecondaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
-}
-
-static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
- PIDSDRIVERBUFFER pBuffer,
- LPVOID *ppvObj)
-{
- /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
- TRACE("(%p,%p): stub\n",iface,pBuffer);
- return DSERR_INVALIDCALL;
-}
-
-static IDsDriverVtbl dsdvt =
-{
- IDsDriverImpl_QueryInterface,
- IDsDriverImpl_AddRef,
- IDsDriverImpl_Release,
- IDsDriverImpl_GetDriverDesc,
- IDsDriverImpl_Open,
- IDsDriverImpl_Close,
- IDsDriverImpl_GetCaps,
- IDsDriverImpl_CreateSoundBuffer,
- IDsDriverImpl_DuplicateSoundBuffer
-};
-
-static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
- IDsDriverBufferImpl * dsdb,
- IDsDriverPropertySetImpl **pdsdps)
-{
- IDsDriverPropertySetImpl * dsdps;
- TRACE("(%p,%p)\n",dsdb,pdsdps);
-
- dsdps = (IDsDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdps));
- if (dsdps == NULL) {
- WARN("out of memory\n");
- return DSERR_OUTOFMEMORY;
- }
-
- dsdps->ref = 0;
- dsdps->lpVtbl = &dsdpsvt;
- dsdps->buffer = dsdb;
- dsdb->property_set = dsdps;
- IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
- *pdsdps = dsdps;
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsDriverNotifyImpl_Create(
- IDsDriverBufferImpl * dsdb,
- IDsDriverNotifyImpl **pdsdn)
-{
- IDsDriverNotifyImpl * dsdn;
- TRACE("(%p,%p)\n",dsdb,pdsdn);
-
- dsdn = (IDsDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdn));
-
- if (dsdn == NULL) {
- WARN("out of memory\n");
- return DSERR_OUTOFMEMORY;
- }
-
- dsdn->ref = 0;
- dsdn->lpVtbl = &dsdnvt;
- dsdn->buffer = dsdb;
- dsdb->notify = dsdn;
- IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
-
- *pdsdn = dsdn;
- return DS_OK;
-};
-
-static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
-{
- IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
- TRACE("(%d,%p)\n",wDevID,drv);
-
- /* the HAL isn't much better than the HEL if we can't do mmap() */
- if (!(WOutDev[wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
- ERR("DirectSound flag not set\n");
- MESSAGE("This sound card's driver does not support direct access\n");
- MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
- return MMSYSERR_NOTSUPPORTED;
- }
-
- *idrv = (IDsDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverImpl));
- if (!*idrv)
- return MMSYSERR_NOMEM;
- (*idrv)->lpVtbl = &dsdvt;
- (*idrv)->ref = 1;
- (*idrv)->wDevID = wDevID;
- (*idrv)->primary = NULL;
- (*idrv)->nrofsecondaries = 0;
- (*idrv)->secondaries = NULL;
-
- return MMSYSERR_NOERROR;
-}
-
-static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
- TRACE("(%d,%p)\n",wDevID,desc);
- memcpy(desc, &(WOutDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
- return MMSYSERR_NOERROR;
-}
-
/*======================================================================*
* Low level WAVE IN implementation *
*======================================================================*/
/**************************************************************************
* widOpen [internal]
*/
-static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{
WINE_WAVEIN* wwi;
audio_buf_info info;
return MMSYSERR_NOTSUPPORTED;
}
-/*======================================================================*
- * Low level DSOUND capture definitions *
- *======================================================================*/
-
-typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
-typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
-typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
-typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
-
-struct IDsCaptureDriverPropertySetImpl
-{
- /* IUnknown fields */
- IDsDriverPropertySetVtbl *lpVtbl;
- DWORD ref;
-
- IDsCaptureDriverBufferImpl* capture_buffer;
-};
-
-struct IDsCaptureDriverNotifyImpl
-{
- /* IUnknown fields */
- IDsDriverNotifyVtbl *lpVtbl;
- DWORD ref;
-
- IDsCaptureDriverBufferImpl* capture_buffer;
-};
-
-struct IDsCaptureDriverImpl
-{
- /* IUnknown fields */
- IDsCaptureDriverVtbl *lpVtbl;
- DWORD ref;
-
- /* IDsCaptureDriverImpl fields */
- UINT wDevID;
- IDsCaptureDriverBufferImpl* capture_buffer;
-};
-
-struct IDsCaptureDriverBufferImpl
-{
- /* IUnknown fields */
- IDsCaptureDriverBufferVtbl *lpVtbl;
- DWORD ref;
-
- /* IDsCaptureDriverBufferImpl fields */
- IDsCaptureDriverImpl* drv;
- DWORD buflen;
- LPBYTE buffer;
- DWORD writeptr;
- LPBYTE mapping;
- DWORD maplen;
-
- /* IDsDriverNotifyImpl fields */
- IDsCaptureDriverNotifyImpl* notify;
- int notify_index;
- LPDSBPOSITIONNOTIFY notifies;
- int nrofnotifies;
-
- /* IDsDriverPropertySetImpl fields */
- IDsCaptureDriverPropertySetImpl* property_set;
-
- BOOL is_capturing;
- BOOL is_looping;
-};
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
- IDsCaptureDriverBufferImpl * dscdb,
- IDsCaptureDriverPropertySetImpl **pdscdps);
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
- IDsCaptureDriverBufferImpl * dsdcb,
- IDsCaptureDriverNotifyImpl **pdscdn);
-
-/*======================================================================*
- * Low level DSOUND capture property set implementation *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
- PIDSDRIVERPROPERTYSET iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
- IDsDriverPropertySet_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
- PIDSDRIVERPROPERTYSET iface)
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
- PIDSDRIVERPROPERTYSET iface)
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
- This->capture_buffer->property_set = NULL;
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
- PIDSDRIVERPROPERTYSET iface,
- PDSPROPERTY pDsProperty,
- LPVOID pPropertyParams,
- ULONG cbPropertyParams,
- LPVOID pPropertyData,
- ULONG cbPropertyData,
- PULONG pcbReturnedData )
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,
- cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
- PIDSDRIVERPROPERTYSET iface,
- PDSPROPERTY pDsProperty,
- LPVOID pPropertyParams,
- ULONG cbPropertyParams,
- LPVOID pPropertyData,
- ULONG cbPropertyData )
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,
- cbPropertyParams,pPropertyData,cbPropertyData);
- return DSERR_UNSUPPORTED;
-}
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
- PIDSDRIVERPROPERTYSET iface,
- REFGUID PropertySetId,
- ULONG PropertyId,
- PULONG pSupport )
-{
- IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
- FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
- pSupport);
- return DSERR_UNSUPPORTED;
-}
-
-IDsDriverPropertySetVtbl dscdpsvt =
-{
- IDsCaptureDriverPropertySetImpl_QueryInterface,
- IDsCaptureDriverPropertySetImpl_AddRef,
- IDsCaptureDriverPropertySetImpl_Release,
- IDsCaptureDriverPropertySetImpl_Get,
- IDsCaptureDriverPropertySetImpl_Set,
- IDsCaptureDriverPropertySetImpl_QuerySupport,
-};
-
-/*======================================================================*
- * Low level DSOUND capture notify implementation *
- *======================================================================*/
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
- PIDSDRIVERNOTIFY iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
- IDsDriverNotify_AddRef(iface);
- *ppobj = This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
- PIDSDRIVERNOTIFY iface)
-{
- IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
- PIDSDRIVERNOTIFY iface)
-{
- IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
- This->capture_buffer->notify = NULL;
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
- PIDSDRIVERNOTIFY iface,
- DWORD howmuch,
- LPCDSBPOSITIONNOTIFY notify)
-{
- IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
- TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
-
- if (!notify) {
- WARN("invalid parameter\n");
- return DSERR_INVALIDPARAM;
- }
-
- if (TRACE_ON(wave)) {
- int i;
- for (i=0;i<howmuch;i++)
- TRACE("notify at %ld to 0x%08lx\n",
- notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
- }
-
- /* Make an internal copy of the caller-supplied array.
- * Replace the existing copy if one is already present. */
- if (This->capture_buffer->notifies)
- This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
- howmuch * sizeof(DSBPOSITIONNOTIFY));
- else
- This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
-
- memcpy(This->capture_buffer->notifies, notify,
- howmuch * sizeof(DSBPOSITIONNOTIFY));
- This->capture_buffer->nrofnotifies = howmuch;
-
- return S_OK;
-}
-
-IDsDriverNotifyVtbl dscdnvt =
-{
- IDsCaptureDriverNotifyImpl_QueryInterface,
- IDsCaptureDriverNotifyImpl_AddRef,
- IDsCaptureDriverNotifyImpl_Release,
- IDsCaptureDriverNotifyImpl_SetNotificationPositions,
-};
-
-/*======================================================================*
- * Low level DSOUND capture implementation *
- *======================================================================*/
-
-static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
- if (!dscdb->mapping) {
- dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
- WInDev[dscdb->drv->wDevID].ossdev->fd, 0);
- if (dscdb->mapping == (LPBYTE)-1) {
- TRACE("(%p): Could not map sound device for direct access (%s)\n",
- dscdb, strerror(errno));
- return DSERR_GENERIC;
- }
- TRACE("(%p): sound device has been mapped for direct access at %p, size=%ld\n", dscdb, dscdb->mapping, dscdb->maplen);
- }
- return DS_OK;
-}
-
-static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
-{
- if (dscdb->mapping) {
- if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
- ERR("(%p): Could not unmap sound device (%s)\n",
- dscdb, strerror(errno));
- return DSERR_GENERIC;
- }
- dscdb->mapping = NULL;
- TRACE("(%p): sound device unmapped\n", dscdb);
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
- PIDSCDRIVERBUFFER iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- *ppobj = 0;
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
- IDsCaptureDriverBuffer_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
- if (!This->notify)
- IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
- if (This->notify) {
- IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
- *ppobj = (LPVOID)This->notify;
- return DS_OK;
- }
- return E_FAIL;
- }
-
- if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
- if (!This->property_set)
- IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
- if (This->property_set) {
- IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
- *ppobj = (LPVOID)This->property_set;
- return DS_OK;
- }
- return E_FAIL;
- }
-
- FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
- return DSERR_UNSUPPORTED;
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- DSCDB_UnmapBuffer(This);
- if (This->notifies != NULL)
- HeapFree(GetProcessHeap(), 0, This->notifies);
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
- PIDSCDRIVERBUFFER iface,
- LPVOID* ppvAudio1,
- LPDWORD pdwLen1,
- LPVOID* ppvAudio2,
- LPDWORD pdwLen2,
- DWORD dwWritePosition,
- DWORD dwWriteLen,
- DWORD dwFlags)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- FIXME("(%p,%p,%p,%p,%p,%ld,%ld,0x%08lx): stub!\n",This,ppvAudio1,pdwLen1,
- ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
- PIDSCDRIVERBUFFER iface,
- LPVOID pvAudio1,
- DWORD dwLen1,
- LPVOID pvAudio2,
- DWORD dwLen2)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- FIXME("(%p,%p,%ld,%p,%ld): stub!\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
- PIDSCDRIVERBUFFER iface,
- LPDWORD lpdwCapture,
- LPDWORD lpdwRead)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- count_info info;
- DWORD ptr;
- TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
-
- if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
- ERR("device not open, but accessing?\n");
- return DSERR_UNINITIALIZED;
- }
-
- if (!This->is_capturing) {
- if (lpdwCapture)
- *lpdwCapture = 0;
- if (lpdwRead)
- *lpdwRead = 0;
- }
-
- if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
- WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
- ptr = info.ptr & ~3; /* align the pointer, just in case */
- if (lpdwCapture) *lpdwCapture = ptr;
- if (lpdwRead) {
- /* add some safety margin (not strictly necessary, but...) */
- if (WInDev[This->drv->wDevID].ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
- *lpdwRead = ptr + 32;
- else
- *lpdwRead = ptr + WInDev[This->drv->wDevID].dwFragmentSize;
- while (*lpdwRead > This->buflen)
- *lpdwRead -= This->buflen;
- }
- TRACE("capturepos=%ld, readpos=%ld\n", lpdwCapture?*lpdwCapture:0, lpdwRead?*lpdwRead:0);
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
- PIDSCDRIVERBUFFER iface,
- LPDWORD lpdwStatus)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- TRACE("(%p,%p)\n",This,lpdwStatus);
-
- if (This->is_capturing) {
- if (This->is_looping)
- *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
- else
- *lpdwStatus = DSCBSTATUS_CAPTURING;
- } else
- *lpdwStatus = 0;
-
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
- PIDSCDRIVERBUFFER iface,
- DWORD dwFlags)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- int enable;
- TRACE("(%p,%lx)\n",This,dwFlags);
-
- if (This->is_capturing)
- return DS_OK;
-
- if (dwFlags & DSCBSTART_LOOPING)
- This->is_looping = TRUE;
-
- WInDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
- enable = getEnables(WInDev[This->drv->wDevID].ossdev);
- if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- if (errno == EINVAL) {
- /* Don't give up yet. OSS trigger support is inconsistent. */
- if (WInDev[This->drv->wDevID].ossdev->open_count == 1) {
- /* try the opposite output enable */
- if (WInDev[This->drv->wDevID].ossdev->bOutputEnabled == FALSE)
- WInDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
- else
- WInDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
- /* try it again */
- enable = getEnables(WInDev[This->drv->wDevID].ossdev);
- if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
- This->is_capturing = TRUE;
- return DS_OK;
- }
- }
- }
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
- WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
- return DSERR_GENERIC;
- }
-
- This->is_capturing = TRUE;
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- int enable;
- TRACE("(%p)\n",This);
-
- if (!This->is_capturing)
- return DS_OK;
-
- /* no more captureing */
- WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
- enable = getEnables(WInDev[This->drv->wDevID].ossdev);
- if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
- WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
-
- /* send a final event if necessary */
- if (This->nrofnotifies > 0) {
- if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
- SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
- }
-
- This->is_capturing = FALSE;
- This->is_looping = FALSE;
-
- /* Most OSS drivers just can't stop capturing without closing the device...
- * so we need to somehow signal to our DirectSound implementation
- * that it should completely recreate this HW buffer...
- * this unexpected error code should do the trick... */
- return DSERR_BUFFERLOST;
-}
-
-static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
- PIDSCDRIVERBUFFER iface,
- LPWAVEFORMATEX pwfx)
-{
- IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
- FIXME("(%p): stub!\n",This);
- return DSERR_UNSUPPORTED;
-}
-
-static IDsCaptureDriverBufferVtbl dscdbvt =
-{
- IDsCaptureDriverBufferImpl_QueryInterface,
- IDsCaptureDriverBufferImpl_AddRef,
- IDsCaptureDriverBufferImpl_Release,
- IDsCaptureDriverBufferImpl_Lock,
- IDsCaptureDriverBufferImpl_Unlock,
- IDsCaptureDriverBufferImpl_SetFormat,
- IDsCaptureDriverBufferImpl_GetPosition,
- IDsCaptureDriverBufferImpl_GetStatus,
- IDsCaptureDriverBufferImpl_Start,
- IDsCaptureDriverBufferImpl_Stop
-};
-
-static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
- PIDSCDRIVER iface,
- REFIID riid,
- LPVOID *ppobj)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
- if ( IsEqualGUID(riid, &IID_IUnknown) ||
- IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
- IDsCaptureDriver_AddRef(iface);
- *ppobj = (LPVOID)This;
- return DS_OK;
- }
-
- FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
-
- *ppobj = 0;
-
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- return InterlockedIncrement(&(This->ref));
-}
-
-static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- DWORD ref;
- TRACE("(%p) ref was %ld\n", This, This->ref);
-
- ref = InterlockedDecrement(&(This->ref));
- if (ref == 0) {
- HeapFree(GetProcessHeap(),0,This);
- TRACE("(%p) released\n",This);
- }
- return ref;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
- PIDSCDRIVER iface,
- PDSDRIVERDESC pDesc)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p,%p)\n",This,pDesc);
-
- if (!pDesc) {
- TRACE("invalid parameter\n");
- return DSERR_INVALIDPARAM;
- }
-
- /* copy version from driver */
- memcpy(pDesc, &(WInDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
-
- pDesc->dwFlags |= DSDDESC_USESYSTEMMEMORY;
- pDesc->dnDevNode = WInDev[This->wDevID].waveDesc.dnDevNode;
- pDesc->wVxdId = 0;
- pDesc->wReserved = 0;
- pDesc->ulDeviceNum = This->wDevID;
- pDesc->dwHeapType = DSDHEAP_NOHEAP;
- pDesc->pvDirectDrawHeap = NULL;
- pDesc->dwMemStartAddress = 0;
- pDesc->dwMemEndAddress = 0;
- pDesc->dwMemAllocExtra = 0;
- pDesc->pvReserved1 = NULL;
- pDesc->pvReserved2 = NULL;
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p)\n",This);
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p)\n",This);
- if (This->capture_buffer) {
- ERR("problem with DirectSound: capture buffer not released\n");
- return DSERR_GENERIC;
- }
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
- PIDSCDRIVER iface,
- PDSCDRIVERCAPS pCaps)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- TRACE("(%p,%p)\n",This,pCaps);
- memcpy(pCaps, &(WInDev[This->wDevID].ossdev->dsc_caps), sizeof(DSCDRIVERCAPS));
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
- PIDSCDRIVER iface,
- LPWAVEFORMATEX pwfx,
- DWORD dwFlags,
- DWORD dwCardAddress,
- LPDWORD pdwcbBufferSize,
- LPBYTE *ppbBuffer,
- LPVOID *ppvObj)
-{
- IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
- IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
- HRESULT err;
- audio_buf_info info;
- int enable;
- TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
- pdwcbBufferSize,ppbBuffer,ppvObj);
-
- if (This->capture_buffer) {
- TRACE("already allocated\n");
- return DSERR_ALLOCATED;
- }
-
- *ippdscdb = (IDsCaptureDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
- if (*ippdscdb == NULL) {
- TRACE("out of memory\n");
- return DSERR_OUTOFMEMORY;
- }
-
- (*ippdscdb)->lpVtbl = &dscdbvt;
- (*ippdscdb)->ref = 1;
- (*ippdscdb)->drv = This;
- (*ippdscdb)->notify = NULL;
- (*ippdscdb)->notify_index = 0;
- (*ippdscdb)->notifies = NULL;
- (*ippdscdb)->nrofnotifies = 0;
- (*ippdscdb)->property_set = NULL;
- (*ippdscdb)->is_capturing = FALSE;
- (*ippdscdb)->is_looping = FALSE;
-
- if (WInDev[This->wDevID].state == WINE_WS_CLOSED) {
- WAVEOPENDESC desc;
- desc.hWave = 0;
- desc.lpFormat = pwfx;
- desc.dwCallback = 0;
- desc.dwInstance = 0;
- desc.uMappedDeviceID = 0;
- desc.dnDevNode = 0;
- err = widOpen(This->wDevID, &desc, dwFlags | WAVE_DIRECTSOUND);
- if (err != MMSYSERR_NOERROR) {
- TRACE("widOpen failed\n");
- return err;
- }
- }
-
- /* check how big the DMA buffer is now */
- if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
- WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
- HeapFree(GetProcessHeap(),0,*ippdscdb);
- *ippdscdb = NULL;
- return DSERR_GENERIC;
- }
- (*ippdscdb)->maplen = (*ippdscdb)->buflen = info.fragstotal * info.fragsize;
-
- /* map the DMA buffer */
- err = DSCDB_MapBuffer(*ippdscdb);
- if (err != DS_OK) {
- HeapFree(GetProcessHeap(),0,*ippdscdb);
- *ippdscdb = NULL;
- return err;
- }
-
- /* capture buffer is ready to go */
- *pdwcbBufferSize = (*ippdscdb)->maplen;
- *ppbBuffer = (*ippdscdb)->mapping;
-
- /* some drivers need some extra nudging after mapping */
- WInDev[This->wDevID].ossdev->bInputEnabled = FALSE;
- enable = getEnables(WInDev[This->wDevID].ossdev);
- if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
- ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
- WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
- return DSERR_GENERIC;
- }
-
- This->capture_buffer = *ippdscdb;
-
- return DS_OK;
-}
-
-static IDsCaptureDriverVtbl dscdvt =
-{
- IDsCaptureDriverImpl_QueryInterface,
- IDsCaptureDriverImpl_AddRef,
- IDsCaptureDriverImpl_Release,
- IDsCaptureDriverImpl_GetDriverDesc,
- IDsCaptureDriverImpl_Open,
- IDsCaptureDriverImpl_Close,
- IDsCaptureDriverImpl_GetCaps,
- IDsCaptureDriverImpl_CreateCaptureBuffer
-};
-
-static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
- IDsCaptureDriverBufferImpl * dscdb,
- IDsCaptureDriverPropertySetImpl **pdscdps)
-{
- IDsCaptureDriverPropertySetImpl * dscdps;
- TRACE("(%p,%p)\n",dscdb,pdscdps);
-
- dscdps = (IDsCaptureDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdps));
- if (dscdps == NULL) {
- WARN("out of memory\n");
- return DSERR_OUTOFMEMORY;
- }
-
- dscdps->ref = 0;
- dscdps->lpVtbl = &dscdpsvt;
- dscdps->capture_buffer = dscdb;
- dscdb->property_set = dscdps;
- IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
- *pdscdps = dscdps;
- return DS_OK;
-}
-
-static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
- IDsCaptureDriverBufferImpl * dscdb,
- IDsCaptureDriverNotifyImpl **pdscdn)
-{
- IDsCaptureDriverNotifyImpl * dscdn;
- TRACE("(%p,%p)\n",dscdb,pdscdn);
-
- dscdn = (IDsCaptureDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdn));
- if (dscdn == NULL) {
- WARN("out of memory\n");
- return DSERR_OUTOFMEMORY;
- }
-
- dscdn->ref = 0;
- dscdn->lpVtbl = &dscdnvt;
- dscdn->capture_buffer = dscdb;
- dscdb->notify = dscdn;
- IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
-
- *pdscdn = dscdn;
- return DS_OK;
-};
-
-static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
-{
- IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
- TRACE("(%d,%p)\n",wDevID,drv);
-
- /* the HAL isn't much better than the HEL if we can't do mmap() */
- if (!(WInDev[wDevID].ossdev->in_caps_support & WAVECAPS_DIRECTSOUND)) {
- ERR("DirectSoundCapture flag not set\n");
- MESSAGE("This sound card's driver does not support direct access\n");
- MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
- return MMSYSERR_NOTSUPPORTED;
- }
-
- *idrv = (IDsCaptureDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
- if (!*idrv)
- return MMSYSERR_NOMEM;
- (*idrv)->lpVtbl = &dscdvt;
- (*idrv)->ref = 1;
-
- (*idrv)->wDevID = wDevID;
- (*idrv)->capture_buffer = NULL;
- return MMSYSERR_NOERROR;
-}
-
-static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
-{
- memcpy(desc, &(WInDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
- return MMSYSERR_NOERROR;
-}
-
#else /* !HAVE_OSS */
/**************************************************************************
--- /dev/null
+/*
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
+ *
+ * Copyright 1994 Martin Ayotte
+ * 1999 Eric Pouech (async playing in waveOut/waveIn)
+ * 2000 Eric Pouech (loops in waveOut)
+ * 2002 Eric Pouech (full duplex)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_OSS
+
+/* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
+#define USE_PIPE_SYNC
+
+#define MAX_WAVEDRV (6)
+
+/* states of the playing device */
+#define WINE_WS_PLAYING 0
+#define WINE_WS_PAUSED 1
+#define WINE_WS_STOPPED 2
+#define WINE_WS_CLOSED 3
+
+/* events to be send to device */
+enum win_wm_message {
+ WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
+ WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
+};
+
+#ifdef USE_PIPE_SYNC
+#define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
+#define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
+#define RESET_OMR(omr) do { } while (0)
+#define WAIT_OMR(omr, sleep) \
+ do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
+ pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
+#else
+#define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
+#define CLEAR_OMR(omr) do { } while (0)
+#define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
+#define WAIT_OMR(omr, sleep) \
+ do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
+#endif
+
+typedef struct {
+ enum win_wm_message msg; /* message identifier */
+ DWORD param; /* parameter for this message */
+ HANDLE hEvent; /* if message is synchronous, handle of event for synchro */
+} OSS_MSG;
+
+/* implement an in-process message ring for better performance
+ * (compared to passing thru the server)
+ * this ring will be used by the input (resp output) record (resp playback) routine
+ */
+#define OSS_RING_BUFFER_INCREMENT 64
+typedef struct {
+ int ring_buffer_size;
+ OSS_MSG * messages;
+ int msg_tosave;
+ int msg_toget;
+#ifdef USE_PIPE_SYNC
+ int msg_pipe[2];
+#else
+ HANDLE msg_event;
+#endif
+ CRITICAL_SECTION msg_crst;
+} OSS_MSG_RING;
+
+typedef struct tagOSS_DEVICE {
+ char* dev_name;
+ char* mixer_name;
+ char* interface_name;
+ unsigned open_count;
+ WAVEOUTCAPSA out_caps;
+ WAVEOUTCAPSA duplex_out_caps;
+ WAVEINCAPSA in_caps;
+ DWORD in_caps_support;
+ unsigned open_access;
+ int fd;
+ DWORD owner_tid;
+ int sample_rate;
+ int stereo;
+ int format;
+ unsigned audio_fragment;
+ BOOL full_duplex;
+ BOOL bTriggerSupport;
+ BOOL bOutputEnabled;
+ BOOL bInputEnabled;
+ DSDRIVERDESC ds_desc;
+ DSDRIVERCAPS ds_caps;
+ DSCDRIVERCAPS dsc_caps;
+} OSS_DEVICE;
+
+typedef struct {
+ OSS_DEVICE* ossdev;
+ volatile int state; /* one of the WINE_WS_ manifest constants */
+ WAVEOPENDESC waveDesc;
+ WORD wFlags;
+ WAVEFORMATPCMEX waveFormat;
+ DWORD volume;
+
+ /* OSS information */
+ DWORD dwFragmentSize; /* size of OSS buffer fragment */
+ DWORD dwBufferSize; /* size of whole OSS buffer in bytes */
+ LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */
+ LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */
+ DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */
+
+ LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */
+ DWORD dwLoops; /* private copy of loop counter */
+
+ DWORD dwPlayedTotal; /* number of bytes actually played since opening */
+ DWORD dwWrittenTotal; /* number of bytes written to OSS buffer since opening */
+ BOOL bNeedPost; /* whether audio still needs to be physically started */
+
+ /* synchronization stuff */
+ HANDLE hStartUpEvent;
+ HANDLE hThread;
+ DWORD dwThreadID;
+ OSS_MSG_RING msgRing;
+} WINE_WAVEOUT;
+
+typedef struct {
+ OSS_DEVICE* ossdev;
+ volatile int state;
+ DWORD dwFragmentSize; /* OpenSound '/dev/dsp' give us that size */
+ WAVEOPENDESC waveDesc;
+ WORD wFlags;
+ WAVEFORMATPCMEX waveFormat;
+ LPWAVEHDR lpQueuePtr;
+ DWORD dwTotalRecorded;
+ DWORD dwTotalRead;
+
+ /* synchronization stuff */
+ HANDLE hThread;
+ DWORD dwThreadID;
+ HANDLE hStartUpEvent;
+ OSS_MSG_RING msgRing;
+} WINE_WAVEIN;
+
+extern OSS_DEVICE OSS_Devices[MAX_WAVEDRV];
+extern WINE_WAVEOUT WOutDev[MAX_WAVEDRV];
+extern WINE_WAVEIN WInDev[MAX_WAVEDRV];
+extern unsigned numOutDev;
+extern unsigned numInDev;
+
+extern int getEnables(OSS_DEVICE *ossdev);
+extern void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2);
+
+extern DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
+ int* frag, int strict_format,
+ int sample_rate, int stereo, int fmt);
+
+extern void OSS_CloseDevice(OSS_DEVICE* ossdev);
+
+extern DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags);
+extern DWORD wodSetVolume(WORD wDevID, DWORD dwParam);
+extern DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags);
+
+/* dscapture.c */
+extern DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);
+extern DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc);
+
+/* dsrender.c */
+extern DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
+extern DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
+
+#endif /* HAVE_OSS */
--- /dev/null
+/*
+ * Direct Sound Capture driver
+ *
+ * Copyright 2004 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/winuser16.h"
+#include "mmddk.h"
+#include "mmreg.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "oss.h"
+#include "wine/debug.h"
+
+#include "audio.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
+#ifdef HAVE_OSS
+
+/*======================================================================*
+ * Low level DSOUND capture definitions *
+ *======================================================================*/
+
+typedef struct IDsCaptureDriverPropertySetImpl IDsCaptureDriverPropertySetImpl;
+typedef struct IDsCaptureDriverNotifyImpl IDsCaptureDriverNotifyImpl;
+typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
+typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
+
+struct IDsCaptureDriverPropertySetImpl
+{
+ /* IUnknown fields */
+ IDsDriverPropertySetVtbl *lpVtbl;
+ DWORD ref;
+
+ IDsCaptureDriverBufferImpl* capture_buffer;
+};
+
+struct IDsCaptureDriverNotifyImpl
+{
+ /* IUnknown fields */
+ IDsDriverNotifyVtbl *lpVtbl;
+ DWORD ref;
+
+ IDsCaptureDriverBufferImpl* capture_buffer;
+};
+
+struct IDsCaptureDriverImpl
+{
+ /* IUnknown fields */
+ IDsCaptureDriverVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDsCaptureDriverImpl fields */
+ UINT wDevID;
+ IDsCaptureDriverBufferImpl* capture_buffer;
+};
+
+struct IDsCaptureDriverBufferImpl
+{
+ /* IUnknown fields */
+ IDsCaptureDriverBufferVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDsCaptureDriverBufferImpl fields */
+ IDsCaptureDriverImpl* drv;
+ DWORD buflen;
+ LPBYTE buffer;
+ DWORD writeptr;
+ LPBYTE mapping;
+ DWORD maplen;
+
+ /* IDsDriverNotifyImpl fields */
+ IDsCaptureDriverNotifyImpl* notify;
+ int notify_index;
+ LPDSBPOSITIONNOTIFY notifies;
+ int nrofnotifies;
+
+ /* IDsDriverPropertySetImpl fields */
+ IDsCaptureDriverPropertySetImpl* property_set;
+
+ BOOL is_capturing;
+ BOOL is_looping;
+};
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
+ IDsCaptureDriverBufferImpl * dscdb,
+ IDsCaptureDriverPropertySetImpl **pdscdps);
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
+ IDsCaptureDriverBufferImpl * dsdcb,
+ IDsCaptureDriverNotifyImpl **pdscdn);
+
+/*======================================================================*
+ * Low level DSOUND capture property set implementation *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QueryInterface(
+ PIDSDRIVERPROPERTYSET iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
+ IDsDriverPropertySet_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverPropertySetImpl_AddRef(
+ PIDSDRIVERPROPERTYSET iface)
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverPropertySetImpl_Release(
+ PIDSDRIVERPROPERTYSET iface)
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
+ This->capture_buffer->property_set = NULL;
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Get(
+ PIDSDRIVERPROPERTYSET iface,
+ PDSPROPERTY pDsProperty,
+ LPVOID pPropertyParams,
+ ULONG cbPropertyParams,
+ LPVOID pPropertyData,
+ ULONG cbPropertyData,
+ PULONG pcbReturnedData )
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,
+ cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Set(
+ PIDSDRIVERPROPERTYSET iface,
+ PDSPROPERTY pDsProperty,
+ LPVOID pPropertyParams,
+ ULONG cbPropertyParams,
+ LPVOID pPropertyData,
+ ULONG cbPropertyData )
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,
+ cbPropertyParams,pPropertyData,cbPropertyData);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_QuerySupport(
+ PIDSDRIVERPROPERTYSET iface,
+ REFGUID PropertySetId,
+ ULONG PropertyId,
+ PULONG pSupport )
+{
+ IDsCaptureDriverPropertySetImpl *This = (IDsCaptureDriverPropertySetImpl *)iface;
+ FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,
+ pSupport);
+ return DSERR_UNSUPPORTED;
+}
+
+IDsDriverPropertySetVtbl dscdpsvt =
+{
+ IDsCaptureDriverPropertySetImpl_QueryInterface,
+ IDsCaptureDriverPropertySetImpl_AddRef,
+ IDsCaptureDriverPropertySetImpl_Release,
+ IDsCaptureDriverPropertySetImpl_Get,
+ IDsCaptureDriverPropertySetImpl_Set,
+ IDsCaptureDriverPropertySetImpl_QuerySupport,
+};
+
+/*======================================================================*
+ * Low level DSOUND capture notify implementation *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_QueryInterface(
+ PIDSDRIVERNOTIFY iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
+ IDsDriverNotify_AddRef(iface);
+ *ppobj = This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverNotifyImpl_AddRef(
+ PIDSDRIVERNOTIFY iface)
+{
+ IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverNotifyImpl_Release(
+ PIDSDRIVERNOTIFY iface)
+{
+ IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ IDsCaptureDriverBuffer_Release((PIDSCDRIVERBUFFER)This->capture_buffer);
+ This->capture_buffer->notify = NULL;
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_SetNotificationPositions(
+ PIDSDRIVERNOTIFY iface,
+ DWORD howmuch,
+ LPCDSBPOSITIONNOTIFY notify)
+{
+ IDsCaptureDriverNotifyImpl *This = (IDsCaptureDriverNotifyImpl *)iface;
+ TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+
+ if (!notify) {
+ WARN("invalid parameter\n");
+ return DSERR_INVALIDPARAM;
+ }
+
+ if (TRACE_ON(wave)) {
+ int i;
+ for (i=0;i<howmuch;i++)
+ TRACE("notify at %ld to 0x%08lx\n",
+ notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+ }
+
+ /* Make an internal copy of the caller-supplied array.
+ * Replace the existing copy if one is already present. */
+ if (This->capture_buffer->notifies)
+ This->capture_buffer->notifies = HeapReAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, This->capture_buffer->notifies,
+ howmuch * sizeof(DSBPOSITIONNOTIFY));
+ else
+ This->capture_buffer->notifies = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY, howmuch * sizeof(DSBPOSITIONNOTIFY));
+
+ memcpy(This->capture_buffer->notifies, notify,
+ howmuch * sizeof(DSBPOSITIONNOTIFY));
+ This->capture_buffer->nrofnotifies = howmuch;
+
+ return S_OK;
+}
+
+IDsDriverNotifyVtbl dscdnvt =
+{
+ IDsCaptureDriverNotifyImpl_QueryInterface,
+ IDsCaptureDriverNotifyImpl_AddRef,
+ IDsCaptureDriverNotifyImpl_Release,
+ IDsCaptureDriverNotifyImpl_SetNotificationPositions,
+};
+
+/*======================================================================*
+ * Low level DSOUND capture implementation *
+ *======================================================================*/
+
+static HRESULT DSCDB_MapBuffer(IDsCaptureDriverBufferImpl *dscdb)
+{
+ if (!dscdb->mapping) {
+ dscdb->mapping = mmap(NULL, dscdb->maplen, PROT_READ, MAP_SHARED,
+ WInDev[dscdb->drv->wDevID].ossdev->fd, 0);
+ if (dscdb->mapping == (LPBYTE)-1) {
+ TRACE("(%p): Could not map sound device for direct access (%s)\n",
+ dscdb, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ TRACE("(%p): sound device has been mapped for direct access at %p, size=%ld\n", dscdb, dscdb->mapping, dscdb->maplen);
+ }
+ return DS_OK;
+}
+
+static HRESULT DSCDB_UnmapBuffer(IDsCaptureDriverBufferImpl *dscdb)
+{
+ if (dscdb->mapping) {
+ if (munmap(dscdb->mapping, dscdb->maplen) < 0) {
+ ERR("(%p): Could not unmap sound device (%s)\n",
+ dscdb, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ dscdb->mapping = NULL;
+ TRACE("(%p): sound device unmapped\n", dscdb);
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(
+ PIDSCDRIVERBUFFER iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ *ppobj = 0;
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsCaptureDriverBuffer) ) {
+ IDsCaptureDriverBuffer_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
+ if (!This->notify)
+ IDsCaptureDriverNotifyImpl_Create(This, &(This->notify));
+ if (This->notify) {
+ IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
+ *ppobj = (LPVOID)This->notify;
+ return DS_OK;
+ }
+ return E_FAIL;
+ }
+
+ if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
+ if (!This->property_set)
+ IDsCaptureDriverPropertySetImpl_Create(This, &(This->property_set));
+ if (This->property_set) {
+ IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
+ *ppobj = (LPVOID)This->property_set;
+ return DS_OK;
+ }
+ return E_FAIL;
+ }
+
+ FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
+ return DSERR_UNSUPPORTED;
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ DSCDB_UnmapBuffer(This);
+ if (This->notifies != NULL)
+ HeapFree(GetProcessHeap(), 0, This->notifies);
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(
+ PIDSCDRIVERBUFFER iface,
+ LPVOID* ppvAudio1,
+ LPDWORD pdwLen1,
+ LPVOID* ppvAudio2,
+ LPDWORD pdwLen2,
+ DWORD dwWritePosition,
+ DWORD dwWriteLen,
+ DWORD dwFlags)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ FIXME("(%p,%p,%p,%p,%p,%ld,%ld,0x%08lx): stub!\n",This,ppvAudio1,pdwLen1,
+ ppvAudio2,pdwLen2,dwWritePosition,dwWriteLen,dwFlags);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(
+ PIDSCDRIVERBUFFER iface,
+ LPVOID pvAudio1,
+ DWORD dwLen1,
+ LPVOID pvAudio2,
+ DWORD dwLen2)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ FIXME("(%p,%p,%ld,%p,%ld): stub!\n",This,pvAudio1,dwLen1,pvAudio2,dwLen2);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(
+ PIDSCDRIVERBUFFER iface,
+ LPDWORD lpdwCapture,
+ LPDWORD lpdwRead)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ count_info info;
+ DWORD ptr;
+ TRACE("(%p,%p,%p)\n",This,lpdwCapture,lpdwRead);
+
+ if (WInDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
+ ERR("device not open, but accessing?\n");
+ return DSERR_UNINITIALIZED;
+ }
+
+ if (!This->is_capturing) {
+ if (lpdwCapture)
+ *lpdwCapture = 0;
+ if (lpdwRead)
+ *lpdwRead = 0;
+ }
+
+ if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_GETIPTR) failed (%s)\n",
+ WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ ptr = info.ptr & ~3; /* align the pointer, just in case */
+ if (lpdwCapture) *lpdwCapture = ptr;
+ if (lpdwRead) {
+ /* add some safety margin (not strictly necessary, but...) */
+ if (WInDev[This->drv->wDevID].ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
+ *lpdwRead = ptr + 32;
+ else
+ *lpdwRead = ptr + WInDev[This->drv->wDevID].dwFragmentSize;
+ while (*lpdwRead > This->buflen)
+ *lpdwRead -= This->buflen;
+ }
+ TRACE("capturepos=%ld, readpos=%ld\n", lpdwCapture?*lpdwCapture:0, lpdwRead?*lpdwRead:0);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(
+ PIDSCDRIVERBUFFER iface,
+ LPDWORD lpdwStatus)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ TRACE("(%p,%p)\n",This,lpdwStatus);
+
+ if (This->is_capturing) {
+ if (This->is_looping)
+ *lpdwStatus = DSCBSTATUS_CAPTURING | DSCBSTATUS_LOOPING;
+ else
+ *lpdwStatus = DSCBSTATUS_CAPTURING;
+ } else
+ *lpdwStatus = 0;
+
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(
+ PIDSCDRIVERBUFFER iface,
+ DWORD dwFlags)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ int enable;
+ TRACE("(%p,%lx)\n",This,dwFlags);
+
+ if (This->is_capturing)
+ return DS_OK;
+
+ if (dwFlags & DSCBSTART_LOOPING)
+ This->is_looping = TRUE;
+
+ WInDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
+ enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+ if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ if (errno == EINVAL) {
+ /* Don't give up yet. OSS trigger support is inconsistent. */
+ if (WInDev[This->drv->wDevID].ossdev->open_count == 1) {
+ /* try the opposite output enable */
+ if (WInDev[This->drv->wDevID].ossdev->bOutputEnabled == FALSE)
+ WInDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
+ else
+ WInDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+ /* try it again */
+ enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+ if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0) {
+ This->is_capturing = TRUE;
+ return DS_OK;
+ }
+ }
+ }
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+ WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+ return DSERR_GENERIC;
+ }
+
+ This->is_capturing = TRUE;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ int enable;
+ TRACE("(%p)\n",This);
+
+ if (!This->is_capturing)
+ return DS_OK;
+
+ /* no more captureing */
+ WInDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+ enable = getEnables(WInDev[This->drv->wDevID].ossdev);
+ if (ioctl(WInDev[This->drv->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+ WInDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+
+ /* send a final event if necessary */
+ if (This->nrofnotifies > 0) {
+ if (This->notifies[This->nrofnotifies - 1].dwOffset == DSBPN_OFFSETSTOP)
+ SetEvent(This->notifies[This->nrofnotifies - 1].hEventNotify);
+ }
+
+ This->is_capturing = FALSE;
+ This->is_looping = FALSE;
+
+ /* Most OSS drivers just can't stop capturing without closing the device...
+ * so we need to somehow signal to our DirectSound implementation
+ * that it should completely recreate this HW buffer...
+ * this unexpected error code should do the trick... */
+ return DSERR_BUFFERLOST;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(
+ PIDSCDRIVERBUFFER iface,
+ LPWAVEFORMATEX pwfx)
+{
+ IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
+ FIXME("(%p): stub!\n",This);
+ return DSERR_UNSUPPORTED;
+}
+
+static IDsCaptureDriverBufferVtbl dscdbvt =
+{
+ IDsCaptureDriverBufferImpl_QueryInterface,
+ IDsCaptureDriverBufferImpl_AddRef,
+ IDsCaptureDriverBufferImpl_Release,
+ IDsCaptureDriverBufferImpl_Lock,
+ IDsCaptureDriverBufferImpl_Unlock,
+ IDsCaptureDriverBufferImpl_SetFormat,
+ IDsCaptureDriverBufferImpl_GetPosition,
+ IDsCaptureDriverBufferImpl_GetStatus,
+ IDsCaptureDriverBufferImpl_Start,
+ IDsCaptureDriverBufferImpl_Stop
+};
+
+static HRESULT WINAPI IDsCaptureDriverImpl_QueryInterface(
+ PIDSCDRIVER iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsCaptureDriver) ) {
+ IDsCaptureDriver_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(
+ PIDSCDRIVER iface,
+ PDSDRIVERDESC pDesc)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p,%p)\n",This,pDesc);
+
+ if (!pDesc) {
+ TRACE("invalid parameter\n");
+ return DSERR_INVALIDPARAM;
+ }
+
+ /* copy version from driver */
+ memcpy(pDesc, &(WInDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+
+ pDesc->dwFlags |= DSDDESC_USESYSTEMMEMORY;
+ pDesc->dnDevNode = WInDev[This->wDevID].waveDesc.dnDevNode;
+ pDesc->wVxdId = 0;
+ pDesc->wReserved = 0;
+ pDesc->ulDeviceNum = This->wDevID;
+ pDesc->dwHeapType = DSDHEAP_NOHEAP;
+ pDesc->pvDirectDrawHeap = NULL;
+ pDesc->dwMemStartAddress = 0;
+ pDesc->dwMemEndAddress = 0;
+ pDesc->dwMemAllocExtra = 0;
+ pDesc->pvReserved1 = NULL;
+ pDesc->pvReserved2 = NULL;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p)\n",This);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p)\n",This);
+ if (This->capture_buffer) {
+ ERR("problem with DirectSound: capture buffer not released\n");
+ return DSERR_GENERIC;
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(
+ PIDSCDRIVER iface,
+ PDSCDRIVERCAPS pCaps)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ TRACE("(%p,%p)\n",This,pCaps);
+ memcpy(pCaps, &(WInDev[This->wDevID].ossdev->dsc_caps), sizeof(DSCDRIVERCAPS));
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(
+ PIDSCDRIVER iface,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwFlags,
+ DWORD dwCardAddress,
+ LPDWORD pdwcbBufferSize,
+ LPBYTE *ppbBuffer,
+ LPVOID *ppvObj)
+{
+ IDsCaptureDriverImpl *This = (IDsCaptureDriverImpl *)iface;
+ IDsCaptureDriverBufferImpl** ippdscdb = (IDsCaptureDriverBufferImpl**)ppvObj;
+ HRESULT err;
+ audio_buf_info info;
+ int enable;
+ TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",This,pwfx,dwFlags,dwCardAddress,
+ pdwcbBufferSize,ppbBuffer,ppvObj);
+
+ if (This->capture_buffer) {
+ TRACE("already allocated\n");
+ return DSERR_ALLOCATED;
+ }
+
+ *ippdscdb = (IDsCaptureDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverBufferImpl));
+ if (*ippdscdb == NULL) {
+ TRACE("out of memory\n");
+ return DSERR_OUTOFMEMORY;
+ }
+
+ (*ippdscdb)->lpVtbl = &dscdbvt;
+ (*ippdscdb)->ref = 1;
+ (*ippdscdb)->drv = This;
+ (*ippdscdb)->notify = NULL;
+ (*ippdscdb)->notify_index = 0;
+ (*ippdscdb)->notifies = NULL;
+ (*ippdscdb)->nrofnotifies = 0;
+ (*ippdscdb)->property_set = NULL;
+ (*ippdscdb)->is_capturing = FALSE;
+ (*ippdscdb)->is_looping = FALSE;
+
+ if (WInDev[This->wDevID].state == WINE_WS_CLOSED) {
+ WAVEOPENDESC desc;
+ desc.hWave = 0;
+ desc.lpFormat = pwfx;
+ desc.dwCallback = 0;
+ desc.dwInstance = 0;
+ desc.uMappedDeviceID = 0;
+ desc.dnDevNode = 0;
+ err = widOpen(This->wDevID, &desc, dwFlags | WAVE_DIRECTSOUND);
+ if (err != MMSYSERR_NOERROR) {
+ TRACE("widOpen failed\n");
+ return err;
+ }
+ }
+
+ /* check how big the DMA buffer is now */
+ if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_GETISPACE) failed (%s)\n",
+ WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
+ HeapFree(GetProcessHeap(),0,*ippdscdb);
+ *ippdscdb = NULL;
+ return DSERR_GENERIC;
+ }
+ (*ippdscdb)->maplen = (*ippdscdb)->buflen = info.fragstotal * info.fragsize;
+
+ /* map the DMA buffer */
+ err = DSCDB_MapBuffer(*ippdscdb);
+ if (err != DS_OK) {
+ HeapFree(GetProcessHeap(),0,*ippdscdb);
+ *ippdscdb = NULL;
+ return err;
+ }
+
+ /* capture buffer is ready to go */
+ *pdwcbBufferSize = (*ippdscdb)->maplen;
+ *ppbBuffer = (*ippdscdb)->mapping;
+
+ /* some drivers need some extra nudging after mapping */
+ WInDev[This->wDevID].ossdev->bInputEnabled = FALSE;
+ enable = getEnables(WInDev[This->wDevID].ossdev);
+ if (ioctl(WInDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+ WInDev[This->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+
+ This->capture_buffer = *ippdscdb;
+
+ return DS_OK;
+}
+
+static IDsCaptureDriverVtbl dscdvt =
+{
+ IDsCaptureDriverImpl_QueryInterface,
+ IDsCaptureDriverImpl_AddRef,
+ IDsCaptureDriverImpl_Release,
+ IDsCaptureDriverImpl_GetDriverDesc,
+ IDsCaptureDriverImpl_Open,
+ IDsCaptureDriverImpl_Close,
+ IDsCaptureDriverImpl_GetCaps,
+ IDsCaptureDriverImpl_CreateCaptureBuffer
+};
+
+static HRESULT WINAPI IDsCaptureDriverPropertySetImpl_Create(
+ IDsCaptureDriverBufferImpl * dscdb,
+ IDsCaptureDriverPropertySetImpl **pdscdps)
+{
+ IDsCaptureDriverPropertySetImpl * dscdps;
+ TRACE("(%p,%p)\n",dscdb,pdscdps);
+
+ dscdps = (IDsCaptureDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdps));
+ if (dscdps == NULL) {
+ WARN("out of memory\n");
+ return DSERR_OUTOFMEMORY;
+ }
+
+ dscdps->ref = 0;
+ dscdps->lpVtbl = &dscdpsvt;
+ dscdps->capture_buffer = dscdb;
+ dscdb->property_set = dscdps;
+ IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
+
+ *pdscdps = dscdps;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsCaptureDriverNotifyImpl_Create(
+ IDsCaptureDriverBufferImpl * dscdb,
+ IDsCaptureDriverNotifyImpl **pdscdn)
+{
+ IDsCaptureDriverNotifyImpl * dscdn;
+ TRACE("(%p,%p)\n",dscdb,pdscdn);
+
+ dscdn = (IDsCaptureDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscdn));
+ if (dscdn == NULL) {
+ WARN("out of memory\n");
+ return DSERR_OUTOFMEMORY;
+ }
+
+ dscdn->ref = 0;
+ dscdn->lpVtbl = &dscdnvt;
+ dscdn->capture_buffer = dscdb;
+ dscdb->notify = dscdn;
+ IDsCaptureDriverBuffer_AddRef((PIDSCDRIVER)dscdb);
+
+ *pdscdn = dscdn;
+ return DS_OK;
+}
+
+DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv)
+{
+ IDsCaptureDriverImpl** idrv = (IDsCaptureDriverImpl**)drv;
+ TRACE("(%d,%p)\n",wDevID,drv);
+
+ /* the HAL isn't much better than the HEL if we can't do mmap() */
+ if (!(WInDev[wDevID].ossdev->in_caps_support & WAVECAPS_DIRECTSOUND)) {
+ ERR("DirectSoundCapture flag not set\n");
+ MESSAGE("This sound card's driver does not support direct access\n");
+ MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
+ return MMSYSERR_NOTSUPPORTED;
+ }
+
+ *idrv = (IDsCaptureDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsCaptureDriverImpl));
+ if (!*idrv)
+ return MMSYSERR_NOMEM;
+ (*idrv)->lpVtbl = &dscdvt;
+ (*idrv)->ref = 1;
+
+ (*idrv)->wDevID = wDevID;
+ (*idrv)->capture_buffer = NULL;
+ return MMSYSERR_NOERROR;
+}
+
+DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc)
+{
+ memcpy(desc, &(WInDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+ return MMSYSERR_NOERROR;
+}
+
+#endif /* HAVE_OSS */
--- /dev/null
+/*
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
+ *
+ * Copyright 1994 Martin Ayotte
+ * 1999 Eric Pouech (async playing in waveOut/waveIn)
+ * 2000 Eric Pouech (loops in waveOut)
+ * 2002 Eric Pouech (full duplex)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "wine/winuser16.h"
+#include "mmddk.h"
+#include "mmreg.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "oss.h"
+#include "wine/debug.h"
+
+#include "audio.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
+#ifdef HAVE_OSS
+
+/*======================================================================*
+ * Low level DSOUND definitions *
+ *======================================================================*/
+
+typedef struct IDsDriverPropertySetImpl IDsDriverPropertySetImpl;
+typedef struct IDsDriverNotifyImpl IDsDriverNotifyImpl;
+typedef struct IDsDriverImpl IDsDriverImpl;
+typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
+
+struct IDsDriverPropertySetImpl
+{
+ /* IUnknown fields */
+ IDsDriverPropertySetVtbl *lpVtbl;
+ DWORD ref;
+
+ IDsDriverBufferImpl* buffer;
+};
+
+struct IDsDriverNotifyImpl
+{
+ /* IUnknown fields */
+ IDsDriverNotifyVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDsDriverNotifyImpl fields */
+ LPDSBPOSITIONNOTIFY notifies;
+ int nrofnotifies;
+
+ IDsDriverBufferImpl* buffer;
+};
+
+struct IDsDriverImpl
+{
+ /* IUnknown fields */
+ IDsDriverVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDsDriverImpl fields */
+ UINT wDevID;
+ IDsDriverBufferImpl* primary;
+
+ int nrofsecondaries;
+ IDsDriverBufferImpl** secondaries;
+};
+
+struct IDsDriverBufferImpl
+{
+ /* IUnknown fields */
+ IDsDriverBufferVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDsDriverBufferImpl fields */
+ IDsDriverImpl* drv;
+ DWORD buflen;
+ WAVEFORMATPCMEX wfex;
+ LPBYTE mapping;
+ DWORD maplen;
+ int fd;
+ DWORD dwFlags;
+
+ /* IDsDriverNotifyImpl fields */
+ IDsDriverNotifyImpl* notify;
+ int notify_index;
+
+ /* IDsDriverPropertySetImpl fields */
+ IDsDriverPropertySetImpl* property_set;
+};
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
+ IDsDriverBufferImpl * dsdb,
+ IDsDriverPropertySetImpl **pdsdps);
+
+static HRESULT WINAPI IDsDriverNotifyImpl_Create(
+ IDsDriverBufferImpl * dsdb,
+ IDsDriverNotifyImpl **pdsdn);
+
+/*======================================================================*
+ * Low level DSOUND property set implementation *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_QueryInterface(
+ PIDSDRIVERPROPERTYSET iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriverPropertySet) ) {
+ IDsDriverPropertySet_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverPropertySetImpl_AddRef(PIDSDRIVERPROPERTYSET iface)
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverPropertySetImpl_Release(PIDSDRIVERPROPERTYSET iface)
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Get(
+ PIDSDRIVERPROPERTYSET iface,
+ PDSPROPERTY pDsProperty,
+ LPVOID pPropertyParams,
+ ULONG cbPropertyParams,
+ LPVOID pPropertyData,
+ ULONG cbPropertyData,
+ PULONG pcbReturnedData )
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ FIXME("(%p,%p,%p,%lx,%p,%lx,%p)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData,pcbReturnedData);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Set(
+ PIDSDRIVERPROPERTYSET iface,
+ PDSPROPERTY pDsProperty,
+ LPVOID pPropertyParams,
+ ULONG cbPropertyParams,
+ LPVOID pPropertyData,
+ ULONG cbPropertyData )
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ FIXME("(%p,%p,%p,%lx,%p,%lx)\n",This,pDsProperty,pPropertyParams,cbPropertyParams,pPropertyData,cbPropertyData);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_QuerySupport(
+ PIDSDRIVERPROPERTYSET iface,
+ REFGUID PropertySetId,
+ ULONG PropertyId,
+ PULONG pSupport )
+{
+ IDsDriverPropertySetImpl *This = (IDsDriverPropertySetImpl *)iface;
+ FIXME("(%p,%s,%lx,%p)\n",This,debugstr_guid(PropertySetId),PropertyId,pSupport);
+ return DSERR_UNSUPPORTED;
+}
+
+IDsDriverPropertySetVtbl dsdpsvt =
+{
+ IDsDriverPropertySetImpl_QueryInterface,
+ IDsDriverPropertySetImpl_AddRef,
+ IDsDriverPropertySetImpl_Release,
+ IDsDriverPropertySetImpl_Get,
+ IDsDriverPropertySetImpl_Set,
+ IDsDriverPropertySetImpl_QuerySupport,
+};
+
+/*======================================================================*
+ * Low level DSOUND notify implementation *
+ *======================================================================*/
+
+static HRESULT WINAPI IDsDriverNotifyImpl_QueryInterface(
+ PIDSDRIVERNOTIFY iface,
+ REFIID riid,
+ LPVOID *ppobj)
+{
+ IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriverNotify) ) {
+ IDsDriverNotify_AddRef(iface);
+ *ppobj = This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverNotifyImpl_AddRef(PIDSDRIVERNOTIFY iface)
+{
+ IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverNotifyImpl_Release(PIDSDRIVERNOTIFY iface)
+{
+ IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ IDsDriverBuffer_Release((PIDSDRIVERBUFFER)This->buffer);
+ if (This->notifies != NULL)
+ HeapFree(GetProcessHeap(), 0, This->notifies);
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsDriverNotifyImpl_SetNotificationPositions(
+ PIDSDRIVERNOTIFY iface,
+ DWORD howmuch,
+ LPCDSBPOSITIONNOTIFY notify)
+{
+ IDsDriverNotifyImpl *This = (IDsDriverNotifyImpl *)iface;
+ TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+
+ if (!notify) {
+ WARN("invalid parameter\n");
+ return DSERR_INVALIDPARAM;
+ }
+
+ if (TRACE_ON(wave)) {
+ int i;
+ for (i=0;i<howmuch;i++)
+ TRACE("notify at %ld to 0x%08lx\n",
+ notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+ }
+
+ /* Make an internal copy of the caller-supplied array.
+ * Replace the existing copy if one is already present. */
+ if (This->notifies)
+ This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ This->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
+ else
+ This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ howmuch * sizeof(DSBPOSITIONNOTIFY));
+
+ memcpy(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
+ This->nrofnotifies = howmuch;
+
+ return S_OK;
+}
+
+IDsDriverNotifyVtbl dsdnvt =
+{
+ IDsDriverNotifyImpl_QueryInterface,
+ IDsDriverNotifyImpl_AddRef,
+ IDsDriverNotifyImpl_Release,
+ IDsDriverNotifyImpl_SetNotificationPositions,
+};
+
+/*======================================================================*
+ * Low level DSOUND implementation *
+ *======================================================================*/
+
+static HRESULT DSDB_MapBuffer(IDsDriverBufferImpl *dsdb)
+{
+ TRACE("(%p), format=%ldx%dx%d\n", dsdb, dsdb->wfex.Format.nSamplesPerSec,
+ dsdb->wfex.Format.wBitsPerSample, dsdb->wfex.Format.nChannels);
+ if (!dsdb->mapping) {
+ dsdb->mapping = mmap(NULL, dsdb->maplen, PROT_WRITE, MAP_SHARED,
+ dsdb->fd, 0);
+ if (dsdb->mapping == (LPBYTE)-1) {
+ ERR("Could not map sound device for direct access (%s)\n", strerror(errno));
+ ERR("Use: \"HardwareAcceleration\" = \"Emulation\" in the [dsound] section of your config file.\n");
+ return DSERR_GENERIC;
+ }
+ TRACE("The sound device has been mapped for direct access at %p, size=%ld\n", dsdb->mapping, dsdb->maplen);
+
+ /* for some reason, es1371 and sblive! sometimes have junk in here.
+ * clear it, or we get junk noise */
+ /* some libc implementations are buggy: their memset reads from the buffer...
+ * to work around it, we have to zero the block by hand. We don't do the expected:
+ * memset(dsdb->mapping,0, dsdb->maplen);
+ */
+ {
+ unsigned char* p1 = dsdb->mapping;
+ unsigned len = dsdb->maplen;
+ unsigned char silence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 128 : 0;
+ unsigned long ulsilence = (dsdb->wfex.Format.wBitsPerSample == 8) ? 0x80808080 : 0;
+
+ if (len >= 16) /* so we can have at least a 4 long area to store... */
+ {
+ /* the mmap:ed value is (at least) dword aligned
+ * so, start filling the complete unsigned long:s
+ */
+ int b = len >> 2;
+ unsigned long* p4 = (unsigned long*)p1;
+
+ while (b--) *p4++ = ulsilence;
+ /* prepare for filling the rest */
+ len &= 3;
+ p1 = (unsigned char*)p4;
+ }
+ /* in all cases, fill the remaining bytes */
+ while (len-- != 0) *p1++ = silence;
+ }
+ }
+ return DS_OK;
+}
+
+static HRESULT DSDB_UnmapBuffer(IDsDriverBufferImpl *dsdb)
+{
+ TRACE("(%p)\n",dsdb);
+ if (dsdb->mapping) {
+ if (munmap(dsdb->mapping, dsdb->maplen) < 0) {
+ ERR("(%p): Could not unmap sound device (%s)\n", dsdb, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ dsdb->mapping = NULL;
+ TRACE("(%p): sound device unmapped\n", dsdb);
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_QueryInterface(PIDSDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),*ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriverBuffer) ) {
+ IDsDriverBuffer_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ if ( IsEqualGUID( &IID_IDsDriverNotify, riid ) ) {
+ if (!This->notify)
+ IDsDriverNotifyImpl_Create(This, &(This->notify));
+ if (This->notify) {
+ IDsDriverNotify_AddRef((PIDSDRIVERNOTIFY)This->notify);
+ *ppobj = (LPVOID)This->notify;
+ return DS_OK;
+ }
+ *ppobj = 0;
+ return E_FAIL;
+ }
+
+ if ( IsEqualGUID( &IID_IDsDriverPropertySet, riid ) ) {
+ if (!This->property_set)
+ IDsDriverPropertySetImpl_Create(This, &(This->property_set));
+ if (This->property_set) {
+ IDsDriverPropertySet_AddRef((PIDSDRIVERPROPERTYSET)This->property_set);
+ *ppobj = (LPVOID)This->property_set;
+ return DS_OK;
+ }
+ *ppobj = 0;
+ return E_FAIL;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverBufferImpl_AddRef(PIDSDRIVERBUFFER iface)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverBufferImpl_Release(PIDSDRIVERBUFFER iface)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref)
+ return ref;
+
+ if (This == This->drv->primary)
+ This->drv->primary = NULL;
+ else {
+ int i;
+ for (i = 0; i < This->drv->nrofsecondaries; i++)
+ if (This->drv->secondaries[i] == This)
+ break;
+ if (i < This->drv->nrofsecondaries) {
+ /* Put the last buffer of the list in the (now empty) position */
+ This->drv->secondaries[i] = This->drv->secondaries[This->drv->nrofsecondaries - 1];
+ This->drv->nrofsecondaries--;
+ This->drv->secondaries = HeapReAlloc(GetProcessHeap(),0,
+ This->drv->secondaries,
+ sizeof(PIDSDRIVERBUFFER)*This->drv->nrofsecondaries);
+ TRACE("(%p) buffer count is now %d\n", This, This->drv->nrofsecondaries);
+ }
+
+ WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingAllBuffers++;
+ WOutDev[This->drv->wDevID].ossdev->ds_caps.dwFreeHwMixingStreamingBuffers++;
+ }
+
+ DSDB_UnmapBuffer(This);
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ return 0;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
+ LPVOID*ppvAudio1,LPDWORD pdwLen1,
+ LPVOID*ppvAudio2,LPDWORD pdwLen2,
+ DWORD dwWritePosition,DWORD dwWriteLen,
+ DWORD dwFlags)
+{
+ /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+ /* since we (GetDriverDesc flags) have specified DSDDESC_DONTNEEDPRIMARYLOCK,
+ * and that we don't support secondary buffers, this method will never be called */
+ TRACE("(%p): stub\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
+ LPVOID pvAudio1,DWORD dwLen1,
+ LPVOID pvAudio2,DWORD dwLen2)
+{
+ /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+ TRACE("(%p): stub\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetFormat(PIDSDRIVERBUFFER iface,
+ LPWAVEFORMATEX pwfx)
+{
+ /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+
+ TRACE("(%p,%p)\n",iface,pwfx);
+ /* On our request (GetDriverDesc flags), DirectSound has by now used
+ * waveOutClose/waveOutOpen to set the format...
+ * unfortunately, this means our mmap() is now gone...
+ * so we need to somehow signal to our DirectSound implementation
+ * that it should completely recreate this HW buffer...
+ * this unexpected error code should do the trick... */
+ return DSERR_BUFFERLOST;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetFrequency(PIDSDRIVERBUFFER iface, DWORD dwFreq)
+{
+ /* IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; */
+ TRACE("(%p,%ld): stub\n",iface,dwFreq);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetVolumePan(PIDSDRIVERBUFFER iface, PDSVOLUMEPAN pVolPan)
+{
+ DWORD vol;
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ TRACE("(%p,%p)\n",This,pVolPan);
+
+ vol = pVolPan->dwTotalLeftAmpFactor | (pVolPan->dwTotalRightAmpFactor << 16);
+
+ if (wodSetVolume(This->drv->wDevID, vol) != MMSYSERR_NOERROR) {
+ WARN("wodSetVolume failed\n");
+ return DSERR_INVALIDPARAM;
+ }
+
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_SetPosition(PIDSDRIVERBUFFER iface, DWORD dwNewPos)
+{
+ /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
+ TRACE("(%p,%ld): stub\n",iface,dwNewPos);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
+ LPDWORD lpdwPlay, LPDWORD lpdwWrite)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ count_info info;
+ DWORD ptr;
+
+ TRACE("(%p)\n",iface);
+ if (WOutDev[This->drv->wDevID].state == WINE_WS_CLOSED) {
+ ERR("device not open, but accessing?\n");
+ return DSERR_UNINITIALIZED;
+ }
+ if (ioctl(This->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_GETOPTR) failed (%s)\n",
+ WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ ptr = info.ptr & ~3; /* align the pointer, just in case */
+ if (lpdwPlay) *lpdwPlay = ptr;
+ if (lpdwWrite) {
+ /* add some safety margin (not strictly necessary, but...) */
+ if (WOutDev[This->drv->wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
+ *lpdwWrite = ptr + 32;
+ else
+ *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
+ while (*lpdwWrite > This->buflen)
+ *lpdwWrite -= This->buflen;
+ }
+ TRACE("playpos=%ld, writepos=%ld\n", lpdwPlay?*lpdwPlay:0, lpdwWrite?*lpdwWrite:0);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Play(PIDSDRIVERBUFFER iface, DWORD dwRes1, DWORD dwRes2, DWORD dwFlags)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ int enable;
+ TRACE("(%p,%lx,%lx,%lx)\n",iface,dwRes1,dwRes2,dwFlags);
+ WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = TRUE;
+ enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+ if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ if (errno == EINVAL) {
+ /* Don't give up yet. OSS trigger support is inconsistent. */
+ if (WOutDev[This->drv->wDevID].ossdev->open_count == 1) {
+ /* try the opposite input enable */
+ if (WOutDev[This->drv->wDevID].ossdev->bInputEnabled == FALSE)
+ WOutDev[This->drv->wDevID].ossdev->bInputEnabled = TRUE;
+ else
+ WOutDev[This->drv->wDevID].ossdev->bInputEnabled = FALSE;
+ /* try it again */
+ enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+ if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) >= 0)
+ return DS_OK;
+ }
+ }
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+ WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+ return DSERR_GENERIC;
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface)
+{
+ IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
+ int enable;
+ TRACE("(%p)\n",iface);
+ /* no more playing */
+ WOutDev[This->drv->wDevID].ossdev->bOutputEnabled = FALSE;
+ enable = getEnables(WOutDev[This->drv->wDevID].ossdev);
+ if (ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+#if 0
+ /* the play position must be reset to the beginning of the buffer */
+ if (ioctl(This->fd, SNDCTL_DSP_RESET, 0) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_RESET) failed (%s)\n", WOutDev[This->drv->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+#endif
+ /* Most OSS drivers just can't stop the playback without closing the device...
+ * so we need to somehow signal to our DirectSound implementation
+ * that it should completely recreate this HW buffer...
+ * this unexpected error code should do the trick... */
+ /* FIXME: ...unless we are doing full duplex, then it's not nice to close the device */
+ if (WOutDev[This->drv->wDevID].ossdev->open_count == 1)
+ return DSERR_BUFFERLOST;
+
+ return DS_OK;
+}
+
+static IDsDriverBufferVtbl dsdbvt =
+{
+ IDsDriverBufferImpl_QueryInterface,
+ IDsDriverBufferImpl_AddRef,
+ IDsDriverBufferImpl_Release,
+ IDsDriverBufferImpl_Lock,
+ IDsDriverBufferImpl_Unlock,
+ IDsDriverBufferImpl_SetFormat,
+ IDsDriverBufferImpl_SetFrequency,
+ IDsDriverBufferImpl_SetVolumePan,
+ IDsDriverBufferImpl_SetPosition,
+ IDsDriverBufferImpl_GetPosition,
+ IDsDriverBufferImpl_Play,
+ IDsDriverBufferImpl_Stop
+};
+
+static HRESULT WINAPI IDsDriverImpl_QueryInterface(PIDSDRIVER iface, REFIID riid, LPVOID *ppobj)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+ if ( IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDsDriver) ) {
+ IDsDriver_AddRef(iface);
+ *ppobj = (LPVOID)This;
+ return DS_OK;
+ }
+
+ FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
+
+ *ppobj = 0;
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IDsDriverImpl_AddRef(PIDSDRIVER iface)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDsDriverImpl_Release(PIDSDRIVER iface)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ DWORD ref;
+ TRACE("(%p) ref was %ld\n", This, This->ref);
+
+ ref = InterlockedDecrement(&(This->ref));
+ if (ref == 0) {
+ HeapFree(GetProcessHeap(),0,This);
+ TRACE("(%p) released\n",This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IDsDriverImpl_GetDriverDesc(PIDSDRIVER iface,
+ PDSDRIVERDESC pDesc)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ TRACE("(%p,%p)\n",iface,pDesc);
+
+ /* copy version from driver */
+ memcpy(pDesc, &(WOutDev[This->wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+
+ pDesc->dwFlags |= DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT |
+ DSDDESC_USESYSTEMMEMORY | DSDDESC_DONTNEEDPRIMARYLOCK |
+ DSDDESC_DONTNEEDSECONDARYLOCK;
+ pDesc->dnDevNode = WOutDev[This->wDevID].waveDesc.dnDevNode;
+ pDesc->wVxdId = 0;
+ pDesc->wReserved = 0;
+ pDesc->ulDeviceNum = This->wDevID;
+ pDesc->dwHeapType = DSDHEAP_NOHEAP;
+ pDesc->pvDirectDrawHeap = NULL;
+ pDesc->dwMemStartAddress = 0;
+ pDesc->dwMemEndAddress = 0;
+ pDesc->dwMemAllocExtra = 0;
+ pDesc->pvReserved1 = NULL;
+ pDesc->pvReserved2 = NULL;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_Open(PIDSDRIVER iface)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ int enable;
+ TRACE("(%p)\n",iface);
+
+ /* make sure the card doesn't start playing before we want it to */
+ WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
+ enable = getEnables(WOutDev[This->wDevID].ossdev);
+ if (ioctl(WOutDev[This->wDevID].ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_Close(PIDSDRIVER iface)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ TRACE("(%p)\n",iface);
+ if (This->primary) {
+ ERR("problem with DirectSound: primary not released\n");
+ return DSERR_GENERIC;
+ }
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverImpl_GetCaps(PIDSDRIVER iface, PDSDRIVERCAPS pCaps)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ TRACE("(%p,%p)\n",iface,pCaps);
+ memcpy(pCaps, &(WOutDev[This->wDevID].ossdev->ds_caps), sizeof(DSDRIVERCAPS));
+ return DS_OK;
+}
+
+static HRESULT WINAPI DSD_CreatePrimaryBuffer(PIDSDRIVER iface,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwFlags,
+ DWORD dwCardAddress,
+ LPDWORD pdwcbBufferSize,
+ LPBYTE *ppbBuffer,
+ LPVOID *ppvObj)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
+ HRESULT err;
+ audio_buf_info info;
+ int enable = 0;
+ TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+ if (This->primary)
+ return DSERR_ALLOCATED;
+ if (dwFlags & (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN))
+ return DSERR_CONTROLUNAVAIL;
+
+ *ippdsdb = (IDsDriverBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverBufferImpl));
+ if (*ippdsdb == NULL)
+ return DSERR_OUTOFMEMORY;
+ (*ippdsdb)->lpVtbl = &dsdbvt;
+ (*ippdsdb)->ref = 1;
+ (*ippdsdb)->drv = This;
+ copy_format(pwfx, &(*ippdsdb)->wfex);
+ (*ippdsdb)->fd = WOutDev[This->wDevID].ossdev->fd;
+ (*ippdsdb)->dwFlags = dwFlags;
+
+ /* check how big the DMA buffer is now */
+ if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_GETOSPACE) failed (%s)\n",
+ WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+ HeapFree(GetProcessHeap(),0,*ippdsdb);
+ *ippdsdb = NULL;
+ return DSERR_GENERIC;
+ }
+ (*ippdsdb)->maplen = (*ippdsdb)->buflen = info.fragstotal * info.fragsize;
+
+ /* map the DMA buffer */
+ err = DSDB_MapBuffer(*ippdsdb);
+ if (err != DS_OK) {
+ HeapFree(GetProcessHeap(),0,*ippdsdb);
+ *ippdsdb = NULL;
+ return err;
+ }
+
+ /* primary buffer is ready to go */
+ *pdwcbBufferSize = (*ippdsdb)->maplen;
+ *ppbBuffer = (*ippdsdb)->mapping;
+
+ /* some drivers need some extra nudging after mapping */
+ WOutDev[This->wDevID].ossdev->bOutputEnabled = FALSE;
+ enable = getEnables(WOutDev[This->wDevID].ossdev);
+ if (ioctl((*ippdsdb)->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0) {
+ ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER) failed (%s)\n",
+ WOutDev[This->wDevID].ossdev->dev_name, strerror(errno));
+ return DSERR_GENERIC;
+ }
+
+ This->primary = *ippdsdb;
+
+ return DS_OK;
+}
+
+static HRESULT WINAPI DSD_CreateSecondaryBuffer(PIDSDRIVER iface,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwFlags,
+ DWORD dwCardAddress,
+ LPDWORD pdwcbBufferSize,
+ LPBYTE *ppbBuffer,
+ LPVOID *ppvObj)
+{
+ IDsDriverImpl *This = (IDsDriverImpl *)iface;
+ IDsDriverBufferImpl** ippdsdb = (IDsDriverBufferImpl**)ppvObj;
+ FIXME("(%p,%p,%lx,%lx,%p,%p,%p): stub\n",This,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+ *ippdsdb = 0;
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsDriverImpl_CreateSoundBuffer(PIDSDRIVER iface,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwFlags,
+ DWORD dwCardAddress,
+ LPDWORD pdwcbBufferSize,
+ LPBYTE *ppbBuffer,
+ LPVOID *ppvObj)
+{
+ TRACE("(%p,%p,%lx,%lx,%p,%p,%p)\n",iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+ if (dwFlags & DSBCAPS_PRIMARYBUFFER)
+ return DSD_CreatePrimaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+
+ return DSD_CreateSecondaryBuffer(iface,pwfx,dwFlags,dwCardAddress,pdwcbBufferSize,ppbBuffer,ppvObj);
+}
+
+static HRESULT WINAPI IDsDriverImpl_DuplicateSoundBuffer(PIDSDRIVER iface,
+ PIDSDRIVERBUFFER pBuffer,
+ LPVOID *ppvObj)
+{
+ /* IDsDriverImpl *This = (IDsDriverImpl *)iface; */
+ TRACE("(%p,%p): stub\n",iface,pBuffer);
+ return DSERR_INVALIDCALL;
+}
+
+static IDsDriverVtbl dsdvt =
+{
+ IDsDriverImpl_QueryInterface,
+ IDsDriverImpl_AddRef,
+ IDsDriverImpl_Release,
+ IDsDriverImpl_GetDriverDesc,
+ IDsDriverImpl_Open,
+ IDsDriverImpl_Close,
+ IDsDriverImpl_GetCaps,
+ IDsDriverImpl_CreateSoundBuffer,
+ IDsDriverImpl_DuplicateSoundBuffer
+};
+
+static HRESULT WINAPI IDsDriverPropertySetImpl_Create(
+ IDsDriverBufferImpl * dsdb,
+ IDsDriverPropertySetImpl **pdsdps)
+{
+ IDsDriverPropertySetImpl * dsdps;
+ TRACE("(%p,%p)\n",dsdb,pdsdps);
+
+ dsdps = (IDsDriverPropertySetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdps));
+ if (dsdps == NULL) {
+ WARN("out of memory\n");
+ return DSERR_OUTOFMEMORY;
+ }
+
+ dsdps->ref = 0;
+ dsdps->lpVtbl = &dsdpsvt;
+ dsdps->buffer = dsdb;
+ dsdb->property_set = dsdps;
+ IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
+
+ *pdsdps = dsdps;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDsDriverNotifyImpl_Create(
+ IDsDriverBufferImpl * dsdb,
+ IDsDriverNotifyImpl **pdsdn)
+{
+ IDsDriverNotifyImpl * dsdn;
+ TRACE("(%p,%p)\n",dsdb,pdsdn);
+
+ dsdn = (IDsDriverNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsdn));
+
+ if (dsdn == NULL) {
+ WARN("out of memory\n");
+ return DSERR_OUTOFMEMORY;
+ }
+
+ dsdn->ref = 0;
+ dsdn->lpVtbl = &dsdnvt;
+ dsdn->buffer = dsdb;
+ dsdb->notify = dsdn;
+ IDsDriverBuffer_AddRef((PIDSDRIVER)dsdb);
+
+ *pdsdn = dsdn;
+ return DS_OK;
+};
+
+DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
+{
+ IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
+ TRACE("(%d,%p)\n",wDevID,drv);
+
+ /* the HAL isn't much better than the HEL if we can't do mmap() */
+ if (!(WOutDev[wDevID].ossdev->duplex_out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
+ ERR("DirectSound flag not set\n");
+ MESSAGE("This sound card's driver does not support direct access\n");
+ MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
+ return MMSYSERR_NOTSUPPORTED;
+ }
+
+ *idrv = (IDsDriverImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDsDriverImpl));
+ if (!*idrv)
+ return MMSYSERR_NOMEM;
+ (*idrv)->lpVtbl = &dsdvt;
+ (*idrv)->ref = 1;
+ (*idrv)->wDevID = wDevID;
+ (*idrv)->primary = NULL;
+ (*idrv)->nrofsecondaries = 0;
+ (*idrv)->secondaries = NULL;
+
+ return MMSYSERR_NOERROR;
+}
+
+DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
+{
+ TRACE("(%d,%p)\n",wDevID,desc);
+ memcpy(desc, &(WOutDev[wDevID].ossdev->ds_desc), sizeof(DSDRIVERDESC));
+ return MMSYSERR_NOERROR;
+}
+
+#endif /* HAVE_OSS */