Fix crash when using multiple audio clips streaming with XAudio2 backend

This commit is contained in:
Wojtek Figat
2023-04-22 13:01:05 +02:00
parent 8d0cfcf05d
commit 2090cba743
8 changed files with 43 additions and 30 deletions

View File

@@ -58,8 +58,8 @@ private:
virtual void Source_DequeueProcessedBuffers(AudioSource* source) = 0;
// Buffer
virtual void Buffer_Create(uint32& bufferId) = 0;
virtual void Buffer_Delete(uint32& bufferId) = 0;
virtual uint32 Buffer_Create() = 0;
virtual void Buffer_Delete(uint32 bufferId) = 0;
virtual void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) = 0;
// Base
@@ -224,15 +224,14 @@ public:
{
public:
FORCE_INLINE static void Create(uint32& bufferId)
FORCE_INLINE static uint32 Create()
{
Instance->Buffer_Create(bufferId);
return Instance->Buffer_Create();
}
FORCE_INLINE static void Delete(uint32& bufferId)
FORCE_INLINE static void Delete(uint32 bufferId)
{
if (Instance)
Instance->Buffer_Delete(bufferId);
Instance->Buffer_Delete(bufferId);
}
FORCE_INLINE static void Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)

View File

@@ -19,7 +19,7 @@ REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClip
bool AudioClip::StreamingTask::Run()
{
AssetReference<AudioClip> ref = _asset.Get();
if (ref == nullptr)
if (ref == nullptr || AudioBackend::Instance == nullptr)
return true;
ScopeLock lock(ref->Locker);
const auto& queue = ref->StreamingQueue;
@@ -34,13 +34,13 @@ bool AudioClip::StreamingTask::Run()
uint32& bufferId = clip->Buffers[idx];
if (bufferId == AUDIO_BUFFER_ID_INVALID)
{
AudioBackend::Buffer::Create(bufferId);
bufferId = AudioBackend::Buffer::Create();
}
else
{
// Release unused data
AudioBackend::Buffer::Delete(bufferId);
bufferId = 0;
bufferId = AUDIO_BUFFER_ID_INVALID;
}
}
@@ -370,9 +370,7 @@ Asset::LoadResult AudioClip::load()
return LoadResult::CannotLoadData;
// Create single buffer
uint32 bufferId;
AudioBackend::Buffer::Create(bufferId);
Buffers[0] = bufferId;
Buffers[0] = AudioBackend::Buffer::Create();
// Write data to audio buffer
if (WriteBuffer(0))
@@ -398,14 +396,12 @@ void AudioClip::unload(bool isReloading)
StopStreaming();
StreamingQueue.Clear();
if (hasAnyBuffer)
if (hasAnyBuffer && AudioBackend::Instance)
{
for (AUDIO_BUFFER_ID_TYPE bufferId : Buffers)
{
if (bufferId != AUDIO_BUFFER_ID_INVALID)
{
AudioBackend::Buffer::Delete(bufferId);
}
}
}
Buffers.Clear();

View File

@@ -114,12 +114,12 @@ void AudioBackendNone::Source_DequeueProcessedBuffers(AudioSource* source)
{
}
void AudioBackendNone::Buffer_Create(uint32& bufferId)
uint32 AudioBackendNone::Buffer_Create()
{
bufferId = 1;
return 1;
}
void AudioBackendNone::Buffer_Delete(uint32& bufferId)
void AudioBackendNone::Buffer_Delete(uint32 bufferId)
{
}

View File

@@ -40,8 +40,8 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;

View File

