From 8d28d85a09d1a6fc29847923d0a38a508e01fa8d Mon Sep 17 00:00:00 2001 From: Attila Uygun Date: Tue, 23 May 2023 01:38:31 +0200 Subject: [PATCH] Move AudioDriver ownership to AudioMixer --- src/engine/audio/audio_driver.h | 8 ------- src/engine/audio/audio_driver_alsa.cc | 30 +++++++++++------------- src/engine/audio/audio_driver_alsa.h | 8 +++---- src/engine/audio/audio_driver_delegate.h | 2 ++ src/engine/audio/audio_driver_oboe.cc | 26 +++++++------------- src/engine/audio/audio_driver_oboe.h | 10 +++----- src/engine/audio/audio_mixer.cc | 28 +++++++++++++++++++++- src/engine/audio/audio_mixer.h | 11 ++++++++- src/engine/engine.cc | 13 ++++------ src/engine/engine.h | 5 ++-- src/engine/platform/platform.cc | 17 +------------- src/engine/platform/platform.h | 2 -- 12 files changed, 74 insertions(+), 86 deletions(-) diff --git a/src/engine/audio/audio_driver.h b/src/engine/audio/audio_driver.h index 865ad0c..81a7937 100644 --- a/src/engine/audio/audio_driver.h +++ b/src/engine/audio/audio_driver.h @@ -1,12 +1,8 @@ #ifndef ENGINE_AUDIO_AUDIO_DRIVER_H #define ENGINE_AUDIO_AUDIO_DRIVER_H -#include "engine/audio/audio_driver.h" - namespace eng { -class AudioDriverDelegate; - // Models an audio sink sending mixed audio to the audio driver. Audio data from // the mixer source is delivered on a pull model using AudioDriverDelegate. class AudioDriver { @@ -14,12 +10,8 @@ class AudioDriver { AudioDriver() = default; virtual ~AudioDriver() = default; - virtual void SetDelegate(AudioDriverDelegate* delegate) = 0; - virtual bool Initialize() = 0; - virtual void Shutdown() = 0; - virtual void Suspend() = 0; virtual void Resume() = 0; diff --git a/src/engine/audio/audio_driver_alsa.cc b/src/engine/audio/audio_driver_alsa.cc index 689d8c7..959908e 100644 --- a/src/engine/audio/audio_driver_alsa.cc +++ b/src/engine/audio/audio_driver_alsa.cc @@ -11,17 +11,19 @@ using namespace base; namespace eng { -AudioDriverAlsa::AudioDriverAlsa() = default; +AudioDriverAlsa::AudioDriverAlsa(AudioDriverDelegate* delegate) + : delegate_(delegate) {} -AudioDriverAlsa::~AudioDriverAlsa() = default; +AudioDriverAlsa::~AudioDriverAlsa() { + LOG << "Shutting down audio."; -void AudioDriverAlsa::SetDelegate(AudioDriverDelegate* delegate) { - delegate_ = delegate; - Resume(); + TerminateAudioThread(); + snd_pcm_drop(device_); + snd_pcm_close(device_); } bool AudioDriverAlsa::Initialize() { - LOG << "Initializing audio system."; + LOG << "Initializing audio."; int err; @@ -142,13 +144,6 @@ bool AudioDriverAlsa::Initialize() { return false; } -void AudioDriverAlsa::Shutdown() { - LOG << "Shutting down audio system."; - TerminateAudioThread(); - snd_pcm_drop(device_); - snd_pcm_close(device_); -} - void AudioDriverAlsa::Suspend() { suspend_audio_thread_.store(true, std::memory_order_relaxed); } @@ -162,15 +157,16 @@ int AudioDriverAlsa::GetHardwareSampleRate() { } void AudioDriverAlsa::StartAudioThread() { + DCHECK(!audio_thread_.joinable()); + LOG << "Starting audio thread."; terminate_audio_thread_.store(false, std::memory_order_relaxed); - suspend_audio_thread_.store(delegate_ ? false : true, - std::memory_order_relaxed); + suspend_audio_thread_.store(false, std::memory_order_relaxed); audio_thread_ = std::thread(&AudioDriverAlsa::AudioThreadMain, this); } void AudioDriverAlsa::TerminateAudioThread() { - if (terminate_audio_thread_.load(std::memory_order_relaxed)) + if (!audio_thread_.joinable()) return; LOG << "Terminating audio thread"; @@ -180,6 +176,8 @@ void AudioDriverAlsa::TerminateAudioThread() { } void AudioDriverAlsa::AudioThreadMain() { + DCHECK(delegate_); + size_t num_frames = period_size_ / (num_channels_ * sizeof(float)); auto buffer = std::make_unique(num_frames * 2); diff --git a/src/engine/audio/audio_driver_alsa.h b/src/engine/audio/audio_driver_alsa.h index f3d56d4..71160a9 100644 --- a/src/engine/audio/audio_driver_alsa.h +++ b/src/engine/audio/audio_driver_alsa.h @@ -10,17 +10,15 @@ typedef struct _snd_pcm snd_pcm_t; namespace eng { +class AudioDriverDelegate; + class AudioDriverAlsa final : public AudioDriver { public: - AudioDriverAlsa(); + AudioDriverAlsa(AudioDriverDelegate* delegate); ~AudioDriverAlsa() final; - void SetDelegate(AudioDriverDelegate* delegate) final; - bool Initialize() final; - void Shutdown() final; - void Suspend() final; void Resume() final; diff --git a/src/engine/audio/audio_driver_delegate.h b/src/engine/audio/audio_driver_delegate.h index e2fee3f..1d1727a 100644 --- a/src/engine/audio/audio_driver_delegate.h +++ b/src/engine/audio/audio_driver_delegate.h @@ -10,6 +10,8 @@ class AudioDriverDelegate { AudioDriverDelegate() = default; virtual ~AudioDriverDelegate() = default; + virtual int GetChannelCount() = 0; + virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0; }; diff --git a/src/engine/audio/audio_driver_oboe.cc b/src/engine/audio/audio_driver_oboe.cc index a49ed7d..d358309 100644 --- a/src/engine/audio/audio_driver_oboe.cc +++ b/src/engine/audio/audio_driver_oboe.cc @@ -8,28 +8,19 @@ using namespace base; namespace eng { -AudioDriverOboe::AudioDriverOboe() - : callback_(std::make_unique(this)) {} +AudioDriverOboe::AudioDriverOboe(AudioDriverDelegate* delegate) + : callback_(std::make_unique(this)), delegate_(delegate) {} -AudioDriverOboe::~AudioDriverOboe() = default; - -void AudioDriverOboe::SetDelegate(AudioDriverDelegate* delegate) { - delegate_ = delegate; - stream_->start(); +AudioDriverOboe::~AudioDriverOboe() { + LOG << "Shutting down audio."; + stream_->stop(); } bool AudioDriverOboe::Initialize() { - LOG << "Initializing audio system."; - + LOG << "Initializing audio."; return RestartStream(); } -void AudioDriverOboe::Shutdown() { - LOG << "Shutting down audio system."; - - stream_->stop(); -} - void AudioDriverOboe::Suspend() { stream_->pause(); } @@ -70,7 +61,7 @@ bool AudioDriverOboe::RestartStream() { builder.setSharingMode(oboe::SharingMode::Exclusive) ->setPerformanceMode(oboe::PerformanceMode::LowLatency) ->setFormat(oboe::AudioFormat::Float) - ->setChannelCount(kChannelCount) + ->setChannelCount(delegate_->GetChannelCount()) ->setDirection(oboe::Direction::Output) ->setUsage(oboe::Usage::Game) ->setCallback(callback_.get()) @@ -88,8 +79,7 @@ bool AudioDriverOboe::RestartStream() { return false; } - if (delegate_) - stream_->start(); + stream_->start(); return true; } diff --git a/src/engine/audio/audio_driver_oboe.h b/src/engine/audio/audio_driver_oboe.h index 01d961f..e48ff04 100644 --- a/src/engine/audio/audio_driver_oboe.h +++ b/src/engine/audio/audio_driver_oboe.h @@ -10,25 +10,21 @@ namespace eng { +class AudioDriverDelegate; + class AudioDriverOboe final : public AudioDriver { public: - AudioDriverOboe(); + AudioDriverOboe(AudioDriverDelegate* delegate); ~AudioDriverOboe() final; - void SetDelegate(AudioDriverDelegate* delegate) final; - bool Initialize() final; - void Shutdown() final; - void Suspend() final; void Resume() final; int GetHardwareSampleRate() final; private: - static constexpr int kChannelCount = 2; - class StreamCallback final : public oboe::AudioStreamCallback { public: StreamCallback(AudioDriverOboe* audio); diff --git a/src/engine/audio/audio_mixer.cc b/src/engine/audio/audio_mixer.cc index db53b0e..84ece45 100644 --- a/src/engine/audio/audio_mixer.cc +++ b/src/engine/audio/audio_mixer.cc @@ -7,12 +7,26 @@ #include "base/thread_pool.h" #include "engine/sound.h" +#if defined(__ANDROID__) +#include "engine/audio/audio_driver_oboe.h" +#elif defined(__linux__) +#include "engine/audio/audio_driver_alsa.h" +#endif + using namespace base; namespace eng { AudioMixer::AudioMixer() - : main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {} + : main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()), +#if defined(__ANDROID__) + audio_driver_{std::make_unique(this)} { +#elif defined(__linux__) + audio_driver_{std::make_unique(this)} { +#endif + bool res = audio_driver_->Initialize(); + CHECK(res) << "Failed to initialize audio driver."; +} AudioMixer::~AudioMixer() = default; @@ -139,6 +153,18 @@ void AudioMixer::SetEndCallback(uint64_t resource_id, base::Closure cb) { it->second->end_cb = std::move(cb); } +void AudioMixer::Suspend() { + audio_driver_->Suspend(); +} + +void AudioMixer::Resume() { + audio_driver_->Resume(); +} + +int AudioMixer::GetHardwareSampleRate() { + return audio_driver_->GetHardwareSampleRate(); +} + void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) { { std::unique_lock scoped_lock(lock_, std::try_to_lock); diff --git a/src/engine/audio/audio_mixer.h b/src/engine/audio/audio_mixer.h index b0fff9f..b63a5d2 100644 --- a/src/engine/audio/audio_mixer.h +++ b/src/engine/audio/audio_mixer.h @@ -16,10 +16,11 @@ class TaskRunner; namespace eng { +class AudioDriver; class Sound; // Mix and render audio with low overhead. A platform specific AudioDriver -// implementation is expected to periodically call Render() in a background +// implementation is expected to periodically call RenderAudio() in a background // thread. class AudioMixer : public AudioDriverDelegate { public: @@ -44,6 +45,11 @@ class AudioMixer : public AudioDriverDelegate { void SetEnableAudio(bool enable) { audio_enabled_ = enable; } + void Suspend(); + void Resume(); + + int GetHardwareSampleRate(); + private: enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 }; static constexpr int kChannelCount = 2; @@ -80,9 +86,12 @@ class AudioMixer : public AudioDriverDelegate { base::TaskRunner* main_thread_task_runner_; + std::unique_ptr audio_driver_; + bool audio_enabled_ = true; // AudioDriverDelegate implementation + int GetChannelCount() final { return kChannelCount; } void RenderAudio(float* output_buffer, size_t num_frames) final; void DoStream(std::shared_ptr sample, bool loop); diff --git a/src/engine/engine.cc b/src/engine/engine.cc index e323d57..7a6de43 100644 --- a/src/engine/engine.cc +++ b/src/engine/engine.cc @@ -2,7 +2,6 @@ #include "base/log.h" #include "engine/animator.h" -#include "engine/audio/audio_driver.h" #include "engine/audio/audio_mixer.h" #include "engine/drawable.h" #include "engine/font.h" @@ -26,17 +25,13 @@ namespace eng { Engine* Engine::singleton = nullptr; -Engine::Engine(Platform* platform, - Renderer* renderer, - AudioDriver* audio_driver) +Engine::Engine(Platform* platform, Renderer* renderer) : platform_(platform), renderer_(renderer), - audio_driver_(audio_driver), audio_mixer_{std::make_unique()} { DCHECK(!singleton); singleton = this; - audio_driver_->SetDelegate(audio_mixer_.get()); renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this)); quad_ = CreateRenderResource(); @@ -143,14 +138,14 @@ void Engine::Draw(float frame_frac) { } void Engine::LostFocus() { - audio_driver_->Suspend(); + audio_mixer_->Suspend(); if (game_) game_->LostFocus(); } void Engine::GainedFocus(bool from_interstitial_ad) { - audio_driver_->Resume(); + audio_mixer_->Resume(); if (game_) game_->GainedFocus(from_interstitial_ad); @@ -488,7 +483,7 @@ const std::string& Engine::GetSharedDataPath() const { } int Engine::GetAudioHardwareSampleRate() { - return audio_driver_->GetHardwareSampleRate(); + return audio_mixer_->GetHardwareSampleRate(); } bool Engine::IsMobile() const { diff --git a/src/engine/engine.h b/src/engine/engine.h index c47f9c7..5bf42a1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -16,7 +16,6 @@ class TextureCompressor; namespace eng { class Animator; -class AudioDriver; class AudioMixer; class Font; class Game; @@ -34,7 +33,7 @@ class Engine { public: using CreateImageCB = std::function()>; - Engine(Platform* platform, Renderer* renderer, AudioDriver* audio_driver); + Engine(Platform* platform, Renderer* renderer); ~Engine(); static Engine& Get(); @@ -176,9 +175,9 @@ class Engine { Platform* platform_ = nullptr; Renderer* renderer_ = nullptr; - AudioDriver* audio_driver_ = nullptr; std::unique_ptr audio_mixer_; + std::unique_ptr game_; std::unique_ptr quad_; diff --git a/src/engine/platform/platform.cc b/src/engine/platform/platform.cc index 96bc5b6..c65d6ea 100644 --- a/src/engine/platform/platform.cc +++ b/src/engine/platform/platform.cc @@ -6,12 +6,6 @@ #include "engine/renderer/opengl/renderer_opengl.h" #include "engine/renderer/vulkan/renderer_vulkan.h" -#if defined(__ANDROID__) -#include "engine/audio/audio_driver_oboe.h" -#elif defined(__linux__) -#include "engine/audio/audio_driver_alsa.h" -#endif - #define USE_VULKAN_RENDERER 1 using namespace base; @@ -47,14 +41,6 @@ void Platform::InitializeCommon() { thread_pool_.Initialize(); TaskRunner::CreateThreadLocalTaskRunner(); -#if defined(__ANDROID__) - audio_driver_ = std::make_unique(); -#elif defined(__linux__) - audio_driver_ = std::make_unique(); -#endif - bool res = audio_driver_->Initialize(); - CHECK(res) << "Failed to initialize audio driver."; - #if (USE_VULKAN_RENDERER == 1) renderer_ = std::make_unique(); #else @@ -65,13 +51,12 @@ void Platform::InitializeCommon() { void Platform::ShutdownCommon() { LOG << "Shutting down platform."; - audio_driver_->Shutdown(); renderer_->Shutdown(); } void Platform::RunMainLoop() { engine_ = - std::make_unique(this, renderer_.get(), audio_driver_.get()); + std::make_unique(this, renderer_.get()); bool res = engine_->Initialize(); CHECK(res) << "Failed to initialize the engine."; diff --git a/src/engine/platform/platform.h b/src/engine/platform/platform.h index a5ef7ac..977a868 100644 --- a/src/engine/platform/platform.h +++ b/src/engine/platform/platform.h @@ -24,7 +24,6 @@ struct ANativeWindow; namespace eng { -class AudioDriver; class Renderer; class Engine; @@ -79,7 +78,6 @@ class Platform { bool has_focus_ = false; bool should_exit_ = false; - std::unique_ptr audio_driver_; std::unique_ptr renderer_; std::unique_ptr engine_;