Started to add support for a real direct sound capture driver.
Changed the capture fragment size but this still needs tuning for best
performance.
diff --git a/dlls/winmm/wineoss/audio.c b/dlls/winmm/wineoss/audio.c
index ab24acf..72df7cc 100644
--- a/dlls/winmm/wineoss/audio.c
+++ b/dlls/winmm/wineoss/audio.c
@@ -149,6 +149,7 @@
unsigned open_count;
WAVEOUTCAPSA out_caps;
WAVEINCAPSA in_caps;
+ DWORD in_caps_support;
unsigned open_access;
int fd;
DWORD owner_tid;
@@ -217,6 +218,7 @@
static unsigned numInDev;
static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
+static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv);
/* These strings used only for tracing */
static const char *wodPlayerCmdString[] = {
@@ -590,6 +592,9 @@
TRACE("OSS dsp in caps=%08X\n", arg);
if (arg & DSP_CAP_TRIGGER)
ossdev->bTriggerSupport = TRUE;
+ if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) &&
+ !(arg & DSP_CAP_BATCH))
+ ossdev->in_caps_support |= WAVECAPS_DIRECTSOUND;
}
OSS_CloseDevice(ossdev);
TRACE("in dwFormats = %08lX\n", ossdev->in_caps.dwFormats);
@@ -2493,13 +2498,36 @@
wwi = &WInDev[wDevID];
if (wwi->state != WINE_WS_CLOSED) return MMSYSERR_ALLOCATED;
- /* This is actually hand tuned to work so that my SB Live:
- * - does not skip
- * - does not buffer too much
- * when sending with the Shoutcast winamp plugin
- */
- /* 15 fragments max, 2^10 = 1024 bytes per fragment */
- audio_fragment = 0x000F000A;
+
+ if ((dwFlags & WAVE_DIRECTSOUND) &&
+ !(wwi->ossdev->in_caps_support & WAVECAPS_DIRECTSOUND))
+ /* not supported, ignore it */
+ dwFlags &= ~WAVE_DIRECTSOUND;
+
+ if (dwFlags & WAVE_DIRECTSOUND) {
+ TRACE("has DirectSoundCapture driver\n");
+ if (wwi->ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
+ /* we have realtime DirectSound, fragments just waste our time,
+ * but a large buffer is good, so choose 64KB (32 * 2^11) */
+ audio_fragment = 0x0020000B;
+ else
+ /* to approximate realtime, we must use small fragments,
+ * let's try to fragment the above 64KB (256 * 2^8) */
+ audio_fragment = 0x01000008;
+ } else {
+ TRACE("doesn't have DirectSoundCapture driver\n");
+ /* This is actually hand tuned to work so that my SB Live:
+ * - does not skip
+ * - does not buffer too much
+ * when sending with the Shoutcast winamp plugin
+ */
+ /* 15 fragments max, 2^10 = 1024 bytes per fragment */
+/* audio_fragment = 0x000F000A; */
+ audio_fragment = 0x01000008;
+ }
+
+ TRACE("using %d %d byte fragments\n", audio_fragment >> 16, 1 << (audio_fragment & 0xffff));
+
ret = OSS_OpenDevice(wwi->ossdev, O_RDONLY, &audio_fragment,
1,
lpDesc->lpFormat->nSamplesPerSec,
@@ -2720,7 +2748,7 @@
break;
case TIME_SAMPLES:
lpTime->u.sample = wwi->dwTotalRecorded * 8 /
- wwi->format.wBitsPerSample;
+ wwi->format.wBitsPerSample / wwi->format.wf.nChannels;
TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
break;
case TIME_SMPTE:
@@ -2777,12 +2805,234 @@
case WIDM_RESET: return widReset (wDevID);
case WIDM_START: return widStart (wDevID);
case WIDM_STOP: return widStop (wDevID);
+ case DRV_QUERYDSOUNDIFACE: return widDsCreate (wDevID, (PIDSCDRIVER*)dwParam1);
default:
FIXME("unknown message %u!\n", wMsg);
}
return MMSYSERR_NOTSUPPORTED;
}
+/*======================================================================*
+ * Low level DSOUND capture implementation *
+ *======================================================================*/
+
+typedef struct IDsCaptureDriverImpl IDsCaptureDriverImpl;
+typedef struct IDsCaptureDriverBufferImpl IDsCaptureDriverBufferImpl;
+
+struct IDsCaptureDriverImpl
+{
+ /* IUnknown fields */
+ ICOM_VFIELD(IDsCaptureDriver);
+ DWORD ref;
+ /* IDsCaptureDriverImpl fields */
+ UINT wDevID;
+ IDsCaptureDriverBufferImpl* capture_buffer;
+};
+
+struct IDsCaptureDriverBufferImpl
+{
+ /* IUnknown fields */
+ ICOM_VFIELD(IDsCaptureDriverBuffer);
+ DWORD ref;
+ /* IDsCaptureDriverBufferImpl fields */
+ IDsCaptureDriverImpl* drv;
+ DWORD buflen;
+};
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_QueryInterface(PIDSCDRIVERBUFFER iface, REFIID riid, LPVOID *ppobj)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(): stub!\n");
+ return DSERR_UNSUPPORTED;
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_AddRef(PIDSCDRIVERBUFFER iface)
+{
+ ICOM_THIS(IDsCaptureDriverBufferImpl,iface);
+ This->ref++;
+ return This->ref;
+}
+
+static ULONG WINAPI IDsCaptureDriverBufferImpl_Release(PIDSCDRIVERBUFFER iface)
+{
+ ICOM_THIS(IDsCaptureDriverBufferImpl,iface);
+ if (--This->ref)
+ return This->ref;
+ HeapFree(GetProcessHeap(),0,This);
+ return 0;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Lock(PIDSCDRIVERBUFFER iface,
+ LPVOID*ppvAudio1,LPDWORD pdwLen1,
+ LPVOID*ppvAudio2,LPDWORD pdwLen2,
+ DWORD dwWritePosition,DWORD dwWriteLen,
+ DWORD dwFlags)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p): stub\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Unlock(PIDSCDRIVERBUFFER iface,
+ LPVOID pvAudio1,DWORD dwLen1,
+ LPVOID pvAudio2,DWORD dwLen2)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p): stub\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(PIDSCDRIVERBUFFER iface,
+ LPDWORD lpdwCapture, LPDWORD lpdwWrite)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p,%p,%p): stub!\n",iface,lpdwCapture,lpdwWrite);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(PIDSCDRIVERBUFFER iface, LPDWORD lpdwStatus)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p,%p): stub!\n",iface,lpdwStatus);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Start(PIDSCDRIVERBUFFER iface, DWORD dwFlags)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p,%lx): stub!\n",iface,dwFlags);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_Stop(PIDSCDRIVERBUFFER iface)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p): stub!\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER iface, LPWAVEFORMATEX pwfx)
+{
+ /*ICOM_THIS(IDsCaptureDriverBufferImpl,iface);*/
+ FIXME("(%p): stub!\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static ICOM_VTABLE(IDsCaptureDriverBuffer) dscdbvt =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ 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)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p): stub!\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_AddRef(PIDSCDRIVER iface)
+{
+ ICOM_THIS(IDsCaptureDriverImpl,iface);
+ This->ref++;
+ return This->ref;
+}
+
+static ULONG WINAPI IDsCaptureDriverImpl_Release(PIDSCDRIVER iface)
+{
+ ICOM_THIS(IDsCaptureDriverImpl,iface);
+ if (--This->ref)
+ return This->ref;
+ HeapFree(GetProcessHeap(),0,This);
+ return 0;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetDriverDesc(PIDSCDRIVER iface, PDSDRIVERDESC pDesc)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p,%p): stub!\n",iface,pDesc);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Open(PIDSCDRIVER iface)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p): stub!\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_Close(PIDSCDRIVER iface)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p): stub!\n",iface);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_GetCaps(PIDSCDRIVER iface, PDSDRIVERCAPS pCaps)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p,%p): stub!\n",iface,pCaps);
+ return DSERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IDsCaptureDriverImpl_CreateCaptureBuffer(PIDSCDRIVER iface,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwFlags, DWORD dwCardAddress,
+ LPDWORD pdwcbBufferSize,
+ LPBYTE *ppbBuffer,
+ LPVOID *ppvObj)
+{
+ /*ICOM_THIS(IDsCaptureDriverImpl,iface);*/
+ FIXME("(%p,%p,%lx,%lx): stub!\n",iface,pwfx,dwFlags,dwCardAddress);
+ return DSERR_UNSUPPORTED;
+}
+static ICOM_VTABLE(IDsCaptureDriver) dscdvt =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ IDsCaptureDriverImpl_QueryInterface,
+ IDsCaptureDriverImpl_AddRef,
+ IDsCaptureDriverImpl_Release,
+ IDsCaptureDriverImpl_GetDriverDesc,
+ IDsCaptureDriverImpl_Open,
+ IDsCaptureDriverImpl_Close,
+ IDsCaptureDriverImpl_GetCaps,
+ IDsCaptureDriverImpl_CreateCaptureBuffer
+};
+
+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(),0,sizeof(IDsCaptureDriverImpl));
+ if (!*idrv)
+ return MMSYSERR_NOMEM;
+ ICOM_VTBL(*idrv) = &dscdvt;
+ (*idrv)->ref = 1;
+
+ (*idrv)->wDevID = wDevID;
+ (*idrv)->capture_buffer = NULL;
+ return MMSYSERR_NOERROR;
+}
+
#else /* !HAVE_OSS */
/**************************************************************************