Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ AudioPlayer::AudioPlayer(
const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
float sampleRate,
int channelCount)
: renderAudio_(renderAudio), sampleRate_(sampleRate), channelCount_(channelCount) {
: renderAudio_(renderAudio),
sampleRate_(sampleRate),
channelCount_(channelCount),
isRunning_(false) {
isInitialized_ = openAudioStream();

nativeAudioPlayer_ = jni::make_global(NativeAudioPlayer::create());
Expand All @@ -41,15 +44,16 @@ bool AudioPlayer::openAudioStream() {
return false;
}

mBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, sampleRate_);
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, sampleRate_);
return true;
}

bool AudioPlayer::start() {
if (mStream_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can get rid of all implicit stream to bool casts in this pr

jni::ThreadScope::WithClassLoader([this]() { nativeAudioPlayer_->start(); });
auto result = mStream_->requestStart();
return result == oboe::Result::OK;
auto result = mStream_->requestStart() == oboe::Result::OK;
isRunning_.store(result, std::memory_order_release);
return result;
}

return false;
Expand All @@ -58,21 +62,28 @@ bool AudioPlayer::start() {
void AudioPlayer::stop() {
if (mStream_) {
jni::ThreadScope::WithClassLoader([this]() { nativeAudioPlayer_->stop(); });
isRunning_.store(false, std::memory_order_release);
mStream_->requestStop();
}
}

bool AudioPlayer::resume() {
if (isRunning()) {
return true;
}

if (mStream_) {
auto result = mStream_->requestStart();
return result == oboe::Result::OK;
auto result = mStream_->requestStart() == oboe::Result::OK;
isRunning_.store(result, std::memory_order_release);
return result;
}

return false;
}

void AudioPlayer::suspend() {
if (mStream_) {
isRunning_.store(false, std::memory_order_release);
mStream_->requestPause();
}
}
Expand All @@ -87,7 +98,8 @@ void AudioPlayer::cleanup() {
}

bool AudioPlayer::isRunning() const {
return mStream_ && mStream_->getState() == oboe::StreamState::Started;
return mStream_ && mStream_->getState() == oboe::StreamState::Started &&
isRunning_.load(std::memory_order_acquire);
}

DataCallbackResult
Expand All @@ -99,17 +111,19 @@ AudioPlayer::onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numF
auto buffer = static_cast<float *>(audioData);
int processedFrames = 0;

assert(buffer != nullptr);

while (processedFrames < numFrames) {
int framesToProcess = std::min(numFrames - processedFrames, RENDER_QUANTUM_SIZE);
renderAudio_(mBus_, framesToProcess);

// TODO: optimize this with SIMD?
if (isRunning_.load(std::memory_order_acquire)) {
renderAudio_(audioBus_, framesToProcess);
} else {
audioBus_->zero();
}

for (int i = 0; i < framesToProcess; i++) {
for (int channel = 0; channel < channelCount_; channel += 1) {
Comment on lines 123 to 124
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (int i = 0; i < framesToProcess; i++) {
for (int channel = 0; channel < channelCount_; channel += 1) {
for (int i = 0; i < framesToProcess; i++) {
for (int channel = 0; channel < channelCount_; channel++) {

consistency

buffer[(processedFrames + i) * channelCount_ + channel] =
mBus_->getChannel(channel)->getData()[i];
audioBus_->getChannel(channel)->getData()[i];
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include <oboe/Oboe.h>
#include <cassert>
#include <functional>
#include <memory>

Expand Down Expand Up @@ -45,10 +44,11 @@ class AudioPlayer : public AudioStreamDataCallback, AudioStreamErrorCallback {
private:
std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
std::shared_ptr<AudioStream> mStream_;
std::shared_ptr<AudioBus> mBus_;
std::shared_ptr<AudioBus> audioBus_;
bool isInitialized_ = false;
float sampleRate_;
int channelCount_;
std::atomic<bool> isRunning_;

bool openAudioStream();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace audioapi {

AudioParamHostObject::AudioParamHostObject(const std::shared_ptr<AudioParam> &param)
: param_(param) {
: param_(param), defaultValue_(param->getDefaultValue()), minValue_(param->getMinValue()), maxValue_(param->getMaxValue()) {
addGetters(
JSI_EXPORT_PROPERTY_GETTER(AudioParamHostObject, value),
JSI_EXPORT_PROPERTY_GETTER(AudioParamHostObject, defaultValue),
Expand All @@ -31,47 +31,58 @@ JSI_PROPERTY_GETTER_IMPL(AudioParamHostObject, value) {
}

JSI_PROPERTY_GETTER_IMPL(AudioParamHostObject, defaultValue) {
return {param_->getDefaultValue()};
return {defaultValue_};
}

JSI_PROPERTY_GETTER_IMPL(AudioParamHostObject, minValue) {
return {param_->getMinValue()};
return {minValue_};
}

JSI_PROPERTY_GETTER_IMPL(AudioParamHostObject, maxValue) {
return {param_->getMaxValue()};
return {maxValue_};
}

JSI_PROPERTY_SETTER_IMPL(AudioParamHostObject, value) {
param_->setValue(static_cast<float>(value.getNumber()));
auto event = [param = param_, value = static_cast<float>(value.getNumber())](BaseAudioContext &context) {
param->setValue(value);
};

param_->scheduleAudioEvent(std::move(event));
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueAtTime) {
auto value = static_cast<float>(args[0].getNumber());
double startTime = args[1].getNumber();
param_->setValueAtTime(value, startTime);
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), startTime = args[1].getNumber()](BaseAudioContext &context) {
param->setValueAtTime(value, startTime);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, linearRampToValueAtTime) {
auto value = static_cast<float>(args[0].getNumber());
double endTime = args[1].getNumber();
param_->linearRampToValueAtTime(value, endTime);
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), endTime = args[1].getNumber()](BaseAudioContext &context) {
param->linearRampToValueAtTime(value, endTime);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, exponentialRampToValueAtTime) {
auto value = static_cast<float>(args[0].getNumber());
double endTime = args[1].getNumber();
param_->exponentialRampToValueAtTime(value, endTime);
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), endTime = args[1].getNumber()](BaseAudioContext &context) {
param->exponentialRampToValueAtTime(value, endTime);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setTargetAtTime) {
auto target = static_cast<float>(args[0].getNumber());
double startTime = args[1].getNumber();
double timeConstant = args[2].getNumber();
param_->setTargetAtTime(target, startTime, timeConstant);
auto event = [param = param_, target = static_cast<float>(args[0].getNumber()), startTime = args[1].getNumber(), timeConstant = args[2].getNumber()](BaseAudioContext &context) {
param->setTargetAtTime(target, startTime, timeConstant);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

Expand All @@ -80,24 +91,32 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueCurveAtTime) {
args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime);
auto rawValues = reinterpret_cast<float *>(arrayBuffer.data(runtime));
auto length = static_cast<int>(arrayBuffer.size(runtime));
auto values = std::make_unique<std::vector<float>>(rawValues, rawValues + length);
auto values = std::make_shared<std::vector<float>>(rawValues, rawValues + length);

double startTime = args[1].getNumber();
double duration = args[2].getNumber();
param_->setValueCurveAtTime(std::move(values), length, startTime, duration);
auto event = [param = param_, values, length, startTime = args[1].getNumber(), duration = args[2].getNumber()](BaseAudioContext &context) {
param->setValueCurveAtTime(values, length, startTime, duration);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, cancelScheduledValues) {
double cancelTime = args[0].getNumber();
param_->cancelScheduledValues(cancelTime);
auto event = [param = param_, cancelTime = args[0].getNumber()](BaseAudioContext &context) {
param->cancelScheduledValues(cancelTime);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, cancelAndHoldAtTime) {
double cancelTime = args[0].getNumber();
param_->cancelAndHoldAtTime(cancelTime);
return jsi::Value::undefined();
auto event = [param = param_, cancelTime = args[0].getNumber()](BaseAudioContext &context) {
param->cancelAndHoldAtTime(cancelTime);
};

param_->scheduleAudioEvent(std::move(event));
return jsi::Value::undefined();
}

} // namespace audioapi
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ class AudioParamHostObject : public JsiHostObject {
friend class AudioNodeHostObject;

std::shared_ptr<AudioParam> param_;
float defaultValue_;
float minValue_;
float maxValue_;
};
} // namespace audioapi
Loading