From 93d3492f7f8e56f7dd4fd71f12d94d6ce089fedf Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 8 Oct 2003 22:35:26 +0000 Subject: [PATCH] Make capture more reliable by submitting all buffers before start. Added support for non pcm formats. Added more property set support. --- dlls/dsound/capture.c | 80 ++++++++++++++++++++--------------- dlls/dsound/dsound_private.h | 4 +- dlls/dsound/propset.c | 99 +++++++++++++++++++++++++++++++++++++++++++- dlls/dsound/tests/capture.c | 54 +++++++++++++++++++----- 4 files changed, 188 insertions(+), 49 deletions(-) diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index 5d61d061d19..3948882a912 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -79,7 +79,7 @@ static ICOM_VTABLE(IDirectSoundCapture) dscvt; static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt; static ICOM_VTABLE(IDirectSoundFullDuplex) dsfdvt; -IDirectSoundCaptureImpl* dsound_capture = NULL; +static IDirectSoundCaptureImpl* dsound_capture = NULL; /*************************************************************************** * DirectSoundCaptureCreate [DSOUND.6] @@ -316,6 +316,7 @@ DSOUND_capture_callback( EnterCriticalSection( &(This->lock) ); TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%ld, old This->index=%d\n",This->state,This->index); if (This->state != STATE_STOPPED) { + int index = This->index; if (This->state == STATE_STARTING) { MMTIME mtime; mtime.wType = TIME_BYTES; @@ -334,8 +335,8 @@ DSOUND_capture_callback( This->state = STATE_STOPPED; } else { if (This->state == STATE_CAPTURING) { - waveInPrepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR)); - waveInAddBuffer(hwi, &(This->pwave[This->index]), sizeof(WAVEHDR)); + waveInPrepareHeader(hwi,&(This->pwave[index]),sizeof(WAVEHDR)); + waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR)); } } } @@ -416,6 +417,9 @@ IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface ) IDsCaptureDriver_Release(This->driver); } + if (This->pwfx) + HeapFree(GetProcessHeap(), 0, This->pwfx); + DeleteCriticalSection( &(This->lock) ); HeapFree( GetProcessHeap(), 0, This ); dsound_capture = NULL; @@ -678,12 +682,13 @@ DSOUND_CreateDirectSoundCaptureBuffer( wfex->nAvgBytesPerSec, wfex->nBlockAlign, wfex->wBitsPerSample, wfex->cbSize); - if (wfex->wFormatTag == WAVE_FORMAT_PCM) - memcpy(&(ipDSC->wfx), wfex, sizeof(WAVEFORMATEX)); - else { - WARN("non PCM formats not supported\n"); - *ppobj = NULL; - return DSERR_BADFORMAT; + if (wfex->wFormatTag == WAVE_FORMAT_PCM) { + ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)); + memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)); + ipDSC->pwfx->cbSize = 0; + } else { + ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize); + memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize); } } else { WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n"); @@ -725,7 +730,7 @@ DSOUND_CreateDirectSoundCaptureBuffer( if (ipDSC->driver) { err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver, - &(ipDSC->wfx),0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf)); + ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf)); if (err != DS_OK) { WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n"); This->dsound->capture_buffer = 0; @@ -740,7 +745,7 @@ DSOUND_CreateDirectSoundCaptureBuffer( if (ds_hw_accel != DS_HW_ACCEL_EMULATION) flags |= WAVE_DIRECTSOUND; err = mmErr(waveInOpen(&(ipDSC->hwi), - ipDSC->drvdesc.dnDevNode, &(ipDSC->wfx), + ipDSC->drvdesc.dnDevNode, ipDSC->pwfx, (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags)); if (err != DS_OK) { WARN("waveInOpen failed\n"); @@ -1135,16 +1140,16 @@ IDirectSoundCaptureBufferImpl_GetFormat( return DSERR_INVALIDPARAM; } - /* FIXME: use real size for extended formats someday */ - if (dwSizeAllocated > sizeof(This->dsound->wfx)) - dwSizeAllocated = sizeof(This->dsound->wfx); + if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize)) + dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; + if (lpwfxFormat) { /* NULL is valid (just want size) */ - memcpy(lpwfxFormat,&(This->dsound->wfx),dwSizeAllocated); + memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated); if (lpdwSizeWritten) *lpdwSizeWritten = dwSizeAllocated; } else { if (lpdwSizeWritten) - *lpdwSizeWritten = sizeof(This->dsound->wfx); + *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; else { TRACE("invalid parameter: lpdwSizeWritten = NULL\n"); return DSERR_INVALIDPARAM; @@ -1328,6 +1333,7 @@ IDirectSoundCaptureBufferImpl_Start( unsigned c; ipDSC->nrofpwaves = This->nrofnotifies; + TRACE("nrofnotifies=%d\n", This->nrofnotifies); /* prepare headers */ ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave, @@ -1350,16 +1356,25 @@ IDirectSoundCaptureBufferImpl_Start( ipDSC->pwave[c].dwLoops = 0; err = mmErr(waveInPrepareHeader(ipDSC->hwi, &(ipDSC->pwave[c]),sizeof(WAVEHDR))); - if (err != DS_OK) { + if (err != DS_OK) { + while (c--) + waveInUnprepareHeader(ipDSC->hwi, + &(ipDSC->pwave[c]),sizeof(WAVEHDR)); + break; + } + + err = mmErr(waveInAddBuffer(ipDSC->hwi, + &(ipDSC->pwave[c]), sizeof(WAVEHDR))); + if (err != DS_OK) { while (c--) - waveInUnprepareHeader(ipDSC->hwi, - &(ipDSC->pwave[c]),sizeof(WAVEHDR)); - break; - } + waveInUnprepareHeader(ipDSC->hwi, + &(ipDSC->pwave[c]),sizeof(WAVEHDR)); + break; + } } memset(ipDSC->buffer, - (ipDSC->wfx.wBitsPerSample == 16) ? 0 : 128, ipDSC->buflen); + (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen); } else { TRACE("no notifiers specified\n"); /* no notifiers specified so just create a single default header */ @@ -1378,6 +1393,12 @@ IDirectSoundCaptureBufferImpl_Start( waveInUnprepareHeader(ipDSC->hwi, &(ipDSC->pwave[0]),sizeof(WAVEHDR)); } + err = mmErr(waveInAddBuffer(ipDSC->hwi, + &(ipDSC->pwave[0]), sizeof(WAVEHDR))); + if (err != DS_OK) { + waveInUnprepareHeader(ipDSC->hwi, + &(ipDSC->pwave[0]),sizeof(WAVEHDR)); + } } } @@ -1385,17 +1406,8 @@ IDirectSoundCaptureBufferImpl_Start( ipDSC->read_position = 0; if (err == DS_OK) { - err = mmErr(waveInReset(ipDSC->hwi)); - if (err == DS_OK) { - /* add the first buffer to the queue */ - err = mmErr(waveInAddBuffer(ipDSC->hwi, &(ipDSC->pwave[0]), sizeof(WAVEHDR))); - if (err == DS_OK) { - /* start filling the first buffer */ - err = mmErr(waveInStart(ipDSC->hwi)); - } else - WARN("waveInAddBuffer failed\n"); - } else - WARN("waveInReset failed\n"); + /* start filling the first buffer */ + err = mmErr(waveInStart(ipDSC->hwi)); } } @@ -1443,7 +1455,7 @@ IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) /* Wine-only: the driver wants us to reopen the device */ IDsCaptureDriverBuffer_Release(This->dsound->hwbuf); err = IDsCaptureDriver_CreateCaptureBuffer(This->dsound->driver, - &(This->dsound->wfx),0,0,&(This->dsound->buflen),&(This->dsound->buffer), + This->dsound->pwfx,0,0,&(This->dsound->buflen),&(This->dsound->buffer), (LPVOID*)&(This->dsound->hwbuf)); if (err != DS_OK) { WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n"); diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 41a205abe2c..77f0c531c31 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -211,8 +211,7 @@ struct IDirectSoundCaptureImpl DWORD buflen; DWORD read_position; - /* FIXME: this should be a pointer because it can be bigger */ - WAVEFORMATEX wfx; + PWAVEFORMATEX pwfx; IDirectSoundCaptureBufferImpl* capture_buffer; DWORD state; @@ -400,7 +399,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb); #define DSOUND_FREQSHIFT (14) extern IDirectSoundImpl* dsound; -extern IDirectSoundCaptureImpl* dsound_capture; extern HRESULT mmErr(UINT err); extern void setup_dsound_options(void); diff --git a/dlls/dsound/propset.c b/dlls/dsound/propset.c index f5abbe22c50..11f18ec2bfb 100644 --- a/dlls/dsound/propset.c +++ b/dlls/dsound/propset.c @@ -597,6 +597,55 @@ static HRESULT WINAPI DSPROPERTY_DescriptionA( return E_PROP_ID_UNSUPPORTED; } } + } else { + BOOL found = FALSE; + ULONG wod; + int wodn; + /* given specific device so try the render devices first */ + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0)); + if (err == DS_OK) { + if (IsEqualGUID( &ppd->DeviceId, &guid) ) { + DSDRIVERDESC desc; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + ppd->WaveDeviceId = wod; + err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); + CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvName) + 1); + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); + + strcpy(szDescription, desc.szDesc); + strcpy(szModule, desc.szDrvName); + strcpy(szInterface, "Interface"); + + ppd->Description = szDescription; + ppd->Module = szModule; + ppd->Interface = szInterface; + err = mmErr(waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + found = TRUE; + break; + } else { + WARN("waveOutMessage failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } else { + WARN("waveOutMessage failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + + if (found == FALSE) { + WARN("device not found\n"); + return E_PROP_ID_UNSUPPORTED; + } } if (pcbReturned) { @@ -723,8 +772,54 @@ static HRESULT WINAPI DSPROPERTY_DescriptionW( } } } else { - FIXME("DeviceId=Unknown\n"); - return E_PROP_ID_UNSUPPORTED; + BOOL found = FALSE; + ULONG wod; + int wodn; + /* given specific device so try the render devices first */ + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0)); + if (err == DS_OK) { + if (IsEqualGUID( &ppd->DeviceId, &guid) ) { + DSDRIVERDESC desc; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + ppd->WaveDeviceId = wod; + err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); + + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvName, -1, wModule, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); + + ppd->Description = wDescription; + ppd->Module = wModule; + ppd->Interface = wInterface; + err = mmErr(waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + found = TRUE; + break; + } else { + WARN("waveOutMessage failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } else { + WARN("waveOutMessage failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + + if (found == FALSE) { + WARN("device not found\n"); + return E_PROP_ID_UNSUPPORTED; + } } if (pcbReturned) { diff --git a/dlls/dsound/tests/capture.c b/dlls/dsound/tests/capture.c index 7b94e1735f7..474fb9bcaa4 100644 --- a/dlls/dsound/tests/capture.c +++ b/dlls/dsound/tests/capture.c @@ -25,11 +25,13 @@ #include #include +#include #include "wine/test.h" #include "windef.h" #include "wingdi.h" #include "dsound.h" +#include "mmreg.h" static const unsigned int formats[][3]={ { 8000, 8, 1}, @@ -61,17 +63,32 @@ static const unsigned int formats[][3]={ #define NOTIFICATIONS 5 -static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels) +static void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth, int channels) { - wfx->wFormatTag=WAVE_FORMAT_PCM; + wfx->wFormatTag=format; wfx->nChannels=channels; wfx->wBitsPerSample=depth; wfx->nSamplesPerSec=rate; wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; - wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; + if (wfx->nBlockAlign==0) /* align compressed formats to byte boundry */ + wfx->nBlockAlign=1; + wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nChannels*wfx->wBitsPerSample/8; wfx->cbSize=0; } +static char * format_string(WAVEFORMATEX* wfx) +{ + static char str[64]; + + sprintf(str, "%ldx%dx%d %s", + wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels, + wfx->wFormatTag == WAVE_FORMAT_PCM ? "PCM" : + wfx->wFormatTag == WAVE_FORMAT_MULAW ? "MULAW" : + wfx->wFormatTag == WAVE_FORMAT_IMA_ADPCM ? "IMA ADPCM" : "Unknown"); + + return str; +} + typedef struct { char* wave; DWORD wave_len; @@ -325,7 +342,7 @@ static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, /* Private dsound.dll: Error: Invalid buffer size */ /* Private dsound.dll: Error: Invalid capture buffer description */ - init_format(&wfx,11025,8,1); + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=0; @@ -341,15 +358,14 @@ static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, for (f=0;f