Fix crash when using multiple audio clips streaming with XAudio2 backend
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user