dsound: Transparantly fall back to software mode if hardware mode is unavailable.
This commit is contained in:
parent
a247ca5308
commit
2ececbeda9
|
@ -57,10 +57,6 @@ static void DSOUND_RecalcPrimary(DirectSoundDevice *device)
|
||||||
if (device->pwfx->nSamplesPerSec >= 80000)
|
if (device->pwfx->nSamplesPerSec >= 80000)
|
||||||
fraglen *= 2;
|
fraglen *= 2;
|
||||||
|
|
||||||
/* If in emulation mode, reduce fragment size until an integer number of them fits in the buffer */
|
|
||||||
if (!device->driver)
|
|
||||||
while (device->buflen % fraglen)
|
|
||||||
fraglen -= nBlockAlign;
|
|
||||||
device->fraglen = fraglen;
|
device->fraglen = fraglen;
|
||||||
device->helfrags = device->buflen / fraglen;
|
device->helfrags = device->buflen / fraglen;
|
||||||
TRACE("fraglen=%d helfrags=%d\n", device->fraglen, device->helfrags);
|
TRACE("fraglen=%d helfrags=%d\n", device->fraglen, device->helfrags);
|
||||||
|
@ -77,20 +73,51 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
||||||
HRESULT err = DS_OK;
|
HRESULT err = DS_OK;
|
||||||
TRACE("(%p)\n", device);
|
TRACE("(%p)\n", device);
|
||||||
|
|
||||||
|
if (device->driver)
|
||||||
|
{
|
||||||
|
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
|
||||||
|
DSBCAPS_PRIMARYBUFFER,0,
|
||||||
|
&(device->buflen),&(device->buffer),
|
||||||
|
(LPVOID*)&(device->hwbuf));
|
||||||
|
|
||||||
|
if (err != DS_OK) {
|
||||||
|
WARN("IDsDriver_CreateSoundBuffer failed, falling back to waveout\n");
|
||||||
|
/* Wine-only: close wine directsound driver, then reopen without WAVE_DIRECTSOUND */
|
||||||
|
device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
|
||||||
|
IDsDriver_Close(device->driver);
|
||||||
|
waveOutClose(device->hwo);
|
||||||
|
IDsDriver_Release(device->driver);
|
||||||
|
device->driver = NULL;
|
||||||
|
device->buffer = NULL;
|
||||||
|
device->hwo = 0;
|
||||||
|
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device, CALLBACK_FUNCTION));
|
||||||
|
if (err != DS_OK)
|
||||||
|
{
|
||||||
|
WARN("Falling back to waveout failed too! Giving up\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
||||||
|
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
||||||
|
|
||||||
/* are we using waveOut stuff? */
|
/* are we using waveOut stuff? */
|
||||||
if (!device->driver) {
|
if (!device->driver) {
|
||||||
LPBYTE newbuf;
|
LPBYTE newbuf;
|
||||||
LPWAVEHDR headers = NULL;
|
LPWAVEHDR headers = NULL;
|
||||||
DWORD buflen;
|
DWORD buflen, overshot, oldbuflen;
|
||||||
HRESULT merr = DS_OK;
|
unsigned int c;
|
||||||
|
|
||||||
/* Start in pause mode, to allow buffers to get filled */
|
/* Start in pause mode, to allow buffers to get filled */
|
||||||
waveOutPause(device->hwo);
|
waveOutPause(device->hwo);
|
||||||
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
|
||||||
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
|
||||||
|
|
||||||
/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
|
/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
|
||||||
on windows this size is always fixed (tested on win-xp) */
|
on windows this size is always fixed (tested on win-xp) */
|
||||||
buflen = ds_hel_buflen;
|
if (!device->buflen)
|
||||||
|
buflen = ds_hel_buflen;
|
||||||
|
else /* In case we move from hw accelerated to waveout */
|
||||||
|
buflen = device->buflen;
|
||||||
buflen -= ds_hel_buflen % device->pwfx->nBlockAlign;
|
buflen -= ds_hel_buflen % device->pwfx->nBlockAlign;
|
||||||
|
|
||||||
TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
|
TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
|
||||||
|
@ -101,18 +128,14 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
||||||
else
|
else
|
||||||
newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
|
newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
|
||||||
|
|
||||||
|
if (!newbuf) {
|
||||||
if (newbuf == NULL) {
|
|
||||||
ERR("failed to allocate primary buffer\n");
|
ERR("failed to allocate primary buffer\n");
|
||||||
merr = DSERR_OUTOFMEMORY;
|
return DSERR_OUTOFMEMORY;
|
||||||
/* but the old buffer might still exist and must be re-prepared */
|
/* but the old buffer might still exist and must be re-prepared */
|
||||||
} else {
|
|
||||||
device->playpos = 0;
|
|
||||||
device->mixpos = 0;
|
|
||||||
device->buffer = newbuf;
|
|
||||||
device->buflen = buflen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oldbuflen = device->buflen;
|
||||||
|
device->buflen = buflen;
|
||||||
DSOUND_RecalcPrimary(device);
|
DSOUND_RecalcPrimary(device);
|
||||||
if (device->pwave)
|
if (device->pwave)
|
||||||
headers = HeapReAlloc(GetProcessHeap(),0,device->pwave, device->helfrags * sizeof(WAVEHDR));
|
headers = HeapReAlloc(GetProcessHeap(),0,device->pwave, device->helfrags * sizeof(WAVEHDR));
|
||||||
|
@ -121,60 +144,42 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
ERR("failed to allocate wave headers\n");
|
ERR("failed to allocate wave headers\n");
|
||||||
merr = DSERR_OUTOFMEMORY;
|
HeapFree(GetProcessHeap(), 0, newbuf);
|
||||||
|
device->buflen = oldbuflen;
|
||||||
|
DSOUND_RecalcPrimary(device);
|
||||||
|
return DSERR_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
else if (device->buffer) {
|
|
||||||
unsigned c;
|
|
||||||
|
|
||||||
device->pwave = headers;
|
device->buffer = newbuf;
|
||||||
|
device->pwave = headers;
|
||||||
|
|
||||||
/* sanity */
|
/* prepare fragment headers */
|
||||||
if(device->buflen % device->helfrags){
|
for (c=0; c<device->helfrags; c++) {
|
||||||
ERR("Bad helfrags resolution\n");
|
device->pwave[c].lpData = (char*)device->buffer + c*device->fraglen;
|
||||||
|
device->pwave[c].dwBufferLength = device->fraglen;
|
||||||
|
device->pwave[c].dwUser = (DWORD)device;
|
||||||
|
device->pwave[c].dwFlags = 0;
|
||||||
|
device->pwave[c].dwLoops = 0;
|
||||||
|
err = mmErr(waveOutPrepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR)));
|
||||||
|
if (err != DS_OK) {
|
||||||
|
while (c--)
|
||||||
|
waveOutUnprepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare fragment headers */
|
|
||||||
for (c=0; c<device->helfrags; c++) {
|
|
||||||
device->pwave[c].lpData = (char*)device->buffer + c*device->fraglen;
|
|
||||||
device->pwave[c].dwBufferLength = device->fraglen;
|
|
||||||
device->pwave[c].dwUser = (DWORD)device;
|
|
||||||
device->pwave[c].dwFlags = 0;
|
|
||||||
device->pwave[c].dwLoops = 0;
|
|
||||||
err = mmErr(waveOutPrepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR)));
|
|
||||||
if (err != DS_OK) {
|
|
||||||
while (c--)
|
|
||||||
waveOutUnprepareHeader(device->hwo,&device->pwave[c],sizeof(WAVEHDR));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
device->pwplay = 0;
|
|
||||||
device->pwqueue = 0;
|
|
||||||
device->playpos = 0;
|
|
||||||
device->mixpos = 0;
|
|
||||||
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
|
||||||
TRACE("fraglen=%d\n", device->fraglen);
|
|
||||||
}
|
|
||||||
if ((err == DS_OK) && (merr != DS_OK))
|
|
||||||
err = merr;
|
|
||||||
} else if (!device->hwbuf) {
|
|
||||||
device->playpos = 0;
|
|
||||||
device->mixpos = 0;
|
|
||||||
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
|
|
||||||
DSBCAPS_PRIMARYBUFFER,0,
|
|
||||||
&(device->buflen),&(device->buffer),
|
|
||||||
(LPVOID*)&(device->hwbuf));
|
|
||||||
if (err != DS_OK) {
|
|
||||||
WARN("IDsDriver_CreateSoundBuffer failed\n");
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
overshot = device->buflen % device->helfrags;
|
||||||
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
/* sanity */
|
||||||
device->playpos = 0;
|
if(overshot)
|
||||||
device->mixpos = 0;
|
{
|
||||||
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
WARN("helfrags (%d x %d) doesn't fit entirely in buflen (%d) overshot: %d\n", device->helfrags, device->fraglen, device->buflen, overshot);
|
||||||
|
device->pwave[device->helfrags - 1].dwBufferLength += overshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("fraglen=%d\n", device->fraglen);
|
||||||
}
|
}
|
||||||
|
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
||||||
|
device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
|
||||||
DSOUND_RecalcPrimary(device);
|
DSOUND_RecalcPrimary(device);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -212,35 +217,7 @@ HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
|
||||||
HRESULT err = DS_OK;
|
HRESULT err = DS_OK;
|
||||||
TRACE("(%p)\n", device);
|
TRACE("(%p)\n", device);
|
||||||
|
|
||||||
device->playpos = 0;
|
device->buflen = ds_hel_buflen;
|
||||||
device->mixpos = 0;
|
|
||||||
device->buflen = device->pwfx->nAvgBytesPerSec;
|
|
||||||
|
|
||||||
/* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
|
|
||||||
|
|
||||||
if (device->driver) {
|
|
||||||
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
|
|
||||||
DSBCAPS_PRIMARYBUFFER,0,
|
|
||||||
&(device->buflen),&(device->buffer),
|
|
||||||
(LPVOID*)&(device->hwbuf));
|
|
||||||
if (err != DS_OK) {
|
|
||||||
WARN("IDsDriver_CreateSoundBuffer failed, falling back to waveout\n");
|
|
||||||
/* Wine-only: close wine directsound driver, then reopen without WAVE_DIRECTSOUND */
|
|
||||||
device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
|
|
||||||
waveOutClose(device->hwo);
|
|
||||||
IDsDriver_Release(device->driver);
|
|
||||||
device->driver = NULL;
|
|
||||||
device->buffer = NULL;
|
|
||||||
device->hwo = 0;
|
|
||||||
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device, CALLBACK_FUNCTION));
|
|
||||||
if (err != DS_OK)
|
|
||||||
{
|
|
||||||
WARN("Falling back to waveout failed too! Giving up\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = DSOUND_PrimaryOpen(device);
|
err = DSOUND_PrimaryOpen(device);
|
||||||
|
|
||||||
if (err != DS_OK) {
|
if (err != DS_OK) {
|
||||||
|
@ -302,34 +279,10 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
|
||||||
if (device->hwbuf) {
|
if (device->hwbuf) {
|
||||||
err = IDsDriverBuffer_Stop(device->hwbuf);
|
err = IDsDriverBuffer_Stop(device->hwbuf);
|
||||||
if (err == DSERR_BUFFERLOST) {
|
if (err == DSERR_BUFFERLOST) {
|
||||||
DWORD flags = CALLBACK_FUNCTION | WAVE_DIRECTSOUND;
|
DSOUND_PrimaryClose(device);
|
||||||
/* Wine-only: the driver wants us to reopen the device */
|
err = DSOUND_PrimaryOpen(device);
|
||||||
/* FIXME: check for errors */
|
if (FAILED(err))
|
||||||
IDsDriverBuffer_Release(device->hwbuf);
|
WARN("DSOUND_PrimaryOpen failed\n");
|
||||||
waveOutClose(device->hwo);
|
|
||||||
device->hwo = 0;
|
|
||||||
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode,
|
|
||||||
device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device,
|
|
||||||
flags));
|
|
||||||
if (err == DS_OK) {
|
|
||||||
device->playpos = 0;
|
|
||||||
device->mixpos = 0;
|
|
||||||
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
|
|
||||||
DSBCAPS_PRIMARYBUFFER,0,
|
|
||||||
&(device->buflen),&(device->buffer),
|
|
||||||
(LPVOID)&(device->hwbuf));
|
|
||||||
if (err != DS_OK)
|
|
||||||
WARN("IDsDriver_CreateSoundBuffer failed\n");
|
|
||||||
else if (device->state == STATE_STOPPING)
|
|
||||||
device->state = STATE_STOPPED;
|
|
||||||
else if (device->state == STATE_PLAYING)
|
|
||||||
device->state = STATE_STARTING;
|
|
||||||
if (err == DS_OK)
|
|
||||||
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
WARN("waveOutOpen failed\n");
|
|
||||||
}
|
|
||||||
} else if (err != DS_OK) {
|
} else if (err != DS_OK) {
|
||||||
WARN("IDsDriverBuffer_Stop failed\n");
|
WARN("IDsDriverBuffer_Stop failed\n");
|
||||||
}
|
}
|
||||||
|
@ -423,50 +376,36 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex)
|
||||||
|
|
||||||
CopyMemory(device->pwfx, wfex, cp_size);
|
CopyMemory(device->pwfx, wfex, cp_size);
|
||||||
|
|
||||||
if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
|
if (!(device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) && device->hwbuf) {
|
||||||
DWORD flags = CALLBACK_FUNCTION;
|
|
||||||
if (device->driver)
|
|
||||||
flags |= WAVE_DIRECTSOUND;
|
|
||||||
/* FIXME: check for errors */
|
|
||||||
DSOUND_PrimaryClose(device);
|
|
||||||
waveOutClose(device->hwo);
|
|
||||||
device->hwo = 0;
|
|
||||||
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode,
|
|
||||||
device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device,
|
|
||||||
flags));
|
|
||||||
if (err == DS_OK) {
|
|
||||||
err = DSOUND_PrimaryOpen(device);
|
|
||||||
if (err != DS_OK) {
|
|
||||||
WARN("DSOUND_PrimaryOpen failed\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WARN("waveOutOpen failed\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else if (device->hwbuf) {
|
|
||||||
err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx);
|
err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx);
|
||||||
if (err == DSERR_BUFFERLOST) {
|
if (err != DSERR_BUFFERLOST && FAILED(err)) {
|
||||||
/* Wine-only: the driver wants us to recreate the HW buffer */
|
|
||||||
IDsDriverBuffer_Release(device->hwbuf);
|
|
||||||
device->playpos = 0;
|
|
||||||
device->mixpos = 0;
|
|
||||||
err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx,
|
|
||||||
DSBCAPS_PRIMARYBUFFER,0,
|
|
||||||
&(device->buflen),&(device->buffer),
|
|
||||||
(LPVOID)&(device->hwbuf));
|
|
||||||
if (err != DS_OK) {
|
|
||||||
WARN("IDsDriver_CreateSoundBuffer failed\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
|
||||||
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
|
||||||
} else if (FAILED(err)) {
|
|
||||||
WARN("IDsDriverBuffer_SetFormat failed\n");
|
WARN("IDsDriverBuffer_SetFormat failed\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* FIXME: should we set err back to DS_OK in all cases ? */
|
else DSOUND_RecalcPrimary(device);
|
||||||
DSOUND_RecalcPrimary(device);
|
}
|
||||||
|
|
||||||
|
if (err == DSERR_BUFFERLOST || device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT)
|
||||||
|
{
|
||||||
|
DSOUND_PrimaryClose(device);
|
||||||
|
|
||||||
|
if (!device->driver)
|
||||||
|
{
|
||||||
|
waveOutClose(device->hwo);
|
||||||
|
device->hwo = 0;
|
||||||
|
err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device, CALLBACK_FUNCTION));
|
||||||
|
if (FAILED(err))
|
||||||
|
{
|
||||||
|
WARN("waveOutOpen failed\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DSOUND_PrimaryOpen(device);
|
||||||
|
if (err != DS_OK) {
|
||||||
|
WARN("DSOUND_PrimaryOpen failed\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
|
if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
|
||||||
|
|
Loading…
Reference in New Issue