put dsstream's packet functions into its own file

This commit is contained in:
RadWolfie 2020-01-05 19:35:52 -06:00
parent 54421832e5
commit 8fb60f6806
6 changed files with 326 additions and 230 deletions

View File

@ -143,6 +143,7 @@ file (GLOB CXBXR_HEADER_EMU
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundLogging.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundLogging.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundTypes.h"
"${CXBXR_ROOT_DIR}/src/core/hle/Intercept.hpp"
@ -277,6 +278,7 @@ file (GLOB CXBXR_SOURCE_EMU
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundLogging.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundStream.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundLogging.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/Intercept.cpp"

View File

@ -0,0 +1,272 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// ******************************************************************
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2020 RadWolfie
// *
// * All rights reserved
// *
// ******************************************************************
#define LOG_PREFIX CXBXR_MODULE::DSSTREAM
// prevent name collisions
namespace xboxkrnl {
#include <xboxkrnl/xboxkrnl.h>
};
#include <dsound.h>
#include "DirectSoundGlobal.hpp"
#include "Logging.h"
#include "DirectSoundLogging.hpp"
#include "..\XbDSoundLogging.hpp"
#include "DirectSoundInline.hpp"
#include "DSStream_PacketManager.hpp"
static inline void DSStream_Packet_UpdateHostBuffer(
LPDIRECTSOUNDBUFFER8 &pDSBuffer,
DWORD dwOffset,
PVOID pBufferData,
DWORD dwBufferSize
)
{
LPVOID pAudioPtr, pAudioPtr2;
DWORD dwAudioBytes, dwAudioBytes2;
HRESULT hRet = pDSBuffer->Lock(dwOffset, dwBufferSize, &pAudioPtr, &dwAudioBytes,
&pAudioPtr2, &dwAudioBytes2, 0);
if (hRet == DS_OK) {
if (pAudioPtr != nullptr) {
memcpy_s(pAudioPtr, dwAudioBytes, pBufferData, dwAudioBytes);
if (pAudioPtr2 != nullptr) {
memcpy_s(pAudioPtr2, dwAudioBytes2, (PBYTE)pBufferData + dwAudioBytes, dwAudioBytes2);
}
pDSBuffer->Unlock(pAudioPtr, dwAudioBytes, pAudioPtr2, dwAudioBytes2);
}
}
}
void DSStream_Packet_Clear(
vector_hvp_iterator &buffer,
DWORD status,
XTL::LPFNXMOCALLBACK Xb_lpfnCallback,
LPVOID Xb_lpvContext,
XTL::X_CDirectSoundStream* pThis
)
{
free(buffer->pBuffer_data);
// Peform release only, don't trigger any events below.
if (status == XMP_STATUS_RELEASE_CXBXR) {
DSoundSGEMemDealloc(buffer->xmp_data.dwMaxSize);
buffer = pThis->Host_BufferPacketArray.erase(buffer);
return;
}
if (buffer->xmp_data.pdwStatus != xbnullptr) {
(*buffer->xmp_data.pdwStatus) = status;
}
if (buffer->xmp_data.pdwCompletedSize != xbnullptr) {
(*buffer->xmp_data.pdwCompletedSize) = DSoundBufferGetXboxBufferSize(pThis->EmuFlags, buffer->xmp_data.dwMaxSize);
}
DSoundSGEMemDealloc(buffer->xmp_data.dwMaxSize);
auto unionEventContext = buffer->xmp_data.hCompletionEvent;
buffer = pThis->Host_BufferPacketArray.erase(buffer);
// NOTE: Packet must be erase before call the callback function below. See test case below.
// Test case: Pocketbike Racer
// * (cause audio skipping due to callback function called process then another called to process outside callback (x2)
// It only need to call process once.
// If a callback is set, only do the callback instead of event handle.
if (Xb_lpfnCallback != xbnullptr) {
Xb_lpfnCallback(Xb_lpvContext, unionEventContext, status);
} else if (unionEventContext != 0) {
BOOL checkHandle = SetEvent(unionEventContext);
if (checkHandle == 0) {
DWORD error = GetLastError();
EmuLog(LOG_LEVEL::WARNING, "Unable to set event on packet's hCompletionEvent. %8X | error = %8X", unionEventContext, error);
}
}
}
static inline void DSStream_Packet_UploadPartial(
XTL::X_CDirectSoundStream* pThis,
vector_hvp_iterator &bufferCurrent
)
{
// Don't write beyond given buffer data, force do nothing.
if (bufferCurrent->bufPlayed >= bufferCurrent->xmp_data.dwMaxSize) {
EmuLog(LOG_LEVEL::DEBUG, "Attempted packet buffer overflow | pThis = %08X | bufferCurrent = %08X | bufferSize - %08X | dwBufferBytes = %08X",
pThis, bufferCurrent, bufferCurrent->xmp_data.dwMaxSize, pThis->EmuBufferDesc.dwBufferBytes);
return;
}
uint32_t avgBytesPerSec = bufferCurrent->avgBytesPerSec;
uint32_t bufferOffset = avgBytesPerSec * bufferCurrent->bufWrittenIndex;
if ((bufferOffset + avgBytesPerSec) > bufferCurrent->xmp_data.dwMaxSize) {
avgBytesPerSec = bufferCurrent->xmp_data.dwMaxSize - bufferOffset;
}
DSStream_Packet_UpdateHostBuffer(pThis->EmuDirectSoundBuffer8, bufferCurrent->nextWriteOffset, (uint8_t*)bufferCurrent->pBuffer_data + bufferOffset, avgBytesPerSec);
bufferCurrent->nextWriteOffset += avgBytesPerSec;
if (pThis->EmuBufferDesc.dwBufferBytes < bufferCurrent->nextWriteOffset) {
bufferCurrent->nextWriteOffset -= pThis->EmuBufferDesc.dwBufferBytes;
}
#if 0
// Debug area begin
EmuLog(LOG_LEVEL::DEBUG, "upload packet buffer process | pThis = %08X | bufferCurrent = %08X",
pThis, bufferCurrent._Ptr);
EmuLog(LOG_LEVEL::DEBUG, "nextWriteOffset = %08X | bufPlayed = %08X | bufWrittenIndex = %08X",
bufferCurrent->nextWriteOffset, bufferCurrent->bufPlayed, bufferCurrent->bufWrittenIndex);
EmuLog(LOG_LEVEL::DEBUG, "bufferSize - %08X | dwBufferBytes = %08X | dwLastWritePos = %08X | dwWriteOffsetNext = %08X\n",
bufferCurrent->xmp_data.dwMaxSize, pThis->EmuBufferDesc.dwBufferBytes, pThis->Host_dwLastWritePos, pThis->Host_dwWriteOffsetNext);
// Debug area end
#endif
if (pThis->Host_isProcessing == false) {
pThis->EmuDirectSoundBuffer8->Play(0, 0, pThis->EmuPlayFlags);
pThis->Host_isProcessing = true;
}
bufferCurrent->bufWrittenIndex++;
}
static inline void DSStream_Packet_Starved(
XTL::X_CDirectSoundStream* pThis
)
{
pThis->Host_isProcessing = false;
pThis->EmuDirectSoundBuffer8->Stop();
}
bool DSStream_Packet_Process(
XTL::X_CDirectSoundStream* pThis
)
{
// If title want to pause, then don't process the packets.
if ((pThis->EmuFlags & DSE_FLAG_PAUSE) > 0) {
return 0;
}
// If media object is being used as playback synch, then don't process the packets.
if ((pThis->EmuFlags & DSE_FLAG_SYNCHPLAYBACK_CONTROL) > 0) {
return 0;
}
// Do not allow to process if there is no packets.
if (pThis->Host_BufferPacketArray.size() == 0) {
return 0;
}
DWORD dwAudioBytes;
HRESULT hRet = pThis->EmuDirectSoundBuffer8->GetStatus(&dwAudioBytes);
if (hRet == DS_OK) {
vector_hvp_iterator bufferCurrent = pThis->Host_BufferPacketArray.begin();
vector_hvp_iterator bufferPrev = bufferCurrent;
if (bufferCurrent->bufWrittenIndex == 0) {
DSStream_Packet_UploadPartial(pThis, bufferCurrent);
} else {
// NOTE: p1. Do not use play cursor, use write cursor to check ahead since by the time it gets there. The buffer is already played.
// p2. Plus play cursor is not reliable to check, write cursor is reliable as it is update more often.
// Test case proof: Gauntlet Dark Legacy give 256 bytes of data to a per packet during intro FMV.
DWORD writePos = 0;
hRet = pThis->EmuDirectSoundBuffer8->GetCurrentPosition(nullptr, &writePos);
if (hRet == DS_OK) {
int bufPlayed = writePos - bufferCurrent->lastWritePos;
// Correct it if buffer was playing and is at beginning.
if (writePos < bufferCurrent->lastWritePos) {
bufPlayed = writePos + (pThis->EmuBufferDesc.dwBufferBytes - bufferCurrent->lastWritePos);
}
bufferCurrent->lastWritePos = writePos;
bufferCurrent->bufPlayed += bufPlayed;
if (bufferCurrent->isPlayed == false) {
bufferCurrent->isPlayed = true;
}
#if 0 // Extend debug verification
if (pThis->Host_BufferPacketArray.size() == 1) {
EmuLog(LOG_LEVEL::DEBUG, "pThis: %08X; bufPlayed: %08X; bufdesc-bufferBytes: %08X; xmp-maxSize: %08X",
pThis,
bufPlayed,
pThis->EmuBufferDesc.dwBufferBytes,
bufferCurrent->xmp_data.dwMaxSize
);
}
#endif
if (bufferCurrent->bufPlayed >= bufferCurrent->xmp_data.dwMaxSize) {
bufPlayed = bufferCurrent->bufPlayed - bufferCurrent->xmp_data.dwMaxSize;
bufferCurrent->bufPlayed = bufferCurrent->xmp_data.dwMaxSize;
}
if (bufferCurrent->xmp_data.pdwCompletedSize != xbnullptr) {
(*bufferCurrent->xmp_data.pdwCompletedSize) = DSoundBufferGetXboxBufferSize(pThis->EmuFlags, bufferCurrent->bufPlayed);
}
if (bufferCurrent->bufPlayed == bufferCurrent->xmp_data.dwMaxSize) {
DSStream_Packet_Clear(bufferCurrent, XMP_STATUS_SUCCESS, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis);
if (pThis->Host_BufferPacketArray.size() == 0) {
DSStream_Packet_Starved(pThis);
return 0;
}
#if 0 // Extend debug verification
EmuLog(LOG_LEVEL::DEBUG, "nextBuffer: %08X; bufferCurrent->bufPlayed: %08X; bufPlayed: %08X;\n",
bufferCurrent._Ptr,
bufferCurrent->bufPlayed,
bufPlayed
);
#endif
#if 0 //TODO: How to send extra play process to next packet?
// Save what had been played in next packet.
//bufferCurrent->bufPlayed += bufPlayed;
#endif
}
if (bufferCurrent == bufferPrev) {
if ((bufferCurrent->bufWrittenIndex * bufferCurrent->avgBytesPerSec) <= bufferCurrent->bufPlayed) {
DSStream_Packet_UploadPartial(pThis, bufferCurrent);
}
}
if (pThis->Host_BufferPacketArray.size() > 1) {
if ((bufferCurrent->xmp_data.dwMaxSize - bufferCurrent->bufPlayed) <= pThis->EmuBufferDesc.lpwfxFormat->nAvgBytesPerSec
&& (bufferCurrent + 1)->bufWrittenIndex == 0) {
bufferCurrent++;
DSStream_Packet_UploadPartial(pThis, bufferCurrent);
}
}
}
// Out of packets, let's stop it.
if (pThis->Host_BufferPacketArray.size() == 0) {
DSStream_Packet_Starved(pThis);
return 0;
}
}
}
return 1;
}

View File

@ -0,0 +1,40 @@
// ******************************************************************
// *
// * This file is part of the Cxbx project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2017-2020 RadWolfie
// *
// * All rights reserved
// *
// ******************************************************************
#pragma once
#include <vector>
#include "DirectSound.hpp"
#define vector_hvp_iterator std::vector<XTL::host_voice_packet>::iterator
extern void DSStream_Packet_Clear(
vector_hvp_iterator &buffer,
DWORD status,
XTL::LPFNXMOCALLBACK Xb_lpfnCallback,
LPVOID Xb_lpvContext,
XTL::X_CDirectSoundStream* pThis);
extern bool DSStream_Packet_Process(XTL::X_CDirectSoundStream* pThis);

View File

@ -40,6 +40,8 @@ namespace xboxkrnl {
#include "DirectSoundLogging.hpp"
#include "..\XbDSoundLogging.hpp"
#include "DSStream_PacketManager.hpp"
#include <mmreg.h>
#include <msacm.h>
#include <process.h>
@ -391,7 +393,7 @@ static void dsound_thread_worker(LPVOID nullPtr)
continue;
}
if (((*ppDSStream)->EmuFlags & DSE_FLAG_FLUSH_ASYNC) > 0 && (*ppDSStream)->Xb_rtFlushEx == 0) {
DSoundStreamProcess((*ppDSStream));
DSStream_Packet_Process((*ppDSStream));
}
}
}
@ -901,7 +903,7 @@ HRESULT WINAPI XTL::EMUPATCH(CDirectSound_SynchPlayback)
}
if (((*ppDSStream)->EmuFlags & DSE_FLAG_SYNCHPLAYBACK_CONTROL) > 0) {
DSoundBufferSynchPlaybackFlagRemove((*ppDSStream)->EmuFlags);
DSoundStreamProcess((*ppDSStream));
DSStream_Packet_Process((*ppDSStream));
}
}

