Make capture more reliable by submitting all buffers before start.

Added support for non pcm formats.
Added more property set support.
This commit is contained in:
Robert Reif 2003-10-08 22:35:26 +00:00 committed by Alexandre Julliard
parent e5e1844d24
commit 93d3492f7f
4 changed files with 189 additions and 50 deletions

View File

@ -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,
@ -1356,10 +1362,19 @@ IDirectSoundCaptureBufferImpl_Start(
&(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;
}
}
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,24 +1393,21 @@ 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));
}
}
}
ipDSC->index = 0;
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");
}
}
@ -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");

View File

@ -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);

View File

@ -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,9 +772,55 @@ static HRESULT WINAPI DSPROPERTY_DescriptionW(
}
}
} else {
FIXME("DeviceId=Unknown\n");
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) {
*pcbReturned = cbPropData;

View File

@ -25,11 +25,13 @@
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#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<NB_FORMATS;f++) {
dscbo=NULL;
init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],formats[f][2]);
ZeroMemory(&bufdesc, sizeof(bufdesc));
bufdesc.dwSize=sizeof(bufdesc);
bufdesc.dwFlags=0;
bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
bufdesc.dwReserved=0;
bufdesc.lpwfxFormat=&wfx;
trace(" Testing the capture buffer at %ldx%dx%d\n",
wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
trace(" Testing the capture buffer at %s\n", format_string(&wfx));
rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
ok((rc==DS_OK)&&(dscbo!=NULL),"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
if (rc==DS_OK) {
@ -359,17 +375,35 @@ static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
}
}
/* Try an invalid format to test error handling */
/* try a non PCM format */
#if 0
init_format(&wfx,2000000,16,2);
init_format(&wfx,WAVE_FORMAT_MULAW,8000,8,1);
ZeroMemory(&bufdesc, sizeof(bufdesc));
bufdesc.dwSize=sizeof(bufdesc);
bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
bufdesc.dwReserved=0;
bufdesc.lpwfxFormat=&wfx;
trace(" Testing the capture buffer at %ldx%dx%d\n",
wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
trace(" Testing the capture buffer at %s\n", format_string(&wfx));
rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
ok((rc==DS_OK)&&(dscbo!=NULL),"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
if ((rc==DS_OK)&&(dscbo!=NULL)) {
test_capture_buffer(dsco, dscbo, winetest_interactive);
ref=IDirectSoundCaptureBuffer_Release(dscbo);
ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
}
#endif
/* Try an invalid format to test error handling */
#if 0
init_format(&wfx,WAVE_FORMAT_PCM,2000000,16,2);
ZeroMemory(&bufdesc, sizeof(bufdesc));
bufdesc.dwSize=sizeof(bufdesc);
bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
bufdesc.dwReserved=0;
bufdesc.lpwfxFormat=&wfx;
trace(" Testing the capture buffer at %s\n", format_string(&wfx));
rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
ok(rc!=DS_OK,"CreateCaptureBuffer should have failed at 2 MHz 0x%lx\n",rc);
#endif