Fix issues with OpenAL audio backend

This commit is contained in:
Wojciech Figat
2022-02-01 17:34:46 +01:00
parent cf6fb07a05
commit 26191935a7
4 changed files with 130 additions and 203 deletions

View File

@@ -96,7 +96,6 @@ bool AudioClip::StreamingTask::Run()
} }
break; break;
default: default:
CRASH;
return true; return true;
} }

View File

@@ -102,7 +102,8 @@ void AudioSource::SetAttenuation(float value)
void AudioSource::Play() void AudioSource::Play()
{ {
if (_state == States::Playing) auto state = _state;
if (state == States::Playing)
return; return;
if (Clip == nullptr) if (Clip == nullptr)
{ {
@@ -120,8 +121,16 @@ void AudioSource::Play()
// Audio clips with disabled streaming are controlled by audio source, otherwise streaming manager will play it // Audio clips with disabled streaming are controlled by audio source, otherwise streaming manager will play it
if (Clip->IsStreamable()) if (Clip->IsStreamable())
{ {
// Request faster streaming update if (state == States::Paused)
Clip->RequestStreamingUpdate(); {
// Resume
PlayInternal();
}
else
{
// Request faster streaming update
Clip->RequestStreamingUpdate();
}
} }
else else
{ {

View File

@@ -18,7 +18,32 @@
#include <OpenAL/al.h> #include <OpenAL/al.h>
#include <OpenAL/alc.h> #include <OpenAL/alc.h>
#define ALC_MULTIPLE_LISTENERS 0
#define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, -vec.Z * 0.01f #define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, -vec.Z * 0.01f
#if BUILD_RELEASE
#define ALC_CHECK_ERROR(method)
#else
#define ALC_CHECK_ERROR(method) { int alError = alGetError(); if (alError != 0) { LOG(Error, "OpenAL method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), alError, __LINE__ - 1); PLATFORM_DEBUG_BREAK; } }
#endif
#if ALC_MULTIPLE_LISTENERS
#define ALC_FOR_EACH_CONTEXT() \
for (int32 i = 0; i < Contexts.Count(); i++)
{ \
if (Contexts.Count() > 1) \
alcMakeContextCurrent(Contexts[i]);
#define ALC_GET_DEFAULT_CONTEXT() \
if (Contexts.Count() > 1) \
alcMakeContextCurrent(Contexts[0]);
#define ALC_GET_LISTENER_CONTEXT(listener) \
if (Contexts.Count() > 1) \
alcMakeContextCurrent(ALC::GetContext(listener)));
#else
#define ALC_FOR_EACH_CONTEXT() { int32 i = 0;
#define ALC_GET_DEFAULT_CONTEXT()
#define ALC_GET_LISTENER_CONTEXT(listener)
#endif
namespace ALC namespace ALC
{ {
@@ -39,20 +64,23 @@ namespace ALC
ALCcontext* GetContext(const class AudioListener* listener) ALCcontext* GetContext(const class AudioListener* listener)
{ {
#if ALC_MULTIPLE_LISTENERS
const auto& listeners = Audio::Listeners; const auto& listeners = Audio::Listeners;
if (listeners.HasItems()) if (listeners.HasItems())
{ {
ASSERT(listeners.Count() == Contexts.Count()); ASSERT(listeners.Count() == Contexts.Count());
const int32 numContexts = Contexts.Count(); const int32 numContexts = Contexts.Count();
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{ {
if (listeners[i] == listener) if (listeners[i] == listener)
return Contexts[i]; return Contexts[i];
} }
} }
ASSERT(Contexts.HasItems()); ASSERT(Contexts.HasItems());
#else
ASSERT(Contexts.Count() == 1)
#endif
return Contexts[0]; return Contexts[0];
} }
@@ -87,30 +115,19 @@ namespace ALC
void Rebuild(AudioSource* source) void Rebuild(AudioSource* source)
{ {
ASSERT(source->SourceIDs.IsEmpty()); ASSERT(source->SourceIDs.IsEmpty());
auto& contexts = GetContexts();
const int32 numContexts = contexts.Count();
const bool is3D = source->Is3D(); const bool is3D = source->Is3D();
const bool loop = source->GetIsLooping() && !source->UseStreaming(); const bool loop = source->GetIsLooping() && !source->UseStreaming();
const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero; const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero;
const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero; const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero;
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
uint32 sourceID = 0; uint32 sourceID = 0;
alGenSources(1, &sourceID); alGenSources(1, &sourceID);
source->SourceIDs.Add(sourceID); source->SourceIDs.Add(sourceID);
} }
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_GAIN, source->GetVolume()); alSourcef(sourceID, AL_GAIN, source->GetVolume());
@@ -143,14 +160,19 @@ namespace ALC
if (Device == nullptr) if (Device == nullptr)
return; return;
#if ALC_MULTIPLE_LISTENERS
const int32 numListeners = Audio::Listeners.Count(); const int32 numListeners = Audio::Listeners.Count();
const int32 numContexts = numListeners > 1 ? numListeners : 1; const int32 numContexts = numListeners > 1 ? numListeners : 1;
Contexts.Resize(numContexts);
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
ALCcontext* context = alcCreateContext(Device, nullptr); ALCcontext* context = alcCreateContext(Device, nullptr);
Contexts.Add(context); Contexts[i] = context;
} }
#else
Contexts.Resize(1);
Contexts[0] = alcCreateContext(Device, nullptr);
#endif
// If only one context is available keep it active as an optimization. // If only one context is available keep it active as an optimization.
// Audio listeners and sources will avoid excessive context switching in such case. // Audio listeners and sources will avoid excessive context switching in such case.
@@ -187,7 +209,7 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
case 8: case 8:
return alGetEnumValue("AL_FORMAT_71CHN8"); return alGetEnumValue("AL_FORMAT_71CHN8");
default: default:
CRASH; CRASH;
return 0; return 0;
} }
} }
@@ -208,7 +230,7 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
case 8: case 8:
return alGetEnumValue("AL_FORMAT_71CHN16"); return alGetEnumValue("AL_FORMAT_71CHN16");
default: default:
CRASH; CRASH;
return 0; return 0;
} }
} }
@@ -229,36 +251,38 @@ ALenum GetOpenALBufferFormat(uint32 numChannels, uint32 bitDepth)
case 8: case 8:
return alGetEnumValue("AL_FORMAT_71CHN32"); return alGetEnumValue("AL_FORMAT_71CHN32");
default: default:
CRASH; CRASH;
return 0; return 0;
} }
} }
default: default:
CRASH; CRASH;
return 0; return 0;
} }
} }
void AudioBackendOAL::Listener_OnAdd(AudioListener* listener) void AudioBackendOAL::Listener_OnAdd(AudioListener* listener)
{ {
#if ALC_MULTIPLE_LISTENERS
ALC::RebuildContexts(false); ALC::RebuildContexts(false);
#else
AudioBackend::Listener::TransformChanged(listener);
const auto& velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
alListenerf(AL_GAIN, Audio::GetVolume());
#endif
} }
void AudioBackendOAL::Listener_OnRemove(AudioListener* listener) void AudioBackendOAL::Listener_OnRemove(AudioListener* listener)
{ {
#if ALC_MULTIPLE_LISTENERS
ALC::RebuildContexts(false); ALC::RebuildContexts(false);
#endif
} }
void AudioBackendOAL::Listener_VelocityChanged(AudioListener* listener) void AudioBackendOAL::Listener_VelocityChanged(AudioListener* listener)
{ {
auto& contexts = ALC::GetContexts(); ALC_GET_LISTENER_CONTEXT(listener)
const int32 numContexts = contexts.Count();
if (numContexts > 1)
{
const auto context = ALC::GetContext(listener);
alcMakeContextCurrent(context);
}
const auto& velocity = listener->GetVelocity(); const auto& velocity = listener->GetVelocity();
alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity)); alListener3f(AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
@@ -266,8 +290,8 @@ void AudioBackendOAL::Listener_VelocityChanged(AudioListener* listener)
void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener) void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener)
{ {
auto& contexts = ALC::GetContexts(); ALC_GET_LISTENER_CONTEXT(listener)
const int32 numContexts = contexts.Count();
const Vector3& position = listener->GetPosition(); const Vector3& position = listener->GetPosition();
const Quaternion& orientation = listener->GetOrientation(); const Quaternion& orientation = listener->GetOrientation();
Vector3 alOrientation[2] = Vector3 alOrientation[2] =
@@ -278,13 +302,6 @@ void AudioBackendOAL::Listener_TransformChanged(AudioListener* listener)
orientation * Vector3::Up orientation * Vector3::Up
}; };
// If only one context is available it is guaranteed it is always active, so we can avoid setting it
if (numContexts > 1)
{
const auto context = ALC::GetContext(listener);
alcMakeContextCurrent(context);
}
alListenerfv(AL_ORIENTATION, (float*)alOrientation); alListenerfv(AL_ORIENTATION, (float*)alOrientation);
alListener3f(AL_POSITION, FLAX_POS_TO_OAL(position)); alListener3f(AL_POSITION, FLAX_POS_TO_OAL(position));
} }
@@ -301,16 +318,10 @@ void AudioBackendOAL::Source_OnRemove(AudioSource* source)
void AudioBackendOAL::Source_VelocityChanged(AudioSource* source) void AudioBackendOAL::Source_VelocityChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts();
const int32 numContexts = contexts.Count();
const bool is3D = source->Is3D(); const bool is3D = source->Is3D();
const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero; const Vector3 velocity = is3D ? source->GetVelocity() : Vector3::Zero;
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity)); alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
@@ -319,16 +330,10 @@ void AudioBackendOAL::Source_VelocityChanged(AudioSource* source)
void AudioBackendOAL::Source_TransformChanged(AudioSource* source) void AudioBackendOAL::Source_TransformChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts();
const int32 numContexts = contexts.Count();
const bool is3D = source->Is3D(); const bool is3D = source->Is3D();
const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero; const Vector3 position = is3D ? source->GetPosition() : Vector3::Zero;
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position)); alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
@@ -337,13 +342,7 @@ void AudioBackendOAL::Source_TransformChanged(AudioSource* source)
void AudioBackendOAL::Source_VolumeChanged(AudioSource* source) void AudioBackendOAL::Source_VolumeChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_GAIN, source->GetVolume()); alSourcef(sourceID, AL_GAIN, source->GetVolume());
@@ -352,13 +351,7 @@ void AudioBackendOAL::Source_VolumeChanged(AudioSource* source)
void AudioBackendOAL::Source_PitchChanged(AudioSource* source) void AudioBackendOAL::Source_PitchChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_PITCH, source->GetPitch()); alSourcef(sourceID, AL_PITCH, source->GetPitch());
@@ -367,13 +360,7 @@ void AudioBackendOAL::Source_PitchChanged(AudioSource* source)
void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source) void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_LOOPING, source->GetIsLooping()); alSourcei(sourceID, AL_LOOPING, source->GetIsLooping());
@@ -382,13 +369,7 @@ void AudioBackendOAL::Source_IsLoopingChanged(AudioSource* source)
void AudioBackendOAL::Source_MinDistanceChanged(AudioSource* source) void AudioBackendOAL::Source_MinDistanceChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance()); alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
@@ -397,13 +378,7 @@ void AudioBackendOAL::Source_MinDistanceChanged(AudioSource* source)
void AudioBackendOAL::Source_AttenuationChanged(AudioSource* source) void AudioBackendOAL::Source_AttenuationChanged(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation()); alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
@@ -412,20 +387,14 @@ void AudioBackendOAL::Source_AttenuationChanged(AudioSource* source)
void AudioBackendOAL::Source_ClipLoaded(AudioSource* source) void AudioBackendOAL::Source_ClipLoaded(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); if (source->SourceIDs.Count() < ALC::Contexts.Count())
const int32 numContexts = contexts.Count();
if (source->SourceIDs.Count() < numContexts)
return; return;
const auto clip = source->Clip.Get(); const auto clip = source->Clip.Get();
const bool is3D = source->Is3D(); const bool is3D = source->Is3D();
const bool isStreamable = clip->IsStreamable(); const bool isStreamable = clip->IsStreamable();
const bool loop = source->GetIsLooping() && !isStreamable; const bool loop = source->GetIsLooping() && !isStreamable;
for (int32 i = 0; i < numContexts; i++) ALC_FOR_EACH_CONTEXT()
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D); alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
@@ -435,92 +404,57 @@ void AudioBackendOAL::Source_ClipLoaded(AudioSource* source)
void AudioBackendOAL::Source_Cleanup(AudioSource* source) void AudioBackendOAL::Source_Cleanup(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_BUFFER, 0); alSourcei(sourceID, AL_BUFFER, 0);
ALC_CHECK_ERROR(alSourcei);
alDeleteSources(1, &sourceID); alDeleteSources(1, &sourceID);
ALC_CHECK_ERROR(alDeleteSources);
} }
} }
void AudioBackendOAL::Source_Play(AudioSource* source) void AudioBackendOAL::Source_Play(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
// Play // Play
alSourcePlay(sourceID); alSourcePlay(sourceID);
ALC_CHECK_ERROR(alSourcePlay);
} }
} }
void AudioBackendOAL::Source_Pause(AudioSource* source) void AudioBackendOAL::Source_Pause(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
// Pause // Pause
alSourcePause(sourceID); alSourcePause(sourceID);
ALC_CHECK_ERROR(alSourcePause);
// Unset streaming buffers
int32 numQueuedBuffers;
alGetSourcei(sourceID, AL_BUFFERS_QUEUED, &numQueuedBuffers);
uint32 buffer;
for (int32 j = 0; j < numQueuedBuffers; j++)
alSourceUnqueueBuffers(sourceID, 1, &buffer);
} }
} }
void AudioBackendOAL::Source_Stop(AudioSource* source) void AudioBackendOAL::Source_Stop(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
// Stop and rewind // Stop and rewind
alSourceStop(sourceID); alSourceRewind(sourceID);
ALC_CHECK_ERROR(alSourceRewind);
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f); alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
// Unset streaming buffers // Unset streaming buffers
int32 numQueuedBuffers; alSourcei(sourceID, AL_BUFFER, 0);
alGetSourcei(sourceID, AL_BUFFERS_QUEUED, &numQueuedBuffers); ALC_CHECK_ERROR(alSourcei);
uint32 buffer;
for (int32 j = 0; j < numQueuedBuffers; j++)
alSourceUnqueueBuffers(sourceID, 1, &buffer);
} }
} }
void AudioBackendOAL::Source_SetCurrentBufferTime(AudioSource* source, float value) void AudioBackendOAL::Source_SetCurrentBufferTime(AudioSource* source, float value)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcef(sourceID, AL_SEC_OFFSET, value); alSourcef(sourceID, AL_SEC_OFFSET, value);
@@ -529,11 +463,7 @@ void AudioBackendOAL::Source_SetCurrentBufferTime(AudioSource* source, float val
float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source) float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source)
{ {
auto& contexts = ALC::GetContexts(); ALC_GET_DEFAULT_CONTEXT()
const int32 numContexts = contexts.Count();
if (numContexts > 1)
alcMakeContextCurrent(contexts[0]);
#if 0 #if 0
float time; float time;
@@ -552,88 +482,69 @@ float AudioBackendOAL::Source_GetCurrentBufferTime(const AudioSource* source)
void AudioBackendOAL::Source_SetNonStreamingBuffer(AudioSource* source) void AudioBackendOAL::Source_SetNonStreamingBuffer(AudioSource* source)
{ {
auto& contexts = ALC::GetContexts();
const int32 numContexts = contexts.Count();
const uint32 bufferId = source->Clip->Buffers[0]; const uint32 bufferId = source->Clip->Buffers[0];
ALC_FOR_EACH_CONTEXT()
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
alSourcei(sourceID, AL_BUFFER, bufferId); alSourcei(sourceID, AL_BUFFER, bufferId);
ALC_CHECK_ERROR(alSourcei);
} }
} }
void AudioBackendOAL::Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) void AudioBackendOAL::Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
{ {
auto& contexts = ALC::GetContexts(); ALC_GET_DEFAULT_CONTEXT()
const int32 numContexts = contexts.Count();
if (numContexts > 1)
alcMakeContextCurrent(contexts[0]);
// Check the first context only // Check the first context only
const uint32 sourceID = source->SourceIDs[0]; const uint32 sourceID = source->SourceIDs[0];
alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &processedBuffersCount); alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &processedBuffersCount);
ALC_CHECK_ERROR(alGetSourcei);
} }
void AudioBackendOAL::Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) void AudioBackendOAL::Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
{ {
auto& contexts = ALC::GetContexts(); ALC_GET_DEFAULT_CONTEXT()
const int32 numContexts = contexts.Count();
if (numContexts > 1)
alcMakeContextCurrent(contexts[0]);
// Check the first context only // Check the first context only
const uint32 sourceID = source->SourceIDs[0]; const uint32 sourceID = source->SourceIDs[0];
alGetSourcei(sourceID, AL_BUFFERS_QUEUED, &queuedBuffersCount); alGetSourcei(sourceID, AL_BUFFERS_QUEUED, &queuedBuffersCount);
ALC_CHECK_ERROR(alGetSourcei);
} }
void AudioBackendOAL::Source_QueueBuffer(AudioSource* source, uint32 bufferId) void AudioBackendOAL::Source_QueueBuffer(AudioSource* source, uint32 bufferId)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
// Queue new buffer // Queue new buffer
alSourceQueueBuffers(sourceID, 1, &bufferId); alSourceQueueBuffers(sourceID, 1, &bufferId);
ALC_CHECK_ERROR(alSourceQueueBuffers);
} }
} }
void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source) void AudioBackendOAL::Source_DequeueProcessedBuffers(AudioSource* source)
{ {
ALuint buffers[AUDIO_MAX_SOURCE_BUFFERS]; ALuint buffers[AUDIO_MAX_SOURCE_BUFFERS];
ALC_FOR_EACH_CONTEXT()
auto& contexts = ALC::GetContexts();
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
const uint32 sourceID = source->SourceIDs[i]; const uint32 sourceID = source->SourceIDs[i];
int32 numProcessedBuffers; int32 numProcessedBuffers;
alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &numProcessedBuffers); alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &numProcessedBuffers);
alSourceUnqueueBuffers(sourceID, numProcessedBuffers, buffers); alSourceUnqueueBuffers(sourceID, numProcessedBuffers, buffers);
ALC_CHECK_ERROR(alSourceUnqueueBuffers);
} }
} }
void AudioBackendOAL::Buffer_Create(uint32& bufferId) void AudioBackendOAL::Buffer_Create(uint32& bufferId)
{ {
alGenBuffers(1, &bufferId); alGenBuffers(1, &bufferId);
ALC_CHECK_ERROR(alGenBuffers);
} }
void AudioBackendOAL::Buffer_Delete(uint32& bufferId) void AudioBackendOAL::Buffer_Delete(uint32& bufferId)
{ {
alDeleteBuffers(1, &bufferId); alDeleteBuffers(1, &bufferId);
ALC_CHECK_ERROR(alDeleteBuffers);
} }
void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
@@ -656,6 +567,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth); const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
alBufferData(bufferId, format, sampleBufferFloat, bufferSize, info.SampleRate); alBufferData(bufferId, format, sampleBufferFloat, bufferSize, info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
Allocator::Free(sampleBufferFloat); Allocator::Free(sampleBufferFloat);
} }
@@ -670,6 +582,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16); const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
alBufferData(bufferId, format, sampleBuffer16, bufferSize, info.SampleRate); alBufferData(bufferId, format, sampleBuffer16, bufferSize, info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
Allocator::Free(sampleBuffer16); Allocator::Free(sampleBuffer16);
} }
@@ -685,6 +598,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16); const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate); alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
Allocator::Free(sampleBuffer); Allocator::Free(sampleBuffer);
} }
@@ -692,9 +606,10 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
{ {
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth); const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate); alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
} }
} }
// Multichannel // Multichannel
else else
{ {
// Note: Assuming AL_EXT_MCFORMATS is supported. If it's not, channels should be reduced to mono or stereo. // Note: Assuming AL_EXT_MCFORMATS is supported. If it's not, channels should be reduced to mono or stereo.
@@ -709,6 +624,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 32); const ALenum format = GetOpenALBufferFormat(info.NumChannels, 32);
alBufferData(bufferId, format, sampleBuffer32, bufferSize, info.SampleRate); alBufferData(bufferId, format, sampleBuffer32, bufferSize, info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
Allocator::Free(sampleBuffer32); Allocator::Free(sampleBuffer32);
} }
@@ -723,6 +639,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16); const ALenum format = GetOpenALBufferFormat(info.NumChannels, 16);
alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate); alBufferData(bufferId, format, sampleBuffer, bufferSize, info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
Allocator::Free(sampleBuffer); Allocator::Free(sampleBuffer);
} }
@@ -730,6 +647,7 @@ void AudioBackendOAL::Buffer_Write(uint32 bufferId, byte* samples, const AudioDa
{ {
const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth); const ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate); alBufferData(bufferId, format, samples, info.NumSamples * (info.BitDepth / 8), info.SampleRate);
ALC_CHECK_ERROR(alBufferData);
} }
} }
} }
@@ -772,13 +690,7 @@ void AudioBackendOAL::Base_SetDopplerFactor(float value)
void AudioBackendOAL::Base_SetVolume(float value) void AudioBackendOAL::Base_SetVolume(float value)
{ {
auto& contexts = ALC::GetContexts(); ALC_FOR_EACH_CONTEXT()
const int32 numContexts = contexts.Count();
for (int32 i = 0; i < numContexts; i++)
{
if (numContexts > 1)
alcMakeContextCurrent(contexts[i]);
alListenerf(AL_GAIN, value); alListenerf(AL_GAIN, value);
} }
} }
@@ -787,6 +699,13 @@ bool AudioBackendOAL::Base_Init()
{ {
auto& devices = Audio::Devices; auto& devices = Audio::Devices;
#if 0
// Use it for ALSOFT errors debugging (build OpenAL-Soft in Debug)
Platform::SetEnvironmentVariable(TEXT("ALSOFT_TRAP_ERROR"), TEXT("1"));
Platform::SetEnvironmentVariable(TEXT("ALSOFT_LOGLEVEL"), TEXT("9"));
Platform::SetEnvironmentVariable(TEXT("ALSOFT_LOGFILE"), TEXT("alc_log.txt"));
#endif
// Initialization (use the preferred device) // Initialization (use the preferred device)
int32 activeDeviceIndex; int32 activeDeviceIndex;
ALC::Device = alcOpenDevice(nullptr); ALC::Device = alcOpenDevice(nullptr);
@@ -871,19 +790,19 @@ bool AudioBackendOAL::Base_Init()
} }
} }
// Log service info
LOG(Info, "OpenAL version 1.19.1");
for (int32 i = 0; i < devices.Count(); i++)
{
LOG(Info, "{0}{1}", i == activeDeviceIndex ? TEXT("[active] ") : TEXT(""), devices[i].Name);
}
// Init // Init
ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32"); ALC::AL_EXT_float32 = ALC::IsExtensionSupported("AL_EXT_float32");
SetDopplerFactor(AudioSettings::Get()->DopplerFactor); SetDopplerFactor(AudioSettings::Get()->DopplerFactor);
ALC::RebuildContexts(true); ALC::RebuildContexts(true);
Audio::SetActiveDeviceIndex(activeDeviceIndex); Audio::SetActiveDeviceIndex(activeDeviceIndex);
// Log service info
LOG(Info, "{0} ({1})", String(alGetString(AL_RENDERER)), String(alGetString(AL_VERSION)));
for (int32 i = 0; i < devices.Count(); i++)
{
LOG(Info, "{0}{1}", i == activeDeviceIndex ? TEXT("[active] ") : TEXT(""), devices[i].Name);
}
return false; return false;
} }

