@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.
Files changed (73) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/LICENSE +21 -0
  3. package/README.md +603 -44
  4. package/binding.gyp +29 -13
  5. package/cppsrc/binding.cpp +3 -6
  6. package/cppsrc/odinbindings.cpp +9 -45
  7. package/cppsrc/odincipher.cpp +92 -0
  8. package/cppsrc/odincipher.h +32 -0
  9. package/cppsrc/odinclient.cpp +19 -158
  10. package/cppsrc/odinclient.h +2 -5
  11. package/cppsrc/odinmedia.cpp +144 -186
  12. package/cppsrc/odinmedia.h +51 -18
  13. package/cppsrc/odinroom.cpp +675 -635
  14. package/cppsrc/odinroom.h +76 -26
  15. package/cppsrc/utilities.cpp +11 -81
  16. package/cppsrc/utilities.h +25 -140
  17. package/index.cjs +829 -0
  18. package/index.d.ts +3 -4
  19. package/libs/bin/linux/arm64/libodin.so +0 -0
  20. package/libs/bin/linux/arm64/libodin_crypto.so +0 -0
  21. package/libs/bin/linux/ia32/libodin.so +0 -0
  22. package/libs/bin/linux/ia32/libodin_crypto.so +0 -0
  23. package/libs/bin/linux/x64/libodin.so +0 -0
  24. package/libs/bin/linux/x64/libodin_crypto.so +0 -0
  25. package/{prebuilds/darwin-x64/node.napi.node → libs/bin/macos/universal/libodin.dylib} +0 -0
  26. package/libs/bin/macos/universal/libodin_crypto.dylib +0 -0
  27. package/libs/bin/windows/arm64/odin.dll +0 -0
  28. package/libs/bin/windows/arm64/odin.lib +0 -0
  29. package/libs/bin/windows/arm64/odin_crypto.dll +0 -0
  30. package/libs/bin/windows/arm64/odin_crypto.lib +0 -0
  31. package/libs/bin/windows/ia32/odin.dll +0 -0
  32. package/libs/bin/windows/ia32/odin.lib +0 -0
  33. package/libs/bin/windows/ia32/odin_crypto.dll +0 -0
  34. package/libs/bin/windows/ia32/odin_crypto.lib +0 -0
  35. package/libs/bin/windows/x64/odin.dll +0 -0
  36. package/libs/bin/windows/x64/odin.lib +0 -0
  37. package/libs/bin/windows/x64/odin_crypto.dll +0 -0
  38. package/libs/bin/windows/x64/odin_crypto.lib +0 -0
  39. package/libs/include/odin.h +665 -567
  40. package/libs/include/odin_crypto.h +46 -0
  41. package/odin.cipher.d.ts +31 -0
  42. package/odin.media.d.ts +69 -19
  43. package/odin.room.d.ts +348 -7
  44. package/package.json +5 -4
  45. package/prebuilds/{darwin-arm64/node.napi.node → darwin-x64+arm64/libodin.dylib} +0 -0
  46. package/prebuilds/darwin-x64+arm64/libodin_crypto.dylib +0 -0
  47. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  48. package/prebuilds/linux-x64/libodin.so +0 -0
  49. package/prebuilds/linux-x64/libodin_crypto.so +0 -0
  50. package/prebuilds/linux-x64/node.napi.node +0 -0
  51. package/prebuilds/win32-x64/node.napi.node +0 -0
  52. package/prebuilds/win32-x64/odin.dll +0 -0
  53. package/prebuilds/win32-x64/odin_crypto.dll +0 -0
  54. package/scripts/postbuild.cjs +133 -0
  55. package/tests/audio-recording/README.md +97 -12
  56. package/tests/audio-recording/index.js +238 -130
  57. package/tests/connection-test/README.md +97 -0
  58. package/tests/connection-test/index.js +273 -0
  59. package/tests/lifecycle/test-room-cycle.js +169 -0
  60. package/tests/sending-audio/README.md +178 -9
  61. package/tests/sending-audio/canBounce.mp3 +0 -0
  62. package/tests/sending-audio/index.js +250 -87
  63. package/tests/sending-audio/test-kiss-api.js +149 -0
  64. package/tests/sending-audio/test-loop-audio.js +142 -0
  65. package/CMakeLists.txt +0 -25
  66. package/libs/bin/linux/arm64/libodin_static.a +0 -0
  67. package/libs/bin/linux/ia32/libodin_static.a +0 -0
  68. package/libs/bin/linux/x64/libodin_static.a +0 -0
  69. package/libs/bin/macos/arm64/libodin_static.a +0 -0
  70. package/libs/bin/macos/x64/libodin_static.a +0 -0
  71. package/libs/bin/windows/arm64/odin_static.lib +0 -0
  72. package/libs/bin/windows/ia32/odin_static.lib +0 -0
  73. package/libs/bin/windows/x64/odin_static.lib +0 -0
