async callback using libuv not working

226 views
Skip to first unread message

shah...@essential.com

unread,
May 25, 2017, 1:07:47 AM5/25/17
to nodejs
Hello everyone,

I have a node js service that calls into a native C library. The native library, fire events repeatedly and continuously. These events are delivered to a C callback function. My goal is to call a Javascript callback from this native C callback.

Based on my reading, I am using  uv_async_init and uv_async_send to accomplish this goal.

The problem I am encountering is that my native C callback function gets called many times and in there uv_async_send is called many times, but the function passed to uv_async_init is called only once and only when my program exits.

Here is my C code:

=====================================================
#include "jsaudio.h"
#include <iostream>

using namespace v8;

static void recordAudioCallback(int index);
void asyncmsg(uv_async_t* handle);
Callback* cbPeriodic;
uv_async_t async;
uv_loop_t* loop;

NAN_METHOD(createEngine) {
    std::cout << "==> createEngine\n" ;
}

void createAudioRecorder(const Nan::FunctionCallbackInfo<v8::Value>& info) {
    std::cout << "==> createAudioRecorder\n";
}

void startRecording(const Nan::FunctionCallbackInfo<v8::Value>& info) {
    std::cout << "==> startRecording\n";
    cbPeriodic = new Callback(info[0].As<Function>());
    loop = uv_default_loop();
    uv_async_init(loop, &async, asyncmsg);
}

void asyncmsg(uv_async_t* handle) {
  std::cout << "==> asyncmsg \n";
  Nan::HandleScope scope;
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  Local<Value> argv[] = { v8::String::NewFromUtf8(isolate, "Hello world") };
  cbPeriodic->Call(1, argv);
}

/* This my callback that gets called many times, by a native library(/
static void recordAudioCallback(int index) {
  std::cout << "==> recordAudioCallback " << index << "\n";
  uv_async_send(&async);
}
======================================================

Here is my test node.js code that calls the above native code

const jsAudio = new JsAudio({sampleRate: 48000, bufferSize: 8192})

function Test () {
  jsAudio.createEngine();

  jsAudio.createAudioRecorder();

  jsAudio.startRecording(function(error, result) {
    if (error) {
      console.log('startRecording failed: ' + error);
    } else {
      console.log('startRecording result: ' + result);
    }
  });
}

Test();

var waitTill = new Date(new Date().getTime() + 3 * 1000);
while(waitTill > new Date()){}

jsAudio.shutdown();

console.log('program exit...');

==========================================================


Here is the out:


==> createEngine
==> createAudioRecorder
==> startRecording
==> recordAudioCallback 0
==> recordAudioCallback 1
==> recordAudioCallback 0
==> recordAudioCallback 1
==> recordAudioCallback 0
==> shutdown
program exit...
==> asyncmsg 
startRecording failed: Hello world

===========================================================

Why asyncmsg is called only once! even though recordAudioCallback is called several times! Any why is it called after program exits!

Any help is appreciated.

Regards, Shahriar

Ben Noordhuis

unread,
May 26, 2017, 12:51:33 PM5/26/17
to nod...@googlegroups.com
It's right there in the documentation for uv_async_send():

libuv will coalesce calls to :c:func:`uv_async_send`, that is, not
every call to it will
yield an execution of the callback. For example: if
:c:func:`uv_async_send` is called 5
times in a row before the callback is called, the callback will
only be called once. If
:c:func:`uv_async_send` is called again after the callback was
called, it will be called
again.

shah...@essential.com

unread,
May 26, 2017, 6:49:20 PM5/26/17
to nodejs
Hi,

The problem was these two lines

var waitTill = new Date(new Date().getTime() + 3 * 1000);
while(waitTill > new Date()){}

This loop never allows the javascript main loop to run. I replaced it with a setTimeout and it is working.

Thanks!
Reply all
Reply to author
Forward
0 new messages