OpenAL: destroy context when not in use

This prevents the CoreAudio thread from spinning when paused on macOS
This commit is contained in:
Rodger Combs 2017-11-25 23:27:53 -06:00 committed by Thomas Goyne
parent 5a3b7301c6
commit 16d57dac79
1 changed files with 30 additions and 12 deletions

View File

@ -104,6 +104,9 @@ class OpenALPlayer final : public AudioPlayer, wxTimer {
/// wxTimer override to periodically fill available buffers /// wxTimer override to periodically fill available buffers
void Notify() override; void Notify() override;
void InitContext();
void TeardownContext();
public: public:
OpenALPlayer(agi::AudioProvider *provider); OpenALPlayer(agi::AudioProvider *provider);
~OpenALPlayer(); ~OpenALPlayer();
@ -124,11 +127,24 @@ OpenALPlayer::OpenALPlayer(agi::AudioProvider *provider)
, samplerate(provider->GetSampleRate()) , samplerate(provider->GetSampleRate())
, bpf(provider->GetChannels() * provider->GetBytesPerSample()) , bpf(provider->GetChannels() * provider->GetBytesPerSample())
{ {
try { device = alcOpenDevice(nullptr);
// Open device if (!device) throw AudioPlayerOpenError("Failed opening default OpenAL device");
device = alcOpenDevice(nullptr);
if (!device) throw AudioPlayerOpenError("Failed opening default OpenAL device");
// Determine buffer length
decode_buffer.resize(samplerate * bpf / num_buffers / 2); // buffers for half a second of audio
}
OpenALPlayer::~OpenALPlayer()
{
Stop();
alcCloseDevice(device);
}
void OpenALPlayer::InitContext()
{
if (context) return;
try {
// Create context // Create context
context = alcCreateContext(device, nullptr); context = alcCreateContext(device, nullptr);
if (!context) throw AudioPlayerOpenError("Failed creating OpenAL context"); if (!context) throw AudioPlayerOpenError("Failed creating OpenAL context");
@ -151,27 +167,25 @@ OpenALPlayer::OpenALPlayer(agi::AudioProvider *provider)
catch (...) catch (...)
{ {
alcDestroyContext(context); alcDestroyContext(context);
alcCloseDevice(device); context = nullptr;
throw; throw;
} }
// Determine buffer length
decode_buffer.resize(samplerate * bpf / num_buffers / 2); // buffers for half a second of audio
} }
OpenALPlayer::~OpenALPlayer() void OpenALPlayer::TeardownContext()
{ {
Stop(); if (!context) return;
alcMakeContextCurrent(context); alcMakeContextCurrent(context);
alDeleteSources(1, &source); alDeleteSources(1, &source);
alDeleteBuffers(num_buffers, buffers); alDeleteBuffers(num_buffers, buffers);
alcMakeContextCurrent(nullptr);
alcDestroyContext(context); alcDestroyContext(context);
alcCloseDevice(device); context = nullptr;
} }
void OpenALPlayer::Play(int64_t start, int64_t count) void OpenALPlayer::Play(int64_t start, int64_t count)
{ {
InitContext();
alcMakeContextCurrent(context); alcMakeContextCurrent(context);
if (playing) { if (playing) {
// Quick reset // Quick reset
@ -201,6 +215,7 @@ void OpenALPlayer::Play(int64_t start, int64_t count)
void OpenALPlayer::Stop() void OpenALPlayer::Stop()
{ {
TeardownContext();
if (!playing) return; if (!playing) return;
// Reset data // Reset data
@ -214,10 +229,12 @@ void OpenALPlayer::Stop()
alcMakeContextCurrent(context); alcMakeContextCurrent(context);
alSourceStop(source); alSourceStop(source);
alSourcei(source, AL_BUFFER, 0); alSourcei(source, AL_BUFFER, 0);
alcMakeContextCurrent(nullptr);
} }
void OpenALPlayer::FillBuffers(ALsizei count) void OpenALPlayer::FillBuffers(ALsizei count)
{ {
InitContext();
// Do the actual filling/queueing // Do the actual filling/queueing
for (count = mid(1, count, buffers_free); count > 0; --count) { for (count = mid(1, count, buffers_free); count > 0; --count) {
ALsizei fill_len = mid<ALsizei>(0, decode_buffer.size() / bpf, end_frame - cur_frame); ALsizei fill_len = mid<ALsizei>(0, decode_buffer.size() / bpf, end_frame - cur_frame);
@ -240,6 +257,7 @@ void OpenALPlayer::FillBuffers(ALsizei count)
void OpenALPlayer::Notify() void OpenALPlayer::Notify()
{ {
InitContext();
alcMakeContextCurrent(context); alcMakeContextCurrent(context);
ALsizei newplayed; ALsizei newplayed;
alGetSourcei(source, AL_BUFFERS_PROCESSED, &newplayed); alGetSourcei(source, AL_BUFFERS_PROCESSED, &newplayed);