@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
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Phillip Schuster on 11.02.23.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#include "odinroom.h"
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <iostream>
|
|
8
|
+
#include <codecvt>
|
|
9
|
+
#include <locale>
|
|
10
|
+
#include "odinmedia.h"
|
|
11
|
+
|
|
12
|
+
using namespace std;
|
|
13
|
+
|
|
14
|
+
// Required, otherwise an unknown symbol error comes up
|
|
15
|
+
Napi::FunctionReference* OdinRoom::constructor;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Prepares a NAPI value object for the event
|
|
19
|
+
* @param env
|
|
20
|
+
* @param event The event data
|
|
21
|
+
* @return
|
|
22
|
+
*/
|
|
23
|
+
Napi::Object OdinRoom::PrepareEventObject(Napi::Env env, const EventData *event) {
|
|
24
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
25
|
+
obj.Set("event", event->Event);
|
|
26
|
+
obj.Set("tag", (int)event->Tag);
|
|
27
|
+
switch(event->Tag) {
|
|
28
|
+
case OdinEvent_Joined: {
|
|
29
|
+
const JoinedEventData *joined = static_cast<const JoinedEventData*>(event);
|
|
30
|
+
obj.Set("roomId", joined->RoomId);
|
|
31
|
+
obj.Set("ownPeerId", joined->PeerId);
|
|
32
|
+
obj.Set("ownUserId", joined->UserId);
|
|
33
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, (void*)joined->Data, joined->DataLen);
|
|
34
|
+
Napi::Uint8Array array = Napi::Uint8Array::New(env, joined->DataLen, buffer, 0, napi_uint8_array);
|
|
35
|
+
obj.Set("roomUserData", array);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case OdinEvent_PeerJoined: {
|
|
39
|
+
const PeerJoinedEventData *joined = static_cast<const PeerJoinedEventData*>(event);
|
|
40
|
+
obj.Set("peerId", joined->PeerId);
|
|
41
|
+
obj.Set("userId", joined->UserId);
|
|
42
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, (void*)joined->Data, joined->DataLen);
|
|
43
|
+
Napi::Uint8Array array = Napi::Uint8Array::New(env, joined->DataLen, buffer, 0, napi_uint8_array);
|
|
44
|
+
obj.Set("userData", array);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case OdinEvent_PeerLeft: {
|
|
48
|
+
const PeerLeftEventData *left = static_cast<const PeerLeftEventData*>(event);
|
|
49
|
+
obj.Set("peerId", left->PeerId);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case OdinEvent_PeerUserDataChanged: {
|
|
53
|
+
const PeerUserDataChangedEventData *changed = static_cast<const PeerUserDataChangedEventData*>(event);
|
|
54
|
+
obj.Set("peerId", changed->PeerId);
|
|
55
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, (void*)changed->Data, changed->DataLen);
|
|
56
|
+
Napi::Uint8Array array = Napi::Uint8Array::New(env, changed->DataLen, buffer, 0, napi_uint8_array);
|
|
57
|
+
obj.Set("userData", array);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case OdinEvent_RoomUserDataChanged: {
|
|
61
|
+
const RoomUserDataChangedEventData *changed = static_cast<const RoomUserDataChangedEventData*>(event);
|
|
62
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, (void*)changed->Data, changed->DataLen);
|
|
63
|
+
Napi::Uint8Array array = Napi::Uint8Array::New(env, changed->DataLen, buffer, 0, napi_uint8_array);
|
|
64
|
+
obj.Set("userData", array);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case OdinEvent_MessageReceived: {
|
|
68
|
+
const MessageReceivedEventData *message = static_cast<const MessageReceivedEventData*>(event);
|
|
69
|
+
obj.Set("peerId", message->PeerId);
|
|
70
|
+
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, (void*)message->Data, message->DataLen);
|
|
71
|
+
Napi::Uint8Array array = Napi::Uint8Array::New(env, message->DataLen, buffer, 0, napi_uint8_array);
|
|
72
|
+
obj.Set("messageData", array);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case OdinEvent_RoomConnectionStateChanged: {
|
|
76
|
+
const RoomConnectionStateChangedEventData *state = static_cast<const RoomConnectionStateChangedEventData*>(event);
|
|
77
|
+
obj.Set("state", state->StateName);
|
|
78
|
+
obj.Set("reason", state->ReasonName);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case OdinEvent_MediaAdded: {
|
|
82
|
+
const MediaAddedEventData *added = static_cast<const MediaAddedEventData*>(event);
|
|
83
|
+
obj.Set("peerId", added->PeerId);
|
|
84
|
+
obj.Set("mediaId", added->MediaId);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case OdinEvent_MediaRemoved: {
|
|
88
|
+
const MediaRemovedEventData *removed = static_cast<const MediaRemovedEventData*>(event);
|
|
89
|
+
obj.Set("peerId", removed->PeerId);
|
|
90
|
+
obj.Set("mediaId", removed->MediaId);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case OdinEvent_MediaActiveStateChanged: {
|
|
94
|
+
const MediaActiveStateChangedEventData *activity = static_cast<const MediaActiveStateChangedEventData*>(event);
|
|
95
|
+
obj.Set("peerId", activity->PeerId);
|
|
96
|
+
obj.Set("mediaId", activity->MediaId);
|
|
97
|
+
obj.Set("state", activity->Active);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return obj;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the room id as string of this room instance
|
|
107
|
+
* @param info
|
|
108
|
+
*/
|
|
109
|
+
Napi::Value OdinRoom::RoomId(const Napi::CallbackInfo &info) {
|
|
110
|
+
Napi::Env env = info.Env();
|
|
111
|
+
|
|
112
|
+
char out_id[512];
|
|
113
|
+
OdinReturnCode error = odin_room_id(_roomHandle, out_id, sizeof(out_id));
|
|
114
|
+
if (odin_is_error(error))
|
|
115
|
+
{
|
|
116
|
+
Napi::TypeError::New(env, "Failed to get room id").ThrowAsJavaScriptException();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return Napi::String::New(env, out_id);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Returns the room handle of this room instance
|
|
124
|
+
*/
|
|
125
|
+
OdinRoomHandle OdinRoom::GetRoomHandle() const {
|
|
126
|
+
return _roomHandle;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns the media id of a media stream handle, used internally to map media stream handles to media ids in event callbacks
|
|
131
|
+
*/
|
|
132
|
+
uint16_t OdinRoom::GetMediaIdFromHandle(OdinMediaStreamHandle handle)
|
|
133
|
+
{
|
|
134
|
+
uint16_t media_id;
|
|
135
|
+
int error = odin_media_stream_media_id(handle, &media_id);
|
|
136
|
+
return odin_is_error(error) ? 0 : media_id;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Creates an EventData object instance from an OdinEvent. As OdinEvents are allocated on the Odin SDK side, we need to
|
|
141
|
+
* copy the data as the callbacks to the JS side are asynchronous.
|
|
142
|
+
* @param event
|
|
143
|
+
* @return EventData
|
|
144
|
+
*/
|
|
145
|
+
EventData* OdinRoom::PrepareEventData(OdinEvent* event)
|
|
146
|
+
{
|
|
147
|
+
switch(event->tag) {
|
|
148
|
+
case OdinEvent_Joined: {
|
|
149
|
+
JoinedEventData* data = new JoinedEventData();
|
|
150
|
+
data->Tag = event->tag;
|
|
151
|
+
data->Event = "Joined";
|
|
152
|
+
data->RoomId = event->joined.room_id;
|
|
153
|
+
data->UserId = event->joined.own_user_id;
|
|
154
|
+
data->PeerId = event->joined.own_peer_id;
|
|
155
|
+
data->SetData(event->joined.room_user_data, event->joined.room_user_data_len);
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
case OdinEvent_PeerJoined: {
|
|
159
|
+
PeerJoinedEventData* data = new PeerJoinedEventData();
|
|
160
|
+
data->Tag = event->tag;
|
|
161
|
+
data->Event = "PeerJoined";
|
|
162
|
+
data->PeerId = event->peer_joined.peer_id;
|
|
163
|
+
data->UserId = event->peer_joined.user_id;
|
|
164
|
+
data->SetData(event->peer_joined.peer_user_data, event->peer_joined.peer_user_data_len);
|
|
165
|
+
return data;
|
|
166
|
+
}
|
|
167
|
+
case OdinEvent_PeerLeft: {
|
|
168
|
+
PeerLeftEventData* data = new PeerLeftEventData();
|
|
169
|
+
data->Tag = event->tag;
|
|
170
|
+
data->Event = "PeerLeft";
|
|
171
|
+
data->PeerId = event->peer_left.peer_id;
|
|
172
|
+
return data;
|
|
173
|
+
}
|
|
174
|
+
case OdinEvent_PeerUserDataChanged: {
|
|
175
|
+
PeerUserDataChangedEventData* data = new PeerUserDataChangedEventData();
|
|
176
|
+
data->Tag = event->tag;
|
|
177
|
+
data->Event = "PeerUserDataChanged";
|
|
178
|
+
data->PeerId = event->peer_user_data_changed.peer_id;
|
|
179
|
+
data->SetData(event->peer_user_data_changed.peer_user_data, event->peer_user_data_changed.peer_user_data_len);
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
case OdinEvent_RoomUserDataChanged: {
|
|
183
|
+
RoomUserDataChangedEventData* data = new RoomUserDataChangedEventData();
|
|
184
|
+
data->Tag = event->tag;
|
|
185
|
+
data->Event = "RoomUserDataChanged";
|
|
186
|
+
data->SetData(event->room_user_data_changed.room_user_data, event->room_user_data_changed.room_user_data_len);
|
|
187
|
+
return data;
|
|
188
|
+
}
|
|
189
|
+
case OdinEvent_MessageReceived: {
|
|
190
|
+
MessageReceivedEventData* data = new MessageReceivedEventData();
|
|
191
|
+
data->Tag = event->tag;
|
|
192
|
+
data->Event = "MessageReceived";
|
|
193
|
+
data->PeerId = event->message_received.peer_id;
|
|
194
|
+
data->SetData(event->message_received.data, event->message_received.data_len);
|
|
195
|
+
return data;
|
|
196
|
+
}
|
|
197
|
+
case OdinEvent_RoomConnectionStateChanged: {
|
|
198
|
+
RoomConnectionStateChangedEventData* data = new RoomConnectionStateChangedEventData();
|
|
199
|
+
data->Tag = event->tag;
|
|
200
|
+
data->Event = "ConnectionStateChanged";
|
|
201
|
+
data->State = (int)event->room_connection_state_changed.state;
|
|
202
|
+
data->Reason = (int)event->room_connection_state_changed.reason;
|
|
203
|
+
data->StateName = OdinUtilities::GetNameFromConnectionState(event->room_connection_state_changed.state);
|
|
204
|
+
data->ReasonName = OdinUtilities::GetNameFromConnectionStateChangeReason(event->room_connection_state_changed.reason);
|
|
205
|
+
return data;
|
|
206
|
+
}
|
|
207
|
+
case OdinEvent_MediaAdded: {
|
|
208
|
+
MediaAddedEventData* data = new MediaAddedEventData();
|
|
209
|
+
data->Tag = event->tag;
|
|
210
|
+
data->Event = "MediaAdded";
|
|
211
|
+
data->PeerId = event->media_added.peer_id;
|
|
212
|
+
data->MediaId = GetMediaIdFromHandle(event->media_added.media_handle);
|
|
213
|
+
data->MediaStreamHandle = event->media_added.media_handle;
|
|
214
|
+
return data;
|
|
215
|
+
}
|
|
216
|
+
case OdinEvent_MediaRemoved: {
|
|
217
|
+
MediaRemovedEventData* data = new MediaRemovedEventData();
|
|
218
|
+
data->Tag = event->tag;
|
|
219
|
+
data->Event = "MediaRemoved";
|
|
220
|
+
data->PeerId = event->media_removed.peer_id;
|
|
221
|
+
data->MediaId = GetMediaIdFromHandle(event->media_removed.media_handle);
|
|
222
|
+
return data;
|
|
223
|
+
}
|
|
224
|
+
case OdinEvent_MediaActiveStateChanged: {
|
|
225
|
+
MediaActiveStateChangedEventData *data = new MediaActiveStateChangedEventData();
|
|
226
|
+
data->Tag = event->tag;
|
|
227
|
+
data->Event = "MediaActivity";
|
|
228
|
+
data->PeerId = event->media_active_state_changed.peer_id;
|
|
229
|
+
data->MediaId = GetMediaIdFromHandle(event->media_active_state_changed.media_handle);
|
|
230
|
+
data->Active = event->media_active_state_changed.active;
|
|
231
|
+
return data;
|
|
232
|
+
}
|
|
233
|
+
default:
|
|
234
|
+
return NULL;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return NULL;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Callback function for Odin events. This function is called by the Odin SDK when an event occurs. It creates an EventData
|
|
242
|
+
* object instance from the OdinEvent and calls the JavaScript callback function with the event data.
|
|
243
|
+
* @param room OdinRoomHandle
|
|
244
|
+
* @param event OdinEvent
|
|
245
|
+
* @param data void* Pointer to the OdinRoom instance
|
|
246
|
+
*/
|
|
247
|
+
void OdinRoom::HandleOdinEvent(OdinRoomHandle room, const OdinEvent *event, void *data)
|
|
248
|
+
{
|
|
249
|
+
OdinRoom* odinRoom = (OdinRoom*)data;
|
|
250
|
+
if (odinRoom != NULL) {
|
|
251
|
+
|
|
252
|
+
::uint16_t mediaId = OdinRoom::GetMediaIdFromHandle(event->media_added.media_handle);
|
|
253
|
+
if (event->tag == OdinEvent_MediaAdded) {
|
|
254
|
+
Media media;
|
|
255
|
+
media.PeerId = event->media_added.peer_id;
|
|
256
|
+
media.Id = mediaId;
|
|
257
|
+
media.Handle = event->media_added.media_handle;
|
|
258
|
+
odinRoom->_mediaStreams[media.Id] = media;
|
|
259
|
+
} else if (event->tag == OdinEvent_MediaRemoved) {
|
|
260
|
+
if (odinRoom->_mediaStreams.find(mediaId) != odinRoom->_mediaStreams.end()) {
|
|
261
|
+
odinRoom->_mediaStreams.erase(mediaId);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
auto callback = []( Napi::Env env, Napi::Function jsCallback, void* value ) {
|
|
266
|
+
EventData* eventData = (EventData*)value;
|
|
267
|
+
if (eventData == NULL) {
|
|
268
|
+
// I have no idea how to call a function without a parameter ;-)
|
|
269
|
+
// This should never happen anyway
|
|
270
|
+
jsCallback.Call({Napi::Number::New( env, 42 )});
|
|
271
|
+
} else {
|
|
272
|
+
Napi::Object obj = PrepareEventObject(env, eventData);
|
|
273
|
+
jsCallback.Call( {obj} );
|
|
274
|
+
delete eventData;
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
if (odinRoom->_eventListener != NULL)
|
|
278
|
+
{
|
|
279
|
+
EventData* data = odinRoom->PrepareEventData((OdinEvent*)event);
|
|
280
|
+
#ifdef DEBUG
|
|
281
|
+
printf("Odin NodeJS Addon: Sending event to JS: %s\n", data->Event.c_str());
|
|
282
|
+
#endif
|
|
283
|
+
odinRoom->_eventListener.BlockingCall( (void*)data, callback );
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
EventData* data = odinRoom->PrepareEventData((OdinEvent*)event);
|
|
287
|
+
Napi::ThreadSafeFunction function = odinRoom->_eventListeners[data->Event];
|
|
288
|
+
if (function != NULL) {
|
|
289
|
+
function.BlockingCall( (void*)data, callback );
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
} else {
|
|
293
|
+
printf("Odin NodeJS Addon: No room available when handling events - this should NEVER HAPPEN.\n");
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Creates a new OdinRoom instance. Requires an Odin token as a parameter.
|
|
299
|
+
* @param info Napi::CallbackInfo
|
|
300
|
+
*/
|
|
301
|
+
OdinRoom::OdinRoom(const Napi::CallbackInfo& info) :Napi::ObjectWrap<OdinRoom>(info) {
|
|
302
|
+
Napi::Env env = info.Env();
|
|
303
|
+
|
|
304
|
+
if (info.Length() != 1 || !info[0].IsString()) {
|
|
305
|
+
Napi::TypeError::New(env, "Provide a token to create a room").ThrowAsJavaScriptException();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
_token = info[0].ToString().Utf8Value();
|
|
309
|
+
_roomHandle = odin_room_create();
|
|
310
|
+
_started = false;
|
|
311
|
+
_joined = false;
|
|
312
|
+
|
|
313
|
+
odin_room_set_event_callback(_roomHandle, OdinRoom::HandleOdinEvent, this);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Destructor. Closes and destroys the OdinRoom and resets the event callback for this room handle.
|
|
318
|
+
*/
|
|
319
|
+
void OdinRoom::Finalize(Napi::Env env) {
|
|
320
|
+
odin_room_set_event_callback(_roomHandle, NULL, NULL);
|
|
321
|
+
odin_room_close(_roomHandle);
|
|
322
|
+
odin_room_destroy(_roomHandle);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Exposes this class to JavaScript
|
|
327
|
+
* @param info Napi::CallbackInfo
|
|
328
|
+
*/
|
|
329
|
+
Napi::Object OdinRoom::Init(Napi::Env env, Napi::Object exports) {
|
|
330
|
+
// This method is used to hook the accessor and method callbacks
|
|
331
|
+
Napi::Function func = DefineClass(env, "OdinRoom", {
|
|
332
|
+
InstanceMethod<&OdinRoom::Join>("join", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
333
|
+
InstanceMethod<&OdinRoom::UpdatePeerUserData>("updateOwnUserData", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
334
|
+
InstanceMethod<&OdinRoom::UpdateRoomUserData>("updateRoomUserData", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
335
|
+
InstanceMethod<&OdinRoom::SendMessage>("sendMessage", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
336
|
+
InstanceMethod<&OdinRoom::SetEventListener>("setEventListener", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
337
|
+
InstanceMethod<&OdinRoom::AddEventListener>("addEventListener", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
338
|
+
InstanceMethod<&OdinRoom::RemoveEventListener>("removeEventListener", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
339
|
+
InstanceMethod<&OdinRoom::Close>("close", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
340
|
+
InstanceMethod<&OdinRoom::CreateAudioStream>("createAudioStream", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
341
|
+
InstanceAccessor("ownPeerId", &OdinRoom::GetOwnPeerId, nullptr, static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
342
|
+
InstanceAccessor("id", &OdinRoom::RoomId, nullptr, static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
343
|
+
StaticMethod<&OdinRoom::CreateNewItem>("CreateNewItem", static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// We use a static variable to store the constructor. This is because we need to create instances within C++ and
|
|
347
|
+
// expose to JavaScript. We can't use the constructor directly because it's not exposed to JavaScript.
|
|
348
|
+
constructor = new Napi::FunctionReference();
|
|
349
|
+
|
|
350
|
+
// Create a persistent reference to the class constructor. This will allow
|
|
351
|
+
// a function called on a class prototype and a function
|
|
352
|
+
// called on instance of a class to be distinguished from each other.
|
|
353
|
+
*constructor = Napi::Persistent(func);
|
|
354
|
+
exports.Set("OdinRoom", func);
|
|
355
|
+
|
|
356
|
+
// Store the constructor as the add-on instance data. This will allow this
|
|
357
|
+
// add-on to support multiple instances of itself running on multiple worker
|
|
358
|
+
// threads, as well as multiple instances of itself running in different
|
|
359
|
+
// contexts on the same thread.
|
|
360
|
+
//
|
|
361
|
+
// By default, the value set on the environment here will be destroyed when
|
|
362
|
+
// the add-on is unloaded using the `delete` operator, but it is also
|
|
363
|
+
// possible to supply a custom deleter.
|
|
364
|
+
env.SetInstanceData<Napi::FunctionReference>(constructor);
|
|
365
|
+
|
|
366
|
+
return exports;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Joins the Odin room. Requires a gateway URL as a parameter and optionally initial peer data.
|
|
371
|
+
* @param info Napi::CallbackInfo
|
|
372
|
+
*/
|
|
373
|
+
void OdinRoom::Join(const Napi::CallbackInfo &info) {
|
|
374
|
+
Napi::Env env = info.Env();
|
|
375
|
+
|
|
376
|
+
if (info.Length() < 1) {
|
|
377
|
+
Napi::TypeError::New(env, "Gateway required as first parameter").ThrowAsJavaScriptException();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
std::string url = info[0].ToString().Utf8Value();
|
|
381
|
+
|
|
382
|
+
if (info.Length() > 1) {
|
|
383
|
+
Napi::Uint8Array data = info[1].As<Napi::Uint8Array>();
|
|
384
|
+
OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Peer, data.Data(), data.ByteLength());
|
|
385
|
+
if (odin_is_error(error))
|
|
386
|
+
{
|
|
387
|
+
Napi::TypeError::New(env, "Setting initial room peer data failed").ThrowAsJavaScriptException();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
OdinReturnCode error = odin_room_join(_roomHandle, url.c_str(), _token.c_str());
|
|
392
|
+
if (odin_is_error(error))
|
|
393
|
+
{
|
|
394
|
+
OdinUtilities::ThrowNapiException(env, error, "Failed to join room");
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
_joined = true;
|
|
398
|
+
|
|
399
|
+
// Start capturing audio data if event listener has not been started yet
|
|
400
|
+
if (_audioDataReceivedEventListener) {
|
|
401
|
+
HandleAudioData();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Closes the room connection and destroys the room handle.
|
|
407
|
+
* @param info
|
|
408
|
+
*/
|
|
409
|
+
void OdinRoom::Close(const Napi::CallbackInfo &info) {
|
|
410
|
+
//Napi::Env env = info.Env();
|
|
411
|
+
|
|
412
|
+
if (_roomHandle <= 0) return;
|
|
413
|
+
|
|
414
|
+
odin_room_set_event_callback(_roomHandle, NULL, NULL);
|
|
415
|
+
|
|
416
|
+
if (this->_eventListener != NULL) {
|
|
417
|
+
this->_eventListener.Release();
|
|
418
|
+
this->_eventListener = NULL;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
for (auto it = _eventListeners.begin(); it != _eventListeners.end(); ++it) {
|
|
422
|
+
if (it->second != NULL) {
|
|
423
|
+
it->second.Release();
|
|
424
|
+
it->second = NULL;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
odin_room_close(_roomHandle);
|
|
429
|
+
odin_room_destroy(_roomHandle);
|
|
430
|
+
_roomHandle = 0;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Creates a new instance of the OdinRoom class. Requires a token as a parameter.
|
|
435
|
+
* @param info
|
|
436
|
+
* @return
|
|
437
|
+
*/
|
|
438
|
+
Napi::Value OdinRoom::CreateNewItem(const Napi::CallbackInfo& info) {
|
|
439
|
+
Napi::Env env = info.Env();
|
|
440
|
+
|
|
441
|
+
if (info.Length() < 1) {
|
|
442
|
+
Napi::TypeError::New(env, "Token required as first parameter").ThrowAsJavaScriptException();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
Napi::String token = info[0].ToString();
|
|
446
|
+
|
|
447
|
+
// Retrieve the instance data we stored during `Init()`. We only stored the
|
|
448
|
+
// constructor there, so we retrieve it here to create a new instance of the
|
|
449
|
+
// JS class the constructor represents.
|
|
450
|
+
Napi::FunctionReference* constructor =
|
|
451
|
+
info.Env().GetInstanceData<Napi::FunctionReference>();
|
|
452
|
+
return constructor->New({ token });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Creates a new instance of the OdinRoom class. Requires a token as a parameter.
|
|
457
|
+
* @param info
|
|
458
|
+
* @return
|
|
459
|
+
*/
|
|
460
|
+
Napi::Object OdinRoom::NewInstance(Napi::Value arg) {
|
|
461
|
+
return constructor->New({ arg });
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Updates the peer user data. Requires an array of bytes as a parameter.
|
|
466
|
+
* @param info
|
|
467
|
+
* @return
|
|
468
|
+
*/
|
|
469
|
+
void OdinRoom::UpdatePeerUserData(const Napi::CallbackInfo &info) {
|
|
470
|
+
Napi::Env env = info.Env();
|
|
471
|
+
|
|
472
|
+
if (info.Length() != 1 || !info[0].IsTypedArray()) {
|
|
473
|
+
Napi::TypeError::New(env, "Data as byte array expected").ThrowAsJavaScriptException();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
|
|
477
|
+
|
|
478
|
+
OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Peer, data.Data(), data.ByteLength());
|
|
479
|
+
|
|
480
|
+
if (odin_is_error(error))
|
|
481
|
+
{
|
|
482
|
+
OdinUtilities::ThrowNapiException(env, error, "Failed to update peer user data");
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Updates the room user data. Requires an array of bytes as a parameter.
|
|
488
|
+
* @param info
|
|
489
|
+
* @return
|
|
490
|
+
*/
|
|
491
|
+
void OdinRoom::UpdateRoomUserData(const Napi::CallbackInfo &info) {
|
|
492
|
+
Napi::Env env = info.Env();
|
|
493
|
+
|
|
494
|
+
if (info.Length() != 1 || !info[0].IsTypedArray()) {
|
|
495
|
+
Napi::TypeError::New(env, "Data as byte array expected").ThrowAsJavaScriptException();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
|
|
499
|
+
|
|
500
|
+
OdinReturnCode error = odin_room_update_user_data(_roomHandle, OdinUserDataTarget_Room, data.Data(), data.ByteLength());
|
|
501
|
+
|
|
502
|
+
if (odin_is_error(error))
|
|
503
|
+
{
|
|
504
|
+
OdinUtilities::ThrowNapiException(env, error, "Failed to update room user data");
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Sends a message to the room. Requires an array of bytes as a parameter and optinally a list of peer ids to send to.
|
|
510
|
+
* Please note: If the list is NULL the message will be sent to all peers in the room. If the list is not NULL the message
|
|
511
|
+
* will be sent to all peers in the list. If the list is empty the message ODIN will raise an error.
|
|
512
|
+
* @param info
|
|
513
|
+
* @return
|
|
514
|
+
*/
|
|
515
|
+
void OdinRoom::SendMessage(const Napi::CallbackInfo &info) {
|
|
516
|
+
Napi::Env env = info.Env();
|
|
517
|
+
|
|
518
|
+
if (info.Length() < 1 || !info[0].IsTypedArray()) {
|
|
519
|
+
Napi::TypeError::New(env, "Data as byte array expected").ThrowAsJavaScriptException();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
Napi::Uint8Array data = info[0].As<Napi::Uint8Array>();
|
|
523
|
+
|
|
524
|
+
uint64_t *peer_id_list = NULL;
|
|
525
|
+
size_t peer_id_list_length = 0;
|
|
526
|
+
if (info.Length() >= 2 && !info[1].IsNull() && !info[1].IsUndefined()) {
|
|
527
|
+
if (!info[1].IsArray()) {
|
|
528
|
+
Napi::TypeError::New(env, "Peer id list as uint32 array expected").ThrowAsJavaScriptException();
|
|
529
|
+
} else {
|
|
530
|
+
Napi::Array peerIds = info[1].As<Napi::Array>();
|
|
531
|
+
peer_id_list_length = peerIds.Length();
|
|
532
|
+
peer_id_list = new uint64_t[peer_id_list_length];
|
|
533
|
+
for (int i = 0; i < (int)peer_id_list_length; i++) {
|
|
534
|
+
peer_id_list[i] = peerIds.Get(i).As<Napi::Number>().Uint32Value();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
OdinReturnCode error = odin_room_send_message(_roomHandle, peer_id_list, peer_id_list_length, data.Data(), data.ByteLength());
|
|
540
|
+
|
|
541
|
+
if (peer_id_list != NULL) {
|
|
542
|
+
delete[] peer_id_list;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (odin_is_error(error))
|
|
546
|
+
{
|
|
547
|
+
OdinUtilities::ThrowNapiException(env, error, "Failed to update room user data");
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Sets a global event listener for this room. Requires a callback function as a parameter and will receive all events
|
|
553
|
+
* @param info
|
|
554
|
+
* @return
|
|
555
|
+
*/
|
|
556
|
+
void OdinRoom::SetEventListener(const Napi::CallbackInfo &info) {
|
|
557
|
+
Napi::Env env = info.Env();
|
|
558
|
+
|
|
559
|
+
if (info.Length() != 1 || !info[0].IsFunction()) {
|
|
560
|
+
Napi::TypeError::New(env, "Callback function expected").ThrowAsJavaScriptException();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
Napi::Function napiFunction = info[0].As<Napi::Function>();
|
|
564
|
+
|
|
565
|
+
_eventListener = Napi::ThreadSafeFunction::New(env, napiFunction, "Callback", 0, 1);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Adds an event listener for this room. Requires the event type to listen to and a callback function as a second parameter
|
|
570
|
+
* @param info
|
|
571
|
+
* @return
|
|
572
|
+
*/
|
|
573
|
+
void OdinRoom::AddEventListener(const Napi::CallbackInfo &info) {
|
|
574
|
+
Napi::Env env = info.Env();
|
|
575
|
+
|
|
576
|
+
if (info.Length() != 2 || !info[0].IsString() || !info[1].IsFunction()) {
|
|
577
|
+
Napi::TypeError::New(env, "Event Name and Callback function expected").ThrowAsJavaScriptException();
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
std::string eventName = info[0].As<Napi::String>().Utf8Value();
|
|
581
|
+
Napi::Function napiFunction = info[1].As<Napi::Function>();
|
|
582
|
+
|
|
583
|
+
if (eventName != "AudioDataReceived") {
|
|
584
|
+
_eventListeners[eventName] = Napi::ThreadSafeFunction::New(env, napiFunction, eventName + "Callback", 0, 1);
|
|
585
|
+
} else {
|
|
586
|
+
_audioDataReceivedEventListener = Napi::ThreadSafeFunction::New(
|
|
587
|
+
env,
|
|
588
|
+
napiFunction,
|
|
589
|
+
"AudioDataReceivedCallback",
|
|
590
|
+
0,
|
|
591
|
+
1,
|
|
592
|
+
[this](Napi::Env) {
|
|
593
|
+
// This is the finalizer thread
|
|
594
|
+
this->_nativeThread.join();
|
|
595
|
+
}
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
HandleAudioData();
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Removes an event listener for this room. Requires the event type to remove the listener for.
|
|
604
|
+
* @param info
|
|
605
|
+
* @return
|
|
606
|
+
*/
|
|
607
|
+
void OdinRoom::RemoveEventListener(const Napi::CallbackInfo &info) {
|
|
608
|
+
Napi::Env env = info.Env();
|
|
609
|
+
|
|
610
|
+
if (info.Length() != 1 || !info[0].IsString()) {
|
|
611
|
+
Napi::TypeError::New(env, "Event Name expected").ThrowAsJavaScriptException();
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
std::string eventName = info[0].As<Napi::String>().Utf8Value();
|
|
615
|
+
|
|
616
|
+
if (eventName != "AudioDataReceived") {
|
|
617
|
+
_eventListeners[eventName].Release();
|
|
618
|
+
_eventListeners.erase(eventName);
|
|
619
|
+
} else {
|
|
620
|
+
_audioDataReceivedEventListener.Release();
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Internal function to receive audio data every 20ms and send it to the JS side. This function will start once the client
|
|
626
|
+
* has registered AudioDataReceived as an event listener.
|
|
627
|
+
*/
|
|
628
|
+
void OdinRoom::HandleAudioData()
|
|
629
|
+
{
|
|
630
|
+
if (!_joined) {
|
|
631
|
+
#ifdef DEBUG
|
|
632
|
+
printf("Odin NodeJS Addon: Skipping audio until joined\n");
|
|
633
|
+
#endif
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (_started) {
|
|
638
|
+
#ifdef DEBUG
|
|
639
|
+
printf("Odin NodeJS Addon: Handle Audio Data thread already started\n");
|
|
640
|
+
#endif
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
_started = true;
|
|
645
|
+
|
|
646
|
+
// Create a native thread
|
|
647
|
+
_nativeThread = std::thread( [this] {
|
|
648
|
+
auto callback = []( Napi::Env env, Napi::Function jsCallback, void* value ) {
|
|
649
|
+
AudioSamples* samples = static_cast<AudioSamples*>( value );
|
|
650
|
+
// Transform native data into JS data, passing it to the provided
|
|
651
|
+
// `jsCallback` -- the TSFN's JavaScript function.
|
|
652
|
+
//Napi::Buffer<float> buffer = Napi::Buffer<float>::New(env, samples->OriginalData, samples->Len);
|
|
653
|
+
//Napi::ArrayBuffer buffer32 = Napi::ArrayBuffer::New(env, samples->OriginalData, samples->Len*sizeof(float));
|
|
654
|
+
//Napi::ArrayBuffer buffer16 = Napi::ArrayBuffer::New(env, samples->Data, samples->Len*sizeof(short));
|
|
655
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
656
|
+
obj.Set("peerId", samples->PeerId);
|
|
657
|
+
obj.Set("mediaId", samples->MediaId);
|
|
658
|
+
obj.Set("samples16", Napi::Buffer<short>::New(env, samples->Data, samples->Len));
|
|
659
|
+
obj.Set("samples32", Napi::Buffer<float>::New(env, samples->OriginalData, samples->Len));
|
|
660
|
+
|
|
661
|
+
jsCallback.Call( {obj} );
|
|
662
|
+
|
|
663
|
+
// We're finished with the data.
|
|
664
|
+
delete samples;
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
while (this->_started)
|
|
668
|
+
{
|
|
669
|
+
for (auto it = _mediaStreams.begin(); it != _mediaStreams.end(); it++)
|
|
670
|
+
{
|
|
671
|
+
OdinReturnCode rc = odin_audio_read_data((OdinMediaStreamHandle)it->second.Handle, this->_audioSamplesBuffer, 960);
|
|
672
|
+
|
|
673
|
+
if (odin_is_error(rc)) {
|
|
674
|
+
printf("Odin NodeJS Addon: Failed to read audio data\n");
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
AudioSamples* samples = new AudioSamples();
|
|
679
|
+
samples->SetSamples(this->_audioSamplesBuffer, 960);
|
|
680
|
+
samples->PeerId = it->second.PeerId;
|
|
681
|
+
samples->MediaId = it->second.Id;
|
|
682
|
+
|
|
683
|
+
// Perform a blocking call
|
|
684
|
+
napi_status status = _audioDataReceivedEventListener.BlockingCall( samples, callback );
|
|
685
|
+
if ( status != napi_ok )
|
|
686
|
+
{
|
|
687
|
+
// Handle error
|
|
688
|
+
printf("Odin NodeJS Addon: Failed to call audio data received callback\n");
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
std::this_thread::sleep_for( std::chrono::milliseconds ( 20 ) );
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
#ifdef DEBUG
|
|
697
|
+
printf("Odin NodeJS Addon: Handle Audio Thread finished.");
|
|
698
|
+
#endif
|
|
699
|
+
|
|
700
|
+
// Release the thread-safe function
|
|
701
|
+
_audioDataReceivedEventListener.Release();
|
|
702
|
+
} );
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
Napi::Value OdinRoom::CreateAudioStream(const Napi::CallbackInfo &info)
|
|
706
|
+
{
|
|
707
|
+
Napi::Env env = info.Env();
|
|
708
|
+
|
|
709
|
+
// Checking for input of sample rate (int) and number of channels (int)
|
|
710
|
+
if (info.Length() != 2 || !info[0].IsNumber() || !info[1].IsNumber()) {
|
|
711
|
+
Napi::TypeError::New(env, "Sample rate and number of channels expected").ThrowAsJavaScriptException();
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (info.Length() == 3 && !info[2].IsObject()) {
|
|
715
|
+
Napi::TypeError::New(env, "Options need to be an object").ThrowAsJavaScriptException();
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (info.Length() == 2) {
|
|
719
|
+
return OdinMedia::NewInstance({this->Value(), info[0], info[1]});
|
|
720
|
+
} else {
|
|
721
|
+
return OdinMedia::NewInstance({this->Value(), info[0], info[1], info[2]});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Removes an event listener for this room. Requires the event type to remove the listener for.
|
|
728
|
+
* @param info
|
|
729
|
+
* @return
|
|
730
|
+
*/
|
|
731
|
+
Napi::Value OdinRoom::GetOwnPeerId(const Napi::CallbackInfo &info) {
|
|
732
|
+
Napi::Env env = info.Env();
|
|
733
|
+
|
|
734
|
+
uint64_t out_peer_id = 0;
|
|
735
|
+
odin_room_peer_id(this->_roomHandle, &out_peer_id);
|
|
736
|
+
|
|
737
|
+
return Napi::Number::New(env, out_peer_id);
|
|
738
|
+
}
|