View File

@@ -186,7 +186,7 @@ int32 AudioStreamingHandler::CalculateResidency(StreamableResource* resource, fl
ASSERT(resource); ASSERT(resource);
auto clip = static_cast<AudioClip*>(resource); auto clip = static_cast<AudioClip*>(resource);
const int32 chunksCount = clip->Buffers.Count(); const int32 chunksCount = clip->Buffers.Count();
bool chunksMask[ASSET_FILE_DATA_CHUNKS]; bool chunksMask[ASSET_FILE_DATA_CHUNKS]; // TODO: use single int as bit mask
Platform::MemoryClear(chunksMask, sizeof(chunksMask)); Platform::MemoryClear(chunksMask, sizeof(chunksMask));
// Find audio chunks required for streaming // Find audio chunks required for streaming
@@ -196,14 +196,14 @@ int32 AudioStreamingHandler::CalculateResidency(StreamableResource* resource, fl
// TODO: collect refs to audio clip from sources and use faster iteration (but do it thread-safe) // TODO: collect refs to audio clip from sources and use faster iteration (but do it thread-safe)
const auto src = Audio::Sources[sourceIndex]; const auto src = Audio::Sources[sourceIndex];
if (src->Clip == clip && src->GetState() == AudioSource::States::Playing) if (src->Clip == clip && src->GetState() != AudioSource::States::Stopped)
{ {
// Stream the current and the next chunk if could be used in a while // Stream the current and the next chunk if could be used in a while
const int32 chunk = src->_streamingFirstChunk; const int32 chunk = src->_streamingFirstChunk;
ASSERT(Math::IsInRange(chunk, 0, chunksCount)); ASSERT(Math::IsInRange(chunk, 0, chunksCount));
chunksMask[chunk] = true; chunksMask[chunk] = true;
const float StreamingDstSec = 2.0f; const float StreamingDstSec = 2.0f; // TODO: make it configurable via StreamingSettings
if (chunk + 1 < chunksCount && src->GetTime() + StreamingDstSec >= clip->GetBufferStartTime(src->_streamingFirstChunk)) if (chunk + 1 < chunksCount && src->GetTime() + StreamingDstSec >= clip->GetBufferStartTime(src->_streamingFirstChunk))
{ {
chunksMask[chunk + 1] = true; chunksMask[chunk + 1] = true;