Make member variables in MixerInput private

This commit is contained in:
Attila Uygun 2023-07-15 11:01:32 +02:00
parent 19910be27e
commit e65d37e846
6 changed files with 158 additions and 117 deletions

View File

@ -4,7 +4,6 @@
#include "base/log.h"
#include "base/task_runner.h"
#include "base/thread_pool.h"
#include "engine/audio/audio_bus.h"
#include "engine/audio/mixer_input.h"
@ -33,11 +32,11 @@ AudioMixer::~AudioMixer() {
audio_sink_.reset();
}
void AudioMixer::AddInput(std::shared_ptr<MixerInput> input) {
void AudioMixer::AddInput(std::shared_ptr<MixerInput> mixer_input) {
DCHECK(audio_enabled_);
std::lock_guard<std::mutex> scoped_lock(lock_);
inputs_[0].push_back(input);
inputs_[0].push_back(mixer_input);
}
void AudioMixer::Suspend() {
@ -62,8 +61,8 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
memset(output_buffer, 0, sizeof(float) * num_frames * kChannelCount);
for (auto it = inputs_[1].begin(); it != inputs_[1].end();) {
auto audio_bus = (*it)->audio_bus.get();
unsigned flags = (*it)->flags.load(std::memory_order_relaxed);
auto* audio_bus = (*it)->GetAudioBus().get();
unsigned flags = (*it)->GetFlags();
bool marked_for_removal = false;
if (flags & MixerInput::kStopped) {
@ -75,14 +74,12 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
src[1] = src[0]; // mono.
size_t num_samples = audio_bus->samples_per_channel();
size_t src_index = (*it)->src_index;
size_t step = (*it)->step.load(std::memory_order_relaxed);
size_t accumulator = (*it)->accumulator;
float amplitude = (*it)->amplitude;
float amplitude_inc =
(*it)->amplitude_inc.load(std::memory_order_relaxed);
float max_amplitude =
(*it)->max_amplitude.load(std::memory_order_relaxed);
size_t src_index = (*it)->GetSrcIndex();
size_t step = (*it)->GetStep();
size_t accumulator = (*it)->GetAccumulator();
float amplitude = (*it)->GetAmplitude();
float amplitude_inc = (*it)->GetAmplitudeInc();
float max_amplitude = (*it)->GetMaxAmplitude();
size_t channel_offset = (flags & MixerInput::kSimulateStereo)
? audio_bus->sample_rate() / 10
: 0;
@ -118,37 +115,29 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
accumulator %= 100;
} else {
if (audio_bus->EndOfStream()) {
if (!(flags & MixerInput::kLoop))
marked_for_removal = true;
else
src_index %= num_samples;
marked_for_removal = !(flags & MixerInput::kLoop);
break;
}
if (!(*it)->streaming_in_progress.load(std::memory_order_acquire)) {
if ((*it)->OnMoreData(!!(flags & MixerInput::kLoop))) {
src_index %= num_samples;
(*it)->streaming_in_progress.store(true, std::memory_order_relaxed);
// Swap buffers and start streaming in background.
audio_bus->SwapBuffers();
src[0] = audio_bus->GetChannelData(0);
src[1] = audio_bus->GetChannelData(1);
if (!src[1])
src[1] = src[0]; // mono.
num_samples = audio_bus->samples_per_channel();
ThreadPool::Get().PostTask(
HERE,
std::bind(&AudioMixer::DoStream, this, *it,
flags & MixerInput::kLoop),
true);
} else {
DLOG(0) << "Mixer buffer underrun!";
}
}
}
(*it)->src_index = src_index;
(*it)->accumulator = accumulator;
(*it)->amplitude = amplitude;
// Remember last sample position and volume.
(*it)->SetPosition(src_index, accumulator);
(*it)->SetAmplitude(amplitude);
}
if (marked_for_removal) {
@ -160,9 +149,9 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
}
for (auto it = removed_inputs_.begin(); it != removed_inputs_.end();) {
if (!(*it)->streaming_in_progress.load(std::memory_order_relaxed)) {
if (!(*it)->IsStreamingInProgress()) {
main_thread_task_runner_->PostTask(
HERE, std::bind(&AudioMixer::EndCallback, this, *it));
HERE, std::bind(&MixerInput::OnRemovedFromMixer, *it));
it = removed_inputs_.erase(it);
} else {
++it;
@ -170,25 +159,4 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
}
}
void AudioMixer::DoStream(std::shared_ptr<MixerInput> input, bool loop) {
input->audio_bus->Stream(loop);
input->streaming_in_progress.store(false, std::memory_order_release);
}
void AudioMixer::EndCallback(std::shared_ptr<MixerInput> input) {
input->streaming = false;
if (input->pending_audio_bus) {
input->audio_bus = input->pending_audio_bus;
input->pending_audio_bus.reset();
}
if (input->end_cb)
input->end_cb();
if (input->restart_cb) {
input->restart_cb();
input->restart_cb = nullptr;
}
}
} // namespace eng

View File

@ -14,8 +14,7 @@ class TaskRunner;
namespace eng {
class AudioBus;
struct MixerInput;
class MixerInput;
// Mix and render audio with low overhead. The mixer has zero or more inputs
// which can be added at any time. The mixer will pull from each input source
@ -29,7 +28,7 @@ class AudioMixer : public AudioSink::Delegate {
AudioMixer();
~AudioMixer();
void AddInput(std::shared_ptr<MixerInput> input);
void AddInput(std::shared_ptr<MixerInput> mixer_input);
void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
bool IsAudioEnabled() const { return audio_enabled_; }
@ -57,10 +56,6 @@ class AudioMixer : public AudioSink::Delegate {
int GetChannelCount() final { return kChannelCount; }
void RenderAudio(float* output_buffer, size_t num_frames) final;
void DoStream(std::shared_ptr<MixerInput> sample, bool loop);
void EndCallback(std::shared_ptr<MixerInput> sample);
AudioMixer(const AudioMixer&) = delete;
AudioMixer& operator=(const AudioMixer&) = delete;
};

View File

@ -1,6 +1,7 @@
#include "engine/audio/mixer_input.h"
#include "base/log.h"
#include "base/thread_pool.h"
#include "engine/audio/audio_bus.h"
#include "engine/audio/audio_mixer.h"
@ -21,78 +22,124 @@ std::shared_ptr<MixerInput> MixerInput::Create() {
return std::shared_ptr<MixerInput>(new MixerInput());
}
void MixerInput::SetAudioBus(std::shared_ptr<AudioBus> bus) {
if (streaming)
pending_audio_bus = bus;
void MixerInput::SetAudioBus(std::shared_ptr<AudioBus> audio_bus) {
if (playing_)
pending_audio_bus_ = audio_bus;
else
audio_bus = bus;
audio_bus_ = audio_bus;
}
void MixerInput::Play(AudioMixer* mixer, bool restart) {
if (!mixer->IsAudioEnabled())
if (!mixer->IsAudioEnabled()) {
if (!playing_ && end_cb_)
end_cb_();
return;
}
// If already streaming check if stream position needs to be reset.
if (streaming) {
// If already playing check if stream position needs to be reset.
if (playing_) {
if (restart)
flags.fetch_or(kStopped, std::memory_order_relaxed);
flags_.fetch_or(kStopped, std::memory_order_relaxed);
if (flags.load(std::memory_order_relaxed) & kStopped)
restart_cb = [&, mixer, restart]() -> void { Play(mixer, restart); };
if (flags_.load(std::memory_order_relaxed) & kStopped)
restart_cb_ = [&, mixer, restart]() -> void { Play(mixer, restart); };
return;
}
if (restart || audio_bus->EndOfStream()) {
src_index = 0;
accumulator = 0;
audio_bus->ResetStream();
if (restart || audio_bus_->EndOfStream()) {
src_index_ = 0;
accumulator_ = 0;
audio_bus_->ResetStream();
}
streaming = true;
flags.fetch_and(~kStopped, std::memory_order_relaxed);
playing_ = true;
flags_.fetch_and(~kStopped, std::memory_order_relaxed);
mixer->AddInput(shared_from_this());
}
void MixerInput::Stop() {
if (streaming) {
restart_cb = nullptr;
flags.fetch_or(kStopped, std::memory_order_relaxed);
if (playing_) {
restart_cb_ = nullptr;
flags_.fetch_or(kStopped, std::memory_order_relaxed);
}
}
void MixerInput::SetLoop(bool loop) {
if (loop)
flags.fetch_or(kLoop, std::memory_order_relaxed);
flags_.fetch_or(kLoop, std::memory_order_relaxed);
else
flags.fetch_and(~kLoop, std::memory_order_relaxed);
flags_.fetch_and(~kLoop, std::memory_order_relaxed);
}
void MixerInput::SetSimulateStereo(bool simulate) {
if (simulate)
flags.fetch_or(kSimulateStereo, std::memory_order_relaxed);
flags_.fetch_or(kSimulateStereo, std::memory_order_relaxed);
else
flags.fetch_and(~kSimulateStereo, std::memory_order_relaxed);
flags_.fetch_and(~kSimulateStereo, std::memory_order_relaxed);
}
void MixerInput::SetResampleStep(size_t value) {
step.store(value + 100, std::memory_order_relaxed);
step_.store(value + 100, std::memory_order_relaxed);
}
void MixerInput::SetAmplitude(float value) {
amplitude.store(value, std::memory_order_relaxed);
amplitude_.store(value, std::memory_order_relaxed);
}
void MixerInput::SetMaxAmplitude(float value) {
max_amplitude.store(value, std::memory_order_relaxed);
max_amplitude_.store(value, std::memory_order_relaxed);
}
void MixerInput::SetAmplitudeInc(float value) {
amplitude_inc.store(value, std::memory_order_relaxed);
amplitude_inc_.store(value, std::memory_order_relaxed);
}
void MixerInput::SetEndCallback(base::Closure cb) {
end_cb = std::move(cb);
end_cb_ = std::move(cb);
}
bool MixerInput::IsStreamingInProgress() const {
return streaming_in_progress_.load(std::memory_order_relaxed);
}
void MixerInput::SetPosition(size_t index, int accumulator) {
src_index_ = index;
accumulator_ = accumulator;
}
bool MixerInput::OnMoreData(bool loop) {
if (streaming_in_progress_.load(std::memory_order_acquire))
return false;
streaming_in_progress_.store(true, std::memory_order_relaxed);
audio_bus_->SwapBuffers();
ThreadPool::Get().PostTask(
HERE,
[&, loop]() {
audio_bus_->Stream(loop);
streaming_in_progress_.store(false, std::memory_order_release);
},
true);
return true;
}
void MixerInput::OnRemovedFromMixer() {
DCHECK(!streaming_in_progress_.load(std::memory_order_relaxed));
DCHECK(playing_);
playing_ = false;
if (pending_audio_bus_) {
audio_bus_ = pending_audio_bus_;
pending_audio_bus_.reset();
}
if (end_cb_)
end_cb_();
if (restart_cb_) {
restart_cb_();
restart_cb_ = nullptr;
}
}
} // namespace eng

View File

@ -13,16 +13,19 @@ class AudioMixer;
// An audio input stream that gets mixed and rendered to the audio sink. Handles
// playback and volume control.
struct MixerInput : public std::enable_shared_from_this<MixerInput> {
class MixerInput : public std::enable_shared_from_this<MixerInput> {
public:
enum Flags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
~MixerInput();
static std::shared_ptr<MixerInput> Create();
// Set AudioBus for playback. If this MixerInput is already streaming, keeps
// it as pending and sets once playback ends.
void SetAudioBus(std::shared_ptr<AudioBus> bus);
bool IsValid() const { return !!audio_bus_; }
// Set AudioBus for playback. If this MixerInput is already playing, keeps it
// as pending and sets once playback ends.
void SetAudioBus(std::shared_ptr<AudioBus> audio_bus);
// Starts playback. Remembers last stream position. Resets the stream position
// if restart is true.
@ -31,6 +34,7 @@ struct MixerInput : public std::enable_shared_from_this<MixerInput> {
// Stops playback. Does not reset stream position.
void Stop();
// Set whether the playback should loop or not.
void SetLoop(bool loop);
// Simulate stereo effect slightly delays one channel.
@ -47,30 +51,57 @@ struct MixerInput : public std::enable_shared_from_this<MixerInput> {
// Set a callback to be called once playback ends.
void SetEndCallback(base::Closure cb);
// Active AudioBus.
std::shared_ptr<AudioBus> audio_bus;
// AudioBus to be set as active once playback ends.
std::shared_ptr<AudioBus> pending_audio_bus;
// Stream position.
size_t src_index = 0;
size_t accumulator = 0;
// Getters
std::shared_ptr<AudioBus> GetAudioBus() const { return audio_bus_; }
unsigned GetFlags() const { return flags_.load(std::memory_order_relaxed); }
size_t GetStep() const { return step_.load(std::memory_order_relaxed); }
float GetAmplitude() const {
return amplitude_.load(std::memory_order_relaxed);
}
float GetAmplitudeInc() const {
return amplitude_inc_.load(std::memory_order_relaxed);
}
float GetMaxAmplitude() const {
return max_amplitude_.load(std::memory_order_relaxed);
}
size_t GetSrcIndex() const { return src_index_; }
size_t GetAccumulator() const { return accumulator_; }
// Accessed by main thread only.
bool streaming = false;
base::Closure end_cb;
base::Closure restart_cb;
bool IsStreamingInProgress() const;
// Accessed by main thread and audio thread.
std::atomic<unsigned> flags{0};
std::atomic<size_t> step{100};
std::atomic<float> amplitude{1.0f};
std::atomic<float> amplitude_inc{0};
std::atomic<float> max_amplitude{1.0f};
// Called by the mixer to save the last sample position.
void SetPosition(size_t index, int accumulator);
// Accessed by audio thread and decoding worker thread.
std::atomic<bool> streaming_in_progress{false};
// Called by the mixer when more data is needed.
bool OnMoreData(bool loop);
// Called by the mixer when playback ends.
void OnRemovedFromMixer();
private:
// Active AudioBus.
std::shared_ptr<AudioBus> audio_bus_;
// AudioBus to be set as active once playback ends.
std::shared_ptr<AudioBus> pending_audio_bus_;
// Stream position.
size_t src_index_ = 0;
size_t accumulator_ = 0;
// Accessed by main thread only.
bool playing_ = false;
base::Closure end_cb_;
base::Closure restart_cb_;
// Accessed by main thread and audio thread.
std::atomic<unsigned> flags_{0};
std::atomic<size_t> step_{100};
std::atomic<float> amplitude_{1.0f};
std::atomic<float> amplitude_inc_{0};
std::atomic<float> max_amplitude_{1.0f};
// Accessed by audio thread and decoding worker thread.
std::atomic<bool> streaming_in_progress_{false};
MixerInput();
};

View File

@ -26,7 +26,7 @@ void SoundPlayer::SetSound(std::shared_ptr<AudioBus> sound) {
}
void SoundPlayer::Play(bool loop, float fade_in_duration) {
if (!input_->audio_bus)
if (!input_->IsValid())
return;
int step = variate_ ? Engine::Get().GetRandomGenerator().Roll(3) - 2 : 0;
@ -35,7 +35,7 @@ void SoundPlayer::Play(bool loop, float fade_in_duration) {
if (fade_in_duration > 0) {
input_->SetAmplitude(0);
input_->SetAmplitudeInc(
1.0f / (input_->audio_bus->sample_rate() * fade_in_duration));
1.0f / (input_->GetAudioBus()->sample_rate() * fade_in_duration));
} else {
input_->SetAmplitude(max_amplitude_);
input_->SetAmplitudeInc(0);
@ -44,24 +44,24 @@ void SoundPlayer::Play(bool loop, float fade_in_duration) {
}
void SoundPlayer::Resume(float fade_in_duration) {
if (!input_->audio_bus)
if (!input_->IsValid())
return;
if (fade_in_duration > 0) {
input_->SetAmplitude(0);
input_->SetAmplitudeInc(
1.0f / (input_->audio_bus->sample_rate() * fade_in_duration));
1.0f / (input_->GetAudioBus()->sample_rate() * fade_in_duration));
}
input_->Play(Engine::Get().GetAudioMixer(), false);
}
void SoundPlayer::Stop(float fade_out_duration) {
if (!input_->audio_bus)
if (!input_->IsValid())
return;
if (fade_out_duration > 0)
input_->SetAmplitudeInc(
-1.0f / (input_->audio_bus->sample_rate() * fade_out_duration));
-1.0f / (input_->GetAudioBus()->sample_rate() * fade_out_duration));
else
input_->Stop();
}

View File

@ -9,7 +9,7 @@
namespace eng {
class AudioBus;
struct MixerInput;
class MixerInput;
class SoundPlayer {
public: