diff --git a/bin/Makefile.am b/bin/Makefile.am
index bbe9d273e158ac60280bc5990c50412094a2a8c6..c833d0746a3a4e787c470b2ec7645da8fc535866 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -18,8 +18,10 @@ ringcli_CXXFLAGS = -I$(top_srcdir)/src \
 ringcli_LDADD = $(top_builddir)/src/libring.la
 endif
 
+SUBDIRS=
+
 if RING_DBUS
-SUBDIRS=dbus
+SUBDIRS+=dbus
 
 ringlib_PROGRAMS = dring
 
@@ -32,8 +34,12 @@ dring_CXXFLAGS= -I$(top_srcdir)/src ${DBUSCPP_CFLAGS} \
 dring_LDADD = dbus/libclient_dbus.la ${DBUSCPP_LIBS} $(top_builddir)/src/libring.la
 endif
 
+if RING_NODEJS
+SUBDIRS+=nodejs
+endif
+
 if RING_RESTCPP
-SUBDIRS=restcpp
+SUBDIRS+=restcpp
 
 sbin_PROGRAMS = restdring
 
diff --git a/bin/nodejs/Makefile.am b/bin/nodejs/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..bc18443eb5f502e447b1d0378ee7035babd4f5f2
--- /dev/null
+++ b/bin/nodejs/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/globals.mk
+
+BUILT_SOURCES= \
+	ring_wrapper.cpp \
+	build/Makefile \
+	build/Release/obj.target/dring.node
+
+ring_wrapper.cpp: nodejs_interface.i configurationmanager.i managerimpl.i
+	$(SWIG) -v -c++ -javascript -node -o ring_wrapper.cpp nodejs_interface.i
+
+build/Makefile: ring_wrapper.cpp binding.gyp
+	node-gyp configure
+
+build/Release/obj.target/dring.node: build/Makefile ring_wrapper.cpp callback.h
+	node-gyp build
+
+CLEANFILES= \
+	$(BUILT_SOURCES) \
+	build/Release/dring.node
diff --git a/bin/nodejs/binding.gyp b/bin/nodejs/binding.gyp
new file mode 100644
index 0000000000000000000000000000000000000000..dcdb13ebc411ed51fccb53a97865d64396ad5a9f
--- /dev/null
+++ b/bin/nodejs/binding.gyp
@@ -0,0 +1,12 @@
+{
+  "targets": [
+    {
+      "target_name": "dring",
+      "sources": [ "ring_wrapper.cpp" ],
+      'include_dirs': ['../../src/'],
+      'libraries': ['-L<(module_root_dir)/../../src/.libs/', '-lring'],
+      'cflags!': [ '-fno-exceptions' ],
+      'cflags_cc!': [ '-fno-exceptions' ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/bin/nodejs/callback.h b/bin/nodejs/callback.h
new file mode 100755
index 0000000000000000000000000000000000000000..823f908ab322b72d577f1e70c52e22100ae52fbe
--- /dev/null
+++ b/bin/nodejs/callback.h
@@ -0,0 +1,344 @@
+#pragma once
+
+#define V8_STRING_NEW(str) v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), str.data(), v8::String::kNormalString, str.size())
+
+#include <uv.h>
+#include <queue>
+#include <functional>
+#include <mutex>
+
+using namespace v8;
+
+Persistent<Function> accountsChangedCb;
+Persistent<Function> registrationStateChangedCb;
+Persistent<Function> volatileDetailsChangedCb;
+Persistent<Function> incomingAccountMessageCb;
+Persistent<Function> accountMessageStatusChangedCb;
+Persistent<Function> incomingTrustRequestCb;
+Persistent<Function> contactAddedCb;
+Persistent<Function> contactRemovedCb;
+Persistent<Function> exportOnRingEndedCb;
+Persistent<Function> nameRegistrationEndedCb;
+Persistent<Function> knownDevicesChangedCb;
+Persistent<Function> registeredNameFoundCb;
+Persistent<Function> callStateChangedCb;
+Persistent<Function> incomingMessageCb;
+Persistent<Function> incomingCallCb;
+Persistent<Function> newCallCreatedCb;
+
+std::queue<std::function<void() >> pendingSignals;
+std::mutex pendingSignalsLock;
+
+uv_async_t signalAsync;
+
+Persistent<Function>* getPresistentCb(const std::string &signal) {
+    if (signal == "AccountsChanged")
+        return &accountsChangedCb;
+    else if (signal == "RegistrationStateChanged")
+        return &registrationStateChangedCb;
+    else if (signal == "VolatileDetailsChanged")
+        return &volatileDetailsChangedCb;
+    else if (signal == "IncomingAccountMessage")
+        return &incomingAccountMessageCb;
+    else if (signal == "AccountMessageStatusChanged")
+        return &accountMessageStatusChangedCb;
+    else if (signal == "IncomingTrustRequest")
+        return &incomingTrustRequestCb;
+    else if (signal == "ContactAdded")
+        return &contactAddedCb;
+    else if (signal == "ContactRemoved")
+        return &contactRemovedCb;
+    else if (signal == "ExportOnRingEnded")
+        return &exportOnRingEndedCb;
+    else if (signal == "NameRegistrationEnded")
+        return &nameRegistrationEndedCb;
+    else if (signal == "KnownDevicesChanged")
+        return &knownDevicesChangedCb;
+    else if (signal == "RegisteredNameFound")
+        return &registeredNameFoundCb;
+    else if (signal == "CallStateChanged")
+        return &callStateChangedCb;
+    else if (signal == "IncomingMessage")
+        return &incomingMessageCb;
+    else if (signal == "IncomingCall")
+        return &incomingCallCb;
+    else if (signal == "NewCallCreated")
+        return &newCallCreatedCb;
+    else return nullptr;
+}
+
+void intVectToJsArray(const std::vector<uint8_t>& intVect, const Local<Array>& jsArray) {
+    for (unsigned int i = 0; i < intVect.size(); i++)
+        jsArray->Set(SWIGV8_INTEGER_NEW_UNS(i), SWIGV8_INTEGER_NEW(intVect[i]));
+}
+
+void stringMapToJsMap(const std::map<std::string, std::string>& strmap, const Local<Object> &jsMap) {
+    for (auto& kvpair : strmap)
+        jsMap->Set(V8_STRING_NEW(std::get<0>(kvpair)), V8_STRING_NEW(std::get<1>(kvpair)));
+}
+
+void setCallback(const std::string& signal, Local<Function>& func) {
+    if (auto* presistentCb = getPresistentCb(signal)) {
+        if (func->IsObject() && func->IsFunction()) {
+            presistentCb->Reset(Isolate::GetCurrent(), func);
+        } else {
+            presistentCb->Reset();
+        }
+    } else {
+        printf("No Signal Associated with Event \'%s\'\n", signal.c_str());
+    }
+}
+
+void parseCbMap(const Local<Value>& callbackMap) {
+    Local<Object> cbAssocArray = callbackMap->ToObject();
+    Local<Array> props = cbAssocArray->GetOwnPropertyNames();
+    for (uint32_t i = 0; i < props->Length(); ++i) {
+        const Local<Value> key_local = props->Get(i);
+        std::string key = *String::Utf8Value(key_local);
+        Handle<Object> buffer = cbAssocArray->Get(V8_STRING_NEW(key))->ToObject();
+        Local<Function> func = Local<Function>::Cast(buffer);
+        setCallback(key, func);
+    }
+}
+
+void handlePendingSignals(uv_async_t* async_data) {
+    SWIGV8_HANDLESCOPE();
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    while (not pendingSignals.empty()) {
+        pendingSignals.front()();
+        pendingSignals.pop();
+    }
+}
+
+void registrationStateChanged(const std::string& account_id, const std::string& state, int code, const std::string& detail_str) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, state, code, detail_str]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), registrationStateChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(state), SWIGV8_INTEGER_NEW(code), V8_STRING_NEW(detail_str)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 4, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void volatileDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, details]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), volatileDetailsChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Object> jsMap = SWIGV8_OBJECT_NEW();
+            stringMapToJsMap(details, jsMap);
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), jsMap};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 2, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void accountsChanged() {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), accountsChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 0, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void contactAdded(const std::string& account_id, const std::string& uri, bool confirmed) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, uri, confirmed]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), contactAddedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(uri), SWIGV8_BOOLEAN_NEW(confirmed)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void contactRemoved(const std::string& account_id, const std::string& uri, bool banned) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, uri, banned]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), contactRemovedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(uri), SWIGV8_BOOLEAN_NEW(banned)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void exportOnRingEnded(const std::string& account_id, int state, const std::string& pin) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, state, pin]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), exportOnRingEndedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), SWIGV8_INTEGER_NEW(state), V8_STRING_NEW(pin)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void nameRegistrationEnded(const std::string& account_id, int state, const std::string& name) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, state, name]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), nameRegistrationEndedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), SWIGV8_INTEGER_NEW(state), V8_STRING_NEW(name)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void registeredNameFound(const std::string& account_id, int state, const std::string& address, const std::string& name) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, state, address, name]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), registeredNameFoundCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), SWIGV8_INTEGER_NEW(state), V8_STRING_NEW(address), V8_STRING_NEW(name)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 4, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void accountMessageStatusChanged(const std::string& account_id, uint64_t message_id, const std::string& to, int state) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, message_id, to, state]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), accountMessageStatusChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), SWIGV8_INTEGER_NEW_UNS(message_id), V8_STRING_NEW(to), SWIGV8_INTEGER_NEW(state)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 4, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void incomingAccountMessage(const std::string& account_id, const std::string& from, const std::map<std::string, std::string>& payloads) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, from, payloads]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), incomingAccountMessageCb);
+        if (!func.IsEmpty()) {
+            Local<Object> jsMap = SWIGV8_OBJECT_NEW();
+            stringMapToJsMap(payloads, jsMap);
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(from), jsMap};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void knownDevicesChanged(const std::string& account_id, const std::map<std::string, std::string>& devices) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, devices]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), knownDevicesChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Object> jsMap = SWIGV8_OBJECT_NEW();
+            stringMapToJsMap(devices, jsMap);
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), jsMap};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 2, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void incomingTrustRequest(const std::string& account_id, const std::string& from, const std::vector<uint8_t>& payload, time_t received) {
+
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, from, payload, received]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), incomingTrustRequestCb);
+        if (!func.IsEmpty()) {
+            Local<Array> jsArray = SWIGV8_ARRAY_NEW();
+            intVectToJsArray(payload, jsArray);
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(from), jsArray, SWIGV8_NUMBER_NEW(received)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 4, callback_args);
+        }
+    });
+    uv_async_send(&signalAsync);
+}
+
+void callStateChanged(const std::string& call_id, const std::string& state, int detail_code) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([call_id, state, detail_code]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), callStateChangedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(call_id), V8_STRING_NEW(state), SWIGV8_INTEGER_NEW(detail_code)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void incomingMessage(const std::string& id, const std::string& from, const std::map<std::string, std::string>& messages) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([id, from, messages]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), incomingMessageCb);
+        if (!func.IsEmpty()) {
+            Local<Object> jsMap = SWIGV8_OBJECT_NEW();
+            stringMapToJsMap(messages, jsMap);
+            Local<Value> callback_args[] = {V8_STRING_NEW(id), V8_STRING_NEW(from), jsMap};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 4, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+
+void incomingCall(const std::string& account_id, const std::string& call_id, const std::string& from) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, call_id, from]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), incomingCallCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(call_id), V8_STRING_NEW(from)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
+void newCallCreated(const std::string& account_id, const std::string& call_id, const std::string& to_uri) {
+
+    std::lock_guard<std::mutex> lock(pendingSignalsLock);
+    pendingSignals.emplace([account_id, call_id, to_uri]() {
+        Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), newCallCreatedCb);
+        if (!func.IsEmpty()) {
+            Local<Value> callback_args[] = {V8_STRING_NEW(account_id), V8_STRING_NEW(call_id), V8_STRING_NEW(to_uri)};
+            func->Call(SWIGV8_CURRENT_CONTEXT()->Global(), 3, callback_args);
+        }
+    });
+
+    uv_async_send(&signalAsync);
+}
\ No newline at end of file
diff --git a/bin/nodejs/callmanager.i b/bin/nodejs/callmanager.i
new file mode 100644
index 0000000000000000000000000000000000000000..39c1bf09df42bd23e6ab0a2b57cf8166377d8616
--- /dev/null
+++ b/bin/nodejs/callmanager.i
@@ -0,0 +1,137 @@
+/*
+ *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
+ *          Alexandre Lision <alexnadre.L@savoirfairelinux.com>
+ *          Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+%header %{
+
+#include "dring/dring.h"
+#include "dring/callmanager_interface.h"
+
+class Callback {
+public:
+    virtual ~Callback() {}
+    virtual void callStateChanged(const std::string& call_id, const std::string& state, int detail_code){}
+    virtual void transferFailed(void){}
+    virtual void transferSucceeded(void){}
+    virtual void recordPlaybackStopped(const std::string& path){}
+    virtual void voiceMailNotify(const std::string& call_id, int nd_msg){}
+    virtual void incomingMessage(const std::string& id, const std::string& from, const std::map<std::string, std::string>& messages){}
+    virtual void incomingCall(const std::string& account_id, const std::string& call_id, const std::string& from){}
+    virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){}
+    virtual void conferenceCreated(const std::string& conf_id){}
+    virtual void conferenceChanged(const std::string& conf_id, const std::string& state){}
+    virtual void conferenceRemoved(const std::string& conf_id){}
+    virtual void newCallCreated(const std::string& call_id, const std::string&, const std::string&){}
+    virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){}
+    virtual void conferenceRemove(const std::string& conf_id){}
+    virtual void newCall(const std::string& account_id, const std::string& call_id, const std::string& to){}
+    virtual void sipCallStateChange(const std::string& call_id, const std::string& state, int code){}
+    virtual void recordingStateChanged(const std::string& call_id, int code){}
+    virtual void recordStateChange(const std::string& call_id, int state){}
+    virtual void onRtcpReportReceived(const std::string& call_id, const std::map<std::string, int>& stats){}
+    virtual void peerHold(const std::string& call_id, bool holding){}
+};
+
+
+%}
+
+%feature("director") Callback;
+
+namespace DRing {
+
+/* Call related methods */
+std::string placeCall(const std::string& accountID, const std::string& to);
+
+bool refuse(const std::string& callID);
+bool accept(const std::string& callID);
+bool hangUp(const std::string& callID);
+bool hold(const std::string& callID);
+bool unhold(const std::string& callID);
+bool muteLocalMedia(const std::string& callid, const std::string& mediaType, bool mute);
+bool transfer(const std::string& callID, const std::string& to);
+bool attendedTransfer(const std::string& transferID, const std::string& targetID);
+std::map<std::string, std::string> getCallDetails(const std::string& callID);
+std::vector<std::string> getCallList();
+
+/* Conference related methods */
+void removeConference(const std::string& conference_id);
+bool joinParticipant(const std::string& sel_callID, const std::string& drag_callID);
+void createConfFromParticipantList(const std::vector<std::string>& participants);
+bool isConferenceParticipant(const std::string& call_id);
+bool addParticipant(const std::string& callID, const std::string& confID);
+bool addMainParticipant(const std::string& confID);
+bool detachParticipant(const std::string& callID);
+bool joinConference(const std::string& sel_confID, const std::string& drag_confID);
+bool hangUpConference(const std::string& confID);
+bool holdConference(const std::string& confID);
+bool unholdConference(const std::string& confID);
+std::vector<std::string> getConferenceList();
+std::vector<std::string> getParticipantList(const std::string& confID);
+std::vector<std::string> getDisplayNames(const std::string& confID);
+std::string getConferenceId(const std::string& callID);
+std::map<std::string, std::string> getConferenceDetails(const std::string& callID);
+
+/* File Playback methods */
+bool startRecordedFilePlayback(const std::string& filepath);
+void stopRecordedFilePlayback(const std::string& filepath);
+
+/* General audio methods */
+bool toggleRecording(const std::string& callID);
+/* DEPRECATED */
+void setRecording(const std::string& callID);
+
+void recordPlaybackSeek(double value);
+bool getIsRecording(const std::string& callID);
+std::string getCurrentAudioCodecName(const std::string& callID);
+void playDTMF(const std::string& key);
+void startTone(int32_t start, int32_t type);
+
+bool switchInput(const std::string& callID, const std::string& resource);
+
+/* Instant messaging */
+void sendTextMessage(const std::string& callID, const std::map<std::string, std::string>& messages, const std::string& from, const bool& isMixed);
+
+}
+
+class Callback {
+public:
+    virtual ~Callback() {}
+    virtual void callStateChanged(const std::string& call_id, const std::string& state, int detail_code){}
+    virtual void transferFailed(void){}
+    virtual void transferSucceeded(void){}
+    virtual void recordPlaybackStopped(const std::string& path){}
+    virtual void voiceMailNotify(const std::string& call_id, int nd_msg){}
+    virtual void incomingMessage(const std::string& id, const std::string& from, const std::map<std::string, std::string>& messages){}
+    virtual void incomingCall(const std::string& account_id, const std::string& call_id, const std::string& from){}
+    virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){}
+    virtual void conferenceCreated(const std::string& conf_id){}
+    virtual void conferenceChanged(const std::string& conf_id, const std::string& state){}
+    virtual void conferenceRemoved(const std::string& conf_id){}
+    virtual void newCallCreated(const std::string& call_id, const std::string&, const std::string&){}
+    virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){}
+    virtual void conferenceRemove(const std::string& conf_id){}
+    virtual void newCall(const std::string& account_id, const std::string& call_id, const std::string& to){}
+    virtual void sipCallStateChange(const std::string& call_id, const std::string& state, int code){}
+    virtual void recordingStateChanged(const std::string& call_id, int code){}
+    virtual void recordStateChange(const std::string& call_id, int state){}
+    virtual void onRtcpReportReceived(const std::string& call_id, const std::map<std::string, int>& stats){}
+    virtual void peerHold(const std::string& call_id, bool holding){}
+};
diff --git a/bin/nodejs/configurationmanager.i b/bin/nodejs/configurationmanager.i
new file mode 100644
index 0000000000000000000000000000000000000000..4124e9c0264a7ec62a47b759520a9852742a02b5
--- /dev/null
+++ b/bin/nodejs/configurationmanager.i
@@ -0,0 +1,226 @@
+/*
+ *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+%header %{
+#include "dring/dring.h"
+#include "dring/configurationmanager_interface.h"
+
+class ConfigurationCallback {
+public:
+    virtual ~ConfigurationCallback(){}
+    virtual void volumeChanged(const std::string& device, int value){}
+    virtual void accountsChanged(void){}
+    virtual void historyChanged(void){}
+    virtual void stunStatusFailure(const std::string& account_id){}
+    virtual void registrationStateChanged(const std::string& account_id, const std::string& state, int code, const std::string& detail_str){}
+    virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
+    virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
+    virtual void accountMessageStatusChanged(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/){}
+    virtual void knownDevicesChanged(const std::string& /*account_id*/, const std::map<std::string, std::string>& /*devices*/){}
+    virtual void exportOnRingEnded(const std::string& /*account_id*/, int /*state*/, const std::string& /*pin*/){}
+
+    virtual void incomingTrustRequest(const std::string& /*account_id*/, const std::string& /*from*/, const std::vector<uint8_t>& /*payload*/, time_t received){}
+    virtual void contactAdded(const std::string& /*account_id*/, const std::string& /*uri*/, bool confirmed){}
+    virtual void contactRemoved(const std::string& /*account_id*/, const std::string& /*uri*/, bool banned){}
+
+    virtual void certificatePinned(const std::string& /*certId*/){}
+    virtual void certificatePathPinned(const std::string& /*path*/, const std::vector<std::string>& /*certId*/){}
+    virtual void certificateExpired(const std::string& /*certId*/){}
+    virtual void certificateStateChanged(const std::string& /*account_id*/, const std::string& /*certId*/, const std::string& /*state*/){}
+
+    virtual void errorAlert(int alert){}
+
+    virtual void nameRegistrationEnded(const std::string& /*account_id*/, int state, const std::string& /*name*/){}
+    virtual void registeredNameFound(const std::string& /*account_id*/, int state, const std::string& /*address*/, const std::string& /*name*/){}
+
+    virtual void migrationEnded(const std::string& /*accountId*/, const std::string& /*state*/){}
+    virtual void deviceRevocationEnded(const std::string& /*accountId*/, const std::string& /*device*/, int /*status*/){}
+};
+%}
+
+%feature("director") ConfigurationCallback;
+
+namespace DRing {
+
+std::map<std::string, std::string> getAccountDetails(const std::string& accountID);
+std::map<std::string, std::string> getVolatileAccountDetails(const std::string& accountID);
+void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details);
+void setAccountActive(const std::string& accountID, bool active);
+std::map<std::string, std::string> getAccountTemplate(const std::string& accountType);
+std::string addAccount(const std::map<std::string, std::string>& details);
+void removeAccount(const std::string& accountID);
+std::vector<std::string> getAccountList();
+void sendRegister(const std::string& accountID, bool enable);
+void registerAllAccounts(void);
+uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message);
+int getMessageStatus(uint64_t id);
+
+bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
+bool lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address);
+bool registerName(const std::string& account, const std::string& password, const std::string& name);
+
+std::map<std::string, std::string> getTlsDefaultSettings();
+
+std::vector<unsigned> getCodecList();
+std::vector<std::string> getSupportedTlsMethod();
+std::vector<std::string> getSupportedCiphers(const std::string& accountID);
+std::map<std::string, std::string> getCodecDetails(const std::string& accountID, const unsigned& codecId);
+bool setCodecDetails(const std::string& accountID, const unsigned& codecId, const std::map<std::string, std::string>& details);
+std::vector<unsigned> getActiveCodecList(const std::string& accountID);
+std::string exportOnRing(const std::string& accountID, const std::string& password);
+
+std::map<std::string, std::string> getKnownRingDevices(const std::string& accountID);
+bool revokeDevice(const std::string& accountID, const std::string& password, const std::string& deviceID);
+
+void setActiveCodecList(const std::string& accountID, const std::vector<unsigned>& list);
+
+std::vector<std::string> getAudioPluginList();
+void setAudioPlugin(const std::string& audioPlugin);
+std::vector<std::string> getAudioOutputDeviceList();
+void setAudioOutputDevice(int32_t index);
+void setAudioInputDevice(int32_t index);
+void setAudioRingtoneDevice(int32_t index);
+std::vector<std::string> getAudioInputDeviceList();
+std::vector<std::string> getCurrentAudioDevicesIndex();
+int32_t getAudioInputDeviceIndex(const std::string& name);
+int32_t getAudioOutputDeviceIndex(const std::string& name);
+std::string getCurrentAudioOutputPlugin();
+bool getNoiseSuppressState();
+void setNoiseSuppressState(bool state);
+
+bool isAgcEnabled();
+void setAgcState(bool enabled);
+
+void muteDtmf(bool mute);
+bool isDtmfMuted();
+
+bool isCaptureMuted();
+void muteCapture(bool mute);
+bool isPlaybackMuted();
+void mutePlayback(bool mute);
+bool isRingtoneMuted();
+void muteRingtone(bool mute);
+
+std::string getAudioManager();
+bool setAudioManager(const std::string& api);
+
+std::string getRecordPath();
+void setRecordPath(const std::string& recPath);
+bool getIsAlwaysRecording();
+void setIsAlwaysRecording(bool rec);
+
+void setHistoryLimit(int32_t days);
+int32_t getHistoryLimit();
+
+void setAccountsOrder(const std::string& order);
+
+std::map<std::string, std::string> getHookSettings();
+void setHookSettings(const std::map<std::string, std::string>& settings);
+
+std::vector<std::map<std::string, std::string> > getCredentials(const std::string& accountID);
+void setCredentials(const std::string& accountID, const std::vector<std::map<std::string, std::string> >& details);
+
+std::string getAddrFromInterfaceName(const std::string& interface);
+
+std::vector<std::string> getAllIpInterface();
+std::vector<std::string> getAllIpInterfaceByName();
+
+std::map<std::string, std::string> getShortcuts();
+void setShortcuts(const std::map<std::string, std::string> &shortcutsMap);
+
+void setVolume(const std::string& device, double value);
+double getVolume(const std::string& device);
+
+/*
+ * Security
+ */
+std::map<std::string, std::string> validateCertificatePath(const std::string& accountId,
+                                                       const std::string& certificate,
+                                                       const std::string& privateKey,
+                                                       const std::string& privateKeyPassword,
+                                                       const std::string& caList);
+
+std::map<std::string, std::string> validateCertificate(const std::string& accountId, const std::string& certificate);
+
+std::map<std::string, std::string> getCertificateDetails(const std::string& certificate);
+std::map<std::string, std::string> getCertificateDetailsPath(const std::string& certificate, const std::string& privateKey, const std::string& privateKeyPass);
+
+std::vector<std::string> getPinnedCertificates();
+
+std::vector<std::string> pinCertificate(const std::vector<uint8_t>& certificate, bool local);
+bool unpinCertificate(const std::string& certId);
+
+void pinCertificatePath(const std::string& path);
+unsigned unpinCertificatePath(const std::string& path);
+
+bool pinRemoteCertificate(const std::string& accountId, const std::string& certId);
+bool setCertificateStatus(const std::string& account, const std::string& certId, const std::string& status);
+std::vector<std::string> getCertificatesByStatus(const std::string& account, const std::string& status);
+
+/* contact requests */
+std::vector<std::map<std::string, std::string>> getTrustRequests(const std::string& accountId);
+bool acceptTrustRequest(const std::string& accountId, const std::string& from);
+bool discardTrustRequest(const std::string& accountId, const std::string& from);
+void sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload);
+
+/* Contacts */
+
+void addContact(const std::string& accountId, const std::string& uri);
+void removeContact(const std::string& accountId, const std::string& uri, const bool& ban);
+std::vector<std::map<std::string, std::string>> getContacts(const std::string& accountId);
+
+int exportAccounts(std::vector<std::string> accountIDs, std::string toDir, std::string password);
+int importAccounts(std::string archivePath, std::string password);
+
+void connectivityChanged();
+}
+
+class ConfigurationCallback {
+public:
+    virtual ~ConfigurationCallback(){}
+    virtual void volumeChanged(const std::string& device, int value){}
+    virtual void accountsChanged(void){}
+    virtual void historyChanged(void){}
+    virtual void stunStatusFailure(const std::string& account_id){}
+    virtual void registrationStateChanged(const std::string& account_id, const std::string& state, int code, const std::string& detail_str){}
+    virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
+    virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
+    virtual void accountMessageStatusChanged(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/){}
+    virtual void knownDevicesChanged(const std::string& /*account_id*/, const std::map<std::string, std::string>& /*devices*/){}
+    virtual void exportOnRingEnded(const std::string& /*account_id*/, int /*state*/, const std::string& /*pin*/){}
+
+    virtual void incomingTrustRequest(const std::string& /*account_id*/, const std::string& /*from*/, const std::vector<uint8_t>& /*payload*/, time_t received){}
+    virtual void contactAdded(const std::string& /*account_id*/, const std::string& /*uri*/, bool confirmed){}
+    virtual void contactRemoved(const std::string& /*account_id*/, const std::string& /*uri*/, bool banned){}
+
+    virtual void certificatePinned(const std::string& /*certId*/){}
+    virtual void certificatePathPinned(const std::string& /*path*/, const std::vector<std::string>& /*certId*/){}
+    virtual void certificateExpired(const std::string& /*certId*/){}
+    virtual void certificateStateChanged(const std::string& /*account_id*/, const std::string& /*certId*/, const std::string& /*state*/){}
+
+    virtual void errorAlert(int alert){}
+
+    virtual void nameRegistrationEnded(const std::string& /*account_id*/, int state, const std::string& /*name*/){}
+    virtual void registeredNameFound(const std::string& /*account_id*/, int state, const std::string& /*address*/, const std::string& /*name*/){}
+
+    virtual void migrationEnded(const std::string& /*accountId*/, const std::string& /*state*/){}
+    virtual void deviceRevocationEnded(const std::string& /*accountId*/, const std::string& /*device*/, int /*status*/){}
+};
diff --git a/bin/nodejs/index.js b/bin/nodejs/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..5c9ea4eba3c0c15942ff31cea159d30d8220b190
--- /dev/null
+++ b/bin/nodejs/index.js
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (c) 2017 Savoir-faire Linux Inc.
+ *
+ *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *  Author: Asad Salman <me@asad.co>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+"use strict";
+class RingDaemon{
+    constructor(callbackMap) {
+        if(callbackMap){
+            this.dring = require("./build/Release/dring");
+            this.dring.init(callbackMap);
+            var that = this;
+            this.pollIntervalId = setInterval(function () {
+                that.dring.pollEvents();
+                //console.log("Polling...");
+            }, 10);
+        }
+    }
+
+    boolToStr(bool){
+        if(bool)
+            return "TRUE";
+        else
+            return "FALSE";
+    }
+
+    addAccount(account) {
+        var params = new this.dring.StringMap();
+        params.set("Account.type", "RING");
+        if(account.archivePassword){
+            params.set("Account.archivePassword", account.archivePassword);
+        } else {
+            console.log("archivePassword required");
+            return;
+        }
+        if(account.alias)
+            params.set("Account.alias", account.alias);
+        if(account.displayName)
+            params.set("Account.displayName", account.displayName);
+        if(account.enable)
+            params.set("Account.enable", this.boolToStr(account.enable));
+        if(account.autoAnswer)
+            params.set("Account.autoAnswer", this.boolToStr(account.autoAnswer));
+        if(account.ringtonePath)
+            params.set("Account.ringtonePath", account.ringtonePath);
+        if(account.ringtoneEnabled)
+            params.set("Account.ringtoneEnabled", this.boolToStr(account.ringtoneEnabled));
+        if(account.videoEnabled)
+            params.set("Account.videoEnabled", this.boolToStr(account.videoEnabled));
+        if(account.useragent){
+            params.set("Account.useragent", account.useragent);
+            params.set("Account.hasCustomUserAgent","TRUE");
+        } else {
+            params.set("Account.hasCustomUserAgent","FALSE");
+        }
+        if(account.audioPortMin)
+            params.set("Account.audioPortMin", account.audioPortMin);
+        if(account.audioPortMax)
+            params.set("Account.audioPortMax", account.audioPortMax);
+        if(account.videoPortMin)
+            params.set("Account.videoPortMin", account.videoPortMin);
+        if(account.videoPortMax)
+            params.set("Account.videoPortMax", account.videoPortMax);
+        if(account.localInterface)
+            params.set("Account.localInterface", account.localInterface);
+        if(account.publishedSameAsLocal)
+            params.set("Account.publishedSameAsLocal", this.boolToStr(account.publishedSameAsLocal));
+        if(account.localPort)
+            params.set("Account.localPort", account.localPort);
+        if(account.publishedPort)
+            params.set("Account.publishedPort", account.publishedPort);
+        if(account.publishedAddress)
+            params.set("Account.publishedAddress", account.publishedAddress);
+        if(account.upnpEnabled)
+            params.set("Account.upnpEnabled", this.boolToStr(account.upnpEnabled));
+
+        this.dring.addAccount(params);
+    }
+
+    getAudioOutputDeviceList() {
+        var devicesVect = this.dring.getAudioOutputDeviceList();
+        var outputDevices = [];
+        for(var i=0; i<devicesVect.size(); i++)
+            outputDevices.push(devicesVect.get(i));
+
+        return outputDevices;
+    }
+
+    getVolume(deviceName) {
+        return this.dring.getVolume(deviceName);
+    }
+
+    setVolume(deviceName, volume) {
+        return this.dring.setVolume(deviceName,volume);
+    }
+
+    stop() {
+        clearInterval(this.pollIntervalId);
+        this.dring.fini();
+    }
+}
+
+var f = function(){
+    console.log("RegistrationStateChanged JS");
+};
+
+var daemon = new RingDaemon({"RegistrationStateChanged": f});
+//daemon.stop();
\ No newline at end of file
diff --git a/bin/nodejs/managerimpl.i b/bin/nodejs/managerimpl.i
new file mode 100644
index 0000000000000000000000000000000000000000..d24a42572156b4c93ab576390d24b9d11c28fbff
--- /dev/null
+++ b/bin/nodejs/managerimpl.i
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* %nodefaultctor ManagerImpl;
+%nodefaultdtor ManagerImpl; */
+%header %{
+#include "dring/dring.h"
+%}
+
+namespace DRing {
+
+/**
+ * Finalizes libsflphone, freeing any resource allocated by the library.
+ */
+void fini(void);
+
+/**
+ * Poll for events
+ */
+void pollEvents(void);
+
+}
diff --git a/bin/nodejs/nodejs_interface.i b/bin/nodejs/nodejs_interface.i
new file mode 100644
index 0000000000000000000000000000000000000000..85d4c60118534164da3488ec5e8797e9730435f6
--- /dev/null
+++ b/bin/nodejs/nodejs_interface.i
@@ -0,0 +1,167 @@
+/*
+ *  Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
+ *  Author: Asad Salman <me@asad.co>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* File : nodejs_interface.i */
+%module (directors="1") Ringservice
+
+#define SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON
+%include "typemaps.i"
+%include "std_string.i" /* std::string typemaps */
+%include "arrays_javascript.i";
+%include "carrays.i";
+%include "std_map.i";
+%include "std_vector.i";
+%include "stdint.i";
+
+
+/* Avoid uint64_t to be converted to BigInteger */
+%apply int64_t { uint64_t };
+
+namespace std {
+
+%extend map<string, string> {
+    std::vector<std::string> keys() const {
+        std::vector<std::string> k;
+        k.reserve($self->size());
+        for (const auto& i : *$self) {
+            k.push_back(i.first);
+        }
+        return k;
+    }
+    void setRaw(std::string key, const vector<uint8_t>& value) {
+        (*$self)[key] = std::string(value.data(), value.data()+value.size());
+    }
+    std::vector<uint8_t> getRaw(std::string key) {
+        auto& v = $self->at(key);
+        return {v.begin(), v.end()};
+    }
+}
+%template(StringMap) map<string, string>;
+
+
+%extend vector<string> {
+  value_type set(int i, const value_type& in) throw (std::out_of_range) {
+    const std::string old = $self->at(i);
+    $self->at(i) = in;
+    return old;
+  }
+  bool add(const value_type& in) {
+    $self->push_back(in);
+    return true;
+  }
+  int32_t size() const {
+    return $self->size();
+  }
+}
+%template(StringVect) vector<string>;
+
+
+%template(VectMap) vector< map<string,string> >;
+%template(IntegerMap) map<string,int>;
+%template(IntVect) vector<int32_t>;
+%template(UintVect) vector<uint32_t>;
+
+
+%template(Blob) vector<uint8_t>;
+%template(FloatVect) vector<float>;
+}
+
+/* not parsed by SWIG but needed by generated C files */
+%header %{
+#include <functional>
+%}
+
+/* parsed by SWIG to generate all the glue */
+/* %include "../managerimpl.h" */
+/* %include <client/callmanager.h> */
+
+%include "managerimpl.i"
+%include "callmanager.i"
+%include "configurationmanager.i"
+%include "presencemanager.i"
+%include "callmanager.i"
+%include "videomanager.i"
+//#include "dring/callmanager_interface.h"
+
+%header %{
+#include "callback.h"
+%}
+
+//typemap for passing Callbacks
+%typemap(in) v8::Local<v8::Function> {
+    $1 = v8::Local<v8::Function>::Cast($input);
+}
+
+//typemap for handling map of functions
+%typemap(in) const v8::Handle<v8::Value>  {
+    $1 = $input;
+}
+
+
+%inline %{
+/* some functions that need to be declared in *_wrap.cpp
+ * that are not declared elsewhere in the c++ code
+ */
+
+void init(const v8::Handle<v8::Value> &funcMap){
+    parseCbMap(funcMap);
+    uv_async_init(uv_default_loop(), &signalAsync, handlePendingSignals);
+
+    using namespace std::placeholders;
+    using std::bind;
+    using DRing::exportable_callback;
+    using DRing::ConfigurationSignal;
+    using DRing::CallSignal;
+    using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;
+    const std::map<std::string, SharedCallback> callEvHandlers = {
+        exportable_callback<CallSignal::StateChange>(bind(&callStateChanged, _1, _2, _3)),
+        exportable_callback<CallSignal::IncomingMessage>(bind(&incomingMessage, _1, _2, _3)),
+        exportable_callback<CallSignal::IncomingCall>(bind(&incomingCall, _1, _2, _3)),
+        exportable_callback<CallSignal::NewCallCreated>(bind(&newCallCreated, _1, _2, _3))
+    };
+
+    const std::map<std::string, SharedCallback> configEvHandlers = {
+        exportable_callback<ConfigurationSignal::AccountsChanged>(bind(&accountsChanged)),
+        exportable_callback<ConfigurationSignal::RegistrationStateChanged>(bind(&registrationStateChanged, _1, _2, _3, _4)),
+        exportable_callback<ConfigurationSignal::ContactAdded>(bind(&contactAdded, _1, _2, _3 )),
+        exportable_callback<ConfigurationSignal::ContactRemoved>(bind(&contactRemoved, _1, _2, _3 )),
+        exportable_callback<ConfigurationSignal::ExportOnRingEnded>(bind(&exportOnRingEnded, _1, _2, _3 )),
+        exportable_callback<ConfigurationSignal::NameRegistrationEnded>(bind(&nameRegistrationEnded, _1, _2, _3 )),
+        exportable_callback<ConfigurationSignal::RegisteredNameFound>(bind(&registeredNameFound, _1, _2, _3, _4 )),
+        exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(bind(&volatileDetailsChanged, _1, _2)),
+        exportable_callback<ConfigurationSignal::KnownDevicesChanged>(bind(&knownDevicesChanged, _1, _2 )),
+        exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&incomingAccountMessage, _1, _2, _3 )),
+        exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&accountMessageStatusChanged, _1, _2, _3, _4 )),
+        exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&incomingTrustRequest, _1, _2, _3, _4 )),
+    };
+
+    if (!DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_DEBUG)))
+        return;
+
+    registerConfHandlers(configEvHandlers);
+    registerCallHandlers(callEvHandlers);
+
+    DRing::start();
+}
+%}
+#ifndef SWIG
+/* some bad declarations */
+#endif
\ No newline at end of file
diff --git a/bin/nodejs/presencemanager.i b/bin/nodejs/presencemanager.i
new file mode 100644
index 0000000000000000000000000000000000000000..5fe2302e6c47b26ca03b3b14e14fd440158c4a5e
--- /dev/null
+++ b/bin/nodejs/presencemanager.i
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (C) 2017 Savoir-faire Linux Inc.
+ *
+ *  Author: Aline Bonnet <aline.bonnet@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+%header %{
+
+#include "dring/dring.h"
+#include "dring/presencemanager_interface.h"
+
+class PresenceCallback {
+public:
+    virtual ~PresenceCallback(){}
+    virtual void newServerSubscriptionRequest(const std::string& /*remote*/){}
+    virtual void serverError(const std::string& /*account_id*/, const std::string& /*error*/, const std::string& /*msg*/){}
+    virtual void newBuddyNotification(const std::string& /*account_id*/, const std::string& /*buddy_uri*/, int /*status*/, const std::string& /*line_status*/){}
+    virtual void subscriptionStateChanged(const std::string& /*account_id*/, const std::string& /*buddy_uri*/, int /*state*/){}
+};
+%}
+
+%feature("director") PresenceCallback;
+
+namespace DRing {
+
+/* Presence subscription/Notification. */
+void publish(const std::string& accountID, bool status, const std::string& note);
+void answerServerRequest(const std::string& uri, bool flag);
+void subscribeBuddy(const std::string& accountID, const std::string& uri, bool flag);
+std::vector<std::map<std::string, std::string>> getSubscriptions(const std::string& accountID);
+void setSubscriptions(const std::string& accountID, const std::vector<std::string>& uris);
+}
+
+class PresenceCallback {
+public:
+    virtual ~PresenceCallback(){}
+    virtual void newServerSubscriptionRequest(const std::string& /*remote*/){}
+    virtual void serverError(const std::string& /*account_id*/, const std::string& /*error*/, const std::string& /*msg*/){}
+    virtual void newBuddyNotification(const std::string& /*account_id*/, const std::string& /*buddy_uri*/, int /*status*/, const std::string& /*line_status*/){}
+    virtual void subscriptionStateChanged(const std::string& /*account_id*/, const std::string& /*buddy_uri*/, int /*state*/){}
+};
\ No newline at end of file
diff --git a/bin/nodejs/videomanager.i b/bin/nodejs/videomanager.i
new file mode 100644
index 0000000000000000000000000000000000000000..87a0cc4267ae73169819a19967d88d7e218fecb7
--- /dev/null
+++ b/bin/nodejs/videomanager.i
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (C) 2015-2016 Savoir-faire Linux Inc.
+ *
+ *  Authors: Damien Riegel <damien.riegel@savoirfairelinux.com>
+ *           Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *           Ciro Santilli <ciro.santilli@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+%header %{
+#include <functional>
+#include <list>
+#include <mutex>
+
+#include "dring/dring.h"
+#include "dring/videomanager_interface.h"
+
+class VideoCallback {
+public:
+    virtual ~VideoCallback(){}
+    virtual void getCameraInfo(const std::string& device, std::vector<int> *formats, std::vector<unsigned> *sizes, std::vector<unsigned> *rates) {}
+    virtual void setParameters(const std::string, const int format, const int width, const int height, const int rate) {}
+    virtual void startCapture(const std::string& camid) {}
+    virtual void stopCapture() {}
+    virtual void decodingStarted(const std::string& id, const std::string& shm_path, int w, int h, bool is_mixer) {}
+    virtual void decodingStopped(const std::string& id, const std::string& shm_path, bool is_mixer) {}
+};
+%}
+
+%feature("director") VideoCallback;
+
+namespace DRing {
+
+void setDefaultDevice(const std::string& name);
+std::string getDefaultDevice();
+
+void startCamera();
+void stopCamera();
+bool hasCameraStarted();
+bool switchInput(const std::string& resource);
+bool switchToCamera();
+std::map<std::string, std::string> getSettings(const std::string& name);
+void applySettings(const std::string& name, const std::map<std::string, std::string>& settings);
+
+void registerSinkTarget(const std::string& sinkId, const DRing::SinkTarget& target);
+}
+
+class VideoCallback {
+public:
+    virtual ~VideoCallback(){}
+    virtual void getCameraInfo(const std::string& device, std::vector<int> *formats, std::vector<unsigned> *sizes, std::vector<unsigned> *rates){}
+    virtual void setParameters(const std::string, const int format, const int width, const int height, const int rate) {}
+    virtual void startCapture(const std::string& camid) {}
+    virtual void stopCapture() {}
+    virtual void decodingStarted(const std::string& id, const std::string& shm_path, int w, int h, bool is_mixer) {}
+    virtual void decodingStopped(const std::string& id, const std::string& shm_path, bool is_mixer) {}
+};
diff --git a/configure.ac b/configure.ac
index 3ee14ce5bb71621d6d98855855e78f4f710b4a73..a10c41b35d32b9b8b5c7ad420c6b1765799dc3a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -390,6 +390,20 @@ AC_ARG_ENABLE([ringns], AS_HELP_STRING([--disable-ringns], [Enable Ring Name Ser
 AM_CONDITIONAL([RINGNS], test "x$enable_ringns" != "xno", [Define if you use the Ring Name Service])
 AC_DEFINE_UNQUOTED([HAVE_RINGNS], `if test "x$enable_ringns" != "xno"; then echo 1; else echo 0; fi`, [Define if you use the Ring Name Service])
 
+dnl Ring nodejs module
+AC_ARG_WITH([nodejs], AS_HELP_STRING([--with-nodejs], [Enable Ring NodeJS module]))
+AM_CONDITIONAL([RING_NODEJS], test "x$enable_nodejs" != "xno", [Define if you use the Ring NodeJS module])
+AC_DEFINE_UNQUOTED([HAVE_NODEJS], `if test "x$enable_ringns" != "xno"; then echo 1; else echo 0; fi`, [Define if you use the Ring NodeJS module])
+AS_IF([test "x$with_nodejs" = "xyes"], [
+    AC_PATH_PROG(SWIG, swig, "")
+    AS_AC_EXPAND(SBINDIR, $sbindir)
+    AC_SUBST(SBINDIR)
+    AC_CONFIG_FILES([bin/nodejs/Makefile])
+    AM_CONDITIONAL(RING_NODEJS, true)
+  ],
+  AM_CONDITIONAL(RING_NODEJS, false)
+);
+
 # Rest C++ with restbed
 AC_ARG_WITH([restcpp],
     AS_HELP_STRING([--with-restcpp], [enable rest support with C++]))