mirror of https://github.com/auygun/kaliber.git
Compare commits
3 Commits
dd14ed30ea
...
261e7f41d6
Author | SHA1 | Date |
---|---|---|
|
261e7f41d6 | |
|
02418aa42a | |
|
e08f6e2022 |
|
@ -114,13 +114,13 @@ android {
|
||||||
java.srcDirs += ['../../../src/engine/platform/java/com/kaliber/base']
|
java.srcDirs += ['../../../src/engine/platform/java/com/kaliber/base']
|
||||||
android.buildTypes.each { buildType ->
|
android.buildTypes.each { buildType ->
|
||||||
"${buildType.name}" {
|
"${buildType.name}" {
|
||||||
assets.srcDirs = [utils.getAssetsDir(buildType.name)]
|
assets.srcDirs = ["${utils.getGnOutDir(buildType.name)}/assets"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
android.buildTypes.each { buildType ->
|
android.buildTypes.each { buildType ->
|
||||||
"${buildType.name}" {
|
"${buildType.name}" {
|
||||||
jniLibs.srcDirs = [utils.getJniLibsDir(buildType.name)]
|
jniLibs.srcDirs = ["${utils.getGnOutDir(buildType.name)}/jniLibs"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ dependencies {
|
||||||
utils.addTask('generateGnArgsFor') { String taskName, String buildType, String arch ->
|
utils.addTask('generateGnArgsFor') { String taskName, String buildType, String arch ->
|
||||||
task(taskName, type: WriteFileTask) {
|
task(taskName, type: WriteFileTask) {
|
||||||
content = utils.generateGnArgsContent(buildType, arch)
|
content = utils.generateGnArgsContent(buildType, arch)
|
||||||
target = project.layout.file(provider { new File("${utils.getOutDir(buildType)}/${arch}", 'args.gn') })
|
target = project.layout.file(provider { new File("${utils.getGnOutDir(buildType)}/${arch}", 'args.gn') })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +153,11 @@ utils.addTask('runGnFor') { String taskName, String buildType, String arch ->
|
||||||
dependsOn "generateGnArgsFor${arch}${buildType}"
|
dependsOn "generateGnArgsFor${arch}${buildType}"
|
||||||
|
|
||||||
executable rootProject.ext.gn
|
executable rootProject.ext.gn
|
||||||
args '--fail-on-unused-args', 'gen', "${utils.getOutDir(buildType)}/${arch}"
|
args '--fail-on-unused-args', 'gen', "${utils.getGnOutDir(buildType)}/${arch}"
|
||||||
|
|
||||||
// Need to run gn only once unless the configuration in `args.gn` changes.
|
// Need to run gn only once unless the configuration in `args.gn` changes.
|
||||||
inputs.file(new File("${utils.getOutDir(buildType)}/${arch}", 'args.gn'))
|
inputs.file(new File("${utils.getGnOutDir(buildType)}/${arch}", 'args.gn'))
|
||||||
outputs.file(new File("${utils.getOutDir(buildType)}/${arch}", 'build.ninja'))
|
outputs.file(new File("${utils.getGnOutDir(buildType)}/${arch}", 'build.ninja'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ utils.addGameTask('runNinjaFor') { String taskName, String buildType, String arc
|
||||||
dependsOn "runGnFor${arch}${buildType}"
|
dependsOn "runGnFor${arch}${buildType}"
|
||||||
|
|
||||||
executable rootProject.ext.ninja
|
executable rootProject.ext.ninja
|
||||||
args '-C', "${utils.getOutDir(buildType)}/${arch}", "src/${utils.getGnTargetFor(game)}"
|
args '-C', "${utils.getGnOutDir(buildType)}/${arch}", "src/${utils.getGnTargetFor(game)}"
|
||||||
|
|
||||||
// Always run ninja and let it figure out what needs to be compiled.
|
// Always run ninja and let it figure out what needs to be compiled.
|
||||||
outputs.upToDateWhen { false }
|
outputs.upToDateWhen { false }
|
||||||
|
@ -180,8 +180,8 @@ utils.addGameTask('copyAssetsFor') { String taskName, String buildType, String a
|
||||||
task(taskName, type: Copy) {
|
task(taskName, type: Copy) {
|
||||||
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
||||||
|
|
||||||
from "${utils.getOutDir(buildType)}/${arch}/assets"
|
from "${utils.getGnOutDir(buildType)}/${arch}/assets"
|
||||||
into utils.getAssetsDir(buildType)
|
into "${utils.getGnOutDir(buildType)}/assets"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +190,10 @@ utils.addGameTask('copyJniLibsFor') { String taskName, String buildType, String
|
||||||
task(taskName, type: Copy) {
|
task(taskName, type: Copy) {
|
||||||
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
dependsOn "runNinjaFor${game}${arch}${buildType}"
|
||||||
|
|
||||||
from("${utils.getOutDir(buildType)}/${arch}") {
|
from("${utils.getGnOutDir(buildType)}/${arch}") {
|
||||||
include "lib${utils.getGnTargetFor(game)}.so"
|
include "lib${utils.getGnTargetFor(game)}.so"
|
||||||
}
|
}
|
||||||
into "${utils.getJniLibsDir(buildType)}/${utils.getAbiCodeFor(arch)}"
|
into "${utils.getGnOutDir(buildType)}/jniLibs/${utils.getAbiCodeFor(arch)}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,17 +357,9 @@ class Utils implements Plugin<Project> {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
def getOutDir(String buildType) {
|
def getGnOutDir(String buildType) {
|
||||||
return "${project.buildDir}/gn_out/${buildType.toLowerCase()}"
|
return "${project.buildDir}/gn_out/${buildType.toLowerCase()}"
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAssetsDir(String buildType) {
|
|
||||||
return "${project.buildDir}/gn_out/${buildType.toLowerCase()}/assets"
|
|
||||||
}
|
|
||||||
|
|
||||||
def getJniLibsDir(String buildType) {
|
|
||||||
return "${project.buildDir}/gn_out/jniLibs/${buildType.toLowerCase()}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class WriteFileTask extends DefaultTask {
|
abstract class WriteFileTask extends DefaultTask {
|
||||||
|
|
|
@ -2,9 +2,9 @@ source_set("audio") {
|
||||||
sources = [
|
sources = [
|
||||||
"audio_bus.cc",
|
"audio_bus.cc",
|
||||||
"audio_bus.h",
|
"audio_bus.h",
|
||||||
|
"audio_device.h",
|
||||||
"audio_mixer.cc",
|
"audio_mixer.cc",
|
||||||
"audio_mixer.h",
|
"audio_mixer.h",
|
||||||
"audio_sink.h",
|
|
||||||
"mixer_input.cc",
|
"mixer_input.cc",
|
||||||
"mixer_input.h",
|
"mixer_input.h",
|
||||||
"sinc_resampler.cc",
|
"sinc_resampler.cc",
|
||||||
|
@ -16,16 +16,16 @@ source_set("audio") {
|
||||||
|
|
||||||
if (target_os == "linux") {
|
if (target_os == "linux") {
|
||||||
sources += [
|
sources += [
|
||||||
"audio_sink_alsa.cc",
|
"audio_device_alsa.cc",
|
||||||
"audio_sink_alsa.h",
|
"audio_device_alsa.h",
|
||||||
]
|
]
|
||||||
libs += [ "asound" ]
|
libs += [ "asound" ]
|
||||||
} else if (target_os == "win") {
|
} else if (target_os == "win") {
|
||||||
sources += [ "audio_sink_null.h" ]
|
sources += [ "audio_device_null.h" ]
|
||||||
} else if (target_os == "android") {
|
} else if (target_os == "android") {
|
||||||
sources += [
|
sources += [
|
||||||
"audio_sink_oboe.cc",
|
"audio_device_oboe.cc",
|
||||||
"audio_sink_oboe.h",
|
"audio_device_oboe.h",
|
||||||
]
|
]
|
||||||
deps += [ "//src/third_party/oboe" ]
|
deps += [ "//src/third_party/oboe" ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_DEVICE_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_DEVICE_H
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
// Models an audio device sending mixed audio to the audio driver. Audio data
|
||||||
|
// from the mixer source is delivered on a pull model using Delegate.
|
||||||
|
class AudioDevice {
|
||||||
|
public:
|
||||||
|
class Delegate {
|
||||||
|
public:
|
||||||
|
Delegate() = default;
|
||||||
|
virtual ~Delegate() = default;
|
||||||
|
|
||||||
|
virtual int GetChannelCount() = 0;
|
||||||
|
|
||||||
|
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioDevice() = default;
|
||||||
|
virtual ~AudioDevice() = default;
|
||||||
|
|
||||||
|
virtual bool Initialize() = 0;
|
||||||
|
|
||||||
|
virtual void Suspend() = 0;
|
||||||
|
virtual void Resume() = 0;
|
||||||
|
|
||||||
|
virtual size_t GetHardwareSampleRate() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioDevice(const AudioDevice&) = delete;
|
||||||
|
AudioDevice& operator=(const AudioDevice&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_DEVICE_H
|
|
@ -1,4 +1,4 @@
|
||||||
#include "engine/audio/audio_sink_alsa.h"
|
#include "engine/audio/audio_device_alsa.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioSinkAlsa::AudioSinkAlsa(AudioSink::Delegate* delegate)
|
AudioDeviceAlsa::AudioDeviceAlsa(AudioDevice::Delegate* delegate)
|
||||||
: delegate_(delegate) {}
|
: delegate_(delegate) {}
|
||||||
|
|
||||||
AudioSinkAlsa::~AudioSinkAlsa() {
|
AudioDeviceAlsa::~AudioDeviceAlsa() {
|
||||||
LOG(0) << "Shutting down audio.";
|
LOG(0) << "Shutting down audio.";
|
||||||
|
|
||||||
TerminateAudioThread();
|
TerminateAudioThread();
|
||||||
|
@ -22,7 +22,7 @@ AudioSinkAlsa::~AudioSinkAlsa() {
|
||||||
snd_pcm_close(device_);
|
snd_pcm_close(device_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSinkAlsa::Initialize() {
|
bool AudioDeviceAlsa::Initialize() {
|
||||||
LOG(0) << "Initializing audio.";
|
LOG(0) << "Initializing audio.";
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
@ -145,28 +145,28 @@ bool AudioSinkAlsa::Initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkAlsa::Suspend() {
|
void AudioDeviceAlsa::Suspend() {
|
||||||
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkAlsa::Resume() {
|
void AudioDeviceAlsa::Resume() {
|
||||||
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AudioSinkAlsa::GetHardwareSampleRate() {
|
size_t AudioDeviceAlsa::GetHardwareSampleRate() {
|
||||||
return sample_rate_;
|
return sample_rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkAlsa::StartAudioThread() {
|
void AudioDeviceAlsa::StartAudioThread() {
|
||||||
DCHECK(!audio_thread_.joinable());
|
DCHECK(!audio_thread_.joinable());
|
||||||
|
|
||||||
LOG(0) << "Starting audio thread.";
|
LOG(0) << "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(false, std::memory_order_relaxed);
|
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
audio_thread_ = std::thread(&AudioSinkAlsa::AudioThreadMain, this);
|
audio_thread_ = std::thread(&AudioDeviceAlsa::AudioThreadMain, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkAlsa::TerminateAudioThread() {
|
void AudioDeviceAlsa::TerminateAudioThread() {
|
||||||
if (!audio_thread_.joinable())
|
if (!audio_thread_.joinable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ void AudioSinkAlsa::TerminateAudioThread() {
|
||||||
audio_thread_.join();
|
audio_thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkAlsa::AudioThreadMain() {
|
void AudioDeviceAlsa::AudioThreadMain() {
|
||||||
DCHECK(delegate_);
|
DCHECK(delegate_);
|
||||||
|
|
||||||
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
|
@ -1,19 +1,19 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
#ifndef ENGINE_AUDIO_AUDIO_DEVICE_ALSA_H
|
||||||
#define ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
#define ENGINE_AUDIO_AUDIO_DEVICE_ALSA_H
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "engine/audio/audio_sink.h"
|
#include "engine/audio/audio_device.h"
|
||||||
|
|
||||||
typedef struct _snd_pcm snd_pcm_t;
|
typedef struct _snd_pcm snd_pcm_t;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioSinkAlsa final : public AudioSink {
|
class AudioDeviceAlsa final : public AudioDevice {
|
||||||
public:
|
public:
|
||||||
AudioSinkAlsa(AudioSink::Delegate* delegate);
|
AudioDeviceAlsa(AudioDevice::Delegate* delegate);
|
||||||
~AudioSinkAlsa() final;
|
~AudioDeviceAlsa() final;
|
||||||
|
|
||||||
bool Initialize() final;
|
bool Initialize() final;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class AudioSinkAlsa final : public AudioSink {
|
||||||
size_t sample_rate_ = 0;
|
size_t sample_rate_ = 0;
|
||||||
size_t period_size_ = 0;
|
size_t period_size_ = 0;
|
||||||
|
|
||||||
AudioSink::Delegate* delegate_ = nullptr;
|
AudioDevice::Delegate* delegate_ = nullptr;
|
||||||
|
|
||||||
void StartAudioThread();
|
void StartAudioThread();
|
||||||
void TerminateAudioThread();
|
void TerminateAudioThread();
|
||||||
|
@ -44,4 +44,4 @@ class AudioSinkAlsa final : public AudioSink {
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_SINK_ALSA_H
|
#endif // ENGINE_AUDIO_AUDIO_DEVICE_ALSA_H
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_DEVICE_NULL_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_DEVICE_NULL_H
|
||||||
|
|
||||||
|
#include "engine/audio/audio_device.h"
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
class AudioDeviceNull final : public AudioDevice {
|
||||||
|
public:
|
||||||
|
AudioDeviceNull() = default;
|
||||||
|
~AudioDeviceNull() final = default;
|
||||||
|
|
||||||
|
bool Initialize() final { return true; }
|
||||||
|
|
||||||
|
void Suspend() final {}
|
||||||
|
void Resume() final {}
|
||||||
|
|
||||||
|
size_t GetHardwareSampleRate() final { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_DEVICE_NULL_H
|
|
@ -1,4 +1,4 @@
|
||||||
#include "engine/audio/audio_sink_oboe.h"
|
#include "engine/audio/audio_device_oboe.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "third_party/oboe/include/oboe/Oboe.h"
|
#include "third_party/oboe/include/oboe/Oboe.h"
|
||||||
|
@ -7,54 +7,54 @@ using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioSinkOboe::AudioSinkOboe(AudioSink::Delegate* delegate)
|
AudioDeviceOboe::AudioDeviceOboe(AudioDevice::Delegate* delegate)
|
||||||
: callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {}
|
: callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {}
|
||||||
|
|
||||||
AudioSinkOboe::~AudioSinkOboe() {
|
AudioDeviceOboe::~AudioDeviceOboe() {
|
||||||
LOG(0) << "Shutting down audio.";
|
LOG(0) << "Shutting down audio.";
|
||||||
stream_->stop();
|
stream_->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSinkOboe::Initialize() {
|
bool AudioDeviceOboe::Initialize() {
|
||||||
LOG(0) << "Initializing audio.";
|
LOG(0) << "Initializing audio.";
|
||||||
return RestartStream();
|
return RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkOboe::Suspend() {
|
void AudioDeviceOboe::Suspend() {
|
||||||
stream_->pause();
|
stream_->pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkOboe::Resume() {
|
void AudioDeviceOboe::Resume() {
|
||||||
stream_->start();
|
stream_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AudioSinkOboe::GetHardwareSampleRate() {
|
size_t AudioDeviceOboe::GetHardwareSampleRate() {
|
||||||
return stream_->getSampleRate();
|
return stream_->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSinkOboe::StreamCallback::StreamCallback(AudioSinkOboe* audio_sink)
|
AudioDeviceOboe::StreamCallback::StreamCallback(AudioDeviceOboe* audio_device)
|
||||||
: audio_sink_(audio_sink) {}
|
: audio_device_(audio_device) {}
|
||||||
|
|
||||||
AudioSinkOboe::StreamCallback::~StreamCallback() = default;
|
AudioDeviceOboe::StreamCallback::~StreamCallback() = default;
|
||||||
|
|
||||||
oboe::DataCallbackResult AudioSinkOboe::StreamCallback::onAudioReady(
|
oboe::DataCallbackResult AudioDeviceOboe::StreamCallback::onAudioReady(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
void* audio_data,
|
void* audio_data,
|
||||||
int32_t num_frames) {
|
int32_t num_frames) {
|
||||||
float* output_buffer = static_cast<float*>(audio_data);
|
float* output_buffer = static_cast<float*>(audio_data);
|
||||||
audio_sink_->delegate_->RenderAudio(output_buffer, num_frames);
|
audio_device_->delegate_->RenderAudio(output_buffer, num_frames);
|
||||||
return oboe::DataCallbackResult::Continue;
|
return oboe::DataCallbackResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSinkOboe::StreamCallback::onErrorAfterClose(
|
void AudioDeviceOboe::StreamCallback::onErrorAfterClose(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
oboe::Result error) {
|
oboe::Result error) {
|
||||||
LOG(0) << "Error after close. Error: " << oboe::convertToText(error);
|
LOG(0) << "Error after close. Error: " << oboe::convertToText(error);
|
||||||
|
|
||||||
audio_sink_->RestartStream();
|
audio_device_->RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSinkOboe::RestartStream() {
|
bool AudioDeviceOboe::RestartStream() {
|
||||||
oboe::AudioStreamBuilder builder;
|
oboe::AudioStreamBuilder builder;
|
||||||
oboe::Result result =
|
oboe::Result result =
|
||||||
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
|
@ -1,19 +1,19 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
#ifndef ENGINE_AUDIO_AUDIO_DEVICE_OBOE_H
|
||||||
#define ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
#define ENGINE_AUDIO_AUDIO_DEVICE_OBOE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "third_party/oboe/include/oboe/AudioStream.h"
|
#include "third_party/oboe/include/oboe/AudioStream.h"
|
||||||
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
||||||
|
|
||||||
#include "engine/audio/audio_sink.h"
|
#include "engine/audio/audio_device.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioSinkOboe final : public AudioSink {
|
class AudioDeviceOboe final : public AudioDevice {
|
||||||
public:
|
public:
|
||||||
AudioSinkOboe(AudioSink::Delegate* delegate);
|
AudioDeviceOboe(AudioDevice::Delegate* delegate);
|
||||||
~AudioSinkOboe() final;
|
~AudioDeviceOboe() final;
|
||||||
|
|
||||||
bool Initialize() final;
|
bool Initialize() final;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class AudioSinkOboe final : public AudioSink {
|
||||||
private:
|
private:
|
||||||
class StreamCallback final : public oboe::AudioStreamCallback {
|
class StreamCallback final : public oboe::AudioStreamCallback {
|
||||||
public:
|
public:
|
||||||
StreamCallback(AudioSinkOboe* audio);
|
StreamCallback(AudioDeviceOboe* audio);
|
||||||
~StreamCallback() final;
|
~StreamCallback() final;
|
||||||
|
|
||||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
||||||
|
@ -36,17 +36,17 @@ class AudioSinkOboe final : public AudioSink {
|
||||||
oboe::Result error) final;
|
oboe::Result error) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioSinkOboe* audio_sink_;
|
AudioDeviceOboe* audio_device_;
|
||||||
};
|
};
|
||||||
|
|
||||||
oboe::ManagedStream stream_;
|
oboe::ManagedStream stream_;
|
||||||
std::unique_ptr<StreamCallback> callback_;
|
std::unique_ptr<StreamCallback> callback_;
|
||||||
|
|
||||||
AudioSink::Delegate* delegate_ = nullptr;
|
AudioDevice::Delegate* delegate_ = nullptr;
|
||||||
|
|
||||||
bool RestartStream();
|
bool RestartStream();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_SINK_OBOE_H
|
#endif // ENGINE_AUDIO_AUDIO_DEVICE_OBOE_H
|
|
@ -8,11 +8,11 @@
|
||||||
#include "engine/audio/mixer_input.h"
|
#include "engine/audio/mixer_input.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include "engine/audio/audio_sink_oboe.h"
|
#include "engine/audio/audio_device_oboe.h"
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include "engine/audio/audio_sink_alsa.h"
|
#include "engine/audio/audio_device_alsa.h"
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include "engine/audio/audio_sink_null.h"
|
#include "engine/audio/audio_device_null.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
@ -22,19 +22,19 @@ namespace eng {
|
||||||
AudioMixer::AudioMixer()
|
AudioMixer::AudioMixer()
|
||||||
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()),
|
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()),
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
audio_sink_{std::make_unique<AudioSinkOboe>(this)} {
|
audio_device_{std::make_unique<AudioDeviceOboe>(this)} {
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
audio_sink_{std::make_unique<AudioSinkAlsa>(this)} {
|
audio_device_{std::make_unique<AudioDeviceAlsa>(this)} {
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
// TODO: Implement AudioSinkWindows
|
// TODO: Implement AudioDeviceWindows
|
||||||
audio_sink_{std::make_unique<AudioSinkNull>()} {
|
audio_device_{std::make_unique<AudioDeviceNull>()} {
|
||||||
#endif
|
#endif
|
||||||
bool res = audio_sink_->Initialize();
|
bool res = audio_device_->Initialize();
|
||||||
CHECK(res) << "Failed to initialize audio sink.";
|
CHECK(res) << "Failed to initialize audio device.";
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMixer::~AudioMixer() {
|
AudioMixer::~AudioMixer() {
|
||||||
audio_sink_.reset();
|
audio_device_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::AddInput(std::shared_ptr<MixerInput> mixer_input) {
|
void AudioMixer::AddInput(std::shared_ptr<MixerInput> mixer_input) {
|
||||||
|
@ -45,15 +45,15 @@ void AudioMixer::AddInput(std::shared_ptr<MixerInput> mixer_input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::Suspend() {
|
void AudioMixer::Suspend() {
|
||||||
audio_sink_->Suspend();
|
audio_device_->Suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::Resume() {
|
void AudioMixer::Resume() {
|
||||||
audio_sink_->Resume();
|
audio_device_->Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AudioMixer::GetHardwareSampleRate() {
|
size_t AudioMixer::GetHardwareSampleRate() {
|
||||||
return audio_sink_->GetHardwareSampleRate();
|
return audio_device_->GetHardwareSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "base/closure.h"
|
#include "base/closure.h"
|
||||||
#include "engine/audio/audio_sink.h"
|
#include "engine/audio/audio_device.h"
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class TaskRunner;
|
class TaskRunner;
|
||||||
|
@ -21,9 +21,9 @@ class MixerInput;
|
||||||
// when it needs more data. Input source will be removed once end-of-stream is
|
// when it needs more data. Input source will be removed once end-of-stream is
|
||||||
// reached. Any unfilled frames will be filled with silence. The mixer always
|
// reached. Any unfilled frames will be filled with silence. The mixer always
|
||||||
// outputs audio when active, even if input sources underflow. A platform
|
// outputs audio when active, even if input sources underflow. A platform
|
||||||
// specific AudioSink implementation is expected to periodically call
|
// specific AudioDevice implementation is expected to periodically call
|
||||||
// RenderAudio() in a background thread.
|
// RenderAudio() in a background thread.
|
||||||
class AudioMixer : public AudioSink::Delegate {
|
class AudioMixer : public AudioDevice::Delegate {
|
||||||
public:
|
public:
|
||||||
AudioMixer();
|
AudioMixer();
|
||||||
~AudioMixer();
|
~AudioMixer();
|
||||||
|
@ -48,11 +48,11 @@ class AudioMixer : public AudioSink::Delegate {
|
||||||
|
|
||||||
std::shared_ptr<base::TaskRunner> main_thread_task_runner_;
|
std::shared_ptr<base::TaskRunner> main_thread_task_runner_;
|
||||||
|
|
||||||
std::unique_ptr<AudioSink> audio_sink_;
|
std::unique_ptr<AudioDevice> audio_device_;
|
||||||
|
|
||||||
bool audio_enabled_ = true;
|
bool audio_enabled_ = true;
|
||||||
|
|
||||||
// AudioSink::Delegate interface
|
// AudioDevice::Delegate interface
|
||||||
int GetChannelCount() final { return kChannelCount; }
|
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;
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_SINK_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_SINK_H
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
// Models an audio sink sending mixed audio to the audio driver. Audio data from
|
|
||||||
// the mixer source is delivered on a pull model using Delegate.
|
|
||||||
class AudioSink {
|
|
||||||
public:
|
|
||||||
class Delegate {
|
|
||||||
public:
|
|
||||||
Delegate() = default;
|
|
||||||
virtual ~Delegate() = default;
|
|
||||||
|
|
||||||
virtual int GetChannelCount() = 0;
|
|
||||||
|
|
||||||
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
AudioSink() = default;
|
|
||||||
virtual ~AudioSink() = default;
|
|
||||||
|
|
||||||
virtual bool Initialize() = 0;
|
|
||||||
|
|
||||||
virtual void Suspend() = 0;
|
|
||||||
virtual void Resume() = 0;
|
|
||||||
|
|
||||||
virtual size_t GetHardwareSampleRate() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AudioSink(const AudioSink&) = delete;
|
|
||||||
AudioSink& operator=(const AudioSink&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_SINK_H
|
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_SINK_NULL_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_SINK_NULL_H
|
|
||||||
|
|
||||||
#include "engine/audio/audio_sink.h"
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioSinkNull final : public AudioSink {
|
|
||||||
public:
|
|
||||||
AudioSinkNull() = default;
|
|
||||||
~AudioSinkNull() final = default;
|
|
||||||
|
|
||||||
bool Initialize() final { return true; }
|
|
||||||
|
|
||||||
void Suspend() final {}
|
|
||||||
void Resume() final {}
|
|
||||||
|
|
||||||
size_t GetHardwareSampleRate() final { return 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_SINK_NULL_H
|
|
|
@ -11,8 +11,8 @@ namespace eng {
|
||||||
class AudioBus;
|
class AudioBus;
|
||||||
class AudioMixer;
|
class AudioMixer;
|
||||||
|
|
||||||
// An audio input stream that gets mixed and rendered to the audio sink. Handles
|
// An audio input stream that gets mixed and rendered to the audio device.
|
||||||
// playback and volume control.
|
// Handles playback and volume control.
|
||||||
class MixerInput : public std::enable_shared_from_this<MixerInput> {
|
class MixerInput : public std::enable_shared_from_this<MixerInput> {
|
||||||
public:
|
public:
|
||||||
enum Flags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
enum Flags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "engine/drawable.h"
|
#include "engine/drawable.h"
|
||||||
|
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
|
#include "engine/renderer/shader.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
@ -12,4 +13,17 @@ Drawable::~Drawable() {
|
||||||
Engine::Get().RemoveDrawable(this);
|
Engine::Get().RemoveDrawable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Drawable::SetCustomShader(const std::string& asset_name) {
|
||||||
|
custom_shader_ = Engine::Get().GetShader(asset_name);
|
||||||
|
custom_uniforms_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drawable::DoSetCustomUniforms() {
|
||||||
|
if (custom_shader_) {
|
||||||
|
for (auto& cu : custom_uniforms_)
|
||||||
|
std::visit([&](auto&& arg) { custom_shader_->SetUniform(cu.first, arg); },
|
||||||
|
cu.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
#ifndef ENGINE_DRAWABLE_H
|
#ifndef ENGINE_DRAWABLE_H
|
||||||
#define ENGINE_DRAWABLE_H
|
#define ENGINE_DRAWABLE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
|
class Shader;
|
||||||
|
|
||||||
class Drawable {
|
class Drawable {
|
||||||
public:
|
public:
|
||||||
Drawable();
|
Drawable();
|
||||||
|
@ -21,9 +27,30 @@ class Drawable {
|
||||||
int GetZOrder() const { return z_order_; }
|
int GetZOrder() const { return z_order_; }
|
||||||
bool IsVisible() const { return visible_; }
|
bool IsVisible() const { return visible_; }
|
||||||
|
|
||||||
|
void SetCustomShader(const std::string& asset_name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SetCustomUniform(const std::string& name, T value) {
|
||||||
|
custom_uniforms_[name] = UniformValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Shader* GetCustomShader() { return custom_shader_; }
|
||||||
|
void DoSetCustomUniforms();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using UniformValue = std::variant<base::Vector2f,
|
||||||
|
base::Vector3f,
|
||||||
|
base::Vector4f,
|
||||||
|
base::Matrix4f,
|
||||||
|
float,
|
||||||
|
int>;
|
||||||
|
|
||||||
bool visible_ = false;
|
bool visible_ = false;
|
||||||
int z_order_ = 0;
|
int z_order_ = 0;
|
||||||
|
|
||||||
|
Shader* custom_shader_ = nullptr;
|
||||||
|
std::unordered_map<std::string, UniformValue> custom_uniforms_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -40,11 +40,6 @@ void ImageQuad::Destroy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageQuad::SetCustomShader(const std::string& asset_name) {
|
|
||||||
custom_shader_ = Engine::Get().GetShader(asset_name);
|
|
||||||
custom_uniforms_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageQuad::SetFrame(size_t frame) {
|
void ImageQuad::SetFrame(size_t frame) {
|
||||||
DCHECK(frame < GetNumFrames())
|
DCHECK(frame < GetNumFrames())
|
||||||
<< "asset: " << asset_name_ << " frame: " << frame;
|
<< "asset: " << asset_name_ << " frame: " << frame;
|
||||||
|
@ -66,8 +61,9 @@ void ImageQuad::Draw(float frame_frac) {
|
||||||
Vector2f tex_scale = {GetFrameWidth() / texture_->GetWidth(),
|
Vector2f tex_scale = {GetFrameWidth() / texture_->GetWidth(),
|
||||||
GetFrameHeight() / texture_->GetHeight()};
|
GetFrameHeight() / texture_->GetHeight()};
|
||||||
|
|
||||||
Shader* shader =
|
Shader* shader = GetCustomShader();
|
||||||
custom_shader_ ? custom_shader_ : Engine::Get().GetPassThroughShader();
|
if (!shader)
|
||||||
|
shader = Engine::Get().GetPassThroughShader();
|
||||||
|
|
||||||
shader->Activate();
|
shader->Activate();
|
||||||
shader->SetUniform("offset", position_);
|
shader->SetUniform("offset", position_);
|
||||||
|
@ -78,12 +74,7 @@ void ImageQuad::Draw(float frame_frac) {
|
||||||
shader->SetUniform("projection", Engine::Get().GetProjectionMatrix());
|
shader->SetUniform("projection", Engine::Get().GetProjectionMatrix());
|
||||||
shader->SetUniform("color", color_);
|
shader->SetUniform("color", color_);
|
||||||
shader->SetUniform("texture_0", 0);
|
shader->SetUniform("texture_0", 0);
|
||||||
if (custom_shader_) {
|
DoSetCustomUniforms();
|
||||||
for (auto& cu : custom_uniforms_)
|
|
||||||
std::visit(
|
|
||||||
[shader, &cu](auto&& arg) { shader->SetUniform(cu.first, arg); },
|
|
||||||
cu.second);
|
|
||||||
}
|
|
||||||
shader->UploadUniforms();
|
shader->UploadUniforms();
|
||||||
|
|
||||||
Engine::Get().GetQuad()->Draw();
|
Engine::Get().GetQuad()->Draw();
|
||||||
|
|
|
@ -3,15 +3,12 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
#include "engine/animatable.h"
|
#include "engine/animatable.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class Shader;
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
class ImageQuad final : public Animatable {
|
class ImageQuad final : public Animatable {
|
||||||
|
@ -26,13 +23,6 @@ class ImageQuad final : public Animatable {
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
void SetCustomShader(const std::string& asset_name);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void SetCustomUniform(const std::string& name, T value) {
|
|
||||||
custom_uniforms_[name] = UniformValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animatable interface.
|
// Animatable interface.
|
||||||
void SetFrame(size_t frame) final;
|
void SetFrame(size_t frame) final;
|
||||||
size_t GetFrame() const final { return current_frame_; }
|
size_t GetFrame() const final { return current_frame_; }
|
||||||
|
@ -44,18 +34,8 @@ class ImageQuad final : public Animatable {
|
||||||
void Draw(float frame_frac) final;
|
void Draw(float frame_frac) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using UniformValue = std::variant<base::Vector2f,
|
|
||||||
base::Vector3f,
|
|
||||||
base::Vector4f,
|
|
||||||
base::Matrix4f,
|
|
||||||
float,
|
|
||||||
int>;
|
|
||||||
|
|
||||||
Texture* texture_ = nullptr;
|
Texture* texture_ = nullptr;
|
||||||
|
|
||||||
Shader* custom_shader_ = nullptr;
|
|
||||||
std::unordered_map<std::string, UniformValue> custom_uniforms_;
|
|
||||||
|
|
||||||
size_t current_frame_ = 0;
|
size_t current_frame_ = 0;
|
||||||
std::array<int, 2> num_frames_ = {1, 1}; // horizontal, vertical
|
std::array<int, 2> num_frames_ = {1, 1}; // horizontal, vertical
|
||||||
int frame_width_ = 0;
|
int frame_width_ = 0;
|
||||||
|
|
|
@ -12,7 +12,9 @@ namespace eng {
|
||||||
void SolidQuad::Draw(float frame_frac) {
|
void SolidQuad::Draw(float frame_frac) {
|
||||||
DCHECK(IsVisible());
|
DCHECK(IsVisible());
|
||||||
|
|
||||||
Shader* shader = Engine::Get().GetSolidShader();
|
Shader* shader = GetCustomShader();
|
||||||
|
if (!shader)
|
||||||
|
shader = Engine::Get().GetSolidShader();
|
||||||
|
|
||||||
shader->Activate();
|
shader->Activate();
|
||||||
shader->SetUniform("offset", position_);
|
shader->SetUniform("offset", position_);
|
||||||
|
@ -20,6 +22,7 @@ void SolidQuad::Draw(float frame_frac) {
|
||||||
shader->SetUniform("rotation", rotation_);
|
shader->SetUniform("rotation", rotation_);
|
||||||
shader->SetUniform("projection", Engine::Get().GetProjectionMatrix());
|
shader->SetUniform("projection", Engine::Get().GetProjectionMatrix());
|
||||||
shader->SetUniform("color", color_);
|
shader->SetUniform("color", color_);
|
||||||
|
DoSetCustomUniforms();
|
||||||
shader->UploadUniforms();
|
shader->UploadUniforms();
|
||||||
|
|
||||||
Engine::Get().GetQuad()->Draw();
|
Engine::Get().GetQuad()->Draw();
|
||||||
|
|
Loading…
Reference in New Issue