@@ -589,13 +589,15 @@ void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source)
}
}
void AudioBackendOAL::Buffer_Create(uint32& bufferId)
uint32 AudioBackendOAL::Buffer_Create()
{
uint32 bufferId;
alGenBuffers(1, &bufferId);
ALC_CHECK_ERROR(alGenBuffers);
return bufferId;
}
void AudioBackendOAL::Buffer_Delete(uint32& bufferId)
void AudioBackendOAL::Buffer_Delete(uint32 bufferId)
{
alDeleteBuffers(1, &bufferId);
ALC_CHECK_ERROR(alDeleteBuffers);

View File

@@ -40,8 +40,8 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;

View File

@@ -9,6 +9,7 @@
#include "Engine/Audio/Audio.h"
#include "Engine/Audio/AudioSource.h"
#include "Engine/Audio/AudioListener.h"
#include "Engine/Threading/Threading.h"
#if PLATFORM_WINDOWS
// Tweak Win ver
@@ -206,6 +207,7 @@ namespace XAudio2
UINT32 Channels;
bool ForceDirty = true;
Listener Listeners[AUDIO_MAX_LISTENERS];
CriticalSection Locker;
Array<Source> Sources(32); // TODO: use ChunkedArray for better performance
Array<Buffer*> Buffers(64); // TODO: use ChunkedArray for better performance or use buffers pool?
EngineCallback Callback;
@@ -306,7 +308,6 @@ void AudioBackendXAudio2::Listener_OnAdd(AudioListener* listener)
void AudioBackendXAudio2::Listener_OnRemove(AudioListener* listener)
{
// Free listener
XAudio2::Listener* aListener = XAudio2::GetListener(listener);
if (aListener)
{
@@ -346,6 +347,7 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
if (source->Clip == nullptr || !source->Clip->IsLoaded())
return;
auto clip = source->Clip.Get();
ScopeLock lock(XAudio2::Locker);
// Get first free source
XAudio2::Source* aSource = nullptr;
@@ -419,6 +421,7 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
void AudioBackendXAudio2::Source_OnRemove(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
source->Cleanup();
}
@@ -485,8 +488,10 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
// Looping is defined during buffer submission so reset source buffer (this is called only for non-streamable sources that ue single buffer)
XAudio2::Locker.Lock();
const uint32 bufferId = source->Clip->Buffers[0];
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
const bool isPlaying = source->IsActuallyPlayingSth();
if (isPlaying)
@@ -536,6 +541,7 @@ void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source)
void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
auto aSource = XAudio2::GetSource(source);
if (!aSource)
{
@@ -546,6 +552,7 @@ void AudioBackendXAudio2::Source_ClipLoaded(AudioSource* source)
void AudioBackendXAudio2::Source_Cleanup(AudioSource* source)
{
ScopeLock lock(XAudio2::Locker);
auto aSource = XAudio2::GetSource(source);
if (!aSource)
return;
@@ -632,8 +639,10 @@ void AudioBackendXAudio2::Source_SetNonStreamingBuffer(AudioSource* source)
if (!aSource)
return;
XAudio2::Locker.Lock();
const uint32 bufferId = source->Clip->Buffers[0];
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
XAUDIO2_BUFFER buffer = { 0 };
buffer.pContext = aBuffer;
@@ -695,8 +704,11 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source)
}
}
void AudioBackendXAudio2::Buffer_Create(uint32& bufferId)
uint32 AudioBackendXAudio2::Buffer_Create()
{
uint32 bufferId;
ScopeLock lock(XAudio2::Locker);
// Get first free buffer slot
XAudio2::Buffer* aBuffer = nullptr;
for (int32 i = 0; i < XAudio2::Buffers.Count(); i++)
@@ -718,10 +730,12 @@ void AudioBackendXAudio2::Buffer_Create(uint32& bufferId)
}
aBuffer->Data.Resize(0);
return bufferId;
}
void AudioBackendXAudio2::Buffer_Delete(uint32& bufferId)
void AudioBackendXAudio2::Buffer_Delete(uint32 bufferId)
{
ScopeLock lock(XAudio2::Locker);
XAudio2::Buffer*& aBuffer = XAudio2::Buffers[bufferId - 1];
aBuffer->Data.Resize(0);
Delete(aBuffer);
@@ -730,7 +744,9 @@ void AudioBackendXAudio2::Buffer_Delete(uint32& bufferId)
void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
{
XAudio2::Locker.Lock();
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
XAudio2::Locker.Unlock();
const uint32 bytesPerSample = info.BitDepth / 8;
const int32 samplesLength = info.NumSamples * bytesPerSample;

View File

@@ -40,8 +40,8 @@ public:
void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) override;
void Source_QueueBuffer(AudioSource* source, uint32 bufferId) override;
void Source_DequeueProcessedBuffers(AudioSource* source) override;
void Buffer_Create(uint32& bufferId) override;
void Buffer_Delete(uint32& bufferId) override;
uint32 Buffer_Create() override;
void Buffer_Delete(uint32 bufferId) override;
void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) override;
const Char* Base_Name() override;
FeatureFlags Base_Features() override;