From 0e3c524f4cfd30580b9d2cdf4282621e3b4b1ce8 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 26 Oct 2004 22:04:55 +0000 Subject: [PATCH] Split up audio.c into three separate .c files: audio.c: OSS functions and waveIn and waveOut driver functions. dscapture.c: direct sound capture driver implementation. dsrender.c: direct sound renderer driver implementation. --- dlls/winmm/wineoss/Makefile.in | 2 + dlls/winmm/wineoss/audio.c | 1895 +------------------------------- dlls/winmm/wineoss/audio.h | 181 +++ dlls/winmm/wineoss/dscapture.c | 901 +++++++++++++++ dlls/winmm/wineoss/dsrender.c | 958 ++++++++++++++++ 5 files changed, 2056 insertions(+), 1881 deletions(-) create mode 100644 dlls/winmm/wineoss/audio.h create mode 100644 dlls/winmm/wineoss/dscapture.c create mode 100644 dlls/winmm/wineoss/dsrender.c diff --git a/dlls/winmm/wineoss/Makefile.in b/dlls/winmm/wineoss/Makefile.in index f7a0d78f7b8..c3655263e83 100644 --- a/dlls/winmm/wineoss/Makefile.in +++ b/dlls/winmm/wineoss/Makefile.in @@ -8,6 +8,8 @@ EXTRALIBS = -ldxguid -luuid C_SRCS = \ audio.c \ + dscapture.c \ + dsrender.c \ midi.c \ midipatch.c \ mixer.c \ diff --git a/dlls/winmm/wineoss/audio.c b/dlls/winmm/wineoss/audio.c index 35d05813faa..817a504dec5 100644 --- a/dlls/winmm/wineoss/audio.c +++ b/dlls/winmm/wineoss/audio.c @@ -1,4 +1,3 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ /* * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD) * @@ -29,9 +28,6 @@ /*#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 @@ -74,6 +70,8 @@ #include "oss.h" #include "wine/debug.h" +#include "audio.h" + WINE_DEFAULT_DEBUG_CHANNEL(wave); /* Allow 1% deviation for sample rates (some ES137x cards) */ @@ -81,7 +79,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave); #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: * @@ -100,141 +102,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave); * +---------+-------------+---------------+---------------------------------+ */ -/* 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) { @@ -256,7 +123,7 @@ 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) ); @@ -412,7 +279,7 @@ static BOOL supportedFormat(LPWAVEFORMATEX wf) 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) @@ -535,7 +402,7 @@ error2: * 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) { @@ -641,7 +508,7 @@ static DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access, * * */ -static void OSS_CloseDevice(OSS_DEVICE* ossdev) +void OSS_CloseDevice(OSS_DEVICE* ossdev) { TRACE("(%p)\n",ossdev); if (ossdev->open_count>0) { @@ -1900,7 +1767,7 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize) /************************************************************************** * 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; @@ -2331,7 +2198,7 @@ static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol) /************************************************************************** * wodSetVolume [internal] */ -static DWORD wodSetVolume(WORD wDevID, DWORD dwParam) +DWORD wodSetVolume(WORD wDevID, DWORD dwParam) { int mixer; int volume; @@ -2411,900 +2278,6 @@ DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 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;inotifies) - 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 * *======================================================================*/ @@ -3703,7 +2676,7 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) /************************************************************************** * 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; @@ -4049,846 +3022,6 @@ DWORD WINAPI OSS_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 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;icapture_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 */ /************************************************************************** diff --git a/dlls/winmm/wineoss/audio.h b/dlls/winmm/wineoss/audio.h new file mode 100644 index 00000000000..27e5274e404 --- /dev/null +++ b/dlls/winmm/wineoss/audio.h @@ -0,0 +1,181 @@ +/* + * 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 */ diff --git a/dlls/winmm/wineoss/dscapture.c b/dlls/winmm/wineoss/dscapture.c new file mode 100644 index 00000000000..cfc7c849568 --- /dev/null +++ b/dlls/winmm/wineoss/dscapture.c @@ -0,0 +1,901 @@ +/* + * 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 +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#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;icapture_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 */ diff --git a/dlls/winmm/wineoss/dsrender.c b/dlls/winmm/wineoss/dsrender.c new file mode 100644 index 00000000000..250dba90f77 --- /dev/null +++ b/dlls/winmm/wineoss/dsrender.c @@ -0,0 +1,958 @@ +/* + * 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 +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#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;inotifies) + 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 */