@@ -0,0 +1,149 @@
1
+ /**
2
+ * ODIN Node.js SDK - Audio Sending Example (High-Level API)
3
+ *
4
+ * This example demonstrates the HIGH-LEVEL API for sending audio to an ODIN room.
5
+ * The high-level API handles all the complexity automatically:
6
+ * - Media ID allocation from the Joined event
7
+ * - StartMedia RPC to notify the server
8
+ * - Proper 20ms chunk timing
9
+ * - Audio decoding for MP3/WAV files
10
+ *
11
+ * With the high-level API, sending audio is just:
12
+ * await media.sendMP3('./file.mp3');
13
+ *
14
+ * For full control, see index.js which uses the LOW-LEVEL API.
15
+ *
16
+ * Prerequisites:
17
+ * - Replace __YOUR_ACCESS_KEY__ with your ODIN access key
18
+ * - Get a free access key at https://www.4players.io/odin
19
+ */
20
+
21
+ import odin from '../../index.cjs';
22
+ const { OdinClient, OdinCipher } = odin;
23
+ import path from 'path';
24
+ import { fileURLToPath } from 'url';
25
+
26
+ // Get the directory of the current script
27
+ const __filename = fileURLToPath(import.meta.url);
28
+ const __dirname = path.dirname(__filename);
29
+
30
+ // ============================================
31
+ // Configuration - Replace with your values
32
+ // ============================================
33
+
34
+ /**
35
+ * Your ODIN access key. Get one for free at https://www.4players.io/odin
36
+ * @type {string}
37
+ */
38
+ const accessKey = "__YOUR_ACCESS_KEY__";
39
+
40
+ /**
41
+ * The room ID to join. All users joining the same room can hear your audio.
42
+ * @type {string}
43
+ */
44
+ const roomId = "__YOUR_ROOM_ID__";
45
+
46
+ /**
47
+ * Your unique user identifier.
48
+ * @type {string}
49
+ */
50
+ const userId = "AudioBot-" + Math.floor(Math.random() * 10000);
51
+
52
+ /**
53
+ * Optional: Password for End-to-End Encryption.
54
+ * Set to null to disable, or set a string that matches other peers.
55
+ * @type {string|null}
56
+ */
57
+ const cipherPassword = null;
58
+
59
+ // ============================================
60
+ // Main Function
61
+ // ============================================
62
+
63
+ async function main() {
64
+ console.log("=== ODIN NodeJS SDK - High-Level API Audio Test ===\n");
65
+
66
+ // Step 1: Create ODIN client
67
+ console.log("1. Creating ODIN client...");
68
+ const client = new OdinClient();
69
+
70
+ // Step 2: Generate token from access key
71
+ console.log("2. Generating token from access key...");
72
+ const token = client.generateToken(accessKey, roomId, userId);
73
+ console.log(" Token generated.\n");
74
+
75
+ // Step 3: Create room
76
+ console.log("3. Creating room...");
77
+ const room = client.createRoom(token);
78
+
79
+ // Step 4: Set up E2EE cipher (optional)
80
+ if (cipherPassword) {
81
+ console.log("4. Setting up E2EE cipher...");
82
+ const cipher = new OdinCipher();
83
+ cipher.setPassword(new TextEncoder().encode(cipherPassword));
84
+ room.setCipher(cipher);
85
+ console.log(" E2EE enabled.\n");
86
+ } else {
87
+ console.log("4. E2EE disabled.\n");
88
+ }
89
+
90
+ // Wait for join to complete
91
+ const joinPromise = new Promise(resolve => room.onJoined(resolve));
92
+
93
+ // Prepare user data
94
+ const userData = new TextEncoder().encode(JSON.stringify({
95
+ name: "High-Level API Bot",
96
+ platform: "ODIN Node.js SDK"
97
+ }));
98
+
99
+ // Step 5: Join the room
100
+ console.log("5. Joining room...");
101
+ room.join("https://gateway.odin.4players.io", userData);
102
+
103
+ // Wait for join confirmation
104
+ console.log(" Waiting for room join...");
105
+ const joinEvent = await joinPromise;
106
+ console.log(` Joined! Own Peer ID: ${joinEvent.ownPeerId}`);
107
+ console.log(` Available media IDs: ${JSON.stringify(room.availableMediaIds)}\n`);
108
+
109
+ // Step 6: Create audio stream
110
+ console.log("6. Creating audio stream (44.1kHz, stereo)...");
111
+ const media = room.createAudioStream(44100, 2);
112
+ console.log(" Audio stream created.\n");
113
+
114
+ // Step 7: Send MP3 with one line! (high-level API magic)
115
+ // The sendMP3 method automatically:
116
+ // - Claims a media ID from the available pool
117
+ // - Sends the StartMedia RPC
118
+ // - Decodes the MP3 file
119
+ // - Streams audio in 20ms chunks with correct timing
120
+ console.log("7. Sending MP3 file (auto handles setup & timing)...");
121
+ const audioFile = path.join(__dirname, 'canBounce.mp3');
122
+ console.log(` File: ${audioFile}`);
123
+
124
+ await media.sendMP3(audioFile);
125
+
126
+ console.log(" Audio streaming complete!\n");
127
+
128
+ // Wait a bit for final audio to transmit
129
+ console.log("8. Waiting for transmission to complete...");
130
+ await new Promise(r => setTimeout(r, 2000));
131
+
132
+ // Step 9: Clean up
133
+ console.log("9. Cleaning up...");
134
+ media.close();
135
+ room.close();
136
+ console.log(" Resources released.\n");
137
+
138
+ console.log("=== Test Complete ===");
139
+ process.exit(0);
140
+ }
141
+
142
+ // ============================================
143
+ // Entry Point
144
+ // ============================================
145
+
146
+ main().catch(err => {
147
+ console.error("Error:", err);
148
+ process.exit(1);
149
+ });
@@ -0,0 +1,142 @@
1
+ /**
2
+ * ODIN Node.js SDK - Multiple Audio Sending Test
3
+ *
4
+ * This test verifies that multiple audio files can be sent in sequence
5
+ * within a single room connection. It creates a media stream, sends an MP3,
6
+ * closes the media, waits 5 seconds, and repeats.
7
+ *
8
+ * This is a regression test for issues where sending multiple MP3s in
9
+ * one connection instance would fail.
10
+ */
11
+
12
+ import odin from '../../index.cjs';
13
+ const { OdinClient, OdinCipher } = odin;
14
+ import path from 'path';
15
+ import { fileURLToPath } from 'url';
16
+
17
+ // Get the directory of the current script
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+
21
+ // ============================================
22
+ // Configuration - Replace with your values
23
+ // ============================================
24
+
25
+ const accessKey = "__YOUR_ACCESS_KEY__";
26
+ const roomId = "__YOUR_ROOM_ID__";
27
+ const userId = "LoopBot-" + Math.floor(Math.random() * 10000);
28
+ const cipherPassword = "__YOUR_CIPHER_PASSWORD_OR_NULL__";
29
+
30
+ // Number of times to send the audio file
31
+ const LOOP_COUNT = 3;
32
+
33
+ // Delay between sends (in milliseconds)
34
+ const DELAY_BETWEEN_SENDS = 5000;
35
+
36
+ // ============================================
37
+ // Main Function
38
+ // ============================================
39
+
40
+ async function main() {
41
+ console.log("=== ODIN NodeJS SDK - Multiple Audio Sending Test ===\n");
42
+ console.log(`Will send audio ${LOOP_COUNT} times with ${DELAY_BETWEEN_SENDS}ms delay between sends.\n`);
43
+
44
+ // Step 1: Create ODIN client
45
+ console.log("1. Creating ODIN client...");
46
+ const client = new OdinClient();
47
+
48
+ // Step 2: Generate token from access key
49
+ console.log("2. Generating token from access key...");
50
+ const token = client.generateToken(accessKey, roomId, userId);
51
+ console.log(" Token generated.\n");
52
+
53
+ // Step 3: Create room
54
+ console.log("3. Creating room...");
55
+ const room = client.createRoom(token);
56
+
57
+ // Step 4: Set up E2EE cipher (optional)
58
+ if (cipherPassword) {
59
+ console.log("4. Setting up E2EE cipher...");
60
+ const cipher = new OdinCipher();
61
+ cipher.setPassword(new TextEncoder().encode(cipherPassword));
62
+ room.setCipher(cipher);
63
+ console.log(" E2EE enabled.\n");
64
+ } else {
65
+ console.log("4. E2EE disabled.\n");
66
+ }
67
+
68
+ // Wait for join to complete
69
+ const joinPromise = new Promise(resolve => room.onJoined(resolve));
70
+
71
+ // Prepare user data
72
+ const userData = new TextEncoder().encode(JSON.stringify({
73
+ name: "Loop Audio Bot",
74
+ platform: "ODIN Node.js SDK"
75
+ }));
76
+
77
+ // Step 5: Join the room
78
+ console.log("5. Joining room...");
79
+ room.join("https://gateway.odin.4players.io", userData);
80
+
81
+ // Wait for join confirmation
82
+ console.log(" Waiting for room join...");
83
+ const joinEvent = await joinPromise;
84
+ console.log(` Joined! Own Peer ID: ${joinEvent.ownPeerId}`);
85
+ console.log(` Available media IDs: ${JSON.stringify(room.availableMediaIds)}\n`);
86
+
87
+ const audioFile = path.join(__dirname, 'canBounce.mp3');
88
+
89
+ // Loop: Send audio multiple times
90
+ for (let i = 1; i <= LOOP_COUNT; i++) {
91
+ console.log(`\n========== ITERATION ${i}/${LOOP_COUNT} ==========\n`);
92
+
93
+ // Step 6: Create audio stream
94
+ console.log(`${i}.1 Creating audio stream (44.1kHz, stereo)...`);
95
+ const media = room.createAudioStream(44100, 2);
96
+ console.log(" Audio stream created.");
97
+ console.log(` Available media IDs after create: ${JSON.stringify(room.availableMediaIds)}`);
98
+
99
+ // Step 7: Send MP3 with high-level API
100
+ console.log(`${i}.2 Sending MP3 file...`);
101
+ console.log(` File: ${audioFile}`);
102
+
103
+ try {
104
+ await media.sendMP3(audioFile);
105
+ console.log(" Audio streaming complete!");
106
+ } catch (error) {
107
+ console.error(` ERROR during sendMP3: ${error.message}`);
108
+ console.error(error.stack);
109
+ }
110
+
111
+ // Step 8: Close media
112
+ console.log(`${i}.3 Closing media stream...`);
113
+ media.close();
114
+ console.log(" Media stream closed.");
115
+ console.log(` Available media IDs after close: ${JSON.stringify(room.availableMediaIds)}`);
116
+
117
+ // Wait before next iteration (except on last iteration)
118
+ if (i < LOOP_COUNT) {
119
+ console.log(`\n${i}.4 Waiting ${DELAY_BETWEEN_SENDS}ms before next send...`);
120
+ await new Promise(r => setTimeout(r, DELAY_BETWEEN_SENDS));
121
+ console.log(" Wait complete.");
122
+ }
123
+ }
124
+
125
+ // Final cleanup
126
+ console.log("\n========== CLEANUP ==========\n");
127
+ console.log("Closing room...");
128
+ room.close();
129
+ console.log("Room closed.\n");
130
+
131
+ console.log("=== Test Complete ===");
132
+ process.exit(0);
133
+ }
134
+
135
+ // ============================================
136
+ // Entry Point
137
+ // ============================================
138
+
139
+ main().catch(err => {
140
+ console.error("Error:", err);
141
+ process.exit(1);
142
+ });
package/CMakeLists.txt DELETED
@@ -1,25 +0,0 @@
1
- cmake_minimum_required(VERSION 3.24)
2
- project(odin_nodejs)
3
-
4
- set(CMAKE_CXX_STANDARD 14)
5
-
6
- add_definitions(-DNAPI_VERSION=4)
7
-
8
- include_directories(cppsrc/samples)
9
- include_directories(libs)
10
- include_directories(libs/include)
11
- include_directories(node_modules/node-addon-api)
12
-
13
- add_executable(odin_nodejs
14
- cppsrc/odinbindings.cpp
15
- cppsrc/odinbindings.h
16
- cppsrc/odinroom.cpp
17
- cppsrc/odinroom.h
18
- cppsrc/binding.cpp
19
- libs/include/odin.h
20
- node_modules/node-addon-api/napi-inl.deprecated.h
21
- node_modules/node-addon-api/napi-inl.h
22
- node_modules/node-addon-api/napi.h
23
- node_modules/node-addon-api/nothing.c
24
- node_modules/node-gyp/gyp/data/win/large-pdb-shim.cc
25
- node_modules/node-gyp/src/win_delay_load_hook.cc cppsrc/odinbindings.h cppsrc/odinbindings.cpp cppsrc/odinroom.h cppsrc/odinroom.cpp cppsrc/utilities.cpp cppsrc/utilities.h cppsrc/odinclient.h cppsrc/odinclient.cpp cppsrc/odinmedia.h cppsrc/odinmedia.cpp)
Binary file
Binary file