dsound: fix async flush

This commit is contained in:
RadWolfie 2020-11-29 05:04:48 -06:00
parent f872bb5f8a
commit 07c3f3b0fa
3 changed files with 36 additions and 20 deletions

View File

@ -217,6 +217,10 @@ bool DSStream_Packet_Process(
return 0; return 0;
} }
if (pThis->EmuFlags & DSE_FLAG_IS_FLUSHING) {
return 0;
}
if (!(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) { if (!(pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED)) {
pThis->EmuFlags |= DSE_FLAG_IS_ACTIVATED; pThis->EmuFlags |= DSE_FLAG_IS_ACTIVATED;
} }
@ -347,7 +351,9 @@ bool DSStream_Packet_Flush(
xbox::X_CDirectSoundStream* pThis xbox::X_CDirectSoundStream* pThis
) )
{ {
if ((pThis->EmuFlags & DSE_FLAG_IS_FLUSHING) == 0) {
pThis->EmuFlags |= DSE_FLAG_IS_FLUSHING;
}
// If host's audio is still playing then return busy-state until buffer has stop playing. // If host's audio is still playing then return busy-state until buffer has stop playing.
DWORD dwStatus; DWORD dwStatus;
pThis->EmuDirectSoundBuffer8->GetStatus(&dwStatus); pThis->EmuDirectSoundBuffer8->GetStatus(&dwStatus);
@ -373,5 +379,6 @@ bool DSStream_Packet_Flush(
if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) != 0) { if ((pThis->EmuFlags & DSE_FLAG_IS_ACTIVATED) != 0) {
pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED); pThis->EmuFlags &= ~(DSE_FLAG_PAUSE | DSE_FLAG_IS_ACTIVATED);
} }
pThis->EmuFlags &= ~DSE_FLAG_IS_FLUSHING;
return false; return false;
} }

View File

