Calling callback inside callback in native Node - javascript

I'm a node & C++ newbie so be clement.
I'm writing a native node addon.
My addon start a webcam streaming (using UVC lib) and I want every frame to be available to node.
My CC addon do something like
uvc_start_streaming(devh, &ctrl, frameProcess, (void *) &args, 0)
Where:
devh: is the UVC device
ctrl: are device config
frameProcess: is my function callback to be called at every new frame
args: are arguments from javascript function.
The c++ callback is called every new frame and I want to simple print something like "new frame received" so my C++ is like:
void frameProcess(uvc_frame_t *frame, void *ptr) {
const FunctionCallbackInfo<Value> args = *((const FunctionCallbackInfo<Value>*)(ptr));
Isolate* isolate = args.GetIsolate();
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "new frame received") };
cb->Call(Null(isolate), argc, argv);
}
void testStreaming (const FunctionCallbackInfo<Value>& args) {
...
res = uvc_start_streaming(devh, &ctrl, frameProcess, (void *) &args, 0);
puts("Streaming...");
Sleep(10000); /* stream for 10 seconds */
uvc_stop_streaming(devh);
puts("Done streaming.");
...
}
...
NODE_SET_METHOD(exports, "testStreaming", testDevice);
My js is something like:
'use strict';
var uvc = require('../build/Release/binding')
uvc.testStreaming(
function (x) {
console.log(x)
}
)
The problem is that node exit without any message or error when program reach cb->Call.
If I comment cb->Call row the program run for 10 seconds (continuosly calling the ) as programmed and then exit.
But if I uncomment cb->Call the program exit immediatly.

Your frameProcess() function should call v8::Function callback in the Node.js thread, see https://stackoverflow.com/a/28116160/1355844

Related

NAPI Call Emit inside a c++ Lambda fucnction

