@4players/odin-nodejs 0.10.3 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/LICENSE +21 -0
- package/README.md +603 -44
- package/binding.gyp +29 -13
- package/cppsrc/binding.cpp +3 -6
- package/cppsrc/odinbindings.cpp +9 -45
- package/cppsrc/odincipher.cpp +92 -0
- package/cppsrc/odincipher.h +32 -0
- package/cppsrc/odinclient.cpp +19 -158
- package/cppsrc/odinclient.h +2 -5
- package/cppsrc/odinmedia.cpp +144 -186
- package/cppsrc/odinmedia.h +51 -18
- package/cppsrc/odinroom.cpp +675 -635
- package/cppsrc/odinroom.h +76 -26
- package/cppsrc/utilities.cpp +11 -81
- package/cppsrc/utilities.h +25 -140
- package/index.cjs +829 -0
- package/index.d.ts +3 -4
- package/libs/bin/linux/arm64/libodin.so +0 -0
- package/libs/bin/linux/arm64/libodin_crypto.so +0 -0
- package/libs/bin/linux/ia32/libodin.so +0 -0
- package/libs/bin/linux/ia32/libodin_crypto.so +0 -0
- package/libs/bin/linux/x64/libodin.so +0 -0
- package/libs/bin/linux/x64/libodin_crypto.so +0 -0
- package/{prebuilds/darwin-x64/node.napi.node → libs/bin/macos/universal/libodin.dylib} +0 -0
- package/libs/bin/macos/universal/libodin_crypto.dylib +0 -0
- package/libs/bin/windows/arm64/odin.dll +0 -0
- package/libs/bin/windows/arm64/odin.lib +0 -0
- package/libs/bin/windows/arm64/odin_crypto.dll +0 -0
- package/libs/bin/windows/arm64/odin_crypto.lib +0 -0
- package/libs/bin/windows/ia32/odin.dll +0 -0
- package/libs/bin/windows/ia32/odin.lib +0 -0
- package/libs/bin/windows/ia32/odin_crypto.dll +0 -0
- package/libs/bin/windows/ia32/odin_crypto.lib +0 -0
- package/libs/bin/windows/x64/odin.dll +0 -0
- package/libs/bin/windows/x64/odin.lib +0 -0
- package/libs/bin/windows/x64/odin_crypto.dll +0 -0
- package/libs/bin/windows/x64/odin_crypto.lib +0 -0
- package/libs/include/odin.h +665 -567
- package/libs/include/odin_crypto.h +46 -0
- package/odin.cipher.d.ts +31 -0
- package/odin.media.d.ts +69 -19
- package/odin.room.d.ts +348 -7
- package/package.json +5 -4
- package/prebuilds/{darwin-arm64/node.napi.node → darwin-x64+arm64/libodin.dylib} +0 -0
- package/prebuilds/darwin-x64+arm64/libodin_crypto.dylib +0 -0
- package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/libodin.so +0 -0
- package/prebuilds/linux-x64/libodin_crypto.so +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/prebuilds/win32-x64/odin.dll +0 -0
- package/prebuilds/win32-x64/odin_crypto.dll +0 -0
- package/scripts/postbuild.cjs +133 -0
- package/tests/audio-recording/README.md +97 -12
- package/tests/audio-recording/index.js +238 -130
- package/tests/connection-test/README.md +97 -0
- package/tests/connection-test/index.js +273 -0
- package/tests/lifecycle/test-room-cycle.js +169 -0
- package/tests/sending-audio/README.md +178 -9
- package/tests/sending-audio/canBounce.mp3 +0 -0
- package/tests/sending-audio/index.js +250 -87
- package/tests/sending-audio/test-kiss-api.js +149 -0
- package/tests/sending-audio/test-loop-audio.js +142 -0
- package/CMakeLists.txt +0 -25
- package/libs/bin/linux/arm64/libodin_static.a +0 -0
- package/libs/bin/linux/ia32/libodin_static.a +0 -0
- package/libs/bin/linux/x64/libodin_static.a +0 -0
- package/libs/bin/macos/arm64/libodin_static.a +0 -0
- package/libs/bin/macos/x64/libodin_static.a +0 -0
- package/libs/bin/windows/arm64/odin_static.lib +0 -0
- package/libs/bin/windows/ia32/odin_static.lib +0 -0
- package/libs/bin/windows/x64/odin_static.lib +0 -0
package/binding.gyp
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"cppsrc/odinclient.cpp",
|
|
9
9
|
"cppsrc/odinroom.cpp",
|
|
10
10
|
"cppsrc/odinmedia.cpp",
|
|
11
|
+
"cppsrc/odincipher.cpp",
|
|
11
12
|
"cppsrc/utilities.cpp"
|
|
12
13
|
],
|
|
13
14
|
"include_dirs": [
|
|
@@ -20,27 +21,41 @@
|
|
|
20
21
|
"conditions": [
|
|
21
22
|
["OS=='linux'", {
|
|
22
23
|
"libraries": [
|
|
24
|
+
"-Wl,-rpath,$$ORIGIN",
|
|
23
25
|
"-L<(module_root_dir)/libs/bin/linux/<(target_arch)",
|
|
24
|
-
"-
|
|
26
|
+
"-lodin",
|
|
27
|
+
"-lodin_crypto"
|
|
25
28
|
]
|
|
26
29
|
}],
|
|
27
30
|
["OS=='mac'", {
|
|
28
|
-
"
|
|
29
|
-
"-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
"cflags+": [
|
|
32
|
+
"-fvisibility=hidden"
|
|
33
|
+
],
|
|
34
|
+
"xcode_settings": {
|
|
35
|
+
"GCC_SYMBOLS_PRIVATE_EXTERN": "YES",
|
|
36
|
+
"OTHER_CFLAGS": [
|
|
37
|
+
"-arch x86_64",
|
|
38
|
+
"-arch arm64"
|
|
39
|
+
],
|
|
40
|
+
"OTHER_LDFLAGS": [
|
|
41
|
+
"-Wl,-rpath,@loader_path/",
|
|
42
|
+
"-L<(module_root_dir)/libs/bin/macos/universal",
|
|
43
|
+
"-lodin",
|
|
44
|
+
"-lodin_crypto",
|
|
45
|
+
"-arch x86_64",
|
|
46
|
+
"-arch arm64"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
32
49
|
}],
|
|
33
50
|
["OS=='win'", {
|
|
34
51
|
"msvs_settings": {
|
|
35
52
|
"VCCLCompilerTool": {
|
|
36
|
-
"AdditionalOptions": [ "/MD" ]
|
|
37
|
-
}
|
|
38
|
-
"VCLinkerTool": {
|
|
39
|
-
|
|
40
|
-
},
|
|
53
|
+
"AdditionalOptions": [ "/MD" ]
|
|
54
|
+
}
|
|
41
55
|
},
|
|
42
56
|
"libraries": [
|
|
43
|
-
"<(module_root_dir)/libs/bin/windows/<(target_arch)/
|
|
57
|
+
"<(module_root_dir)/libs/bin/windows/<(target_arch)/odin.lib",
|
|
58
|
+
"<(module_root_dir)/libs/bin/windows/<(target_arch)/odin_crypto.lib",
|
|
44
59
|
"-lws2_32",
|
|
45
60
|
"-lbcrypt",
|
|
46
61
|
"-lucrt",
|
|
@@ -50,11 +65,12 @@
|
|
|
50
65
|
]
|
|
51
66
|
}]
|
|
52
67
|
],
|
|
53
|
-
"defines": [ "
|
|
68
|
+
"defines": [ "NAPI_CPP_EXCEPTIONS" ],
|
|
54
69
|
"cflags!": [ "-fno-exceptions" ],
|
|
55
70
|
"cflags_cc!": [ "-fno-exceptions" ],
|
|
71
|
+
"cflags_cc": [ "-fexceptions" ],
|
|
56
72
|
"xcode_settings": {
|
|
57
|
-
"GCC_ENABLE_CPP_EXCEPTIONS": "
|
|
73
|
+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
|
58
74
|
"CLANG_CXX_LIBRARY": "libc++",
|
|
59
75
|
"MACOSX_DEPLOYMENT_TARGET": "10.12",
|
|
60
76
|
},
|
package/cppsrc/binding.cpp
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/* cppsrc/main.cpp */
|
|
2
2
|
#include <napi.h>
|
|
3
3
|
#include "odinbindings.h"
|
|
4
|
-
#include "odinroom.h"
|
|
5
|
-
#include "odinmedia.h"
|
|
6
4
|
#include "odinclient.h"
|
|
7
5
|
|
|
8
6
|
Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
|
|
9
|
-
OdinBindings::Init(env,exports);
|
|
10
|
-
OdinClient::Init(env, exports);
|
|
11
|
-
|
|
12
|
-
return OdinRoom::Init(env, exports);
|
|
7
|
+
OdinBindings::Init(env, exports); // Registers generateAccessToken, Room, Media, Cipher
|
|
8
|
+
OdinClient::Init(env, exports); // Registers OdinClient
|
|
9
|
+
return exports;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
12
|
NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitAll)
|
package/cppsrc/odinbindings.cpp
CHANGED
|
@@ -1,58 +1,22 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Created by Phillip Schuster on 08.03.23.
|
|
3
|
-
//
|
|
4
1
|
#include "odinbindings.h"
|
|
2
|
+
#include "odincipher.h"
|
|
3
|
+
#include "odinmedia.h"
|
|
4
|
+
#include "odinroom.h"
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Wrapper function to generate an access token with access key, room id and user id
|
|
8
|
-
* @param info
|
|
9
|
-
* @return
|
|
10
|
-
*/
|
|
11
6
|
Napi::String OdinBindings::GenerateAccessToken(const Napi::CallbackInfo &info)
|
|
12
7
|
{
|
|
13
8
|
Napi::Env env = info.Env();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Napi::TypeError::New(env, "Room and User Id expected").ThrowAsJavaScriptException();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
std::string accessKey = info[0].ToString().Utf8Value();
|
|
20
|
-
std::string roomId = info[1].ToString().Utf8Value();
|
|
21
|
-
std::string userId = info[2].ToString().Utf8Value();
|
|
22
|
-
|
|
23
|
-
OdinTokenGenerator *generator = odin_token_generator_create(accessKey.c_str());
|
|
24
|
-
if (!generator)
|
|
25
|
-
{
|
|
26
|
-
Napi::TypeError::New(env, "Failed to initialize token generator, invalid access key").ThrowAsJavaScriptException();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/*
|
|
30
|
-
* Generate a new room token to access the ODIN network
|
|
31
|
-
*/
|
|
32
|
-
char room_token[512];
|
|
33
|
-
OdinReturnCode error = odin_token_generator_create_token(generator, roomId.c_str(), userId.c_str(), room_token, sizeof(room_token));
|
|
34
|
-
if (odin_is_error(error))
|
|
35
|
-
{
|
|
36
|
-
Napi::TypeError::New(env, "Creating access token failed").ThrowAsJavaScriptException();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/*
|
|
40
|
-
* Destroy the token generator as we don't need it anymore
|
|
41
|
-
*/
|
|
42
|
-
odin_token_generator_destroy(generator);
|
|
43
|
-
|
|
44
|
-
return Napi::String::New(env, room_token);
|
|
9
|
+
Napi::TypeError::New(env, "Native token generation is deprecated. Use a server-side implementation.").ThrowAsJavaScriptException();
|
|
10
|
+
return Napi::String::New(env, "");
|
|
45
11
|
}
|
|
46
12
|
|
|
47
|
-
/**
|
|
48
|
-
* Initialize the bindings
|
|
49
|
-
* @param env
|
|
50
|
-
* @param exports
|
|
51
|
-
* @return
|
|
52
|
-
*/
|
|
53
13
|
Napi::Object OdinBindings::Init(Napi::Env env, Napi::Object exports)
|
|
54
14
|
{
|
|
55
15
|
exports.Set("generateAccessToken", Napi::Function::New(env, OdinBindings::GenerateAccessToken));
|
|
16
|
+
|
|
17
|
+
OdinRoomWrapper::Init(env, exports);
|
|
18
|
+
OdinMediaWrapper::Init(env, exports);
|
|
19
|
+
OdinCipherWrapper::Init(env, exports);
|
|
56
20
|
|
|
57
21
|
return exports;
|
|
58
22
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#include "odincipher.h"
|
|
2
|
+
#include "utilities.h"
|
|
3
|
+
|
|
4
|
+
Napi::FunctionReference *OdinCipherWrapper::constructor;
|
|
5
|
+
|
|
6
|
+
OdinCipherWrapper::OdinCipherWrapper(const Napi::CallbackInfo& info) : Napi::ObjectWrap<OdinCipherWrapper>(info) {
|
|
7
|
+
_cipher = nullptr;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
void OdinCipherWrapper::Finalize(Napi::Env env) {
|
|
11
|
+
if (_cipher) {
|
|
12
|
+
if (_cipher->free) {
|
|
13
|
+
_cipher->free(_cipher);
|
|
14
|
+
}
|
|
15
|
+
_cipher = nullptr;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Napi::Object OdinCipherWrapper::Init(Napi::Env env, Napi::Object exports) {
|
|
20
|
+
Napi::Function func = DefineClass(env, "OdinCipher", {
|
|
21
|
+
InstanceMethod<&OdinCipherWrapper::SetPassword>("setPassword", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
22
|
+
InstanceMethod<&OdinCipherWrapper::GetPeerStatus>("getPeerStatus", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
constructor = new Napi::FunctionReference();
|
|
26
|
+
*constructor = Napi::Persistent(func);
|
|
27
|
+
exports.Set("OdinCipher", func);
|
|
28
|
+
return exports;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Napi::Value OdinCipherWrapper::CreateNewItem(const Napi::CallbackInfo& info) {
|
|
32
|
+
return constructor->New({});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void OdinCipherWrapper::SetPassword(const Napi::CallbackInfo& info) {
|
|
36
|
+
Napi::Env env = info.Env();
|
|
37
|
+
if (info.Length() < 1 || !info[0].IsTypedArray()) {
|
|
38
|
+
Napi::TypeError::New(env, "Password as Uint8Array required").ThrowAsJavaScriptException();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
|
|
42
|
+
|
|
43
|
+
// Lazy initialization: create cipher only when setPassword is called
|
|
44
|
+
if (!_cipher) {
|
|
45
|
+
_cipher = odin_crypto_create(ODIN_CRYPTO_VERSION);
|
|
46
|
+
if (!_cipher) {
|
|
47
|
+
Napi::TypeError::New(env, "Failed to create OdinCipher").ThrowAsJavaScriptException();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
odin_crypto_set_password(_cipher, data.Data(), (uint32_t)data.ByteLength());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the encryption status of a specific peer.
|
|
57
|
+
*
|
|
58
|
+
* @param info[0] Peer ID (number) - The peer to check status for
|
|
59
|
+
* @returns {string} One of:
|
|
60
|
+
* - 'unknown': Peer status not yet determined
|
|
61
|
+
* - 'unencrypted': Peer is not using encryption
|
|
62
|
+
* - 'encrypted': Peer is using encryption with matching password
|
|
63
|
+
* - 'password_mismatch': Peer is encrypted but password doesn't match
|
|
64
|
+
*/
|
|
65
|
+
Napi::Value OdinCipherWrapper::GetPeerStatus(const Napi::CallbackInfo& info) {
|
|
66
|
+
Napi::Env env = info.Env();
|
|
67
|
+
|
|
68
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
69
|
+
Napi::TypeError::New(env, "Peer ID (number) required").ThrowAsJavaScriptException();
|
|
70
|
+
return env.Undefined();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!_cipher) {
|
|
74
|
+
// Cipher not initialized yet
|
|
75
|
+
return Napi::String::New(env, "unknown");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
uint64_t peerId = static_cast<uint64_t>(info[0].As<Napi::Number>().DoubleValue());
|
|
79
|
+
OdinCryptoPeerStatus status = odin_crypto_get_peer_status(_cipher, peerId);
|
|
80
|
+
|
|
81
|
+
switch (status) {
|
|
82
|
+
case ODIN_CRYPTO_PEER_STATUS_ENCRYPTED:
|
|
83
|
+
return Napi::String::New(env, "encrypted");
|
|
84
|
+
case ODIN_CRYPTO_PEER_STATUS_UNENCRYPTED:
|
|
85
|
+
return Napi::String::New(env, "unencrypted");
|
|
86
|
+
case ODIN_CRYPTO_PEER_STATUS_PASSWORD_MISSMATCH:
|
|
87
|
+
return Napi::String::New(env, "password_mismatch");
|
|
88
|
+
case ODIN_CRYPTO_PEER_STATUS_UNKNOWN:
|
|
89
|
+
default:
|
|
90
|
+
return Napi::String::New(env, "unknown");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#ifndef ODIN_NODEJS_ODINCIPHER_H
|
|
2
|
+
#define ODIN_NODEJS_ODINCIPHER_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
#include <odin_crypto.h>
|
|
6
|
+
|
|
7
|
+
class OdinCipherWrapper : public Napi::ObjectWrap<OdinCipherWrapper> {
|
|
8
|
+
public:
|
|
9
|
+
OdinCipherWrapper(const Napi::CallbackInfo& info);
|
|
10
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
11
|
+
static Napi::Value CreateNewItem(const Napi::CallbackInfo& info);
|
|
12
|
+
|
|
13
|
+
struct OdinCipher* GetCipher() const { return _cipher; }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Transfer ownership of the cipher to the room.
|
|
17
|
+
* After calling this, the wrapper will no longer try to free the cipher
|
|
18
|
+
* in its destructor (the room now owns it).
|
|
19
|
+
*/
|
|
20
|
+
void TransferOwnership() { _cipher = nullptr; }
|
|
21
|
+
|
|
22
|
+
void Finalize(Napi::Env env) override;
|
|
23
|
+
|
|
24
|
+
private:
|
|
25
|
+
static Napi::FunctionReference *constructor;
|
|
26
|
+
struct OdinCipher* _cipher;
|
|
27
|
+
|
|
28
|
+
void SetPassword(const Napi::CallbackInfo& info);
|
|
29
|
+
Napi::Value GetPeerStatus(const Napi::CallbackInfo& info);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
#endif //ODIN_NODEJS_ODINCIPHER_H
|
package/cppsrc/odinclient.cpp
CHANGED
|
@@ -1,198 +1,59 @@
|
|
|
1
1
|
#include "odinclient.h"
|
|
2
|
-
#include <inttypes.h>
|
|
3
2
|
#include "odinroom.h"
|
|
3
|
+
#include "utilities.h" // Added include
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Initialize the OdinClient class
|
|
7
|
-
* @param env
|
|
8
|
-
* @param exports
|
|
9
|
-
* @return
|
|
10
|
-
*/
|
|
11
5
|
Napi::Object OdinClient::Init(Napi::Env env, Napi::Object exports) {
|
|
12
|
-
// This method is used to hook the accessor and method callbacks
|
|
13
6
|
Napi::Function func = DefineClass(env, "OdinClient", {
|
|
14
7
|
InstanceMethod<&OdinClient::GenerateAccessToken>("generateToken", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
15
8
|
InstanceMethod<&OdinClient::CreateRoom>("createRoom", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
16
9
|
InstanceMethod<&OdinClient::CreateRoomWithAccessToken>("createRoomWithToken", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
17
|
-
|
|
18
|
-
// Deprecated functions
|
|
19
10
|
InstanceMethod<&OdinClient::GenerateAccessToken>("generateAccessToken", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
20
11
|
InstanceMethod<&OdinClient::CreateRoomWithAccessToken>("createRoomWithAccessToken", static_cast<napi_property_attributes>(napi_writable | napi_configurable))
|
|
21
12
|
});
|
|
22
13
|
|
|
23
14
|
Napi::FunctionReference* constructor = new Napi::FunctionReference();
|
|
24
|
-
|
|
25
|
-
// Create a persistent reference to the class constructor. This will allow
|
|
26
|
-
// a function called on a class prototype and a function
|
|
27
|
-
// called on instance of a class to be distinguished from each other.
|
|
28
15
|
*constructor = Napi::Persistent(func);
|
|
29
16
|
exports.Set("OdinClient", func);
|
|
30
|
-
|
|
31
|
-
// Store the constructor as the add-on instance data. This will allow this
|
|
32
|
-
// add-on to support multiple instances of itself running on multiple worker
|
|
33
|
-
// threads, as well as multiple instances of itself running in different
|
|
34
|
-
// contexts on the same thread.
|
|
35
|
-
//
|
|
36
|
-
// By default, the value set on the environment here will be destroyed when
|
|
37
|
-
// the add-on is unloaded using the `delete` operator, but it is also
|
|
38
|
-
// possible to supply a custom deleter.
|
|
39
|
-
env.SetInstanceData<Napi::FunctionReference>(constructor);
|
|
40
|
-
|
|
17
|
+
// env.SetInstanceData<Napi::FunctionReference>(constructor);
|
|
41
18
|
return exports;
|
|
42
19
|
}
|
|
43
20
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* @param info
|
|
47
|
-
*/
|
|
48
|
-
OdinClient::OdinClient(const Napi::CallbackInfo& info) : Napi::ObjectWrap<OdinClient>(info) {
|
|
49
|
-
Napi::Env env = info.Env();
|
|
50
|
-
Napi::HandleScope scope(env);
|
|
51
|
-
|
|
52
|
-
_sampleRate = 48000;
|
|
53
|
-
_numChannels = 1;
|
|
54
|
-
|
|
55
|
-
if (info.Length() >= 1) {
|
|
56
|
-
if (info[0].IsNumber()) {
|
|
57
|
-
_sampleRate = info[0].ToNumber();
|
|
58
|
-
} else {
|
|
59
|
-
Napi::TypeError::New(env, "Sample rate must be a number").ThrowAsJavaScriptException();
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (info.Length() >= 2) {
|
|
65
|
-
if (info[1].IsNumber()) {
|
|
66
|
-
_numChannels = info[1].ToNumber();
|
|
67
|
-
} else {
|
|
68
|
-
Napi::TypeError::New(env, "Channels must be a number").ThrowAsJavaScriptException();
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
#ifdef DEBUG
|
|
74
|
-
printf("Odin NodeJS Addon: Initializing Odin runtime (%s) with sample rate %f and %d channels\n", ODIN_VERSION, _sampleRate, _numChannels);
|
|
75
|
-
#endif
|
|
76
|
-
|
|
77
|
-
// Create a OdinAudioStreamConfig struct to configure the audio stream
|
|
78
|
-
OdinAudioStreamConfig config;
|
|
79
|
-
config.sample_rate = _sampleRate;
|
|
80
|
-
config.channel_count = _numChannels;
|
|
21
|
+
// Extern declaration of shared SDK initialization flag (defined in odinroom.cpp)
|
|
22
|
+
extern bool g_odinSdkInitialized;
|
|
81
23
|
|
|
82
|
-
|
|
24
|
+
OdinClient::OdinClient(const Napi::CallbackInfo& info) : Napi::ObjectWrap<OdinClient>(info) {
|
|
25
|
+
// SDK lifecycle is now managed by OdinRoomWrapper via reference counting.
|
|
26
|
+
// The SDK is initialized when the first room is created and shut down
|
|
27
|
+
// when the last room is destroyed. This avoids issues with GC timing.
|
|
83
28
|
}
|
|
84
29
|
|
|
85
|
-
/**
|
|
86
|
-
* OdinClient destructor
|
|
87
|
-
*/
|
|
88
30
|
void OdinClient::Finalize(Napi::Env env) {
|
|
31
|
+
// Note: SDK lifecycle is managed by OdinRoomWrapper via reference counting.
|
|
32
|
+
// Do NOT call odin_shutdown() here as it would invalidate encoders/decoders
|
|
33
|
+
// that may still be in use by other rooms.
|
|
89
34
|
}
|
|
90
35
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
* @return
|
|
95
|
-
*/
|
|
96
|
-
Napi::Value OdinClient::GenerateAccessToken(const Napi::CallbackInfo &info)
|
|
97
|
-
{
|
|
98
|
-
Napi::Env env = info.Env();
|
|
99
|
-
|
|
100
|
-
if (info.Length() != 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsString()) {
|
|
101
|
-
Napi::TypeError::New(env, "Access-Key, Room and User Id expected").ThrowAsJavaScriptException();
|
|
102
|
-
return env.Undefined();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
std::string accessKey = info[0].ToString().Utf8Value();
|
|
106
|
-
std::string roomId = info[1].ToString().Utf8Value();
|
|
107
|
-
std::string userId = info[2].ToString().Utf8Value();
|
|
108
|
-
|
|
109
|
-
OdinTokenGenerator *generator = odin_token_generator_create(accessKey.c_str());
|
|
110
|
-
if (!generator)
|
|
111
|
-
{
|
|
112
|
-
Napi::TypeError::New(env, "Failed to initialize token generator, invalid access key").ThrowAsJavaScriptException();
|
|
113
|
-
return env.Undefined();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/*
|
|
117
|
-
* Generate a new room token to access the ODIN network
|
|
118
|
-
*/
|
|
119
|
-
char room_token[512];
|
|
120
|
-
OdinReturnCode error = odin_token_generator_create_token(generator, roomId.c_str(), userId.c_str(), room_token, sizeof(room_token));
|
|
121
|
-
if (odin_is_error(error))
|
|
122
|
-
{
|
|
123
|
-
Napi::TypeError::New(env, "Creating access token failed").ThrowAsJavaScriptException();
|
|
124
|
-
return env.Undefined();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/*
|
|
128
|
-
* Destroy the token generator as we don't need it anymore
|
|
129
|
-
*/
|
|
130
|
-
odin_token_generator_destroy(generator);
|
|
131
|
-
|
|
132
|
-
return Napi::String::New(env, room_token);
|
|
36
|
+
Napi::Value OdinClient::GenerateAccessToken(const Napi::CallbackInfo &info) {
|
|
37
|
+
Napi::TypeError::New(info.Env(), "Native token generation is removed in SDK 1.8.2. Use 'jsonwebtoken' or similar to generate JWTs.").ThrowAsJavaScriptException();
|
|
38
|
+
return info.Env().Undefined();
|
|
133
39
|
}
|
|
134
40
|
|
|
135
|
-
/**
|
|
136
|
-
* Create a new room, requires a room id and user id as string as first and second parameter, returns the room instance
|
|
137
|
-
* @param info
|
|
138
|
-
* @return
|
|
139
|
-
*/
|
|
140
41
|
Napi::Value OdinClient::CreateRoom(const Napi::CallbackInfo &info) {
|
|
141
42
|
Napi::Env env = info.Env();
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
Napi::TypeError::New(env, "Access-Key, Room and User Id expected").ThrowAsJavaScriptException();
|
|
145
|
-
return env.Undefined();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
std::string accessKey = info[0].ToString().Utf8Value();
|
|
149
|
-
std::string roomId = info[1].ToString().Utf8Value();
|
|
150
|
-
std::string userId = info[2].ToString().Utf8Value();
|
|
151
|
-
|
|
152
|
-
OdinTokenGenerator *generator = odin_token_generator_create(accessKey.c_str());
|
|
153
|
-
if (!generator)
|
|
154
|
-
{
|
|
155
|
-
Napi::TypeError::New(env, "Failed to initialize token generator, invalid access key").ThrowAsJavaScriptException();
|
|
156
|
-
odin_token_generator_destroy(generator);
|
|
157
|
-
return env.Undefined();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/*
|
|
161
|
-
* Generate a new room token to access the ODIN network
|
|
162
|
-
*/
|
|
163
|
-
char room_token[512];
|
|
164
|
-
OdinReturnCode error = odin_token_generator_create_token(generator, roomId.c_str(), userId.c_str(), room_token, sizeof(room_token));
|
|
165
|
-
if (odin_is_error(error))
|
|
166
|
-
{
|
|
167
|
-
Napi::TypeError::New(env, "Creating access token failed").ThrowAsJavaScriptException();
|
|
168
|
-
odin_token_generator_destroy(generator);
|
|
43
|
+
if (info.Length() < 1 || !info[0].IsString()) {
|
|
44
|
+
Napi::TypeError::New(env, "Token expected").ThrowAsJavaScriptException();
|
|
169
45
|
return env.Undefined();
|
|
170
46
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
* Destroy the token generator as we don't need it anymore
|
|
174
|
-
*/
|
|
175
|
-
odin_token_generator_destroy(generator);
|
|
176
|
-
|
|
177
|
-
return OdinRoom::NewInstance(Napi::String::New(env, room_token));
|
|
47
|
+
std::string token = info[0].ToString().Utf8Value();
|
|
48
|
+
return OdinRoomWrapper::NewInstance(Napi::String::New(env, token));
|
|
178
49
|
}
|
|
179
50
|
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Create a new room with a given access token
|
|
183
|
-
* @param info
|
|
184
|
-
* @return
|
|
185
|
-
*/
|
|
186
51
|
Napi::Value OdinClient::CreateRoomWithAccessToken(const Napi::CallbackInfo &info) {
|
|
187
52
|
Napi::Env env = info.Env();
|
|
188
|
-
|
|
189
|
-
// Check for existence of access token
|
|
190
53
|
if (info.Length() < 1 || !info[0].IsString()) {
|
|
191
54
|
Napi::TypeError::New(env, "Access token expected").ThrowAsJavaScriptException();
|
|
192
55
|
return env.Undefined();
|
|
193
56
|
}
|
|
194
|
-
|
|
195
57
|
std::string token = info[0].ToString().Utf8Value();
|
|
196
|
-
|
|
197
|
-
return OdinRoom::NewInstance(Napi::String::New(env, token));
|
|
58
|
+
return OdinRoomWrapper::NewInstance(Napi::String::New(env, token));
|
|
198
59
|
}
|
package/cppsrc/odinclient.h
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
class OdinClient : public Napi::ObjectWrap<OdinClient> {
|
|
5
5
|
public:
|
|
6
|
-
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
7
|
-
OdinClient(const Napi::CallbackInfo& info);
|
|
6
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
7
|
+
OdinClient(const Napi::CallbackInfo& info);
|
|
8
8
|
void Finalize(Napi::Env env) override;
|
|
9
9
|
private:
|
|
10
10
|
Napi::Value GenerateAccessToken(const Napi::CallbackInfo& info);
|
|
11
11
|
Napi::Value CreateRoom(const Napi::CallbackInfo& info);
|
|
12
12
|
Napi::Value CreateRoomWithAccessToken(const Napi::CallbackInfo& info);
|
|
13
|
-
|
|
14
|
-
float _sampleRate;
|
|
15
|
-
uint32_t _numChannels;
|
|
16
13
|
};
|