From c4d03c6dbf93a74c4fb41a1e2db398b10777ee3d Mon Sep 17 00:00:00 2001 From: Adrien Beraud <adrien.beraud@savoirfairelinux.com> Date: Mon, 15 May 2017 11:15:54 -0400 Subject: [PATCH] nodejs: add initial module Change-Id: I12310bd4a5826e5658e5b7fe72a8a5ae6efe82d0 --- bin/nodejs/Makefile.am | 10 ++ bin/nodejs/binding.gyp | 10 ++ bin/nodejs/callmanager.i | 137 +++++++++++++++ bin/nodejs/configurationmanager.i | 226 ++++++++++++++++++++++++ bin/nodejs/index.js | 21 +++ bin/nodejs/jni_interface.i | 275 ++++++++++++++++++++++++++++++ bin/nodejs/managerimpl.i | 39 +++++ bin/nodejs/presencemanager.i | 54 ++++++ bin/nodejs/ringservice.c.template | 73 ++++++++ bin/nodejs/videomanager.i | 69 ++++++++ configure.ac | 14 ++ 11 files changed, 928 insertions(+) create mode 100644 bin/nodejs/Makefile.am create mode 100644 bin/nodejs/binding.gyp create mode 100644 bin/nodejs/callmanager.i create mode 100644 bin/nodejs/configurationmanager.i create mode 100644 bin/nodejs/index.js create mode 100644 bin/nodejs/jni_interface.i create mode 100644 bin/nodejs/managerimpl.i create mode 100644 bin/nodejs/presencemanager.i create mode 100644 bin/nodejs/ringservice.c.template create mode 100644 bin/nodejs/videomanager.i diff --git a/bin/nodejs/Makefile.am b/bin/nodejs/Makefile.am new file mode 100644 index 0000000000..f2b1e82c19 --- /dev/null +++ b/bin/nodejs/Makefile.am @@ -0,0 +1,10 @@ +include $(top_srcdir)/globals.mk + +BUILT_SOURCES= \ + ring_wrapper.cpp + +ring_wrapper.cpp: jni_interface.i configurationmanager.i managerimpl.i + $(SWIG) -v -c++ -javascript -node -o ring_wrapper.cpp jni_interface.i + +CLEANFILES= \ + $(BUILT_SOURCES) diff --git a/bin/nodejs/binding.gyp b/bin/nodejs/binding.gyp new file mode 100644 index 0000000000..900a555c7d --- /dev/null +++ b/bin/nodejs/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "dring", + "sources": [ "ring_wrapper.cpp" ], + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ] + } + ] +} \ No newline at end of file diff --git a/bin/nodejs/callmanager.i b/bin/nodejs/callmanager.i new file mode 100644 index 0000000000..39c1bf09df --- /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 0000000000..b27a3f97c3 --- /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); +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 100644 index 0000000000..6a0e4fc3ac --- /dev/null +++ b/bin/nodejs/index.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2017 Savoir-faire Linux Inc. + * + * 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, see <https://www.gnu.org/licenses/>. + */ +'use strict'; + +require("./build/Release/dring") diff --git a/bin/nodejs/jni_interface.i b/bin/nodejs/jni_interface.i new file mode 100644 index 0000000000..d927ad6f13 --- /dev/null +++ b/bin/nodejs/jni_interface.i @@ -0,0 +1,275 @@ +/* + * 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. + */ + +/* File : jni_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"; + +/* void* shall be handled as byte arrays */ +%typemap(jni) void * "void *" +%typemap(jtype) void * "byte[]" +%typemap(jstype) void * "byte[]" +%typemap(javain) void * "$javainput" +%typemap(in) void * %{ + $1 = (void*)$input; +%} +%typemap(javadirectorin) void * "$jniinput" +%typemap(out) void * %{ + $result = $1; +%} +%typemap(javaout) void * { + return $jnicall; +} + +/* Avoid uint64_t to be converted to BigInteger */ +%apply int64_t { uint64_t }; + +namespace std { + +%typemap(javacode) map<string, string> %{ + public static $javaclassname toSwig(java.util.Map<String,String> in) { + $javaclassname n = new $javaclassname(); + for (java.util.Map.Entry<String, String> entry : in.entrySet()) { + if (entry.getValue() != null) { + n.set(entry.getKey(), entry.getValue()); + } + } + return n; + } + public java.util.HashMap<String,String> toNative() { + java.util.HashMap<String,String> out = new java.util.HashMap<>((int)size()); + StringVect keys = keys(); + for (String s : keys) { + out.put(s, get(s)); + } + return out; + } + public java.util.HashMap<String,String> toNativeFromUtf8() { + java.util.HashMap<String,String> out = new java.util.HashMap<>((int)size()); + StringVect keys = keys(); + for (String s : keys) { + out.put(s, getRaw(s).toJavaString()); + } + return out; + } +%} +%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>; + +%typemap(javabase) vector<string> "java.util.AbstractList<String>" +%typemap(javainterface) vector<string> "java.util.RandomAccess" +%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>; + +%typemap(javacode) vector< map<string,string> > %{ + public java.util.ArrayList<java.util.Map<String, String>> toNative() { + java.util.ArrayList<java.util.Map<String, String>> out = new java.util.ArrayList<>(); + for (int i = 0; i < size(); ++i) { + out.add(get(i).toNative()); + } + return out; + } +%} +%template(VectMap) vector< map<string,string> >; +%template(IntegerMap) map<string,int>; +%template(IntVect) vector<int32_t>; +%template(UintVect) vector<uint32_t>; + +%typemap(javacode) vector<uint8_t> %{ + public static Blob fromString(String in) { + byte[] dat; + try { + dat = in.getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + dat = in.getBytes(); + } + Blob n = new Blob(dat.length); + for (int i=0; i<dat.length; i++) { + n.set(i, dat[i]); + } + return n; + } + public String toJavaString() { + byte[] dat = new byte[(int)size()]; + for (int i=0; i<dat.length; i++) { + dat[i] = (byte)get(i); + } + try { + return new String(dat, "utf-8"); + } catch (java.io.UnsupportedEncodingException e) { + return ""; + } + } +%} +%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 "videomanager.i" + +#include "dring/callmanager_interface.h" + +%inline %{ +/* some functions that need to be declared in *_wrap.cpp + * that are not declared elsewhere in the c++ code + */ + +void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM, VideoCallback* videoM) { + using namespace std::placeholders; + + using std::bind; + using DRing::exportable_callback; + using DRing::CallSignal; + using DRing::ConfigurationSignal; + using DRing::PresenceSignal; + using DRing::VideoSignal; + + using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>; + + // Call event handlers + const std::map<std::string, SharedCallback> callEvHandlers = { + exportable_callback<CallSignal::StateChange>(bind(&Callback::callStateChanged, callM, _1, _2, _3)), + exportable_callback<CallSignal::TransferFailed>(bind(&Callback::transferFailed, callM)), + exportable_callback<CallSignal::TransferSucceeded>(bind(&Callback::transferSucceeded, callM)), + exportable_callback<CallSignal::RecordPlaybackStopped>(bind(&Callback::recordPlaybackStopped, callM, _1)), + exportable_callback<CallSignal::VoiceMailNotify>(bind(&Callback::voiceMailNotify, callM, _1, _2)), + exportable_callback<CallSignal::IncomingMessage>(bind(&Callback::incomingMessage, callM, _1, _2, _3)), + exportable_callback<CallSignal::IncomingCall>(bind(&Callback::incomingCall, callM, _1, _2, _3)), + exportable_callback<CallSignal::RecordPlaybackFilepath>(bind(&Callback::recordPlaybackFilepath, callM, _1, _2)), + exportable_callback<CallSignal::ConferenceCreated>(bind(&Callback::conferenceCreated, callM, _1)), + exportable_callback<CallSignal::ConferenceChanged>(bind(&Callback::conferenceChanged, callM, _1, _2)), + exportable_callback<CallSignal::UpdatePlaybackScale>(bind(&Callback::updatePlaybackScale, callM, _1, _2, _3)), + exportable_callback<CallSignal::ConferenceRemoved>(bind(&Callback::conferenceRemoved, callM, _1)), + exportable_callback<CallSignal::NewCallCreated>(bind(&Callback::newCallCreated, callM, _1, _2, _3)), + exportable_callback<CallSignal::RecordingStateChanged>(bind(&Callback::recordingStateChanged, callM, _1, _2)), + exportable_callback<CallSignal::RtcpReportReceived>(bind(&Callback::onRtcpReportReceived, callM, _1, _2)), + exportable_callback<CallSignal::PeerHold>(bind(&Callback::peerHold, callM, _1, _2)) + }; + + // Configuration event handlers + const std::map<std::string, SharedCallback> configEvHandlers = { + exportable_callback<ConfigurationSignal::VolumeChanged>(bind(&ConfigurationCallback::volumeChanged, confM, _1, _2)), + exportable_callback<ConfigurationSignal::AccountsChanged>(bind(&ConfigurationCallback::accountsChanged, confM)), + exportable_callback<ConfigurationSignal::StunStatusFailed>(bind(&ConfigurationCallback::stunStatusFailure, confM, _1)), + exportable_callback<ConfigurationSignal::RegistrationStateChanged>(bind(&ConfigurationCallback::registrationStateChanged, confM, _1, _2, _3, _4)), + exportable_callback<ConfigurationSignal::VolatileDetailsChanged>(bind(&ConfigurationCallback::volatileAccountDetailsChanged, confM, _1, _2)), + exportable_callback<ConfigurationSignal::KnownDevicesChanged>(bind(&ConfigurationCallback::knownDevicesChanged, confM, _1, _2)), + exportable_callback<ConfigurationSignal::ExportOnRingEnded>(bind(&ConfigurationCallback::exportOnRingEnded, confM, _1, _2, _3)), + exportable_callback<ConfigurationSignal::Error>(bind(&ConfigurationCallback::errorAlert, confM, _1)), + exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&ConfigurationCallback::incomingAccountMessage, confM, _1, _2, _3 )), + exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&ConfigurationCallback::accountMessageStatusChanged, confM, _1, _2, _3, _4 )), + exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&ConfigurationCallback::incomingTrustRequest, confM, _1, _2, _3, _4 )), + exportable_callback<ConfigurationSignal::ContactAdded>(bind(&ConfigurationCallback::contactAdded, confM, _1, _2, _3 )), + exportable_callback<ConfigurationSignal::ContactRemoved>(bind(&ConfigurationCallback::contactRemoved, confM, _1, _2, _3 )), + exportable_callback<ConfigurationSignal::CertificatePinned>(bind(&ConfigurationCallback::certificatePinned, confM, _1 )), + exportable_callback<ConfigurationSignal::CertificatePathPinned>(bind(&ConfigurationCallback::certificatePathPinned, confM, _1, _2 )), + exportable_callback<ConfigurationSignal::CertificateExpired>(bind(&ConfigurationCallback::certificateExpired, confM, _1 )), + exportable_callback<ConfigurationSignal::CertificateStateChanged>(bind(&ConfigurationCallback::certificateStateChanged, confM, _1, _2, _3 )), + exportable_callback<ConfigurationSignal::RegisteredNameFound>(bind(&ConfigurationCallback::registeredNameFound, confM, _1, _2, _3, _4 )), + exportable_callback<ConfigurationSignal::NameRegistrationEnded>(bind(&ConfigurationCallback::nameRegistrationEnded, confM, _1, _2, _3 )), + exportable_callback<ConfigurationSignal::MigrationEnded>(bind(&ConfigurationCallback::migrationEnded, confM, _1, _2)), + exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(bind(&ConfigurationCallback::deviceRevocationEnded, confM, _1, _2, _3)) + }; + + // Presence event handlers + const std::map<std::string, SharedCallback> presenceEvHandlers = { + exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(bind(&PresenceCallback::newServerSubscriptionRequest, presM, _1 )), + exportable_callback<PresenceSignal::ServerError>(bind(&PresenceCallback::serverError, presM, _1, _2, _3 )), + exportable_callback<PresenceSignal::NewBuddyNotification>(bind(&PresenceCallback::newBuddyNotification, presM, _1, _2, _3, _4 )), + exportable_callback<PresenceSignal::SubscriptionStateChanged>(bind(&PresenceCallback::subscriptionStateChanged, presM, _1, _2, _3 )) + }; + + /*const std::map<std::string, SharedCallback> videoEvHandlers = { + exportable_callback<VideoSignal::GetCameraInfo>(bind(&VideoCallback::getCameraInfo, videoM, _1, _2, _3, _4)), + exportable_callback<VideoSignal::SetParameters>(bind(&VideoCallback::setParameters, videoM, _1, _2, _3, _4, _5)), + exportable_callback<VideoSignal::StartCapture>(bind(&VideoCallback::startCapture, videoM, _1)), + exportable_callback<VideoSignal::StopCapture>(bind(&VideoCallback::stopCapture, videoM)), + exportable_callback<VideoSignal::DecodingStarted>(bind(&VideoCallback::decodingStarted, videoM, _1, _2, _3, _4, _5)), + exportable_callback<VideoSignal::DecodingStopped>(bind(&VideoCallback::decodingStopped, videoM, _1, _2, _3)), + };*/ + + if (!DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_DEBUG))) + return; + + registerCallHandlers(callEvHandlers); + registerConfHandlers(configEvHandlers); + registerPresHandlers(presenceEvHandlers); + //registerVideoHandlers(videoEvHandlers); + + DRing::start(); +} + + +%} +#ifndef SWIG +/* some bad declarations */ +#endif diff --git a/bin/nodejs/managerimpl.i b/bin/nodejs/managerimpl.i new file mode 100644 index 0000000000..d24a425721 --- /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/presencemanager.i b/bin/nodejs/presencemanager.i new file mode 100644 index 0000000000..5fe2302e6c --- /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/ringservice.c.template b/bin/nodejs/ringservice.c.template new file mode 100644 index 0000000000..61c4e61262 --- /dev/null +++ b/bin/nodejs/ringservice.c.template @@ -0,0 +1,73 @@ +#include "logger.h" + +JavaVM *gJavaVM; +const char *kringservicePath = "cx/ring/daemon/RingserviceJNI"; + +void deinitClassHelper(JNIEnv *env, jobject obj) { + RING_INFO("deinitClassHelper"); + + /* delete cached object instances */ + env->DeleteGlobalRef(obj); + RING_INFO("deinitClassHelper: object %x deleted", obj); +} + +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env; + jclass clazz; + jint r; + + RING_INFO("JNI_OnLoad"); + + //Assume it is c++ + r = vm->GetEnv ((void **) &env, JNI_VERSION_1_6); + if (r != JNI_OK) { + RING_ERR("JNI_OnLoad: failed to get the environment using GetEnv()"); + return -1; + } + RING_INFO("JNI_Onload: GetEnv %p", env); + + clazz = env->FindClass (kringservicePath); + if (!clazz) { + RING_ERR("JNI_Onload: whoops, %s class not found!", kringservicePath); + } + gJavaVM = vm; + RING_INFO("JNI_Onload: JavaVM %p", gJavaVM); + + /* put instances of class object we need into cache */ + //initClassHelper(env, kManagerPath, &gManagerObject); + + JNINativeMethod methods[] = { + + $defs + + }; + + r = env->RegisterNatives (clazz, methods, (int) (sizeof(methods) / sizeof(methods[0]))); + return JNI_VERSION_1_6; +} + +void JNI_OnUnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + jclass clazz; + + RING_INFO("JNI_OnUnLoad"); + + /* get env */ + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + RING_ERR("JNI_OnUnLoad: failed to get the environment using GetEnv()"); + return; + } + RING_INFO("JNI_OnUnLoad: GetEnv %p", env); + + /* Get jclass with env->FindClass */ + clazz = env->FindClass(kringservicePath); + if (!clazz) { + RING_ERR("JNI_OnUnLoad: whoops, %s class not found!", kringservicePath); + } + + /* remove instances of class object we need into cache */ + //deinitClassHelper(env, gManagerObject); + + env->UnregisterNatives(clazz); + RING_INFO("JNI_OnUnLoad: Native functions unregistered"); +} diff --git a/bin/nodejs/videomanager.i b/bin/nodejs/videomanager.i new file mode 100644 index 0000000000..87a0cc4267 --- /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 3ee14ce5bb..a10c41b35d 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++])) -- GitLab