Fix XAudio2 playback when seeking audio start play location
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
#define XAUDIO2_CHECK_ERROR(method) \
|
#define XAUDIO2_CHECK_ERROR(method) \
|
||||||
if (hr != 0) \
|
if (hr != 0) \
|
||||||
{ \
|
{ \
|
||||||
LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), hr, __LINE__ - 1); \
|
LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), (uint32)hr, __LINE__ - 1); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define XAUDIO2_CHECK_ERROR(method)
|
#define XAUDIO2_CHECK_ERROR(method)
|
||||||
@@ -131,7 +131,8 @@ namespace XAudio2
|
|||||||
XAUDIO2_SEND_DESCRIPTOR Destination;
|
XAUDIO2_SEND_DESCRIPTOR Destination;
|
||||||
float Pitch;
|
float Pitch;
|
||||||
float Pan;
|
float Pan;
|
||||||
float StartTime;
|
float StartTimeForQueueBuffer;
|
||||||
|
float LastBufferStartTime;
|
||||||
float DopplerFactor;
|
float DopplerFactor;
|
||||||
uint64 LastBufferStartSamplesPlayed;
|
uint64 LastBufferStartSamplesPlayed;
|
||||||
int32 BuffersProcessed;
|
int32 BuffersProcessed;
|
||||||
@@ -155,7 +156,8 @@ namespace XAudio2
|
|||||||
Destination.pOutputVoice = nullptr;
|
Destination.pOutputVoice = nullptr;
|
||||||
Pitch = 1.0f;
|
Pitch = 1.0f;
|
||||||
Pan = 0.0f;
|
Pan = 0.0f;
|
||||||
StartTime = 0.0f;
|
StartTimeForQueueBuffer = 0.0f;
|
||||||
|
LastBufferStartTime = 0.0f;
|
||||||
IsDirty = false;
|
IsDirty = false;
|
||||||
Is3D = false;
|
Is3D = false;
|
||||||
IsPlaying = false;
|
IsPlaying = false;
|
||||||
@@ -265,11 +267,14 @@ namespace XAudio2
|
|||||||
buffer.pAudioData = aBuffer->Data.Get();
|
buffer.pAudioData = aBuffer->Data.Get();
|
||||||
buffer.AudioBytes = aBuffer->Data.Count();
|
buffer.AudioBytes = aBuffer->Data.Count();
|
||||||
|
|
||||||
if (aSource->StartTime > ZeroTolerance)
|
if (aSource->StartTimeForQueueBuffer > ZeroTolerance)
|
||||||
{
|
{
|
||||||
buffer.PlayBegin = (UINT32)(aSource->StartTime * (aBuffer->Info.SampleRate * aBuffer->Info.NumChannels));
|
// Offset start position when playing buffer with a custom time offset
|
||||||
buffer.PlayLength = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels - buffer.PlayBegin;
|
const uint32 bytesPerSample = aBuffer->Info.BitDepth / 8 * aBuffer->Info.NumChannels;
|
||||||
aSource->StartTime = 0;
|
buffer.PlayBegin = (UINT32)(aSource->StartTimeForQueueBuffer * aBuffer->Info.SampleRate);
|
||||||
|
buffer.PlayLength = (buffer.AudioBytes / bytesPerSample) - buffer.PlayBegin;
|
||||||
|
aSource->LastBufferStartTime = aSource->StartTimeForQueueBuffer;
|
||||||
|
aSource->StartTimeForQueueBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HRESULT hr = aSource->Voice->SubmitSourceBuffer(&buffer);
|
const HRESULT hr = aSource->Voice->SubmitSourceBuffer(&buffer);
|
||||||
@@ -512,6 +517,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
|||||||
hr = aSource->Voice->FlushSourceBuffers();
|
hr = aSource->Voice->FlushSourceBuffers();
|
||||||
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
||||||
aSource->LastBufferStartSamplesPlayed = 0;
|
aSource->LastBufferStartSamplesPlayed = 0;
|
||||||
|
aSource->LastBufferStartTime = 0;
|
||||||
aSource->BuffersProcessed = 0;
|
aSource->BuffersProcessed = 0;
|
||||||
|
|
||||||
XAUDIO2_BUFFER buffer = { 0 };
|
XAUDIO2_BUFFER buffer = { 0 };
|
||||||
@@ -524,7 +530,7 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
|||||||
const UINT32 totalSamples = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels;
|
const UINT32 totalSamples = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels;
|
||||||
buffer.PlayBegin = state.SamplesPlayed % totalSamples;
|
buffer.PlayBegin = state.SamplesPlayed % totalSamples;
|
||||||
buffer.PlayLength = totalSamples - buffer.PlayBegin;
|
buffer.PlayLength = totalSamples - buffer.PlayBegin;
|
||||||
aSource->StartTime = 0;
|
aSource->StartTimeForQueueBuffer = 0;
|
||||||
|
|
||||||
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
||||||
|
|
||||||
@@ -610,7 +616,8 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source)
|
|||||||
auto aSource = XAudio2::GetSource(source);
|
auto aSource = XAudio2::GetSource(source);
|
||||||
if (aSource && aSource->Voice)
|
if (aSource && aSource->Voice)
|
||||||
{
|
{
|
||||||
aSource->StartTime = 0.0f;
|
aSource->StartTimeForQueueBuffer = 0.0f;
|
||||||
|
aSource->LastBufferStartTime = 0.0f;
|
||||||
|
|
||||||
// Pause
|
// Pause
|
||||||
HRESULT hr = aSource->Voice->Stop();
|
HRESULT hr = aSource->Voice->Stop();
|
||||||
@@ -620,6 +627,7 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source)
|
|||||||
// Unset streaming buffers to rewind
|
// Unset streaming buffers to rewind
|
||||||
hr = aSource->Voice->FlushSourceBuffers();
|
hr = aSource->Voice->FlushSourceBuffers();
|
||||||
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
||||||
|
Platform::Sleep(10); // TODO: find a better way to handle case when VoiceCallback::OnBufferEnd is called after source was stopped thus BuffersProcessed != 0, probably via buffers contexts ptrs
|
||||||
aSource->BuffersProcessed = 0;
|
aSource->BuffersProcessed = 0;
|
||||||
aSource->Callback.PeekSamples();
|
aSource->Callback.PeekSamples();
|
||||||
}
|
}
|
||||||
@@ -631,7 +639,7 @@ void AudioBackendXAudio2::Source_SetCurrentBufferTime(AudioSource* source, float
|
|||||||
if (aSource)
|
if (aSource)
|
||||||
{
|
{
|
||||||
// Store start time so next buffer submitted will start from here (assumes audio is stopped)
|
// Store start time so next buffer submitted will start from here (assumes audio is stopped)
|
||||||
aSource->StartTime = value;
|
aSource->StartTimeForQueueBuffer = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,8 +655,9 @@ float AudioBackendXAudio2::Source_GetCurrentBufferTime(const AudioSource* source
|
|||||||
aSource->Voice->GetState(&state);
|
aSource->Voice->GetState(&state);
|
||||||
const uint32 numChannels = clipInfo.NumChannels;
|
const uint32 numChannels = clipInfo.NumChannels;
|
||||||
const uint32 totalSamples = clipInfo.NumSamples / numChannels;
|
const uint32 totalSamples = clipInfo.NumSamples / numChannels;
|
||||||
|
const uint32 sampleRate = clipInfo.SampleRate;// / clipInfo.NumChannels;
|
||||||
state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
|
state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
|
||||||
time = aSource->StartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, clipInfo.SampleRate));
|
time = aSource->LastBufferStartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, sampleRate));
|
||||||
}
|
}
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
@@ -765,8 +774,7 @@ void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const Aud
|
|||||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||||
XAudio2::Locker.Unlock();
|
XAudio2::Locker.Unlock();
|
||||||
|
|
||||||
const uint32 bytesPerSample = info.BitDepth / 8;
|
const uint32 samplesLength = info.NumSamples * info.BitDepth / 8;
|
||||||
const int32 samplesLength = info.NumSamples * bytesPerSample;
|
|
||||||
|
|
||||||
aBuffer->Info = info;
|
aBuffer->Info = info;
|
||||||
aBuffer->Data.Set(samples, samplesLength);
|
aBuffer->Data.Set(samples, samplesLength);
|
||||||
|
|||||||
Reference in New Issue
Block a user