diff --git a/js/index.js b/js/index.js index 71e5595..3521a89 100644 --- a/js/index.js +++ b/js/index.js @@ -2,17 +2,17 @@ const addon = require('../build/libjack2.node'); - +const snooze = ms => new Promise(resolve => setTimeout(resolve, ms)); var time = 0 -async function process_callback(nframes, out1, out2) { - console.log("time" + time) +async function process_callback(time_c, nframes, out1, out2) { + console.log("time js: " + time-time_c) f = 440.0; sr = 44000; - + for (var i=0; i Jack2_c::JackPort* @@frame = OutputFrame.new - @time = 0 - def initialize status = Jack2_c::JackStatus::JackFailure @client = Jack2_c.jack_client_open("testclient", Jack2_c::JackOptions::JackNullOption, pointerof(status)) || @@ -46,15 +44,6 @@ module Jack2 @ports[name] = port end - def process(nframes, &block : (OutputFrame -> Void)) - @@frame.nframes = nframes - @@frame.out1 = Jack2_c.jack_port_get_buffer(@ports["out1"], nframes).as(Float32*) - @@frame.out2 = Jack2_c.jack_port_get_buffer(@ports["out2"], nframes).as(Float32*) - - block.call(@@frame) - return 0 - end - def connect(p1, p2) case Jack2_c.jack_connect(@client, p1, p2) when 0 @@ -65,7 +54,13 @@ module Jack2 def register_process_callback(&block : (OutputFrame -> Void)) closure = ->(nframes : Jack2_c::JackNframesT, data : Void*) { - process(nframes, &block) + puts "time from crystal: #{@@frame.time}" + @@frame.nframes = nframes + @@frame.time = @@frame.time + nframes + @@frame.out1 = Jack2_c.jack_port_get_buffer(@ports["out1"], nframes).as(Float32*) + @@frame.out2 = Jack2_c.jack_port_get_buffer(@ports["out2"], nframes).as(Float32*) + + block.call(@@frame) } # Make sure garbagem collector is not running @@ -73,12 +68,16 @@ module Jack2 @@closure_callback = Box.box(closure) Jack2_c.jack_set_process_callback(@client, ->(nframes : Jack2_c::JackNframesT, data : Void*) { + # Make sure GC is not running within another thread + GC.disable begin callback = Box(typeof(closure)).unbox(data) callback.call(nframes, data) rescue e puts "Exception within process callback: #{e}" return 1 + ensure + GC.enable end 0 }, @@closure_callback) diff --git a/src/libnode.cr b/src/libnode.cr index 68ff89d..ae0da24 100644 --- a/src/libnode.cr +++ b/src/libnode.cr @@ -89,16 +89,17 @@ module Node VERSION = "0.1.0" @@module = Node_c::NapiModule.new + @@client = ::Jack2::Client.new + @@call_js_cb : Pointer(Void)? def self.setup module_register_callback = ->(env : Node_c::NapiEnv, exports : Node_c::NapiValue) { # Avoid closure register_fn("setup", ->(env : Node_c::NapiEnv, info : Node_c::NapiCallbackInfo) { begin - client = ::Jack2::Client.new - client.register_port("out1", ::Jack2::Client::PORT_OUTPUT) - client.register_port("out2", ::Jack2::Client::PORT_OUTPUT) - puts client.ports + @@client.register_port("out1", ::Jack2::Client::PORT_OUTPUT) + @@client.register_port("out2", ::Jack2::Client::PORT_OUTPUT) + puts @@client.ports # Get arguments argc = 1_u64 @@ -110,45 +111,47 @@ module Node # Create threadsafe function call_js_cb = ->(env : Node_c::NapiEnv, cb : Node_c::NapiValue, ctx : Void*, frame : Void*) { + # This is called within a NodeJS UV Process context begin + GC.disable recv = uninitialized Node_c::NapiValue frame = Box(::Jack2::OutputFrame).unbox(frame) - typed_out1 = napi_typedarray(frame.out1, frame.nframes) - typed_out2 = napi_typedarray(frame.out2, frame.nframes) - - args = uninitialized Node_c::NapiValue[3] + args = uninitialized Node_c::NapiValue[4] nframes = frame.nframes - args[0] = napi_int(nframes) - args[1] = typed_out1 - args[2] = typed_out2 + args[0] = napi_int(frame.time) + args[1] = napi_int(frame.nframes) + args[2] = napi_typedarray(frame.out1, frame.nframes) + args[3] = napi_typedarray(frame.out2, frame.nframes) assert_napiok(Node_c.napi_get_undefined(env, pointerof(recv))) - assert_napiok(Node_c.napi_call_function(env, recv, cb, 3, args.to_unsafe, nil)) + assert_napiok(Node_c.napi_call_function(env, recv, cb, 4, args.to_unsafe, nil)) return # Void rescue e puts e.to_s + ensure + GC.enable end } + assert(call_js_cb.closure?) assert_napiok(Node_c.napi_create_threadsafe_function(env, callback_fn, nil, napi_string("callback for jack2 process"), 20, 1, nil, nil, nil, call_js_cb, pointerof(threadsafe_function))) # Callback definition (will call jack_process->jack_closure->closure below->call_js_cb->function) - client.register_process_callback do |frame| + + @@client.register_process_callback do |frame| + # This is jack_c process thread (GC is disabled already) assert_napiok(Node_c.napi_acquire_threadsafe_function(threadsafe_function)) assert_napiok(Node_c.napi_call_threadsafe_function(threadsafe_function, Box.box(frame), Node_c::NapiThreadsafeFunctionCallMode::NapiTsfnBlocking)) assert_napiok(Node_c.napi_release_threadsafe_function(threadsafe_function, Node_c::NapiThreadsafeFunctionReleaseMode::NapiTsfnRelease)) end - client.activate - client.connect("testclient:out1", "Live:in1") - client.connect("testclient:out2", "Live:in2") - puts client.ports - - ports = client.ports + @@client.activate + @@client.connect("testclient:out1", "Live:in1") + @@client.connect("testclient:out2", "Live:in2") - return napi_array(ports) + return napi_array(@@client.ports) rescue e napi_throw("Exception from Crystal: #{e.to_s}") end diff --git a/src/tools.cr b/src/tools.cr index c79a6d9..362b667 100644 --- a/src/tools.cr +++ b/src/tools.cr @@ -12,3 +12,7 @@ end macro log_debug(str) end + +macro assert(eval) + raise "Assert failed: {{eval}}" if {{eval}} +end