View File

@ -836,74 +836,6 @@ static inline void DSoundBufferReplace(
}
}
static inline void DSoundStreamWriteToBuffer(
LPDIRECTSOUNDBUFFER8 &pDSBuffer,
DWORD dwOffset,
PVOID pBufferData,
DWORD dwBufferSize) {
LPVOID pAudioPtr, pAudioPtr2;
DWORD dwAudioBytes, dwAudioBytes2;
HRESULT hRet = pDSBuffer->Lock(dwOffset, dwBufferSize, &pAudioPtr, &dwAudioBytes,
&pAudioPtr2, &dwAudioBytes2, 0);
if (hRet == DS_OK) {
if (pAudioPtr != nullptr) {
memcpy_s(pAudioPtr, dwAudioBytes, pBufferData, dwAudioBytes);
if (pAudioPtr2 != nullptr) {
memcpy_s(pAudioPtr2, dwAudioBytes2, (PBYTE)pBufferData + dwAudioBytes, dwAudioBytes2);
}
pDSBuffer->Unlock(pAudioPtr, dwAudioBytes, pAudioPtr2, dwAudioBytes2);
}
}
}
#define vector_hvp_iterator std::vector<XTL::host_voice_packet>::iterator
static inline void DSoundStreamClearPacket(
vector_hvp_iterator &buffer,
DWORD status,
XTL::LPFNXMOCALLBACK Xb_lpfnCallback,
LPVOID Xb_lpvContext,
XTL::X_CDirectSoundStream* pThis) {
free(buffer->pBuffer_data);
// Peform release only, don't trigger any events below.
if (status == XMP_STATUS_RELEASE_CXBXR) {
DSoundSGEMemDealloc(buffer->xmp_data.dwMaxSize);
buffer = pThis->Host_BufferPacketArray.erase(buffer);
return;
}
if (buffer->xmp_data.pdwStatus != xbnullptr) {
(*buffer->xmp_data.pdwStatus) = status;
}
if (buffer->xmp_data.pdwCompletedSize != xbnullptr) {
(*buffer->xmp_data.pdwCompletedSize) = DSoundBufferGetXboxBufferSize(pThis->EmuFlags, buffer->xmp_data.dwMaxSize);
}
DSoundSGEMemDealloc(buffer->xmp_data.dwMaxSize);
auto unionEventContext = buffer->xmp_data.hCompletionEvent;
buffer = pThis->Host_BufferPacketArray.erase(buffer);
// NOTE: Packet must be erase before call the callback function below. See test case below.
// Test case: Pocketbike Racer
// * (cause audio skipping due to callback function called process then another called to process outside callback (x2)
// It only need to call process once.
// If a callback is set, only do the callback instead of event handle.
if (Xb_lpfnCallback != xbnullptr) {
Xb_lpfnCallback(Xb_lpvContext, unionEventContext, status);
} else if (unionEventContext != 0) {
BOOL checkHandle = SetEvent(unionEventContext);
if (checkHandle == 0) {
DWORD error = GetLastError();
EmuLog(LOG_LEVEL::WARNING, "Unable to set event on packet's hCompletionEvent. %8X | error = %8X", unionEventContext, error);
}
}
}
// Generic force remove synch playback control flag.
static inline void DSoundBufferSynchPlaybackFlagRemove(
DWORD &dwEmuFlags
@ -936,159 +868,6 @@ static inline HRESULT DSoundBufferSynchPlaybackFlagAdd(
return DS_OK;
}
static inline void DSoundStreamPacketUploadPartial(
XTL::X_CDirectSoundStream* pThis,
vector_hvp_iterator &bufferCurrent
)
{
// Don't write beyond given buffer data, force do nothing.
if (bufferCurrent->bufPlayed >= bufferCurrent->xmp_data.dwMaxSize) {
EmuLog(LOG_LEVEL::DEBUG, "Attempted packet buffer overflow | pThis = %08X | bufferCurrent = %08X | bufferSize - %08X | dwBufferBytes = %08X",
pThis, bufferCurrent, bufferCurrent->xmp_data.dwMaxSize, pThis->EmuBufferDesc.dwBufferBytes);
return;
}
uint32_t avgBytesPerSec = bufferCurrent->avgBytesPerSec;
uint32_t bufferOffset = avgBytesPerSec * bufferCurrent->bufWrittenIndex;
if ((bufferOffset + avgBytesPerSec) > bufferCurrent->xmp_data.dwMaxSize) {
avgBytesPerSec = bufferCurrent->xmp_data.dwMaxSize - bufferOffset;
}
DSoundStreamWriteToBuffer(pThis->EmuDirectSoundBuffer8, bufferCurrent->nextWriteOffset, (uint8_t*)bufferCurrent->pBuffer_data + bufferOffset, avgBytesPerSec);
bufferCurrent->nextWriteOffset += avgBytesPerSec;
if (pThis->EmuBufferDesc.dwBufferBytes < bufferCurrent->nextWriteOffset) {
bufferCurrent->nextWriteOffset -= pThis->EmuBufferDesc.dwBufferBytes;
}
#if 0
// Debug area begin
EmuLog(LOG_LEVEL::DEBUG, "upload packet buffer process | pThis = %08X | bufferCurrent = %08X",
pThis, bufferCurrent._Ptr);
EmuLog(LOG_LEVEL::DEBUG, "nextWriteOffset = %08X | bufPlayed = %08X | bufWrittenIndex = %08X",
bufferCurrent->nextWriteOffset, bufferCurrent->bufPlayed, bufferCurrent->bufWrittenIndex);
EmuLog(LOG_LEVEL::DEBUG, "bufferSize - %08X | dwBufferBytes = %08X | dwLastWritePos = %08X | dwWriteOffsetNext = %08X\n",
bufferCurrent->xmp_data.dwMaxSize, pThis->EmuBufferDesc.dwBufferBytes, pThis->Host_dwLastWritePos, pThis->Host_dwWriteOffsetNext);
// Debug area end
#endif
if (pThis->Host_isProcessing == false) {
pThis->EmuDirectSoundBuffer8->Play(0, 0, pThis->EmuPlayFlags);
pThis->Host_isProcessing = true;
}
bufferCurrent->bufWrittenIndex++;
}
static inline void DSoundStreamEndPacket(XTL::X_CDirectSoundStream* pThis) {
pThis->Host_isProcessing = false;
pThis->EmuDirectSoundBuffer8->Stop();
}
static inline bool DSoundStreamProcess(XTL::X_CDirectSoundStream* pThis) {
// If title want to pause, then don't process the packets.
if ((pThis->EmuFlags & DSE_FLAG_PAUSE) > 0) {
return 0;
}
// If media object is being used as playback synch, then don't process the packets.
if ((pThis->EmuFlags & DSE_FLAG_SYNCHPLAYBACK_CONTROL) > 0) {
return 0;
}
// Do not allow to process if there is no packets.
if (pThis->Host_BufferPacketArray.size() == 0) {
return 0;
}
DWORD dwAudioBytes;
HRESULT hRet = pThis->EmuDirectSoundBuffer8->GetStatus(&dwAudioBytes);
if (hRet == DS_OK) {
vector_hvp_iterator bufferCurrent = pThis->Host_BufferPacketArray.begin();
vector_hvp_iterator bufferPrev = bufferCurrent;
if (bufferCurrent->bufWrittenIndex == 0) {
DSoundStreamPacketUploadPartial(pThis, bufferCurrent);
} else {
// NOTE: p1. Do not use play cursor, use write cursor to check ahead since by the time it gets there. The buffer is already played.
// p2. Plus play cursor is not reliable to check, write cursor is reliable as it is update more often.
// Test case proof: Gauntlet Dark Legacy give 256 bytes of data to a per packet during intro FMV.
DWORD writePos = 0;
hRet = pThis->EmuDirectSoundBuffer8->GetCurrentPosition(nullptr, &writePos);
if (hRet == DS_OK) {
int bufPlayed = writePos - bufferCurrent->lastWritePos;
// Correct it if buffer was playing and is at beginning.
if (writePos < bufferCurrent->lastWritePos) {
bufPlayed = writePos + (pThis->EmuBufferDesc.dwBufferBytes - bufferCurrent->lastWritePos);
}
bufferCurrent->lastWritePos = writePos;
bufferCurrent->bufPlayed += bufPlayed;
if (bufferCurrent->isPlayed == false) {
bufferCurrent->isPlayed = true;
}
#if 0 // Extend debug verification
if (pThis->Host_BufferPacketArray.size() == 1) {
EmuLog(LOG_LEVEL::DEBUG, "pThis: %08X; bufPlayed: %08X; bufdesc-bufferBytes: %08X; xmp-maxSize: %08X",
pThis,
bufPlayed,
pThis->EmuBufferDesc.dwBufferBytes,
bufferCurrent->xmp_data.dwMaxSize
);
}
#endif
if (bufferCurrent->bufPlayed >= bufferCurrent->xmp_data.dwMaxSize) {
bufPlayed = bufferCurrent->bufPlayed - bufferCurrent->xmp_data.dwMaxSize;
bufferCurrent->bufPlayed = bufferCurrent->xmp_data.dwMaxSize;
}
if (bufferCurrent->xmp_data.pdwCompletedSize != xbnullptr) {
(*bufferCurrent->xmp_data.pdwCompletedSize) = DSoundBufferGetXboxBufferSize(pThis->EmuFlags, bufferCurrent->bufPlayed);
}
if (bufferCurrent->bufPlayed == bufferCurrent->xmp_data.dwMaxSize) {
DSoundStreamClearPacket(bufferCurrent, XMP_STATUS_SUCCESS, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis);
if (pThis->Host_BufferPacketArray.size() == 0) {
DSoundStreamEndPacket(pThis);
return 0;
}
#if 0 // Extend debug verification
EmuLog(LOG_LEVEL::DEBUG, "nextBuffer: %08X; bufferCurrent->bufPlayed: %08X; bufPlayed: %08X;\n",
bufferCurrent._Ptr,
bufferCurrent->bufPlayed,
bufPlayed
);
#endif
#if 0 //TODO: How to send extra play process to next packet?
// Save what had been played in next packet.
//bufferCurrent->bufPlayed += bufPlayed;
#endif
}
if (bufferCurrent == bufferPrev) {
if ((bufferCurrent->bufWrittenIndex * bufferCurrent->avgBytesPerSec) <= bufferCurrent->bufPlayed) {
DSoundStreamPacketUploadPartial(pThis, bufferCurrent);
}
}
if (pThis->Host_BufferPacketArray.size() > 1) {
if ((bufferCurrent->xmp_data.dwMaxSize - bufferCurrent->bufPlayed) <= pThis->EmuBufferDesc.lpwfxFormat->nAvgBytesPerSec
&& (bufferCurrent + 1)->bufWrittenIndex == 0) {
bufferCurrent++;
DSoundStreamPacketUploadPartial(pThis, bufferCurrent);
}
}
}
// Out of packets, let's stop it.
if (pThis->Host_BufferPacketArray.size() == 0) {
DSoundStreamEndPacket(pThis);
return 0;
}
}
}
return 1;
}
//TODO: RadWolfie - Need to implement DirectSoundBuffer create support. Or not able to do so due to all three classes function differently.
//IDirectSound
//IDirectSoundStream

View File

@ -40,6 +40,7 @@ namespace xboxkrnl {
#include "DirectSoundLogging.hpp"
#include "..\XbDSoundLogging.hpp"
#include "DSStream_PacketManager.hpp"
// TODO: Tasks need to do for DirectSound HLE
// * Missing CDirectSoundStream patch
@ -102,15 +103,15 @@ void DirectSoundDoWork_Stream(xboxkrnl::LARGE_INTEGER& time)
if (pThis->Xb_rtPauseEx != 0 && pThis->Xb_rtPauseEx <= time.QuadPart) {
pThis->Xb_rtPauseEx = 0LL;
pThis->EmuFlags ^= DSE_FLAG_PAUSE;
// Don't call play here, let DSoundStreamProcess deal with it.
// Don't call play here, let DSStream_Packet_Process deal with it.
}
if ((pThis->EmuFlags & DSE_FLAG_FLUSH_ASYNC) == 0) {
DSoundStreamProcess(pThis);
DSStream_Packet_Process(pThis);
} else {
// Confirmed flush packet must be done in DirectSoundDoWork only when title is ready.
if (pThis->Xb_rtFlushEx != 0 && pThis->Xb_rtFlushEx <= time.QuadPart) {
pThis->Xb_rtFlushEx = 0LL;
DSoundStreamProcess(pThis);
DSStream_Packet_Process(pThis);
}
}
}
@ -159,7 +160,7 @@ ULONG WINAPI XTL::EMUPATCH(CDirectSoundStream_Release)
}
for (auto buffer = pThis->Host_BufferPacketArray.begin(); buffer != pThis->Host_BufferPacketArray.end();) {
DSoundStreamClearPacket(buffer, XMP_STATUS_RELEASE_CXBXR, nullptr, nullptr, pThis);
DSStream_Packet_Clear(buffer, XMP_STATUS_RELEASE_CXBXR, nullptr, nullptr, pThis);
}
if (pThis->EmuBufferDesc.lpwfxFormat != nullptr) {
@ -347,7 +348,7 @@ HRESULT WINAPI XTL::EMUPATCH(CDirectSoundStream_Discontinuity)
pThis->Xb_rtPauseEx = 0LL;
for (auto buffer = pThis->Host_BufferPacketArray.begin(); buffer != pThis->Host_BufferPacketArray.end();) {
DSoundStreamClearPacket(buffer, XMP_STATUS_FLUSHED, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis);
DSStream_Packet_Clear(buffer, XMP_STATUS_FLUSHED, pThis->Xb_lpfnCallback, pThis->Xb_lpvContext, pThis);
}
return DS_OK;
@ -370,7 +371,7 @@ HRESULT WINAPI XTL::EMUPATCH(CDirectSoundStream_Flush)
pThis->EmuFlags &= ~(DSE_FLAG_FLUSH_ASYNC | DSE_FLAG_ENVELOPE | DSE_FLAG_ENVELOPE2);
pThis->Xb_rtFlushEx = 0LL;
while (DSoundStreamProcess(pThis));
while (DSStream_Packet_Process(pThis));
return DS_OK;
}
@ -909,7 +910,7 @@ HRESULT WINAPI XTL::EMUPATCH(CDirectSoundStream_SetFormat)
for (auto buffer = pThis->Host_BufferPacketArray.begin(); buffer != pThis->Host_BufferPacketArray.end();) {
// TODO: Also need to pass down callback and context as well?
DSoundStreamClearPacket(buffer, XMP_STATUS_FLUSHED, nullptr, nullptr, pThis);
DSStream_Packet_Clear(buffer, XMP_STATUS_FLUSHED, nullptr, nullptr, pThis);
}
HRESULT hRet = HybridDirectSoundBuffer_SetFormat(pThis->EmuDirectSoundBuffer8, pwfxFormat, pThis->EmuBufferDesc,