Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/android/oscillator node #25

Merged
merged 10 commits into from
Jul 17, 2024
35 changes: 23 additions & 12 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,33 @@ project(react-native-audio-context)
set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_CXX_STANDARD 14)

add_library(react-native-audio-context
SHARED
../cpp/JSIExampleHostObject.cpp
cpp-adapter.cpp
)
include(../node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake)
add_compile_options(${folly_FLAGS})

# Specifies a path to native header files.
include_directories(
../cpp
../node_modules/react-native/ReactCommon/jsi
../cpp
src/main/cpp
../node_modules/react-native/ReactCommon/jsi
../node_modules/react-native/ReactAndroid/src/main/jni/react/jni
../node_modules/react-native/ReactAndroid/src/main/jni/third-party/folly
)

add_library(react-native-audio-context SHARED
src/main/cpp/OnLoad.cpp
src/main/cpp/AudioContext
src/main/cpp/OscillatorNode
../cpp/AudioContextHostObject
../cpp/OscillatorNodeHostObject
)

find_package(ReactAndroid REQUIRED CONFIG)
find_package(fbjni REQUIRED CONFIG)

target_link_libraries(
react-native-audio-context
ReactAndroid::jsi
android
target_link_libraries(react-native-audio-context
ReactAndroid::jsi
ReactAndroid::reactnativejni
fbjni::fbjni
ReactAndroid::folly_runtime
android
log
)
5 changes: 5 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ android {
}
}

packagingOptions {
excludes = ["**/libc++_shared.so", "**/libfbjni.so", "**/libjsi.so", "**/libreactnativejni.so", "**/libfolly_json.so", "**/libreanimated.so", "**/libjscexecutor.so", "**/libhermes.so"]
}

externalNativeBuild {
cmake {
path "CMakeLists.txt"
Expand Down Expand Up @@ -125,6 +129,7 @@ dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'com.facebook.fbjni:fbjni:0.6.0'
}

if (isNewArchitectureEnabled()) {
Expand Down
20 changes: 0 additions & 20 deletions android/cpp-adapter.cpp

This file was deleted.

28 changes: 28 additions & 0 deletions android/src/main/cpp/AudioContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "AudioContext.h"
#include "AudioContextHostObject.h"
#include "OscillatorNode.h"
#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <android/log.h>

namespace audiocontext {

using namespace facebook::jni;

AudioContext::AudioContext(jni::alias_ref<AudioContext::jhybridobject> &jThis,
jlong jsContext): javaObject_(make_global(jThis)) {
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext);
auto hostObject = std::make_shared<AudioContextHostObject>(this);
auto object = jsi::Object::createFromHostObject(*runtime, hostObject);
runtime->global().setProperty(*runtime, "__AudioContextProxy", std::move(object));
}

jsi::Object AudioContext::createOscillator() {
static const auto method = javaClassLocal()->getMethod<OscillatorNode()>("createOscillator");
auto oscillator = method(javaObject_.get());
auto oscillatorCppInstance = oscillator->cthis();

return oscillatorCppInstance->createOscillatorNodeHostObject();
}

} // namespace audiocontext
41 changes: 41 additions & 0 deletions android/src/main/cpp/AudioContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include "AudioContextHostObject.h"
#include "OscillatorNode.h"

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class AudioContext : public jni::HybridClass<AudioContext> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/context/AudioContext;";

static jni::local_ref<AudioContext::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis, jlong jsContext)
{
return makeCxxInstance(jThis, jsContext);
}

static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", AudioContext::initHybrid),
});
}

jsi::Object createOscillator();

private:
friend HybridBase;

global_ref<AudioContext::javaobject> javaObject_;
std::shared_ptr<jsi::Runtime> runtime_;

explicit AudioContext(jni::alias_ref<AudioContext::jhybridobject>& jThis, jlong jsContext);
};

} // namespace audiocontext
13 changes: 13 additions & 0 deletions android/src/main/cpp/OnLoad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <fbjni/fbjni.h>
#include "OscillatorNode.h"
#include "AudioContext.h"

using namespace audiocontext;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
return facebook::jni::initialize(vm, [] {
OscillatorNode::registerNatives();
AudioContext::registerNatives();
});
}
48 changes: 48 additions & 0 deletions android/src/main/cpp/OscillatorNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "OscillatorNode.h"
#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <android/log.h>