I'm working on a N-API addon to capture video frame using windows graphic capture API , extract frame bytes and send it back to JavaScript.
I have tried the event emitter but I can't get the data.
Here is my C++ code:
#include <napi.h>
// my other include
Napi::Value startCapture(const Napi::CallbackInfo &info){
Napi::Env env = info.Env();
Napi::Function emit = info[0].As<Napi::Function>();
emit.Call({Napi::String::New(env, "start")});
auto framePool = winrt::Direct3D11CaptureFramePool::Create(
device, //d3d device
winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized,
2,
itemSize);
// capture session
auto session = framePool.CreateCaptureSession(item);
// Lambda Function
framePool.FrameArrived([session, d3dDevice, d3dContext, &emit, &env](auto &framePool, auto &) {
auto frame = framePool.TryGetNextFrame();
auto frameTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
// Extraction the byte and so on ...
emit.Call({Napi::String::New(env, "data"), Napi::String::New(env, "data ...")});
}
session.StartCapture();
emit.Call({Napi::String::New(env, "end")});
return Napi::String::New(env, "OK");
}
here my JavaScript code calling the start capture function
<!-- language-all: js -->
const EventEmitter = require('events').EventEmitter
const addon = require('./build/myaddon.node')
const emitter = new EventEmitter()
emitter.on('start', () => {
console.log('Start Recording ...')
})
emitter.on('data', (evt) => {
console.log(evt);
})
emitter.on('end', () => {
console.log('Stop Recording ...')
})
addon.startCapture(emitter.emit.bind(emitter))
Normally my output should be an infinite loop of data messages until I stop it
Start Recording …
data data
.
.
.
data
After looking to the lambda function framePool.FrameArrived it seems that it's running on a different thread than the startCapture function if I understand the lambda function concept correctly, I just wanna to found a way on how I can stream those messages to JavaScript using event Emitter or any other recommendation is well welcoming.
//instead of
Napi::Env env = info.Env();
Napi::Function emit = info[0].As<Napi::Function>();
emit.Call({Napi::String::New(env, "data"), Napi::String::New(env, "data ...")});
//try
Napi::Env env = info.Env();
Napi::Function fn = info[0].As<Napi::Function>();
emit = Persistent(fn);
emit.SuppressDestruct();
emit.Value().Call({Napi::String::New(env, "data"), Napi::String::New(env, "data ...")});

The `Module` variable's mechanism in Emscripten while compiling Pthread to workers

I am confused by the Module variable in Emsripten while compiling Pthread to Web Worker + Wasm
There is a simple Pthread code which just adds 1 in the shared variable sum in each thread. (simple.c is attached in the end.)
We can use the command to compile the Pthread code:
$ emcc simple.c -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 -o simple.html
Emscripten will generate simple.html, simple.js, simple.worker.js, and simple.wasm.
In simple.worker.js, there is a snippet:
// simple.worker.js
var Module = {};
// ...
Module['instantiateWasm'] = function(info, receiveInstance) {
// Instantiate from the module posted from the main thread.
// We can just use sync instantiation in the worker.
var instance = new WebAssembly.Instance(Module['wasmModule'], info);
// We don't need the module anymore; new threads will be spawned from the main thread.
Module['wasmModule'] = null;
receiveInstance(instance); // The second 'module' parameter is intentionally null here, we don't need to keep a ref to the Module object from here.
return instance.exports;
};
Note that it declares var Module = {} in the worker, and defines Module['instantiateWasm'].
However, Module['instantiateWasm'] is only called by simple.js, which the code snippet looks like:
//simple.js
var Module = {}
// ...
if (Module['instantiateWasm']) {
try {
var exports = Module['instantiateWasm'](info, receiveInstance);
return exports;
} catch(e) {
err('Module.instantiateWasm callback failed with error: ' + e);
return false;
}
}
// ...
As we can see, simple.js also declares var Module = {} too.
AFAIK, VAR global variables cannot be accessed across the main thread and its worker. I don't understand why simple.js can call Module['instantiateWasm'] as the Module of simple.js and the Module of simple.worker.js should be not the same thing.
Pthread Code:
// simple.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUMTHRDS 4
#define MAGNIFICATION 1e9
typedef struct
{
int thread_id;
double *sum;
} Arg;
pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;
void *count_pi(void *arg)
{
Arg *data = (Arg *)arg;
int thread_id = data->thread_id;
double *sum = data->sum;
pthread_mutex_lock(&mutexsum);
*sum += 1;
pthread_mutex_unlock(&mutexsum);
printf("Thread %d: sum=%f\n", thread_id, *sum);
pthread_exit((void *)0);
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&mutexsum, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
double *sum = malloc(sizeof(*sum));
*sum = 0;
Arg arg[NUMTHRDS];
for (int i = 0; i < NUMTHRDS; i++)
{
arg[i].thread_id = i;
arg[i].sum = sum;
pthread_create(&callThd[i], &attr, count_pi, (void *)&arg[i]);
}
pthread_attr_destroy(&attr);
void *status;
for (int i = 0; i < NUMTHRDS; i++)
{
pthread_join(callThd[i], &status);
}
printf("Final Sum = %f \n", *sum);
free(sum);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
}
A main program sends self to worker.
// simple.js
// Ask the new worker to load up the Emscripten-compiled page. This is a heavy operation.
worker.postMessage({
'cmd': 'load',
// If the application main .js file was loaded from a Blob, then it is not possible
// to access the URL of the current script that could be passed to a Web Worker so that
// it could load up the same file. In that case, developer must either deliver the Blob
// object in Module['mainScriptUrlOrBlob'], or a URL to it, so that pthread Workers can
// independently load up the same main application file.
'urlOrBlob': Module['mainScriptUrlOrBlob'] || _scriptDir,
'wasmMemory': wasmMemory,
'wasmModule': wasmModule,
'DYNAMIC_BASE': DYNAMIC_BASE,
'DYNAMICTOP_PTR': DYNAMICTOP_PTR
});
and worker import that.
// simple.worker.js
if (typeof e.data.urlOrBlob === 'string') {
importScripts(e.data.urlOrBlob);
} else {
var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
importScripts(objectUrl);
URL.revokeObjectURL(objectUrl);
}
Therefore Module isn't shared, but it is initialized independently.

How do I call a Python function from Node.js?

I'm working on making a Homebridge plugin for a project. Homebridge is a Node.js server which I have running on a Raspberry Pi which emulates an Apple HomeKit Bridge.
Using this link, I was able to execute Python code from the following Node.js code:
var Service, Characteristic;
var spawn = require('child_process').spawn;
var py = spawn('python', ['/home/pi/Desktop/RFbulb/nRF24L01PLUS.py']);
var data = [10,10,10];
var dataString = '';
var RFstatus = true;
module.exports = function(homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory("homebridge-RFbulb", "RFbulb", RFbulbAccessory);
}
function RFbulbAccessory(log, config) {
this.log = log;
this.config = config;
this.name = config["name"];
this.address = config["address"];
this.service = new Service.Lightbulb(this.name);
this.service
.getCharacteristic(Characteristic.On)
.on('get', this.getOn.bind(this))
.on('set', this.setOn.bind(this));
}
RFbulbAccessory.prototype.setOn = function(on, callback) { // This is the function throwing the error
var state = on ? "on": "off";
if (state == "on") {
data = [1,parseInt(this.address, 10),100];
dataString = '';
py.stdout.on('data', function(data) {
dataString += data.toString();
});
py.stdout.on('end', function() {
console.log(dataString);
});
py.stdin.write(JSON.stringify(data));
py.stdin.end();
RFstatus = true;
}
callback(null);
}
RFbulbAccessory.prototype.getServices = function() {
return [this.service];
}
Interestingly enough, when I activate the setOn function the first time (for example, to turn the device on) it works fine, but when I activate the setOn function a second time (to turn the device off) I get the following errors and the server exits:
events.js:141
throw er; // Unhandled 'error' event
^
Error: write after end
at writeAfterEnd (_stream_writable.js:166:12)
at Socket.Writable.write (_stream_writable.js:211:5)
at Socket.write (net.js:642:40)
at RFbulbAccessory.setOn (/usr/lib/node_modules/homebridge-RFbulb/index.js:47:12)
at emitThree (events.js:97:13)
at emit (events.js:175:7)
at Characteristic.setValue (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Characteristic.js:155:10)
at Bridge.<anonymous> (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Accessory.js:710:22)
at Array.forEach (native)
at Bridge.Accessory._handleSetCharacteristics (/usr/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/Accessory.js:655:8)
What could be causing this error? Especially since the function appears to work fine for a single use.
You're getting that error because you're closing the input stream:
py.stdin.end();
After a stream has been closed, you can no longer write to it like you are here:
py.stdin.write(JSON.stringify(data));
If the Python program you're running accepts multiple commands over STDIN then simply remove the py.stdin.end() line.
However, it's likely that your Python program runs once then completes. If that's the case, you will need to respawn the process every time you want the program to run.
if (state === "on") {
py = spawn('python', ['/home/pi/Desktop/RFbulb/nRF24L01PLUS.py']);
...
}

JavaScriptCore console.log

I've put together a very simple program that uses JavaScriptCore to evaluate JS:
#import <CoreFoundation/CoreFoundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
int main(int argc, const char * argv[])
{
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
FILE *f = fopen(argv[1],"r");
char * buffer = malloc(10000000);
fread(buffer,1,10000000,f);
CFStringRef strs = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingASCII);
JSStringRef jsstr = JSStringCreateWithCFString(strs);
JSValueRef result = JSEvaluateScript(ctx, jsstr, NULL, NULL, 0, NULL);
double res = JSValueToNumber(ctx, result, NULL);
JSGlobalContextRelease(ctx);
printf("%lf\n", res);
return 0;
}
The idea here is that the last value is expected to be a Number, and that value is printed. This works for valid javascript code, such as
var square = function(x) { return x*x; }; square(4)
However, if the code tries to perform a console.log, the program segfaults. Is there a log function available in JSC or do I have to roll my own?
You do have to provide your own console log if using the JavaScriptCore framework from Mac or IOS.
Here is some code that worked for me (sorry it is Objective-C rather than standard C as per your code above):
JSContext *javascriptContext = [[JSContext alloc] init];
javascriptContext[#"consoleLog"] = ^(NSString *message) {
NSLog(#"Javascript log: %#",message);
};
Then you use it from Javascript by:
consoleLog("My debug message");
Note that I have tried to define a vararg version (log taking multiple parameters) but I couldn't get this to work correctly across the framework api.
Note that this solution uses features introduced with the new Objective-C API for the JavaScriptCore.framework introduced at the same time as IOS 7. If you are looking for an intro to this well-integrated bridge between Objective-C and Javascript, check out the 2013 WWDC introduction "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/videos/wwdc/2013/?id=615
Update to answer:
For those of you wanting to maximise your javascript code reuse without refactoring, I've managed to get a version working that declares a log of the form console.log() :
JSContext *javascriptContext = [[JSContext alloc] init];
[javascriptContext evaluateScript:#"var console = {}"];
javascriptContext[#"console"][#"log"] = ^(NSString *message) {
NSLog(#"Javascript log: %#",message);
};
Then you use it from Javascript by:
console.log("My debug message");
Swift 3.0
let javascriptContext = JSContext()
javascriptContext?.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: #convention(block) (String) -> Void = { message in
print("console.log: " + message)
}
javascriptContext?.setObject(unsafeBitCast(consoleLog, to: AnyObject.self), forKeyedSubscript: "_consoleLog" as (NSCopying & NSObjectProtocol)!)
Swift 2.1
let javascriptContext = JSContext()
javascriptContext.evaluateScript("var console = { log: function(message) { _consoleLog(message) } }")
let consoleLog: #convention(block) String -> Void = { message in
print("console.log: " + message)
}
javascriptContext.setObject(unsafeBitCast(consoleLog, AnyObject.self), forKeyedSubscript: "_consoleLog")
Then you use it from Javascript by:
console.log("My debug message");
self.jsContext = JSContext()
self.jsContext.evaluateScript(...)
let logFunction: #convention(block) (String) -> Void = { (string: String) in
print(string)
}
self.jsContext.setObject(logFunction, forKeyedSubscript: "consoleLog" as NSCopying & NSObjectProtocol)
You can debug JS file attached to context in Safari.
Steps:
1) Start Safari
2) In Safari, enable the Develop menu by going to "Preferences" -> "Advanced" -> "Show Develop menu in menu bar"
3) Go to Develop menu -> "Simulator" or name of your computer -> select "Automatically show web inspector for JSContexts" and "Automatically pause connecting to JSContexts"
4) Re-run your project and Safari should auto-show the web inspector
Swift 5.0
The other suggestions didn't work for me, so I found a web post that explains how to do it now.Essentially
let logFunction: #convention(block) (String) -> Void = { string in
print("JS_Console:", string)
}
if let console = context.objectForKeyedSubscript("console") {
console.setObject(logFunction, forKeyedSubscript: "log") // works for me
// is this needed? "console.setObject(unsafeBitCast(logFunction, to: AnyObject.self), forKeyedSubscript: "log")
}
log.console is variadic, but I could find no way to utilize it even though the link above suggests it's possible. What I did discover though is that you can use JavaScript interpolation to get values, for example:
console.log(`getCombinedFrameYaw: ${frameYaw} rot=${pathRotation}`)

