Audio: Handle AudioBuffer compatibility

OpenAL buffers are shared between contextes
This commit is contained in:
Jérôme Leclercq 2022-03-17 13:36:09 +01:00
parent 01061380ee
commit 667a4a0c08
10 changed files with 44 additions and 9 deletions

View File

@ -29,6 +29,8 @@ namespace Nz
virtual UInt32 GetSize() const = 0;
virtual UInt32 GetSampleRate() const = 0;
virtual bool IsCompatibleWith(const AudioDevice& device) const = 0;
virtual bool Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) = 0;
AudioBuffer& operator=(const AudioBuffer&) = default;

View File

@ -38,6 +38,7 @@ namespace Nz
virtual Quaternionf GetListenerRotation() const = 0;
virtual Vector3f GetListenerVelocity() const = 0;
virtual float GetSpeedOfSound() const = 0;
virtual const void* GetSubSystemIdentifier() const = 0;
virtual bool IsFormatSupported(AudioFormat format) const = 0;

View File

@ -32,6 +32,8 @@ namespace Nz
UInt32 GetSize() const override;
UInt32 GetSampleRate() const override;
bool IsCompatibleWith(const AudioDevice& device) const override;
bool Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples) override;
OpenALBuffer& operator=(const OpenALBuffer&) = delete;

View File

@ -39,9 +39,10 @@ namespace Nz
float GetGlobalVolume() const override;
Vector3f GetListenerDirection(Vector3f* up = nullptr) const override;
Vector3f GetListenerPosition() const override;
Quaternionf GetListenerRotation(Vector3f* up = nullptr) const override;
Quaternionf GetListenerRotation() const override;
Vector3f GetListenerVelocity() const override;
float GetSpeedOfSound() const override;
const void* GetSubSystemIdentifier() const override;
bool IsFormatSupported(AudioFormat format) const override;

View File

@ -50,7 +50,7 @@ namespace Nz
SoundBuffer(SoundBuffer&&) = delete;
~SoundBuffer() = default;
const std::shared_ptr<AudioBuffer>& GetBuffer(AudioDevice* device);
const std::shared_ptr<AudioBuffer>& GetAudioBuffer(AudioDevice* device);
inline UInt32 GetDuration() const;
inline AudioFormat GetFormat() const;

View File

@ -52,6 +52,12 @@ namespace Nz
return SafeCast<UInt32>(sampleRate);
}
bool OpenALBuffer::IsCompatibleWith(const AudioDevice& device) const
{
// OpenAL buffers are shared among contexts and thus devices
return device.GetSubSystemIdentifier() == &m_library;
}
bool OpenALBuffer::Reset(AudioFormat format, UInt64 sampleCount, UInt32 sampleRate, const void* samples)
{
OpenALDevice& device = GetDevice();

View File

@ -206,6 +206,11 @@ namespace Nz
return m_library.alGetFloat(AL_SPEED_OF_SOUND);
}
const void* OpenALDevice::GetSubSystemIdentifier() const
{
return &m_library;
}
/*!
* \brief Checks whether the format is supported by the engine
* \return true if it is the case

View File

@ -150,7 +150,7 @@ namespace Nz
void OpenALSource::QueueBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
{
NazaraAssert(audioBuffer, "invalid buffer");
NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer");
NazaraAssert(audioBuffer->IsCompatibleWith(*GetAudioDevice()), "incompatible buffer");
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));
@ -185,7 +185,7 @@ namespace Nz
void OpenALSource::SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer)
{
NazaraAssert(audioBuffer->GetAudioDevice() == GetAudioDevice(), "incompatible buffer");
NazaraAssert(audioBuffer->IsCompatibleWith(*GetAudioDevice()), "incompatible buffer");
std::shared_ptr<OpenALBuffer> newBuffer = std::static_pointer_cast<OpenALBuffer>(std::move(audioBuffer));

View File

@ -219,7 +219,7 @@ namespace Nz
Stop();
m_buffer = std::move(buffer);
m_source->SetBuffer(m_buffer->GetBuffer(m_source->GetAudioDevice().get()));
m_source->SetBuffer(m_buffer->GetAudioBuffer(m_source->GetAudioDevice().get()));
}
/*!

View File

@ -58,14 +58,32 @@ namespace Nz
std::memcpy(&m_samples[0], samples, sampleCount * sizeof(Int16));
}
const std::shared_ptr<AudioBuffer>& SoundBuffer::GetBuffer(AudioDevice* device)
const std::shared_ptr<AudioBuffer>& SoundBuffer::GetAudioBuffer(AudioDevice* device)
{
NazaraAssert(device, "invalid device");
auto it = m_audioBufferByDevice.find(device);
if (it == m_audioBufferByDevice.end())
{
auto audioBuffer = device->CreateBuffer();
if (!audioBuffer->Reset(m_format, m_sampleCount, m_sampleRate, m_samples.get()))
throw std::runtime_error("failed to initialize audio buffer");
// Try to find an existing compatible buffer
std::shared_ptr<AudioBuffer> audioBuffer;
for (it = m_audioBufferByDevice.begin(); it != m_audioBufferByDevice.end(); ++it)
{
const auto& entry = it->second;
if (entry.audioBuffer->IsCompatibleWith(*device))
{
audioBuffer = entry.audioBuffer;
break;
}
}
if (!audioBuffer)
{
// Create a new buffer
audioBuffer = device->CreateBuffer();
if (!audioBuffer->Reset(m_format, m_sampleCount, m_sampleRate, m_samples.get()))
throw std::runtime_error("failed to initialize audio buffer");
}
it = m_audioBufferByDevice.emplace(device, AudioDeviceEntry{}).first;