namespace audiocontext {

using namespace facebook::jni;

OscillatorNode::OscillatorNode(jni::alias_ref<OscillatorNode::jhybridobject> &jThis, jlong jsContext)
: javaObject_(make_global(jThis)), jsContext(jsContext){}

jsi::Object OscillatorNode::createOscillatorNodeHostObject() {
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext);
auto hostObject = std::make_shared<OscillatorNodeHostObject>(this);
return jsi::Object::createFromHostObject(*runtime, hostObject);
}

void OscillatorNode::start() {
static const auto method = javaClassStatic()->getMethod<void()>("start");
method(javaObject_.get());
}

void OscillatorNode::stop() {
static const auto method = javaClassStatic()->getMethod<void()>("stop");
method(javaObject_.get());
}

void OscillatorNode::setFrequency(jdouble frequency) {
static const auto method = javaClassStatic()->getMethod<void(jdouble)>("setFrequency");
method(javaObject_.get(), frequency);
}

void OscillatorNode::setDetune(jdouble detune) {
static const auto method = javaClassStatic()->getMethod<void(jdouble)>("setDetune");
method(javaObject_.get(), detune);
}

jdouble OscillatorNode::getFrequency() {
static const auto method = javaClassLocal()->getMethod<jdouble()>("getFrequency");
return method(javaObject_.get());
}

jdouble OscillatorNode::getDetune() {
static const auto method = javaClassStatic()->getMethod<jdouble()>("getDetune");
return method(javaObject_.get());
}
} // namespace audiocontext
47 changes: 47 additions & 0 deletions android/src/main/cpp/OscillatorNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include "OscillatorNodeHostObject.h"

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class OscillatorNode : public jni::HybridClass<OscillatorNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/oscillator/OscillatorNode;";

static jni::local_ref<OscillatorNode::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis, jlong jsContext)
{
return makeCxxInstance(jThis, jsContext);
}

static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", OscillatorNode::initHybrid),
});
}

void start();
void stop();
void setFrequency(jdouble frequency);
void setDetune(jdouble detune);
jdouble getFrequency();
jdouble getDetune();

jsi::Object createOscillatorNodeHostObject();

private:
friend HybridBase;

global_ref<OscillatorNode::javaobject> javaObject_;
jlong jsContext;

explicit OscillatorNode(jni::alias_ref<OscillatorNode::jhybridobject>& jThis, jlong jsContext);
};

} // namespace audiocontext
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.audiocontext

import com.audiocontext.jsi.JSIExampleModule
import com.audiocontext.nativemodules.AudioContextModule
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

class JSIExamplePackage : ReactPackage {
class AudioContextPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf<NativeModule>(JSIExampleModule(reactContext))
return listOf<NativeModule>(AudioContextModule(reactContext))
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
Expand Down
40 changes: 40 additions & 0 deletions android/src/main/java/com/audiocontext/context/AudioContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.audiocontext.context

import android.media.AudioTrack
import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.AudioNode
import com.audiocontext.nodes.oscillator.OscillatorNode
import com.facebook.jni.HybridData
import com.facebook.react.bridge.ReactApplicationContext
import java.util.concurrent.CopyOnWriteArrayList

class AudioContext(private val reactContext: ReactApplicationContext) : BaseAudioContext {
override var sampleRate: Int = 44100
override val destination: AudioDestinationNode = AudioDestinationNode(this)
override val sources = CopyOnWriteArrayList<AudioNode>()

private val mHybridData: HybridData?;

companion object {
init {
System.loadLibrary("react-native-audio-context")
}
}

init {
mHybridData = initHybrid(reactContext.javaScriptContextHolder!!.get())
}

external fun initHybrid(l: Long): HybridData?

private fun addNode(node: AudioNode) {
sources.add(node)
}

override fun createOscillator(): OscillatorNode {
val oscillator = OscillatorNode(this, reactContext)
oscillator.connect(destination)
addNode(oscillator)
return oscillator
}
}
15 changes: 15 additions & 0 deletions android/src/main/java/com/audiocontext/context/BaseAudioContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.audiocontext.context

import android.media.AudioTrack
import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.AudioNode
import com.audiocontext.nodes.oscillator.OscillatorNode
import com.facebook.jni.HybridData

interface BaseAudioContext {
val sampleRate: Int
val destination: AudioDestinationNode
val sources: List<AudioNode>

abstract fun createOscillator(): OscillatorNode
}
36 changes: 0 additions & 36 deletions android/src/main/java/com/audiocontext/jsi/JSIExampleModule.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.audiocontext.nativemodules

import com.audiocontext.context.AudioContext
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod

class AudioContextModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

override fun getName(): String {
return "AudioContextModule"
}

@ReactMethod(isBlockingSynchronousMethod = true)
fun initAudioContext() {
AudioContext(reactContext)
}
}
Loading