Writing ASYNC CPP nodejs (0.5.3+) modules

I´m searching for a way to build c++ modules for NodeJs with the current release (0.5.9).
By using the following tutorial and abstracting from nodes node_file.cc I was able to build a module by my self for node 0.5.3.
https://github.com/jedp/node-rot13/blob/master/src/rot13.cpp
But with node 0.5.4 some of the API´s must have changed because because I´m no longer able to warp functions with eio_* anymore.
Looking at node_file.cc I discovered that the eio_* wrapping is replaced by new ReqWrap classes.
For Example in this macro: https://gist.github.com/1303926
No I wonder what's the best way of writing async extensions?
Basically looking at the crypto node module solved my problem this module was not poluted with macros like the file module. I came up with a simple async module that calculates the sum of two integers:
#include <v8.h>
#include <node.h>
#include <stdlib.h>
#include <errno.h>
using namespace node;
using namespace v8;
struct Test_req
{
ssize_t result;
ssize_t int1;
ssize_t int2;
Persistent<Function> callback;
};
void TestWorker(uv_work_t* req)
{
Test_req* request = (Test_req*)req->data;
request->result = request->int1 + request->int2;
}
void TestAfter(uv_work_t* req)
{
HandleScope scope;
Test_req* request = (Test_req*)req->data;
delete req;
Handle<Value> argv[2];
// XXX: Error handling
argv[0] = Undefined();
argv[1] = Integer::New(request->result);
TryCatch try_catch;
request->callback->Call(Context::GetCurrent()->Global(), 2, argv);
if (try_catch.HasCaught())
{
FatalException(try_catch);
}
request->callback.Dispose();
delete request;
}
static Handle<Value> Test(const Arguments& args)
{
HandleScope scope;
if ( args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsNumber() )
{
return ThrowException(Exception::TypeError(String::New("Bad argument")));
}
ssize_t int1 ( args[0]->Int32Value() );
ssize_t int2 ( args[1]->Int32Value() );
if ( args[2]->IsFunction() )
{
Local<Function> callback = Local<Function>::Cast(args[2]);
Test_req* request = new Test_req;
request->callback = Persistent<Function>::New(callback);
request->int1 = int1;
request->int2 = int2;
uv_work_t* req = new uv_work_t();
req->data = request;
uv_queue_work(uv_default_loop(), req, TestWorker, TestAfter);
}
else
{
return ThrowException(Exception::TypeError(String::New("Callback missing")));
}
return Undefined();
}
extern "C"
{
static void init(Handle<Object> target)
{
HandleScope scope;
}
}
NODE_MODULE(node_AsyncTest, init);
On the node side you call the module like this:
var foo = process.binding('AsyncTest');
foo.Test(1,2,function(err,data){
console.log(err,data);
});
result:
undefined 3
Hope this is helpful ;)
Ps: Since the lack of node compiling extensions under windows. I´m building this directly into the core of the node windows port with the Visual Studio build solution.

Categories