Skip to content

Commit

Permalink
Merge pull request #30 from software-mansion-labs/feat/android/connec…
Browse files Browse the repository at this point in the history
…t-method

Feat/android/connect method
  • Loading branch information
maciejmakowski2003 authored Jul 17, 2024
2 parents 2f267e2 + 2e04a4b commit eb97dff
Show file tree
Hide file tree
Showing 23 changed files with 373 additions and 171 deletions.
2 changes: 2 additions & 0 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ add_library(react-native-audio-context SHARED
src/main/cpp/OnLoad.cpp
src/main/cpp/AudioContext
src/main/cpp/OscillatorNode
src/main/cpp/AudioDestinationNode
../cpp/AudioContextHostObject
../cpp/OscillatorNodeHostObject
../cpp/AudioDestinationNodeHostObject
)

find_package(ReactAndroid REQUIRED CONFIG)
Expand Down
57 changes: 32 additions & 25 deletions android/src/main/cpp/AudioContext.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
#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
{

using namespace facebook::jni;

AudioContext::AudioContext(jni::alias_ref<AudioContext::jhybridobject> &jThis,
jlong jsContext) : javaObject_(make_global(jThis)), jsContext_(jsContext)
{
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();
}

jsi::Object AudioContext::getDestination()
{
static const auto method = javaClassLocal()->getMethod<AudioDestinationNode()>("getDestination");
auto destination = method(javaObject_.get());
auto destinationCppInstance = destination->cthis();

return destinationCppInstance->createAudioDestinationHostObject();
}

} // namespace audiocontext
49 changes: 27 additions & 22 deletions android/src/main/cpp/AudioContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,41 @@
#include <react/jni/JMessageQueueThread.h>
#include "AudioContextHostObject.h"
#include "OscillatorNode.h"
#include "AudioDestinationNode.h"

namespace audiocontext {
namespace audiocontext
{

using namespace facebook;
using namespace facebook::jni;
using namespace facebook;
using namespace facebook::jni;

class AudioContext : public jni::HybridClass<AudioContext> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/context/AudioContext;";
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 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),
});
}
static void registerNatives()
{
registerHybrid({
makeNativeMethod("initHybrid", AudioContext::initHybrid),
});
}

jsi::Object createOscillator();
jsi::Object createOscillator();
jsi::Object getDestination();

private:
friend HybridBase;
private:
friend HybridBase;

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

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

} // namespace audiocontext
15 changes: 15 additions & 0 deletions android/src/main/cpp/AudioDestinationNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "AudioDestinationNode.h"

namespace audiocontext {

using namespace facebook::jni;

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

jsi::Object AudioDestinationNode::createAudioDestinationHostObject() {
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext_);
auto hostObject = std::make_shared<AudioDestinationNodeHostObject>(this);
return jsi::Object::createFromHostObject(*runtime, hostObject);
}
} // namespace audiocontext
44 changes: 44 additions & 0 deletions android/src/main/cpp/AudioDestinationNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

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

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class OscillatorNode;

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

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

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

jsi::Object createAudioDestinationHostObject();

private:
friend HybridBase;
friend class OscillatorNode;

global_ref<AudioDestinationNode::javaobject> javaObject_;
jlong jsContext_{};

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

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

using namespace audiocontext;

Expand All @@ -9,5 +10,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
return facebook::jni::initialize(vm, [] {
OscillatorNode::registerNatives();
AudioContext::registerNatives();
AudioDestinationNode::registerNatives();
});
}
12 changes: 7 additions & 5 deletions android/src/main/cpp/OscillatorNode.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
#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){}
: javaObject_(make_global(jThis)), jsContext_(jsContext){}

jsi::Object OscillatorNode::createOscillatorNodeHostObject() {
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext);
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext_);
auto hostObject = std::make_shared<OscillatorNodeHostObject>(this);
return jsi::Object::createFromHostObject(*runtime, hostObject);
}
Expand Down Expand Up @@ -45,4 +42,9 @@ namespace audiocontext {
static const auto method = javaClassStatic()->getMethod<jdouble()>("getDetune");
return method(javaObject_.get());
}

void OscillatorNode::connect(const AudioDestinationNode &destination) {
const auto method = javaClassLocal()->getMethod<void(AudioDestinationNode::javaobject)>("connect");
method(javaObject_.get(), destination.javaObject_.get());
}
} // namespace audiocontext
6 changes: 5 additions & 1 deletion android/src/main/cpp/OscillatorNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include "OscillatorNodeHostObject.h"
#include "AudioDestinationNode.h"

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class AudioDestinationNode;

class OscillatorNode : public jni::HybridClass<OscillatorNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/oscillator/OscillatorNode;";
Expand All @@ -32,14 +35,15 @@ namespace audiocontext {
void setDetune(jdouble detune);
jdouble getFrequency();
jdouble getDetune();
void connect(const AudioDestinationNode &destination);

jsi::Object createOscillatorNodeHostObject();

private:
friend HybridBase;

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

explicit OscillatorNode(jni::alias_ref<OscillatorNode::jhybridobject>& jThis, jlong jsContext);
};
Expand Down
15 changes: 4 additions & 11 deletions android/src/main/java/com/audiocontext/context/AudioContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ 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>()
override val sampleRate: Int = 44100
override val destination: AudioDestinationNode = AudioDestinationNode(this, reactContext)
get() = field

private val mHybridData: HybridData?;

Expand All @@ -27,14 +27,7 @@ class AudioContext(private val reactContext: ReactApplicationContext) : BaseAudi

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
return OscillatorNode(this, reactContext)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import com.facebook.jni.HybridData
interface BaseAudioContext {
val sampleRate: Int
val destination: AudioDestinationNode
val sources: List<AudioNode>

abstract fun createOscillator(): OscillatorNode
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,28 @@ package com.audiocontext.nodes

import android.media.AudioTrack
import com.audiocontext.context.BaseAudioContext
import com.facebook.jni.HybridData
import com.facebook.react.bridge.ReactApplicationContext


class AudioDestinationNode(context: BaseAudioContext): AudioNode(context) {
class AudioDestinationNode(context: BaseAudioContext, reactContext: ReactApplicationContext): AudioNode(context) {
override val numberOfInputs = 1
override val numberOfOutputs = 0

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?

override fun process(buffer: ShortArray, audioTrack: AudioTrack) {
audioTrack.write(buffer, 0, buffer.size)
}
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/java/com/audiocontext/nodes/AudioNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ abstract class AudioNode(val context: BaseAudioContext) {
abstract val numberOfOutputs: Int;
private val connectedNodes = mutableListOf<AudioNode>()

fun connect(destination: AudioNode) {
fun connect(destination: AudioDestinationNode) {
if(this.numberOfOutputs > 0) {
connectedNodes.add(destination)
}
Expand Down
Loading

0 comments on commit eb97dff

Please sign in to comment.