Move AudioDriver ownership to AudioMixer

This commit is contained in:
Attila Uygun 2023-05-23 01:38:31 +02:00
parent b160ae0bd3
commit 8d28d85a09
12 changed files with 74 additions and 86 deletions

View File

@ -1,12 +1,8 @@
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_H #ifndef ENGINE_AUDIO_AUDIO_DRIVER_H
#define ENGINE_AUDIO_AUDIO_DRIVER_H #define ENGINE_AUDIO_AUDIO_DRIVER_H
#include "engine/audio/audio_driver.h"
namespace eng { namespace eng {
class AudioDriverDelegate;
// Models an audio sink sending mixed audio to the audio driver. Audio data from // 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. // the mixer source is delivered on a pull model using AudioDriverDelegate.
class AudioDriver { class AudioDriver {
@ -14,12 +10,8 @@ class AudioDriver {
AudioDriver() = default; AudioDriver() = default;
virtual ~AudioDriver() = default; virtual ~AudioDriver() = default;
virtual void SetDelegate(AudioDriverDelegate* delegate) = 0;
virtual bool Initialize() = 0; virtual bool Initialize() = 0;
virtual void Shutdown() = 0;
virtual void Suspend() = 0; virtual void Suspend() = 0;
virtual void Resume() = 0; virtual void Resume() = 0;

View File

@ -11,17 +11,19 @@ using namespace base;
namespace eng { 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) { TerminateAudioThread();
delegate_ = delegate; snd_pcm_drop(device_);
Resume(); snd_pcm_close(device_);
} }
bool AudioDriverAlsa::Initialize() { bool AudioDriverAlsa::Initialize() {
LOG << "Initializing audio system."; LOG << "Initializing audio.";
int err; int err;
@ -142,13 +144,6 @@ bool AudioDriverAlsa::Initialize() {
return false; return false;
} }
void AudioDriverAlsa::Shutdown() {
LOG << "Shutting down audio system.";
TerminateAudioThread();
snd_pcm_drop(device_);
snd_pcm_close(device_);
}
void AudioDriverAlsa::Suspend() { void AudioDriverAlsa::Suspend() {
suspend_audio_thread_.store(true, std::memory_order_relaxed); suspend_audio_thread_.store(true, std::memory_order_relaxed);
} }
@ -162,15 +157,16 @@ int AudioDriverAlsa::GetHardwareSampleRate() {
} }
void AudioDriverAlsa::StartAudioThread() { void AudioDriverAlsa::StartAudioThread() {
DCHECK(!audio_thread_.joinable());
LOG << "Starting audio thread."; LOG << "Starting audio thread.";
terminate_audio_thread_.store(false, std::memory_order_relaxed); terminate_audio_thread_.store(false, std::memory_order_relaxed);
suspend_audio_thread_.store(delegate_ ? false : true, suspend_audio_thread_.store(false, std::memory_order_relaxed);
std::memory_order_relaxed);
audio_thread_ = std::thread(&AudioDriverAlsa::AudioThreadMain, this); audio_thread_ = std::thread(&AudioDriverAlsa::AudioThreadMain, this);
} }
void AudioDriverAlsa::TerminateAudioThread() { void AudioDriverAlsa::TerminateAudioThread() {
if (terminate_audio_thread_.load(std::memory_order_relaxed)) if (!audio_thread_.joinable())
return; return;
LOG << "Terminating audio thread"; LOG << "Terminating audio thread";
@ -180,6 +176,8 @@ void AudioDriverAlsa::TerminateAudioThread() {
} }
void AudioDriverAlsa::AudioThreadMain() { void AudioDriverAlsa::AudioThreadMain() {
DCHECK(delegate_);
size_t num_frames = period_size_ / (num_channels_ * sizeof(float)); size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
auto buffer = std::make_unique<float[]>(num_frames * 2); auto buffer = std::make_unique<float[]>(num_frames * 2);

View File

@ -10,17 +10,15 @@ typedef struct _snd_pcm snd_pcm_t;
namespace eng { namespace eng {
class AudioDriverDelegate;
class AudioDriverAlsa final : public AudioDriver { class AudioDriverAlsa final : public AudioDriver {
public: public:
AudioDriverAlsa(); AudioDriverAlsa(AudioDriverDelegate* delegate);
~AudioDriverAlsa() final; ~AudioDriverAlsa() final;
void SetDelegate(AudioDriverDelegate* delegate) final;
bool Initialize() final; bool Initialize() final;
void Shutdown() final;
void Suspend() final; void Suspend() final;
void Resume() final; void Resume() final;

View File

@ -10,6 +10,8 @@ class AudioDriverDelegate {
AudioDriverDelegate() = default; AudioDriverDelegate() = default;
virtual ~AudioDriverDelegate() = default; virtual ~AudioDriverDelegate() = default;
virtual int GetChannelCount() = 0;
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0; virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
}; };

View File

@ -8,28 +8,19 @@ using namespace base;
namespace eng { namespace eng {
AudioDriverOboe::AudioDriverOboe() AudioDriverOboe::AudioDriverOboe(AudioDriverDelegate* delegate)
: callback_(std::make_unique<StreamCallback>(this)) {} : callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {}
AudioDriverOboe::~AudioDriverOboe() = default; AudioDriverOboe::~AudioDriverOboe() {
LOG << "Shutting down audio.";
void AudioDriverOboe::SetDelegate(AudioDriverDelegate* delegate) { stream_->stop();
delegate_ = delegate;
stream_->start();
} }
bool AudioDriverOboe::Initialize() { bool AudioDriverOboe::Initialize() {
LOG << "Initializing audio system."; LOG << "Initializing audio.";
return RestartStream(); return RestartStream();
} }
void AudioDriverOboe::Shutdown() {
LOG << "Shutting down audio system.";
stream_->stop();
}
void AudioDriverOboe::Suspend() { void AudioDriverOboe::Suspend() {
stream_->pause(); stream_->pause();
} }
@ -70,7 +61,7 @@ bool AudioDriverOboe::RestartStream() {
builder.setSharingMode(oboe::SharingMode::Exclusive) builder.setSharingMode(oboe::SharingMode::Exclusive)
->setPerformanceMode(oboe::PerformanceMode::LowLatency) ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
->setFormat(oboe::AudioFormat::Float) ->setFormat(oboe::AudioFormat::Float)
->setChannelCount(kChannelCount) ->setChannelCount(delegate_->GetChannelCount())
->setDirection(oboe::Direction::Output) ->setDirection(oboe::Direction::Output)
->setUsage(oboe::Usage::Game) ->setUsage(oboe::Usage::Game)
->setCallback(callback_.get()) ->setCallback(callback_.get())
@ -88,7 +79,6 @@ bool AudioDriverOboe::RestartStream() {
return false; return false;
} }
if (delegate_)
stream_->start(); stream_->start();
return true; return true;
} }

View File

@ -10,25 +10,21 @@
namespace eng { namespace eng {
class AudioDriverDelegate;
class AudioDriverOboe final : public AudioDriver { class AudioDriverOboe final : public AudioDriver {
public: public:
AudioDriverOboe(); AudioDriverOboe(AudioDriverDelegate* delegate);
~AudioDriverOboe() final; ~AudioDriverOboe() final;
void SetDelegate(AudioDriverDelegate* delegate) final;
bool Initialize() final; bool Initialize() final;
void Shutdown() final;
void Suspend() final; void Suspend() final;
void Resume() final; void Resume() final;
int GetHardwareSampleRate() final; int GetHardwareSampleRate() final;
private: private:
static constexpr int kChannelCount = 2;
class StreamCallback final : public oboe::AudioStreamCallback { class StreamCallback final : public oboe::AudioStreamCallback {
public: public:
StreamCallback(AudioDriverOboe* audio); StreamCallback(AudioDriverOboe* audio);

View File

@ -7,12 +7,26 @@
#include "base/thread_pool.h" #include "base/thread_pool.h"
#include "engine/sound.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; using namespace base;
namespace eng { namespace eng {
AudioMixer::AudioMixer() AudioMixer::AudioMixer()
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {} : main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()),
#if defined(__ANDROID__)
audio_driver_{std::make_unique<AudioDriverOboe>(this)} {
#elif defined(__linux__)
audio_driver_{std::make_unique<AudioDriverAlsa>(this)} {
#endif
bool res = audio_driver_->Initialize();
CHECK(res) << "Failed to initialize audio driver.";
}
AudioMixer::~AudioMixer() = default; AudioMixer::~AudioMixer() = default;
@ -139,6 +153,18 @@ void AudioMixer::SetEndCallback(uint64_t resource_id, base::Closure cb) {
it->second->end_cb = std::move(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) { void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
{ {
std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock); std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock);

View File

@ -16,10 +16,11 @@ class TaskRunner;
namespace eng { namespace eng {
class AudioDriver;
class Sound; class Sound;
// Mix and render audio with low overhead. A platform specific AudioDriver // 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. // thread.
class AudioMixer : public AudioDriverDelegate { class AudioMixer : public AudioDriverDelegate {
public: public:
@ -44,6 +45,11 @@ class AudioMixer : public AudioDriverDelegate {
void SetEnableAudio(bool enable) { audio_enabled_ = enable; } void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
void Suspend();
void Resume();
int GetHardwareSampleRate();
private: private:
enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 }; enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
static constexpr int kChannelCount = 2; static constexpr int kChannelCount = 2;
@ -80,9 +86,12 @@ class AudioMixer : public AudioDriverDelegate {
base::TaskRunner* main_thread_task_runner_; base::TaskRunner* main_thread_task_runner_;
std::unique_ptr<AudioDriver> audio_driver_;
bool audio_enabled_ = true; bool audio_enabled_ = true;
// AudioDriverDelegate implementation // AudioDriverDelegate implementation
int GetChannelCount() final { return kChannelCount; }
void RenderAudio(float* output_buffer, size_t num_frames) final; void RenderAudio(float* output_buffer, size_t num_frames) final;
void DoStream(std::shared_ptr<Resource> sample, bool loop); void DoStream(std::shared_ptr<Resource> sample, bool loop);

View File

@ -2,7 +2,6 @@
#include "base/log.h" #include "base/log.h"
#include "engine/animator.h" #include "engine/animator.h"
#include "engine/audio/audio_driver.h"
#include "engine/audio/audio_mixer.h" #include "engine/audio/audio_mixer.h"
#include "engine/drawable.h" #include "engine/drawable.h"
#include "engine/font.h" #include "engine/font.h"
@ -26,17 +25,13 @@ namespace eng {
Engine* Engine::singleton = nullptr; Engine* Engine::singleton = nullptr;
Engine::Engine(Platform* platform, Engine::Engine(Platform* platform, Renderer* renderer)
Renderer* renderer,
AudioDriver* audio_driver)
: platform_(platform), : platform_(platform),
renderer_(renderer), renderer_(renderer),
audio_driver_(audio_driver),
audio_mixer_{std::make_unique<AudioMixer>()} { audio_mixer_{std::make_unique<AudioMixer>()} {
DCHECK(!singleton); DCHECK(!singleton);
singleton = this; singleton = this;
audio_driver_->SetDelegate(audio_mixer_.get());
renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this)); renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
quad_ = CreateRenderResource<Geometry>(); quad_ = CreateRenderResource<Geometry>();
@ -143,14 +138,14 @@ void Engine::Draw(float frame_frac) {
} }
void Engine::LostFocus() { void Engine::LostFocus() {
audio_driver_->Suspend(); audio_mixer_->Suspend();
if (game_) if (game_)
game_->LostFocus(); game_->LostFocus();
} }
void Engine::GainedFocus(bool from_interstitial_ad) { void Engine::GainedFocus(bool from_interstitial_ad) {
audio_driver_->Resume(); audio_mixer_->Resume();
if (game_) if (game_)
game_->GainedFocus(from_interstitial_ad); game_->GainedFocus(from_interstitial_ad);
@ -488,7 +483,7 @@ const std::string& Engine::GetSharedDataPath() const {
} }
int Engine::GetAudioHardwareSampleRate() { int Engine::GetAudioHardwareSampleRate() {
return audio_driver_->GetHardwareSampleRate(); return audio_mixer_->GetHardwareSampleRate();
} }
bool Engine::IsMobile() const { bool Engine::IsMobile() const {

View File

@ -16,7 +16,6 @@ class TextureCompressor;
namespace eng { namespace eng {
class Animator; class Animator;
class AudioDriver;
class AudioMixer; class AudioMixer;
class Font; class Font;
class Game; class Game;
@ -34,7 +33,7 @@ class Engine {
public: public:
using CreateImageCB = std::function<std::unique_ptr<Image>()>; using CreateImageCB = std::function<std::unique_ptr<Image>()>;
Engine(Platform* platform, Renderer* renderer, AudioDriver* audio_driver); Engine(Platform* platform, Renderer* renderer);
~Engine(); ~Engine();
static Engine& Get(); static Engine& Get();
@ -176,9 +175,9 @@ class Engine {
Platform* platform_ = nullptr; Platform* platform_ = nullptr;
Renderer* renderer_ = nullptr; Renderer* renderer_ = nullptr;
AudioDriver* audio_driver_ = nullptr;
std::unique_ptr<AudioMixer> audio_mixer_; std::unique_ptr<AudioMixer> audio_mixer_;
std::unique_ptr<Game> game_; std::unique_ptr<Game> game_;
std::unique_ptr<Geometry> quad_; std::unique_ptr<Geometry> quad_;

View File

@ -6,12 +6,6 @@
#include "engine/renderer/opengl/renderer_opengl.h" #include "engine/renderer/opengl/renderer_opengl.h"
#include "engine/renderer/vulkan/renderer_vulkan.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 #define USE_VULKAN_RENDERER 1
using namespace base; using namespace base;
@ -47,14 +41,6 @@ void Platform::InitializeCommon() {
thread_pool_.Initialize(); thread_pool_.Initialize();
TaskRunner::CreateThreadLocalTaskRunner(); TaskRunner::CreateThreadLocalTaskRunner();
#if defined(__ANDROID__)
audio_driver_ = std::make_unique<AudioDriverOboe>();
#elif defined(__linux__)
audio_driver_ = std::make_unique<AudioDriverAlsa>();
#endif
bool res = audio_driver_->Initialize();
CHECK(res) << "Failed to initialize audio driver.";
#if (USE_VULKAN_RENDERER == 1) #if (USE_VULKAN_RENDERER == 1)
renderer_ = std::make_unique<RendererVulkan>(); renderer_ = std::make_unique<RendererVulkan>();
#else #else
@ -65,13 +51,12 @@ void Platform::InitializeCommon() {
void Platform::ShutdownCommon() { void Platform::ShutdownCommon() {
LOG << "Shutting down platform."; LOG << "Shutting down platform.";
audio_driver_->Shutdown();
renderer_->Shutdown(); renderer_->Shutdown();
} }
void Platform::RunMainLoop() { void Platform::RunMainLoop() {
engine_ = engine_ =
std::make_unique<Engine>(this, renderer_.get(), audio_driver_.get()); std::make_unique<Engine>(this, renderer_.get());
bool res = engine_->Initialize(); bool res = engine_->Initialize();
CHECK(res) << "Failed to initialize the engine."; CHECK(res) << "Failed to initialize the engine.";

View File

@ -24,7 +24,6 @@ struct ANativeWindow;
namespace eng { namespace eng {
class AudioDriver;
class Renderer; class Renderer;
class Engine; class Engine;
@ -79,7 +78,6 @@ class Platform {
bool has_focus_ = false; bool has_focus_ = false;
bool should_exit_ = false; bool should_exit_ = false;
std::unique_ptr<AudioDriver> audio_driver_;
std::unique_ptr<Renderer> renderer_; std::unique_ptr<Renderer> renderer_;
std::unique_ptr<Engine> engine_; std::unique_ptr<Engine> engine_;