@4players/odin-nodejs 0.7.0
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/.idea/.name +1 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/misc.xml +4 -0
- package/.idea/modules.xml +9 -0
- package/.idea/odin-nodejs.iml +8 -0
- package/.idea/odin_nodejs.iml +2 -0
- package/.idea/php.xml +19 -0
- package/.idea/vcs.xml +6 -0
- package/CMakeLists.txt +25 -0
- package/README.md +53 -0
- package/binding.gyp +61 -0
- package/build/Makefile +352 -0
- package/build/Release/.deps/Release/nothing.a.d +1 -0
- package/build/Release/.deps/Release/obj.target/nothing/node_modules/node-addon-api/nothing.o.d +4 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/binding.o.d +27 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/odinbindings.o.d +24 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/odinclient.o.d +24 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/odinmedia.o.d +24 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/odinroom.o.d +24 -0
- package/build/Release/.deps/Release/obj.target/odin/cppsrc/utilities.o.d +21 -0
- package/build/Release/.deps/Release/odin.node.d +1 -0
- package/build/Release/nothing.a +0 -0
- package/build/Release/obj.target/nothing/node_modules/node-addon-api/nothing.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/binding.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/odinbindings.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/odinclient.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/odinmedia.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/odinroom.o +0 -0
- package/build/Release/obj.target/odin/cppsrc/utilities.o +0 -0
- package/build/binding.Makefile +6 -0
- package/build/gyp-mac-tool +772 -0
- package/build/node_modules/node-addon-api/node_api.Makefile +6 -0
- package/build/node_modules/node-addon-api/nothing.target.mk +186 -0
- package/build/odin.target.mk +201 -0
- package/cmake-build-debug/.cmake/api/v1/query/cache-v2 +0 -0
- package/cmake-build-debug/.cmake/api/v1/query/cmakeFiles-v1 +0 -0
- package/cmake-build-debug/.cmake/api/v1/query/codemodel-v2 +0 -0
- package/cmake-build-debug/.cmake/api/v1/query/toolchains-v1 +0 -0
- package/cmake-build-debug/.cmake/api/v1/reply/cache-v2-912a6d0c3c2c7ebbadf8.json +1183 -0
- package/cmake-build-debug/.cmake/api/v1/reply/cmakeFiles-v1-0825651e80f1fb47890c.json +161 -0
- package/cmake-build-debug/.cmake/api/v1/reply/codemodel-v2-bc24edc239de864eb886.json +60 -0
- package/cmake-build-debug/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json +14 -0
- package/cmake-build-debug/.cmake/api/v1/reply/index-2023-03-18T11-25-22-0179.json +108 -0
- package/cmake-build-debug/.cmake/api/v1/reply/target-odin_nodejs-Debug-1ac16802f252a85492c7.json +322 -0
- package/cmake-build-debug/.cmake/api/v1/reply/toolchains-v1-b57293a485ebf36c82cc.json +88 -0
- package/cmake-build-debug/.ninja_log +1 -0
- package/cmake-build-debug/CMakeCache.txt +367 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CMakeCCompiler.cmake +72 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CMakeCXXCompiler.cmake +83 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CMakeDetermineCompilerABI_C.bin +0 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CMakeSystem.cmake +15 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CompilerIdC/CMakeCCompilerId.c +838 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CompilerIdC/CMakeCCompilerId.o +0 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +826 -0
- package/cmake-build-debug/CMakeFiles/3.24.2/CompilerIdCXX/CMakeCXXCompilerId.o +0 -0
- package/cmake-build-debug/CMakeFiles/CMakeError.log +22 -0
- package/cmake-build-debug/CMakeFiles/CMakeOutput.log +250 -0
- package/cmake-build-debug/CMakeFiles/TargetDirectories.txt +3 -0
- package/cmake-build-debug/CMakeFiles/clion-Debug-log.txt +4 -0
- package/cmake-build-debug/CMakeFiles/clion-environment.txt +3 -0
- package/cmake-build-debug/CMakeFiles/cmake.check_cache +1 -0
- package/cmake-build-debug/CMakeFiles/rules.ninja +74 -0
- package/cmake-build-debug/Testing/Temporary/LastTest.log +3 -0
- package/cmake-build-debug/build.ninja +205 -0
- package/cmake-build-debug/cmake_install.cmake +49 -0
- package/cppsrc/binding.cpp +15 -0
- package/cppsrc/odinbindings.cpp +58 -0
- package/cppsrc/odinbindings.h +9 -0
- package/cppsrc/odinclient.cpp +162 -0
- package/cppsrc/odinclient.h +17 -0
- package/cppsrc/odinmedia.cpp +242 -0
- package/cppsrc/odinmedia.h +35 -0
- package/cppsrc/odinroom.cpp +738 -0
- package/cppsrc/odinroom.h +65 -0
- package/cppsrc/utilities.cpp +102 -0
- package/cppsrc/utilities.h +175 -0
- package/index.cjs +2 -0
- package/index.d.ts +5 -0
- 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/libs/include/odin.h +896 -0
- package/odin.client.d.ts +22 -0
- package/odin.media.d.ts +33 -0
- package/odin.room.d.ts +473 -0
- package/package.json +50 -0
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/test.js +211 -0
- package/tests/audio-recording/README.md +24 -0
- package/tests/audio-recording/index.js +148 -0
- package/tests/sending-audio/README.md +20 -0
- package/tests/sending-audio/index.js +81 -0
- package/tests/sending-audio/santa.mp3 +0 -0
package/test.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const accessKey = "Ad4R7/hpCx1U5yGvC61oNBeJ/fWiW7dodvXWW7MEwrjg";
|
|
2
|
+
const roomName = "Hallo";
|
|
3
|
+
const userName = "My Bot";
|
|
4
|
+
|
|
5
|
+
import odin from '../../index.cjs';
|
|
6
|
+
const {OdinRoom, OdinClient} = odin;
|
|
7
|
+
|
|
8
|
+
import wav from 'wav';
|
|
9
|
+
import { Configuration, OpenAIApi } from "openai";
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
|
|
12
|
+
const configuration = new Configuration({
|
|
13
|
+
apiKey: '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'
|
|
14
|
+
});
|
|
15
|
+
const openai = new OpenAIApi(configuration);
|
|
16
|
+
|
|
17
|
+
//const token = odin.generateAccessToken(accessKey, roomName, userName);
|
|
18
|
+
//console.log(token);
|
|
19
|
+
|
|
20
|
+
const userData = {
|
|
21
|
+
name: "Recorder Bot",
|
|
22
|
+
seed: "123",
|
|
23
|
+
userId: "Bot007",
|
|
24
|
+
outputMuted: 1,
|
|
25
|
+
platform: "ODIN JS Bot SDK",
|
|
26
|
+
version: "0.1"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const fileRecorder = {};
|
|
30
|
+
|
|
31
|
+
const data = new TextEncoder().encode(JSON.stringify(userData));
|
|
32
|
+
|
|
33
|
+
const odinClient = new OdinClient(accessKey);
|
|
34
|
+
const room2 = odinClient.createRoom(roomName, userName);
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
//odin.startup();
|
|
38
|
+
|
|
39
|
+
//room2 = odin.initRoom(token);
|
|
40
|
+
room2.setEventListener((event) => {
|
|
41
|
+
console.log(event);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
room2.addEventListener('PeerJoined', (event) => {
|
|
45
|
+
console.log("Received PeerJoined event", event);
|
|
46
|
+
console.log(JSON.parse(new TextDecoder().decode(event.userData)));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
room2.addEventListener('PeerLeft', (event) => {
|
|
50
|
+
console.log("Received PeerLeft event", event);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
room2.addEventListener('MediaActivity', (event) => {
|
|
54
|
+
console.log("Media", event);
|
|
55
|
+
if (event.state) {
|
|
56
|
+
// User started talking
|
|
57
|
+
if (!fileRecorder[event.mediaId]) {
|
|
58
|
+
const timer = new Date().getTime();
|
|
59
|
+
const fileName = `./recording_${event.peerId}_${event.mediaId}_${timer}.wav`;
|
|
60
|
+
console.log(fileName);
|
|
61
|
+
fileRecorder[event.mediaId] = {
|
|
62
|
+
wavEncoder: new wav.FileWriter(fileName, {
|
|
63
|
+
channels: 1,
|
|
64
|
+
sampleRate: 48000,
|
|
65
|
+
bitDepth: 16
|
|
66
|
+
}),
|
|
67
|
+
fileName: fileName
|
|
68
|
+
};
|
|
69
|
+
} else {
|
|
70
|
+
if (fileRecorder[event.mediaId].timer) {
|
|
71
|
+
clearTimeout(fileRecorder[event.mediaId].timer);
|
|
72
|
+
delete fileRecorder[event.mediaId].timer;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// User stopped talking
|
|
77
|
+
if (fileRecorder[event.mediaId]) {
|
|
78
|
+
if (!fileRecorder[event.mediaId].timer) {
|
|
79
|
+
fileRecorder[event.mediaId].timer = setTimeout(() => {
|
|
80
|
+
fileRecorder[event.mediaId].wavEncoder.end();
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const file = fs.createReadStream(fileRecorder[event.mediaId].fileName);
|
|
84
|
+
openai.createTranscription(file, "whisper-1").then((response) => {
|
|
85
|
+
console.log("TRANSACTION", response.data.text);
|
|
86
|
+
});
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.log("Failed to transcribe: ", e);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
delete fileRecorder[event.mediaId];
|
|
93
|
+
}, 2000);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
//const input = prompt('Press any key?');
|
|
100
|
+
//const odinClient = new OdinClient(accessKey);
|
|
101
|
+
//const room2 = new OdinRoom(token);
|
|
102
|
+
|
|
103
|
+
room2.join("gateway.odin.4players.io", data);
|
|
104
|
+
|
|
105
|
+
console.log("ROOM-ID:", room2.id);
|
|
106
|
+
|
|
107
|
+
const message = {
|
|
108
|
+
kind: 'message',
|
|
109
|
+
payload: {
|
|
110
|
+
text: 'Hello World'
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const fileWriter = new wav.FileWriter('./recording.wav', {
|
|
115
|
+
channels: 1,
|
|
116
|
+
sampleRate: 48000,
|
|
117
|
+
bitDepth: 16
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
room2.addEventListener('AudioDataReceived', (data) => {
|
|
121
|
+
//console.log("Received AudioDataReceived event from peer", data.peerId, "with mediaId", data.mediaId, "and event", data.samples32);
|
|
122
|
+
//console.log(Float32Array.from(data.samples32));
|
|
123
|
+
|
|
124
|
+
// Getting an array of the sample buffer
|
|
125
|
+
/*
|
|
126
|
+
let ui32 = new Float32Array(data.samples32.buffer);
|
|
127
|
+
console.log(ui32);
|
|
128
|
+
|
|
129
|
+
let ui16 = new Int16Array(data.samples16.buffer);
|
|
130
|
+
console.log(ui16);
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
fileWriter.file.write(data.samples16, (error) => {
|
|
134
|
+
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if (fileRecorder[data.mediaId]) {
|
|
139
|
+
fileRecorder[data.mediaId].wavEncoder.file.write(data.samples16, (error) => {
|
|
140
|
+
if (error) {
|
|
141
|
+
console.log("Failed to write audio file");
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
room2.sendMessage(new TextEncoder().encode(JSON.stringify(message)));
|
|
148
|
+
|
|
149
|
+
console.log("Press any key to stop");
|
|
150
|
+
const stdin = process.stdin;
|
|
151
|
+
stdin.resume();
|
|
152
|
+
stdin.setEncoding( 'utf8' );
|
|
153
|
+
stdin.on( 'data', function( key )
|
|
154
|
+
{
|
|
155
|
+
console.log("Shutting down");
|
|
156
|
+
room2.close();
|
|
157
|
+
fileWriter.end();
|
|
158
|
+
|
|
159
|
+
process.exit();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
/*
|
|
165
|
+
const room = odin.createRoom();
|
|
166
|
+
|
|
167
|
+
let error = 0;
|
|
168
|
+
try {
|
|
169
|
+
error = odin.joinRoom(room, "gateway.odin.4players.io", token);
|
|
170
|
+
} catch(e) {
|
|
171
|
+
console.log(error);
|
|
172
|
+
console.log(odin.formatError(error));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const userData = {
|
|
176
|
+
name: "Recorder Bot",
|
|
177
|
+
seed: "123",
|
|
178
|
+
userId: "Bot007",
|
|
179
|
+
outputMuted: 1,
|
|
180
|
+
platform: "ODIN JS Bot SDK",
|
|
181
|
+
version: "0.1"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const data = new TextEncoder().encode(JSON.stringify(userData));
|
|
185
|
+
|
|
186
|
+
odin.updatePeerUserData(room, data);
|
|
187
|
+
*/
|
|
188
|
+
//const name = prompt('Press any key?');
|
|
189
|
+
/*
|
|
190
|
+
odin.closeRoom(room);
|
|
191
|
+
odin.destroyRoom(room);
|
|
192
|
+
odin.shutdown();
|
|
193
|
+
*/
|
|
194
|
+
/*
|
|
195
|
+
|
|
196
|
+
const tokenGenerator = new TokenGenerator(accessKey);
|
|
197
|
+
const token = tokenGenerator.createToken(roomName, userName);
|
|
198
|
+
|
|
199
|
+
console.log(token);
|
|
200
|
+
|
|
201
|
+
const testAddon = require('./build/Release/testaddon.node')
|
|
202
|
+
console.log(testAddon.hello());
|
|
203
|
+
console.log(testAddon.add(5,10));
|
|
204
|
+
|
|
205
|
+
const classInstance = new testAddon.ClassExample(4.3);
|
|
206
|
+
console.log('Testing class initial value : ',classInstance.getValue());
|
|
207
|
+
console.log('After adding 3.3 : ',classInstance.add(3.3));
|
|
208
|
+
|
|
209
|
+
const odinClient = new testAddon.OdinClient();
|
|
210
|
+
odinClient.joinRoom(accessKey, roomName, userName);
|
|
211
|
+
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ODIN Node JS Sample "Audio Recording"
|
|
2
|
+
|
|
3
|
+
This sample demonstrates how to use the ODIN SDK to record audio from other users and sending these to OpenAI for
|
|
4
|
+
transcription. It also features basic "Bot" functionality like sending a message to the chat.
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
You need to have an ODIN Access Key. See [here](https://www.4players.io/odin/introduction/access-keys/#generating-access-keys))
|
|
9
|
+
for more info on the topic and to create one for free directly in the documentation.
|
|
10
|
+
|
|
11
|
+
This sample also requires an OpenAI API Key for transcription. You can get one for free [here](https://beta.openai.com/).
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
Run the script with the following command:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node index.js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
It will connect to the room `Lobby` using your access key and will send a "Hello World" message to the chat. It will
|
|
22
|
+
then wait for users start to talk and will record their audio into a file. The file name will be the user's name with a
|
|
23
|
+
timestamp and will be a WAV file. 2 seconds after the user stops talking, the recording will be stopped and the file
|
|
24
|
+
will be sent to OpenAI for transcription.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const accessKey = "__YOUR_ACCESS_KEY__";
|
|
2
|
+
const roomName = "Lobby";
|
|
3
|
+
const userName = "My Bot";
|
|
4
|
+
|
|
5
|
+
// Load the odin module
|
|
6
|
+
import odin from '../../index.cjs';
|
|
7
|
+
const {OdinClient} = odin;
|
|
8
|
+
|
|
9
|
+
// Import wav module and OpenAI API
|
|
10
|
+
import wav from 'wav';
|
|
11
|
+
import { Configuration, OpenAIApi } from "openai";
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
|
|
14
|
+
// Configure OpenAI - use your own API key
|
|
15
|
+
const configuration = new Configuration({
|
|
16
|
+
apiKey: '__YOUR_OPENAI_API_KEY__'
|
|
17
|
+
});
|
|
18
|
+
const openai = new OpenAIApi(configuration);
|
|
19
|
+
|
|
20
|
+
// Create an odin client instance using our access key and create a room
|
|
21
|
+
const odinClient = new OdinClient(accessKey);
|
|
22
|
+
const room = odinClient.createRoom(roomName, userName);
|
|
23
|
+
|
|
24
|
+
// Listen on PeerJoined messages and print the user data of the joined peer
|
|
25
|
+
room.addEventListener('PeerJoined', (event) => {
|
|
26
|
+
console.log("Received PeerJoined event", event);
|
|
27
|
+
console.log(JSON.parse(new TextDecoder().decode(event.userData)));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Listen on PeerLeft messages and print the user data of the left peer
|
|
31
|
+
room.addEventListener('PeerLeft', (event) => {
|
|
32
|
+
console.log("Received PeerLeft event", event);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Listen on MediaActivity messages and prepare a wav file for each media stream. The basic idea here is to
|
|
36
|
+
// create a WAV encoder file whenever a users starts talking and to close the file when the user stops talking. This way,
|
|
37
|
+
// we have isolated WAV files for each user and can transcribe them individually. If we don't want to create new files
|
|
38
|
+
// during short pauses, we wait 2 seconds before closing the file.
|
|
39
|
+
room.addEventListener('MediaActivity', (event) => {
|
|
40
|
+
if (event.state) {
|
|
41
|
+
// User started talking - prepare a new file
|
|
42
|
+
if (!fileRecorder[event.mediaId]) {
|
|
43
|
+
const timer = new Date().getTime();
|
|
44
|
+
const fileName = `./recording_${event.peerId}_${event.mediaId}_${timer}.wav`;
|
|
45
|
+
console.log("Created a new recording file: ", fileName);
|
|
46
|
+
fileRecorder[event.mediaId] = {
|
|
47
|
+
wavEncoder: new wav.FileWriter(fileName, {
|
|
48
|
+
channels: 1,
|
|
49
|
+
sampleRate: 48000,
|
|
50
|
+
bitDepth: 16
|
|
51
|
+
}),
|
|
52
|
+
fileName: fileName
|
|
53
|
+
};
|
|
54
|
+
} else {
|
|
55
|
+
// We already have a file for this media stream - reset the timer to avoid closing the file
|
|
56
|
+
if (fileRecorder[event.mediaId].timer) {
|
|
57
|
+
clearTimeout(fileRecorder[event.mediaId].timer);
|
|
58
|
+
delete fileRecorder[event.mediaId].timer;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
// User stopped talking
|
|
63
|
+
if (fileRecorder[event.mediaId]) {
|
|
64
|
+
// If we don't have a timer yet, create one
|
|
65
|
+
if (!fileRecorder[event.mediaId].timer) {
|
|
66
|
+
fileRecorder[event.mediaId].timer = setTimeout(() => {
|
|
67
|
+
// The timer timed out - i.e. the user did stop talking for 2 seconds - close the file
|
|
68
|
+
fileRecorder[event.mediaId].wavEncoder.end();
|
|
69
|
+
|
|
70
|
+
// Transcribe the file using OpenAI
|
|
71
|
+
try {
|
|
72
|
+
const file = fs.createReadStream(fileRecorder[event.mediaId].fileName);
|
|
73
|
+
openai.createTranscription(file, "whisper-1").then((response) => {
|
|
74
|
+
console.log("OpenAI Transcription: ", response.data.text);
|
|
75
|
+
});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.log("Failed to transcribe: ", e);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Delete the file recorder object
|
|
81
|
+
delete fileRecorder[event.mediaId];
|
|
82
|
+
}, 2000);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Configure user data used by the bot - this user data will be compatible with ODIN Web Client (https://odin.4players.de/app).
|
|
89
|
+
const userData = {
|
|
90
|
+
name: "Recorder Bot",
|
|
91
|
+
seed: "123",
|
|
92
|
+
userId: "Bot007",
|
|
93
|
+
outputMuted: 1,
|
|
94
|
+
platform: "ODIN JS Bot SDK",
|
|
95
|
+
version: "0.1"
|
|
96
|
+
}
|
|
97
|
+
// Create a byte array from the user data (ODIN uses byte arrays for user data for maximum flexibility)
|
|
98
|
+
const data = new TextEncoder().encode(JSON.stringify(userData));
|
|
99
|
+
|
|
100
|
+
// Join the room using the default gateway and our user data
|
|
101
|
+
room.join("gateway.odin.4players.io", data);
|
|
102
|
+
|
|
103
|
+
// Print the room-id
|
|
104
|
+
console.log("ROOM-ID:", room.id);
|
|
105
|
+
|
|
106
|
+
// Add an event filter for audio data received events
|
|
107
|
+
room.addEventListener('AudioDataReceived', (data) => {
|
|
108
|
+
// Getting an array of the sample buffer - use for example to visualize audio
|
|
109
|
+
/*
|
|
110
|
+
let ui32 = new Float32Array(data.samples32.buffer);
|
|
111
|
+
console.log(ui32);
|
|
112
|
+
|
|
113
|
+
let ui16 = new Int16Array(data.samples16.buffer);
|
|
114
|
+
console.log(ui16);
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
// Write the audio data to the file using a WAV encoder
|
|
118
|
+
if (fileRecorder[data.mediaId]) {
|
|
119
|
+
fileRecorder[data.mediaId].wavEncoder.file.write(data.samples16, (error) => {
|
|
120
|
+
if (error) {
|
|
121
|
+
console.log("Failed to write audio file");
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Prepare a message compatible with the ODIN Web Client and send it to all users (see @4players/odin-foundation for more info)
|
|
128
|
+
const message = {
|
|
129
|
+
kind: 'message',
|
|
130
|
+
payload: {
|
|
131
|
+
text: 'Hello World'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
room.sendMessage(new TextEncoder().encode(JSON.stringify(message)));
|
|
135
|
+
|
|
136
|
+
// Wait for a key press to stop the script
|
|
137
|
+
console.log("Press any key to stop");
|
|
138
|
+
const stdin = process.stdin;
|
|
139
|
+
stdin.resume();
|
|
140
|
+
stdin.setEncoding( 'utf8' );
|
|
141
|
+
stdin.on( 'data', function( key )
|
|
142
|
+
{
|
|
143
|
+
console.log("Shutting down");
|
|
144
|
+
room.close();
|
|
145
|
+
fileWriter.end();
|
|
146
|
+
|
|
147
|
+
process.exit();
|
|
148
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# ODIN Send Music Example
|
|
2
|
+
|
|
3
|
+
This sample demonstrates how to use the ODIN SDK to send music to other users in a room. It loads a sample MP3 file,
|
|
4
|
+
decodes it and sends it to the ODIN server.
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
You need to have an ODIN Access Key. See [here](https://www.4players.io/odin/introduction/access-keys/#generating-access-keys))
|
|
9
|
+
for more info on the topic and to create one for free directly in the documentation.
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
Run the script with the following command:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
node index.js
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
It will connect to the room `Lobby` using your access key and will send a "Hello World" message to the chat. It will then
|
|
20
|
+
start sending an MP3 file into the room.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const accessKey = "__YOUR_ACCESS_KEY__";
|
|
2
|
+
const roomName = "Lobby";
|
|
3
|
+
const userName = "My Bot";
|
|
4
|
+
|
|
5
|
+
// Load the odin module and other libs
|
|
6
|
+
import odin from '../../index.cjs';
|
|
7
|
+
const {OdinClient} = odin;
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import decode, {decoders} from 'audio-decode';
|
|
10
|
+
import AudioBufferStream from 'audio-buffer-stream';
|
|
11
|
+
|
|
12
|
+
// Create an odin client instance using our access key and create a room
|
|
13
|
+
const userData = {
|
|
14
|
+
name: "Music Bot",
|
|
15
|
+
avatar: "https://avatars.dicebear.com/api/bottts/123.svg?backgroundColor=%23333333&textureChance=0&margin=10",
|
|
16
|
+
seed: "123",
|
|
17
|
+
userId: "Bot007",
|
|
18
|
+
outputMuted: 1,
|
|
19
|
+
inputMuted: 0,
|
|
20
|
+
platform: "ODIN JS Bot SDK",
|
|
21
|
+
version: "0.1"
|
|
22
|
+
}
|
|
23
|
+
const data = new TextEncoder().encode(JSON.stringify(userData));
|
|
24
|
+
const odinClient = new OdinClient(accessKey, 44100, 1);
|
|
25
|
+
const room = odinClient.createRoom(roomName, userName);
|
|
26
|
+
|
|
27
|
+
// Join the room
|
|
28
|
+
room.join("gateway.odin.4players.io", data);
|
|
29
|
+
|
|
30
|
+
// Send a message to the room
|
|
31
|
+
const message = {
|
|
32
|
+
kind: 'message',
|
|
33
|
+
payload: {
|
|
34
|
+
text: 'Hello, I am a music bot and will stream some music to you.'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
room.sendMessage(new TextEncoder().encode(JSON.stringify(message)));
|
|
38
|
+
|
|
39
|
+
// Send music to the room
|
|
40
|
+
const sendMusic = async (media) => {
|
|
41
|
+
// Prepare our MP3 decoder and load the sample file
|
|
42
|
+
const audioBuffer = await decode(fs.readFileSync('./santa.mp3'));
|
|
43
|
+
|
|
44
|
+
// Print our some info about the audio file
|
|
45
|
+
console.log(audioBuffer);
|
|
46
|
+
|
|
47
|
+
// Create a stream that will match the settings of the file
|
|
48
|
+
const audioBufferStream = new AudioBufferStream({channels: 1, sampleRate: 44100, float: true, bitDepth: 32});
|
|
49
|
+
|
|
50
|
+
// Whenever the stream has data, send it to the media stream
|
|
51
|
+
audioBufferStream.on('data', (data) => {
|
|
52
|
+
const floats = new Float32Array(new Uint8Array(data).buffer)
|
|
53
|
+
media.sendAudioData(floats);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
audioBufferStream.write(audioBuffer);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Create a media stream in the room - it will return an OdinMedia instance that we can use to send data to ODIN
|
|
60
|
+
const media = room.createAudioStream(44100, 1);
|
|
61
|
+
console.log(media);
|
|
62
|
+
console.log("MEDIA-ID:", media.id);
|
|
63
|
+
|
|
64
|
+
// Start the stream and send the music to ODIN
|
|
65
|
+
sendMusic(media).then(() => {
|
|
66
|
+
console.log("Finished sending song");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Wait until the user presses a key to stop
|
|
70
|
+
console.log("Press any key to stop");
|
|
71
|
+
const stdin = process.stdin;
|
|
72
|
+
stdin.resume();
|
|
73
|
+
stdin.setEncoding( 'utf8' );
|
|
74
|
+
stdin.on( 'data', function( key )
|
|
75
|
+
{
|
|
76
|
+
console.log("Shutting down");
|
|
77
|
+
room.close();
|
|
78
|
+
|
|
79
|
+
process.exit();
|
|
80
|
+
});
|
|
81
|
+
|
|
Binary file
|