@ -139,6 +139,7 @@ struct SharedDSBuffer : DSBUFFER_S {
#define DSE_FLAG_ENVELOPE2 (1 << 15) // NOTE: This flag is a requirement for GetStatus to return X_DSSSTATUS_ENVELOPECOMPLETE value. #define DSE_FLAG_ENVELOPE2 (1 << 15) // NOTE: This flag is a requirement for GetStatus to return X_DSSSTATUS_ENVELOPECOMPLETE value.
#define DSE_FLAG_RECIEVEDATA (1 << 20) #define DSE_FLAG_RECIEVEDATA (1 << 20)
#define DSE_FLAG_IS_ACTIVATED (1 << 21) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag. #define DSE_FLAG_IS_ACTIVATED (1 << 21) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag.
#define DSE_FLAG_IS_FLUSHING (1 << 22) // Only used for DirectSoundStream class, to acknowledge pause's no activate flag.
#define DSE_FLAG_DEBUG_MUTE (1 << 30) // Cxbx-R debugging usage only #define DSE_FLAG_DEBUG_MUTE (1 << 30) // Cxbx-R debugging usage only
#define DSE_FLAG_BUFFER_EXTERNAL (1 << 31) #define DSE_FLAG_BUFFER_EXTERNAL (1 << 31)
#define DSE_FLAG_AUDIO_CODECS (DSE_FLAG_PCM | DSE_FLAG_XADPCM | DSE_FLAG_PCM_UNKNOWN) #define DSE_FLAG_AUDIO_CODECS (DSE_FLAG_PCM | DSE_FLAG_XADPCM | DSE_FLAG_PCM_UNKNOWN)

View File

@ -380,6 +380,18 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Discontinuity)
return DS_OK; return DS_OK;
} }
xbox::hresult_xt CxbxrImpl_CDirectSoundStream_Flush
(
xbox::X_CDirectSoundStream* pThis)
{
DSoundBufferSynchPlaybackFlagRemove(pThis->EmuFlags);
while (DSStream_Packet_Flush(pThis));
return DS_OK;
}
// ****************************************************************** // ******************************************************************
// * patch: CDirectSoundStream_Flush // * patch: CDirectSoundStream_Flush
// ****************************************************************** // ******************************************************************
@ -391,11 +403,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Flush)
LOG_FUNC_ONE_ARG(pThis); LOG_FUNC_ONE_ARG(pThis);
DSoundBufferSynchPlaybackFlagRemove(pThis->EmuFlags); return CxbxrImpl_CDirectSoundStream_Flush(pThis);
while (DSStream_Packet_Flush(pThis));
return DS_OK;
} }
// ****************************************************************** // ******************************************************************
@ -422,22 +430,20 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_FlushEx)
// Cannot use rtTimeStamp here, it must be flush. // Cannot use rtTimeStamp here, it must be flush.
if (dwFlags == X_DSSFLUSHEX_IMMEDIATE) { if (dwFlags == X_DSSFLUSHEX_IMMEDIATE) {
hRet = xbox::EMUPATCH(CDirectSoundStream_Flush)(pThis); hRet = CxbxrImpl_CDirectSoundStream_Flush(pThis);
} }
// Remaining flags require X_DSSFLUSHEX_ASYNC to be include. // Remaining flags require X_DSSFLUSHEX_ASYNC to be include.
else if ((dwFlags & X_DSSFLUSHEX_ASYNC) > 0) { else if ((dwFlags & X_DSSFLUSHEX_ASYNC) > 0 && !pThis->Host_BufferPacketArray.empty()) {
// If rtTimeStamp is zero'd, then call flush once and allow process flush in worker thread. // If rtTimeStamp is zero'd, then call flush once and allow process flush in worker thread.
if (rtTimeStamp == 0LL) { if (rtTimeStamp == 0LL) {
bool isBusy = DSStream_Packet_Flush(pThis);
if (!isBusy) {
// testcase: Obscure will crash after new game's video if not call DSStream_Packet_Flush in same thread.
// If flush is not busy, then we don't need worker thread to continue flushing.
return hRet;
}
xbox::LARGE_INTEGER getTime; xbox::LARGE_INTEGER getTime;
xbox::KeQuerySystemTime(&getTime); xbox::KeQuerySystemTime(&getTime);
pThis->Xb_rtFlushEx = getTime.QuadPart; pThis->Xb_rtFlushEx = getTime.QuadPart;
pThis->EmuFlags |= DSE_FLAG_IS_FLUSHING;
// HACK: Need to find a way to remove Flush call without break Obscure.
// Otherwise, it will behave like on hardware.
DSStream_Packet_Flush(pThis);
} }
else { else {
pThis->Xb_rtFlushEx = rtTimeStamp; pThis->Xb_rtFlushEx = rtTimeStamp;
@ -549,16 +555,17 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_GetStatus__r2)
// Convert host to xbox status flag. // Convert host to xbox status flag.
if (hRet == DS_OK) { if (hRet == DS_OK) {
if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & (DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE)) == 0) {
dwStatusXbox |= X_DSSSTATUS_PLAYING;
}
if (pThis->Host_BufferPacketArray.size() != pThis->X_MaxAttachedPackets) { if (pThis->Host_BufferPacketArray.size() != pThis->X_MaxAttachedPackets) {
dwStatusXbox |= X_DSSSTATUS_READY; dwStatusXbox |= X_DSSSTATUS_READY;
} }
if (!pThis->Host_BufferPacketArray.empty() && (pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) { if (!pThis->Host_BufferPacketArray.empty()) {
if ((pThis->EmuFlags & DSE_FLAG_PAUSE) != 0) {
dwStatusXbox |= X_DSSSTATUS_PAUSED; dwStatusXbox |= X_DSSSTATUS_PAUSED;
} }
else if ((pThis->EmuFlags & (DSE_FLAG_PAUSE | DSE_FLAG_PAUSENOACTIVATE | DSE_FLAG_IS_FLUSHING)) == 0) {
dwStatusXbox |= X_DSSSTATUS_PLAYING;
}
}
} else { } else {
dwStatusXbox = 0; dwStatusXbox = 0;
hRet = DSERR_GENERIC; hRet = DSERR_GENERIC;
@ -735,6 +742,7 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(CDirectSoundStream_Process)
if ((pThis->Xb_Status & X_DSSSTATUS_STARVED) > 0) { if ((pThis->Xb_Status & X_DSSSTATUS_STARVED) > 0) {
pThis->Xb_Status &= ~X_DSSSTATUS_STARVED; pThis->Xb_Status &= ~X_DSSSTATUS_STARVED;
} }
pThis->EmuFlags &= ~DSE_FLAG_IS_FLUSHING;
DSStream_Packet_Process(pThis); DSStream_Packet_Process(pThis);
// Once full it needs to change status to flushed when cannot hold any more packets. // Once full it needs to change status to flushed when cannot hold any more packets.
} else { } else {