Skip to content

Commit

Permalink
Fix #78. Add Context suspend and resume. Verified CPU utilization is …
Browse files Browse the repository at this point in the history
…minimized upon suspension
  • Loading branch information
meshula committed May 24, 2021
1 parent bde0b91 commit c720c5e
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 5 deletions.
6 changes: 6 additions & 0 deletions include/LabSound/core/AudioContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ class AudioContext
void startOfflineRendering();
std::function<void()> offlineRenderCompleteCallback;

// suspend the progression of time in the audio context, any queued samples will play
void suspend();

// if the context was suspended, resume the progression of time and processing in the audio context
void resume();

// event dispatching will be called automatically, depending on constructor
// argument. If not automatically dispatching, it is the user's responsibility
// to call dispatchEvents often enough to satisfy the user's needs.
Expand Down
2 changes: 2 additions & 0 deletions include/LabSound/core/AudioDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class AudioDeviceRenderCallback
virtual void render(AudioBus * src, AudioBus * dst, int frames, const SamplingInfo & info) = 0;
virtual void start() = 0;
virtual void stop() = 0;
virtual bool isRunning() const = 0;

virtual const SamplingInfo getSamplingInfo() const = 0;
virtual const AudioStreamConfig getOutputConfig() const = 0;
Expand Down Expand Up @@ -114,6 +115,7 @@ class AudioDevice
virtual ~AudioDevice() {}
virtual void start() = 0;
virtual void stop() = 0;
virtual bool isRunning() = 0;
};

} // lab
Expand Down
1 change: 1 addition & 0 deletions include/LabSound/core/AudioHardwareDeviceNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class AudioHardwareDeviceNode : public AudioNode, public AudioDeviceRenderCallba
virtual void render(AudioBus * src, AudioBus * dst, int frames, const SamplingInfo & info) override;
virtual void start() override;
virtual void stop() override;
virtual bool isRunning() const override;
virtual const SamplingInfo getSamplingInfo() const override;
virtual const AudioStreamConfig getOutputConfig() const override;
virtual const AudioStreamConfig getInputConfig() const override;
Expand Down
1 change: 1 addition & 0 deletions include/LabSound/core/NullDeviceNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class NullDeviceNode final : public AudioNode, public AudioDeviceRenderCallback
virtual void render(AudioBus * src, AudioBus * dst, int frames, const SamplingInfo & info) override final;
virtual void start() override final;
virtual void stop() override final;
virtual bool isRunning() const override final;
virtual const SamplingInfo getSamplingInfo() const override final;
virtual const AudioStreamConfig getOutputConfig() const override final;
virtual const AudioStreamConfig getInputConfig() const override final;
Expand Down
18 changes: 16 additions & 2 deletions src/backends/RtAudio/AudioDevice_RtAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ AudioDevice_RtAudio::AudioDevice_RtAudio(AudioDeviceRenderCallback & callback,
// heap corruption, for example, when dac.stopStream() is invoked.
uint32_t bufferFrames = AudioNode::ProcessingSizeInFrames;

samplingInfo.epoch[0] = samplingInfo.epoch[1] = std::chrono::high_resolution_clock::now();

try
{
rtaudio_ctx.openStream(&outputParams, (inputParams.nChannels > 0) ? &inputParams : nullptr, RTAUDIO_FLOAT32,
Expand All @@ -177,7 +179,6 @@ AudioDevice_RtAudio::~AudioDevice_RtAudio()
void AudioDevice_RtAudio::start()
{
ASSERT(authoritativeDeviceSampleRateAtRuntime != 0.f); // something went very wrong
samplingInfo.epoch[0] = samplingInfo.epoch[1] = std::chrono::high_resolution_clock::now();
try
{
rtaudio_ctx.startStream();
Expand All @@ -198,9 +199,22 @@ void AudioDevice_RtAudio::stop()
{
LOG_ERROR(e.getMessage().c_str());
}
samplingInfo = {};
}

bool AudioDevice_RtAudio::isRunning()
{
try
{
return rtaudio_ctx.isStreamRunning();
}
catch (const RtAudioError & e)
{
LOG_ERROR(e.getMessage().c_str());
return false;
}
}


// Pulls on our provider to get rendered audio stream.
void AudioDevice_RtAudio::render(int numberOfFrames, void * outputBuffer, void * inputBuffer)
{
Expand Down
1 change: 1 addition & 0 deletions src/backends/RtAudio/AudioDevice_RtAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class AudioDevice_RtAudio : public AudioDevice
void render(int numberOfFrames, void * outputBuffer, void * inputBuffer);
virtual void start() override final;
virtual void stop() override final;
virtual bool isRunning() override final;
};

int rt_audio_callback(void * outputBuffer, void * inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void * userData);
Expand Down
10 changes: 8 additions & 2 deletions src/backends/miniaudio/AudioDevice_Miniaudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ AudioDevice_Miniaudio::AudioDevice_Miniaudio(AudioDeviceRenderCallback & callbac

authoritativeDeviceSampleRateAtRuntime = outputConfig.desired_samplerate;

samplingInfo.epoch[0] = samplingInfo.epoch[1] = std::chrono::high_resolution_clock::now();

_ring = new cinder::RingBufferT<float>();
_ring->resize(static_cast<int>(authoritativeDeviceSampleRateAtRuntime)); // ad hoc. hold one second
_scratch = reinterpret_cast<float *>(malloc(sizeof(float) * kRenderQuantum * inputConfig.desired_channels));
Expand All @@ -230,7 +232,6 @@ AudioDevice_Miniaudio::~AudioDevice_Miniaudio()
void AudioDevice_Miniaudio::start()
{
ASSERT(authoritativeDeviceSampleRateAtRuntime != 0.f); // something went very wrong
samplingInfo.epoch[0] = samplingInfo.epoch[1] = std::chrono::high_resolution_clock::now();
if (ma_device_start(&_device) != MA_SUCCESS)
{
LOG_ERROR("Unable to start audio device");
Expand All @@ -243,9 +244,14 @@ void AudioDevice_Miniaudio::stop()
{
LOG_ERROR("Unable to stop audio device");
}
samplingInfo = {};
}

bool AudioDevice_MiniAudio::isRunning()
{
return ma_device_is_started(&_device);
}


// Pulls on our provider to get rendered audio stream.
void AudioDevice_Miniaudio::render(int numberOfFrames_, void * outputBuffer, void * inputBuffer)
{
Expand Down
17 changes: 17 additions & 0 deletions src/core/AudioContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,11 @@ void AudioContext::handlePostRenderTasks(ContextRenderLock & r)
void AudioContext::synchronizeConnections(int timeOut_ms)
{
cv.notify_all();

// don't synch if the context is suspended as that will simply max out the timeout
if (!device_callback->isRunning())
return;

while (m_internal->pendingNodeConnections.size_approx() > 0 && timeOut_ms > 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
Expand Down Expand Up @@ -651,4 +656,16 @@ void AudioContext::startOfflineRendering()
device_callback->start();
}

void AudioContext::suspend()
{
device_callback->stop();
}

// if the context was suspended, resume the progression of time and processing in the audio context
void AudioContext::resume()
{
device_callback->start();
}


} // End namespace lab
5 changes: 5 additions & 0 deletions src/core/AudioHardwareDeviceNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ void AudioHardwareDeviceNode::stop()
m_platformAudioDevice->stop();
}

bool AudioHardwareDeviceNode::isRunning() const
{
return m_platformAudioDevice->isRunning();
}

const SamplingInfo AudioHardwareDeviceNode::getSamplingInfo() const
{
return last_info;
Expand Down
6 changes: 5 additions & 1 deletion src/core/NullDeviceNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ void NullDeviceNode::start()
void NullDeviceNode::stop()
{
shouldExit = true;
info = {};
}

bool NullDeviceNode::isRunning() const
{
return m_startedRendering;
}

void NullDeviceNode::render(AudioBus * src, AudioBus * dst, int frames, const SamplingInfo & info)
Expand Down

0 comments on commit c720c5e

Please sign in to comment.