mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
audio/internal/oboe: Do not call a Go function from onAudioReady
Calling a Go function from C has some overhead. onAudioReady is a very performance-critical function and should not call Go function. Updates #1662
This commit is contained in:
parent
78459953cf
commit
ea6e2091c5
45
audio/internal/oboe/binding_android.cpp
vendored
45
audio/internal/oboe/binding_android.cpp
vendored
@ -17,7 +17,10 @@
|
|||||||
#include "_cgo_export.h"
|
#include "_cgo_export.h"
|
||||||
#include "oboe_oboe_Oboe_android.h"
|
#include "oboe_oboe_Oboe_android.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -35,6 +38,7 @@ public:
|
|||||||
const char *Pause();
|
const char *Pause();
|
||||||
const char *Resume();
|
const char *Resume();
|
||||||
const char *Close();
|
const char *Close();
|
||||||
|
const char *AppendBuffer(float *buf, size_t len);
|
||||||
|
|
||||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboe_stream,
|
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboe_stream,
|
||||||
void *audio_data,
|
void *audio_data,
|
||||||
@ -42,11 +46,20 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Stream();
|
Stream();
|
||||||
|
void Loop(int num_frames);
|
||||||
|
|
||||||
int sample_rate_ = 0;
|
int sample_rate_ = 0;
|
||||||
int channel_num_ = 0;
|
int channel_num_ = 0;
|
||||||
int bit_depth_in_bytes_ = 0;
|
int bit_depth_in_bytes_ = 0;
|
||||||
|
|
||||||
std::shared_ptr<oboe::AudioStream> stream_;
|
std::shared_ptr<oboe::AudioStream> stream_;
|
||||||
|
|
||||||
|
// All the member variables other than the thread must be initialized before
|
||||||
|
// the thread.
|
||||||
|
std::vector<float> buf_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cond_;
|
||||||
|
std::unique_ptr<std::thread> thread_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Stream &Stream::GetInstance() {
|
Stream &Stream::GetInstance() {
|
||||||
@ -74,7 +87,6 @@ const char *Stream::Play(int sample_rate, int channel_num,
|
|||||||
->setFormat(oboe::AudioFormat::Float)
|
->setFormat(oboe::AudioFormat::Float)
|
||||||
->setChannelCount(channel_num_)
|
->setChannelCount(channel_num_)
|
||||||
->setSampleRate(sample_rate_)
|
->setSampleRate(sample_rate_)
|
||||||
->setBufferCapacityInFrames(1024)
|
|
||||||
->setDataCallback(this)
|
->setDataCallback(this)
|
||||||
->openStream(stream_);
|
->openStream(stream_);
|
||||||
if (result != oboe::Result::OK) {
|
if (result != oboe::Result::OK) {
|
||||||
@ -84,6 +96,11 @@ const char *Stream::Play(int sample_rate, int channel_num,
|
|||||||
if (stream_->getSharingMode() != oboe::SharingMode::Shared) {
|
if (stream_->getSharingMode() != oboe::SharingMode::Shared) {
|
||||||
return "oboe::SharingMode::Shared is not available";
|
return "oboe::SharingMode::Shared is not available";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int num_frames = stream_->getBufferSizeInFrames();
|
||||||
|
thread_ =
|
||||||
|
std::make_unique<std::thread>([this, num_frames]() { Loop(num_frames); });
|
||||||
|
|
||||||
// What if the buffer size is not enough?
|
// What if the buffer size is not enough?
|
||||||
if (oboe::Result result = stream_->start(); result != oboe::Result::OK) {
|
if (oboe::Result result = stream_->start(); result != oboe::Result::OK) {
|
||||||
return oboe::convertToText(result);
|
return oboe::convertToText(result);
|
||||||
@ -130,15 +147,37 @@ oboe::DataCallbackResult Stream::onAudioReady(oboe::AudioStream *oboe_stream,
|
|||||||
void *audio_data,
|
void *audio_data,
|
||||||
int32_t num_frames) {
|
int32_t num_frames) {
|
||||||
size_t num = num_frames * channel_num_;
|
size_t num = num_frames * channel_num_;
|
||||||
float *dst = reinterpret_cast<float *>(audio_data);
|
|
||||||
// TODO: Do not use a lock in onAudioReady.
|
// TODO: Do not use a lock in onAudioReady.
|
||||||
// https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d
|
// https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d
|
||||||
ebiten_oboe_read(dst, num);
|
{
|
||||||
|
std::unique_lock<std::mutex> lock{mutex_};
|
||||||
|
cond_.wait(lock, [this, num] { return buf_.size() >= num; });
|
||||||
|
std::copy(buf_.begin(), buf_.begin() + num,
|
||||||
|
reinterpret_cast<float *>(audio_data));
|
||||||
|
buf_.erase(buf_.begin(), buf_.begin() + num);
|
||||||
|
cond_.notify_one();
|
||||||
|
}
|
||||||
return oboe::DataCallbackResult::Continue;
|
return oboe::DataCallbackResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream() = default;
|
Stream::Stream() = default;
|
||||||
|
|
||||||
|
void Stream::Loop(int num_frames) {
|
||||||
|
std::vector<float> tmp(num_frames * channel_num_ * 2);
|
||||||
|
for (;;) {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock{mutex_};
|
||||||
|
cond_.wait(lock, [this, &tmp] { return buf_.size() < tmp.size(); });
|
||||||
|
}
|
||||||
|
ebiten_oboe_read(&tmp[0], tmp.size());
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
buf_.insert(buf_.end(), tmp.begin(), tmp.end());
|
||||||
|
cond_.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
Loading…
Reference in New Issue
Block a user